Index: content/browser/startup_task_runner_unittest.cc |
diff --git a/content/browser/startup_task_runner_unittest.cc b/content/browser/startup_task_runner_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2ca7a9652084b879c9261685ff11861f3d1c9b0b |
--- /dev/null |
+++ b/content/browser/startup_task_runner_unittest.cc |
@@ -0,0 +1,253 @@ |
+// 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/browser/startup_task_runner.h" |
+ |
+#include "base/bind.h" |
+#include "base/bind_helpers.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; |
+ |
+bool observer_called = false; |
Yaron
2013/07/30 18:53:22
Nit: I think it's common to place these members as
aberent
2013/07/31 17:24:49
Normally I would, but these would have to be stati
|
+int observer_result; |
+ |
+class StartupTaskRunnerTest : public testing::Test { |
+ private: |
Yaron
2013/07/30 18:53:22
Nit: A little unorthodox. Please move private to t
aberent
2013/07/31 17:24:49
Done.
|
+ |
+ int last_task_; |
+ |
+ public: |
+ |
+ virtual void SetUp() { |
+ last_task_ = 0; |
+ observer_called = false; |
+ } |
+ |
+ int Task1() { |
+ last_task_ = 1; |
+ return 0; |
+ } |
+ |
+ int Task2() { |
+ last_task_ = 2; |
+ return 0; |
+ } |
+ |
+ int Task3() { |
Yaron
2013/07/30 18:53:22
Nit: renaming FailingTask (and the local variable
aberent
2013/07/31 17:24:49
Done.
|
+ // Task returning failure |
+ last_task_ = 3; |
+ return 1; |
+ } |
+ |
+ int GetLastTask() { return last_task_; } |
+}; |
+ |
+void Observer(int result) { |
+ observer_called = true; |
+ observer_result = result; |
+} |
+ |
+// 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) {} |
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; } |
+ virtual bool PostDelayedTask(const tracked_objects::Location& location, |
+ const Closure& closure, |
+ base::TimeDelta delta) OVERRIDE { |
+ return mock_->PostDelayedTask(location, closure, delta); |
+ } |
+ virtual bool PostNonNestableDelayedTask( |
+ const tracked_objects::Location& location, |
+ const Closure& closure, |
+ base::TimeDelta delta) OVERRIDE { |
+ return mock_->PostNonNestableDelayedTask(location, closure, delta); |
+ } |
+ |
+ private: |
+ MockTaskRunner* mock_; |
+ virtual ~TaskRunnerProxy() {} |
+}; |
+ |
+TEST_F(StartupTaskRunnerTest, SynchronousExecution) { |
+ 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(false, Observer, proxy); |
+ |
+ StartupTask task1 = |
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
+ runner->AddTask(task1); |
+ EXPECT_EQ(GetLastTask(), 0); |
+ StartupTask 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); |
+ |
+ EXPECT_TRUE(observer_called); |
+ EXPECT_EQ(observer_result, 0); |
+} |
+ |
+TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) { |
+ 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(false, Observer, proxy); |
+ |
+ StartupTask task3 = |
+ base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this)); |
+ runner->AddTask(task3); |
+ EXPECT_EQ(GetLastTask(), 0); |
+ StartupTask 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(); |
+ |
+ // Only the first task should have run, since it failed |
+ EXPECT_EQ(GetLastTask(), 3); |
+ |
+ EXPECT_TRUE(observer_called); |
+ EXPECT_EQ(observer_result, 1); |
+} |
+base::Closure task; |
Yaron
2013/07/30 18:53:22
Nit: member variabe as well.
aberent
2013/07/31 17:24:49
Could only be static member variable since used by
|
+ |
+// 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, AsynchronousExecution) { |
+ |
+ MockTaskRunner mock_runner; |
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
+ |
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
+ EXPECT_CALL( |
+ mock_runner, |
+ PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) |
+ .Times(testing::Between(2, 3)) |
+ .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); |
+ |
+ scoped_refptr<StartupTaskRunner> runner = |
+ new StartupTaskRunner(true, Observer, proxy); |
+ |
+ StartupTask task1 = |
+ base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
+ runner->AddTask(task1); |
+ StartupTask 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 |
+ // at most 3 times (once for each task plus possibly once for the observer), |
+ // the "4" is a backstop. |
+ for (int i = 0; i < 4 && !observer_called; i++) { |
+ task.Run(); |
+ EXPECT_EQ(i + 1, GetLastTask()); |
+ } |
+ EXPECT_TRUE(observer_called); |
+ EXPECT_EQ(observer_result, 0); |
+} |
+ |
+TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) { |
+ |
+ MockTaskRunner mock_runner; |
+ scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
+ |
+ EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
+ EXPECT_CALL( |
+ mock_runner, |
+ PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) |
+ .Times(testing::Between(1, 2)) |
+ .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); |
+ |
+ scoped_refptr<StartupTaskRunner> runner = |
+ new StartupTaskRunner(true, Observer, proxy); |
+ |
+ StartupTask task3 = |
+ base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this)); |
+ runner->AddTask(task3); |
+ StartupTask 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 |
+ // at most twice (once for the failed task plus possibly once for the |
+ // observer), the "4" is a backstop. |
+ for (int i = 0; i < 4 && !observer_called; i++) { |
+ task.Run(); |
+ } |
+ EXPECT_EQ(GetLastTask(), 3); |
+ |
+ EXPECT_TRUE(observer_called); |
+ EXPECT_EQ(observer_result, 1); |
+} |
+} // namespace |
+} // namespace content |