blob: a4dd6d6e45f3f1b33121afdedbf853fe76b3064e [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]57624ab2013-08-01 16:01:512// 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
tzik070c8ffb2017-03-29 05:28:127#include <utility>
8
Avi Drissmanadac21992023-01-11 23:46:399#include "base/functional/bind.h"
10#include "base/functional/callback.h"
11#include "base/functional/callback_helpers.h"
[email protected]57624ab2013-08-01 16:01:5112#include "base/location.h"
Keishi Hattori0e45c022021-11-27 09:25:5213#include "base/memory/raw_ptr.h"
[email protected]57624ab2013-08-01 16:01:5114#include "base/run_loop.h"
Patrick Monette643cdf62021-10-15 19:13:4215#include "base/task/single_thread_task_runner.h"
16#include "base/task/task_runner.h"
[email protected]57624ab2013-08-01 16:01:5117
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace content {
22namespace {
23
[email protected]57624ab2013-08-01 16:01:5124using testing::_;
25using testing::Assign;
26using testing::Invoke;
[email protected]57624ab2013-08-01 16:01:5127
[email protected]b07c0812013-10-10 21:39:1528int observer_calls = 0;
29int task_count = 0;
[email protected]57624ab2013-08-01 16:01:5130int observer_result;
[email protected]57624ab2013-08-01 16:01:5131
Chidera Olibie76bdf2a2025-07-04 19:10:3232void Observer(int result, base::TimeDelta max_task_duration) {
[email protected]b07c0812013-10-10 21:39:1533 observer_calls++;
[email protected]57624ab2013-08-01 16:01:5134 observer_result = result;
35}
36
37class StartupTaskRunnerTest : public testing::Test {
38 public:
dchengfa85b152014-10-28 01:13:4239 void SetUp() override {
[email protected]57624ab2013-08-01 16:01:5140 last_task_ = 0;
[email protected]b07c0812013-10-10 21:39:1541 observer_calls = 0;
42 task_count = 0;
[email protected]57624ab2013-08-01 16:01:5143 }
44
45 int Task1() {
46 last_task_ = 1;
[email protected]b07c0812013-10-10 21:39:1547 task_count++;
[email protected]57624ab2013-08-01 16:01:5148 return 0;
49 }
50
51 int Task2() {
52 last_task_ = 2;
[email protected]b07c0812013-10-10 21:39:1553 task_count++;
[email protected]57624ab2013-08-01 16:01:5154 return 0;
55 }
56
57 int FailingTask() {
58 // Task returning failure
59 last_task_ = 3;
[email protected]b07c0812013-10-10 21:39:1560 task_count++;
[email protected]57624ab2013-08-01 16:01:5161 return 1;
62 }
63
64 int GetLastTask() { return last_task_; }
65
66 private:
67
68 int last_task_;
69};
70
71// We can't use the real message loop, even if we want to, since doing so on
72// Android requires a complex Java infrastructure. The test would have to built
73// as a content_shell test; but content_shell startup invokes the class we are
74// trying to test.
75//
76// The mocks are not directly in TaskRunnerProxy because reference counted
77// objects seem to confuse the mocking framework
78
79class MockTaskRunner {
80 public:
Brett Wilson1c990022017-09-12 20:11:1581 MOCK_METHOD2(PostDelayedTask, bool(const base::Location&, base::TimeDelta));
tzik070c8ffb2017-03-29 05:28:1282 MOCK_METHOD2(PostNonNestableDelayedTask,
Brett Wilson1c990022017-09-12 20:11:1583 bool(const base::Location&, base::TimeDelta));
[email protected]57624ab2013-08-01 16:01:5184};
85
86class TaskRunnerProxy : public base::SingleThreadTaskRunner {
87 public:
Chidera Olibie76bdf2a2025-07-04 19:10:3288 explicit TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {}
peary23322df62017-05-09 03:55:4889 bool RunsTasksInCurrentSequence() const override { return true; }
Brett Wilson1c990022017-09-12 20:11:1590 bool PostDelayedTask(const base::Location& location,
tzik6e427842017-04-05 10:13:2191 base::OnceClosure closure,
dchengc2282aa2014-10-21 12:07:5892 base::TimeDelta delta) override {
tzik070c8ffb2017-03-29 05:28:1293 last_task_ = std::move(closure);
94 return mock_->PostDelayedTask(location, delta);
[email protected]57624ab2013-08-01 16:01:5195 }
Brett Wilson1c990022017-09-12 20:11:1596 bool PostNonNestableDelayedTask(const base::Location& location,
tzik6e427842017-04-05 10:13:2197 base::OnceClosure closure,
dchengc2282aa2014-10-21 12:07:5898 base::TimeDelta delta) override {
tzik070c8ffb2017-03-29 05:28:1299 last_task_ = std::move(closure);
100 return mock_->PostNonNestableDelayedTask(location, delta);
[email protected]57624ab2013-08-01 16:01:51101 }
102
tzik6e427842017-04-05 10:13:21103 base::OnceClosure TakeLastTaskClosure() { return std::move(last_task_); }
tzik070c8ffb2017-03-29 05:28:12104
[email protected]57624ab2013-08-01 16:01:51105 private:
dchengc2282aa2014-10-21 12:07:58106 ~TaskRunnerProxy() override {}
tzik070c8ffb2017-03-29 05:28:12107
Keishi Hattori0e45c022021-11-27 09:25:52108 raw_ptr<MockTaskRunner> mock_;
tzik6e427842017-04-05 10:13:21109 base::OnceClosure last_task_;
[email protected]57624ab2013-08-01 16:01:51110};
111
112TEST_F(StartupTaskRunnerTest, SynchronousExecution) {
113 MockTaskRunner mock_runner;
114 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
115
tzik070c8ffb2017-03-29 05:28:12116 EXPECT_CALL(mock_runner, PostDelayedTask(_, _)).Times(0);
117 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _)).Times(0);
[email protected]57624ab2013-08-01 16:01:51118
Mark Pilgrimb9350ee2018-06-18 22:25:22119 StartupTaskRunner runner(base::BindOnce(&Observer), proxy);
[email protected]57624ab2013-08-01 16:01:51120
121 StartupTask task1 =
danakjf416ce9d2019-12-11 20:45:45122 base::BindOnce(&StartupTaskRunnerTest::Task1, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29123 runner.AddTask(std::move(task1));
[email protected]57624ab2013-08-01 16:01:51124 EXPECT_EQ(GetLastTask(), 0);
125 StartupTask task2 =
danakjf416ce9d2019-12-11 20:45:45126 base::BindOnce(&StartupTaskRunnerTest::Task2, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29127 runner.AddTask(std::move(task2));
[email protected]57624ab2013-08-01 16:01:51128
129 // Nothing should run until we tell them to.
130 EXPECT_EQ(GetLastTask(), 0);
[email protected]232e09d2013-08-27 15:29:56131 runner.RunAllTasksNow();
[email protected]57624ab2013-08-01 16:01:51132
133 // On an immediate StartupTaskRunner the tasks should now all have run.
134 EXPECT_EQ(GetLastTask(), 2);
135
[email protected]b07c0812013-10-10 21:39:15136 EXPECT_EQ(task_count, 2);
137 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51138 EXPECT_EQ(observer_result, 0);
[email protected]b07c0812013-10-10 21:39:15139
140 // Running the tasks asynchronously shouldn't do anything
141 // In particular Post... should not be called
142 runner.StartRunningTasksAsync();
143
144 // No more tasks should be run and the observer should not have been called
145 // again
146 EXPECT_EQ(task_count, 2);
147 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51148}
149
150TEST_F(StartupTaskRunnerTest, NullObserver) {
151 MockTaskRunner mock_runner;
152 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
153
tzik070c8ffb2017-03-29 05:28:12154 EXPECT_CALL(mock_runner, PostDelayedTask(_, _)).Times(0);
155 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _)).Times(0);
[email protected]57624ab2013-08-01 16:01:51156
Chidera Olibie76bdf2a2025-07-04 19:10:32157 StartupTaskRunner runner(base::OnceCallback<void(int, base::TimeDelta)>(),
158 proxy);
[email protected]57624ab2013-08-01 16:01:51159
160 StartupTask task1 =
danakjf416ce9d2019-12-11 20:45:45161 base::BindOnce(&StartupTaskRunnerTest::Task1, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29162 runner.AddTask(std::move(task1));
[email protected]57624ab2013-08-01 16:01:51163 EXPECT_EQ(GetLastTask(), 0);
164 StartupTask task2 =
danakjf416ce9d2019-12-11 20:45:45165 base::BindOnce(&StartupTaskRunnerTest::Task2, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29166 runner.AddTask(std::move(task2));
[email protected]57624ab2013-08-01 16:01:51167
168 // Nothing should run until we tell them to.
169 EXPECT_EQ(GetLastTask(), 0);
[email protected]232e09d2013-08-27 15:29:56170 runner.RunAllTasksNow();
[email protected]57624ab2013-08-01 16:01:51171
172 // On an immediate StartupTaskRunner the tasks should now all have run.
173 EXPECT_EQ(GetLastTask(), 2);
[email protected]b07c0812013-10-10 21:39:15174 EXPECT_EQ(task_count, 2);
[email protected]57624ab2013-08-01 16:01:51175
[email protected]b07c0812013-10-10 21:39:15176 // Running the tasks asynchronously shouldn't do anything
177 // In particular Post... should not be called
178 runner.StartRunningTasksAsync();
179
180 // No more tasks should have been run
181 EXPECT_EQ(task_count, 2);
182
183 EXPECT_EQ(observer_calls, 0);
[email protected]57624ab2013-08-01 16:01:51184}
185
186TEST_F(StartupTaskRunnerTest, SynchronousExecutionFailedTask) {
187 MockTaskRunner mock_runner;
188 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
189
tzik070c8ffb2017-03-29 05:28:12190 EXPECT_CALL(mock_runner, PostDelayedTask(_, _)).Times(0);
191 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, _)).Times(0);
[email protected]57624ab2013-08-01 16:01:51192
Mark Pilgrimb9350ee2018-06-18 22:25:22193 StartupTaskRunner runner(base::BindOnce(&Observer), proxy);
[email protected]57624ab2013-08-01 16:01:51194
danakjf416ce9d2019-12-11 20:45:45195 StartupTask task3 = base::BindOnce(&StartupTaskRunnerTest::FailingTask,
196 base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29197 runner.AddTask(std::move(task3));
[email protected]57624ab2013-08-01 16:01:51198 EXPECT_EQ(GetLastTask(), 0);
199 StartupTask task2 =
danakjf416ce9d2019-12-11 20:45:45200 base::BindOnce(&StartupTaskRunnerTest::Task2, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29201 runner.AddTask(std::move(task2));
[email protected]57624ab2013-08-01 16:01:51202
203 // Nothing should run until we tell them to.
204 EXPECT_EQ(GetLastTask(), 0);
[email protected]232e09d2013-08-27 15:29:56205 runner.RunAllTasksNow();
[email protected]57624ab2013-08-01 16:01:51206
207 // Only the first task should have run, since it failed
208 EXPECT_EQ(GetLastTask(), 3);
[email protected]b07c0812013-10-10 21:39:15209 EXPECT_EQ(task_count, 1);
210 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51211 EXPECT_EQ(observer_result, 1);
[email protected]b07c0812013-10-10 21:39:15212
213 // After a failed task all remaining tasks should be cancelled
214 // In particular Post... should not be called by running asynchronously
215 runner.StartRunningTasksAsync();
216
217 // The observer should only be called the first time the queue completes and
218 // no more tasks should have run
219 EXPECT_EQ(observer_calls, 1);
220 EXPECT_EQ(task_count, 1);
[email protected]57624ab2013-08-01 16:01:51221}
222
223TEST_F(StartupTaskRunnerTest, AsynchronousExecution) {
224
225 MockTaskRunner mock_runner;
226 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
227
tzik070c8ffb2017-03-29 05:28:12228 EXPECT_CALL(mock_runner, PostDelayedTask(_, _)).Times(0);
Peter Kastinge5a38ed2021-10-02 03:06:35229 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, base::Milliseconds(0)))
[email protected]57624ab2013-08-01 16:01:51230 .Times(testing::Between(2, 3))
tzik070c8ffb2017-03-29 05:28:12231 .WillRepeatedly(testing::Return(true));
[email protected]57624ab2013-08-01 16:01:51232
Mark Pilgrimb9350ee2018-06-18 22:25:22233 StartupTaskRunner runner(base::BindOnce(&Observer), proxy);
[email protected]57624ab2013-08-01 16:01:51234
235 StartupTask task1 =
danakjf416ce9d2019-12-11 20:45:45236 base::BindOnce(&StartupTaskRunnerTest::Task1, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29237 runner.AddTask(std::move(task1));
[email protected]57624ab2013-08-01 16:01:51238 StartupTask task2 =
danakjf416ce9d2019-12-11 20:45:45239 base::BindOnce(&StartupTaskRunnerTest::Task2, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29240 runner.AddTask(std::move(task2));
[email protected]57624ab2013-08-01 16:01:51241
242 // Nothing should run until we tell them to.
243 EXPECT_EQ(GetLastTask(), 0);
[email protected]232e09d2013-08-27 15:29:56244 runner.StartRunningTasksAsync();
[email protected]57624ab2013-08-01 16:01:51245
246 // No tasks should have run yet, since we the message loop hasn't run.
247 EXPECT_EQ(GetLastTask(), 0);
248
249 // Fake the actual message loop. Each time a task is run a new task should
250 // be added to the queue, hence updating "task". The loop should actually run
251 // at most 3 times (once for each task plus possibly once for the observer),
252 // the "4" is a backstop.
[email protected]b07c0812013-10-10 21:39:15253 for (int i = 0; i < 4 && observer_calls == 0; i++) {
tzik070c8ffb2017-03-29 05:28:12254 proxy->TakeLastTaskClosure().Run();
[email protected]57624ab2013-08-01 16:01:51255 EXPECT_EQ(i + 1, GetLastTask());
256 }
[email protected]b07c0812013-10-10 21:39:15257 EXPECT_EQ(task_count, 2);
258 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51259 EXPECT_EQ(observer_result, 0);
[email protected]b07c0812013-10-10 21:39:15260
261 // Check that running synchronously now doesn't do anything
262
263 runner.RunAllTasksNow();
264 EXPECT_EQ(task_count, 2);
265 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51266}
267
268TEST_F(StartupTaskRunnerTest, AsynchronousExecutionFailedTask) {
269
270 MockTaskRunner mock_runner;
271 scoped_refptr<TaskRunnerProxy> proxy = new TaskRunnerProxy(&mock_runner);
272
tzik070c8ffb2017-03-29 05:28:12273 EXPECT_CALL(mock_runner, PostDelayedTask(_, _)).Times(0);
Peter Kastinge5a38ed2021-10-02 03:06:35274 EXPECT_CALL(mock_runner, PostNonNestableDelayedTask(_, base::Milliseconds(0)))
[email protected]57624ab2013-08-01 16:01:51275 .Times(testing::Between(1, 2))
tzik070c8ffb2017-03-29 05:28:12276 .WillRepeatedly(testing::Return(true));
[email protected]57624ab2013-08-01 16:01:51277
Mark Pilgrimb9350ee2018-06-18 22:25:22278 StartupTaskRunner runner(base::BindOnce(&Observer), proxy);
[email protected]57624ab2013-08-01 16:01:51279
danakjf416ce9d2019-12-11 20:45:45280 StartupTask task3 = base::BindOnce(&StartupTaskRunnerTest::FailingTask,
281 base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29282 runner.AddTask(std::move(task3));
[email protected]57624ab2013-08-01 16:01:51283 StartupTask task2 =
danakjf416ce9d2019-12-11 20:45:45284 base::BindOnce(&StartupTaskRunnerTest::Task2, base::Unretained(this));
Tommy Nyquist4b749d02018-03-20 21:46:29285 runner.AddTask(std::move(task2));
[email protected]57624ab2013-08-01 16:01:51286
287 // Nothing should run until we tell them to.
288 EXPECT_EQ(GetLastTask(), 0);
[email protected]232e09d2013-08-27 15:29:56289 runner.StartRunningTasksAsync();
[email protected]57624ab2013-08-01 16:01:51290
Chidera Olibie76bdf2a2025-07-04 19:10:32291 // No tasks should have run yet, since the message loop hasn't run.
[email protected]57624ab2013-08-01 16:01:51292 EXPECT_EQ(GetLastTask(), 0);
293
Chidera Olibie76bdf2a2025-07-04 19:10:32294 // Fake the actual message loop. Each time a task is run, a new task should
[email protected]57624ab2013-08-01 16:01:51295 // be added to the queue, hence updating "task". The loop should actually run
296 // at most twice (once for the failed task plus possibly once for the
297 // observer), the "4" is a backstop.
tzik070c8ffb2017-03-29 05:28:12298 for (int i = 0; i < 4 && observer_calls == 0; i++)
299 proxy->TakeLastTaskClosure().Run();
[email protected]57624ab2013-08-01 16:01:51300 EXPECT_EQ(GetLastTask(), 3);
[email protected]b07c0812013-10-10 21:39:15301 EXPECT_EQ(task_count, 1);
[email protected]57624ab2013-08-01 16:01:51302
[email protected]b07c0812013-10-10 21:39:15303 EXPECT_EQ(observer_calls, 1);
[email protected]57624ab2013-08-01 16:01:51304 EXPECT_EQ(observer_result, 1);
[email protected]b07c0812013-10-10 21:39:15305
306 // Check that running synchronously now doesn't do anything
307 runner.RunAllTasksNow();
308 EXPECT_EQ(observer_calls, 1);
309 EXPECT_EQ(task_count, 1);
[email protected]57624ab2013-08-01 16:01:51310}
311} // namespace
312} // namespace content