• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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