Home | History | Annotate | Download | only in sequence_manager
      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:
     25   TaskQueueImplForTest(internal::SequenceManagerImpl* sequence_manager,
     26                        TimeDomain* time_domain,
     27                        const TaskQueue::Spec& spec)
     28       : TaskQueueImpl(sequence_manager, time_domain, spec) {}
     29   ~TaskQueueImplForTest() {}
     30 
     31   using TaskQueueImpl::SetDelayedWakeUpForTesting;
     32 };
     33 
     34 class TestTimeDomain : public TimeDomain {
     35  public:
     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 
     45   LazyNow CreateLazyNow() const override { return LazyNow(now_); }
     46   TimeTicks Now() const override { return now_; }
     47 
     48   Optional<TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override {
     49     return Optional<TimeDelta>();
     50   }
     51 
     52   void AsValueIntoInternal(trace_event::TracedValue* state) const override {}
     53   const char* GetName() const override { return "Test"; }
     54 
     55   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 
     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:
     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 
     80   void TearDown() final {
     81     if (task_queue_)
     82       task_queue_->UnregisterTaskQueue();
     83   }
     84 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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