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