OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 #include "base/task_scheduler/task_tracker.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/macros.h" | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "base/task_scheduler/task.h" | |
11 #include "base/task_scheduler/task_traits.h" | |
12 #include "base/threading/platform_thread.h" | |
13 #include "base/threading/simple_thread.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 | |
16 namespace base { | |
robliao
2016/03/01 22:29:42
I think you need a test case where we block shutdo
fdoray
2016/03/02 00:38:41
Done. PostAndRunBlockedContinueOnShutdownTaskBefor
| |
17 namespace internal { | |
18 | |
19 namespace { | |
20 | |
21 class ThreadCallingShutdown : public SimpleThread { | |
22 public: | |
23 explicit ThreadCallingShutdown(TaskTracker* tracker) | |
24 : SimpleThread("ThreadCallingShutdown"), | |
25 tracker_(tracker), | |
26 has_returned_(false) {} | |
27 | |
28 // Returns true once the call to Shutdown() has returned. | |
29 bool has_returned() const { return has_returned_; } | |
30 | |
31 private: | |
32 void Run() override { | |
33 tracker_->Shutdown(); | |
34 has_returned_ = true; | |
35 } | |
36 | |
37 TaskTracker* tracker_; | |
38 bool has_returned_; | |
39 | |
40 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown); | |
41 }; | |
42 | |
43 class TaskSchedulerTaskTrackerTest : public testing::Test { | |
44 protected: | |
45 TaskSchedulerTaskTrackerTest() : num_run_tasks_(0) {} | |
46 | |
47 // Creates a task with |shutdown_behavior|. | |
48 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) { | |
49 return make_scoped_ptr(new Task( | |
50 FROM_HERE, | |
51 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)), | |
52 TaskTraits().WithShutdownBehavior(shutdown_behavior))); | |
53 } | |
54 | |
55 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation, | |
56 // returns the posted task. Otherwise, returns nullptr. | |
57 scoped_ptr<Task> PostTaskViaTracker(scoped_ptr<Task> task) { | |
58 scoped_ptr<Task> posted_task; | |
59 tracker_.PostTask(Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, | |
60 Unretained(this), &posted_task), | |
61 std::move(task)); | |
62 return posted_task; | |
gab
2016/03/01 22:18:47
This feels very weird... how about instead have a
fdoray
2016/03/02 00:38:41
Done. I now use an std::queue.
| |
63 } | |
64 | |
65 // Calls tracker_->Shutdown() on a new thread. When this returns, the | |
66 // Shutdown() method has been entered on the new thread, but it hasn't | |
67 // necessarily returned. | |
68 void CallShutdownAsync() { | |
69 DCHECK(!thread_calling_shutdown_.get()); | |
70 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_)); | |
71 thread_calling_shutdown_->Start(); | |
72 while (!tracker_.is_shutting_down_for_testing() && | |
73 !tracker_.shutdown_completed()) { | |
74 PlatformThread::YieldCurrentThread(); | |
75 } | |
76 } | |
77 | |
78 void ExpectShutdownAsyncHasReturned() { | |
79 DCHECK(thread_calling_shutdown_.get()); | |
80 thread_calling_shutdown_->Join(); | |
robliao
2016/03/01 22:29:42
It would be unexpected to join with the duality be
fdoray
2016/03/02 00:38:41
Done.
| |
81 EXPECT_TRUE(thread_calling_shutdown_->has_returned()); | |
82 EXPECT_TRUE(tracker_.shutdown_completed()); | |
83 } | |
84 | |
85 void ExpectShutdownAsyncHasNotReturned() { | |
86 DCHECK(thread_calling_shutdown_.get()); | |
87 EXPECT_FALSE(thread_calling_shutdown_->has_returned()); | |
88 EXPECT_FALSE(tracker_.shutdown_completed()); | |
89 } | |
90 | |
91 TaskTracker tracker_; | |
92 size_t num_run_tasks_; | |
gab
2016/03/01 22:18:47
num_tasks_executed_ ?
fdoray
2016/03/02 00:38:41
Done.
| |
93 | |
94 private: | |
95 void PostTaskCallback(scoped_ptr<Task>* out_task, scoped_ptr<Task> in_task) { | |
96 *out_task = std::move(in_task); | |
97 } | |
98 | |
99 void RunTaskCallback() { ++num_run_tasks_; } | |
100 | |
101 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_; | |
102 | |
103 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest); | |
104 }; | |
105 | |
106 } // namespace | |
107 | |
108 TEST_F(TaskSchedulerTaskTrackerTest, | |
109 PostAndRunBeforeShutdown_ContinueOnShutdown) { | |
110 scoped_ptr<Task> task_to_post( | |
111 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
112 const Task* task_to_post_raw = task_to_post.get(); | |
113 | |
114 // Post the task. | |
115 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
116 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
117 | |
118 // Run the posted task. | |
119 tracker_.RunTask(posted_task.get()); | |
120 EXPECT_EQ(1U, num_run_tasks_); | |
gab
2016/03/01 22:18:47
EXPECT_EQ(0U, ...); as well before RunTask()?
fdoray
2016/03/02 00:38:41
Done.
| |
121 | |
122 // Shutdown() shouldn't block. | |
123 tracker_.Shutdown(); | |
124 } | |
125 | |
126 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_SkipOnShutdown) { | |
127 scoped_ptr<Task> task_to_post( | |
128 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
129 const Task* task_to_post_raw = task_to_post.get(); | |
130 | |
131 // Post the task. | |
132 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
133 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
134 | |
135 // Run the posted task. | |
136 tracker_.RunTask(posted_task.get()); | |
137 EXPECT_EQ(1U, num_run_tasks_); | |
138 | |
139 // Shutdown() shouldn't block. | |
140 tracker_.Shutdown(); | |
141 } | |
142 | |
143 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown_BlockShutdown) { | |
144 scoped_ptr<Task> task_to_post( | |
145 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
146 const Task* task_to_post_raw = task_to_post.get(); | |
147 | |
148 // Post the task. | |
149 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
150 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
151 | |
152 // Run the posted task. | |
153 tracker_.RunTask(posted_task.get()); | |
154 EXPECT_EQ(1U, num_run_tasks_); | |
155 | |
156 // Shutdown() shouldn't block. | |
157 tracker_.Shutdown(); | |
158 } | |
159 | |
160 TEST_F(TaskSchedulerTaskTrackerTest, | |
161 PostBeforeShutdownRunDuringShutdown_ContinueOnShutdown) { | |
162 scoped_ptr<Task> task_to_post( | |
163 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
164 const Task* task_to_post_raw = task_to_post.get(); | |
165 | |
166 // Post the task. | |
167 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
168 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
169 | |
170 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
171 // asynchronously. | |
172 scoped_ptr<Task> blocking_task( | |
173 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
174 CallShutdownAsync(); | |
175 ExpectShutdownAsyncHasNotReturned(); | |
176 | |
177 // Try to run |posted_task| via |tracker_|. It should not run. | |
178 tracker_.RunTask(posted_task.get()); | |
179 EXPECT_EQ(0U, num_run_tasks_); | |
180 ExpectShutdownAsyncHasNotReturned(); | |
181 | |
182 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
183 tracker_.RunTask(blocking_task.get()); | |
184 EXPECT_EQ(1U, num_run_tasks_); | |
185 ExpectShutdownAsyncHasReturned(); | |
186 } | |
187 | |
188 TEST_F(TaskSchedulerTaskTrackerTest, | |
189 PostBeforeShutdownRunDuringShutdown_SkipOnShutdown) { | |
190 scoped_ptr<Task> task_to_post( | |
191 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
192 const Task* task_to_post_raw = task_to_post.get(); | |
193 | |
194 // Post the task. | |
195 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
196 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
197 | |
198 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
199 // asynchronously. | |
200 scoped_ptr<Task> blocking_task( | |
201 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
202 CallShutdownAsync(); | |
203 ExpectShutdownAsyncHasNotReturned(); | |
204 | |
205 // Try to run |posted_task| via |tracker_|. It should not run. | |
206 tracker_.RunTask(posted_task.get()); | |
207 EXPECT_EQ(0U, num_run_tasks_); | |
208 ExpectShutdownAsyncHasNotReturned(); | |
209 | |
210 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
211 tracker_.RunTask(blocking_task.get()); | |
212 EXPECT_EQ(1U, num_run_tasks_); | |
213 ExpectShutdownAsyncHasReturned(); | |
214 } | |
215 | |
216 TEST_F(TaskSchedulerTaskTrackerTest, | |
217 PostBeforeShutdownRunDuringShutdown_BlockShutdown) { | |
218 scoped_ptr<Task> task_to_post( | |
219 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
220 const Task* task_to_post_raw = task_to_post.get(); | |
221 | |
222 // Post the task. | |
223 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
224 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
225 | |
226 // Call Shutdown() asynchronously. It should block before there is a pending | |
227 // BLOCK_SHUTDOWN task. | |
228 CallShutdownAsync(); | |
229 ExpectShutdownAsyncHasNotReturned(); | |
230 | |
231 // Run the posted task. | |
232 tracker_.RunTask(posted_task.get()); | |
233 EXPECT_EQ(1U, num_run_tasks_); | |
234 | |
235 // The async call to Shutdown() should now return. | |
236 ExpectShutdownAsyncHasReturned(); | |
237 } | |
238 | |
239 TEST_F(TaskSchedulerTaskTrackerTest, | |
240 PostBeforeShutdownRunAfterShutdown_ContinueOnShutdown) { | |
241 scoped_ptr<Task> task_to_post( | |
242 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
243 const Task* task_to_post_raw = task_to_post.get(); | |
244 | |
245 // Post the task. | |
246 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
247 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
248 | |
249 // A call to Shutdown() should return immediately. | |
250 tracker_.Shutdown(); | |
251 | |
252 // Try to run |posted_task| via |tracker_|. It should not run. | |
253 tracker_.RunTask(posted_task.get()); | |
254 EXPECT_EQ(0U, num_run_tasks_); | |
255 } | |
256 | |
257 TEST_F(TaskSchedulerTaskTrackerTest, | |
258 PostBeforeShutdownRunAfterShutdown_SkipOnShutdown) { | |
259 scoped_ptr<Task> task_to_post( | |
260 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
261 const Task* task_to_post_raw = task_to_post.get(); | |
262 | |
263 // Post the task. | |
264 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
265 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
266 | |
267 // A call to Shutdown() should return immediately. | |
268 tracker_.Shutdown(); | |
269 | |
270 // Try to run |posted_task| via |tracker_|. It should not run. | |
271 tracker_.RunTask(posted_task.get()); | |
272 EXPECT_EQ(0U, num_run_tasks_); | |
273 } | |
274 | |
275 TEST_F(TaskSchedulerTaskTrackerTest, | |
276 PostBeforeShutdownRunAfterShutdown_BlockShutdown) { | |
robliao
2016/03/01 22:29:42
I'm not sure this test should be here as it's not
fdoray
2016/03/02 00:38:41
Now I test that we get the expected failure with E
| |
277 // It is not possible to run after shutdown a BLOCK_SHUTDOWN task that has | |
278 // been posted before shutdown because Shutdown() won't return when there are | |
279 // pending BLOCK_SHUTDOWN tasks. | |
gab
2016/03/01 22:18:47
I think your code actually handles this (+ a DCHEC
fdoray
2016/03/02 00:38:41
Done.
| |
280 } | |
281 | |
282 TEST_F(TaskSchedulerTaskTrackerTest, | |
283 PostAndRunDuringShutdown_ContinueOnShutdown) { | |
284 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
285 // asynchronously. | |
286 scoped_ptr<Task> blocking_task( | |
287 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
288 CallShutdownAsync(); | |
289 ExpectShutdownAsyncHasNotReturned(); | |
290 | |
291 // Try to post a CONTINUE_ON_SHUTDOWN task via |tracker_|. It should not work. | |
292 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
293 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) | |
294 .get()); | |
295 | |
296 // Since |tracker_| hasn't allowed the task to be posted, it can't be run. | |
297 | |
298 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
299 ExpectShutdownAsyncHasNotReturned(); | |
300 tracker_.RunTask(blocking_task.get()); | |
301 EXPECT_EQ(1U, num_run_tasks_); | |
302 ExpectShutdownAsyncHasReturned(); | |
303 } | |
304 | |
305 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_SkipOnShutdown) { | |
306 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
307 // asynchronously. | |
308 scoped_ptr<Task> blocking_task( | |
309 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
310 CallShutdownAsync(); | |
311 ExpectShutdownAsyncHasNotReturned(); | |
312 | |
313 // Try to post a SKIP_ON_SHUTDOWN task via |tracker_|. It should not work. | |
314 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
315 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) | |
316 .get()); | |
317 | |
318 // Since |tracker_| hasn't allowed the task to be posted, it can't be run. | |
319 | |
320 // Unblock shutdown by running the BLOCK_SHUTDOWN task. | |
321 ExpectShutdownAsyncHasNotReturned(); | |
322 tracker_.RunTask(blocking_task.get()); | |
323 EXPECT_EQ(1U, num_run_tasks_); | |
324 ExpectShutdownAsyncHasReturned(); | |
325 } | |
326 | |
327 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_BlockShutdown) { | |
328 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown() | |
329 // asynchronously. | |
330 scoped_ptr<Task> blocking_task( | |
331 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN))); | |
332 CallShutdownAsync(); | |
333 ExpectShutdownAsyncHasNotReturned(); | |
334 | |
335 // Post a BLOCK_SHUTDOWN task via |tracker_|. | |
336 scoped_ptr<Task> task_to_post( | |
337 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
338 const Task* task_to_post_raw = task_to_post.get(); | |
339 scoped_ptr<Task> posted_task(PostTaskViaTracker(std::move(task_to_post))); | |
340 ASSERT_EQ(task_to_post_raw, posted_task.get()); | |
341 | |
342 // Run |posted_task| via |tracker_|. | |
343 tracker_.RunTask(posted_task.get()); | |
344 EXPECT_EQ(1U, num_run_tasks_); | |
345 ExpectShutdownAsyncHasNotReturned(); | |
346 | |
347 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning | |
348 // of the test. | |
349 tracker_.RunTask(blocking_task.get()); | |
350 EXPECT_EQ(2U, num_run_tasks_); | |
351 ExpectShutdownAsyncHasReturned(); | |
352 } | |
353 | |
354 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_ContinueOnShutdown) { | |
355 // It is not possible to post a task after shutdown. | |
356 tracker_.Shutdown(); | |
357 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
358 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)) | |
359 .get()); | |
360 } | |
361 | |
362 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_SkipOnShutdown) { | |
363 // It is not possible to post a task after shutdown. | |
364 tracker_.Shutdown(); | |
365 EXPECT_EQ(nullptr, PostTaskViaTracker( | |
366 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) | |
367 .get()); | |
368 } | |
369 | |
370 TEST_F(TaskSchedulerTaskTrackerTest, PostAfterShutdown_BlockShutdown) { | |
371 // It is not possible to post a task after shutdown. | |
372 tracker_.Shutdown(); | |
373 EXPECT_EQ(nullptr, | |
374 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)) | |
375 .get()); | |
376 } | |
gab
2016/03/01 22:18:47
To avoid the triad duplication for every test, how
robliao
2016/03/01 22:36:41
Duplication for tests should be okay. Given that w
fdoray
2016/03/02 00:38:41
I think it's a good idea to use a typed test to re
gab
2016/03/09 21:53:25
+1 to Francois' argument, readability is improved
| |
377 | |
378 } // namespace internal | |
379 } // namespace base | |
OLD | NEW |