forked from kiwibrowser/src
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_mock_time_task_runner.h
293 lines (245 loc) · 11.2 KB
/
test_mock_time_task_runner.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
#define BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
#include <stddef.h>
#include <memory>
#include <queue>
#include <vector>
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/test/test_pending_task.h"
#include "base/threading/thread_checker_impl.h"
#include "base/time/clock.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
namespace base {
class ThreadTaskRunnerHandle;
// Runs pending tasks in the order of the tasks' post time + delay, and keeps
// track of a mock (virtual) tick clock time that can be fast-forwarded.
//
// TestMockTimeTaskRunner has the following properties:
//
// - Methods RunsTasksInCurrentSequence() and Post[Delayed]Task() can be
// called from any thread, but the rest of the methods must be called on
// the same thread the TestMockTimeTaskRunner was created on.
// - It allows for reentrancy, in that it handles the running of tasks that in
// turn call back into it (e.g., to post more tasks).
// - Tasks are stored in a priority queue, and executed in the increasing
// order of post time + delay, but ignoring nestability.
// - It does not check for overflow when doing time arithmetic. A sufficient
// condition for preventing overflows is to make sure that the sum of all
// posted task delays and fast-forward increments is still representable by
// a TimeDelta, and that adding this delta to the starting values of Time
// and TickTime is still within their respective range.
//
// A TestMockTimeTaskRunner of Type::kBoundToThread has the following additional
// properties:
// - Thread/SequencedTaskRunnerHandle refers to it on its thread.
// - It can be driven by a RunLoop on the thread it was created on.
// RunLoop::Run() will result in running non-delayed tasks until idle and
// then, if RunLoop::QuitWhenIdle() wasn't invoked, fast-forwarding time to
// the next delayed task and looping again. And so on, until either
// RunLoop::Quit() is invoked (quits immediately after the current task) or
// RunLoop::QuitWhenIdle() is invoked (quits before having to fast forward
// time once again). Should RunLoop::Run() process all tasks (including
// delayed ones), it will block until more are posted. As usual,
// RunLoop::RunUntilIdle() is equivalent to RunLoop::Run() followed by an
// immediate RunLoop::QuitWhenIdle().
// -
//
// This is a slightly more sophisticated version of TestSimpleTaskRunner, in
// that it supports running delayed tasks in the correct temporal order.
class TestMockTimeTaskRunner : public SingleThreadTaskRunner,
public RunLoop::Delegate {
public:
// Everything that is executed in the scope of a ScopedContext will behave as
// though it ran under |scope| (i.e. ThreadTaskRunnerHandle,
// RunsTasksInCurrentSequence, etc.). This allows the test body to be all in
// one block when multiple TestMockTimeTaskRunners share the main thread.
// Note: RunLoop isn't supported: will DCHECK if used inside a ScopedContext.
//
// For example:
//
// class ExampleFixture {
// protected:
// DoBarOnFoo() {
// DCHECK(foo_task_runner_->RunsOnCurrentThread());
// EXPECT_EQ(foo_task_runner_, ThreadTaskRunnerHandle::Get());
// DoBar();
// }
//
// // Mock main task runner.
// base::MessageLoop message_loop_;
// base::ScopedMockTimeMessageLoopTaskRunner main_task_runner_;
//
// // Mock foo task runner.
// scoped_refptr<TestMockTimeTaskRunner> foo_task_runner_ =
// new TestMockTimeTaskRunner();
// };
//
// TEST_F(ExampleFixture, DoBarOnFoo) {
// DoThingsOnMain();
// {
// TestMockTimeTaskRunner::ScopedContext scoped_context(
// foo_task_runner_.get());
// DoBarOnFoo();
// }
// DoMoreThingsOnMain();
// }
//
class ScopedContext {
public:
// Note: |scope| is ran until idle as part of this constructor to ensure
// that anything which runs in the underlying scope runs after any already
// pending tasks (the contrary would break the SequencedTaskRunner
// contract).
explicit ScopedContext(scoped_refptr<TestMockTimeTaskRunner> scope);
~ScopedContext();
private:
ScopedClosureRunner on_destroy_;
DISALLOW_COPY_AND_ASSIGN(ScopedContext);
};
enum class Type {
// A TestMockTimeTaskRunner which can only be driven directly through its
// API. Thread/SequencedTaskRunnerHandle will refer to it only in the scope
// of its tasks.
kStandalone,
// A TestMockTimeTaskRunner which will associate to the thread it is created
// on, enabling RunLoop to drive it and making
// Thread/SequencedTaskRunnerHandle refer to it on that thread.
kBoundToThread,
};
// Constructs an instance whose virtual time will start at the Unix epoch, and
// whose time ticks will start at zero.
TestMockTimeTaskRunner(Type type = Type::kStandalone);
// Constructs an instance starting at the given virtual time and time ticks.
TestMockTimeTaskRunner(Time start_time,
TimeTicks start_ticks,
Type type = Type::kStandalone);
// Fast-forwards virtual time by |delta|, causing all tasks with a remaining
// delay less than or equal to |delta| to be executed. |delta| must be
// non-negative.
void FastForwardBy(TimeDelta delta);
// Fast-forwards virtual time by |delta| but not causing any task execution.
void AdvanceMockTickClock(TimeDelta delta);
// Fast-forwards virtual time just until all tasks are executed.
void FastForwardUntilNoTasksRemain();
// Executes all tasks that have no remaining delay. Tasks with a remaining
// delay greater than zero will remain enqueued, and no virtual time will
// elapse.
void RunUntilIdle();
// Clears the queue of pending tasks without running them.
void ClearPendingTasks();
// Returns the current virtual time (initially starting at the Unix epoch).
Time Now() const;
// Returns the current virtual tick time (initially starting at 0).
TimeTicks NowTicks() const;
// Returns a Clock that uses the virtual time of |this| as its time source.
// The returned Clock will hold a reference to |this|.
// TODO(tzik): Remove DeprecatedGetMockClock() after updating all callers to
// use non-owning Clock.
std::unique_ptr<Clock> DeprecatedGetMockClock() const;
Clock* GetMockClock() const;
// Returns a TickClock that uses the virtual time ticks of |this| as its tick
// source. The returned TickClock will hold a reference to |this|.
// TODO(tzik): Replace Remove DeprecatedGetMockTickClock() after updating all
// callers to use non-owning TickClock.
std::unique_ptr<TickClock> DeprecatedGetMockTickClock() const;
const TickClock* GetMockTickClock() const;
// Cancelled pending tasks get pruned automatically.
base::circular_deque<TestPendingTask> TakePendingTasks();
bool HasPendingTask();
size_t GetPendingTaskCount();
TimeDelta NextPendingTaskDelay();
// SingleThreadTaskRunner:
bool RunsTasksInCurrentSequence() const override;
bool PostDelayedTask(const Location& from_here,
OnceClosure task,
TimeDelta delay) override;
bool PostNonNestableDelayedTask(const Location& from_here,
OnceClosure task,
TimeDelta delay) override;
protected:
~TestMockTimeTaskRunner() override;
// Called before the next task to run is selected, so that subclasses have a
// last chance to make sure all tasks are posted.
virtual void OnBeforeSelectingTask();
// Called after the current mock time has been incremented so that subclasses
// can react to the passing of time.
virtual void OnAfterTimePassed();
// Called after each task is run so that subclasses may perform additional
// activities, e.g., pump additional task runners.
virtual void OnAfterTaskRun();
private:
// MockClock implements TickClock and Clock. Always returns the then-current
// mock time of |task_runner| as the current time or time ticks.
class MockClock : public TickClock, public Clock {
public:
explicit MockClock(TestMockTimeTaskRunner* task_runner)
: task_runner_(task_runner) {}
// TickClock:
TimeTicks NowTicks() const override;
// Clock:
Time Now() const override;
private:
TestMockTimeTaskRunner* task_runner_;
DISALLOW_COPY_AND_ASSIGN(MockClock);
};
struct TestOrderedPendingTask;
// Predicate that defines a strict weak temporal ordering of tasks.
class TemporalOrder {
public:
bool operator()(const TestOrderedPendingTask& first_task,
const TestOrderedPendingTask& second_task) const;
};
typedef std::priority_queue<TestOrderedPendingTask,
std::vector<TestOrderedPendingTask>,
TemporalOrder> TaskPriorityQueue;
// Core of the implementation for all flavors of fast-forward methods. Given a
// non-negative |max_delta|, runs all tasks with a remaining delay less than
// or equal to |max_delta|, and moves virtual time forward as needed for each
// processed task. Pass in TimeDelta::Max() as |max_delta| to run all tasks.
void ProcessAllTasksNoLaterThan(TimeDelta max_delta);
// Forwards |now_ticks_| until it equals |later_ticks|, and forwards |now_| by
// the same amount. Calls OnAfterTimePassed() if |later_ticks| > |now_ticks_|.
// Does nothing if |later_ticks| <= |now_ticks_|.
void ForwardClocksUntilTickTime(TimeTicks later_ticks);
// Returns the |next_task| to run if there is any with a running time that is
// at most |reference| + |max_delta|. This additional complexity is required
// so that |max_delta| == TimeDelta::Max() can be supported.
bool DequeueNextTask(const TimeTicks& reference,
const TimeDelta& max_delta,
TestPendingTask* next_task);
// RunLoop::Delegate:
void Run(bool application_tasks_allowed) override;
void Quit() override;
void EnsureWorkScheduled() override;
// Also used for non-dcheck logic (RunsTasksInCurrentSequence()) and as such
// needs to be a ThreadCheckerImpl.
ThreadCheckerImpl thread_checker_;
Time now_;
TimeTicks now_ticks_;
// Temporally ordered heap of pending tasks. Must only be accessed while the
// |tasks_lock_| is held.
TaskPriorityQueue tasks_;
// The ordinal to use for the next task. Must only be accessed while the
// |tasks_lock_| is held.
size_t next_task_ordinal_ = 0;
mutable Lock tasks_lock_;
ConditionVariable tasks_lock_cv_;
std::unique_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
// Set to true in RunLoop::Delegate::Quit() to signal the topmost
// RunLoop::Delegate::Run() instance to stop, reset to false when it does.
bool quit_run_loop_ = false;
mutable MockClock mock_clock_;
DISALLOW_COPY_AND_ASSIGN(TestMockTimeTaskRunner);
};
} // namespace base
#endif // BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_