Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: base/test/sequenced_task_runner_test_template.h

Issue 9663075: Implementation of SequencedTaskRunner based on SequencedWorkerPool. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This class defines tests that implementations of SequencedTaskRunner should
6 // pass in order to be conformant. Here's how you use it to test your
akalin 2012/03/20 22:16:08 Remove 2nd sentence, merge paragraph below with th
Francois 2012/03/26 09:33:21 Done.
7 // implementation.
8 //
9 // See task_runner_test_template.h for a description of how to use the
10 // constructs in this file; these work the same.
11
12 #ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
13 #define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
14 #pragma once
15
16 #include <cstddef>
17
akalin 2012/03/20 22:16:08 remove extra newline
Francois 2012/03/26 09:33:21 Done.
18 #include <vector>
19
20 #include "base/basictypes.h"
21 #include "base/bind.h"
22 #include "base/memory/ref_counted.h"
23 #include "base/sequenced_task_runner.h"
24 #include "base/synchronization/lock.h"
25 #include "base/tracked_objects.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace base {
29
30 namespace internal {
31
32 // Utility class used in the tests below.
33 class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
34 public:
35 struct TaskPhase {
akalin 2012/03/20 22:16:08 I think TaskEvent is a better name
Francois 2012/03/26 09:33:21 Done.
36 enum Type { POST, START, END };
37 TaskPhase(int i, Type type) : i_(i), type_(type) {}
38 bool operator==(const TaskPhase& phase) {
akalin 2012/03/20 22:16:08 prefer bool Equals(const TaskPhase& phase) const
Francois 2012/03/26 09:33:21 Will do next time, but it isn't required anymore,
39 return (i_ == phase.i_ && type_ == phase.type_);
40 }
41 int i_;
akalin 2012/03/20 22:16:08 typically public member variables don't have an ap
Francois 2012/03/26 09:33:21 Done.
42 Type type_;
43 };
44
45 SequencedTaskTracker();
46
47 int GetNextPostOrdinal();
akalin 2012/03/20 22:16:08 shouldn't need this function (see comments below)
Francois 2012/03/26 09:33:21 Done.
48
49 void TaskPosted(int i);
akalin 2012/03/20 22:16:08 these functions shouldn't be exposed. Instead, yo
Francois 2012/03/26 09:33:21 Done. And DoNothing isn't required if null tasks a
50 void TaskStarted(int i);
51 void TaskEnded(int i);
52
53 const std::vector<TaskPhase>& GetTaskPhases() const;
54
55 void FastTask(int i);
56 void SlowTask(int i);
57
58 // Task which posts a fast, non-nestable task.
59 void PostFastNonNestableFromSlowNonNestable(
60 scoped_refptr<SequencedTaskRunner> task_runner,
61 const int base_status_i,
62 const int child_count);
63
64 private:
65 friend class RefCountedThreadSafe<SequencedTaskTracker>;
66
67 ~SequencedTaskTracker();
68
69 public:
akalin 2012/03/20 22:16:08 these shouldn't be public
Francois 2012/03/26 09:33:21 Done.
70 std::vector<TaskPhase> phases_;
71 mutable Lock phase_lock_;
akalin 2012/03/20 22:16:08 add a comment saying that phase_lock_ protects pha
Francois 2012/03/26 09:33:21 Done.
72
73 private:
74 int next_post_i_;
75
76 DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
77 };
78
79 } // namespace internal
80
81 template <typename TaskRunnerTestDelegate>
82 class SequencedTaskRunnerTest : public testing::Test {
83 protected:
84 SequencedTaskRunnerTest()
85 : task_tracker_(new internal::SequencedTaskTracker()) {}
86
87 // Checks that each phase type occurs in the same order as the tasks were
88 // posted, and that the phases for each given task occur in the expected
89 // order (POST, START, END).
90 ::testing::AssertionResult TaskPhasesInOrder(int task_count);
91
92 const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
93 TaskRunnerTestDelegate delegate_;
94 };
95
96 TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
97
98 // This test posts N non-nestable tasks in sequence, and expects them to run
99 // in FIFO order, with no part of any two tasks' execution
100 // overlapping. I.e. that each task starts only after the previously-posted
101 // one has finished.
102 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
103 const int task_count = 1000;
104
105 this->delegate_.StartTaskRunner();
106 scoped_refptr<SequencedTaskRunner> task_runner =
107 this->delegate_.GetTaskRunner();
108
109 for (int i = 0; i < task_count; ++i) {
110 Closure task;
111 if (i == 0) {
akalin 2012/03/20 22:16:08 with the comments above, you can move the i=0 case
Francois 2012/03/26 09:33:21 Done.
112 task = Bind(&internal::SequencedTaskTracker::SlowTask,
113 this->task_tracker_, i);
114 } else {
115 task = Bind(&internal::SequencedTaskTracker::FastTask,
116 this->task_tracker_, i);
117 }
118 this->task_tracker_->TaskPosted(i);
119 task_runner->PostNonNestableTask(FROM_HERE, task);
120 }
121
122 this->delegate_.StopTaskRunner();
123
124 EXPECT_TRUE(this->TaskPhasesInOrder(task_count));
125 }
126
127 // This test posts N nestable tasks in sequence. It has the same expectations
128 // as SequentialNonNestable because even though the tasks are nestable, they
129 // will not be run nestedly in this case.
130 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
131 const int task_count = 1000;
132
133 this->delegate_.StartTaskRunner();
134 scoped_refptr<SequencedTaskRunner> task_runner =
135 this->delegate_.GetTaskRunner();
136
137 for (int i = 0; i < task_count; ++i) {
138 Closure task;
139 if (i == 0) {
140 task = Bind(&internal::SequencedTaskTracker::SlowTask,
141 this->task_tracker_, i);
142 } else {
143 task = Bind(&internal::SequencedTaskTracker::FastTask,
144 this->task_tracker_, i);
145 }
146 this->task_tracker_->TaskPosted(i);
147 task_runner->PostTask(FROM_HERE, task);
148 }
149
150 this->delegate_.StopTaskRunner();
151
152 EXPECT_TRUE(this->TaskPhasesInOrder(task_count));
153 }
154
155 // This test posts non-nestable tasks in order of increasing delay, and checks
156 // that that the tasks are run in FIFO order and that there is no execution
157 // overlap whatsoever between any two tasks.
158 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
159 if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
160 DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
161 "non-zero delays; skipping";
162 return;
163 }
164
165 const int task_count = 20;
166 const int delay_increment_ms = 50;
167
168 this->delegate_.StartTaskRunner();
169 scoped_refptr<SequencedTaskRunner> task_runner =
170 this->delegate_.GetTaskRunner();
171
172 for (int i = 0; i < task_count; ++i) {
173 Closure task = Bind(&internal::SequencedTaskTracker::FastTask,
174 this->task_tracker_, i);
175 this->task_tracker_->TaskPosted(i);
176 task_runner->PostNonNestableDelayedTask(
177 FROM_HERE,
178 task,
179 TimeDelta::FromMilliseconds(delay_increment_ms * i));
180 }
181
182 this->delegate_.StopTaskRunner();
183
184 EXPECT_TRUE(this->TaskPhasesInOrder(task_count));
185 }
186
187 // This test posts a fast, non-nestable task from within each of a number of
188 // slow, non-nestable tasks and checks that they all run in the sequence they
189 // were posted in and that there is no execution overlap whatsoever.
190 TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
191 const int parent_count = 10;
192 const int children_per_parent = 10;
193
194 this->delegate_.StartTaskRunner();
195 scoped_refptr<SequencedTaskRunner> task_runner =
196 this->delegate_.GetTaskRunner();
197
198 const int end = parent_count;
199 for (int i = 0; i < end; ++i) {
200 AutoLock phase_lock(this->task_tracker_->phase_lock_);
201 const int post_i = this->task_tracker_->GetNextPostOrdinal();
202 Closure task = Bind(
203 &internal::SequencedTaskTracker::PostFastNonNestableFromSlowNonNestable,
204 this->task_tracker_,
205 task_runner,
206 post_i,
207 children_per_parent);
208 this->task_tracker_->phases_.push_back(
209 internal::SequencedTaskTracker::TaskPhase(
210 post_i, internal::SequencedTaskTracker::TaskPhase::POST));
211 task_runner->PostNonNestableTask(FROM_HERE, task);
212 }
213
214 this->delegate_.StopTaskRunner();
215
216 EXPECT_TRUE(this->TaskPhasesInOrder(parent_count *
217 (children_per_parent + 1)));
218 }
219
220 // TODO(francoisk777@gmail.com) Add a test, similiar to the above, which which
221 // runs some tasked nestedly (which should be implemented in the test
222 // delegate). Also add, to the the test delegate, a predicate which checks
223 // whether the implementation supports nested tasks.
224 //
225
226 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
227 SequentialNonNestable,
228 SequentialNestable,
229 SequentialDelayedNonNestable,
230 NonNestablePostFromNonNestableTask
231 );
232
233 template <typename TaskRunnerTestDelegate>
akalin 2012/03/20 22:16:08 the code below should probably go before the unit
Francois 2012/03/26 09:33:21 Done.
234 ::testing::AssertionResult
235 SequencedTaskRunnerTest<TaskRunnerTestDelegate>::TaskPhasesInOrder(
akalin 2012/03/20 22:16:08 this function does a bit too much -- it's complica
Francois 2012/03/26 09:33:21 Done.
236 int task_count) {
237 typedef internal::SequencedTaskTracker::TaskPhase TaskPhase;
238
239 std::vector<TaskPhase> phases = task_tracker_->GetTaskPhases();
240
241 if (phases.size() != task_count * 3U) {
242 return ::testing::AssertionFailure()
243 << "Expecting " << (task_count * 3) << " task phases, but found only"
244 << phases.size();
245 }
246
247 // Stores the order of phases for each task.
248 std::vector<std::vector<TaskPhase::Type> > phase_orders(task_count);
249
250 int expected_post_task = 0;
251 int expected_start_task = 0;
252 int expected_end_task = 0;
253
254 std::vector<TaskPhase>::const_iterator phase;
255 for (phase = phases.begin(); phase != phases.end(); ++phase) {
256 switch (phase->type_) {
257 case TaskPhase::POST:
258 if (phase->i_ != expected_post_task) {
259 return ::testing::AssertionFailure()
260 << "POST phase for task " << phase->i_
261 << " is out of order; expecting one for task "
262 << expected_post_task << ", instead";
263 }
264 phase_orders[expected_post_task].push_back(TaskPhase::POST);
265 ++expected_post_task;
266 break;
267 case TaskPhase::START:
268 if (phase->i_ != expected_start_task) {
269 return ::testing::AssertionFailure()
270 << "START phase for task " << phase->i_
271 << " is out of order; expecting one for task "
272 << expected_start_task << ", instead";
273 }
274 phase_orders[expected_start_task].push_back(TaskPhase::START);
275 ++expected_start_task;
276 break;
277 case TaskPhase::END:
278 if (phase->i_ != expected_end_task) {
279 return ::testing::AssertionFailure()
280 << "END phase for task " << phase->i_
281 << " is out of order; expecting one for task "
282 << expected_end_task << ", instead";
283 }
284 if (phase_orders[expected_end_task].size() != 2) {
285 return ::testing::AssertionFailure()
286 << "POST and/or START phase(s) for task " << phase->i_
287 << " did not occur before its END phase";
288 }
289 if (phase_orders[expected_end_task][1] != TaskPhase::START) {
290 return ::testing::AssertionFailure()
291 << "START phase for task " << phase->i_
292 << " did not occur before its END phase";
293 }
294 if (phase_orders[expected_end_task][0] != TaskPhase::POST) {
295 return ::testing::AssertionFailure()
296 << "POST phase for task " << phase->i_
297 << " did not occur before its START and END phases";
298 }
299 ++expected_end_task;
300 break;
301 }
302 }
303 return ::testing::AssertionSuccess();
304 }
305
306 } // namespace base
307
308 #endif // BASE_TASK_RUNNER_TEST_TEMPLATE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698