1 // Copyright 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 int observer_calls = 0; 27 int task_count = 0; 28 int observer_result; 29 base::Closure task; 30 31 // I couldn't get gMock's SaveArg to compile, hence had to save the argument 32 // this way 33 bool SaveTaskArg(const Closure& arg) { 34 task = arg; 35 return true; 36 } 37 38 void Observer(int result) { 39 observer_calls++; 40 observer_result = result; 41 } 42 43 class StartupTaskRunnerTest : public testing::Test { 44 public: 45 46 virtual void SetUp() { 47 last_task_ = 0; 48 observer_calls = 0; 49 task_count = 0; 50 } 51 52 int Task1() { 53 last_task_ = 1; 54 task_count++; 55 return 0; 56 } 57 58 int Task2() { 59 last_task_ = 2; 60 task_count++; 61 return 0; 62 } 63 64 int FailingTask() { 65 // Task returning failure 66 last_task_ = 3; 67 task_count++; 68 return 1; 69 } 70 71 int GetLastTask() { return last_task_; } 72 73 private: 74 75 int last_task_; 76 }; 77 78 // We can't use the real message loop, even if we want to, since doing so on 79 // Android requires a complex Java infrastructure. The test would have to built 80 // as a content_shell test; but content_shell startup invokes the class we are 81 // trying to test. 82 // 83 // The mocks are not directly in TaskRunnerProxy because reference counted 84 // objects seem to confuse the mocking framework 85 86 class MockTaskRunner { 87 public: 88 MOCK_METHOD3( 89 PostDelayedTask, 90 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); 91 MOCK_METHOD3( 92 PostNonNestableDelayedTask, 93 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta)); 94 }; 95 96 class TaskRunnerProxy : public base::SingleThreadTaskRunner { 97 public: 98 TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {} 99 virtual bool RunsTasksOnCurrentThread() const OVERRIDE { return true; } 100 virtual bool PostDelayedTask(const tracked_objects::Location& location, 101 const Closure& closure, 102 base::TimeDelta delta) OVERRIDE { 103 return mock_->PostDelayedTask(location, closure, delta); 104 } 105 virtual bool PostNonNestableDelayedTask( 106 const tracked_objects::Location& location, 107 const Closure& closure, 108 base::TimeDelta delta) OVERRIDE { 109 return mock_->PostNonNestableDelayedTask(location, closure, delta); 110 } 111 112 private: 113 MockTaskRunner* mock_; 114 virtual ~TaskRunnerProxy() {} 115 }; 116 117 TEST_F(StartupTaskRunnerTest, SynchronousExecution) { 118 MockTaskRunner mock_runner; 119 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); 120 121 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); 122 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); 123 124 StartupTaskRunner runner(base::Bind(&Observer), proxy); 125 126 StartupTask task1 = 127 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); 128 runner.AddTask(task1); 129 EXPECT_EQ(GetLastTask(), 0); 130 StartupTask task2 = 131 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); 132 runner.AddTask(task2); 133 134 // Nothing should run until we tell them to. 135 EXPECT_EQ(GetLastTask(), 0); 136 runner.RunAllTasksNow(); 137 138 // On an immediate StartupTaskRunner the tasks should now all have run. 139 EXPECT_EQ(GetLastTask(), 2); 140 141 EXPECT_EQ(task_count, 2); 142 EXPECT_EQ(observer_calls, 1); 143 EXPECT_EQ(observer_result, 0); 144 145 // Running the tasks asynchronously shouldn't do anything 146 // In particular Post... should not be called 147 runner.StartRunningTasksAsync(); 148 149 // No more tasks should be run and the observer should not have been called 150 // again 151 EXPECT_EQ(task_count, 2); 152 EXPECT_EQ(observer_calls, 1); 153 } 154 155 TEST_F(StartupTaskRunnerTest, NullObserver) { 156 MockTaskRunner mock_runner; 157 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); 158 159 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); 160 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); 161 162 StartupTaskRunner runner(base::Callback<void(int)>(), proxy); 163 164 StartupTask task1 = 165 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); 166 runner.AddTask(task1); 167 EXPECT_EQ(GetLastTask(), 0); 168 StartupTask task2 = 169 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); 170 runner.AddTask(task2); 171 172 // Nothing should run until we tell them to. 173 EXPECT_EQ(GetLastTask(), 0); 174 runner.RunAllTasksNow(); 175 176 // On an immediate StartupTaskRunner the tasks should now all have run. 177 EXPECT_EQ(GetLastTask(), 2); 178 EXPECT_EQ(task_count, 2); 179 180 // Running the tasks asynchronously shouldn't do anything 181 // In particular Post... should not be called 182 runner.StartRunningTasksAsync(); 183 184 // No more tasks should have been run 185 EXPECT_EQ(task_count, 2); 186 187 EXPECT_EQ(observer_calls, 0); 188 } 189 190 TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) { 191 MockTaskRunner mock_runner; 192 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); 193 194 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); 195 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0); 196 197 StartupTaskRunner runner(base::Bind(&Observer), proxy); 198 199 StartupTask task3 = 200 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this)); 201 runner.AddTask(task3); 202 EXPECT_EQ(GetLastTask(), 0); 203 StartupTask task2 = 204 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); 205 runner.AddTask(task2); 206 207 // Nothing should run until we tell them to. 208 EXPECT_EQ(GetLastTask(), 0); 209 runner.RunAllTasksNow(); 210 211 // Only the first task should have run, since it failed 212 EXPECT_EQ(GetLastTask(), 3); 213 EXPECT_EQ(task_count, 1); 214 EXPECT_EQ(observer_calls, 1); 215 EXPECT_EQ(observer_result, 1); 216 217 // After a failed task all remaining tasks should be cancelled 218 // In particular Post... should not be called by running asynchronously 219 runner.StartRunningTasksAsync(); 220 221 // The observer should only be called the first time the queue completes and 222 // no more tasks should have run 223 EXPECT_EQ(observer_calls, 1); 224 EXPECT_EQ(task_count, 1); 225 } 226 227 TEST_F(StartupTaskRunnerTest, AsynchronousExecution) { 228 229 MockTaskRunner mock_runner; 230 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); 231 232 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); 233 EXPECT_CALL( 234 mock_runner, 235 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) 236 .Times(testing::Between(2, 3)) 237 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); 238 239 StartupTaskRunner runner(base::Bind(&Observer), proxy); 240 241 StartupTask task1 = 242 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this)); 243 runner.AddTask(task1); 244 StartupTask task2 = 245 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); 246 runner.AddTask(task2); 247 248 // Nothing should run until we tell them to. 249 EXPECT_EQ(GetLastTask(), 0); 250 runner.StartRunningTasksAsync(); 251 252 // No tasks should have run yet, since we the message loop hasn't run. 253 EXPECT_EQ(GetLastTask(), 0); 254 255 // Fake the actual message loop. Each time a task is run a new task should 256 // be added to the queue, hence updating "task". The loop should actually run 257 // at most 3 times (once for each task plus possibly once for the observer), 258 // the "4" is a backstop. 259 for (int i = 0; i < 4 && observer_calls == 0; i++) { 260 task.Run(); 261 EXPECT_EQ(i + 1, GetLastTask()); 262 } 263 EXPECT_EQ(task_count, 2); 264 EXPECT_EQ(observer_calls, 1); 265 EXPECT_EQ(observer_result, 0); 266 267 // Check that running synchronously now doesn't do anything 268 269 runner.RunAllTasksNow(); 270 EXPECT_EQ(task_count, 2); 271 EXPECT_EQ(observer_calls, 1); 272 } 273 274 TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) { 275 276 MockTaskRunner mock_runner; 277 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner); 278 279 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0); 280 EXPECT_CALL( 281 mock_runner, 282 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0))) 283 .Times(testing::Between(1, 2)) 284 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg))); 285 286 StartupTaskRunner runner(base::Bind(&Observer), proxy); 287 288 StartupTask task3 = 289 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this)); 290 runner.AddTask(task3); 291 StartupTask task2 = 292 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this)); 293 runner.AddTask(task2); 294 295 // Nothing should run until we tell them to. 296 EXPECT_EQ(GetLastTask(), 0); 297 runner.StartRunningTasksAsync(); 298 299 // No tasks should have run yet, since we the message loop hasn't run. 300 EXPECT_EQ(GetLastTask(), 0); 301 302 // Fake the actual message loop. Each time a task is run a new task should 303 // be added to the queue, hence updating "task". The loop should actually run 304 // at most twice (once for the failed task plus possibly once for the 305 // observer), the "4" is a backstop. 306 for (int i = 0; i < 4 && observer_calls == 0; i++) { 307 task.Run(); 308 } 309 EXPECT_EQ(GetLastTask(), 3); 310 EXPECT_EQ(task_count, 1); 311 312 EXPECT_EQ(observer_calls, 1); 313 EXPECT_EQ(observer_result, 1); 314 315 // Check that running synchronously now doesn't do anything 316 runner.RunAllTasksNow(); 317 EXPECT_EQ(observer_calls, 1); 318 EXPECT_EQ(task_count, 1); 319 } 320 } // namespace 321 } // namespace content 322