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
{
46 virtual void SetUp() {
65 // Task returning failure
71 int GetLastTask() { return last_task_
; }
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
83 // The mocks are not directly in TaskRunnerProxy because reference counted
84 // objects seem to confuse the mocking framework
86 class MockTaskRunner
{
90 bool(const tracked_objects::Location
&, const Closure
&, base::TimeDelta
));
92 PostNonNestableDelayedTask
,
93 bool(const tracked_objects::Location
&, const Closure
&, base::TimeDelta
));
96 class TaskRunnerProxy
: public base::SingleThreadTaskRunner
{
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
);
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
);
113 MockTaskRunner
* mock_
;
114 virtual ~TaskRunnerProxy() {}
117 TEST_F(StartupTaskRunnerTest
, SynchronousExecution
) {
118 MockTaskRunner mock_runner
;
119 scoped_refptr
<TaskRunnerProxy
> proxy
= new TaskRunnerProxy(&mock_runner
);
121 EXPECT_CALL(mock_runner
, PostDelayedTask(_
, _
, _
)).Times(0);
122 EXPECT_CALL(mock_runner
, PostNonNestableDelayedTask(_
, _
, _
)).Times(0);
124 StartupTaskRunner
runner(base::Bind(&Observer
), proxy
);
127 base::Bind(&StartupTaskRunnerTest::Task1
, base::Unretained(this));
128 runner
.AddTask(task1
);
129 EXPECT_EQ(GetLastTask(), 0);
131 base::Bind(&StartupTaskRunnerTest::Task2
, base::Unretained(this));
132 runner
.AddTask(task2
);
134 // Nothing should run until we tell them to.
135 EXPECT_EQ(GetLastTask(), 0);
136 runner
.RunAllTasksNow();
138 // On an immediate StartupTaskRunner the tasks should now all have run.
139 EXPECT_EQ(GetLastTask(), 2);
141 EXPECT_EQ(task_count
, 2);
142 EXPECT_EQ(observer_calls
, 1);
143 EXPECT_EQ(observer_result
, 0);
145 // Running the tasks asynchronously shouldn't do anything
146 // In particular Post... should not be called
147 runner
.StartRunningTasksAsync();
149 // No more tasks should be run and the observer should not have been called
151 EXPECT_EQ(task_count
, 2);
152 EXPECT_EQ(observer_calls
, 1);
155 TEST_F(StartupTaskRunnerTest
, NullObserver
) {
156 MockTaskRunner mock_runner
;
157 scoped_refptr
<TaskRunnerProxy
> proxy
= new TaskRunnerProxy(&mock_runner
);
159 EXPECT_CALL(mock_runner
, PostDelayedTask(_
, _
, _
)).Times(0);
160 EXPECT_CALL(mock_runner
, PostNonNestableDelayedTask(_
, _
, _
)).Times(0);
162 StartupTaskRunner
runner(base::Callback
<void(int)>(), proxy
);
165 base::Bind(&StartupTaskRunnerTest::Task1
, base::Unretained(this));
166 runner
.AddTask(task1
);
167 EXPECT_EQ(GetLastTask(), 0);
169 base::Bind(&StartupTaskRunnerTest::Task2
, base::Unretained(this));
170 runner
.AddTask(task2
);
172 // Nothing should run until we tell them to.
173 EXPECT_EQ(GetLastTask(), 0);
174 runner
.RunAllTasksNow();
176 // On an immediate StartupTaskRunner the tasks should now all have run.
177 EXPECT_EQ(GetLastTask(), 2);
178 EXPECT_EQ(task_count
, 2);
180 // Running the tasks asynchronously shouldn't do anything
181 // In particular Post... should not be called
182 runner
.StartRunningTasksAsync();
184 // No more tasks should have been run
185 EXPECT_EQ(task_count
, 2);
187 EXPECT_EQ(observer_calls
, 0);
190 TEST_F(StartupTaskRunnerTest
, SynchronousExecutionFailedTask
) {
191 MockTaskRunner mock_runner
;
192 scoped_refptr
<TaskRunnerProxy
> proxy
= new TaskRunnerProxy(&mock_runner
);
194 EXPECT_CALL(mock_runner
, PostDelayedTask(_
, _
, _
)).Times(0);
195 EXPECT_CALL(mock_runner
, PostNonNestableDelayedTask(_
, _
, _
)).Times(0);
197 StartupTaskRunner
runner(base::Bind(&Observer
), proxy
);
200 base::Bind(&StartupTaskRunnerTest::FailingTask
, base::Unretained(this));
201 runner
.AddTask(task3
);
202 EXPECT_EQ(GetLastTask(), 0);
204 base::Bind(&StartupTaskRunnerTest::Task2
, base::Unretained(this));
205 runner
.AddTask(task2
);
207 // Nothing should run until we tell them to.
208 EXPECT_EQ(GetLastTask(), 0);
209 runner
.RunAllTasksNow();
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);
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();
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);
227 TEST_F(StartupTaskRunnerTest
, AsynchronousExecution
) {
229 MockTaskRunner mock_runner
;
230 scoped_refptr
<TaskRunnerProxy
> proxy
= new TaskRunnerProxy(&mock_runner
);
232 EXPECT_CALL(mock_runner
, PostDelayedTask(_
, _
, _
)).Times(0);
235 PostNonNestableDelayedTask(_
, _
, base::TimeDelta::FromMilliseconds(0)))
236 .Times(testing::Between(2, 3))
237 .WillRepeatedly(WithArg
<1>(Invoke(SaveTaskArg
)));
239 StartupTaskRunner
runner(base::Bind(&Observer
), proxy
);
242 base::Bind(&StartupTaskRunnerTest::Task1
, base::Unretained(this));
243 runner
.AddTask(task1
);
245 base::Bind(&StartupTaskRunnerTest::Task2
, base::Unretained(this));
246 runner
.AddTask(task2
);
248 // Nothing should run until we tell them to.
249 EXPECT_EQ(GetLastTask(), 0);
250 runner
.StartRunningTasksAsync();
252 // No tasks should have run yet, since we the message loop hasn't run.
253 EXPECT_EQ(GetLastTask(), 0);
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
++) {
261 EXPECT_EQ(i
+ 1, GetLastTask());
263 EXPECT_EQ(task_count
, 2);
264 EXPECT_EQ(observer_calls
, 1);
265 EXPECT_EQ(observer_result
, 0);
267 // Check that running synchronously now doesn't do anything
269 runner
.RunAllTasksNow();
270 EXPECT_EQ(task_count
, 2);
271 EXPECT_EQ(observer_calls
, 1);
274 TEST_F(StartupTaskRunnerTest
, AsynchronousExecutionFailedTask
) {
276 MockTaskRunner mock_runner
;
277 scoped_refptr
<TaskRunnerProxy
> proxy
= new TaskRunnerProxy(&mock_runner
);
279 EXPECT_CALL(mock_runner
, PostDelayedTask(_
, _
, _
)).Times(0);
282 PostNonNestableDelayedTask(_
, _
, base::TimeDelta::FromMilliseconds(0)))
283 .Times(testing::Between(1, 2))
284 .WillRepeatedly(WithArg
<1>(Invoke(SaveTaskArg
)));
286 StartupTaskRunner
runner(base::Bind(&Observer
), proxy
);
289 base::Bind(&StartupTaskRunnerTest::FailingTask
, base::Unretained(this));
290 runner
.AddTask(task3
);
292 base::Bind(&StartupTaskRunnerTest::Task2
, base::Unretained(this));
293 runner
.AddTask(task2
);
295 // Nothing should run until we tell them to.
296 EXPECT_EQ(GetLastTask(), 0);
297 runner
.StartRunningTasksAsync();
299 // No tasks should have run yet, since we the message loop hasn't run.
300 EXPECT_EQ(GetLastTask(), 0);
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
++) {
309 EXPECT_EQ(GetLastTask(), 3);
310 EXPECT_EQ(task_count
, 1);
312 EXPECT_EQ(observer_calls
, 1);
313 EXPECT_EQ(observer_result
, 1);
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);
321 } // namespace content