| Index: content/common/startup_task_runner_unittest.cc
|
| diff --git a/content/common/startup_task_runner_unittest.cc b/content/common/startup_task_runner_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..44043c2837c2d9be1d6f3bed783513c4b683f9bb
|
| --- /dev/null
|
| +++ b/content/common/startup_task_runner_unittest.cc
|
| @@ -0,0 +1,200 @@
|
| +// Copyright (c) 2013 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 "content/public/common/startup_task_runner.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/location.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/task_runner.h"
|
| +
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace content {
|
| +namespace {
|
| +
|
| +using base::Closure;
|
| +using testing::_;
|
| +using testing::Assign;
|
| +using testing::Invoke;
|
| +using testing::WithArg;
|
| +
|
| +class StartupTaskRunnerTest : public testing::Test {
|
| + private:
|
| +
|
| + int last_task_;
|
| +
|
| + public:
|
| +
|
| + virtual void SetUp() { last_task_ = 0; }
|
| +
|
| + void Task1() { last_task_ = 1; }
|
| +
|
| + void Task2() { last_task_ = 2; }
|
| +
|
| + int GetLastTask() { return last_task_; }
|
| +};
|
| +
|
| +class MockObserver : public StartupTaskRunner::Observer {
|
| + public:
|
| + MOCK_METHOD0(AllTasksRun, void());
|
| +};
|
| +
|
| +// We can't use the real message loop, even if we want to, since doing so on
|
| +// Android requires a complex Java infrastructure. The test would have to built
|
| +// as a content_shell test; but content_shell startup invokes the class we are
|
| +// trying to test.
|
| +//
|
| +// The mocks are not directly in TaskRunnerProxy because reference counted
|
| +// objects seem to confuse the mocking framework
|
| +
|
| +class MockTaskRunner {
|
| + public:
|
| + MOCK_METHOD3(
|
| + PostDelayedTask,
|
| + bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
|
| + MOCK_METHOD3(
|
| + PostNonNestableDelayedTask,
|
| + bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
|
| +};
|
| +
|
| +class TaskRunnerProxy : public base::SingleThreadTaskRunner {
|
| + public:
|
| + TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
|
| + bool RunsTasksOnCurrentThread() const { return true; }
|
| + bool PostDelayedTask(const tracked_objects::Location& location,
|
| + const Closure& closure,
|
| + base::TimeDelta delta) {
|
| + return mock_->PostDelayedTask(location, closure, delta);
|
| + }
|
| + bool PostNonNestableDelayedTask(const tracked_objects::Location& location,
|
| + const Closure& closure,
|
| + base::TimeDelta delta) {
|
| + return mock_->PostNonNestableDelayedTask(location, closure, delta);
|
| + }
|
| +
|
| + private:
|
| + MockTaskRunner* mock_;
|
| +};
|
| +
|
| +TEST_F(StartupTaskRunnerTest, ImmediateExecution) {
|
| +
|
| + MockTaskRunner mock_runner;
|
| + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
|
| +
|
| + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
|
| + EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
|
| +
|
| + scoped_refptr<StartupTaskRunner> runner =
|
| + new StartupTaskRunner(StartupTaskRunner::IMMEDIATE, NULL);
|
| +
|
| + runner->SetProxy(proxy);
|
| +
|
| + base::Closure task1 =
|
| + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
|
| + runner->AddTask(task1);
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| + base::Closure task2 =
|
| + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
|
| + runner->AddTask(task2);
|
| +
|
| + // Nothing should run until we tell them to.
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| + runner->StartRunningTasks();
|
| +
|
| + // On an immediate StartupTaskRunner the tasks should now all have run.
|
| + EXPECT_EQ(GetLastTask(), 2);
|
| +}
|
| +
|
| +TEST_F(StartupTaskRunnerTest, ImmediateExecutionObserved) {
|
| + MockTaskRunner mock_runner;
|
| + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
|
| +
|
| + MockObserver observer;
|
| + EXPECT_CALL(observer, AllTasksRun()).Times(1);
|
| +
|
| + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
|
| + EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
|
| +
|
| + scoped_refptr<StartupTaskRunner> runner =
|
| + new StartupTaskRunner(StartupTaskRunner::IMMEDIATE, &observer);
|
| +
|
| + runner->SetProxy(proxy);
|
| +
|
| + base::Closure task1 =
|
| + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
|
| + runner->AddTask(task1);
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| + base::Closure task2 =
|
| + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
|
| + runner->AddTask(task2);
|
| +
|
| + // Nothing should run until we tell them to.
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| + runner->StartRunningTasks();
|
| +
|
| + // On an immediate StartupTaskRunner the tasks should now all have run.
|
| + EXPECT_EQ(GetLastTask(), 2);
|
| +}
|
| +
|
| +base::Closure task;
|
| +
|
| +// I couldn't get gMock's SaveArg to compile, hence had to save the argument
|
| +// this way
|
| +bool SaveTaskArg(const Closure& arg) {
|
| + task = arg;
|
| + return true;
|
| +}
|
| +
|
| +TEST_F(StartupTaskRunnerTest, IncrementalExecution) {
|
| +
|
| + MockTaskRunner mock_runner;
|
| + scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
|
| +
|
| + bool done = false;
|
| + ;
|
| +
|
| + MockObserver observer;
|
| +
|
| + EXPECT_CALL(observer, AllTasksRun()).WillOnce(Assign(&done, true));
|
| + EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
|
| + EXPECT_CALL(
|
| + mock_runner,
|
| + PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
|
| + .Times(3).WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
|
| +
|
| + scoped_refptr<StartupTaskRunner> runner =
|
| + new StartupTaskRunner(StartupTaskRunner::INCREMENTAL, &observer);
|
| +
|
| + runner->SetProxy(proxy);
|
| +
|
| + base::Closure task1 =
|
| + base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
|
| + runner->AddTask(task1);
|
| + base::Closure task2 =
|
| + base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
|
| + runner->AddTask(task2);
|
| +
|
| + // Nothing should run until we tell them to.
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| + runner->StartRunningTasks();
|
| +
|
| + // No tasks should have run yet, since we the message loop hasn't run.
|
| + EXPECT_EQ(GetLastTask(), 0);
|
| +
|
| + // Fake the actual message loop. Each time a task is run a new task should
|
| + // be added to the queue, hence updating "task". The loop should actually run
|
| + // three times, the "4" is a backstop.
|
| + for (int i = 0; i < 4 && !done; i++) {
|
| + task.Run();
|
| + if (!done) {
|
| + EXPECT_EQ(i + 1, GetLastTask());
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace content
|
|
|