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
17namespace content {
18namespace {
19
20using base::Closure;
21using testing::_;
22using testing::Assign;
23using testing::Invoke;
24using testing::WithArg;
25
26int observer_calls = 0;
27int task_count = 0;
28int observer_result;
29base::Closure task;
30
31// I couldn't get gMock's SaveArg to compile, hence had to save the argument
32// this way
33bool SaveTaskArg(const Closure& arg) {
34  task = arg;
35  return true;
36}
37
38void Observer(int result) {
39  observer_calls++;
40  observer_result = result;
41}
42
43class 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
86class 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
96class 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
117TEST_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
155TEST_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
190TEST_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
227TEST_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
274TEST_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