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