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.
5 #include "content/browser/startup_task_runner.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"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::Assign;
23 using testing::Invoke;
24 using testing::WithArg;
26 int observer_calls = 0;
31 // I couldn't get gMock's SaveArg to compile, hence had to save the argument
33 bool SaveTaskArg(const Closure& arg) {
38 void Observer(int result) {
40 observer_result = result;
43 class StartupTaskRunnerTest : public testing::Test {
45 void SetUp() override {
64 // Task returning failure
70 int GetLastTask() { return last_task_; }
77 // We can't use the real message loop, even if we want to, since doing so on
78 // Android requires a complex Java infrastructure. The test would have to built
79 // as a content_shell test; but content_shell startup invokes the class we are
82 // The mocks are not directly in TaskRunnerProxy because reference counted
83 // objects seem to confuse the mocking framework
85 class MockTaskRunner {
89 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
91 PostNonNestableDelayedTask,
92 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
95 class TaskRunnerProxy : public base::SingleThreadTaskRunner {
97 TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
98 bool RunsTasksOnCurrentThread() const override { return true; }
99 bool PostDelayedTask(const tracked_objects::Location& location,
100 const Closure& closure,
101 base::TimeDelta delta) override {
102 return mock_->PostDelayedTask(location, closure, delta);
104 bool PostNonNestableDelayedTask(const tracked_objects::Location& location,
105 const Closure& closure,
106 base::TimeDelta delta) override {
107 return mock_->PostNonNestableDelayedTask(location, closure, delta);
111 MockTaskRunner* mock_;
112 ~TaskRunnerProxy() override {}
115 TEST_F(StartupTaskRunnerTest, SynchronousExecution) {
116 MockTaskRunner mock_runner;
117 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
119 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
120 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
122 StartupTaskRunner runner(base::Bind(&Observer), proxy);
125 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
126 runner.AddTask(task1);
127 EXPECT_EQ(GetLastTask(), 0);
129 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
130 runner.AddTask(task2);
132 // Nothing should run until we tell them to.
133 EXPECT_EQ(GetLastTask(), 0);
134 runner.RunAllTasksNow();
136 // On an immediate StartupTaskRunner the tasks should now all have run.
137 EXPECT_EQ(GetLastTask(), 2);
139 EXPECT_EQ(task_count, 2);
140 EXPECT_EQ(observer_calls, 1);
141 EXPECT_EQ(observer_result, 0);
143 // Running the tasks asynchronously shouldn't do anything
144 // In particular Post... should not be called
145 runner.StartRunningTasksAsync();
147 // No more tasks should be run and the observer should not have been called
149 EXPECT_EQ(task_count, 2);
150 EXPECT_EQ(observer_calls, 1);
153 TEST_F(StartupTaskRunnerTest, NullObserver) {
154 MockTaskRunner mock_runner;
155 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
157 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
158 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
160 StartupTaskRunner runner(base::Callback<void(int)>(), proxy);
163 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
164 runner.AddTask(task1);
165 EXPECT_EQ(GetLastTask(), 0);
167 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
168 runner.AddTask(task2);
170 // Nothing should run until we tell them to.
171 EXPECT_EQ(GetLastTask(), 0);
172 runner.RunAllTasksNow();
174 // On an immediate StartupTaskRunner the tasks should now all have run.
175 EXPECT_EQ(GetLastTask(), 2);
176 EXPECT_EQ(task_count, 2);
178 // Running the tasks asynchronously shouldn't do anything
179 // In particular Post... should not be called
180 runner.StartRunningTasksAsync();
182 // No more tasks should have been run
183 EXPECT_EQ(task_count, 2);
185 EXPECT_EQ(observer_calls, 0);
188 TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) {
189 MockTaskRunner mock_runner;
190 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
192 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
193 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _, _)).Times(0);
195 StartupTaskRunner runner(base::Bind(&Observer), proxy);
198 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
199 runner.AddTask(task3);
200 EXPECT_EQ(GetLastTask(), 0);
202 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
203 runner.AddTask(task2);
205 // Nothing should run until we tell them to.
206 EXPECT_EQ(GetLastTask(), 0);
207 runner.RunAllTasksNow();
209 // Only the first task should have run, since it failed
210 EXPECT_EQ(GetLastTask(), 3);
211 EXPECT_EQ(task_count, 1);
212 EXPECT_EQ(observer_calls, 1);
213 EXPECT_EQ(observer_result, 1);
215 // After a failed task all remaining tasks should be cancelled
216 // In particular Post... should not be called by running asynchronously
217 runner.StartRunningTasksAsync();
219 // The observer should only be called the first time the queue completes and
220 // no more tasks should have run
221 EXPECT_EQ(observer_calls, 1);
222 EXPECT_EQ(task_count, 1);
225 TEST_F(StartupTaskRunnerTest, AsynchronousExecution) {
227 MockTaskRunner mock_runner;
228 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
230 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
233 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
234 .Times(testing::Between(2, 3))
235 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
237 StartupTaskRunner runner(base::Bind(&Observer), proxy);
240 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
241 runner.AddTask(task1);
243 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
244 runner.AddTask(task2);
246 // Nothing should run until we tell them to.
247 EXPECT_EQ(GetLastTask(), 0);
248 runner.StartRunningTasksAsync();
250 // No tasks should have run yet, since we the message loop hasn't run.
251 EXPECT_EQ(GetLastTask(), 0);
253 // Fake the actual message loop. Each time a task is run a new task should
254 // be added to the queue, hence updating "task". The loop should actually run
255 // at most 3 times (once for each task plus possibly once for the observer),
256 // the "4" is a backstop.
257 for (int i = 0; i < 4 && observer_calls == 0; i++) {
259 EXPECT_EQ(i + 1, GetLastTask());
261 EXPECT_EQ(task_count, 2);
262 EXPECT_EQ(observer_calls, 1);
263 EXPECT_EQ(observer_result, 0);
265 // Check that running synchronously now doesn't do anything
267 runner.RunAllTasksNow();
268 EXPECT_EQ(task_count, 2);
269 EXPECT_EQ(observer_calls, 1);
272 TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) {
274 MockTaskRunner mock_runner;
275 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
277 EXPECT_CALL(mock_runner, PostDelayedTask(_, _, _)).Times(0);
280 PostNonNestableDelayedTask(_, _, base::TimeDelta::FromMilliseconds(0)))
281 .Times(testing::Between(1, 2))
282 .WillRepeatedly(WithArg<1>(Invoke(SaveTaskArg)));
284 StartupTaskRunner runner(base::Bind(&Observer), proxy);
287 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
288 runner.AddTask(task3);
290 base::Bind(&StartupTaskRunnerTest::Task2, base::Unretained(this));
291 runner.AddTask(task2);
293 // Nothing should run until we tell them to.
294 EXPECT_EQ(GetLastTask(), 0);
295 runner.StartRunningTasksAsync();
297 // No tasks should have run yet, since we the message loop hasn't run.
298 EXPECT_EQ(GetLastTask(), 0);
300 // Fake the actual message loop. Each time a task is run a new task should
301 // be added to the queue, hence updating "task". The loop should actually run
302 // at most twice (once for the failed task plus possibly once for the
303 // observer), the "4" is a backstop.
304 for (int i = 0; i < 4 && observer_calls == 0; i++) {
307 EXPECT_EQ(GetLastTask(), 3);
308 EXPECT_EQ(task_count, 1);
310 EXPECT_EQ(observer_calls, 1);
311 EXPECT_EQ(observer_result, 1);
313 // Check that running synchronously now doesn't do anything
314 runner.RunAllTasksNow();
315 EXPECT_EQ(observer_calls, 1);
316 EXPECT_EQ(task_count, 1);
319 } // namespace content