1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This class defines tests that implementations of TaskRunner should
// pass in order to be conformant. Here's how you use it to test your
// implementation.
//
// Say your class is called MyTaskRunner. Then you need to define a
// class called MyTaskRunnerTestDelegate in my_task_runner_unittest.cc
// like this:
//
// class MyTaskRunnerTestDelegate {
// public:
// // Tasks posted to the task runner after this and before
// // StopTaskRunner() is called is called should run successfully.
// void StartTaskRunner() {
// ...
// }
//
// // Should return the task runner implementation. Only called
// // after StartTaskRunner and before StopTaskRunner.
// scoped_refptr<MyTaskRunner> GetTaskRunner() {
// ...
// }
//
// // Stop the task runner and make sure all tasks posted before
// // this is called are run.
// void StopTaskRunner() {
// ...
// }
//
// // Returns whether or not the task runner obeys non-zero delays.
// bool TaskRunnerHandlesNonZeroDelays() const {
// return true;
// }
// };
//
// The TaskRunnerTest test harness will have a member variable of
// this delegate type and will call its functions in the various
// tests.
//
// Then you simply #include this file as well as gtest.h and add the
// following statement to my_task_runner_unittest.cc:
//
// INSTANTIATE_TYPED_TEST_CASE_P(
// MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
//
// Easy!
#ifndef BASE_TASK_RUNNER_TEST_TEMPLATE_H_
#define BASE_TASK_RUNNER_TEST_TEMPLATE_H_
#pragma once
#include <cstddef>
#include <map>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "base/tracked_objects.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
// Utility class used in the tests below.
class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
public:
TaskTracker();
void RunTask(int i);
std::map<int, int> GetTaskRunCounts() const;
private:
friend class RefCountedThreadSafe<TaskTracker>;
~TaskTracker();
mutable Lock task_run_counts_lock_;
std::map<int, int> task_run_counts_;
DISALLOW_COPY_AND_ASSIGN(TaskTracker);
};
template <typename TaskRunnerTestDelegate>
class TaskRunnerTest : public testing::Test {
protected:
TaskRunnerTest() : task_tracker_(new TaskTracker()) {}
const scoped_refptr<TaskTracker> task_tracker_;
TaskRunnerTestDelegate delegate_;
};
TYPED_TEST_CASE_P(TaskRunnerTest);
// We can't really test much, since TaskRunner provides very few
// guarantees.
// Post a bunch of tasks to the task runner. They should all
// complete.
TYPED_TEST_P(TaskRunnerTest, Basic) {
std::map<int, int> expected_task_run_counts;
this->delegate_.StartTaskRunner();
scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
// Post each ith task i+1 times.
for (int i = 0; i < 20; ++i) {
Closure task = Bind(&TaskTracker::RunTask, this->task_tracker_, i);
for (int j = 0; j < i + 1; ++j) {
task_runner->PostTask(FROM_HERE, task);
++expected_task_run_counts[i];
}
}
this->delegate_.StopTaskRunner();
EXPECT_EQ(expected_task_run_counts,
this->task_tracker_->GetTaskRunCounts());
}
// Post a bunch of delayed tasks to the task runner. They should all
// complete.
TYPED_TEST_P(TaskRunnerTest, Delayed) {
if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
DLOG(INFO) << "This TaskRunner doesn't handle non-zero delays; skipping";
return;
}
std::map<int, int> expected_task_run_counts;
this->delegate_.StartTaskRunner();
scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
// Post each ith task i+1 times with delays from 0-i.
for (int i = 0; i < 20; ++i) {
Closure task = Bind(&TaskTracker::RunTask, this->task_tracker_, i);
for (int j = 0; j < i + 1; ++j) {
task_runner->PostDelayedTask(FROM_HERE, task, j);
++expected_task_run_counts[i];
}
}
this->delegate_.StopTaskRunner();
EXPECT_EQ(expected_task_run_counts,
this->task_tracker_->GetTaskRunCounts());
}
// TODO(akalin): Add test to verify RunsTaskOnCurrentThread() returns
// true for tasks runs on the TaskRunner and returns false on a
// separate PlatformThread.
REGISTER_TYPED_TEST_CASE_P(TaskRunnerTest, Basic, Delayed);
} // namespace base
#endif //#define BASE_TASK_RUNNER_TEST_TEMPLATE_H_
|