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

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
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
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/synchronization/waitable_event.h"
26 #include "base/tracked_objects.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace base {
30
31 namespace internal {
32
33 // Utility class used in the tests below.
34 class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
35 public:
36 // Keeps track of a task's run status. I.e. whether it has run to completion
37 // and whether its predecessor had run to completion by the time it started
38 // running.
39 class TaskStatus {
40 public:
41 TaskStatus();
42 TaskStatus(const TaskStatus& ts);
43 TaskStatus& operator=(const TaskStatus& ts);
44 bool operator==(const TaskStatus& ts) const;
45
46 // Claims ownership of this task status for a task.
47 bool Claim();
48 // Whether the owning task has started running yet.
49 bool Started() const;
50 // Whether the owning task has run to completion yet.
51 bool Completed() const;
52 // Whether the previous task had started by the time this one did.
53 bool PrevStartedBefore() const;
54 // Whether the previous task (the one which owns the preceding position in
55 // the task status vector) had finished by the time this one started.
56 bool PrevCompletedBefore() const;
57 // Declares that the owning task has started running.
58 void SetStarted();
59 // Declares that the owning task has run to completion.
60 void SetCompleted();
61 // Declares that the previous task had started by the time the owning task
62 // started.
63 void SetPrevStartedBefore(bool b);
64 // Declares that the previous task had run to completion by the time the
65 // owning task started.
66 void SetPrevCompletedBefore(bool b);
67
68 private:
69 // An output operator is required to make a failed gtest assertion print
70 // human-readable information.
71 friend std::ostream& operator<<(std::ostream&, const TaskStatus&);
72
73 mutable Lock lock_;
74 // Used to prevent task_i from checking task_i-1.Started() before task_i-1
75 // has had a chance to signal that it has started. There would otherwise
76 // be a race between the top of the task function and the line where it
77 // calls SetStarted().
78 mutable WaitableEvent start_event_;
79 // Whether this status slot has been claimed by a task yet.
80 bool claimed_;
81 bool started_;
82 bool completed_;
83 bool prev_started_;
84 bool prev_completed_;
85 };
86
87 typedef std::vector<TaskStatus> TaskStatuses;
88
89 SequencedTaskTracker();
90
91 // Pre-allocates memory for the non-nestable task statuses.
92 void SetNonNestableTaskCount(std::size_t task_count);
93
94 // Pre-allocates memory for the nestable task statuses.
95 void SetNestableTaskCount(std::size_t task_count);
96
97 const TaskStatuses& GetNonNestableTaskStatuses() const;
98 const TaskStatuses& GetNestableTaskStatuses() const;
99
100 // A fast, non-nestable task.
101 void FastNonNestableTask(int base_status_i);
102
103 // A fast, nestable task.
104 void FastNestableTask(int parent_task_status_slot);
105
106 // A slow, non-nestable task (sleeps for 1 second).
107 void SlowNonNestableTask(int base_status_i);
108
109 // A slow, nestable task (sleeps for 1 second).
110 void SlowNestableTask(int base_status_i);
111
112 // Posts a fast, non-nestable task from a slow, non-nestable one.
113 void PostFastNonNestableFromSlowNonNestable(
114 scoped_refptr<SequencedTaskRunner> task_runner,
115 const int base_status_i,
116 const int child_count);
117
118 // Posts a fast, nestable task from a slow, non-nestable one.
119 void PostFastNestableFromSlowNonNestable(
120 scoped_refptr<SequencedTaskRunner> task_runner,
121 const int base_status_i,
122 const int child_count);
123
124 private:
125 friend class RefCountedThreadSafe<SequencedTaskTracker>;
126
127 ~SequencedTaskTracker();
128
129 // Finds the lowest-numbered non-nestable task status object, beginning at
130 // position |search_from|, which has not yet been claimed.
131 int ClaimNonNestableTaskStatus(const int search_from);
132
133 // Finds the lowest-numbered nestable task status object, beginning at
134 // position |search_from|, which has not yet been claimed.
135 int ClaimNestableTaskStatus(const int search_from);
136
137 TaskStatuses nestable_statuses_;
138 TaskStatuses non_nestable_statuses_;
139
140 DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
141 };
142
143 // An output operator is required to make a failed gtest assertion print
144 // human-readable information.
145 std::ostream& operator<<(std::ostream& os,
146 const SequencedTaskTracker::TaskStatus& ts);
147
148 } // namespace internal
149
150 template <typename TaskRunnerTestDelegate>
151 class SequencedTaskRunnerTest : public testing::Test {
152 protected:
153 SequencedTaskRunnerTest()
154 : task_tracker_(new internal::SequencedTaskTracker()) {
155 good_task_status_prototype_.SetStarted();
156 good_task_status_prototype_.SetPrevStartedBefore(true);
157 good_task_status_prototype_.SetPrevCompletedBefore(true);
158 good_task_status_prototype_.SetCompleted();
159 }
160
161 const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
162 TaskRunnerTestDelegate delegate_;
163 internal::SequencedTaskTracker::TaskStatus good_task_status_prototype_;
164 };
165
166 TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
167
168 // This test posts N non-nestable tasks in sequence, and expects them to run
169 // in FIFO order, with no part of any two tasks' execution overlapping.
170 //
171 // It checks that task0 was done by the time task1 started, and task2 only
172 // started after task1 had executed to completion, etc.
173 //
174 // The first task it starts is a slow one which runs for a second, giving the
175 // subsequent ones plenty of time to run if the implementation fails to
176 // enforce the non-nestable property.
177 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
178 const int task_count = 1000;
179
180 this->task_tracker_->SetNonNestableTaskCount(task_count);
181 internal::SequencedTaskTracker::TaskStatuses expected_statuses(
182 task_count,
183 this->good_task_status_prototype_);
184
185 this->delegate_.StartTaskRunner();
186 scoped_refptr<SequencedTaskRunner> task_runner =
187 this->delegate_.GetTaskRunner();
188
189 for (int i = 0; i < task_count; ++i) {
190 Closure task;
191 if (i == 0) {
192 task = Bind(&internal::SequencedTaskTracker::SlowNonNestableTask,
193 this->task_tracker_, i);
194 } else {
195 task = Bind(&internal::SequencedTaskTracker::FastNonNestableTask,
196 this->task_tracker_, i);
197 }
198 task_runner->PostNonNestableTask(FROM_HERE, task);
199 }
200
201 this->delegate_.StopTaskRunner();
202
203 EXPECT_EQ(expected_statuses,
204 this->task_tracker_->GetNonNestableTaskStatuses());
205 }
206
207 // This test posts N nestable tasks in sequence, and expects them to run in
208 // FIFO order; overlapping execution is allowed.
209 //
210 // It checks only that task_i had started by the time task_i+1 started, for
211 // increasing values of i. Thus it verifies the SequencedTaskRunner guarantee
212 // that nested tasks are run in FIFO order.
213 //
214 // The first task it starts is a slow one which runs for a second, giving the
215 // subsequent ones plenty of time to run in if the implementation fails to
216 // enforce the FIFO property for nestable tasks.
217 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
218 const int task_count = 1000;
219
220 this->task_tracker_->SetNestableTaskCount(task_count);
221 internal::SequencedTaskTracker::TaskStatuses expected_statuses(
222 task_count,
223 this->good_task_status_prototype_);
224
225 this->delegate_.StartTaskRunner();
226 scoped_refptr<SequencedTaskRunner> task_runner =
227 this->delegate_.GetTaskRunner();
228
229 for (int i = 0; i < task_count; ++i) {
230 Closure task;
231 if (i == 0) {
232 task = Bind(&internal::SequencedTaskTracker::SlowNestableTask,
233 this->task_tracker_, i);
234 } else {
235 task = Bind(&internal::SequencedTaskTracker::FastNestableTask,
236 this->task_tracker_, i);
237 }
238 task_runner->PostTask(FROM_HERE, task);
239 }
240
241 this->delegate_.StopTaskRunner();
242
243 EXPECT_EQ(expected_statuses,
244 this->task_tracker_->GetNestableTaskStatuses());
245 }
246
247 // This test posts non-nestable tasks in order of increasing delay, and checks
248 // that that the tasks are run in FIFO order and that there is no execution
249 // overlap whatsoever between any two tasks.
250 //
251 // If there are 10 tasks, task1 is posted first with a delay of zero, followed
252 // by task2 with a delay of, say, 1, and so forth, until task10 is posted with
253 // a delay of 10. It then checks that task2 started after task1, and only
254 // after task1 had finished, and so forth.
255 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
256 if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) {
257 DLOG(INFO) << "This SequencedTaskRunner doesn't handle "
258 "non-zero delays; skipping";
259 return;
260 }
261
262 const int task_count = 20;
263 const int delay_increment_ms = 50;
264
265 this->task_tracker_->SetNonNestableTaskCount(task_count);
266 internal::SequencedTaskTracker::TaskStatuses expected_statuses(
267 task_count,
268 this->good_task_status_prototype_);
269
270 this->delegate_.StartTaskRunner();
271 scoped_refptr<SequencedTaskRunner> task_runner =
272 this->delegate_.GetTaskRunner();
273
274 for (int i = 0; i < task_count; ++i) {
275 Closure task = Bind(&internal::SequencedTaskTracker::FastNonNestableTask,
276 this->task_tracker_, i);
277 task_runner->PostNonNestableDelayedTask(
278 FROM_HERE,
279 task,
280 TimeDelta::FromMilliseconds(delay_increment_ms * i));
281 }
282
283 this->delegate_.StopTaskRunner();
284
285 EXPECT_EQ(expected_statuses,
286 this->task_tracker_->GetNonNestableTaskStatuses());
287 }
288
289 // This test posts a fast, non-nestable task from within each of a number of
290 // slow, non-nestable tasks and checks that they all run in the sequence they
291 // were posted in and that there is no execution overlap whatsoever.
292 TYPED_TEST_P(SequencedTaskRunnerTest,
293 NonNestablePostFromNonNestableTask) {
294 const int parent_count = 1000;
295 const int children_per_parent = 2;
296 const int task_count = parent_count * (children_per_parent + 1);
297
298 this->task_tracker_->SetNonNestableTaskCount(task_count);
299 internal::SequencedTaskTracker::TaskStatuses expected_statuses(
300 task_count,
301 this->good_task_status_prototype_);
302
303 this->delegate_.StartTaskRunner();
304 scoped_refptr<SequencedTaskRunner> task_runner =
305 this->delegate_.GetTaskRunner();
306
307 const int end = parent_count;
308 for (int i = 0; i < end; ++i) {
309 Closure task = Bind(
310 &internal::SequencedTaskTracker::PostFastNonNestableFromSlowNonNestable,
311 this->task_tracker_,
312 task_runner,
313 i,
314 children_per_parent);
315 task_runner->PostNonNestableTask(FROM_HERE, task);
316 }
317
318 this->delegate_.StopTaskRunner();
319
320 EXPECT_EQ(expected_statuses,
321 this->task_tracker_->GetNonNestableTaskStatuses());
322 }
323
324 // This test posts a number of fast, nestable tasks from within each of a
325 // number of slow, non-nestable tasks and checks that the non-nestable ones
326 // all run in the sequence they were posted in and that there is no execution
327 // overlap whatsoever.
328 TYPED_TEST_P(SequencedTaskRunnerTest,
329 NestablePostFromNonNestableTask) {
330 const int parent_count = 500;
331 const int children_per_parent = 2;
332
333 this->task_tracker_->SetNonNestableTaskCount(parent_count);
334 internal::SequencedTaskTracker::TaskStatuses expected_non_nestable_statuses(
335 parent_count,
336 this->good_task_status_prototype_);
337 this->task_tracker_->SetNestableTaskCount(children_per_parent * parent_count);
338 internal::SequencedTaskTracker::TaskStatuses expected_nestable_statuses(
339 children_per_parent * parent_count,
340 this->good_task_status_prototype_);
341
342 this->delegate_.StartTaskRunner();
343 scoped_refptr<SequencedTaskRunner> task_runner =
344 this->delegate_.GetTaskRunner();
345
346 const int end = parent_count;
347 for (int i = 0; i < end; ++i) {
348 Closure task = Bind(
349 &internal::SequencedTaskTracker::PostFastNestableFromSlowNonNestable,
350 this->task_tracker_,
351 task_runner,
352 i,
353 children_per_parent);
354 task_runner->PostNonNestableTask(FROM_HERE, task);
355 }
356
357 this->delegate_.StopTaskRunner();
358
359 EXPECT_EQ(expected_non_nestable_statuses,
360 this->task_tracker_->GetNonNestableTaskStatuses());
361 EXPECT_EQ(expected_nestable_statuses,
362 this->task_tracker_->GetNestableTaskStatuses());
363 }
364
365 // TODO(francoisk777@gmail.com) Add a test, similiar to the above, which which
366 // runs some tasked nestedly (which should be implemented in the test
367 // delegate). Also add, to the the test delegate, a predicate which checks
368 // whether the implementation supports nested tasks.
369
370 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
371 SequentialNonNestable,
372 SequentialNestable,
373 SequentialDelayedNonNestable,
374 NonNestablePostFromNonNestableTask,
375 NestablePostFromNonNestableTask);
376
377 } // namespace base
378
379 #endif // BASE_TASK_RUNNER_TEST_TEMPLATE_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698