• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_), BindOnce(&PostTaskNow),
90                                        nullptr);
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_), BindOnce(&PostTaskNow),
105                                        nullptr);
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_), BindOnce(&PostTaskNow),
125                                        nullptr);
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_), BindOnce(&PostTaskNow),
149                                        nullptr);
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_), BindOnce(&PostTaskNow),
163                                        nullptr);
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                                        nullptr);
187 
188   // The task isn't forwarded before the earliest run time is reached.
189   service_thread_task_runner_->FastForwardBy(kUnalignedLongDelay - kLeeway -
190                                              Milliseconds(1));
191   testing::Mock::VerifyAndClear(&mock_callback_);
192 
193   // Fast-forward time. Expect the task to be forwarded to PostTaskNow().
194   EXPECT_CALL(mock_callback_, Run());
195   service_thread_task_runner_->FastForwardBy(kLeeway + Milliseconds(1));
196 }
197 
198 // Verify that a delayed task added after Start() is forwarded when it is
199 // canceled, even if its delay hasn't expired.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTaskRunsAfterCancelled)200 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTaskRunsAfterCancelled) {
201   static_assert(kLongerDelay > kLongDelay, "");
202 
203   delayed_task_manager_.Start(service_thread_task_runner_);
204 
205   // Add a cancelable task to the DelayedTaskManager with a longer delay.
206   CancelableOnceClosure cancelable_closure(DoNothing());
207   bool post_cancelable_task_now_invoked = false;
208   Task cancelable_task(FROM_HERE, cancelable_closure.callback(),
209                        TimeTicks::Now(), kLongerDelay);
210   auto post_cancelable_task_now = BindLambdaForTesting(
211       [&](Task task) { post_cancelable_task_now_invoked = true; });
212   delayed_task_manager_.AddDelayedTask(std::move(cancelable_task),
213                                        post_cancelable_task_now, nullptr);
214 
215   // Add |task_| to the DelayedTaskManager with a long delay.
216   delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&PostTaskNow),
217                                        nullptr);
218 
219   // Cancel the cancelable task.
220   cancelable_closure.Cancel();
221 
222   // Fast-forward time by |kLongDelay|. The non-cancelable task should have its
223   // "post task now" callback invoked and it should run. The canceled task
224   // should have its "post task now" callback invoked, even if its delay hasn't
225   // expired.
226   EXPECT_CALL(mock_callback_, Run());
227   service_thread_task_runner_->FastForwardBy(kLongDelay);
228   EXPECT_TRUE(post_cancelable_task_now_invoked);
229 }
230 
231 // Verify that multiple delayed tasks added after Start() are forwarded when
232 // they are ripe for execution.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTasksRunAfterDelay)233 TEST_F(ThreadPoolDelayedTaskManagerTest, DelayedTasksRunAfterDelay) {
234   delayed_task_manager_.Start(service_thread_task_runner_);
235 
236   testing::StrictMock<MockCallback> mock_callback_a;
237   Task task_a = ConstructMockedTask(
238       mock_callback_a, service_thread_task_runner_->NowTicks(), Hours(1));
239 
240   testing::StrictMock<MockCallback> mock_callback_b;
241   Task task_b = ConstructMockedTask(
242       mock_callback_b, service_thread_task_runner_->NowTicks(), Hours(2));
243 
244   testing::StrictMock<MockCallback> mock_callback_c;
245   Task task_c = ConstructMockedTask(
246       mock_callback_c, service_thread_task_runner_->NowTicks(), Hours(1));
247 
248   // Send tasks to the DelayedTaskManager.
249   delayed_task_manager_.AddDelayedTask(std::move(task_a),
250                                        BindOnce(&PostTaskNow), nullptr);
251   delayed_task_manager_.AddDelayedTask(std::move(task_b),
252                                        BindOnce(&PostTaskNow), nullptr);
253   delayed_task_manager_.AddDelayedTask(std::move(task_c),
254                                        BindOnce(&PostTaskNow), nullptr);
255 
256   // Run tasks that are ripe for execution on the service thread. Don't expect
257   // any call to PostTaskNow().
258   service_thread_task_runner_->RunUntilIdle();
259 
260   // Fast-forward time. Expect |task_a| and |task_c| to be forwarded to
261   // |task_target_|.
262   EXPECT_CALL(mock_callback_a, Run());
263   EXPECT_CALL(mock_callback_c, Run());
264   service_thread_task_runner_->FastForwardBy(Hours(1));
265   testing::Mock::VerifyAndClear(&mock_callback_a);
266   testing::Mock::VerifyAndClear(&mock_callback_c);
267 
268   // Fast-forward time. Expect |task_b| to be forwarded to PostTaskNow().
269   EXPECT_CALL(mock_callback_b, Run());
270   service_thread_task_runner_->FastForwardBy(Hours(1));
271   testing::Mock::VerifyAndClear(&mock_callback_b);
272 }
273 
274 // Verify that multiple delayed tasks are forwarded respecting the order
275 // prescibed by their latest deadline.
TEST_F(ThreadPoolDelayedTaskManagerTest,DelayedTasksRunAtTime_MixedDelayPolicy)276 TEST_F(ThreadPoolDelayedTaskManagerTest,
277        DelayedTasksRunAtTime_MixedDelayPolicy) {
278   delayed_task_manager_.Start(service_thread_task_runner_);
279 
280   TimeTicks now = service_thread_task_runner_->NowTicks();
281   testing::StrictMock<MockCallback> mock_callback_a;
282   Task task_a =
283       ConstructMockedTask(mock_callback_a, now, now + Milliseconds(8),
284                           base::subtle::DelayPolicy::kFlexibleNoSooner);
285 
286   testing::StrictMock<MockCallback> mock_callback_b;
287   Task task_b =
288       ConstructMockedTask(mock_callback_b, now, now + Milliseconds(10),
289                           base::subtle::DelayPolicy::kPrecise);
290 
291   // Send tasks to the DelayedTaskManager.
292   delayed_task_manager_.AddDelayedTask(std::move(task_a),
293                                        BindOnce(&PostTaskNow), nullptr);
294   EXPECT_EQ(base::subtle::DelayPolicy::kFlexibleNoSooner,
295             delayed_task_manager_.TopTaskDelayPolicyForTesting());
296   delayed_task_manager_.AddDelayedTask(std::move(task_b),
297                                        BindOnce(&PostTaskNow), nullptr);
298   EXPECT_EQ(base::subtle::DelayPolicy::kPrecise,
299             delayed_task_manager_.TopTaskDelayPolicyForTesting());
300 
301   // The task doesn't run before the delay has completed.
302   service_thread_task_runner_->FastForwardBy(Milliseconds(10) -
303                                              Milliseconds(1));
304 
305   // Run tasks that are ripe for execution on the service thread. Don't expect
306   // any call to PostTaskNow().
307   service_thread_task_runner_->RunUntilIdle();
308 
309   // Fast-forward time. Expect |task_b| and |task_b| to be forwarded.
310   EXPECT_CALL(mock_callback_b, Run());
311   EXPECT_CALL(mock_callback_a, Run());
312   service_thread_task_runner_->FastForwardBy(Milliseconds(1));
313 }
314 
TEST_F(ThreadPoolDelayedTaskManagerTest,PostTaskDuringStart)315 TEST_F(ThreadPoolDelayedTaskManagerTest, PostTaskDuringStart) {
316   Thread other_thread("Test");
317   other_thread.StartAndWaitForTesting();
318 
319   WaitableEvent task_posted;
320 
321   other_thread.task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
322                                          delayed_task_manager_.AddDelayedTask(
323                                              std::move(task_),
324                                              BindOnce(&PostTaskNow),
325                                              other_thread.task_runner());
326                                          task_posted.Signal();
327                                        }));
328 
329   delayed_task_manager_.Start(service_thread_task_runner_);
330 
331   // The test is testing a race between AddDelayedTask/Start but it still needs
332   // synchronization to ensure we don't do the final verification before the
333   // task itself is posted.
334   task_posted.Wait();
335 
336   // Fast-forward time. Expect the task to be forwarded to PostTaskNow().
337   EXPECT_CALL(mock_callback_, Run());
338   service_thread_task_runner_->FastForwardBy(kLongDelay);
339 }
340 
341 }  // namespace internal
342 }  // namespace base
343