// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_PUBLIC_TEST_BROWSER_TASK_ENVIRONMENT_H_ #define CONTENT_PUBLIC_TEST_BROWSER_TASK_ENVIRONMENT_H_ #include <memory> #include "base/compiler_specific.h" #include "base/task/sequence_manager/sequence_manager.h" #include "base/test/task_environment.h" #include "build/build_config.h" namespace base { #if BUILDFLAG(IS_WIN) namespace win { class ScopedCOMInitializer; } // namespace win #endif } // namespace base namespace content { class TestBrowserThread; // BrowserTaskEnvironment is a convenience class which allows usage of these // APIs within its scope: // - Same APIs as base::test::TaskEnvironment. // - content::BrowserThread. // - Public APIs of base::test::TaskEnvironment. // // Only tests that need the BrowserThread API should instantiate a // BrowserTaskEnvironment. Use base::test::SingleThreadTaskEnvironment or // base::test::TaskEnvironment otherwise. // // By default, BrowserThread::UI/IO are backed by a single shared message loop // on the main thread. If a test truly needs BrowserThread::IO tasks to run on a // separate thread, it can pass the REAL_IO_THREAD option to the constructor. // ThreadPool tasks always run on dedicated threads. // // To synchronously run tasks from the shared message loop: // // ... until there are no undelayed tasks in the shared message loop: // base::RunLoop().RunUntilIdle(); // // ... until there are no undelayed tasks in the shared message loop, in // ThreadPool (excluding tasks not posted from the shared message loop's thread // or ThreadPool): task_environment.RunUntilIdle(); // // ... until a condition is met: // base::RunLoop run_loop; // // Runs until a task running in the shared message loop calls // // run_loop.Quit() or runs run_loop.QuitClosure() (&run_loop or // // run_loop.QuitClosure() must be kept somewhere accessible by that task). // run_loop.Run(); // // To wait until there are no pending undelayed tasks in ThreadPool, without // running tasks from the shared message loop (this is rarely needed): // base::ThreadPoolInstance::Get()->FlushForTesting(); // // The destructor of BrowserTaskEnvironment runs remaining UI/IO tasks and // remaining thread pool tasks. // // If a test needs to pump IO messages on the main thread, it should use the // IO_MAINLOOP option. Most of the time, IO_MAINLOOP avoids needing to use a // REAL_IO_THREAD. // // For some tests it is important to emulate real browser startup. During real // browser startup, the main message loop and the ThreadPool are created before // browser threads. Passing DONT_CREATE_BROWSER_THREADS to the constructor will // delay creating BrowserThreads until the test explicitly calls // CreateBrowserThreads(). // // DONT_CREATE_BROWSER_THREADS should only be used in conjunction with // REAL_IO_THREAD. // // Basic usage: // // class MyTestFixture : public testing::Test { // public: // (...) // // protected: // // Must be the first member (or at least before any member that cares // // about tasks) to be initialized first and destroyed last. protected // // instead of private visibility will allow controlling the task // // environment (e.g. clock --see base::test::TaskEnvironment for // // details). // content::BrowserTaskEnvironment task_environment_; // // // Other members go here (or further below in private section.) // }; // // To add a BrowserTaskEnvironment to a ChromeFooBase test fixture when its // FooBase base class already provides a base::test::TaskEnvironment: // class FooBase { // public: // // Constructs a FooBase with |traits| being forwarded to its // // TaskEnvironment. // template <typename... TaskEnvironmentTraits> // explicit FooBase(TaskEnvironmentTraits&&... traits) // : task_environment_( // std::in_place, // std::forward<TaskEnvironmentTraits>(traits)...) {} // // // Alternatively a subclass may pass this tag to ask this FooBase not to // // instantiate a TaskEnvironment. The subclass is then responsible // // to instantiate one before FooBase::SetUp(). // struct SubclassManagesTaskEnvironment {}; // FooBase(SubclassManagesTaskEnvironment tag); // // protected: // // Use this protected member directly from the test body to drive tasks // // posted within a FooBase-based test. // std::optional<base::test::TaskEnvironment> task_environment_; // }; // // class ChromeFooBase : public FooBase { // public: // explicit ChromeFooBase(TaskEnvironmentTraits&&... traits) // : FooBase(FooBase::SubclassManagesTaskEnvironment()), // task_environment_( // std::forward<TaskEnvironmentTraits>(traits)...) {} // // protected: // // Use this protected member directly to drive tasks posted within a // // ChromeFooBase-based test. // content::BrowserTaskEnvironment task_environment_; // }; // See views::ViewsTestBase / ChromeViewsTestBase for a real-world example. class BrowserTaskEnvironment : public base::test::TaskEnvironment { … }; } // namespace content #endif // CONTENT_PUBLIC_TEST_BROWSER_TASK_ENVIRONMENT_H_