123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- // 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.
- #ifndef BASE_TEST_TASK_ENVIRONMENT_H_
- #define BASE_TEST_TASK_ENVIRONMENT_H_
- #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 {
- 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.
- //
- // 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,
- class CheckArgumentsAreValid = std::enable_if_t<
- trait_helpers::AreValidTraits<ValidTraits,
- TaskEnvironmentTraits...>::value>>
- NOINLINE explicit TaskEnvironment(TaskEnvironmentTraits... traits)
- : TaskEnvironment(
- 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()) {}
- // 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;
- std::unique_ptr<TickClock> DeprecatedGetMockTickClock();
- // 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 {
- 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);
- // 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:
- 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();
- private:
- 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_;
- #endif
- // Owned by the ThreadPoolInstance.
- TestTaskTracker* task_tracker_ = nullptr;
- // Ensures destruction of lazy TaskRunners when this is destroyed.
- std::unique_ptr<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);
- // 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_|.
- THREAD_CHECKER(main_thread_checker_);
- DISALLOW_COPY_AND_ASSIGN(TaskEnvironment);
- };
- // 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_
|