| 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
|
|
|