Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / startup_task_runner_unittest.cc
blob2ecf9ca63c58c4c32e3f780f607d552e53768ab8
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"
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"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 namespace content {
18 namespace {
20 using base::Closure;
21 using testing::_;
22 using testing::Assign;
23 using testing::Invoke;
24 using testing::WithArg;
26 int observer_calls = 0;
27 int task_count = 0;
28 int observer_result;
29 base::Closure task;
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;
38 void Observer(int result) {
39 observer_calls++;
40 observer_result = result;
43 class StartupTaskRunnerTest : public testing::Test {
44 public:
45 void SetUp() override {
46 last_task_ = 0;
47 observer_calls = 0;
48 task_count = 0;
51 int Task1() {
52 last_task_ = 1;
53 task_count++;
54 return 0;
57 int Task2() {
58 last_task_ = 2;
59 task_count++;
60 return 0;
63 int FailingTask() {
64 // Task returning failure
65 last_task_ = 3;
66 task_count++;
67 return 1;
70 int GetLastTask() { return last_task_; }
72 private:
74 int 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
80 // trying to test.
82 // The mocks are not directly in TaskRunnerProxy because reference counted
83 // objects seem to confuse the mocking framework
85 class MockTaskRunner {
86 public:
87 MOCK_METHOD3(
88 PostDelayedTask,
89 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
90 MOCK_METHOD3(
91 PostNonNestableDelayedTask,
92 bool(const tracked_objects::Location&, const Closure&, base::TimeDelta));
95 class TaskRunnerProxy : public base::SingleThreadTaskRunner {
96 public:
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);
110 private:
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);
124 StartupTask task1 =
125 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
126 runner.AddTask(task1);
127 EXPECT_EQ(GetLastTask(), 0);
128 StartupTask task2 =
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
148 // again
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);
162 StartupTask task1 =
163 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
164 runner.AddTask(task1);
165 EXPECT_EQ(GetLastTask(), 0);
166 StartupTask task2 =
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);
197 StartupTask task3 =
198 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
199 runner.AddTask(task3);
200 EXPECT_EQ(GetLastTask(), 0);
201 StartupTask task2 =
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);
231 EXPECT_CALL(
232 mock_runner,
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);
239 StartupTask task1 =
240 base::Bind(&StartupTaskRunnerTest::Task1, base::Unretained(this));
241 runner.AddTask(task1);
242 StartupTask task2 =
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++) {
258 task.Run();
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);
278 EXPECT_CALL(
279 mock_runner,
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);
286 StartupTask task3 =
287 base::Bind(&StartupTaskRunnerTest::FailingTask, base::Unretained(this));
288 runner.AddTask(task3);
289 StartupTask task2 =
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++) {
305 task.Run();
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);
318 } // namespace
319 } // namespace content