| 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..c366a4822bc7812f7d37efc92c86c0d6931b5400
 | 
| --- /dev/null
 | 
| +++ b/base/task_scheduler/worker_thread_unittest.cc
 | 
| @@ -0,0 +1,236 @@
 | 
| +// 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/memory/scoped_ptr.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 internal {
 | 
| +
 | 
| +class TaskSchedulerWorkerThreadTest : public testing::Test {
 | 
| + protected:
 | 
| +  TaskSchedulerWorkerThreadTest()
 | 
| +      : worker_thread_(WorkerThread::CreateWorkerThread(
 | 
| +            ThreadPriority::NORMAL,
 | 
| +            &shared_priority_queue_,
 | 
| +            Bind(&TaskSchedulerWorkerThreadTest::ThreadMainEntryCallback,
 | 
| +                 Unretained(this)),
 | 
| +            Bind(&TaskSchedulerWorkerThreadTest::ReinsertSequenceCallback,
 | 
| +                 Unretained(this)),
 | 
| +            Bind(&TaskSchedulerWorkerThreadTest::BecomesIdleCallback,
 | 
| +                 Unretained(this)),
 | 
| +            &delayed_task_manager_,
 | 
| +            &shutdown_manager_)),
 | 
| +        cv_(lock_.CreateConditionVariable()),
 | 
| +        num_thread_main_entries_(0),
 | 
| +        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_) {}
 | 
| +
 | 
| +  void ThreadMainEntryCallback() {
 | 
| +    num_thread_main_entries_++;
 | 
| +  }
 | 
| +
 | 
| +  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 ShutdownAndJoinForTesting() {
 | 
| +    shutdown_manager_.set_is_shutting_down_for_testing(false);
 | 
| +    worker_thread_->ShutdownAndJoinForTesting();
 | 
| +  }
 | 
| +
 | 
| +  int num_thread_main_entries() const {
 | 
| +    return num_thread_main_entries_;
 | 
| +  }
 | 
| +
 | 
| +  bool ran_task_that_should_not_run() const {
 | 
| +    return ran_task_that_should_not_run_;
 | 
| +  }
 | 
| +
 | 
| +  ShutdownManager shutdown_manager_;
 | 
| +  scoped_ptr<WorkerThread> worker_thread_;
 | 
| +
 | 
| + 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.
 | 
| +  scoped_ptr<ConditionVariable> cv_;
 | 
| +
 | 
| +  // Number of invocations of the thread main entry callback.
 | 
| +  int num_thread_main_entries_;
 | 
| +
 | 
| +  // 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();
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +  ASSERT_EQ(1, num_thread_main_entries());
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +  }
 | 
| +
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +}
 | 
| +
 | 
| +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();
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +}
 | 
| +
 | 
| +TEST_F(TaskSchedulerWorkerThreadTest, ShutdownBehavior) {
 | 
| +  ASSERT_NE(nullptr, worker_thread_.get());
 | 
| +
 | 
| +  shutdown_manager_.set_is_shutting_down_for_testing(true);
 | 
| +
 | 
| +  // 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();
 | 
| +  ShutdownAndJoinForTesting();
 | 
| +  EXPECT_FALSE(ran_task_that_should_not_run());
 | 
| +}
 | 
| +
 | 
| +}  // namespace internal
 | 
| +}  // namespace base
 | 
| 
 |