|
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. See task_runner_test_template.h for a | |
7 // description of how to use the constructs in this file; these work the same. | |
8 | |
9 #ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_ | |
10 #define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_ | |
11 #pragma once | |
12 | |
13 #include <cstddef> | |
14 #include <iosfwd> | |
15 #include <vector> | |
16 | |
17 #include "base/basictypes.h" | |
18 #include "base/bind.h" | |
19 #include "base/callback.h" | |
20 #include "base/memory/ref_counted.h" | |
21 #include "base/sequenced_task_runner.h" | |
22 #include "base/synchronization/lock.h" | |
23 #include "base/time.h" | |
24 #include "testing/gtest/include/gtest/gtest.h" | |
25 | |
26 namespace base { | |
27 | |
28 namespace internal { | |
29 | |
30 // Utility class used in the tests below. | |
31 class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> { | |
32 public: | |
33 struct TaskEvent { | |
akalin
2012/03/26 18:44:08
just pull out this struct, since it's already in a
Francois
2012/03/28 14:32:42
Done.
| |
34 enum Type { POST, START, END }; | |
35 TaskEvent(int i_in, Type type_in); | |
akalin
2012/03/26 18:44:08
don't use _in, just name them the same
akalin
2012/03/26 18:44:08
define a default constructor and initialize both v
Francois
2012/03/28 14:32:42
Done.
Francois
2012/03/28 14:32:42
Why define a default constructor if it never gets
akalin
2012/03/29 18:44:38
Just defensive coding; the same reason why it's su
| |
36 int i; | |
37 Type type; | |
38 }; | |
39 | |
40 SequencedTaskTracker(); | |
41 | |
42 // Posts the non-nestable task |task|, and records its post event. | |
43 void PostWrappedNonNestableTask( | |
akalin
2012/03/26 18:44:08
the index (int i) should be a member of these func
Francois
2012/03/28 14:32:42
Please see my comment right at the bottom.
| |
44 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
45 const Closure& task); | |
46 | |
47 // Posts the nestable task |task|, and records its post event. | |
48 void PostWrappedNestableTask( | |
49 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
50 const Closure& task); | |
51 | |
52 // Posts the delayed non-nestable task |task|, and records its post event. | |
53 void PostWrappedDelayedNonNestableTask( | |
54 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
55 const Closure& task, | |
56 TimeDelta delay); | |
57 | |
58 // Posts |task_count| non-nestable tasks. | |
59 void PostNonNestableTasks( | |
60 const scoped_refptr<SequencedTaskRunner>& task_runner, | |
61 int task_count); | |
62 | |
63 const std::vector<TaskEvent>& GetTaskEvents() const; | |
64 | |
65 private: | |
66 friend class RefCountedThreadSafe<SequencedTaskTracker>; | |
67 | |
68 ~SequencedTaskTracker(); | |
69 | |
70 // A task which runs |task|, recording the start and end events. | |
71 void RunTask(const Closure& task, int task_i); | |
72 | |
73 // Records a post event for task |i|. The owner is expected to be holding | |
74 // |lock_| (unlike |TaskStarted| and |TaskEnded|). | |
75 void TaskPosted(int i); | |
76 | |
77 // Records a start event for task |i|. | |
78 void TaskStarted(int i); | |
79 | |
80 // Records a end event for task |i|. | |
81 void TaskEnded(int i); | |
82 | |
83 // Protects events_ and next_post_i_. | |
akalin
2012/03/26 18:44:08
events_ only
Francois
2012/03/28 14:32:42
Please see my comment right at the bottom.
| |
84 Lock lock_; | |
85 | |
86 // The events as they occurred for each task (protected by lock_). | |
87 std::vector<TaskEvent> events_; | |
88 | |
89 // The ordinal to be used for the next task-posting task (protected by | |
90 // lock_). | |
91 int next_post_i_; | |
akalin
2012/03/26 18:44:08
remove the need for this, since the index should b
Francois
2012/03/28 14:32:42
Please see my comment right at the bottom.
| |
92 | |
93 DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker); | |
94 }; | |
95 | |
96 void PrintTo(const SequencedTaskTracker::TaskEvent& event, std::ostream* os); | |
97 | |
98 void SleepForOneSecond(); | |
99 | |
100 // Checks the non-nestable task invariants for all tasks in |events|. | |
101 // | |
102 // The invariants are: | |
103 // 1) Events started and ended in the same order that they were posted. | |
104 // 2) Events for an individual tasks occur in the order {POST, START, END}, | |
105 // and there is only one instance of each event type for a task. | |
106 // 3) The only events between a task's START and END events are the POSTs of | |
107 // other tasks. I.e. tasks were run sequentially, not interleaved. | |
108 ::testing::AssertionResult CheckNonNestableInvariants( | |
109 const std::vector<SequencedTaskTracker::TaskEvent>& events, | |
110 int task_count); | |
111 | |
112 } // namespace internal | |
113 | |
114 template <typename TaskRunnerTestDelegate> | |
115 class SequencedTaskRunnerTest : public testing::Test { | |
116 protected: | |
117 SequencedTaskRunnerTest() | |
118 : task_tracker_(new internal::SequencedTaskTracker()) {} | |
119 | |
120 const scoped_refptr<internal::SequencedTaskTracker> task_tracker_; | |
121 TaskRunnerTestDelegate delegate_; | |
122 }; | |
123 | |
124 TYPED_TEST_CASE_P(SequencedTaskRunnerTest); | |
125 | |
126 // This test posts N non-nestable tasks in sequence, and expects them to run | |
127 // in FIFO order, with no part of any two tasks' execution | |
128 // overlapping. I.e. that each task starts only after the previously-posted | |
129 // one has finished. | |
130 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) { | |
131 const int task_count = 1000; | |
132 | |
133 this->delegate_.StartTaskRunner(); | |
134 const scoped_refptr<SequencedTaskRunner> task_runner = | |
135 this->delegate_.GetTaskRunner(); | |
136 | |
137 this->task_tracker_->PostWrappedNonNestableTask( | |
138 task_runner, Bind(&internal::SleepForOneSecond)); | |
akalin
2012/03/26 18:44:08
with the change above to pass i to PostWrappedNonN
Francois
2012/03/28 14:32:42
Please see my comment right at the bottom.
| |
139 for (int i = 1; i < task_count; ++i) { | |
140 this->task_tracker_->PostWrappedNonNestableTask(task_runner, Closure()); | |
141 } | |
142 | |
143 this->delegate_.StopTaskRunner(); | |
144 | |
145 EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(), | |
146 task_count)); | |
147 } | |
148 | |
149 // This test posts N nestable tasks in sequence. It has the same expectations | |
150 // as SequentialNonNestable because even though the tasks are nestable, they | |
151 // will not be run nestedly in this case. | |
152 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) { | |
153 const int task_count = 1000; | |
154 | |
155 this->delegate_.StartTaskRunner(); | |
156 const scoped_refptr<SequencedTaskRunner> task_runner = | |
157 this->delegate_.GetTaskRunner(); | |
158 | |
159 this->task_tracker_->PostWrappedNestableTask( | |
160 task_runner, | |
161 Bind(&internal::SleepForOneSecond)); | |
162 for (int i = 1; i < task_count; ++i) { | |
163 this->task_tracker_->PostWrappedNestableTask(task_runner, Closure()); | |
164 } | |
165 | |
166 this->delegate_.StopTaskRunner(); | |
167 | |
168 EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(), | |
169 task_count)); | |
170 } | |
171 | |
172 // This test posts non-nestable tasks in order of increasing delay, and checks | |
173 // that that the tasks are run in FIFO order and that there is no execution | |
174 // overlap whatsoever between any two tasks. | |
175 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) { | |
176 if (!this->delegate_.TaskRunnerHandlesNonZeroDelays()) { | |
177 DLOG(INFO) << "This SequencedTaskRunner doesn't handle " | |
178 "non-zero delays; skipping"; | |
179 return; | |
180 } | |
181 | |
182 const int task_count = 20; | |
183 const int delay_increment_ms = 50; | |
184 | |
185 this->delegate_.StartTaskRunner(); | |
186 const scoped_refptr<SequencedTaskRunner> task_runner = | |
187 this->delegate_.GetTaskRunner(); | |
188 | |
189 for (int i = 0; i < task_count; ++i) { | |
190 this->task_tracker_->PostWrappedDelayedNonNestableTask( | |
191 task_runner, | |
192 Closure(), | |
193 TimeDelta::FromMilliseconds(delay_increment_ms * i)); | |
194 } | |
195 | |
196 this->delegate_.StopTaskRunner(); | |
197 | |
198 EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(), | |
199 task_count)); | |
200 } | |
201 | |
202 // This test posts a fast, non-nestable task from within each of a number of | |
203 // slow, non-nestable tasks and checks that they all run in the sequence they | |
204 // were posted in and that there is no execution overlap whatsoever. | |
205 TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) { | |
206 const int parent_count = 10; | |
207 const int children_per_parent = 10; | |
208 | |
209 this->delegate_.StartTaskRunner(); | |
210 const scoped_refptr<SequencedTaskRunner> task_runner = | |
211 this->delegate_.GetTaskRunner(); | |
212 | |
213 const int end = parent_count; | |
214 for (int i = 0; i < end; ++i) { | |
215 Closure task = Bind( | |
216 &internal::SequencedTaskTracker::PostNonNestableTasks, | |
217 this->task_tracker_, | |
218 task_runner, | |
219 children_per_parent); | |
akalin
2012/03/26 18:44:08
probably would have to pass in a start/end index f
Francois
2012/03/28 14:32:42
This won't work for tests (such as NonNestablePost
| |
220 this->task_tracker_->PostWrappedNonNestableTask(task_runner, task); | |
221 } | |
222 | |
223 this->delegate_.StopTaskRunner(); | |
224 | |
225 EXPECT_TRUE(CheckNonNestableInvariants( | |
226 this->task_tracker_->GetTaskEvents(), | |
227 parent_count * (children_per_parent + 1))); | |
228 } | |
229 | |
230 // TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs | |
231 // some tasked nestedly (which should be implemented in the test | |
232 // delegate). Also add, to the the test delegate, a predicate which checks | |
233 // whether the implementation supports nested tasks. | |
234 // | |
235 | |
236 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest, | |
237 SequentialNonNestable, | |
238 SequentialNestable, | |
239 SequentialDelayedNonNestable, | |
240 NonNestablePostFromNonNestableTask); | |
241 | |
242 } // namespace base | |
243 | |
244 #endif // BASE_TASK_RUNNER_TEST_TEMPLATE_H_ | |
OLD | NEW |