blob: 03f329a9924cadc75f37bf92d35188f3b7a647d7 [file] [log] [blame]
// Copyright 2017 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.
#include <memory>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/single_thread_task_runner.h"
#include "base/task/lazy_thread_pool_task_runner.h"
#include "base/task/sequence_manager/sequence_manager.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 SimpleTaskExecutor;
class TickClock;
namespace subtle {
class ScopedTimeClockOverrides;
namespace test {
// This header exposes SingleThreadTaskEnvironment and TaskEnvironment.
// SingleThreadTaskEnvironment enables the following APIs within its scope:
// - (Thread|Sequenced)TaskRunnerHandle 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 (Thread|Sequenced)TaskRunnerHandle run synchronously when
// RunLoop::Run(UntilIdle) or TaskEnvironment::RunUntilIdle 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() 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 {
// 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 {};
enum class TimeSource {
// Delayed tasks and Time/TimeTicks::Now() use the real-time system clock.
// 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.
// 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.
// 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.
// The main thread pumps UI messages.
// The main thread pumps asynchronous IO messages and supports the
// FileDescriptorWatcher API on POSIX.
// 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).
// 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.
enum class ThreadingMode {
// ThreadPool will be initialized, thus adding support for multi-threaded
// tests.
// No thread pool will be initialized. Useful for tests that want to run
// single threaded. Prefer using SingleThreadTaskEnvironment over this
// trait.
// 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.
// Place the pool's workers in a 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).
// List of traits that are valid inputs for the constructor below.
struct ValidTraits {
// Constructor accepts zero or more traits which customize the testing
// environment.
template <typename... TaskEnvironmentTraits,
class CheckArgumentsAreValid = std::enable_if_t<
NOINLINE explicit TaskEnvironment(TaskEnvironmentTraits... traits)
: TaskEnvironment(
trait_helpers::GetEnum<TimeSource, TimeSource::DEFAULT>(traits...),
trait_helpers::GetEnum<MainThreadType, MainThreadType::DEFAULT>(
trait_helpers::GetEnum<ThreadingMode, ThreadingMode::DEFAULT>(
trait_helpers::NotATraitTag()) {}
// Waits until no undelayed ThreadPool tasks remain. Then, unregisters the
// ThreadPoolInstance and the (Thread|Sequenced)TaskRunnerHandle.
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;
// Runs tasks until both the (Thread|Sequenced)TaskRunnerHandle 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 returns. |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);
// 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);
// 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
// number of pending tasks (delayed and non-delayed) of the main thread's
// TaskRunner. When debugging, you can use DescribePendingMainThreadTasks() 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.
void DescribePendingMainThreadTasks() const;
class DestructionObserver : public CheckedObserver {
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);
// 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;
explicit 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 TimeDomain driving this TaskEnvironment.
sequence_manager::TimeDomain* GetTimeDomain() const;
sequence_manager::SequenceManager* sequence_manager() const;
void DeferredInitFromSubclass(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
// Derived classes may need to control when the sequence manager goes away.
void NotifyDestructionObserversAndReleaseSequenceManager();
class TestTaskTracker;
class MockTimeDomain;
void InitializeThreadPool();
void DestroyThreadPool();
void CompleteInitialization();
// The template constructor has to be in the header but it delegates to this
// constructor to initialize all other members out-of-line.
TaskEnvironment(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_AND_NOW mode.
// Null in other modes.
std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
scoped_refptr<sequence_manager::TaskQueue> task_queue_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
// Only set for instances using TimeSource::MOCK_TIME.
std::unique_ptr<Clock> mock_clock_;
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
// Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
// Owned by the ThreadPoolInstance.
TestTaskTracker* task_tracker_ = nullptr;
// Ensures destruction of lazy TaskRunners when this is destroyed.
// 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);
// To support base::CurrentThread().
std::unique_ptr<SimpleTaskExecutor> simple_task_executor_;
// 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_|.
// 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 {
template <class... ArgTypes>
SingleThreadTaskEnvironment(ArgTypes... args)
: TaskEnvironment(ThreadingMode::MAIN_THREAD_ONLY, args...) {}
} // namespace test
} // namespace base