1 // Copyright 2016 The Chromium Authors
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 "base/task/thread_pool/delayed_task_manager.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/cancelable_callback.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/task/task_features.h"
17 #include "base/task/thread_pool/task.h"
18 #include "base/test/bind.h"
19 #include "base/test/scoped_feature_list.h"
20 #include "base/test/test_mock_time_task_runner.h"
21 #include "base/threading/thread.h"
22 #include "base/time/time.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace base {
27 namespace internal {
28 namespace {
29
30 constexpr TimeDelta kLongerDelay = Hours(3);
31 constexpr TimeDelta kLongDelay = Hours(1);
32 constexpr TimeDelta kLeeway = base::kDefaultLeeway;
33
34 class MockCallback {
35 public:
36 MOCK_METHOD0(Run, void());
37 };
38
PostTaskNow(Task task)39 void PostTaskNow(Task task) {
40 std::move(task.task).Run();
41 }
42
ConstructMockedTask(testing::StrictMock<MockCallback> & mock_task,TimeTicks now,TimeDelta delay)43 Task ConstructMockedTask(testing::StrictMock<MockCallback>& mock_task,
44 TimeTicks now,
45 TimeDelta delay) {
46 Task task(FROM_HERE, BindOnce(&MockCallback::Run, Unretained(&mock_task)),
47 now, delay);
48 return task;
49 }
50
ConstructMockedTask(testing::StrictMock<MockCallback> & mock_task,TimeTicks now,TimeTicks delayed_run_time,subtle::DelayPolicy delay_policy)51 Task ConstructMockedTask(testing::StrictMock<MockCallback>& mock_task,
52 TimeTicks now,
53 TimeTicks delayed_run_time,
54 subtle::DelayPolicy delay_policy) {
55 Task task(FROM_HERE, BindOnce(&MockCallback::Run, Unretained(&mock_task)),
56 now, delayed_run_time, kLeeway, delay_policy);
57 return task;
58 }
59
60 class ThreadPoolDelayedTaskManagerTest : public testing::Test {
61 public:
62 ThreadPoolDelayedTaskManagerTest(const ThreadPoolDelayedTaskManagerTest&) =
63 delete;
64 ThreadPoolDelayedTaskManagerTest& operator=(
65 const ThreadPoolDelayedTaskManagerTest&) = delete;
66
67 protected:
ThreadPoolDelayedTaskManagerTest()68 ThreadPoolDelayedTaskManagerTest() {
69 // A null clock triggers some assertions.
70 service_thread_task_runner_->AdvanceMockTickClock(Milliseconds(1));
71 task_ = ConstructMockedTask(
72 mock_callback_, service_thread_task_runner_->NowTicks(), kLongDelay);
73 }
74 ~ThreadPoolDelayedTaskManagerTest() override = default;
75
76 const scoped_refptr<TestMockTimeTaskRunner> service_thread_task_runner_ =
77 MakeRefCounted<TestMockTimeTaskRunner>();
78 DelayedTaskManager delayed_task_manager_{
79 service_thread_task_runner_->GetMockTickClock()};
80 testing::StrictMock<MockCallback> mock_callback_;
81 Task task_;
82 };
83
84 } // namespace
85
86 // Verify that a delayed task isn't forwarded before Start().
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskDoesNotRunBeforeStart)87 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskDoesNotRunBeforeStart) {
88 // Send |task| to the DelayedTaskManager.
89 delayed_task_manager_.AddDelayedTask(std::move(task_),
90 BindOnce(&PostTaskNow));
91
92 // Fast-forward time until the task is ripe for execution. Since Start() has
93 // not been called, the task should not be forwarded to PostTaskNow()
94 // (MockCallback is a StrictMock without expectations so test will fail if
95 // PostTaskNow() runs it).
96 service_thread_task_runner_->FastForwardBy(kLongDelay);
97 }
98
99 // Verify that a delayed task added before Start() and whose delay expires after
100 // Start() is forwarded when its delay expires.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire)101 TEST_F(ThreadPoolDelayedTaskManagerTest,
102 DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire) {
103 // Send |task| to the DelayedTaskManager.
104 delayed_task_manager_.AddDelayedTask(std::move(task_),
105 BindOnce(&PostTaskNow));
106
107 delayed_task_manager_.Start(service_thread_task_runner_);
108
109 // Run tasks on the service thread. Don't expect any forwarding to
110 // |task_target_| since the task isn't ripe for execution.
111 service_thread_task_runner_->RunUntilIdle();
112
113 // Fast-forward time until the task is ripe for execution. Expect the task to
114 // be forwarded to PostTaskNow().
115 EXPECT_CALL(mock_callback_, Run());
116 service_thread_task_runner_->FastForwardBy(kLongDelay);
117 }
118
119 // Verify that a delayed task added before Start() and whose delay expires
120 // before Start() is forwarded when Start() is called.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart)121 TEST_F(ThreadPoolDelayedTaskManagerTest,
122 DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart) {
123 // Send |task| to the DelayedTaskManager.
124 delayed_task_manager_.AddDelayedTask(std::move(task_),
125 BindOnce(&PostTaskNow));
126
127 // Run tasks on the service thread. Don't expect any forwarding to
128 // |task_target_| since the task isn't ripe for execution.
129 service_thread_task_runner_->RunUntilIdle();
130
131 // Fast-forward time until the task is ripe for execution. Don't expect the
132 // task to be forwarded since Start() hasn't been called yet.
133 service_thread_task_runner_->FastForwardBy(kLongDelay);
134
135 // Start the DelayedTaskManager. Expect the task to be forwarded to
136 // PostTaskNow().
137 EXPECT_CALL(mock_callback_, Run());
138 delayed_task_manager_.Start(service_thread_task_runner_);
139 service_thread_task_runner_->RunUntilIdle();
140 }
141
142 // Verify that a delayed task added after Start() isn't forwarded before it is
143 // ripe for execution.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskDoesNotRunTooEarly)144 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskDoesNotRunTooEarly) {
145 delayed_task_manager_.Start(service_thread_task_runner_);
146
147 // Send |task| to the DelayedTaskManager.
148 delayed_task_manager_.AddDelayedTask(std::move(task_),
149 BindOnce(&PostTaskNow));
150
151 // Run tasks that are ripe for execution. Don't expect any forwarding to
152 // PostTaskNow().
153 service_thread_task_runner_->RunUntilIdle();
154 }
155
156 // Verify that a delayed task added after Start() is forwarded when it is ripe
157 // for execution.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskRunsAfterDelay)158 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskRunsAfterDelay) {
159 delayed_task_manager_.Start(service_thread_task_runner_);
160
161 // Send |task| to the DelayedTaskManager.
162 delayed_task_manager_.AddDelayedTask(std::move(task_),
163 BindOnce(&PostTaskNow));
164
165 // Fast-forward time. Expect the task to be forwarded to PostTaskNow().
166 EXPECT_CALL(mock_callback_, Run());
167 service_thread_task_runner_->FastForwardBy(kLongDelay);
168 }
169
170 // Verify that a delayed task posted with kFlexiblePreferEarly delay policy
171 // is forwarded within the leeway period preceding the deadline.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskRunsAtTime_FlexiblePreferEarly)172 TEST_F(ThreadPoolDelayedTaskManagerTest,
173 DelayedTaskRunsAtTime_FlexiblePreferEarly) {
174 const TimeDelta kUnalignedLongDelay = kLongDelay + Milliseconds(1);
175 base::test::ScopedFeatureList feature_list;
176 feature_list.InitAndEnableFeature(kAlignWakeUps);
177 delayed_task_manager_.Start(service_thread_task_runner_);
178
179 TimeTicks now = service_thread_task_runner_->NowTicks();
180 Task task =
181 ConstructMockedTask(mock_callback_, now, now + kUnalignedLongDelay,
182 base::subtle::DelayPolicy::kFlexiblePreferEarly);
183
184 // Send |task| to the DelayedTaskManager.
185 delayed_task_manager_.AddDelayedTask(std::move(task), BindOnce(&PostTaskNow));
186
187 // The task isn't forwarded before the earliest run time is reached.
188 service_thread_task_runner_->FastForwardBy(kUnalignedLongDelay - kLeeway -
189 Milliseconds(1));
190 testing::Mock::VerifyAndClear(&mock_callback_);
191
192 // Fast-forward time. Expect the task to be forwarded to PostTaskNow().
193 EXPECT_CALL(mock_callback_, Run());
194 service_thread_task_runner_->FastForwardBy(kLeeway + Milliseconds(1));
195 }
196
197 // Verify that a delayed task added after Start() is forwarded when it is
198 // canceled, even if its delay hasn't expired.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskRunsAfterCancelled)199 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskRunsAfterCancelled) {
200 static_assert(kLongerDelay > kLongDelay, "");
201
202 delayed_task_manager_.Start(service_thread_task_runner_);
203
204 // Add a cancelable task to the DelayedTaskManager with a longer delay.
205 CancelableOnceClosure cancelable_closure(DoNothing());
206 bool post_cancelable_task_now_invoked = false;
207 Task cancelable_task(FROM_HERE, cancelable_closure.callback(),
208 TimeTicks::Now(), kLongerDelay);
209 auto post_cancelable_task_now = BindLambdaForTesting(
210 [&](Task task) { post_cancelable_task_now_invoked = true; });
211 delayed_task_manager_.AddDelayedTask(std::move(cancelable_task),
212 post_cancelable_task_now);
213
214 // Add |task_| to the DelayedTaskManager with a long delay.
215 delayed_task_manager_.AddDelayedTask(std::move(task_),
216 BindOnce(&PostTaskNow));
217
218 // Cancel the cancelable task.
219 cancelable_closure.Cancel();
220
221 // Fast-forward time by |kLongDelay|. The non-cancelable task should have its
222 // "post task now" callback invoked and it should run. The canceled task
223 // should have its "post task now" callback invoked, even if its delay hasn't
224 // expired.
225 EXPECT_CALL(mock_callback_, Run());
226 service_thread_task_runner_->FastForwardBy(kLongDelay);
227 EXPECT_TRUE(post_cancelable_task_now_invoked);
228 }
229
230 // Verify that multiple delayed tasks added after Start() are forwarded when
231 // they are ripe for execution.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTasksRunAfterDelay)232 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTasksRunAfterDelay) {
233 delayed_task_manager_.Start(service_thread_task_runner_);
234
235 testing::StrictMock<MockCallback> mock_callback_a;
236 Task task_a = ConstructMockedTask(
237 mock_callback_a, service_thread_task_runner_->NowTicks(), Hours(1));
238
239 testing::StrictMock<MockCallback> mock_callback_b;
240 Task task_b = ConstructMockedTask(
241 mock_callback_b, service_thread_task_runner_->NowTicks(), Hours(2));
242
243 testing::StrictMock<MockCallback> mock_callback_c;
244 Task task_c = ConstructMockedTask(
245 mock_callback_c, service_thread_task_runner_->NowTicks(), Hours(1));
246
247 // Send tasks to the DelayedTaskManager.
248 delayed_task_manager_.AddDelayedTask(std::move(task_a),
249 BindOnce(&PostTaskNow));
250 delayed_task_manager_.AddDelayedTask(std::move(task_b),
251 BindOnce(&PostTaskNow));
252 delayed_task_manager_.AddDelayedTask(std::move(task_c),
253 BindOnce(&PostTaskNow));
254
255 // Run tasks that are ripe for execution on the service thread. Don't expect
256 // any call to PostTaskNow().
257 service_thread_task_runner_->RunUntilIdle();
258
259 // Fast-forward time. Expect |task_a| and |task_c| to be forwarded to
260 // |task_target_|.
261 EXPECT_CALL(mock_callback_a, Run());
262 EXPECT_CALL(mock_callback_c, Run());
263 service_thread_task_runner_->FastForwardBy(Hours(1));
264 testing::Mock::VerifyAndClear(&mock_callback_a);
265 testing::Mock::VerifyAndClear(&mock_callback_c);
266
267 // Fast-forward time. Expect |task_b| to be forwarded to PostTaskNow().
268 EXPECT_CALL(mock_callback_b, Run());
269 service_thread_task_runner_->FastForwardBy(Hours(1));
270 testing::Mock::VerifyAndClear(&mock_callback_b);
271 }
272
273 // Verify that multiple delayed tasks are forwarded respecting the order
274 // prescibed by their latest deadline.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTasksRunAtTime_MixedDelayPolicy)275 TEST_F(ThreadPoolDelayedTaskManagerTest,
276 DelayedTasksRunAtTime_MixedDelayPolicy) {
277 delayed_task_manager_.Start(service_thread_task_runner_);
278
279 TimeTicks now = service_thread_task_runner_->NowTicks();
280 testing::StrictMock<MockCallback> mock_callback_a;
281 Task task_a =
282 ConstructMockedTask(mock_callback_a, now, now + Milliseconds(8),
283 base::subtle::DelayPolicy::kFlexibleNoSooner);
284
285 testing::StrictMock<MockCallback> mock_callback_b;
286 Task task_b =
287 ConstructMockedTask(mock_callback_b, now, now + Milliseconds(10),
288 base::subtle::DelayPolicy::kPrecise);
289
290 // Send tasks to the DelayedTaskManager.
291 delayed_task_manager_.AddDelayedTask(std::move(task_a),
292 BindOnce(&PostTaskNow));
293 EXPECT_EQ(base::subtle::DelayPolicy::kFlexibleNoSooner,
294 delayed_task_manager_.TopTaskDelayPolicyForTesting());
295 delayed_task_manager_.AddDelayedTask(std::move(task_b),
296 BindOnce(&PostTaskNow));
297 EXPECT_EQ(base::subtle::DelayPolicy::kPrecise,
298 delayed_task_manager_.TopTaskDelayPolicyForTesting());
299
300 // The task doesn't run before the delay has completed.
301 service_thread_task_runner_->FastForwardBy(Milliseconds(10) -
302 Milliseconds(1));
303
304 // Run tasks that are ripe for execution on the service thread. Don't expect
305 // any call to PostTaskNow().
306 service_thread_task_runner_->RunUntilIdle();
307
308 // Fast-forward time. Expect |task_b| and |task_b| to be forwarded.
309 EXPECT_CALL(mock_callback_b, Run());
310 EXPECT_CALL(mock_callback_a, Run());
311 service_thread_task_runner_->FastForwardBy(Milliseconds(1));
312 }
313
TEST_F(ThreadPoolDelayedTaskManagerTest,PostTaskDuringStart)314 TEST_F(ThreadPoolDelayedTaskManagerTest, PostTaskDuringStart) {
315 Thread other_thread("Test");
316 other_thread.StartAndWaitForTesting();
317
318 WaitableEvent task_posted;
319
320 other_thread.task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
321 delayed_task_manager_.AddDelayedTask(
322 std::move(task_),
323 BindOnce(&PostTaskNow));
324 task_posted.Signal();
325 }));
326
327 delayed_task_manager_.Start(service_thread_task_runner_);
328
329 // The test is testing a race between AddDelayedTask/Start but it still needs
330 // synchronization to ensure we don't do the final verification before the
331 // task itself is posted.
332 task_posted.Wait();
333
334 // Fast-forward time. Expect the task to be forwarded to PostTaskNow().
335 EXPECT_CALL(mock_callback_, Run());
336 service_thread_task_runner_->FastForwardBy(kLongDelay);
337 }
338
339 } // namespace internal
340 } // namespace base
341