Chromium Code Reviews| Index: base/task_scheduler/task_tracker_unittest.cc |
| diff --git a/base/task_scheduler/task_tracker_unittest.cc b/base/task_scheduler/task_tracker_unittest.cc |
| index b6c1c207d19087c16a4329b72a303426383853ff..31b51a76d98b656d6033faf34a0e5da4da78f228 100644 |
| --- a/base/task_scheduler/task_tracker_unittest.cc |
| +++ b/base/task_scheduler/task_tracker_unittest.cc |
| @@ -10,6 +10,7 @@ |
| #include <vector> |
| #include "base/bind.h" |
| +#include "base/callback.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ptr_util.h" |
| @@ -17,12 +18,14 @@ |
| #include "base/sequence_token.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/single_thread_task_runner.h" |
| +#include "base/synchronization/atomic_flag.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/task_scheduler/scheduler_lock.h" |
| #include "base/task_scheduler/task.h" |
| #include "base/task_scheduler/task_traits.h" |
| #include "base/test/gtest_util.h" |
| #include "base/test/test_simple_task_runner.h" |
| +#include "base/test/test_timeouts.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/threading/simple_thread.h" |
| @@ -37,28 +40,25 @@ namespace { |
| constexpr size_t kLoadTestNumIterations = 100; |
| -// Calls TaskTracker::Shutdown() asynchronously. |
| -class ThreadCallingShutdown : public SimpleThread { |
| +// Invokes a closure asynchronously. |
| +class CallbackThread : public SimpleThread { |
| public: |
| - explicit ThreadCallingShutdown(TaskTracker* tracker) |
| - : SimpleThread("ThreadCallingShutdown"), |
| - tracker_(tracker), |
| - has_returned_(WaitableEvent::ResetPolicy::MANUAL, |
| - WaitableEvent::InitialState::NOT_SIGNALED) {} |
| + explicit CallbackThread(const Closure& closure) |
| + : SimpleThread("CallbackThread"), closure_(closure) {} |
| // Returns true once the async call to Shutdown() has returned. |
| - bool has_returned() { return has_returned_.IsSignaled(); } |
| + bool has_returned() { return has_returned_.IsSet(); } |
| private: |
| void Run() override { |
| - tracker_->Shutdown(); |
| - has_returned_.Signal(); |
| + closure_.Run(); |
| + has_returned_.Set(); |
| } |
| - TaskTracker* const tracker_; |
| - WaitableEvent has_returned_; |
| + const Closure closure_; |
| + AtomicFlag has_returned_; |
| - DISALLOW_COPY_AND_ASSIGN(ThreadCallingShutdown); |
| + DISALLOW_COPY_AND_ASSIGN(CallbackThread); |
| }; |
| class ThreadPostingAndRunningTask : public SimpleThread { |
| @@ -131,7 +131,8 @@ class TaskSchedulerTaskTrackerTest |
| // returned. |
| void CallShutdownAsync() { |
| ASSERT_FALSE(thread_calling_shutdown_); |
| - thread_calling_shutdown_.reset(new ThreadCallingShutdown(&tracker_)); |
| + thread_calling_shutdown_.reset(new CallbackThread( |
| + Bind(&TaskTracker::Shutdown, Unretained(&tracker_)))); |
| thread_calling_shutdown_->Start(); |
| while (!tracker_.HasShutdownStarted()) |
| PlatformThread::YieldCurrentThread(); |
| @@ -151,6 +152,25 @@ class TaskSchedulerTaskTrackerTest |
| EXPECT_FALSE(tracker_.IsShutdownComplete()); |
| } |
| + // Calls tracker_->FlushForTesting() on a new thread. |
| + void CallFlushForTestingAsync() { |
| + ASSERT_FALSE(thread_calling_flush_for_testing_); |
| + thread_calling_flush_for_testing_.reset(new CallbackThread( |
| + Bind(&TaskTracker::FlushForTesting, Unretained(&tracker_)))); |
| + thread_calling_flush_for_testing_->Start(); |
| + } |
| + |
| + void WaitForAsyncFlushForTestingReturned() { |
| + ASSERT_TRUE(thread_calling_flush_for_testing_); |
| + thread_calling_flush_for_testing_->Join(); |
| + EXPECT_TRUE(thread_calling_flush_for_testing_->has_returned()); |
| + } |
| + |
| + void VerifyAsyncFlushForTestingInProgress() { |
| + ASSERT_TRUE(thread_calling_flush_for_testing_); |
| + EXPECT_FALSE(thread_calling_flush_for_testing_->has_returned()); |
| + } |
| + |
| size_t NumTasksExecuted() { |
| AutoSchedulerLock auto_lock(lock_); |
| return num_tasks_executed_; |
| @@ -164,7 +184,8 @@ class TaskSchedulerTaskTrackerTest |
| ++num_tasks_executed_; |
| } |
| - std::unique_ptr<ThreadCallingShutdown> thread_calling_shutdown_; |
| + std::unique_ptr<CallbackThread> thread_calling_shutdown_; |
| + std::unique_ptr<CallbackThread> thread_calling_flush_for_testing_; |
| // Synchronizes accesses to |num_tasks_executed_|. |
| SchedulerLock lock_; |
| @@ -186,6 +207,18 @@ class TaskSchedulerTaskTrackerTest |
| VerifyAsyncShutdownInProgress(); \ |
| } while (false) |
| +#define WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED() \ |
| + do { \ |
| + SCOPED_TRACE(""); \ |
| + WaitForAsyncFlushForTestingReturned(); \ |
| + } while (false) |
| + |
| +#define VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS() \ |
| + do { \ |
| + SCOPED_TRACE(""); \ |
| + VerifyAsyncFlushForTestingInProgress(); \ |
| + } while (false) |
| + |
| } // namespace |
| TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) { |
| @@ -455,6 +488,103 @@ TEST_P(TaskSchedulerTaskTrackerTest, |
| RunTaskRunnerHandleVerificationTask(&tracker_, std::move(verify_task)); |
| } |
| +TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingDelayedTask) { |
| + const Task delayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta::FromSeconds(10)); |
|
gab
2016/09/23 15:39:18
Make this minutes so that the test would timeout i
fdoray
2016/09/23 15:56:50
Ok. But since I'm just testing TaskTracker (not th
gab
2016/09/23 17:05:25
Sure, but that makes it clear. Increasing readabil
|
| + tracker_.WillPostTask(&delayed_task); |
| + // FlushForTesting() should return even if the delayed task didn't run. |
| + tracker_.FlushForTesting(); |
| +} |
| + |
| +TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingUndelayedTask) { |
| + const Task undelayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta()); |
| + tracker_.WillPostTask(&undelayed_task); |
| + |
| + // FlushForTesting() shouldn't return before the undelayed task runs. |
| + CallFlushForTestingAsync(); |
| + PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| + VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS(); |
| + |
| + // FlushForTesting() should return after the undelayed task runs. |
| + tracker_.RunTask(&undelayed_task, SequenceToken::Create()); |
| + WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED(); |
| +} |
| + |
| +TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingPostDuringCall) { |
| + const Task undelayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta()); |
| + tracker_.WillPostTask(&undelayed_task); |
| + |
| + // FlushForTesting() shouldn't return before the undelayed task runs. |
| + CallFlushForTestingAsync(); |
| + PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| + VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS(); |
| + |
| + // Simulate posting another undelayed task. |
| + const Task other_undelayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta()); |
| + tracker_.WillPostTask(&other_undelayed_task); |
| + |
| + // Run the first undelayed task. |
| + tracker_.RunTask(&undelayed_task, SequenceToken::Create()); |
| + |
| + // FlushForTesting() shouldn't return before the second undelayed task runs. |
| + PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| + VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS(); |
| + |
| + // FlushForTesting() should return after the second undelayed task runs. |
| + tracker_.RunTask(&other_undelayed_task, SequenceToken::Create()); |
| + WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED(); |
| +} |
| + |
| +TEST_P(TaskSchedulerTaskTrackerTest, FlushForTestingAfterShutdown) { |
| + if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) |
| + return; |
| + |
| + // Simulate posting a task. |
| + const Task undelayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta()); |
| + tracker_.WillPostTask(&undelayed_task); |
| + |
| + // Shutdown() should return immediately since there are no pending |
| + // BLOCK_SHUTDOWN tasks. |
| + tracker_.Shutdown(); |
| + |
| + // FlushForTesting() should return immediately after shutdown, even if an |
| + // undelayed task hasn't run. |
| + tracker_.FlushForTesting(); |
| +} |
| + |
| +TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlushForTesting) { |
| + if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) |
| + return; |
| + |
| + // Simulate posting a task. |
| + const Task undelayed_task(FROM_HERE, Bind(&DoNothing), |
| + TaskTraits().WithShutdownBehavior(GetParam()), |
| + TimeDelta()); |
| + tracker_.WillPostTask(&undelayed_task); |
| + |
| + // FlushForTesting() shouldn't return before the undelayed task runs or |
| + // shutdown completes. |
| + CallFlushForTestingAsync(); |
| + PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
| + VERIFY_ASYNC_FLUSH_FOR_TESTING_IN_PROGRESS(); |
| + |
| + // Shutdown() should return immediately since there are no pending |
| + // BLOCK_SHUTDOWN tasks. |
| + tracker_.Shutdown(); |
| + |
| + // FlushForTesting() should now return, even if an undelayed task hasn't run. |
| + WAIT_FOR_ASYNC_FLUSH_FOR_TESTING_RETURNED(); |
| +} |
| + |
| INSTANTIATE_TEST_CASE_P( |
| ContinueOnShutdown, |
| TaskSchedulerTaskTrackerTest, |