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/test/test_mock_time_task_runner.h" 6 7 #include <utility> 8 9 #include "base/logging.h" 10 #include "base/macros.h" 11 #include "base/memory/ptr_util.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/time/clock.h" 15 #include "base/time/tick_clock.h" 16 17 namespace base { 18 19 namespace { 20 21 // MockTickClock -------------------------------------------------------------- 22 23 // TickClock that always returns the then-current mock time ticks of 24 // |task_runner| as the current time ticks. 25 class MockTickClock : public TickClock { 26 public: 27 explicit MockTickClock( 28 scoped_refptr<const TestMockTimeTaskRunner> task_runner); 29 30 // TickClock: 31 TimeTicks NowTicks() override; 32 33 private: 34 scoped_refptr<const TestMockTimeTaskRunner> task_runner_; 35 36 DISALLOW_COPY_AND_ASSIGN(MockTickClock); 37 }; 38 39 MockTickClock::MockTickClock( 40 scoped_refptr<const TestMockTimeTaskRunner> task_runner) 41 : task_runner_(task_runner) { 42 } 43 44 TimeTicks MockTickClock::NowTicks() { 45 return task_runner_->NowTicks(); 46 } 47 48 // MockClock ------------------------------------------------------------------ 49 50 // Clock that always returns the then-current mock time of |task_runner| as the 51 // current time. 52 class MockClock : public Clock { 53 public: 54 explicit MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner); 55 56 // Clock: 57 Time Now() override; 58 59 private: 60 scoped_refptr<const TestMockTimeTaskRunner> task_runner_; 61 62 DISALLOW_COPY_AND_ASSIGN(MockClock); 63 }; 64 65 MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner) 66 : task_runner_(task_runner) { 67 } 68 69 Time MockClock::Now() { 70 return task_runner_->Now(); 71 } 72 73 } // namespace 74 75 // TestMockTimeTaskRunner::TestOrderedPendingTask ----------------------------- 76 77 // Subclass of TestPendingTask which has a strictly monotonically increasing ID 78 // for every task, so that tasks posted with the same 'time to run' can be run 79 // in the order of being posted. 80 struct TestMockTimeTaskRunner::TestOrderedPendingTask 81 : public base::TestPendingTask { 82 TestOrderedPendingTask(); 83 TestOrderedPendingTask(const tracked_objects::Location& location, 84 OnceClosure task, 85 TimeTicks post_time, 86 TimeDelta delay, 87 size_t ordinal, 88 TestNestability nestability); 89 TestOrderedPendingTask(TestOrderedPendingTask&&); 90 ~TestOrderedPendingTask(); 91 92 TestOrderedPendingTask& operator=(TestOrderedPendingTask&&); 93 94 size_t ordinal; 95 96 private: 97 DISALLOW_COPY_AND_ASSIGN(TestOrderedPendingTask); 98 }; 99 100 TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask() 101 : ordinal(0) { 102 } 103 104 TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask( 105 TestOrderedPendingTask&&) = default; 106 107 TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask( 108 const tracked_objects::Location& location, 109 OnceClosure task, 110 TimeTicks post_time, 111 TimeDelta delay, 112 size_t ordinal, 113 TestNestability nestability) 114 : base::TestPendingTask(location, 115 std::move(task), 116 post_time, 117 delay, 118 nestability), 119 ordinal(ordinal) {} 120 121 TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() { 122 } 123 124 TestMockTimeTaskRunner::TestOrderedPendingTask& 125 TestMockTimeTaskRunner::TestOrderedPendingTask::operator=( 126 TestOrderedPendingTask&&) = default; 127 128 // TestMockTimeTaskRunner ----------------------------------------------------- 129 130 // TODO(gab): This should also set the SequenceToken for the current thread. 131 // Ref. TestMockTimeTaskRunner::RunsTasksOnCurrentThread(). 132 TestMockTimeTaskRunner::ScopedContext::ScopedContext( 133 scoped_refptr<TestMockTimeTaskRunner> scope) 134 : on_destroy_(ThreadTaskRunnerHandle::OverrideForTesting(scope)) { 135 scope->RunUntilIdle(); 136 } 137 138 TestMockTimeTaskRunner::ScopedContext::~ScopedContext() = default; 139 140 bool TestMockTimeTaskRunner::TemporalOrder::operator()( 141 const TestOrderedPendingTask& first_task, 142 const TestOrderedPendingTask& second_task) const { 143 if (first_task.GetTimeToRun() == second_task.GetTimeToRun()) 144 return first_task.ordinal > second_task.ordinal; 145 return first_task.GetTimeToRun() > second_task.GetTimeToRun(); 146 } 147 148 TestMockTimeTaskRunner::TestMockTimeTaskRunner() 149 : now_(Time::UnixEpoch()), next_task_ordinal_(0) { 150 } 151 152 TestMockTimeTaskRunner::TestMockTimeTaskRunner(Time start_time, 153 TimeTicks start_ticks) 154 : now_(Time::UnixEpoch()), now_ticks_(start_ticks), next_task_ordinal_(0) {} 155 156 TestMockTimeTaskRunner::~TestMockTimeTaskRunner() { 157 } 158 159 void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) { 160 DCHECK(thread_checker_.CalledOnValidThread()); 161 DCHECK_GE(delta, TimeDelta()); 162 163 const TimeTicks original_now_ticks = now_ticks_; 164 ProcessAllTasksNoLaterThan(delta); 165 ForwardClocksUntilTickTime(original_now_ticks + delta); 166 } 167 168 void TestMockTimeTaskRunner::RunUntilIdle() { 169 DCHECK(thread_checker_.CalledOnValidThread()); 170 ProcessAllTasksNoLaterThan(TimeDelta()); 171 } 172 173 void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() { 174 DCHECK(thread_checker_.CalledOnValidThread()); 175 ProcessAllTasksNoLaterThan(TimeDelta::Max()); 176 } 177 178 void TestMockTimeTaskRunner::ClearPendingTasks() { 179 DCHECK(thread_checker_.CalledOnValidThread()); 180 AutoLock scoped_lock(tasks_lock_); 181 while (!tasks_.empty()) 182 tasks_.pop(); 183 } 184 185 Time TestMockTimeTaskRunner::Now() const { 186 DCHECK(thread_checker_.CalledOnValidThread()); 187 return now_; 188 } 189 190 TimeTicks TestMockTimeTaskRunner::NowTicks() const { 191 DCHECK(thread_checker_.CalledOnValidThread()); 192 return now_ticks_; 193 } 194 195 std::unique_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const { 196 DCHECK(thread_checker_.CalledOnValidThread()); 197 return MakeUnique<MockClock>(this); 198 } 199 200 std::unique_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const { 201 DCHECK(thread_checker_.CalledOnValidThread()); 202 return MakeUnique<MockTickClock>(this); 203 } 204 205 std::deque<TestPendingTask> TestMockTimeTaskRunner::TakePendingTasks() { 206 AutoLock scoped_lock(tasks_lock_); 207 std::deque<TestPendingTask> tasks; 208 while (!tasks_.empty()) { 209 // It's safe to remove const and consume |task| here, since |task| is not 210 // used for ordering the item. 211 tasks.push_back( 212 std::move(const_cast<TestOrderedPendingTask&>(tasks_.top()))); 213 tasks_.pop(); 214 } 215 return tasks; 216 } 217 218 bool TestMockTimeTaskRunner::HasPendingTask() const { 219 DCHECK(thread_checker_.CalledOnValidThread()); 220 return !tasks_.empty(); 221 } 222 223 size_t TestMockTimeTaskRunner::GetPendingTaskCount() const { 224 DCHECK(thread_checker_.CalledOnValidThread()); 225 return tasks_.size(); 226 } 227 228 TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() const { 229 DCHECK(thread_checker_.CalledOnValidThread()); 230 return tasks_.empty() ? TimeDelta::Max() 231 : tasks_.top().GetTimeToRun() - now_ticks_; 232 } 233 234 // TODO(gab): Combine |thread_checker_| with a SequenceToken to differentiate 235 // between tasks running in the scope of this TestMockTimeTaskRunner and other 236 // task runners sharing this thread. http://crbug.com/631186 237 bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const { 238 return thread_checker_.CalledOnValidThread(); 239 } 240 241 bool TestMockTimeTaskRunner::PostDelayedTask( 242 const tracked_objects::Location& from_here, 243 OnceClosure task, 244 TimeDelta delay) { 245 AutoLock scoped_lock(tasks_lock_); 246 tasks_.push(TestOrderedPendingTask(from_here, std::move(task), now_ticks_, 247 delay, next_task_ordinal_++, 248 TestPendingTask::NESTABLE)); 249 return true; 250 } 251 252 bool TestMockTimeTaskRunner::PostNonNestableDelayedTask( 253 const tracked_objects::Location& from_here, 254 OnceClosure task, 255 TimeDelta delay) { 256 return PostDelayedTask(from_here, std::move(task), delay); 257 } 258 259 bool TestMockTimeTaskRunner::IsElapsingStopped() { 260 return false; 261 } 262 263 void TestMockTimeTaskRunner::OnBeforeSelectingTask() { 264 // Empty default implementation. 265 } 266 267 void TestMockTimeTaskRunner::OnAfterTimePassed() { 268 // Empty default implementation. 269 } 270 271 void TestMockTimeTaskRunner::OnAfterTaskRun() { 272 // Empty default implementation. 273 } 274 275 void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) { 276 DCHECK(thread_checker_.CalledOnValidThread()); 277 DCHECK_GE(max_delta, TimeDelta()); 278 279 // Multiple test task runners can share the same thread for determinism in 280 // unit tests. Make sure this TestMockTimeTaskRunner's tasks run in its scope. 281 ScopedClosureRunner undo_override; 282 if (!ThreadTaskRunnerHandle::IsSet() || 283 ThreadTaskRunnerHandle::Get() != this) { 284 undo_override = ThreadTaskRunnerHandle::OverrideForTesting(this); 285 } 286 287 const TimeTicks original_now_ticks = now_ticks_; 288 while (!IsElapsingStopped()) { 289 OnBeforeSelectingTask(); 290 TestPendingTask task_info; 291 if (!DequeueNextTask(original_now_ticks, max_delta, &task_info)) 292 break; 293 // If tasks were posted with a negative delay, task_info.GetTimeToRun() will 294 // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not 295 // moving the clock backwards in this case. 296 ForwardClocksUntilTickTime(task_info.GetTimeToRun()); 297 std::move(task_info.task).Run(); 298 OnAfterTaskRun(); 299 } 300 } 301 302 void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) { 303 DCHECK(thread_checker_.CalledOnValidThread()); 304 if (later_ticks <= now_ticks_) 305 return; 306 307 now_ += later_ticks - now_ticks_; 308 now_ticks_ = later_ticks; 309 OnAfterTimePassed(); 310 } 311 312 bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference, 313 const TimeDelta& max_delta, 314 TestPendingTask* next_task) { 315 AutoLock scoped_lock(tasks_lock_); 316 if (!tasks_.empty() && 317 (tasks_.top().GetTimeToRun() - reference) <= max_delta) { 318 // It's safe to remove const and consume |task| here, since |task| is not 319 // used for ordering the item. 320 *next_task = std::move(const_cast<TestOrderedPendingTask&>(tasks_.top())); 321 tasks_.pop(); 322 return true; 323 } 324 return false; 325 } 326 327 } // namespace base 328