1 // Copyright 2016 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.
4
5 #include "base/task_scheduler/delayed_task_manager.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/task_scheduler/task.h"
15 #include "base/test/bind_test_util.h"
16 #include "base/test/test_mock_time_task_runner.h"
17 #include "base/threading/thread.h"
18 #include "base/time/time.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace base {
23 namespace internal {
24 namespace {
25
26 constexpr TimeDelta kLongDelay = TimeDelta::FromHours(1);
27
28 class MockTask {
29 public:
30 MOCK_METHOD0(Run, void());
31 };
32
RunTask(Task task)33 void RunTask(Task task) {
34 std::move(task.task).Run();
35 }
36
37 class TaskSchedulerDelayedTaskManagerTest : public testing::Test {
38 protected:
TaskSchedulerDelayedTaskManagerTest()39 TaskSchedulerDelayedTaskManagerTest()
40 : delayed_task_manager_(
41 service_thread_task_runner_->DeprecatedGetMockTickClock()),
42 task_(FROM_HERE,
43 BindOnce(&MockTask::Run, Unretained(&mock_task_)),
44 TaskTraits(),
45 kLongDelay) {
46 // The constructor of Task computes |delayed_run_time| by adding |delay| to
47 // the real time. Recompute it by adding |delay| to the mock time.
48 task_.delayed_run_time =
49 service_thread_task_runner_->GetMockTickClock()->NowTicks() +
50 kLongDelay;
51 }
52 ~TaskSchedulerDelayedTaskManagerTest() override = default;
53
54 const scoped_refptr<TestMockTimeTaskRunner> service_thread_task_runner_ =
55 MakeRefCounted<TestMockTimeTaskRunner>();
56 DelayedTaskManager delayed_task_manager_;
57 testing::StrictMock<MockTask> mock_task_;
58 Task task_;
59
60 private:
61 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerDelayedTaskManagerTest);
62 };
63
64 } // namespace
65
66 // Verify that a delayed task isn't forwarded before Start().
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTaskDoesNotRunBeforeStart)67 TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskDoesNotRunBeforeStart) {
68 // Send |task| to the DelayedTaskManager.
69 delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask));
70
71 // Fast-forward time until the task is ripe for execution. Since Start() has
72 // not been called, the task should not be forwarded to RunTask() (MockTask is
73 // a StrictMock without expectations so test will fail if RunTask() runs it).
74 service_thread_task_runner_->FastForwardBy(kLongDelay);
75 }
76
77 // Verify that a delayed task added before Start() and whose delay expires after
78 // Start() is forwarded when its delay expires.
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire)79 TEST_F(TaskSchedulerDelayedTaskManagerTest,
80 DelayedTaskPostedBeforeStartExpiresAfterStartRunsOnExpire) {
81 // Send |task| to the DelayedTaskManager.
82 delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask));
83
84 delayed_task_manager_.Start(service_thread_task_runner_);
85
86 // Run tasks on the service thread. Don't expect any forwarding to
87 // |task_target_| since the task isn't ripe for execution.
88 service_thread_task_runner_->RunUntilIdle();
89
90 // Fast-forward time until the task is ripe for execution. Expect the task to
91 // be forwarded to RunTask().
92 EXPECT_CALL(mock_task_, Run());
93 service_thread_task_runner_->FastForwardBy(kLongDelay);
94 }
95
96 // Verify that a delayed task added before Start() and whose delay expires
97 // before Start() is forwarded when Start() is called.
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart)98 TEST_F(TaskSchedulerDelayedTaskManagerTest,
99 DelayedTaskPostedBeforeStartExpiresBeforeStartRunsOnStart) {
100 // Send |task| to the DelayedTaskManager.
101 delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask));
102
103 // Run tasks on the service thread. Don't expect any forwarding to
104 // |task_target_| since the task isn't ripe for execution.
105 service_thread_task_runner_->RunUntilIdle();
106
107 // Fast-forward time until the task is ripe for execution. Don't expect the
108 // task to be forwarded since Start() hasn't been called yet.
109 service_thread_task_runner_->FastForwardBy(kLongDelay);
110
111 // Start the DelayedTaskManager. Expect the task to be forwarded to RunTask().
112 EXPECT_CALL(mock_task_, Run());
113 delayed_task_manager_.Start(service_thread_task_runner_);
114 service_thread_task_runner_->RunUntilIdle();
115 }
116
117 // Verify that a delayed task added after Start() isn't forwarded before it is
118 // ripe for execution.
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTaskDoesNotRunTooEarly)119 TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskDoesNotRunTooEarly) {
120 delayed_task_manager_.Start(service_thread_task_runner_);
121
122 // Send |task| to the DelayedTaskManager.
123 delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask));
124
125 // Run tasks that are ripe for execution. Don't expect any forwarding to
126 // RunTask().
127 service_thread_task_runner_->RunUntilIdle();
128 }
129
130 // Verify that a delayed task added after Start() is forwarded when it is ripe
131 // for execution.
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTaskRunsAfterDelay)132 TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTaskRunsAfterDelay) {
133 delayed_task_manager_.Start(service_thread_task_runner_);
134
135 // Send |task| to the DelayedTaskManager.
136 delayed_task_manager_.AddDelayedTask(std::move(task_), BindOnce(&RunTask));
137
138 // Fast-forward time. Expect the task to be forwarded to RunTask().
139 EXPECT_CALL(mock_task_, Run());
140 service_thread_task_runner_->FastForwardBy(kLongDelay);
141 }
142
143 // Verify that multiple delayed tasks added after Start() are forwarded when
144 // they are ripe for execution.
TEST_F(TaskSchedulerDelayedTaskManagerTest,DelayedTasksRunAfterDelay)145 TEST_F(TaskSchedulerDelayedTaskManagerTest, DelayedTasksRunAfterDelay) {
146 delayed_task_manager_.Start(service_thread_task_runner_);
147
148 testing::StrictMock<MockTask> mock_task_a;
149 Task task_a(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_a)),
150 TaskTraits(), TimeDelta::FromHours(1));
151
152 testing::StrictMock<MockTask> mock_task_b;
153 Task task_b(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_b)),
154 TaskTraits(), TimeDelta::FromHours(2));
155
156 testing::StrictMock<MockTask> mock_task_c;
157 Task task_c(FROM_HERE, BindOnce(&MockTask::Run, Unretained(&mock_task_c)),
158 TaskTraits(), TimeDelta::FromHours(1));
159
160 // Send tasks to the DelayedTaskManager.
161 delayed_task_manager_.AddDelayedTask(std::move(task_a), BindOnce(&RunTask));
162 delayed_task_manager_.AddDelayedTask(std::move(task_b), BindOnce(&RunTask));
163 delayed_task_manager_.AddDelayedTask(std::move(task_c), BindOnce(&RunTask));
164
165 // Run tasks that are ripe for execution on the service thread. Don't expect
166 // any call to RunTask().
167 service_thread_task_runner_->RunUntilIdle();
168
169 // Fast-forward time. Expect |task_a| and |task_c| to be forwarded to
170 // |task_target_|.
171 EXPECT_CALL(mock_task_a, Run());
172 EXPECT_CALL(mock_task_c, Run());
173 service_thread_task_runner_->FastForwardBy(TimeDelta::FromHours(1));
174 testing::Mock::VerifyAndClear(&mock_task_a);
175 testing::Mock::VerifyAndClear(&mock_task_c);
176
177 // Fast-forward time. Expect |task_b| to be forwarded to RunTask().
178 EXPECT_CALL(mock_task_b, Run());
179 service_thread_task_runner_->FastForwardBy(TimeDelta::FromHours(1));
180 testing::Mock::VerifyAndClear(&mock_task_b);
181 }
182
TEST_F(TaskSchedulerDelayedTaskManagerTest,PostTaskDuringStart)183 TEST_F(TaskSchedulerDelayedTaskManagerTest, PostTaskDuringStart) {
184 Thread other_thread("Test");
185 other_thread.StartAndWaitForTesting();
186
187 WaitableEvent task_posted;
188
189 other_thread.task_runner()->PostTask(FROM_HERE, BindLambdaForTesting([&]() {
190 delayed_task_manager_.AddDelayedTask(
191 std::move(task_),
192 BindOnce(&RunTask));
193 task_posted.Signal();
194 }));
195
196 delayed_task_manager_.Start(service_thread_task_runner_);
197
198 // The test is testing a race between AddDelayedTask/Start but it still needs
199 // synchronization to ensure we don't do the final verification before the
200 // task itself is posted.
201 task_posted.Wait();
202
203 // Fast-forward time. Expect the task to be forwarded to RunTask().
204 EXPECT_CALL(mock_task_, Run());
205 service_thread_task_runner_->FastForwardBy(kLongDelay);
206 }
207
208 } // namespace internal
209 } // namespace base
210