test_mock_time_task_runner.cc revision fe2f52931e8e50253d06329d7bf0a4164c7ba580
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 17namespace base { 18 19namespace { 20 21// MockTickClock -------------------------------------------------------------- 22 23// TickClock that always returns the then-current mock time ticks of 24// |task_runner| as the current time ticks. 25class 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 39MockTickClock::MockTickClock( 40 scoped_refptr<const TestMockTimeTaskRunner> task_runner) 41 : task_runner_(task_runner) { 42} 43 44TimeTicks 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. 52class 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 65MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner) 66 : task_runner_(task_runner) { 67} 68 69Time 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. 80struct TestMockTimeTaskRunner::TestOrderedPendingTask 81 : public base::TestPendingTask { 82 TestOrderedPendingTask(); 83 TestOrderedPendingTask(const tracked_objects::Location& location, 84 Closure 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 100TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask() 101 : ordinal(0) { 102} 103 104TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask( 105 TestOrderedPendingTask&&) = default; 106 107TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask( 108 const tracked_objects::Location& location, 109 Closure 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 121TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() { 122} 123 124TestMockTimeTaskRunner::TestOrderedPendingTask& 125TestMockTimeTaskRunner::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(). 132TestMockTimeTaskRunner::ScopedContext::ScopedContext( 133 scoped_refptr<TestMockTimeTaskRunner> scope) 134 : on_destroy_(ThreadTaskRunnerHandle::OverrideForTesting(scope)) { 135 scope->RunUntilIdle(); 136} 137 138TestMockTimeTaskRunner::ScopedContext::~ScopedContext() = default; 139 140bool 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 148TestMockTimeTaskRunner::TestMockTimeTaskRunner() 149 : now_(Time::UnixEpoch()), next_task_ordinal_(0) { 150} 151 152TestMockTimeTaskRunner::TestMockTimeTaskRunner(Time start_time, 153 TimeTicks start_ticks) 154 : now_(Time::UnixEpoch()), now_ticks_(start_ticks), next_task_ordinal_(0) {} 155 156TestMockTimeTaskRunner::~TestMockTimeTaskRunner() { 157} 158 159void 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 168void TestMockTimeTaskRunner::RunUntilIdle() { 169 DCHECK(thread_checker_.CalledOnValidThread()); 170 ProcessAllTasksNoLaterThan(TimeDelta()); 171} 172 173void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() { 174 DCHECK(thread_checker_.CalledOnValidThread()); 175 ProcessAllTasksNoLaterThan(TimeDelta::Max()); 176} 177 178void TestMockTimeTaskRunner::ClearPendingTasks() { 179 DCHECK(thread_checker_.CalledOnValidThread()); 180 AutoLock scoped_lock(tasks_lock_); 181 while (!tasks_.empty()) 182 tasks_.pop(); 183} 184 185Time TestMockTimeTaskRunner::Now() const { 186 DCHECK(thread_checker_.CalledOnValidThread()); 187 return now_; 188} 189 190TimeTicks TestMockTimeTaskRunner::NowTicks() const { 191 DCHECK(thread_checker_.CalledOnValidThread()); 192 return now_ticks_; 193} 194 195std::unique_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const { 196 DCHECK(thread_checker_.CalledOnValidThread()); 197 return MakeUnique<MockClock>(this); 198} 199 200std::unique_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const { 201 DCHECK(thread_checker_.CalledOnValidThread()); 202 return MakeUnique<MockTickClock>(this); 203} 204 205std::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 218bool TestMockTimeTaskRunner::HasPendingTask() const { 219 DCHECK(thread_checker_.CalledOnValidThread()); 220 return !tasks_.empty(); 221} 222 223size_t TestMockTimeTaskRunner::GetPendingTaskCount() const { 224 DCHECK(thread_checker_.CalledOnValidThread()); 225 return tasks_.size(); 226} 227 228TimeDelta 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 237bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const { 238 return thread_checker_.CalledOnValidThread(); 239} 240 241bool TestMockTimeTaskRunner::PostDelayedTask( 242 const tracked_objects::Location& from_here, 243 Closure 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 252bool TestMockTimeTaskRunner::PostNonNestableDelayedTask( 253 const tracked_objects::Location& from_here, 254 Closure task, 255 TimeDelta delay) { 256 return PostDelayedTask(from_here, std::move(task), delay); 257} 258 259bool TestMockTimeTaskRunner::IsElapsingStopped() { 260 return false; 261} 262 263void TestMockTimeTaskRunner::OnBeforeSelectingTask() { 264 // Empty default implementation. 265} 266 267void TestMockTimeTaskRunner::OnAfterTimePassed() { 268 // Empty default implementation. 269} 270 271void TestMockTimeTaskRunner::OnAfterTaskRun() { 272 // Empty default implementation. 273} 274 275void 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 302void 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 312bool 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