|  | // Copyright 2015 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/task/sequence_manager/wake_up_queue.h" | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/message_loop/message_pump.h" | 
|  | #include "base/message_loop/message_pump_type.h" | 
|  | #include "base/task/sequence_manager/enqueue_order.h" | 
|  | #include "base/task/sequence_manager/sequence_manager_impl.h" | 
|  | #include "base/task/sequence_manager/task_queue_impl.h" | 
|  | #include "base/test/mock_callback.h" | 
|  | #include "base/test/simple_test_tick_clock.h" | 
|  | #include "testing/gmock/include/gmock/gmock.h" | 
|  | #include "third_party/abseil-cpp/absl/types/optional.h" | 
|  |  | 
|  | using testing::_; | 
|  | using testing::AnyNumber; | 
|  | using testing::Mock; | 
|  |  | 
|  | namespace base { | 
|  | namespace sequence_manager { | 
|  | namespace internal { | 
|  |  | 
|  | class TaskQueueImplForTest : public internal::TaskQueueImpl { | 
|  | public: | 
|  | TaskQueueImplForTest(internal::SequenceManagerImpl* sequence_manager, | 
|  | WakeUpQueue* wake_up_queue, | 
|  | const TaskQueue::Spec& spec) | 
|  | : TaskQueueImpl(sequence_manager, wake_up_queue, spec) {} | 
|  | ~TaskQueueImplForTest() = default; | 
|  |  | 
|  | using TaskQueueImpl::SetNextWakeUp; | 
|  | }; | 
|  |  | 
|  | class MockWakeUpQueue : public WakeUpQueue { | 
|  | public: | 
|  | MockWakeUpQueue() | 
|  | : WakeUpQueue(internal::AssociatedThreadId::CreateBound()) {} | 
|  |  | 
|  | MockWakeUpQueue(const MockWakeUpQueue&) = delete; | 
|  | MockWakeUpQueue& operator=(const MockWakeUpQueue&) = delete; | 
|  | ~MockWakeUpQueue() override = default; | 
|  |  | 
|  | using WakeUpQueue::MoveReadyDelayedTasksToWorkQueues; | 
|  | using WakeUpQueue::SetNextWakeUpForQueue; | 
|  | using WakeUpQueue::UnregisterQueue; | 
|  |  | 
|  | void OnNextWakeUpChanged(LazyNow* lazy_now, | 
|  | absl::optional<WakeUp> wake_up) override { | 
|  | TimeTicks time = wake_up ? wake_up->time : TimeTicks::Max(); | 
|  | OnNextWakeUpChanged_TimeTicks(time); | 
|  | } | 
|  | const char* GetName() const override { return "Test"; } | 
|  | void UnregisterQueue(internal::TaskQueueImpl* queue) override { | 
|  | SetNextWakeUpForQueue(queue, nullptr, absl::nullopt); | 
|  | } | 
|  |  | 
|  | internal::TaskQueueImpl* NextScheduledTaskQueue() const { | 
|  | if (wake_up_queue_.empty()) | 
|  | return nullptr; | 
|  | return wake_up_queue_.top().queue; | 
|  | } | 
|  |  | 
|  | TimeTicks NextScheduledRunTime() const { | 
|  | if (wake_up_queue_.empty()) | 
|  | return TimeTicks::Max(); | 
|  | return wake_up_queue_.top().wake_up.time; | 
|  | } | 
|  |  | 
|  | MOCK_METHOD1(OnNextWakeUpChanged_TimeTicks, void(TimeTicks time)); | 
|  | }; | 
|  |  | 
|  | class WakeUpQueueTest : public testing::Test { | 
|  | public: | 
|  | void SetUp() final { | 
|  | // A null clock triggers some assertions. | 
|  | tick_clock_.Advance(Milliseconds(1)); | 
|  | wake_up_queue_ = std::make_unique<MockWakeUpQueue>(); | 
|  | task_queue_ = std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  | } | 
|  |  | 
|  | void TearDown() final { | 
|  | if (task_queue_) | 
|  | task_queue_->UnregisterTaskQueue(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<MockWakeUpQueue> wake_up_queue_; | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue_; | 
|  | SimpleTestTickClock tick_clock_; | 
|  | }; | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, ScheduleWakeUpForQueue) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | TimeDelta delay = Milliseconds(10); | 
|  | TimeTicks delayed_runtime = now + delay; | 
|  | EXPECT_TRUE(wake_up_queue_->empty()); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime)); | 
|  | LazyNow lazy_now(now); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{delayed_runtime}); | 
|  |  | 
|  | EXPECT_FALSE(wake_up_queue_->empty()); | 
|  | EXPECT_EQ(delayed_runtime, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | EXPECT_EQ(task_queue_.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())) | 
|  | .Times(AnyNumber()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, ScheduleWakeUpForQueueSupersedesPreviousWakeUp) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | TimeDelta delay1 = Milliseconds(10); | 
|  | TimeDelta delay2 = Milliseconds(100); | 
|  | TimeTicks delayed_runtime1 = now + delay1; | 
|  | TimeTicks delayed_runtime2 = now + delay2; | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime1)); | 
|  | LazyNow lazy_now(now); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{delayed_runtime1}); | 
|  |  | 
|  | EXPECT_EQ(delayed_runtime1, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | // Now schedule a later wake_up, which should replace the previously | 
|  | // requested one. | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime2)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{delayed_runtime2}); | 
|  |  | 
|  | EXPECT_EQ(delayed_runtime2, wake_up_queue_->NextScheduledRunTime()); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())) | 
|  | .Times(AnyNumber()); | 
|  | } | 
|  |  | 
|  | TEST_F( | 
|  | WakeUpQueueTest, | 
|  | ScheduleFlexibleNoSoonerWakeUpForQueueSupersedesPreviousWakeUpWithLeeway) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | TimeDelta delay1 = Milliseconds(10); | 
|  | TimeDelta delay2 = Milliseconds(15); | 
|  | TimeTicks delayed_runtime1 = now + delay1; | 
|  | TimeTicks delayed_runtime2 = now + delay2; | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime1)); | 
|  | LazyNow lazy_now(now); | 
|  | task_queue_->SetNextWakeUp( | 
|  | &lazy_now, | 
|  | WakeUp{delayed_runtime1, Milliseconds(10), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kFlexibleNoSooner}); | 
|  |  | 
|  | EXPECT_EQ((WakeUp{delayed_runtime1, Milliseconds(10), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kFlexibleNoSooner}), | 
|  | wake_up_queue_->GetNextDelayedWakeUp()); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | // Now schedule a later wake_up, which should replace the previously | 
|  | // requested one. | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime2)); | 
|  | task_queue_->SetNextWakeUp( | 
|  | &lazy_now, WakeUp{delayed_runtime2, TimeDelta(), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kPrecise}); | 
|  |  | 
|  | EXPECT_EQ((WakeUp{delayed_runtime2, TimeDelta(), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kPrecise}), | 
|  | wake_up_queue_->GetNextDelayedWakeUp()); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())) | 
|  | .Times(AnyNumber()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, | 
|  | ScheduleFlexiblePreferEarlyWakeUpForQueueSupersedesPreviousWakeUp) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | TimeDelta delay1 = Milliseconds(10); | 
|  | TimeDelta delay2 = Milliseconds(15); | 
|  | TimeTicks delayed_runtime1 = now + delay1; | 
|  | TimeTicks delayed_runtime2 = now + delay2; | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime1)); | 
|  | LazyNow lazy_now(now); | 
|  | task_queue_->SetNextWakeUp( | 
|  | &lazy_now, WakeUp{delayed_runtime1, TimeDelta(), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kPrecise}); | 
|  |  | 
|  | EXPECT_EQ((WakeUp{delayed_runtime1, TimeDelta(), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kPrecise}), | 
|  | wake_up_queue_->GetNextDelayedWakeUp()); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | // Now schedule a later wake_up, which should replace the previously | 
|  | // requested one. | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime2)); | 
|  | task_queue_->SetNextWakeUp( | 
|  | &lazy_now, | 
|  | WakeUp{delayed_runtime2, Milliseconds(10), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kFlexiblePreferEarly}); | 
|  |  | 
|  | EXPECT_EQ((WakeUp{delayed_runtime2, Milliseconds(10), WakeUpResolution::kLow, | 
|  | subtle::DelayPolicy::kFlexiblePreferEarly}), | 
|  | wake_up_queue_->GetNextDelayedWakeUp()); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())) | 
|  | .Times(AnyNumber()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, SetNextDelayedDoWork_OnlyCalledForEarlierTasks) { | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue2 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue3 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue4 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | TimeDelta delay1 = Milliseconds(10); | 
|  | TimeDelta delay2 = Milliseconds(20); | 
|  | TimeDelta delay3 = Milliseconds(30); | 
|  | TimeDelta delay4 = Milliseconds(1); | 
|  |  | 
|  | // SetNextDelayedDoWork should always be called if there are no other | 
|  | // wake-ups. | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now(now); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(now + delay1)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{now + delay1}); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | // SetNextDelayedDoWork should not be called when scheduling later tasks. | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(_)).Times(0); | 
|  | task_queue2->SetNextWakeUp(&lazy_now, WakeUp{now + delay2}); | 
|  | task_queue3->SetNextWakeUp(&lazy_now, WakeUp{now + delay3}); | 
|  |  | 
|  | // SetNextDelayedDoWork should be called when scheduling earlier tasks. | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(now + delay4)); | 
|  | task_queue4->SetNextWakeUp(&lazy_now, WakeUp{now + delay4}); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(_)).Times(2); | 
|  | task_queue2->UnregisterTaskQueue(); | 
|  | task_queue3->UnregisterTaskQueue(); | 
|  | task_queue4->UnregisterTaskQueue(); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, UnregisterQueue) { | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue2 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  | EXPECT_TRUE(wake_up_queue_->empty()); | 
|  |  | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now(now); | 
|  | TimeTicks wake_up1 = now + Milliseconds(10); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(wake_up1)) | 
|  | .Times(1); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{wake_up1}); | 
|  | TimeTicks wake_up2 = now + Milliseconds(100); | 
|  | task_queue2->SetNextWakeUp(&lazy_now, WakeUp{wake_up2}); | 
|  | EXPECT_FALSE(wake_up_queue_->empty()); | 
|  |  | 
|  | EXPECT_EQ(task_queue_.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | testing::Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(wake_up2)) | 
|  | .Times(1); | 
|  |  | 
|  | wake_up_queue_->UnregisterQueue(task_queue_.get()); | 
|  | EXPECT_EQ(task_queue2.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | task_queue_->UnregisterTaskQueue(); | 
|  | task_queue_ = nullptr; | 
|  |  | 
|  | EXPECT_FALSE(wake_up_queue_->empty()); | 
|  | testing::Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())) | 
|  | .Times(1); | 
|  |  | 
|  | wake_up_queue_->UnregisterQueue(task_queue2.get()); | 
|  | EXPECT_FALSE(wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | task_queue2->UnregisterTaskQueue(); | 
|  | task_queue2 = nullptr; | 
|  | EXPECT_TRUE(wake_up_queue_->empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, MoveReadyDelayedTasksToWorkQueues) { | 
|  | TimeDelta delay = Milliseconds(50); | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now_1(now); | 
|  | TimeTicks delayed_runtime = now + delay; | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(delayed_runtime)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now_1, WakeUp{delayed_runtime}); | 
|  |  | 
|  | EXPECT_EQ(delayed_runtime, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | wake_up_queue_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_1, | 
|  | EnqueueOrder()); | 
|  | EXPECT_EQ(delayed_runtime, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())); | 
|  | tick_clock_.SetNowTicks(delayed_runtime); | 
|  | LazyNow lazy_now_2(&tick_clock_); | 
|  | wake_up_queue_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_2, | 
|  | EnqueueOrder()); | 
|  | ASSERT_TRUE(wake_up_queue_->NextScheduledRunTime().is_max()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, MoveReadyDelayedTasksToWorkQueuesWithLeeway) { | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue2 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now_1(now); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(now + Milliseconds(10))); | 
|  | task_queue2->SetNextWakeUp(&lazy_now_1, | 
|  | WakeUp{now + Milliseconds(10), Milliseconds(4)}); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(now + Milliseconds(11))); | 
|  | task_queue_->SetNextWakeUp(&lazy_now_1, | 
|  | WakeUp{now + Milliseconds(11), TimeDelta()}); | 
|  |  | 
|  | EXPECT_EQ(now + Milliseconds(11), wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | wake_up_queue_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_1, | 
|  | EnqueueOrder()); | 
|  | EXPECT_EQ(now + Milliseconds(11), wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | tick_clock_.SetNowTicks(now + Milliseconds(10)); | 
|  | LazyNow lazy_now_2(&tick_clock_); | 
|  | wake_up_queue_->MoveReadyDelayedTasksToWorkQueues(&lazy_now_2, | 
|  | EnqueueOrder()); | 
|  | EXPECT_EQ(now + Milliseconds(11), wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(_)) | 
|  | .Times(AnyNumber()); | 
|  | // Tidy up. | 
|  | task_queue2->UnregisterTaskQueue(); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, CancelDelayedWork) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now(now); | 
|  | TimeTicks run_time = now + Milliseconds(20); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(run_time)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{run_time}); | 
|  |  | 
|  | EXPECT_EQ(task_queue_.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), | 
|  | OnNextWakeUpChanged_TimeTicks(TimeTicks::Max())); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, absl::nullopt); | 
|  | EXPECT_FALSE(wake_up_queue_->NextScheduledTaskQueue()); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, CancelDelayedWork_TwoQueues) { | 
|  | std::unique_ptr<TaskQueueImplForTest> task_queue2 = | 
|  | std::make_unique<TaskQueueImplForTest>( | 
|  | nullptr, wake_up_queue_.get(), TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now(now); | 
|  | TimeTicks run_time1 = now + Milliseconds(20); | 
|  | TimeTicks run_time2 = now + Milliseconds(40); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(run_time1)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, WakeUp{run_time1}); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(_)).Times(0); | 
|  | task_queue2->SetNextWakeUp(&lazy_now, WakeUp{run_time2}); | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  |  | 
|  | EXPECT_EQ(task_queue_.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | EXPECT_EQ(run_time1, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(run_time2)); | 
|  | task_queue_->SetNextWakeUp(&lazy_now, absl::nullopt); | 
|  | EXPECT_EQ(task_queue2.get(), wake_up_queue_->NextScheduledTaskQueue()); | 
|  |  | 
|  | EXPECT_EQ(run_time2, wake_up_queue_->NextScheduledRunTime()); | 
|  |  | 
|  | Mock::VerifyAndClearExpectations(wake_up_queue_.get()); | 
|  | EXPECT_CALL(*wake_up_queue_.get(), OnNextWakeUpChanged_TimeTicks(_)) | 
|  | .Times(AnyNumber()); | 
|  |  | 
|  | // Tidy up. | 
|  | task_queue2->UnregisterTaskQueue(); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, HighResolutionWakeUps) { | 
|  | TimeTicks now = tick_clock_.NowTicks(); | 
|  | LazyNow lazy_now(now); | 
|  | TimeTicks run_time1 = now + Milliseconds(20); | 
|  | TimeTicks run_time2 = now + Milliseconds(40); | 
|  | TaskQueueImplForTest q1(nullptr, wake_up_queue_.get(), | 
|  | TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  | TaskQueueImplForTest q2(nullptr, wake_up_queue_.get(), | 
|  | TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  |  | 
|  | // Add two high resolution wake-ups. | 
|  | EXPECT_FALSE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  | wake_up_queue_->SetNextWakeUpForQueue( | 
|  | &q1, &lazy_now, WakeUp{run_time1, TimeDelta(), WakeUpResolution::kHigh}); | 
|  | EXPECT_TRUE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  | wake_up_queue_->SetNextWakeUpForQueue( | 
|  | &q2, &lazy_now, WakeUp{run_time2, TimeDelta(), WakeUpResolution::kHigh}); | 
|  | EXPECT_TRUE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Remove one of the wake-ups. | 
|  | wake_up_queue_->SetNextWakeUpForQueue(&q1, &lazy_now, absl::nullopt); | 
|  | EXPECT_TRUE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Remove the second one too. | 
|  | wake_up_queue_->SetNextWakeUpForQueue(&q2, &lazy_now, absl::nullopt); | 
|  | EXPECT_FALSE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Change a low resolution wake-up to a high resolution one. | 
|  | wake_up_queue_->SetNextWakeUpForQueue( | 
|  | &q1, &lazy_now, WakeUp{run_time1, TimeDelta(), WakeUpResolution::kLow}); | 
|  | EXPECT_FALSE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  | wake_up_queue_->SetNextWakeUpForQueue( | 
|  | &q1, &lazy_now, WakeUp{run_time1, TimeDelta(), WakeUpResolution::kHigh}); | 
|  | EXPECT_TRUE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Move a high resolution wake-up in time. | 
|  | wake_up_queue_->SetNextWakeUpForQueue( | 
|  | &q1, &lazy_now, WakeUp{run_time2, TimeDelta(), WakeUpResolution::kHigh}); | 
|  | EXPECT_TRUE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Cancel the wake-up twice. | 
|  | wake_up_queue_->SetNextWakeUpForQueue(&q1, &lazy_now, absl::nullopt); | 
|  | wake_up_queue_->SetNextWakeUpForQueue(&q1, &lazy_now, absl::nullopt); | 
|  | EXPECT_FALSE(wake_up_queue_->has_pending_high_resolution_tasks()); | 
|  |  | 
|  | // Tidy up. | 
|  | q1.UnregisterTaskQueue(); | 
|  | q2.UnregisterTaskQueue(); | 
|  | } | 
|  |  | 
|  | TEST_F(WakeUpQueueTest, SetNextWakeUpForQueueInThePast) { | 
|  | constexpr auto kType = MessagePumpType::DEFAULT; | 
|  | constexpr auto kDelay = Milliseconds(20); | 
|  | auto sequence_manager = sequence_manager::CreateUnboundSequenceManager( | 
|  | SequenceManager::Settings::Builder() | 
|  | .SetMessagePumpType(kType) | 
|  | .SetTickClock(&tick_clock_) | 
|  | .Build()); | 
|  | sequence_manager->BindToMessagePump(MessagePump::Create(kType)); | 
|  | auto high_prio_queue = | 
|  | sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ)); | 
|  | high_prio_queue->SetQueuePriority(TaskQueue::kHighestPriority); | 
|  | auto high_prio_runner = high_prio_queue->CreateTaskRunner(kTaskTypeNone); | 
|  | auto low_prio_queue = | 
|  | sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST2_TQ)); | 
|  | low_prio_queue->SetQueuePriority(TaskQueue::kBestEffortPriority); | 
|  | auto low_prio_runner = low_prio_queue->CreateTaskRunner(kTaskTypeNone); | 
|  | sequence_manager->SetDefaultTaskRunner(high_prio_runner); | 
|  | base::MockCallback<base::OnceCallback<void()>> task_1, task_2; | 
|  |  | 
|  | testing::Sequence s; | 
|  | // Expect task_2 to run after task_1 | 
|  | EXPECT_CALL(task_1, Run); | 
|  | EXPECT_CALL(task_2, Run); | 
|  | // Schedule high and low priority tasks in such a way that clock.Now() will be | 
|  | // way into the future by the time the low prio task run time is used to setup | 
|  | // a wake up. | 
|  | low_prio_runner->PostDelayedTask(FROM_HERE, task_2.Get(), kDelay); | 
|  | high_prio_runner->PostDelayedTask(FROM_HERE, task_1.Get(), kDelay * 2); | 
|  | high_prio_runner->PostTask( | 
|  | FROM_HERE, BindOnce([](SimpleTestTickClock* clock, | 
|  | TimeDelta delay) { clock->Advance(delay); }, | 
|  | base::Unretained(&tick_clock_), kDelay * 2)); | 
|  | RunLoop().RunUntilIdle(); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace sequence_manager | 
|  | }  // namespace base |