OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/browser/startup_task_runner.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/callback.h" |
| 10 #include "base/location.h" |
| 11 #include "base/run_loop.h" |
| 12 #include "base/task_runner.h" |
| 13 |
| 14 #include "testing/gmock/include/gmock/gmock.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 |
| 17 namespace content { |
| 18 namespace { |
| 19 |
| 20 using base::Closure; |
| 21 using testing::_; |
| 22 using testing::Assign; |
| 23 using testing::Invoke; |
| 24 using testing::WithArg; |
| 25 |
| 26 bool observer_called = false; |
| 27 int observer_result; |
| 28 |
| 29 |
| 30 class StartupTaskRunnerTest : public testing::Test { |
| 31 private: |
| 32 |
| 33 int last_task_; |
| 34 |
| 35 public: |
| 36 |
| 37 virtual void SetUp() { |
| 38 last_task_ = 0; |
| 39 observer_called = false; |
| 40 } |
| 41 |
| 42 int Task1() { |
| 43 last_task_ = 1; |
| 44 return 0; |
| 45 } |
| 46 |
| 47 int Task2() { |
| 48 last_task_ = 2; |
| 49 return 0; |
| 50 } |
| 51 |
| 52 int Task3() { |
| 53 // Task returning failure |
| 54 last_task_ = 3; |
| 55 return 1; |
| 56 } |
| 57 |
| 58 int GetLastTask() { return last_task_; } |
| 59 }; |
| 60 |
| 61 void Observer(int result) { |
| 62 observer_called = true; |
| 63 observer_result = result; |
| 64 } |
| 65 |
| 66 // We can't use the real message loop, even if we want to, since doing so on |
| 67 // Android requires a complex Java infrastructure. The test would have to built |
| 68 // as a content_shell test; but content_shell startup invokes the class we are |
| 69 // trying to test. |
| 70 // |
| 71 // The mocks are not directly in TaskRunnerProxy because reference counted |
| 72 // objects seem to confuse the mocking framework |
| 73 |
| 74 class MockTaskRunner { |
| 75 public: |
| 76 MOCK_METHOD3( |
| 77 PostDelayedTask, |
| 78 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); |
| 79 MOCK_METHOD3( |
| 80 PostNonNestableDelayedTask, |
| 81 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); |
| 82 }; |
| 83 |
| 84 class TaskRunnerProxy : public base::SingleThreadTaskRunner { |
| 85 public: |
| 86 TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {} |
| 87 bool RunsTasksOnCurrentThread() const { return true; } |
| 88 bool PostDelayedTask(const tracked_objects::Location& location, |
| 89 const Closure& closure, |
| 90 base::TimeDelta delta) { |
| 91 return mock_->PostDelayedTask(location, closure, delta); |
| 92 } |
| 93 bool PostNonNestableDelayedTask(const tracked_objects::Location& location, |
| 94 const Closure& closure, |
| 95 base::TimeDelta delta) { |
| 96 return mock_->PostNonNestableDelayedTask(location, closure, delta); |
| 97 } |
| 98 |
| 99 private: |
| 100 MockTaskRunner* mock_; |
| 101 }; |
| 102 |
| 103 TEST_F(StartupTaskRunnerTest, SynchronousExecution) { |
| 104 MockTaskRunner mock_runner; |
| 105 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
| 106 |
| 107 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
| 108 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); |
| 109 |
| 110 scoped_refptr<StartupTaskRunner> runner = |
| 111 new StartupTaskRunner(false, Observer, proxy); |
| 112 |
| 113 StartupTask task1 = |
| 114 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
| 115 runner->AddTask(task1); |
| 116 EXPECT_EQ(GetLastTask(), 0); |
| 117 StartupTask task2 = |
| 118 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
| 119 runner->AddTask(task2); |
| 120 |
| 121 // Nothing should run until we tell them to. |
| 122 EXPECT_EQ(GetLastTask(), 0); |
| 123 runner->StartRunningTasks(); |
| 124 |
| 125 // On an immediate StartupTaskRunner the tasks should now all have run. |
| 126 EXPECT_EQ(GetLastTask(), 2); |
| 127 |
| 128 EXPECT_TRUE(observer_called); |
| 129 EXPECT_EQ(observer_result, 0); |
| 130 } |
| 131 |
| 132 TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) { |
| 133 MockTaskRunner mock_runner; |
| 134 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
| 135 |
| 136 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
| 137 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); |
| 138 |
| 139 scoped_refptr<StartupTaskRunner> runner = |
| 140 new StartupTaskRunner(false, Observer, proxy); |
| 141 |
| 142 StartupTask task3 = |
| 143 base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this)); |
| 144 runner->AddTask(task3); |
| 145 EXPECT_EQ(GetLastTask(), 0); |
| 146 StartupTask task2 = |
| 147 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
| 148 runner->AddTask(task2); |
| 149 |
| 150 // Nothing should run until we tell them to. |
| 151 EXPECT_EQ(GetLastTask(), 0); |
| 152 runner->StartRunningTasks(); |
| 153 |
| 154 // Only the first task should have run, since it failed |
| 155 EXPECT_EQ(GetLastTask(), 3); |
| 156 |
| 157 EXPECT_TRUE(observer_called); |
| 158 EXPECT_EQ(observer_result, 1); |
| 159 } |
| 160 base::Closure task; |
| 161 |
| 162 // I couldn't get gMock's SaveArg to compile, hence had to save the argument |
| 163 // this way |
| 164 bool SaveTaskArg(const Closure& arg) { |
| 165 task = arg; |
| 166 return true; |
| 167 } |
| 168 |
| 169 TEST_F(StartupTaskRunnerTest, AsynchronousExecution) { |
| 170 |
| 171 MockTaskRunner mock_runner; |
| 172 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
| 173 |
| 174 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
| 175 EXPECT_CALL( |
| 176 mock_runner, |
| 177 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) |
| 178 .Times(testing::Between(2,3)) |
| 179 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); |
| 180 |
| 181 scoped_refptr<StartupTaskRunner> runner = |
| 182 new StartupTaskRunner(true, Observer, proxy); |
| 183 |
| 184 StartupTask task1 = |
| 185 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); |
| 186 runner->AddTask(task1); |
| 187 StartupTask task2 = |
| 188 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
| 189 runner->AddTask(task2); |
| 190 |
| 191 // Nothing should run until we tell them to. |
| 192 EXPECT_EQ(GetLastTask(), 0); |
| 193 runner->StartRunningTasks(); |
| 194 |
| 195 // No tasks should have run yet, since we the message loop hasn't run. |
| 196 EXPECT_EQ(GetLastTask(), 0); |
| 197 |
| 198 // Fake the actual message loop. Each time a task is run a new task should |
| 199 // be added to the queue, hence updating "task". The loop should actually run |
| 200 // at most 3 times (once for each task plus possibly once for the observer), |
| 201 // the "4" is a backstop. |
| 202 for (int i = 0; i < 4 && !observer_called; i++) { |
| 203 task.Run(); |
| 204 EXPECT_EQ(i + 1, GetLastTask()); |
| 205 } |
| 206 EXPECT_TRUE(observer_called); |
| 207 EXPECT_EQ(observer_result, 0); |
| 208 } |
| 209 |
| 210 TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) { |
| 211 |
| 212 MockTaskRunner mock_runner; |
| 213 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); |
| 214 |
| 215 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); |
| 216 EXPECT_CALL( |
| 217 mock_runner, |
| 218 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) |
| 219 .Times(testing::Between(1,2)) |
| 220 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); |
| 221 |
| 222 scoped_refptr<StartupTaskRunner> runner = |
| 223 new StartupTaskRunner(true, Observer, proxy); |
| 224 |
| 225 StartupTask task3 = |
| 226 base::Bind(&StartupTaskRunnerTest::Task3, base::Unretained(this)); |
| 227 runner->AddTask(task3); |
| 228 StartupTask task2 = |
| 229 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); |
| 230 runner->AddTask(task2); |
| 231 |
| 232 // Nothing should run until we tell them to. |
| 233 EXPECT_EQ(GetLastTask(), 0); |
| 234 runner->StartRunningTasks(); |
| 235 |
| 236 // No tasks should have run yet, since we the message loop hasn't run. |
| 237 EXPECT_EQ(GetLastTask(), 0); |
| 238 |
| 239 // Fake the actual message loop. Each time a task is run a new task should |
| 240 // be added to the queue, hence updating "task". The loop should actually run |
| 241 // at most twice (once for the failed task plus possibly once for the |
| 242 // observer), the "4" is a backstop. |
| 243 for (int i = 0; i < 4 && !observer_called; i++) { |
| 244 task.Run(); |
| 245 } |
| 246 EXPECT_EQ(GetLastTask(), 3); |
| 247 |
| 248 EXPECT_TRUE(observer_called); |
| 249 EXPECT_EQ(observer_result, 1); |
| 250 } |
| 251 } // namespace |
| 252 } // namespace content |
OLD | NEW |