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
MockTickClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner)39 MockTickClock::MockTickClock(
40 scoped_refptr<const TestMockTimeTaskRunner> task_runner)
41 : task_runner_(task_runner) {
42 }
43
NowTicks()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
MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner)65 MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner)
66 : task_runner_(task_runner) {
67 }
68
Now()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
TestOrderedPendingTask()100 TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask()
101 : ordinal(0) {
102 }
103
104 TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
105 TestOrderedPendingTask&&) = default;
106
TestOrderedPendingTask(const tracked_objects::Location & location,OnceClosure task,TimeTicks post_time,TimeDelta delay,size_t ordinal,TestNestability nestability)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
~TestOrderedPendingTask()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().
ScopedContext(scoped_refptr<TestMockTimeTaskRunner> scope)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
operator ()(const TestOrderedPendingTask & first_task,const TestOrderedPendingTask & second_task) const140 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
TestMockTimeTaskRunner()148 TestMockTimeTaskRunner::TestMockTimeTaskRunner()
149 : now_(Time::UnixEpoch()), next_task_ordinal_(0) {
150 }
151
TestMockTimeTaskRunner(Time start_time,TimeTicks start_ticks)152 TestMockTimeTaskRunner::TestMockTimeTaskRunner(Time start_time,
153 TimeTicks start_ticks)
154 : now_(Time::UnixEpoch()), now_ticks_(start_ticks), next_task_ordinal_(0) {}
155
~TestMockTimeTaskRunner()156 TestMockTimeTaskRunner::~TestMockTimeTaskRunner() {
157 }
158
FastForwardBy(TimeDelta delta)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
RunUntilIdle()168 void TestMockTimeTaskRunner::RunUntilIdle() {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 ProcessAllTasksNoLaterThan(TimeDelta());
171 }
172
FastForwardUntilNoTasksRemain()173 void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() {
174 DCHECK(thread_checker_.CalledOnValidThread());
175 ProcessAllTasksNoLaterThan(TimeDelta::Max());
176 }
177
ClearPendingTasks()178 void TestMockTimeTaskRunner::ClearPendingTasks() {
179 DCHECK(thread_checker_.CalledOnValidThread());
180 AutoLock scoped_lock(tasks_lock_);
181 while (!tasks_.empty())
182 tasks_.pop();
183 }
184
Now() const185 Time TestMockTimeTaskRunner::Now() const {
186 DCHECK(thread_checker_.CalledOnValidThread());
187 return now_;
188 }
189
NowTicks() const190 TimeTicks TestMockTimeTaskRunner::NowTicks() const {
191 DCHECK(thread_checker_.CalledOnValidThread());
192 return now_ticks_;
193 }
194
GetMockClock() const195 std::unique_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const {
196 DCHECK(thread_checker_.CalledOnValidThread());
197 return MakeUnique<MockClock>(this);
198 }
199
GetMockTickClock() const200 std::unique_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const {
201 DCHECK(thread_checker_.CalledOnValidThread());
202 return MakeUnique<MockTickClock>(this);
203 }
204
TakePendingTasks()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
HasPendingTask() const218 bool TestMockTimeTaskRunner::HasPendingTask() const {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 return !tasks_.empty();
221 }
222
GetPendingTaskCount() const223 size_t TestMockTimeTaskRunner::GetPendingTaskCount() const {
224 DCHECK(thread_checker_.CalledOnValidThread());
225 return tasks_.size();
226 }
227
NextPendingTaskDelay() const228 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
RunsTasksOnCurrentThread() const237 bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const {
238 return thread_checker_.CalledOnValidThread();
239 }
240
PostDelayedTask(const tracked_objects::Location & from_here,OnceClosure task,TimeDelta delay)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
PostNonNestableDelayedTask(const tracked_objects::Location & from_here,OnceClosure task,TimeDelta delay)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
IsElapsingStopped()259 bool TestMockTimeTaskRunner::IsElapsingStopped() {
260 return false;
261 }
262
OnBeforeSelectingTask()263 void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
264 // Empty default implementation.
265 }
266
OnAfterTimePassed()267 void TestMockTimeTaskRunner::OnAfterTimePassed() {
268 // Empty default implementation.
269 }
270
OnAfterTaskRun()271 void TestMockTimeTaskRunner::OnAfterTaskRun() {
272 // Empty default implementation.
273 }
274
ProcessAllTasksNoLaterThan(TimeDelta max_delta)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
ForwardClocksUntilTickTime(TimeTicks later_ticks)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
DequeueNextTask(const TimeTicks & reference,const TimeDelta & max_delta,TestPendingTask * next_task)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