1 // Copyright 2015 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/sequence_manager/time_domain.h"
6
7 #include <memory>
8 #include "base/macros.h"
9 #include "base/memory/ptr_util.h"
10 #include "base/task/sequence_manager/sequence_manager_impl.h"
11 #include "base/task/sequence_manager/task_queue_impl.h"
12 #include "base/task/sequence_manager/work_queue.h"
13 #include "base/test/simple_test_tick_clock.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15
16 using testing::_;
17 using testing::AnyNumber;
18 using testing::Mock;
19
20 namespace base {
21 namespace sequence_manager {
22
23 class TaskQueueImplForTest : public internal::TaskQueueImpl {
24 public:
TaskQueueImplForTest(internal::SequenceManagerImpl * sequence_manager,TimeDomain * time_domain,const TaskQueue::Spec & spec)25 TaskQueueImplForTest(internal::SequenceManagerImpl* sequence_manager,
26 TimeDomain* time_domain,
27 const TaskQueue::Spec& spec)
28 : TaskQueueImpl(sequence_manager, time_domain, spec) {}
~TaskQueueImplForTest()29 ~TaskQueueImplForTest() {}
30
31 using TaskQueueImpl::SetDelayedWakeUpForTesting;
32 };
33
34 class TestTimeDomain : public TimeDomain {
35 public:
TestTimeDomain()36 TestTimeDomain() : now_(TimeTicks() + TimeDelta::FromSeconds(1)) {}
37
38 ~TestTimeDomain() override = default;
39
40 using TimeDomain::NextScheduledRunTime;
41 using TimeDomain::SetNextWakeUpForQueue;
42 using TimeDomain::UnregisterQueue;
43 using TimeDomain::WakeUpReadyDelayedQueues;
44
CreateLazyNow() const45 LazyNow CreateLazyNow() const override { return LazyNow(now_); }
Now() const46 TimeTicks Now() const override { return now_; }
47
DelayTillNextTask(LazyNow * lazy_now)48 Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override {
49 return Optional<TimeDelta>();
50 }
51
AsValueIntoInternal(trace_event::TracedValue * state) const52 void AsValueIntoInternal(trace_event::TracedValue* state) const override {}
GetName() const53 const char* GetName() const override { return "Test"; }
54
NextScheduledTaskQueue() const55 internal::TaskQueueImpl* NextScheduledTaskQueue() const {
56 if (delayed_wake_up_queue_.empty())
57 return nullptr;
58 return delayed_wake_up_queue_.Min().queue;
59 }
60
61 MOCK_METHOD2(SetNextDelayedDoWork,
62 void(LazyNow* lazy_now, TimeTicks run_time));
63
SetNow(TimeTicks now)64 void SetNow(TimeTicks now) { now_ = now; }
65
66 private:
67 TimeTicks now_;
68
69 DISALLOW_COPY_AND_ASSIGN(TestTimeDomain);
70 };
71
72 class TimeDomainTest : public testing::Test {
73 public:
SetUp()74 void SetUp() final {
75 time_domain_ = WrapUnique(CreateTestTimeDomain());
76 task_queue_ = std::make_unique<TaskQueueImplForTest>(
77 nullptr, time_domain_.get(), TaskQueue::Spec("test"));
78 }
79
TearDown()80 void TearDown() final {
81 if (task_queue_)
82 task_queue_->UnregisterTaskQueue();
83 }
84
CreateTestTimeDomain()85 virtual TestTimeDomain* CreateTestTimeDomain() {
86 return new TestTimeDomain();
87 }
88
89 std::unique_ptr<TestTimeDomain> time_domain_;
90 std::unique_ptr<TaskQueueImplForTest> task_queue_;
91 };
92
TEST_F(TimeDomainTest,ScheduleWakeUpForQueue)93 TEST_F(TimeDomainTest, ScheduleWakeUpForQueue) {
94 TimeDelta delay = TimeDelta::FromMilliseconds(10);
95 TimeTicks delayed_runtime = time_domain_->Now() + delay;
96 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime));
97 TimeTicks now = time_domain_->Now();
98 LazyNow lazy_now(now);
99 task_queue_->SetDelayedWakeUpForTesting(
100 internal::TaskQueueImpl::DelayedWakeUp{now + delay, 0});
101
102 EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
103
104 EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
105 Mock::VerifyAndClearExpectations(time_domain_.get());
106
107 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()))
108 .Times(AnyNumber());
109 }
110
TEST_F(TimeDomainTest,ScheduleWakeUpForQueueSupersedesPreviousWakeUp)111 TEST_F(TimeDomainTest, ScheduleWakeUpForQueueSupersedesPreviousWakeUp) {
112 TimeDelta delay1 = TimeDelta::FromMilliseconds(10);
113 TimeDelta delay2 = TimeDelta::FromMilliseconds(100);
114 TimeTicks delayed_runtime1 = time_domain_->Now() + delay1;
115 TimeTicks delayed_runtime2 = time_domain_->Now() + delay2;
116 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime1));
117 TimeTicks now = time_domain_->Now();
118 LazyNow lazy_now(now);
119 task_queue_->SetDelayedWakeUpForTesting(
120 internal::TaskQueueImpl::DelayedWakeUp{delayed_runtime1, 0});
121
122 EXPECT_EQ(delayed_runtime1, time_domain_->NextScheduledRunTime());
123
124 Mock::VerifyAndClearExpectations(time_domain_.get());
125
126 // Now schedule a later wake_up, which should replace the previously
127 // requested one.
128 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime2));
129 task_queue_->SetDelayedWakeUpForTesting(
130 internal::TaskQueueImpl::DelayedWakeUp{delayed_runtime2, 0});
131
132 EXPECT_EQ(delayed_runtime2, time_domain_->NextScheduledRunTime());
133 Mock::VerifyAndClearExpectations(time_domain_.get());
134
135 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()))
136 .Times(AnyNumber());
137 }
138
TEST_F(TimeDomainTest,SetNextDelayedDoWork_OnlyCalledForEarlierTasks)139 TEST_F(TimeDomainTest, SetNextDelayedDoWork_OnlyCalledForEarlierTasks) {
140 std::unique_ptr<TaskQueueImplForTest> task_queue2 =
141 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
142 TaskQueue::Spec("test"));
143
144 std::unique_ptr<TaskQueueImplForTest> task_queue3 =
145 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
146 TaskQueue::Spec("test"));
147
148 std::unique_ptr<TaskQueueImplForTest> task_queue4 =
149 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
150 TaskQueue::Spec("test"));
151
152 TimeDelta delay1 = TimeDelta::FromMilliseconds(10);
153 TimeDelta delay2 = TimeDelta::FromMilliseconds(20);
154 TimeDelta delay3 = TimeDelta::FromMilliseconds(30);
155 TimeDelta delay4 = TimeDelta::FromMilliseconds(1);
156
157 // SetNextDelayedDoWork should always be called if there are no other
158 // wake-ups.
159 TimeTicks now = time_domain_->Now();
160 LazyNow lazy_now(now);
161 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, now + delay1));
162 task_queue_->SetDelayedWakeUpForTesting(
163 internal::TaskQueueImpl::DelayedWakeUp{now + delay1, 0});
164
165 Mock::VerifyAndClearExpectations(time_domain_.get());
166
167 // SetNextDelayedDoWork should not be called when scheduling later tasks.
168 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, _)).Times(0);
169 task_queue2->SetDelayedWakeUpForTesting(
170 internal::TaskQueueImpl::DelayedWakeUp{now + delay2, 0});
171 task_queue3->SetDelayedWakeUpForTesting(
172 internal::TaskQueueImpl::DelayedWakeUp{now + delay3, 0});
173
174 // SetNextDelayedDoWork should be called when scheduling earlier tasks.
175 Mock::VerifyAndClearExpectations(time_domain_.get());
176 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, now + delay4));
177 task_queue4->SetDelayedWakeUpForTesting(
178 internal::TaskQueueImpl::DelayedWakeUp{now + delay4, 0});
179
180 Mock::VerifyAndClearExpectations(time_domain_.get());
181
182 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, _)).Times(2);
183 task_queue2->UnregisterTaskQueue();
184 task_queue3->UnregisterTaskQueue();
185 task_queue4->UnregisterTaskQueue();
186 }
187
TEST_F(TimeDomainTest,UnregisterQueue)188 TEST_F(TimeDomainTest, UnregisterQueue) {
189 std::unique_ptr<TaskQueueImplForTest> task_queue2_ =
190 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
191 TaskQueue::Spec("test"));
192
193 TimeTicks now = time_domain_->Now();
194 LazyNow lazy_now(now);
195 TimeTicks wake_up1 = now + TimeDelta::FromMilliseconds(10);
196 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, wake_up1)).Times(1);
197 task_queue_->SetDelayedWakeUpForTesting(
198 internal::TaskQueueImpl::DelayedWakeUp{wake_up1, 0});
199 TimeTicks wake_up2 = now + TimeDelta::FromMilliseconds(100);
200 task_queue2_->SetDelayedWakeUpForTesting(
201 internal::TaskQueueImpl::DelayedWakeUp{wake_up2, 0});
202
203 EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
204
205 testing::Mock::VerifyAndClearExpectations(time_domain_.get());
206
207 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, wake_up2)).Times(1);
208
209 time_domain_->UnregisterQueue(task_queue_.get());
210 task_queue_ = std::unique_ptr<TaskQueueImplForTest>();
211 EXPECT_EQ(task_queue2_.get(), time_domain_->NextScheduledTaskQueue());
212
213 testing::Mock::VerifyAndClearExpectations(time_domain_.get());
214
215 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()))
216 .Times(1);
217
218 time_domain_->UnregisterQueue(task_queue2_.get());
219 EXPECT_FALSE(time_domain_->NextScheduledTaskQueue());
220 }
221
TEST_F(TimeDomainTest,WakeUpReadyDelayedQueues)222 TEST_F(TimeDomainTest, WakeUpReadyDelayedQueues) {
223 TimeDelta delay = TimeDelta::FromMilliseconds(50);
224 TimeTicks now = time_domain_->Now();
225 LazyNow lazy_now_1(now);
226 TimeTicks delayed_runtime = now + delay;
227 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime));
228 task_queue_->SetDelayedWakeUpForTesting(
229 internal::TaskQueueImpl::DelayedWakeUp{delayed_runtime, 0});
230
231 EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
232
233 time_domain_->WakeUpReadyDelayedQueues(&lazy_now_1);
234 EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
235
236 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()));
237 time_domain_->SetNow(delayed_runtime);
238 LazyNow lazy_now_2(time_domain_->CreateLazyNow());
239 time_domain_->WakeUpReadyDelayedQueues(&lazy_now_2);
240 ASSERT_FALSE(time_domain_->NextScheduledRunTime());
241 }
242
TEST_F(TimeDomainTest,WakeUpReadyDelayedQueuesWithIdenticalRuntimes)243 TEST_F(TimeDomainTest, WakeUpReadyDelayedQueuesWithIdenticalRuntimes) {
244 int sequence_num = 0;
245 TimeDelta delay = TimeDelta::FromMilliseconds(50);
246 TimeTicks now = time_domain_->Now();
247 LazyNow lazy_now(now);
248 TimeTicks delayed_runtime = now + delay;
249 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime));
250 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()));
251
252 std::unique_ptr<TaskQueueImplForTest> task_queue2 =
253 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
254 TaskQueue::Spec("test"));
255
256 task_queue2->SetDelayedWakeUpForTesting(
257 internal::TaskQueueImpl::DelayedWakeUp{delayed_runtime, ++sequence_num});
258 task_queue_->SetDelayedWakeUpForTesting(
259 internal::TaskQueueImpl::DelayedWakeUp{delayed_runtime, ++sequence_num});
260
261 time_domain_->WakeUpReadyDelayedQueues(&lazy_now);
262
263 // The second task queue should wake up first since it has a lower sequence
264 // number.
265 EXPECT_EQ(task_queue2.get(), time_domain_->NextScheduledTaskQueue());
266
267 task_queue2->UnregisterTaskQueue();
268 }
269
TEST_F(TimeDomainTest,CancelDelayedWork)270 TEST_F(TimeDomainTest, CancelDelayedWork) {
271 TimeTicks now = time_domain_->Now();
272 LazyNow lazy_now(now);
273 TimeTicks run_time = now + TimeDelta::FromMilliseconds(20);
274
275 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, run_time));
276 task_queue_->SetDelayedWakeUpForTesting(
277 internal::TaskQueueImpl::DelayedWakeUp{run_time, 0});
278
279 EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
280
281 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()));
282 task_queue_->SetDelayedWakeUpForTesting(nullopt);
283 EXPECT_FALSE(time_domain_->NextScheduledTaskQueue());
284 }
285
TEST_F(TimeDomainTest,CancelDelayedWork_TwoQueues)286 TEST_F(TimeDomainTest, CancelDelayedWork_TwoQueues) {
287 std::unique_ptr<TaskQueueImplForTest> task_queue2 =
288 std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
289 TaskQueue::Spec("test"));
290
291 TimeTicks now = time_domain_->Now();
292 LazyNow lazy_now(now);
293 TimeTicks run_time1 = now + TimeDelta::FromMilliseconds(20);
294 TimeTicks run_time2 = now + TimeDelta::FromMilliseconds(40);
295 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, run_time1));
296 task_queue_->SetDelayedWakeUpForTesting(
297 internal::TaskQueueImpl::DelayedWakeUp{run_time1, 0});
298 Mock::VerifyAndClearExpectations(time_domain_.get());
299
300 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, _)).Times(0);
301 task_queue2->SetDelayedWakeUpForTesting(
302 internal::TaskQueueImpl::DelayedWakeUp{run_time2, 0});
303 Mock::VerifyAndClearExpectations(time_domain_.get());
304
305 EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
306
307 EXPECT_EQ(run_time1, time_domain_->NextScheduledRunTime());
308
309 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, run_time2));
310 task_queue_->SetDelayedWakeUpForTesting(nullopt);
311 EXPECT_EQ(task_queue2.get(), time_domain_->NextScheduledTaskQueue());
312
313 EXPECT_EQ(run_time2, time_domain_->NextScheduledRunTime());
314
315 Mock::VerifyAndClearExpectations(time_domain_.get());
316 EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, _))
317 .Times(AnyNumber());
318
319 // Tidy up.
320 task_queue2->UnregisterTaskQueue();
321 }
322
323 } // namespace sequence_manager
324 } // namespace base
325