• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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