Home | History | Annotate | Download | only in test
      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