Index: base/task_scheduler/worker_thread_unittest.cc |
diff --git a/base/task_scheduler/worker_thread_unittest.cc b/base/task_scheduler/worker_thread_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9e0a0fae4fea2e1e4b27a43507aaa653573c02bb |
--- /dev/null |
+++ b/base/task_scheduler/worker_thread_unittest.cc |
@@ -0,0 +1,222 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/task_scheduler/worker_thread.h" |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
+#include "base/callback_forward.h" |
+#include "base/logging.h" |
+#include "base/synchronization/condition_variable.h" |
+#include "base/task_scheduler/delayed_task_manager.h" |
+#include "base/task_scheduler/priority_queue.h" |
+#include "base/task_scheduler/scheduler_lock.h" |
+#include "base/task_scheduler/shutdown_manager.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace base { |
+namespace task_scheduler { |
+ |
+class TaskSchedulerWorkerThreadTest : public testing::Test { |
+ protected: |
+ TaskSchedulerWorkerThreadTest() |
+ : worker_thread_(WorkerThread::CreateWorkerThread( |
+ ThreadPriority::NORMAL, |
+ &shared_priority_queue_, |
+ Bind(&TaskSchedulerWorkerThreadTest::ReinsertSequenceCallback, |
+ Unretained(this)), |
+ Bind(&TaskSchedulerWorkerThreadTest::BecomesIdleCallback, |
+ Unretained(this)), |
+ &delayed_task_manager_, |
+ &shutdown_manager_)), |
+ cv_(lock_.RawLockForConditionVariable()), |
+ last_posted_task_index_(0), |
+ last_run_task_index_(0), |
+ ran_task_that_should_not_run_(false), |
+ ran_tasks_in_wrong_order_(true), |
+ shared_priority_queue_(Bind(&DoNothing)), |
+ delayed_task_manager_( |
+ Bind(&WorkerThread::WakeUp, Unretained(worker_thread_.get())), |
+ &shutdown_manager_) {} |
+ |
+ WorkerThread::ReinsertSequenceCallback GetReinsertSequenceCallback() { |
+ return Bind(&TaskSchedulerWorkerThreadTest::ReinsertSequenceCallback, |
+ Unretained(this)); |
+ } |
+ |
+ Closure GetTaskThatShouldRunClosure() { |
+ ++last_posted_task_index_; |
+ return Bind(&TaskSchedulerWorkerThreadTest::RunTaskThatShouldRun, |
+ Unretained(this), last_posted_task_index_); |
+ } |
+ |
+ Closure GetTaskThatShouldNotRunClosure() { |
+ return Bind(&TaskSchedulerWorkerThreadTest::RunTaskThatShouldNotRun, |
+ Unretained(this)); |
+ } |
+ |
+ void WaitUntilLastPostedTaskHasRun() { |
+ AutoSchedulerLock auto_lock(lock_); |
+ while (last_posted_task_index_ != last_run_task_index_) |
+ cv_.Wait(); |
+ } |
+ |
+ void Shutdown() { |
+ shutdown_manager_.Shutdown(); |
+ worker_thread_->JoinForTesting(); |
+ } |
+ |
+ bool ran_task_that_should_not_run() const { |
+ return ran_task_that_should_not_run_; |
+ } |
+ |
+ scoped_ptr<WorkerThread> worker_thread_; |
+ ShutdownManager shutdown_manager_; |
+ |
+ private: |
+ void ReinsertSequenceCallback(scoped_refptr<Sequence> sequence, |
+ const WorkerThread* worker_thread) { |
+ NOTREACHED(); |
+ } |
+ |
+ void BecomesIdleCallback(WorkerThread* worker_thread) { |
+ // TODO(fdoray). |
+ } |
+ |
+ void RunTaskThatShouldRun(size_t index) { |
+ AutoSchedulerLock auto_lock(lock_); |
+ |
+ if (index != last_run_task_index_ + 1) |
+ ran_tasks_in_wrong_order_ = true; |
+ |
+ last_run_task_index_ = index; |
+ cv_.Signal(); |
+ } |
+ |
+ void RunTaskThatShouldNotRun() { ran_task_that_should_not_run_ = true; } |
+ |
+ // Lock protecting |cv_|. |
+ SchedulerLock lock_; |
+ |
+ // Condition variable signaled each time a task completes its execution. |
+ ConditionVariable cv_; |
+ |
+ // Index of the last posted task. |
+ size_t last_posted_task_index_; |
+ |
+ // Index of the last run task. |
+ size_t last_run_task_index_; |
+ |
+ // True if a task that shouldn't run has run. |
+ bool ran_task_that_should_not_run_; |
+ |
+ // True if tasks were run in the wrong order. |
+ bool ran_tasks_in_wrong_order_; |
+ |
+ PriorityQueue shared_priority_queue_; |
+ |
+ DelayedTaskManager delayed_task_manager_; |
+}; |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, PostSingleTask) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ worker_thread_->CreateTaskRunnerWithTraits(TaskTraits(), |
+ ExecutionMode::SINGLE_THREADED) |
+ ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ |
+ WaitUntilLastPostedTaskHasRun(); |
+ Shutdown(); |
+} |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, PostMultipleTasksNoWaitBetweenPosts) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ auto task_runner = worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits(), ExecutionMode::SINGLE_THREADED); |
+ |
+ for (size_t i = 0; i < 100; ++i) |
+ task_runner->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ |
+ WaitUntilLastPostedTaskHasRun(); |
+ Shutdown(); |
+} |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, PostMultipleTasksWaitBetweenPosts) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ auto task_runner = worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits(), ExecutionMode::SINGLE_THREADED); |
+ |
+ for (size_t i = 0; i < 100; ++i) { |
+ task_runner->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ WaitUntilLastPostedTaskHasRun(); |
+ } |
+ |
+ Shutdown(); |
+} |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, PostMultipleTasksTwoTaskRunners) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ auto task_runner_a = worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits(), ExecutionMode::SINGLE_THREADED); |
+ auto task_runner_b = worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits(), ExecutionMode::SINGLE_THREADED); |
+ |
+ for (size_t i = 0; i < 100; ++i) { |
+ task_runner_a->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ task_runner_b->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ } |
+ |
+ WaitUntilLastPostedTaskHasRun(); |
+ |
+ Shutdown(); |
+} |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, PostDelayedTasks) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ auto task_runner = worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits(), ExecutionMode::SINGLE_THREADED); |
+ |
+ for (size_t i = 0; i < 10; ++i) { |
+ task_runner->PostDelayedTask(FROM_HERE, GetTaskThatShouldRunClosure(), |
+ TimeDelta::FromMilliseconds(i * 50)); |
+ } |
+ |
+ WaitUntilLastPostedTaskHasRun(); |
+ |
+ Shutdown(); |
+} |
+ |
+TEST_F(TaskSchedulerWorkerThreadTest, ShutdownBehavior) { |
+ ASSERT_NE(nullptr, worker_thread_.get()); |
+ |
+ shutdown_manager_.SetIsShuttingDownForTesting(); |
+ |
+ // Post tasks with different shutdown behaviors. |
+ worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits().WithShutdownBehavior( |
+ TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), |
+ ExecutionMode::SINGLE_THREADED) |
+ ->PostTask(FROM_HERE, GetTaskThatShouldNotRunClosure()); |
+ worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits().WithShutdownBehavior( |
+ TaskShutdownBehavior::SKIP_ON_SHUTDOWN), |
+ ExecutionMode::SINGLE_THREADED) |
+ ->PostTask(FROM_HERE, GetTaskThatShouldNotRunClosure()); |
+ worker_thread_->CreateTaskRunnerWithTraits( |
+ TaskTraits().WithShutdownBehavior( |
+ TaskShutdownBehavior::BLOCK_SHUTDOWN), |
+ ExecutionMode::SINGLE_THREADED) |
+ ->PostTask(FROM_HERE, GetTaskThatShouldRunClosure()); |
+ |
+ WaitUntilLastPostedTaskHasRun(); |
+ Shutdown(); |
+ EXPECT_FALSE(ran_task_that_should_not_run()); |
+} |
+ |
+} // namespace task_scheduler |
+} // namespace base |