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