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 #ifndef BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
      6 #define BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
      7 
      8 #include <stddef.h>
      9 
     10 #include <deque>
     11 #include <memory>
     12 #include <queue>
     13 #include <vector>
     14 
     15 #include "base/callback.h"
     16 #include "base/callback_helpers.h"
     17 #include "base/macros.h"
     18 #include "base/single_thread_task_runner.h"
     19 #include "base/synchronization/lock.h"
     20 #include "base/test/test_pending_task.h"
     21 #include "base/threading/thread_checker_impl.h"
     22 #include "base/time/time.h"
     23 
     24 namespace base {
     25 
     26 class Clock;
     27 class TickClock;
     28 
     29 // Runs pending tasks in the order of the tasks' post time + delay, and keeps
     30 // track of a mock (virtual) tick clock time that can be fast-forwarded.
     31 //
     32 // TestMockTimeTaskRunner has the following properties:
     33 //
     34 //   - Methods RunsTasksOnCurrentThread() and Post[Delayed]Task() can be called
     35 //     from any thread, but the rest of the methods must be called on the same
     36 //     thread the TaskRunner was created on.
     37 //   - It allows for reentrancy, in that it handles the running of tasks that in
     38 //     turn call back into it (e.g., to post more tasks).
     39 //   - Tasks are stored in a priority queue, and executed in the increasing
     40 //     order of post time + delay, but ignoring nestability.
     41 //   - It does not check for overflow when doing time arithmetic. A sufficient
     42 //     condition for preventing overflows is to make sure that the sum of all
     43 //     posted task delays and fast-forward increments is still representable by
     44 //     a TimeDelta, and that adding this delta to the starting values of Time
     45 //     and TickTime is still within their respective range.
     46 //   - Tasks aren't guaranteed to be destroyed immediately after they're run.
     47 //
     48 // This is a slightly more sophisticated version of TestSimpleTaskRunner, in
     49 // that it supports running delayed tasks in the correct temporal order.
     50 class TestMockTimeTaskRunner : public SingleThreadTaskRunner {
     51  public:
     52   // Everything that is executed in the scope of a ScopedContext will behave as
     53   // though it ran under |scope| (i.e. ThreadTaskRunnerHandle,
     54   // RunsTasksOnCurrentThread, etc.). This allows the test body to be all in one
     55   // block when multiple TestMockTimeTaskRunners share the main thread. For
     56   // example:
     57   //
     58   //   class ExampleFixture {
     59   //    protected:
     60   //     DoBarOnFoo() {
     61   //       DCHECK(foo_task_runner_->RunsOnCurrentThread());
     62   //       EXPECT_EQ(foo_task_runner_, ThreadTaskRunnerHandle::Get());
     63   //       DoBar();
     64   //     }
     65   //
     66   //     // Mock main task runner.
     67   //     base::MessageLoop message_loop_;
     68   //     base::ScopedMockTimeMessageLoopTaskRunner main_task_runner_;
     69   //
     70   //     // Mock foo task runner.
     71   //     scoped_refptr<TestMockTimeTaskRunner> foo_task_runner_ =
     72   //         new TestMockTimeTaskRunner();
     73   //   };
     74   //
     75   //   TEST_F(ExampleFixture, DoBarOnFoo) {
     76   //     DoThingsOnMain();
     77   //     {
     78   //       TestMockTimeTaskRunner::ScopedContext scoped_context(
     79   //           foo_task_runner_.get());
     80   //       DoBarOnFoo();
     81   //     }
     82   //     DoMoreThingsOnMain();
     83   //   }
     84   //
     85   class ScopedContext {
     86    public:
     87     // Note: |scope| is ran until idle as part of this constructor to ensure
     88     // that anything which runs in the underlying scope runs after any already
     89     // pending tasks (the contrary would break the SequencedTraskRunner
     90     // contract).
     91     explicit ScopedContext(scoped_refptr<TestMockTimeTaskRunner> scope);
     92     ~ScopedContext();
     93 
     94    private:
     95     ScopedClosureRunner on_destroy_;
     96     DISALLOW_COPY_AND_ASSIGN(ScopedContext);
     97   };
     98 
     99   // Constructs an instance whose virtual time will start at the Unix epoch, and
    100   // whose time ticks will start at zero.
    101   TestMockTimeTaskRunner();
    102 
    103   // Constructs an instance starting at the given virtual time and time ticks.
    104   TestMockTimeTaskRunner(Time start_time, TimeTicks start_ticks);
    105 
    106   // Fast-forwards virtual time by |delta|, causing all tasks with a remaining
    107   // delay less than or equal to |delta| to be executed. |delta| must be
    108   // non-negative.
    109   void FastForwardBy(TimeDelta delta);
    110 
    111   // Fast-forwards virtual time just until all tasks are executed.
    112   void FastForwardUntilNoTasksRemain();
    113 
    114   // Executes all tasks that have no remaining delay. Tasks with a remaining
    115   // delay greater than zero will remain enqueued, and no virtual time will
    116   // elapse.
    117   void RunUntilIdle();
    118 
    119   // Clears the queue of pending tasks without running them.
    120   void ClearPendingTasks();
    121 
    122   // Returns the current virtual time (initially starting at the Unix epoch).
    123   Time Now() const;
    124 
    125   // Returns the current virtual tick time (initially starting at 0).
    126   TimeTicks NowTicks() const;
    127 
    128   // Returns a Clock that uses the virtual time of |this| as its time source.
    129   // The returned Clock will hold a reference to |this|.
    130   std::unique_ptr<Clock> GetMockClock() const;
    131 
    132   // Returns a TickClock that uses the virtual time ticks of |this| as its tick
    133   // source. The returned TickClock will hold a reference to |this|.
    134   std::unique_ptr<TickClock> GetMockTickClock() const;
    135 
    136   std::deque<TestPendingTask> TakePendingTasks();
    137   bool HasPendingTask() const;
    138   size_t GetPendingTaskCount() const;
    139   TimeDelta NextPendingTaskDelay() const;
    140 
    141   // SingleThreadTaskRunner:
    142   bool RunsTasksOnCurrentThread() const override;
    143   bool PostDelayedTask(const tracked_objects::Location& from_here,
    144                        OnceClosure task,
    145                        TimeDelta delay) override;
    146   bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
    147                                   OnceClosure task,
    148                                   TimeDelta delay) override;
    149 
    150  protected:
    151   ~TestMockTimeTaskRunner() override;
    152 
    153   // Whether the elapsing of virtual time is stopped or not. Subclasses can
    154   // override this method to perform early exits from a running task runner.
    155   // Defaults to always return false.
    156   virtual bool IsElapsingStopped();
    157 
    158   // Called before the next task to run is selected, so that subclasses have a
    159   // last chance to make sure all tasks are posted.
    160   virtual void OnBeforeSelectingTask();
    161 
    162   // Called after the current mock time has been incremented so that subclasses
    163   // can react to the passing of time.
    164   virtual void OnAfterTimePassed();
    165 
    166   // Called after each task is run so that subclasses may perform additional
    167   // activities, e.g., pump additional task runners.
    168   virtual void OnAfterTaskRun();
    169 
    170  private:
    171   struct TestOrderedPendingTask;
    172 
    173   // Predicate that defines a strict weak temporal ordering of tasks.
    174   class TemporalOrder {
    175    public:
    176     bool operator()(const TestOrderedPendingTask& first_task,
    177                     const TestOrderedPendingTask& second_task) const;
    178   };
    179 
    180   typedef std::priority_queue<TestOrderedPendingTask,
    181                               std::vector<TestOrderedPendingTask>,
    182                               TemporalOrder> TaskPriorityQueue;
    183 
    184   // Core of the implementation for all flavors of fast-forward methods. Given a
    185   // non-negative |max_delta|, runs all tasks with a remaining delay less than
    186   // or equal to |max_delta|, and moves virtual time forward as needed for each
    187   // processed task. Pass in TimeDelta::Max() as |max_delta| to run all tasks.
    188   void ProcessAllTasksNoLaterThan(TimeDelta max_delta);
    189 
    190   // Forwards |now_ticks_| until it equals |later_ticks|, and forwards |now_| by
    191   // the same amount. Calls OnAfterTimePassed() if |later_ticks| > |now_ticks_|.
    192   // Does nothing if |later_ticks| <= |now_ticks_|.
    193   void ForwardClocksUntilTickTime(TimeTicks later_ticks);
    194 
    195   // Returns the |next_task| to run if there is any with a running time that is
    196   // at most |reference| + |max_delta|. This additional complexity is required
    197   // so that |max_delta| == TimeDelta::Max() can be supported.
    198   bool DequeueNextTask(const TimeTicks& reference,
    199                        const TimeDelta& max_delta,
    200                        TestPendingTask* next_task);
    201 
    202   // Also used for non-dcheck logic (RunsTasksOnCurrentThread()) and as such
    203   // needs to be a ThreadCheckerImpl.
    204   ThreadCheckerImpl thread_checker_;
    205 
    206   Time now_;
    207   TimeTicks now_ticks_;
    208 
    209   // Temporally ordered heap of pending tasks. Must only be accessed while the
    210   // |tasks_lock_| is held.
    211   TaskPriorityQueue tasks_;
    212 
    213   // The ordinal to use for the next task. Must only be accessed while the
    214   // |tasks_lock_| is held.
    215   size_t next_task_ordinal_;
    216 
    217   Lock tasks_lock_;
    218 
    219   DISALLOW_COPY_AND_ASSIGN(TestMockTimeTaskRunner);
    220 };
    221 
    222 }  // namespace base
    223 
    224 #endif  // BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
    225