|
OLD | NEW |
---|---|
(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/synchronization/lock.h" | |
24 #include "base/sequenced_task_runner.h" | |
25 #include "base/tracked_objects.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 | |
28 namespace base { | |
29 | |
30 // Utility class used in the tests below. | |
31 class SeqTaskTracker : public RefCountedThreadSafe<SeqTaskTracker> { | |
akalin
2012/03/13 07:27:11
SeqTaskTracker -> SequencedTaskTracker (abbreviati
akalin
2012/03/13 07:27:11
put this class in the base::internal namespace
(y
Francois
2012/03/14 15:43:31
Done.
Francois
2012/03/14 15:43:31
Done.
| |
32 public: | |
33 // Keeps track of a task's run status. I.e. whether it has run to completion | |
34 // and whether its predecessor had run to completion by the time it started | |
35 // running. | |
36 class TaskStatus { | |
akalin
2012/03/13 07:27:11
Hmm I think this class may be overkill. I was thi
akalin
2012/03/13 20:00:10
Actually a few corrections. WrapTask should *not*
Francois
2012/03/14 15:43:31
I like your model because it mirrors the task hier
| |
37 public: | |
38 TaskStatus(); | |
39 TaskStatus(const TaskStatus& ts); | |
40 TaskStatus& operator=(const TaskStatus& ts); | |
41 bool operator==(const TaskStatus& ts) const; | |
42 | |
43 // Claims ownership of this task status for a task. | |
44 bool Claim(); | |
45 // Whether the owning task has run to completion yet. | |
46 bool Completed() const; | |
47 // Whether the previous task (the one which owns the preceding position in | |
48 // the task status vector) had finished by the time this one started. | |
49 bool PrevCompletedBefore() const; | |
50 // Declares that the owning task has run to completion. | |
51 void SetCompleted(); | |
52 // Declares that the previous task had run to completion by the time the | |
53 // owning task started. | |
54 void SetPrevCompletedBefore(const bool b); | |
55 | |
56 private: | |
57 mutable Lock lock_; | |
58 // Whether this status slot has been claimed by a task yet. | |
59 bool claimed_; | |
60 bool completed_; | |
61 // Whether the owning task has set the "completed" flag. | |
62 bool completed_set_; | |
63 bool prev_completed_; | |
64 // Whether the owning task has set the "previous completed" flag. | |
65 bool prev_completed_set_; | |
66 }; | |
67 | |
68 typedef std::vector<TaskStatus> TaskStatuses; | |
69 | |
70 SeqTaskTracker(); | |
71 | |
72 // Pre-allocates memory for the non-nestable task statuses. | |
73 void SetNonNestableTaskCount(const std::size_t task_count); | |
akalin
2012/03/13 07:27:11
remove const (doesn't make sense for value paramet
Francois
2012/03/14 15:43:31
Done. But it does make sense to me :) If something
| |
74 | |
75 // Pre-allocates memory for the nestable task statuses. | |
76 void SetNestableTaskCount(const std::size_t task_count); | |
77 | |
78 const TaskStatuses& GetNonNestableTaskStatuses() const; | |
79 const TaskStatuses& GetNestableTaskStatuses() const; | |
80 | |
81 // A fast, non-nestable task. | |
82 void FastNonNestableTask(int base_status_i); | |
83 | |
84 // A fast, nestable task. | |
85 void FastNestableTask(int parent_task_status_slot); | |
86 | |
87 // A slow, non-nestable task (sleeps for 1 second). | |
88 void SlowNonNestableTask(int base_status_i); | |
89 | |
90 // Posts a fast, non-nestable task from a slow, non-nestable one. | |
91 void PostFastNonNestableFromSlowNonNestable( | |
92 scoped_refptr<SequencedTaskRunner> tr, | |
akalin
2012/03/13 07:27:11
tr -> task_runner (abbreviations are discouraged)
Francois
2012/03/14 15:43:31
Done.
| |
93 const int base_status_i, | |
94 const int child_count); | |
95 | |
96 // Posts a fast, nestable task from a slow, non-nestable one. | |
97 void PostFastNestableFromSlowNonNestable( | |
98 scoped_refptr<SequencedTaskRunner> tr, | |
99 const int base_status_i, | |
100 const int child_count); | |
101 | |
102 private: | |
103 friend class RefCountedThreadSafe<SeqTaskTracker>; | |
104 | |
105 ~SeqTaskTracker(); | |
106 | |
107 // Finds the lowest-numbered non-nestable task status object, beginning at | |
108 // position |search_from|, which has not yet been claimed. | |
109 int ClaimNonNestableTaskStatus(const int search_from = 0); | |
akalin
2012/03/13 07:27:11
default arguments are prohibited by style guide
Francois
2012/03/14 15:43:31
Done.
| |
110 | |
111 // Finds the lowest-numbered nestable task status object, beginning at | |
112 // position |search_from|, which has not yet been claimed. | |
113 int ClaimNestableTaskStatus(const int search_from = 0); | |
akalin
2012/03/13 07:27:11
here too
Francois
2012/03/14 15:43:31
Done.
| |
114 | |
115 TaskStatuses nestable_statuses_; | |
116 TaskStatuses non_nestable_statuses_; | |
117 | |
118 DISALLOW_COPY_AND_ASSIGN(SeqTaskTracker); | |
119 }; | |
120 | |
121 std::ostream& operator<<(std::ostream& os, | |
akalin
2012/03/13 07:27:11
a ToString() member function is preferred to overl
Francois
2012/03/14 15:43:31
OK, but I added this to customise the output of EX
| |
122 const SeqTaskTracker::TaskStatus& ts); | |
123 | |
124 template <typename TaskRunnerTestDelegate> | |
125 class SequencedTaskRunnerTest : public testing::Test { | |
126 protected: | |
127 SequencedTaskRunnerTest() : task_tracker_(new SeqTaskTracker()) { | |
128 good_task_status_prototype_.SetPrevCompletedBefore(true); | |
129 good_task_status_prototype_.SetCompleted(); | |
130 } | |
131 | |
132 const scoped_refptr<SeqTaskTracker> task_tracker_; | |
133 TaskRunnerTestDelegate delegate_; | |
134 SeqTaskTracker::TaskStatus good_task_status_prototype_; | |
135 }; | |
136 | |
137 TYPED_TEST_CASE_P(SequencedTaskRunnerTest); | |
138 | |
139 // This test posts N non-nestable tasks in sequence, and expects them to run | |
140 // in FIFO order, with no part of any two tasks' execution overlapping. | |
141 // | |
142 // It checks that task0 was done by the time task1 started, and task2 only | |
143 // started after task1 had executed to completion, etc. | |
144 // | |
145 // The first task it starts is a slow one which runs for a second, giving the | |
146 // subsequent ones plenty of time to run if the implementation fails to | |
147 // enforce the non-nestable property. | |
148 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) { | |
149 const int task_count = 1000; | |
150 | |
151 this->task_tracker_->SetNonNestableTaskCount(task_count); | |
152 SeqTaskTracker::TaskStatuses expected_statuses( | |
153 task_count, | |
154 this->good_task_status_prototype_); | |
155 | |
156 this->delegate_.StartTaskRunner(); | |
157 scoped_refptr<SequencedTaskRunner> task_runner = | |
158 this->delegate_.GetTaskRunner(); | |
159 | |
160 for (int i = 0; i < task_count; ++i) { | |
161 Closure task; | |
162 if (i == 0) { | |
163 task = Bind(&SeqTaskTracker::SlowNonNestableTask, | |
164 this->task_tracker_, i); | |
165 } else { | |
166 task = Bind(&SeqTaskTracker::FastNonNestableTask, | |
167 this->task_tracker_, i); | |
168 } | |
169 task_runner->PostNonNestableTask(FROM_HERE, task); | |
170 } | |
171 | |
172 this->delegate_.StopTaskRunner(); | |
173 | |
174 EXPECT_EQ(expected_statuses, | |
175 this->task_tracker_->GetNonNestableTaskStatuses()); | |
176 } | |
177 | |
178 // This test posts non-nestable tasks in order of increasing delay, and checks | |
179 // that that the tasks are run in FIFO order and that there is no execution | |
180 // overlap whatsoever between any two tasks. | |
181 // | |
182 // If there are 10 tasks, task1 is posted first with a delay of zero, followed | |
183 // by task2 with a delay of, say, 1, and so forth, until task10 is posted with | |
184 // a delay of 10. It then checks that task2 started after task1, and only | |
185 // after task1 had finished, and so forth. | |
186 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) { | |
187 const int task_count = 20; | |
akalin
2012/03/13 07:27:11
if you change the logs in PostDelayed...Task to us
Francois
2012/03/14 15:43:31
Done.
| |
188 const int delay_increment_ms = 50; | |
189 | |
190 this->task_tracker_->SetNonNestableTaskCount(task_count); | |
191 SeqTaskTracker::TaskStatuses expected_statuses( | |
192 task_count, | |
193 this->good_task_status_prototype_); | |
194 | |
195 this->delegate_.StartTaskRunner(); | |
196 scoped_refptr<SequencedTaskRunner> task_runner = | |
197 this->delegate_.GetTaskRunner(); | |
198 | |
199 for (int i = 0; i < task_count; ++i) { | |
200 Closure task = Bind(&SeqTaskTracker::FastNonNestableTask, | |
201 this->task_tracker_, i); | |
202 task_runner->PostNonNestableDelayedTask( | |
203 FROM_HERE, | |
204 task, | |
205 TimeDelta::FromMilliseconds(delay_increment_ms * i)); | |
206 } | |
207 | |
208 this->delegate_.StopTaskRunner(); | |
209 | |
210 EXPECT_EQ(expected_statuses, | |
211 this->task_tracker_->GetNonNestableTaskStatuses()); | |
212 } | |
213 | |
214 // This test posts a fast, non-nestable task from within each of a number of | |
215 // slow, non-nestable tasks and checks that they all run in the sequence they | |
216 // were posted in and that there is no execution overlap whatsoever. | |
217 TYPED_TEST_P(SequencedTaskRunnerTest, | |
218 NonNestablePostFromNonNestableTask) { | |
219 const int parent_count = 1000; | |
220 const int children_per_parent = 2; | |
221 const int task_count = parent_count * (children_per_parent + 1); | |
222 | |
223 this->task_tracker_->SetNonNestableTaskCount(task_count); | |
224 SeqTaskTracker::TaskStatuses expected_statuses( | |
225 task_count, | |
226 this->good_task_status_prototype_); | |
227 | |
228 this->delegate_.StartTaskRunner(); | |
229 scoped_refptr<SequencedTaskRunner> task_runner = | |
230 this->delegate_.GetTaskRunner(); | |
231 | |
232 const int end = parent_count; | |
233 for (int i = 0; i < end; ++i) { | |
234 Closure task = Bind( | |
235 &SeqTaskTracker::PostFastNonNestableFromSlowNonNestable, | |
236 this->task_tracker_, | |
237 task_runner, | |
238 i, | |
239 children_per_parent); | |
240 DLOG(INFO) << "XXX Posted parent task " << i; | |
241 task_runner->PostNonNestableTask(FROM_HERE, task); | |
242 } | |
243 | |
244 this->delegate_.StopTaskRunner(); | |
245 | |
246 EXPECT_EQ(expected_statuses, | |
247 this->task_tracker_->GetNonNestableTaskStatuses()); | |
248 } | |
249 | |
250 // This test posts a number of fast, nestable tasks from within each of a | |
251 // number of slow, non-nestable tasks and checks that the non-nestable ones | |
252 // all run in the sequence they were posted in and that there is no execution | |
253 // overlap whatsoever. | |
254 TYPED_TEST_P(SequencedTaskRunnerTest, | |
255 NestablePostFromNonNestableTask) { | |
256 const int parent_count = 500; | |
257 const int children_per_parent = 2; | |
258 | |
259 this->task_tracker_->SetNonNestableTaskCount(parent_count); | |
260 SeqTaskTracker::TaskStatuses expected_non_nestable_statuses( | |
261 parent_count, | |
262 this->good_task_status_prototype_); | |
263 this->task_tracker_->SetNestableTaskCount(children_per_parent * parent_count); | |
264 SeqTaskTracker::TaskStatuses expected_nestable_statuses( | |
265 children_per_parent * parent_count, | |
266 this->good_task_status_prototype_); | |
267 | |
268 this->delegate_.StartTaskRunner(); | |
269 scoped_refptr<SequencedTaskRunner> task_runner = | |
270 this->delegate_.GetTaskRunner(); | |
271 | |
272 const int end = parent_count; | |
273 for (int i = 0; i < end; ++i) { | |
274 Closure task = Bind( | |
275 &SeqTaskTracker::PostFastNestableFromSlowNonNestable, | |
276 this->task_tracker_, | |
277 task_runner, | |
278 i, | |
279 children_per_parent); | |
280 task_runner->PostNonNestableTask(FROM_HERE, task); | |
281 } | |
282 | |
283 this->delegate_.StopTaskRunner(); | |
284 | |
285 EXPECT_EQ(expected_non_nestable_statuses, | |
286 this->task_tracker_->GetNonNestableTaskStatuses()); | |
287 EXPECT_EQ(expected_nestable_statuses, | |
288 this->task_tracker_->GetNestableTaskStatuses()); | |
289 } | |
290 | |
akalin
2012/03/13 07:27:11
Add a TODO for a test similar to the above, but ha
Francois
2012/03/14 15:43:31
Done.
| |
291 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest, | |
292 SequentialNonNestable, | |
293 SequentialDelayedNonNestable, | |
294 NonNestablePostFromNonNestableTask, | |
295 NestablePostFromNonNestableTask); | |
296 | |
297 } // namespace base | |
298 | |
299 #endif //#define BASE_TASK_RUNNER_TEST_TEMPLATE_H_ | |
akalin
2012/03/13 07:27:11
no '#define' in comment
Francois
2012/03/14 15:43:31
Done.
| |
OLD | NEW |