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

Side by Side Diff: base/task_scheduler/task_tracker_unittest.cc

Issue 1705943002: TaskScheduler [5/9] Task Tracker (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@s_3_pq
Patch Set: expand tests Created 4 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
OLDNEW
(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 <queue>
8
9 #include "base/bind.h"
10 #include "base/macros.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/task_scheduler/task.h"
14 #include "base/task_scheduler/task_traits.h"
15 #include "base/threading/platform_thread.h"
16 #include "base/threading/simple_thread.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace base {
20 namespace internal {
21
22 namespace {
23
24 class ThreadCallingShutdown : public SimpleThread {
25 public:
26 explicit ThreadCallingShutdown(TaskTracker* tracker)
27 : SimpleThread("ThreadCallingShutdown"),
28 tracker_(tracker),
29 has_returned_(false) {}
30
31 // Returns true once the call to Shutdown() has returned.
32 bool has_returned() const { return has_returned_; }
33
34 private:
35 void Run() override {
36 tracker_->Shutdown();
37 has_returned_ = true;
38 }
39
40 TaskTracker* const tracker_;
41 bool has_returned_;
42
43 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown);
44 };
45
46 class TaskSchedulerTaskTrackerTest
47 : public testing::Test,
48 public ::testing::WithParamInterface<TaskShutdownBehavior> {
gab 2016/03/09 21:53:25 You can use testing::TestWithParam<TaskShutdownBeh
fdoray 2016/03/15 17:28:09 Done.
49 public:
50 TaskSchedulerTaskTrackerTest() : num_tasks_executed_(0) {}
gab 2016/03/09 21:53:25 Can initialize member inline now with C++11 :-) (
fdoray 2016/03/15 17:28:09 Done.
51
52 // Creates a task with |shutdown_behavior|.
53 scoped_ptr<Task> CreateTask(TaskShutdownBehavior shutdown_behavior) {
54 return make_scoped_ptr(new Task(
55 FROM_HERE,
56 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
57 TaskTraits().WithShutdownBehavior(shutdown_behavior)));
58 }
59
60 // Tries to post |task| via |tracker_|. If |tracker_| approves the operation,
61 // |task| is added to |posted_tasks_|.
62 void PostTaskViaTracker(scoped_ptr<Task> task) {
63 tracker_.PostTask(
64 Bind(&TaskSchedulerTaskTrackerTest::PostTaskCallback, Unretained(this)),
65 std::move(task));
66 }
67
68 void RunNextPostedTaskViaTracker() {
gab 2016/03/09 21:53:25 All methods but this one can move to "protected" I
fdoray 2016/03/15 17:28:09 Done.
69 ASSERT_FALSE(posted_tasks_.empty());
70 tracker_.RunTask(posted_tasks_.front().get());
71 posted_tasks_.pop();
72 }
73
74 // Calls tracker_->Shutdown() on a new thread. When this returns, the
75 // Shutdown() method has been entered on the new thread, but it hasn't
76 // necessarily returned.
77 void CallShutdownAsync() {
78 DCHECK(!thread_calling_shutdown_.get());
79 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_));
80 thread_calling_shutdown_->Start();
81 while (!tracker_.is_shutting_down_for_testing() &&
82 !tracker_.shutdown_completed()) {
83 PlatformThread::YieldCurrentThread();
84 }
85 }
86
87 void JoinAndExpectShutdownAsyncHasReturned() {
gab 2016/03/09 21:53:25 JoinAndExpectAsyncShutdownCompleted() ?
fdoray 2016/03/15 17:28:09 Done. Called it WaitForAsyncShutdownCompleted as y
88 DCHECK(thread_calling_shutdown_.get());
89 thread_calling_shutdown_->Join();
90 EXPECT_TRUE(thread_calling_shutdown_->has_returned());
91 EXPECT_TRUE(tracker_.shutdown_completed());
92 }
93
94 void ExpectShutdownAsyncHasNotReturned() {
gab 2016/03/09 21:53:25 VerifyAsyncShutdownInProgress()?
fdoray 2016/03/15 17:28:09 Done.
95 DCHECK(thread_calling_shutdown_.get());
96 EXPECT_FALSE(thread_calling_shutdown_->has_returned());
gab 2016/03/09 21:53:25 Add EXPECT_TRUE(tracker_.is_shutting_down_for_test
fdoray 2016/03/15 17:28:09 Done.
97 EXPECT_FALSE(tracker_.shutdown_completed());
98 }
99
100 protected:
101 TaskTracker tracker_;
102 size_t num_tasks_executed_;
103 std::queue<scoped_ptr<Task>> posted_tasks_;
104
105 private:
106 void PostTaskCallback(scoped_ptr<Task> task) {
107 posted_tasks_.push(std::move(task));
108 }
109
110 void RunTaskCallback() { ++num_tasks_executed_; }
111
112 scoped_ptr<ThreadCallingShutdown> thread_calling_shutdown_;
113
114 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
115 };
116
117 // A thread which calls
118 // TaskSchedulerTaskTrackerTest::RunNextPostedTaskViaTracker() asynchronously.
119 class ThreadRunningNextPostedTask : public SimpleThread {
120 public:
121 explicit ThreadRunningNextPostedTask(TaskSchedulerTaskTrackerTest* test)
122 : SimpleThread("ThreadRunningNextPostedTask"), test_(test) {}
123
124 private:
125 void Run() override { test_->RunNextPostedTaskViaTracker(); }
126
127 TaskSchedulerTaskTrackerTest* const test_;
128
129 DISALLOW_COPY_AND_ASSIGN(ThreadRunningNextPostedTask);
130 };
131
132 } // namespace
133
134 // This test is repeated for each TaskShutownBehavior.
135 TEST_P(TaskSchedulerTaskTrackerTest, PostAndRunBeforeShutdown) {
robliao 2016/03/09 22:31:46 If the parametrized tests are like the ones here (
fdoray 2016/03/15 17:28:09 Every test is parameterized now.
136 scoped_ptr<Task> task_to_post(CreateTask(GetParam()));
137 const Task* task_to_post_raw = task_to_post.get();
138
139 // Post the task.
140 EXPECT_TRUE(posted_tasks_.empty());
141 PostTaskViaTracker(std::move(task_to_post));
142 ASSERT_FALSE(posted_tasks_.empty());
143 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
144
145 // Run the posted task.
146 EXPECT_EQ(0U, num_tasks_executed_);
147 RunNextPostedTaskViaTracker();
148 EXPECT_EQ(1U, num_tasks_executed_);
149
150 // Shutdown() shouldn't block.
151 tracker_.Shutdown();
152 }
153
154 TEST_F(TaskSchedulerTaskTrackerTest,
155 PostAndRunLongTaskBeforeShutdown_ContinueOnShutdown) {
156 // Post a CONTINUE_ON_SHUTDOWN task that will block until |event| is signaled.
157 EXPECT_TRUE(posted_tasks_.empty());
158 WaitableEvent event(false, false);
159 PostTaskViaTracker(make_scoped_ptr(
160 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
161 TaskTraits().WithShutdownBehavior(
162 TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))));
163 ASSERT_FALSE(posted_tasks_.empty());
gab 2016/03/09 21:53:25 Even better than verifying !empty() IMO here and e
fdoray 2016/03/15 17:28:09 Done.
164
165 // Run the task asynchronouly.
166 ThreadRunningNextPostedTask thread(this);
167 thread.Start();
168
169 // Shutdown() shouldn't block.
170 tracker_.Shutdown();
171
172 // Unblock the task.
173 event.Signal();
174 thread.Join();
175 }
176
177 TEST_F(TaskSchedulerTaskTrackerTest,
178 PostAndRunLongTaskBeforeShutdown_SkipOnShutdown) {
179 // Post a SKIP_ON_SHUTDOWN task that will block until |event| is signaled.
180 EXPECT_TRUE(posted_tasks_.empty());
181 WaitableEvent event(false, false);
182 PostTaskViaTracker(make_scoped_ptr(
183 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
184 TaskTraits().WithShutdownBehavior(
185 TaskShutdownBehavior::SKIP_ON_SHUTDOWN))));
186 ASSERT_FALSE(posted_tasks_.empty());
187
188 // Run the task asynchronouly.
189 ThreadRunningNextPostedTask thread(this);
190 thread.Start();
191
192 // Shutdown() should block until the task has completed its execution.
193 CallShutdownAsync();
194 ExpectShutdownAsyncHasNotReturned();
195
196 // Unblock the task.
197 event.Signal();
198 thread.Join();
199
200 // Shutdown() should now return.
201 JoinAndExpectShutdownAsyncHasReturned();
202 }
203
204 TEST_F(TaskSchedulerTaskTrackerTest,
205 PostAndRunLongTaskBeforeShutdown_BlockShutdown) {
206 // Post a BLOCK_SHUTDOWN task that will block until |event| is signaled.
207 EXPECT_TRUE(posted_tasks_.empty());
208 WaitableEvent event(false, false);
209 PostTaskViaTracker(make_scoped_ptr(
210 new Task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)),
211 TaskTraits().WithShutdownBehavior(
212 TaskShutdownBehavior::BLOCK_SHUTDOWN))));
213 ASSERT_FALSE(posted_tasks_.empty());
214
215 // Run the task asynchronouly.
216 ThreadRunningNextPostedTask thread(this);
217 thread.Start();
218
219 // Shutdown() should block until the task has completed its execution.
220 CallShutdownAsync();
221 ExpectShutdownAsyncHasNotReturned();
222
223 // Unblock the task.
224 event.Signal();
225 thread.Join();
226
227 // Shutdown() should now return.
228 JoinAndExpectShutdownAsyncHasReturned();
229 }
gab 2016/03/09 21:53:25 I'm surprised mixing TEST_F with TEST_P even works
fdoray 2016/03/15 17:28:09 Done.
230
231 TEST_F(TaskSchedulerTaskTrackerTest,
gab 2016/03/09 21:53:25 Same thing as above for all remaining TEST_F's, tr
fdoray 2016/03/15 17:28:09 Done.
232 PostBeforeShutdownRunDuringShutdown_ContinueOnShutdown) {
233 scoped_ptr<Task> task_to_post(
234 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
235 const Task* task_to_post_raw = task_to_post.get();
236
237 // Post the task.
238 EXPECT_TRUE(posted_tasks_.empty());
239 PostTaskViaTracker(std::move(task_to_post));
240 ASSERT_FALSE(posted_tasks_.empty());
241 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
242
243 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
244 // asynchronously.
245 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
246 CallShutdownAsync();
247 ExpectShutdownAsyncHasNotReturned();
248
249 // Try to run task posted at the beginning of this test. It should not work.
250 EXPECT_EQ(0U, num_tasks_executed_);
251 RunNextPostedTaskViaTracker();
252 EXPECT_EQ(0U, num_tasks_executed_);
253 ExpectShutdownAsyncHasNotReturned();
254
255 // Unblock shutdown by running the BLOCK_SHUTDOWN task.
256 RunNextPostedTaskViaTracker();
257 EXPECT_EQ(1U, num_tasks_executed_);
258 JoinAndExpectShutdownAsyncHasReturned();
259 }
260
261 TEST_F(TaskSchedulerTaskTrackerTest,
262 PostBeforeShutdownRunDuringShutdown_SkipOnShutdown) {
263 scoped_ptr<Task> task_to_post(
264 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
265 const Task* task_to_post_raw = task_to_post.get();
266
267 // Post the task.
268 EXPECT_TRUE(posted_tasks_.empty());
269 PostTaskViaTracker(std::move(task_to_post));
270 ASSERT_FALSE(posted_tasks_.empty());
271 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
272
273 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
274 // asynchronously.
275 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
276 CallShutdownAsync();
277 ExpectShutdownAsyncHasNotReturned();
278
279 // Try to run task posted at the beginning of this test. It should not work.
280 EXPECT_EQ(0U, num_tasks_executed_);
281 RunNextPostedTaskViaTracker();
282 EXPECT_EQ(0U, num_tasks_executed_);
283 ExpectShutdownAsyncHasNotReturned();
284
285 // Unblock shutdown by running the BLOCK_SHUTDOWN task.
286 RunNextPostedTaskViaTracker();
287 EXPECT_EQ(1U, num_tasks_executed_);
288 JoinAndExpectShutdownAsyncHasReturned();
289 }
290
291 TEST_F(TaskSchedulerTaskTrackerTest,
292 PostBeforeShutdownRunDuringShutdown_BlockShutdown) {
293 scoped_ptr<Task> task_to_post(
294 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
295 const Task* task_to_post_raw = task_to_post.get();
296
297 // Post the task.
298 EXPECT_TRUE(posted_tasks_.empty());
299 PostTaskViaTracker(std::move(task_to_post));
300 ASSERT_FALSE(posted_tasks_.empty());
301 EXPECT_EQ(task_to_post_raw, posted_tasks_.front().get());
302
303 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
304 // asynchronously.
305 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
306 CallShutdownAsync();
307 ExpectShutdownAsyncHasNotReturned();
308
309 // Try to run the first task posted in this test. It should run successfully.
310 EXPECT_EQ(0U, num_tasks_executed_);
311 RunNextPostedTaskViaTracker();
312 EXPECT_EQ(1U, num_tasks_executed_);
313 ExpectShutdownAsyncHasNotReturned();
314
315 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task.
316 RunNextPostedTaskViaTracker();
317 EXPECT_EQ(2U, num_tasks_executed_);
318 JoinAndExpectShutdownAsyncHasReturned();
319 }
320
321 TEST_F(TaskSchedulerTaskTrackerTest,
322 PostBeforeShutdownRunAfterShutdown_ContinueOnShutdown) {
323 scoped_ptr<Task> task_to_post(
324 CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
325 const Task* task_to_post_raw = task_to_post.get();
326
327 // Post the task.
328 EXPECT_TRUE(posted_tasks_.empty());
329 PostTaskViaTracker(std::move(task_to_post));
330 ASSERT_FALSE(posted_tasks_.empty());
331 ASSERT_EQ(task_to_post_raw, posted_tasks_.front().get());
332
333 // This should return immediately.
334 tracker_.Shutdown();
335
336 // The task shouldn't be allowed to run.
337 EXPECT_EQ(0U, num_tasks_executed_);
338 RunNextPostedTaskViaTracker();
339 EXPECT_EQ(0U, num_tasks_executed_);
340 }
341
342 TEST_F(TaskSchedulerTaskTrackerTest,
343 PostBeforeShutdownRunAfterShutdown_SkipOnShutdown) {
344 scoped_ptr<Task> task_to_post(
345 CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
346 const Task* task_to_post_raw = task_to_post.get();
347
348 // Post the task.
349 EXPECT_TRUE(posted_tasks_.empty());
350 PostTaskViaTracker(std::move(task_to_post));
351 ASSERT_FALSE(posted_tasks_.empty());
352 ASSERT_EQ(task_to_post_raw, posted_tasks_.front().get());
353
354 // This should return immediately.
355 tracker_.Shutdown();
356
357 // The task shouldn't be allowed to run.
358 EXPECT_EQ(0U, num_tasks_executed_);
359 RunNextPostedTaskViaTracker();
360 EXPECT_EQ(0U, num_tasks_executed_);
361 }
362
363 // It isn't possible to test running after shutdown a task that has been posted
364 // before shutdown because Shutdown() won't return until the task has been
365 // executed.
366
367 TEST_F(TaskSchedulerTaskTrackerTest, RunAfterShutdown_BlockShutdown) {
368 tracker_.Shutdown();
369 EXPECT_DEBUG_DEATH(
370 tracker_.RunTask(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN).get()),
371 "");
372 }
373
374 TEST_F(TaskSchedulerTaskTrackerTest,
375 PostAndRunDuringShutdown_ContinueOnShutdown) {
376 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
377 // asynchronously.
378 EXPECT_TRUE(posted_tasks_.empty());
379 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
380 EXPECT_EQ(1U, posted_tasks_.size());
381 CallShutdownAsync();
382 ExpectShutdownAsyncHasNotReturned();
383
384 // Try to post a CONTINUE_ON_SHUTDOWN task via |tracker_|. This should fail.
385 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
386 EXPECT_EQ(1U, posted_tasks_.size());
387
388 // Don't try to run the task, because it hasn't been posted successfully.
389
390 // Unblock shutdown by running the BLOCK_SHUTDOWN task.
391 ExpectShutdownAsyncHasNotReturned();
392 EXPECT_EQ(0U, num_tasks_executed_);
393 RunNextPostedTaskViaTracker();
394 EXPECT_EQ(1U, num_tasks_executed_);
395 JoinAndExpectShutdownAsyncHasReturned();
396 }
397
398 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_SkipOnShutdown) {
399 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
400 // asynchronously.
401 EXPECT_TRUE(posted_tasks_.empty());
402 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
403 EXPECT_EQ(1U, posted_tasks_.size());
404 CallShutdownAsync();
405 ExpectShutdownAsyncHasNotReturned();
406
407 // Try to post a SKIP_ON_SHUTDOWN task via |tracker_|. This should fail.
408 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
409 EXPECT_EQ(1U, posted_tasks_.size());
410
411 // Don't try to run the task, because it hasn't been posted successfully.
412
413 // Unblock shutdown by running the BLOCK_SHUTDOWN task.
414 ExpectShutdownAsyncHasNotReturned();
415 EXPECT_EQ(0U, num_tasks_executed_);
416 RunNextPostedTaskViaTracker();
417 EXPECT_EQ(1U, num_tasks_executed_);
418 JoinAndExpectShutdownAsyncHasReturned();
419 }
420
421 TEST_F(TaskSchedulerTaskTrackerTest, PostAndRunDuringShutdown_BlockShutdown) {
422 // Post a BLOCK_SHUTDOWN task just to block shutdown. Then, call Shutdown()
423 // asynchronously.
424 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
425 scoped_ptr<Task> block_shutdown_task = std::move(posted_tasks_.front());
426 posted_tasks_.pop();
427 CallShutdownAsync();
428 ExpectShutdownAsyncHasNotReturned();
429
430 // Try to post a BLOCK_SHUTDOWN task via |tracker_|. This should succeed.
431 EXPECT_TRUE(posted_tasks_.empty());
432 PostTaskViaTracker(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN));
433 EXPECT_EQ(1U, posted_tasks_.size());
434
435 // Try to run the task that was just posted. This should succeed.
436 EXPECT_EQ(0U, num_tasks_executed_);
437 RunNextPostedTaskViaTracker();
438 EXPECT_EQ(1U, num_tasks_executed_);
439
440 // Unblock shutdown by running the BLOCK_SHUTDOWN task posted at the beginning
441 // of the test.
442 ExpectShutdownAsyncHasNotReturned();
443 tracker_.RunTask(block_shutdown_task.get());
444 EXPECT_EQ(2U, num_tasks_executed_);
445 JoinAndExpectShutdownAsyncHasReturned();
446 }
447
448 // This test is repeated for each TaskShutownBehavior.
449 TEST_P(TaskSchedulerTaskTrackerTest, PostAfterShutdown) {
450 // It is not possible to post a task after shutdown.
451 tracker_.Shutdown();
452 EXPECT_TRUE(posted_tasks_.empty());
453 PostTaskViaTracker(CreateTask(GetParam()));
454 EXPECT_TRUE(posted_tasks_.empty());
455 }
456
457 INSTANTIATE_TEST_CASE_P(
458 ContinueOnShutdown,
459 TaskSchedulerTaskTrackerTest,
460 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
461 INSTANTIATE_TEST_CASE_P(
462 SkipOnShutdown,
463 TaskSchedulerTaskTrackerTest,
464 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
465 INSTANTIATE_TEST_CASE_P(
466 BlockShutdown,
467 TaskSchedulerTaskTrackerTest,
468 ::testing::Values(TaskShutdownBehavior::BLOCK_SHUTDOWN));
gab 2016/03/09 21:53:26 Oh nice, first time I see someone do it this way (
fdoray 2016/03/15 17:28:09 Acknowledged.
469
470 } // namespace internal
471 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698