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

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

Issue 2362253002: TaskScheduler: Add FlushForTesting(). (Closed)
Patch Set: self-review Created 4 years, 2 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
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/task_scheduler/task_tracker.h" 5 #include "base/task_scheduler/task_tracker.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/callback.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/macros.h" 15 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 16 #include "base/memory/ptr_util.h"
16 #include "base/memory/ref_counted.h" 17 #include "base/memory/ref_counted.h"
17 #include "base/sequence_token.h" 18 #include "base/sequence_token.h"
18 #include "base/sequenced_task_runner.h" 19 #include "base/sequenced_task_runner.h"
19 #include "base/single_thread_task_runner.h" 20 #include "base/single_thread_task_runner.h"
21 #include "base/synchronization/atomic_flag.h"
20 #include "base/synchronization/waitable_event.h" 22 #include "base/synchronization/waitable_event.h"
21 #include "base/task_scheduler/scheduler_lock.h" 23 #include "base/task_scheduler/scheduler_lock.h"
22 #include "base/task_scheduler/task.h" 24 #include "base/task_scheduler/task.h"
23 #include "base/task_scheduler/task_traits.h" 25 #include "base/task_scheduler/task_traits.h"
24 #include "base/test/gtest_util.h" 26 #include "base/test/gtest_util.h"
25 #include "base/test/test_simple_task_runner.h" 27 #include "base/test/test_simple_task_runner.h"
28 #include "base/test/test_timeouts.h"
26 #include "base/threading/platform_thread.h" 29 #include "base/threading/platform_thread.h"
27 #include "base/threading/sequenced_task_runner_handle.h" 30 #include "base/threading/sequenced_task_runner_handle.h"
28 #include "base/threading/simple_thread.h" 31 #include "base/threading/simple_thread.h"
29 #include "base/threading/thread_restrictions.h" 32 #include "base/threading/thread_restrictions.h"
30 #include "base/threading/thread_task_runner_handle.h" 33 #include "base/threading/thread_task_runner_handle.h"
31 #include "testing/gtest/include/gtest/gtest.h" 34 #include "testing/gtest/include/gtest/gtest.h"
32 35
33 namespace base { 36 namespace base {
34 namespace internal { 37 namespace internal {
35 38
36 namespace { 39 namespace {
37 40
38 constexpr size_t kLoadTestNumIterations = 100; 41 constexpr size_t kLoadTestNumIterations = 100;
39 42
40 // Calls TaskTracker::Shutdown() asynchronously. 43 // Invokes a closure asynchronously.
41 class ThreadCallingShutdown : public SimpleThread { 44 class CallbackThread : public SimpleThread {
42 public: 45 public:
43 explicit ThreadCallingShutdown(TaskTracker* tracker) 46 explicit CallbackThread(const Closure& closure)
44 : SimpleThread("ThreadCallingShutdown"), 47 : SimpleThread("CallbackThread"), closure_(closure) {}
45 tracker_(tracker),
46 has_returned_(WaitableEvent::ResetPolicy::MANUAL,
47 WaitableEvent::InitialState::NOT_SIGNALED) {}
48 48
49 // Returns true once the async call to Shutdown() has returned. 49 // Returns true once the async call to Shutdown() has returned.
danakj 2016/09/23 20:51:41 Comment needs updating
fdoray 2016/09/23 21:09:46 Done.
50 bool has_returned() { return has_returned_.IsSignaled(); } 50 bool has_returned() { return has_returned_.IsSet(); }
51 51
52 private: 52 private:
53 void Run() override { 53 void Run() override {
54 tracker_->Shutdown(); 54 closure_.Run();
55 has_returned_.Signal(); 55 has_returned_.Set();
56 } 56 }
57 57
58 TaskTracker* const tracker_; 58 const Closure closure_;
59 WaitableEvent has_returned_; 59 AtomicFlag has_returned_;
60 60
61 DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown); 61 DISALLOW_COPY_AND_ASSIGN(CallbackThread);
62 }; 62 };
63 63
64 class ThreadPostingAndRunningTask : public SimpleThread { 64 class ThreadPostingAndRunningTask : public SimpleThread {
65 public: 65 public:
66 enum class Action { 66 enum class Action {
67 WILL_POST, 67 WILL_POST,
68 RUN, 68 RUN,
69 WILL_POST_AND_RUN, 69 WILL_POST_AND_RUN,
70 }; 70 };
71 71
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 FROM_HERE, 124 FROM_HERE,
125 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)), 125 Bind(&TaskSchedulerTaskTrackerTest::RunTaskCallback, Unretained(this)),
126 TaskTraits().WithShutdownBehavior(shutdown_behavior), TimeDelta()); 126 TaskTraits().WithShutdownBehavior(shutdown_behavior), TimeDelta());
127 } 127 }
128 128
129 // Calls tracker_->Shutdown() on a new thread. When this returns, Shutdown() 129 // Calls tracker_->Shutdown() on a new thread. When this returns, Shutdown()
130 // method has been entered on the new thread, but it hasn't necessarily 130 // method has been entered on the new thread, but it hasn't necessarily
131 // returned. 131 // returned.
132 void CallShutdownAsync() { 132 void CallShutdownAsync() {
133 ASSERT_FALSE(thread_calling_shutdown_); 133 ASSERT_FALSE(thread_calling_shutdown_);
134 thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_)); 134 thread_calling_shutdown_.reset(new CallbackThread(
135 Bind(&TaskTracker::Shutdown, Unretained(&tracker_))));
135 thread_calling_shutdown_->Start(); 136 thread_calling_shutdown_->Start();
136 while (!tracker_.HasShutdownStarted()) 137 while (!tracker_.HasShutdownStarted())
137 PlatformThread::YieldCurrentThread(); 138 PlatformThread::YieldCurrentThread();
138 } 139 }
139 140
140 void WaitForAsyncIsShutdownComplete() { 141 void WaitForAsyncIsShutdownComplete() {
141 ASSERT_TRUE(thread_calling_shutdown_); 142 ASSERT_TRUE(thread_calling_shutdown_);
142 thread_calling_shutdown_->Join(); 143 thread_calling_shutdown_->Join();
143 EXPECT_TRUE(thread_calling_shutdown_->has_returned()); 144 EXPECT_TRUE(thread_calling_shutdown_->has_returned());
144 EXPECT_TRUE(tracker_.IsShutdownComplete()); 145 EXPECT_TRUE(tracker_.IsShutdownComplete());
145 } 146 }
146 147
147 void VerifyAsyncShutdownInProgress() { 148 void VerifyAsyncShutdownInProgress() {
148 ASSERT_TRUE(thread_calling_shutdown_); 149 ASSERT_TRUE(thread_calling_shutdown_);
149 EXPECT_FALSE(thread_calling_shutdown_->has_returned()); 150 EXPECT_FALSE(thread_calling_shutdown_->has_returned());
150 EXPECT_TRUE(tracker_.HasShutdownStarted()); 151 EXPECT_TRUE(tracker_.HasShutdownStarted());
151 EXPECT_FALSE(tracker_.IsShutdownComplete()); 152 EXPECT_FALSE(tracker_.IsShutdownComplete());
152 } 153 }
153 154
155 // Calls tracker_->FlushForTesting() on a new thread.
156 void CallFlushForTestingAsync() {
157 ASSERT_FALSE(thread_calling_flush_for_testing_);
158 thread_calling_flush_for_testing_.reset(new CallbackThread(
159 Bind(&TaskTracker::FlushForTesting, Unretained(&tracker_))));
160 thread_calling_flush_for_testing_->Start();
161 }
162
163 void WaitForAsyncFlushForTestingReturned() {
164 ASSERT_TRUE(thread_calling_flush_for_testing_);
165 thread_calling_flush_for_testing_->Join();
166 EXPECT_TRUE(thread_calling_flush_for_testing_->has_returned());
167 }
168
169 void VerifyAsyncFlushForTestingInProgress() {
170 ASSERT_TRUE(thread_calling_flush_for_testing_);
171 EXPECT_FALSE(thread_calling_flush_for_testing_->has_returned());
172 }
173
154 size_t NumTasksExecuted() { 174 size_t NumTasksExecuted() {
155 AutoSchedulerLock auto_lock(lock_); 175 AutoSchedulerLock auto_lock(lock_);
156 return num_tasks_executed_; 176 return num_tasks_executed_;
157 } 177 }
158 178
159 TaskTracker tracker_; 179 TaskTracker tracker_;
160 180
161 private: 181 private:
162 void RunTaskCallback() { 182 void RunTaskCallback() {
163 AutoSchedulerLock auto_lock(lock_); 183 AutoSchedulerLock auto_lock(lock_);
164 ++num_tasks_executed_; 184 ++num_tasks_executed_;
165 } 185 }
166 186
167 std::unique_ptr<ThreadCallingShutdown> thread_calling_shutdown_; 187 std::unique_ptr<CallbackThread> thread_calling_shutdown_;
188 std::unique_ptr<CallbackThread> thread_calling_flush_for_testing_;
168 189
169 // Synchronizes accesses to |num_tasks_executed_|. 190 // Synchronizes accesses to |num_tasks_executed_|.
170 SchedulerLock lock_; 191 SchedulerLock lock_;
171 192
172 size_t num_tasks_executed_ = 0; 193 size_t num_tasks_executed_ = 0;
173 194
174 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest); 195 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerTaskTrackerTest);
175 }; 196 };
176 197
177 #define WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED() \ 198 #define WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED() \
178 do { \ 199 do { \
179 SCOPED_TRACE(""); \ 200 SCOPED_TRACE(""); \
180 WaitForAsyncIsShutdownComplete(); \ 201 WaitForAsyncIsShutdownComplete(); \
181 } while (false) 202 } while (false)
182 203
183 #define VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS() \ 204 #define VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS() \
184 do { \ 205 do { \
185 SCOPED_TRACE(""); \ 206 SCOPED_TRACE(""); \
186 VerifyAsyncShutdownInProgress(); \ 207 VerifyAsyncShutdownInProgress(); \
187 } while (false) 208 } while (false)
188 209
210 #define WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED() \
211 do { \
212 SCOPED_TRACE(""); \
213 WaitForAsyncFlushForTestingReturned(); \
214 } while (false)
215
216 #define VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS() \
217 do { \
218 SCOPED_TRACE(""); \
219 VerifyAsyncFlushForTestingInProgress(); \
220 } while (false)
221
189 } // namespace 222 } // namespace
190 223
191 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) { 224 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) {
192 std::unique_ptr<Task> task(CreateTask(GetParam())); 225 std::unique_ptr<Task> task(CreateTask(GetParam()));
193 226
194 // Inform |task_tracker_| that |task| will be posted. 227 // Inform |task_tracker_| that |task| will be posted.
195 EXPECT_TRUE(tracker_.WillPostTask(task.get())); 228 EXPECT_TRUE(tracker_.WillPostTask(task.get()));
196 229
197 // Run the task. 230 // Run the task.
198 EXPECT_EQ(0U, NumTasksExecuted()); 231 EXPECT_EQ(0U, NumTasksExecuted());
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 // being set on it. 481 // being set on it.
449 std::unique_ptr<Task> verify_task( 482 std::unique_ptr<Task> verify_task(
450 new Task(FROM_HERE, Bind(&VerifyThreadTaskRunnerHandle, 483 new Task(FROM_HERE, Bind(&VerifyThreadTaskRunnerHandle,
451 base::Unretained(test_task_runner.get())), 484 base::Unretained(test_task_runner.get())),
452 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta())); 485 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()));
453 verify_task->single_thread_task_runner_ref = test_task_runner; 486 verify_task->single_thread_task_runner_ref = test_task_runner;
454 487
455 RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task)); 488 RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task));
456 } 489 }
457 490
491 TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingPendingDelayedTask) {
492 const Task delayed_task(FROM_HERE, Bind(&DoNothing),
493 TaskTraits().WithShutdownBehavior(GetParam()),
494 TimeDelta::FromDays(1));
495 tracker_.WillPostTask(&delayed_task);
496 // FlushForTesting() should return even if the delayed task didn't run.
497 tracker_.FlushForTesting();
498 }
499
500 TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingPendingUndelayedTask) {
501 const Task undelayed_task(FROM_HERE, Bind(&DoNothing),
502 TaskTraits().WithShutdownBehavior(GetParam()),
503 TimeDelta());
504 tracker_.WillPostTask(&undelayed_task);
505
506 // FlushForTesting() shouldn't return before the undelayed task runs.
507 CallFlushForTestingAsync();
508 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
509 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
510
511 // FlushForTesting() should return after the undelayed task runs.
512 tracker_.RunTask(&undelayed_task, SequenceToken::Create());
513 WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED();
514 }
515
516 TEST_P(TaskSchedulerTaskTrackerTest, PostTaskDuringFlushForTesting) {
517 const Task undelayed_task(FROM_HERE, Bind(&DoNothing),
518 TaskTraits().WithShutdownBehavior(GetParam()),
519 TimeDelta());
520 tracker_.WillPostTask(&undelayed_task);
521
522 // FlushForTesting() shouldn't return before the undelayed task runs.
523 CallFlushForTestingAsync();
524 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
525 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
526
527 // Simulate posting another undelayed task.
528 const Task other_undelayed_task(FROM_HERE, Bind(&DoNothing),
529 TaskTraits().WithShutdownBehavior(GetParam()),
530 TimeDelta());
531 tracker_.WillPostTask(&other_undelayed_task);
532
533 // Run the first undelayed task.
534 tracker_.RunTask(&undelayed_task, SequenceToken::Create());
535
536 // FlushForTesting() shouldn't return before the second undelayed task runs.
537 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
538 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
539
540 // FlushForTesting() should return after the second undelayed task runs.
541 tracker_.RunTask(&other_undelayed_task, SequenceToken::Create());
542 WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED();
543 }
544
545 TEST_P(TaskSchedulerTaskTrackerTest, RunDelayedTaskDuringFlushForTesting) {
546 // Simulate posting a delayed and an undelayed task.
547 const Task delayed_task(FROM_HERE, Bind(&DoNothing),
548 TaskTraits().WithShutdownBehavior(GetParam()),
549 TimeDelta::FromDays(1));
550 tracker_.WillPostTask(&delayed_task);
551 const Task undelayed_task(FROM_HERE, Bind(&DoNothing),
552 TaskTraits().WithShutdownBehavior(GetParam()),
553 TimeDelta());
554 tracker_.WillPostTask(&undelayed_task);
555
556 // FlushForTesting() shouldn't return before the undelayed task runs.
557 CallFlushForTestingAsync();
558 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
559 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
560
561 // Run the delayed task.
562 tracker_.RunTask(&delayed_task, SequenceToken::Create());
563
564 // FlushForTesting() shouldn't return since there is still a pending undelayed
565 // task.
566 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
567 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
568
569 // Run the undelayed task.
570 tracker_.RunTask(&undelayed_task, SequenceToken::Create());
571
572 // FlushForTesting() should now return.
573 WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED();
574 }
575
576 TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingAfterShutdown) {
577 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN)
578 return;
579
580 // Simulate posting a task.
581 const Task undelayed_task(FROM_HERE, Bind(&DoNothing),
582 TaskTraits().WithShutdownBehavior(GetParam()),
583 TimeDelta());
584 tracker_.WillPostTask(&undelayed_task);
585
586 // Shutdown() should return immediately since there are no pending
587 // BLOCK_SHUTDOWN tasks.
588 tracker_.Shutdown();
589
590 // FlushForTesting() should return immediately after shutdown, even if an
591 // undelayed task hasn't run.
592 tracker_.FlushForTesting();
593 }
594
595 TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlushForTesting) {
596 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN)
597 return;
598
599 // Simulate posting a task.
600 const Task undelayed_task(FROM_HERE, Bind(&DoNothing),
601 TaskTraits().WithShutdownBehavior(GetParam()),
602 TimeDelta());
603 tracker_.WillPostTask(&undelayed_task);
604
605 // FlushForTesting() shouldn't return before the undelayed task runs or
606 // shutdown completes.
607 CallFlushForTestingAsync();
608 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
609 VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS();
610
611 // Shutdown() should return immediately since there are no pending
612 // BLOCK_SHUTDOWN tasks.
613 tracker_.Shutdown();
614
615 // FlushForTesting() should now return, even if an undelayed task hasn't run.
616 WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED();
617 }
618
458 INSTANTIATE_TEST_CASE_P( 619 INSTANTIATE_TEST_CASE_P(
459 ContinueOnShutdown, 620 ContinueOnShutdown,
460 TaskSchedulerTaskTrackerTest, 621 TaskSchedulerTaskTrackerTest,
461 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); 622 ::testing::Values(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
462 INSTANTIATE_TEST_CASE_P( 623 INSTANTIATE_TEST_CASE_P(
463 SkipOnShutdown, 624 SkipOnShutdown,
464 TaskSchedulerTaskTrackerTest, 625 TaskSchedulerTaskTrackerTest,
465 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); 626 ::testing::Values(TaskShutdownBehavior::SKIP_ON_SHUTDOWN));
466 INSTANTIATE_TEST_CASE_P( 627 INSTANTIATE_TEST_CASE_P(
467 BlockShutdown, 628 BlockShutdown,
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 781
621 // Unblock shutdown by running |block_shutdown_task|. 782 // Unblock shutdown by running |block_shutdown_task|.
622 EXPECT_TRUE( 783 EXPECT_TRUE(
623 tracker_.RunTask(block_shutdown_task.get(), SequenceToken::Create())); 784 tracker_.RunTask(block_shutdown_task.get(), SequenceToken::Create()));
624 EXPECT_EQ(kLoadTestNumIterations + 1, NumTasksExecuted()); 785 EXPECT_EQ(kLoadTestNumIterations + 1, NumTasksExecuted());
625 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); 786 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED();
626 } 787 }
627 788
628 } // namespace internal 789 } // namespace internal
629 } // namespace base 790 } // namespace base
OLDNEW
« base/task_scheduler/task_tracker.h ('K') | « base/task_scheduler/task_tracker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698