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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
base / test / task_environment.h [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TEST_TASK_ENVIRONMENT_H_
#define BASE_TEST_TASK_ENVIRONMENT_H_
#include <memory>
#include "base/compiler_specific.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_types.h"
#include "base/run_loop.h"
#include "base/task/lazy_thread_pool_task_runner.h"
#include "base/task/sequence_manager/sequence_manager.h"
#include "base/task/sequence_manager/task_queue.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/traits_bag.h"
#include "build/build_config.h"
namespace base {
class Clock;
class FileDescriptorWatcher;
class TickClock;
namespace subtle {
class ScopedTimeClockOverrides;
}
namespace test {
// This header exposes SingleThreadTaskEnvironment and TaskEnvironment.
//
// SingleThreadTaskEnvironment enables the following APIs within its scope:
// - (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle on the main
// thread
// - RunLoop on the main thread
//
// TaskEnvironment additionally enables:
// - posting to base::ThreadPool through base/task/thread_pool.h.
//
// Hint: For content::BrowserThreads, use content::BrowserTaskEnvironment.
//
// Tests should prefer SingleThreadTaskEnvironment over TaskEnvironment when the
// former is sufficient.
//
// Tasks posted to the (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle
// run synchronously when RunLoop::Run(UntilIdle) or
// TaskEnvironment::RunUntil(Idle|Quit) is called on the main thread.
//
// The TaskEnvironment requires TestTimeouts::Initialize() to be called in order
// to run posted tasks, so that it can watch for problematic long-running tasks.
//
// The TimeSource trait can be used to request that delayed tasks be under the
// manual control of RunLoop::Run() and TaskEnvironment::FastForward*() methods.
//
// If a TaskEnvironment's ThreadPoolExecutionMode is QUEUED, ThreadPool tasks
// run when RunUntilIdle(), RunUntilQuit(), or ~TaskEnvironment is called. If
// ThreadPoolExecutionMode is ASYNC, they run as they are posted.
//
// All TaskEnvironment methods must be called from the main thread.
//
// Usage:
//
// class MyTestFixture : public testing::Test {
// public:
// (...)
//
// // protected rather than private visibility will allow controlling the
// // task environment (e.g. RunUntilIdle(), FastForwardBy(), etc.). from the
// // test body.
// protected:
// // Must generally be the first member to be initialized first and
// // destroyed last (some members that require single-threaded
// // initialization and tear down may need to come before -- e.g.
// // base::test::ScopedFeatureList). Extra traits, like TimeSource, are
// // best provided inline when declaring the TaskEnvironment, as
// // such:
// base::test::TaskEnvironment task_environment_{
// base::test::TaskEnvironment::TimeSource::MOCK_TIME};
//
// // Other members go here (or further below in private section.)
// };
class TaskEnvironment {
protected:
// This enables a two-phase initialization for sub classes such as
// content::BrowserTaskEnvironment which need to provide the default task
// queue because they instantiate a scheduler on the same thread. Subclasses
// using this trait must invoke DeferredInitFromSubclass() before running the
// task environment.
struct SubclassCreatesDefaultTaskRunner {};
public:
enum class TimeSource {
// Delayed tasks and Time/TimeTicks::Now() use the real-time system clock.
SYSTEM_TIME,
// Delayed tasks use a mock clock which only advances when reaching "idle"
// during a RunLoop::Run() call on the main thread or a FastForward*() call
// to this TaskEnvironment. "idle" is defined as the main thread and thread
// pool being out of ready tasks. In that situation : time advances to the
// soonest delay between main thread and thread pool delayed tasks,
// according to the semantics of the current Run*() or FastForward*() call.
//
// This also mocks Time/TimeTicks::Now() with the same mock clock.
// Time::Now() and TimeTicks::Now() (with respect to its origin) start
// without submillisecond components.
//
// Warning some platform APIs are still real-time, e.g.:
// * PlatformThread::Sleep
// * WaitableEvent::TimedWait
// * ConditionVariable::TimedWait
// * Delayed tasks on unmanaged base::Thread's and other custom task
// runners.
MOCK_TIME,
DEFAULT = SYSTEM_TIME
};
// This type will determine what types of messages will get pumped by the main
// thread.
// Note: If your test needs to use a custom MessagePump you should
// consider using a SingleThreadTaskExecutor instead.
enum class MainThreadType {
// The main thread doesn't pump system messages.
DEFAULT,
// The main thread pumps UI messages.
UI,
// The main thread pumps asynchronous IO messages and supports the
// FileDescriptorWatcher API on POSIX.
IO,
};
// Note that this is irrelevant (and ignored) under
// ThreadingMode::MAIN_THREAD_ONLY
enum class ThreadPoolExecutionMode {
// Thread pool tasks are queued and only executed when RunUntilIdle(),
// FastForwardBy(), or FastForwardUntilNoTasksRemain() are explicitly
// called. Note: RunLoop::Run() does *not* unblock the ThreadPool in this
// mode (it strictly runs only the main thread).
QUEUED,
// Thread pool tasks run as they are posted. RunUntilIdle() can still be
// used to block until done.
// Note that regardless of this trait, delayed tasks are always "queued"
// under TimeSource::MOCK_TIME mode.
ASYNC,
DEFAULT = ASYNC
};
enum class ThreadingMode {
// ThreadPool will be initialized, thus adding support for multi-threaded
// tests.
MULTIPLE_THREADS,
// No thread pool will be initialized. Useful for tests that want to run
// single threaded. Prefer using SingleThreadTaskEnvironment over this
// trait.
MAIN_THREAD_ONLY,
DEFAULT = MULTIPLE_THREADS
};
// On Windows, sets the COM environment for the ThreadPoolInstance. Ignored
// on other platforms.
enum class ThreadPoolCOMEnvironment {
// Do not initialize COM for the pool's workers.
NONE,
// Place the pool's workers in a COM MTA.
COM_MTA,
// Enable the MTA by default in unit tests to match the browser process's
// ThreadPoolInstance configuration.
//
// This has the adverse side-effect of enabling the MTA in non-browser unit
// tests as well but the downside there is not as bad as not having it in
// browser unit tests. It just means some COM asserts may pass in unit
// tests where they wouldn't in integration tests or prod. That's okay
// because unit tests are already generally very loose on allowing I/O,
// waits, etc. Such misuse will still be caught in later phases (and COM
// usage should already be pretty much inexistent in sandboxed processes).
DEFAULT = COM_MTA,
};
// List of traits that are valid inputs for the constructor below.
struct ValidTraits {
ValidTraits(TimeSource);
ValidTraits(MainThreadType);
ValidTraits(ThreadPoolExecutionMode);
ValidTraits(SubclassCreatesDefaultTaskRunner);
ValidTraits(ThreadingMode);
ValidTraits(ThreadPoolCOMEnvironment);
};
// Constructor accepts zero or more traits which customize the testing
// environment.
template <typename... TaskEnvironmentTraits>
requires trait_helpers::AreValidTraits<ValidTraits,
TaskEnvironmentTraits...>
NOINLINE explicit TaskEnvironment(TaskEnvironmentTraits... traits)
: TaskEnvironment(sequence_manager::SequenceManager::PrioritySettings::
CreateDefault(),
traits...) {}
TaskEnvironment(const TaskEnvironment&) = delete;
TaskEnvironment& operator=(const TaskEnvironment&) = delete;
// Waits until no undelayed ThreadPool tasks remain. Then, unregisters the
// ThreadPoolInstance and the
// (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle.
virtual ~TaskEnvironment();
// Returns a TaskRunner that schedules tasks on the main thread.
scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner();
// Returns whether the main thread's TaskRunner has pending tasks. This will
// always return true if called right after RunUntilIdle.
bool MainThreadIsIdle() const;
// Returns a RepeatingClosure that ends the next call to RunUntilQuit(). The
// quit closures must be obtained from the thread owning the TaskEnvironment
// but may then be invoked from any thread. To avoid a potential race
// condition, do not call QuitClosure() while RunUntilQuit() is running.
RepeatingClosure QuitClosure();
// Runs tasks on both the main thread and the thread pool, until a quit
// closure is executed. When RunUntilQuit() returns, all previous quit
// closures are invalidated, and will have no effect on future calls. Be sure
// to create a new quit closure before calling RunUntilQuit() again.
void RunUntilQuit();
// Runs tasks until both the
// (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle and the
// ThreadPool's non-delayed queues are empty. While RunUntilIdle() is quite
// practical and sometimes even necessary -- for example, to flush all tasks
// bound to Unretained() state before destroying test members -- it should be
// used with caution per the following warnings:
//
// WARNING #1: This may run long (flakily timeout) and even never return! Do
// not use this when repeating tasks such as animated web pages
// are present.
// WARNING #2: This may return too early! For example, if used to run until an
// incoming event has occurred but that event depends on a task in
// a different queue -- e.g. a standalone base::Thread or a system
// event.
//
// As such, prefer RunLoop::Run() with an explicit RunLoop::QuitClosure() when
// possible.
void RunUntilIdle();
// Only valid for instances using |TimeSource::MOCK_TIME|. Fast-forwards
// virtual time by |delta|, causing all tasks on the main thread and thread
// pool with a remaining delay less than or equal to |delta| to be executed
// in their natural order before this method returns. Undelayed tasks are just
// delayed tasks with a delay of 0, so they are also executed. |delta| must be
// non-negative. Upon returning from this method, NowTicks() will be >= the
// initial |NowTicks() + delta|. It is guaranteed to be == iff tasks executed
// in this FastForwardBy() didn't result in nested calls to
// time-advancing-methods.
void FastForwardBy(TimeDelta delta);
// Similar to `FastForwardBy` but doesn't advance `base::LiveTicks`, behaving
// as if the system was suspended for `delta` time and immediately woken up.
void SuspendedFastForwardBy(TimeDelta delta);
// Only valid for instances using TimeSource::MOCK_TIME.
// Short for FastForwardBy(TimeDelta::Max()).
//
// WARNING: This has the same caveat as RunUntilIdle() and is even more likely
// to spin forever (any RepeatingTimer will cause this).
void FastForwardUntilNoTasksRemain();
// Only valid for instances using TimeSource::MOCK_TIME. Advances virtual time
// by |delta|. Unlike FastForwardBy, this does not run tasks. Prefer
// FastForwardBy() when possible but this can be useful when testing blocked
// pending tasks where being idle (required to fast-forward) is not possible.
//
// Delayed tasks that are ripe as a result of this will be scheduled.
// RunUntilIdle() can be used after this call to ensure those tasks have run.
// Note: AdvanceClock(delta) + RunUntilIdle() is slightly different from
// FastForwardBy(delta) in that time passes instantly before running any task
// (whereas FastForwardBy() will advance the clock in the smallest increments
// possible at a time). Hence FastForwardBy() is more realistic but
// AdvanceClock() can be useful when testing edge case scenarios that
// specifically handle more time than expected to have passed.
void AdvanceClock(TimeDelta delta);
// Similar to `AdvanceClock` but doesn't advance `base::LiveTicks`, behaving
// as if the system was suspended for `delta` time and immediately woken up.
void SuspendedAdvanceClock(TimeDelta delta);
bool UsesMockTime() const { return !!mock_clock_; }
// Only valid for instances using TimeSource::MOCK_TIME. Returns a
// TickClock whose time is updated by FastForward(By|UntilNoTasksRemain).
const TickClock* GetMockTickClock() const;
// Only valid for instances using TimeSource::MOCK_TIME. Returns a
// Clock whose time is updated by FastForward(By|UntilNoTasksRemain). The
// initial value is implementation defined and should be queried by tests that
// depend on it.
// TickClock should be used instead of Clock to measure elapsed time in a
// process. See time.h.
const Clock* GetMockClock() const;
// Only valid for instances using TimeSource::MOCK_TIME. Returns the current
// virtual tick time (based on a realistic Now(), sampled when this
// TaskEnvironment was created, and manually advanced from that point on).
// This is always equivalent to base::TimeTicks::Now() under
// TimeSource::MOCK_TIME.
base::TimeTicks NowTicks() const;
// Only valid for instances using TimeSource::MOCK_TIME. Returns the current
// virtual live time (based on a realistic Now(), sampled when this
// TaskEnvironment was created, and manually advanced from that point on).
// This is always equivalent to base::LiveTicks::Now() under
// TimeSource::MOCK_TIME.
base::LiveTicks NowLiveTicks() const;
// Only valid for instances using TimeSource::MOCK_TIME. Returns the number of
// pending tasks (delayed and non-delayed) of the main thread's TaskRunner.
// When debugging, you can use DescribeCurrentTasks() to see what those are.
size_t GetPendingMainThreadTaskCount() const;
// Only valid for instances using TimeSource::MOCK_TIME.
// Returns the delay until the next pending task of the main thread's
// TaskRunner if there is one, otherwise it returns TimeDelta::Max().
TimeDelta NextMainThreadPendingTaskDelay() const;
// Only valid for instances using TimeSource::MOCK_TIME.
// Returns true iff the next task is delayed. Returns false if the next task
// is immediate or if there is no next task.
bool NextTaskIsDelayed() const;
// For debugging purposes: Dumps information about pending tasks on the main
// thread, and currently running tasks on the thread pool.
void DescribeCurrentTasks() const;
// Detach ThreadCheckers (will rebind on next usage), useful for the odd test
// suite which doesn't run on the main thread but still has exclusive access
// to driving this TaskEnvironment (e.g. WaylandClientTestSuiteServer).
void DetachFromThread();
class TestTaskTracker;
// Callers outside of TaskEnvironment may not use the returned pointer. They
// should just use base::ThreadPoolInstance::Get().
static TestTaskTracker* CreateThreadPool();
class DestructionObserver : public CheckedObserver {
public:
DestructionObserver() = default;
~DestructionObserver() override = default;
DestructionObserver(const DestructionObserver&) = delete;
DestructionObserver& operator=(const DestructionObserver&) = delete;
virtual void WillDestroyCurrentTaskEnvironment() = 0;
};
// Adds/removes a DestructionObserver to any TaskEnvironment. Observers are
// notified when any TaskEnvironment goes out of scope (other than with a move
// operation). Must be called on the main thread.
static void AddDestructionObserver(DestructionObserver* observer);
static void RemoveDestructionObserver(DestructionObserver* observer);
// Instantiating a ParallelExecutionFence waits for all currently running
// ThreadPool tasks before the constructor returns and from then on prevents
// additional tasks from running during its lifetime.
//
// Must be instantiated from the test main thread.
class ParallelExecutionFence {
public:
// Instantiates a ParallelExecutionFence, crashes with an optional
// |error_message| if not invoked from test main thread.
explicit ParallelExecutionFence(const char* error_message = "");
~ParallelExecutionFence();
ParallelExecutionFence(const ParallelExecutionFence&) = delete;
ParallelExecutionFence& operator=(const ParallelExecutionFence& other) =
delete;
private:
bool previously_allowed_to_run_ = false;
};
// The number of foreground workers in the ThreadPool managed by a
// TaskEnvironment instance. This can be used to determine the maximum
// parallelism in tests that require each parallel task it spawns to be
// running at once. Having multiple threads prevents deadlocks should some
// blocking APIs not use ScopedBlockingCall. It also allows enough concurrency
// to allow TSAN to spot data races.
static constexpr int kNumForegroundThreadPoolThreads = 4;
protected:
template <typename... TaskEnvironmentTraits>
requires trait_helpers::AreValidTraits<ValidTraits,
TaskEnvironmentTraits...>
NOINLINE static TaskEnvironment CreateTaskEnvironmentWithPriorities(
sequence_manager::SequenceManager::PrioritySettings priority_settings,
TaskEnvironmentTraits... traits) {
return TaskEnvironment(std::move(priority_settings), traits...);
}
// Constructor accepts zero or more traits which customize the testing
// environment.
template <typename... TaskEnvironmentTraits>
requires trait_helpers::AreValidTraits<ValidTraits,
TaskEnvironmentTraits...>
NOINLINE explicit TaskEnvironment(
sequence_manager::SequenceManager::PrioritySettings priority_settings,
TaskEnvironmentTraits... traits)
: TaskEnvironment(
std::move(priority_settings),
trait_helpers::GetEnum<TimeSource, TimeSource::DEFAULT>(traits...),
trait_helpers::GetEnum<MainThreadType, MainThreadType::DEFAULT>(
traits...),
trait_helpers::GetEnum<ThreadPoolExecutionMode,
ThreadPoolExecutionMode::DEFAULT>(traits...),
trait_helpers::GetEnum<ThreadingMode, ThreadingMode::DEFAULT>(
traits...),
trait_helpers::GetEnum<ThreadPoolCOMEnvironment,
ThreadPoolCOMEnvironment::DEFAULT>(
traits...),
trait_helpers::HasTrait<SubclassCreatesDefaultTaskRunner,
TaskEnvironmentTraits...>(),
trait_helpers::NotATraitTag()) {}
TaskEnvironment(TaskEnvironment&& other);
constexpr MainThreadType main_thread_type() const {
return main_thread_type_;
}
constexpr ThreadPoolExecutionMode thread_pool_execution_mode() const {
return thread_pool_execution_mode_;
}
// Returns the MockTimeDomain driving this TaskEnvironment if this instance is
// using TimeSource::MOCK_TIME, nullptr otherwise.
sequence_manager::TimeDomain* GetMockTimeDomain() const;
sequence_manager::SequenceManager* sequence_manager() const;
void DeferredInitFromSubclass(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Derived classes may need to control when the task environment goes away
// (e.g. ~FooTaskEnvironment() may want to effectively trigger
// ~TaskEnvironment() before its members are destroyed).
void DestroyTaskEnvironment();
private:
class MockTimeDomain;
void InitializeThreadPool();
void ShutdownAndJoinThreadPool();
void DestroyThreadPool();
void CompleteInitialization();
void FastForwardByInternal(TimeDelta delta, bool advance_live_ticks);
// The template constructor has to be in the header but it delegates to this
// constructor to initialize all other members out-of-line.
TaskEnvironment(
sequence_manager::SequenceManager::PrioritySettings priority_settings,
TimeSource time_source,
MainThreadType main_thread_type,
ThreadPoolExecutionMode thread_pool_execution_mode,
ThreadingMode threading_mode,
ThreadPoolCOMEnvironment thread_pool_com_environment,
bool subclass_creates_default_taskrunner,
trait_helpers::NotATraitTag tag);
const MainThreadType main_thread_type_;
const ThreadPoolExecutionMode thread_pool_execution_mode_;
const ThreadingMode threading_mode_;
const ThreadPoolCOMEnvironment thread_pool_com_environment_;
const bool subclass_creates_default_taskrunner_;
std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
// Manages the clock under TimeSource::MOCK_TIME modes. Null in
// TimeSource::SYSTEM_TIME mode.
std::unique_ptr<MockTimeDomain> mock_time_domain_;
// Overrides Time/TimeTicks::Now() under TimeSource::MOCK_TIME mode.
// Null in other modes.
std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
sequence_manager::TaskQueue::Handle task_queue_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Only set for instances using TimeSource::MOCK_TIME.
std::unique_ptr<Clock> mock_clock_;
#if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
// Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
#endif
// Owned by the ThreadPoolInstance.
raw_ptr<TestTaskTracker, DanglingUntriaged> task_tracker_ = nullptr;
// Ensures destruction of lazy TaskRunners when this is destroyed.
std::unique_ptr<base::internal::ScopedLazyTaskRunnerListForTesting>
scoped_lazy_task_runner_list_for_testing_;
// Sets RunLoop::Run() to LOG(FATAL) if not Quit() in a timely manner.
std::unique_ptr<ScopedRunLoopTimeout> run_loop_timeout_;
std::unique_ptr<bool> owns_instance_ = std::make_unique<bool>(true);
std::unique_ptr<RunLoop> run_until_quit_loop_;
// Used to verify thread-affinity of operations that must occur on the main
// thread. This is the case for anything that modifies or drives the
// |sequence_manager_|.
THREAD_CHECKER(main_thread_checker_);
};
// SingleThreadTaskEnvironment takes the same traits as TaskEnvironment and is
// used the exact same way. It's a short-form for
// TaskEnvironment{TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY, ...};
class SingleThreadTaskEnvironment : public TaskEnvironment {
public:
template <class... ArgTypes>
SingleThreadTaskEnvironment(ArgTypes... args)
: TaskEnvironment(ThreadingMode::MAIN_THREAD_ONLY, args...) {}
};
} // namespace test
} // namespace base
#endif // BASE_TEST_TASK_ENVIRONMENT_H_