xref: /aosp_15_r20/external/cronet/base/test/task_environment.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TEST_TASK_ENVIRONMENT_H_
6 #define BASE_TEST_TASK_ENVIRONMENT_H_
7 
8 #include <memory>
9 
10 #include "base/compiler_specific.h"
11 #include "base/functional/callback_forward.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/observer_list_types.h"
15 #include "base/run_loop.h"
16 #include "base/task/lazy_thread_pool_task_runner.h"
17 #include "base/task/sequence_manager/sequence_manager.h"
18 #include "base/task/sequence_manager/task_queue.h"
19 #include "base/task/single_thread_task_runner.h"
20 #include "base/test/scoped_run_loop_timeout.h"
21 #include "base/threading/thread_checker.h"
22 #include "base/time/time.h"
23 #include "base/traits_bag.h"
24 #include "build/build_config.h"
25 
26 namespace base {
27 
28 class Clock;
29 class FileDescriptorWatcher;
30 class TickClock;
31 
32 namespace subtle {
33 class ScopedTimeClockOverrides;
34 }
35 
36 namespace test {
37 
38 // This header exposes SingleThreadTaskEnvironment and TaskEnvironment.
39 //
40 // SingleThreadTaskEnvironment enables the following APIs within its scope:
41 //  - (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle on the main
42 //    thread
43 //  - RunLoop on the main thread
44 //
45 // TaskEnvironment additionally enables:
46 //  - posting to base::ThreadPool through base/task/thread_pool.h.
47 //
48 // Hint: For content::BrowserThreads, use content::BrowserTaskEnvironment.
49 //
50 // Tests should prefer SingleThreadTaskEnvironment over TaskEnvironment when the
51 // former is sufficient.
52 //
53 // Tasks posted to the (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle
54 // run synchronously when RunLoop::Run(UntilIdle) or
55 // TaskEnvironment::RunUntil(Idle|Quit) is called on the main thread.
56 //
57 // The TaskEnvironment requires TestTimeouts::Initialize() to be called in order
58 // to run posted tasks, so that it can watch for problematic long-running tasks.
59 //
60 // The TimeSource trait can be used to request that delayed tasks be under the
61 // manual control of RunLoop::Run() and TaskEnvironment::FastForward*() methods.
62 //
63 // If a TaskEnvironment's ThreadPoolExecutionMode is QUEUED, ThreadPool tasks
64 // run when RunUntilIdle(), RunUntilQuit(), or ~TaskEnvironment is called. If
65 // ThreadPoolExecutionMode is ASYNC, they run as they are posted.
66 //
67 // All TaskEnvironment methods must be called from the main thread.
68 //
69 // Usage:
70 //
71 //   class MyTestFixture : public testing::Test {
72 //    public:
73 //     (...)
74 //
75 //    // protected rather than private visibility will allow controlling the
76 //    // task environment (e.g. RunUntilIdle(), FastForwardBy(), etc.). from the
77 //    // test body.
78 //    protected:
79 //     // Must generally be the first member to be initialized first and
80 //     // destroyed last (some members that require single-threaded
81 //     // initialization and tear down may need to come before -- e.g.
82 //     // base::test::ScopedFeatureList). Extra traits, like TimeSource, are
83 //     // best provided inline when declaring the TaskEnvironment, as
84 //     // such:
85 //     base::test::TaskEnvironment task_environment_{
86 //         base::test::TaskEnvironment::TimeSource::MOCK_TIME};
87 //
88 //     // Other members go here (or further below in private section.)
89 //   };
90 class TaskEnvironment {
91  protected:
92   // This enables a two-phase initialization for sub classes such as
93   // content::BrowserTaskEnvironment which need to provide the default task
94   // queue because they instantiate a scheduler on the same thread. Subclasses
95   // using this trait must invoke DeferredInitFromSubclass() before running the
96   // task environment.
97   struct SubclassCreatesDefaultTaskRunner {};
98 
99  public:
100   enum class TimeSource {
101     // Delayed tasks and Time/TimeTicks::Now() use the real-time system clock.
102     SYSTEM_TIME,
103 
104     // Delayed tasks use a mock clock which only advances when reaching "idle"
105     // during a RunLoop::Run() call on the main thread or a FastForward*() call
106     // to this TaskEnvironment. "idle" is defined as the main thread and thread
107     // pool being out of ready tasks. In that situation : time advances to the
108     // soonest delay between main thread and thread pool delayed tasks,
109     // according to the semantics of the current Run*() or FastForward*() call.
110     //
111     // This also mocks Time/TimeTicks::Now() with the same mock clock.
112     // Time::Now() and TimeTicks::Now() (with respect to its origin) start
113     // without submillisecond components.
114     //
115     // Warning some platform APIs are still real-time, e.g.:
116     //   * PlatformThread::Sleep
117     //   * WaitableEvent::TimedWait
118     //   * ConditionVariable::TimedWait
119     //   * Delayed tasks on unmanaged base::Thread's and other custom task
120     //     runners.
121     MOCK_TIME,
122 
123     DEFAULT = SYSTEM_TIME
124   };
125 
126   // This type will determine what types of messages will get pumped by the main
127   // thread.
128   // Note: If your test needs to use a custom MessagePump you should
129   // consider using a SingleThreadTaskExecutor instead.
130   enum class MainThreadType {
131     // The main thread doesn't pump system messages.
132     DEFAULT,
133     // The main thread pumps UI messages.
134     UI,
135     // The main thread pumps asynchronous IO messages and supports the
136     // FileDescriptorWatcher API on POSIX.
137     IO,
138   };
139 
140   // Note that this is irrelevant (and ignored) under
141   // ThreadingMode::MAIN_THREAD_ONLY
142   enum class ThreadPoolExecutionMode {
143     // Thread pool tasks are queued and only executed when RunUntilIdle(),
144     // FastForwardBy(), or FastForwardUntilNoTasksRemain() are explicitly
145     // called. Note: RunLoop::Run() does *not* unblock the ThreadPool in this
146     // mode (it strictly runs only the main thread).
147     QUEUED,
148     // Thread pool tasks run as they are posted. RunUntilIdle() can still be
149     // used to block until done.
150     // Note that regardless of this trait, delayed tasks are always "queued"
151     // under TimeSource::MOCK_TIME mode.
152     ASYNC,
153     DEFAULT = ASYNC
154   };
155 
156   enum class ThreadingMode {
157     // ThreadPool will be initialized, thus adding support for multi-threaded
158     // tests.
159     MULTIPLE_THREADS,
160     // No thread pool will be initialized. Useful for tests that want to run
161     // single threaded. Prefer using SingleThreadTaskEnvironment over this
162     // trait.
163     MAIN_THREAD_ONLY,
164     DEFAULT = MULTIPLE_THREADS
165   };
166 
167   // On Windows, sets the COM environment for the ThreadPoolInstance. Ignored
168   // on other platforms.
169   enum class ThreadPoolCOMEnvironment {
170     // Do not initialize COM for the pool's workers.
171     NONE,
172 
173     // Place the pool's workers in a COM MTA.
174     COM_MTA,
175 
176     // Enable the MTA by default in unit tests to match the browser process's
177     // ThreadPoolInstance configuration.
178     //
179     // This has the adverse side-effect of enabling the MTA in non-browser unit
180     // tests as well but the downside there is not as bad as not having it in
181     // browser unit tests. It just means some COM asserts may pass in unit
182     // tests where they wouldn't in integration tests or prod. That's okay
183     // because unit tests are already generally very loose on allowing I/O,
184     // waits, etc. Such misuse will still be caught in later phases (and COM
185     // usage should already be pretty much inexistent in sandboxed processes).
186     DEFAULT = COM_MTA,
187   };
188 
189   // List of traits that are valid inputs for the constructor below.
190   struct ValidTraits {
191     ValidTraits(TimeSource);
192     ValidTraits(MainThreadType);
193     ValidTraits(ThreadPoolExecutionMode);
194     ValidTraits(SubclassCreatesDefaultTaskRunner);
195     ValidTraits(ThreadingMode);
196     ValidTraits(ThreadPoolCOMEnvironment);
197   };
198 
199   // Constructor accepts zero or more traits which customize the testing
200   // environment.
201   template <typename... TaskEnvironmentTraits>
202     requires trait_helpers::AreValidTraits<ValidTraits,
203                                            TaskEnvironmentTraits...>
TaskEnvironment(TaskEnvironmentTraits...traits)204   NOINLINE explicit TaskEnvironment(TaskEnvironmentTraits... traits)
205       : TaskEnvironment(sequence_manager::SequenceManager::PrioritySettings::
206                             CreateDefault(),
207                         traits...) {}
208 
209   TaskEnvironment(const TaskEnvironment&) = delete;
210   TaskEnvironment& operator=(const TaskEnvironment&) = delete;
211 
212   // Waits until no undelayed ThreadPool tasks remain. Then, unregisters the
213   // ThreadPoolInstance and the
214   // (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle.
215   virtual ~TaskEnvironment();
216 
217   // Returns a TaskRunner that schedules tasks on the main thread.
218   scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner();
219 
220   // Returns whether the main thread's TaskRunner has pending tasks. This will
221   // always return true if called right after RunUntilIdle.
222   bool MainThreadIsIdle() const;
223 
224   // Returns a RepeatingClosure that ends the next call to RunUntilQuit(). The
225   // quit closures must be obtained from the thread owning the TaskEnvironment
226   // but may then be invoked from any thread. To avoid a potential race
227   // condition, do not call QuitClosure() while RunUntilQuit() is running.
228   RepeatingClosure QuitClosure();
229 
230   // Runs tasks on both the main thread and the thread pool, until a quit
231   // closure is executed. When RunUntilQuit() returns, all previous quit
232   // closures are invalidated, and will have no effect on future calls. Be sure
233   // to create a new quit closure before calling RunUntilQuit() again.
234   void RunUntilQuit();
235 
236   // Runs tasks until both the
237   // (SingleThread|Sequenced)TaskRunner::CurrentDefaultHandle and the
238   // ThreadPool's non-delayed queues are empty.  While RunUntilIdle() is quite
239   // practical and sometimes even necessary -- for example, to flush all tasks
240   // bound to Unretained() state before destroying test members -- it should be
241   // used with caution per the following warnings:
242   //
243   // WARNING #1: This may run long (flakily timeout) and even never return! Do
244   //             not use this when repeating tasks such as animated web pages
245   //             are present.
246   // WARNING #2: This may return too early! For example, if used to run until an
247   //             incoming event has occurred but that event depends on a task in
248   //             a different queue -- e.g. a standalone base::Thread or a system
249   //             event.
250   //
251   // As such, prefer RunLoop::Run() with an explicit RunLoop::QuitClosure() when
252   // possible.
253   void RunUntilIdle();
254 
255   // Only valid for instances using |TimeSource::MOCK_TIME|. Fast-forwards
256   // virtual time by |delta|, causing all tasks on the main thread and thread
257   // pool with a remaining delay less than or equal to |delta| to be executed
258   // in their natural order before this method returns. Undelayed tasks are just
259   // delayed tasks with a delay of 0, so they are also executed. |delta| must be
260   // non-negative. Upon returning from this method, NowTicks() will be >= the
261   // initial |NowTicks() + delta|. It is guaranteed to be == iff tasks executed
262   // in this FastForwardBy() didn't result in nested calls to
263   // time-advancing-methods.
264   void FastForwardBy(TimeDelta delta);
265 
266   // Similar to `FastForwardBy` but doesn't advance `base::LiveTicks`, behaving
267   // as if the system was suspended for `delta` time and immediately woken up.
268   void SuspendedFastForwardBy(TimeDelta delta);
269 
270   // Only valid for instances using TimeSource::MOCK_TIME.
271   // Short for FastForwardBy(TimeDelta::Max()).
272   //
273   // WARNING: This has the same caveat as RunUntilIdle() and is even more likely
274   // to spin forever (any RepeatingTimer will cause this).
275   void FastForwardUntilNoTasksRemain();
276 
277   // Only valid for instances using TimeSource::MOCK_TIME. Advances virtual time
278   // by |delta|. Unlike FastForwardBy, this does not run tasks. Prefer
279   // FastForwardBy() when possible but this can be useful when testing blocked
280   // pending tasks where being idle (required to fast-forward) is not possible.
281   //
282   // Delayed tasks that are ripe as a result of this will be scheduled.
283   // RunUntilIdle() can be used after this call to ensure those tasks have run.
284   // Note: AdvanceClock(delta) + RunUntilIdle() is slightly different from
285   // FastForwardBy(delta) in that time passes instantly before running any task
286   // (whereas FastForwardBy() will advance the clock in the smallest increments
287   // possible at a time). Hence FastForwardBy() is more realistic but
288   // AdvanceClock() can be useful when testing edge case scenarios that
289   // specifically handle more time than expected to have passed.
290   void AdvanceClock(TimeDelta delta);
291 
292   // Similar to `AdvanceClock` but doesn't advance `base::LiveTicks`, behaving
293   // as if the system was suspended for `delta` time and immediately woken up.
294   void SuspendedAdvanceClock(TimeDelta delta);
295 
UsesMockTime()296   bool UsesMockTime() const { return !!mock_clock_; }
297 
298   // Only valid for instances using TimeSource::MOCK_TIME. Returns a
299   // TickClock whose time is updated by FastForward(By|UntilNoTasksRemain).
300   const TickClock* GetMockTickClock() const;
301 
302   // Only valid for instances using TimeSource::MOCK_TIME. Returns a
303   // Clock whose time is updated by FastForward(By|UntilNoTasksRemain). The
304   // initial value is implementation defined and should be queried by tests that
305   // depend on it.
306   // TickClock should be used instead of Clock to measure elapsed time in a
307   // process. See time.h.
308   const Clock* GetMockClock() const;
309 
310   // Only valid for instances using TimeSource::MOCK_TIME. Returns the current
311   // virtual tick time (based on a realistic Now(), sampled when this
312   // TaskEnvironment was created, and manually advanced from that point on).
313   // This is always equivalent to base::TimeTicks::Now() under
314   // TimeSource::MOCK_TIME.
315   base::TimeTicks NowTicks() const;
316 
317   // Only valid for instances using TimeSource::MOCK_TIME. Returns the current
318   // virtual live time (based on a realistic Now(), sampled when this
319   // TaskEnvironment was created, and manually advanced from that point on).
320   // This is always equivalent to base::LiveTicks::Now() under
321   // TimeSource::MOCK_TIME.
322   base::LiveTicks NowLiveTicks() const;
323 
324   // Only valid for instances using TimeSource::MOCK_TIME. Returns the number of
325   // pending tasks (delayed and non-delayed) of the main thread's TaskRunner.
326   // When debugging, you can use DescribeCurrentTasks() to see what those are.
327   size_t GetPendingMainThreadTaskCount() const;
328 
329   // Only valid for instances using TimeSource::MOCK_TIME.
330   // Returns the delay until the next pending task of the main thread's
331   // TaskRunner if there is one, otherwise it returns TimeDelta::Max().
332   TimeDelta NextMainThreadPendingTaskDelay() const;
333 
334   // Only valid for instances using TimeSource::MOCK_TIME.
335   // Returns true iff the next task is delayed. Returns false if the next task
336   // is immediate or if there is no next task.
337   bool NextTaskIsDelayed() const;
338 
339   // For debugging purposes: Dumps information about pending tasks on the main
340   // thread, and currently running tasks on the thread pool.
341   void DescribeCurrentTasks() const;
342 
343   // Detach ThreadCheckers (will rebind on next usage), useful for the odd test
344   // suite which doesn't run on the main thread but still has exclusive access
345   // to driving this TaskEnvironment (e.g. WaylandClientTestSuiteServer).
346   void DetachFromThread();
347 
348   class TestTaskTracker;
349   // Callers outside of TaskEnvironment may not use the returned pointer. They
350   // should just use base::ThreadPoolInstance::Get().
351   static TestTaskTracker* CreateThreadPool();
352 
353   class DestructionObserver : public CheckedObserver {
354    public:
355     DestructionObserver() = default;
356     ~DestructionObserver() override = default;
357 
358     DestructionObserver(const DestructionObserver&) = delete;
359     DestructionObserver& operator=(const DestructionObserver&) = delete;
360 
361     virtual void WillDestroyCurrentTaskEnvironment() = 0;
362   };
363 
364   // Adds/removes a DestructionObserver to any TaskEnvironment. Observers are
365   // notified when any TaskEnvironment goes out of scope (other than with a move
366   // operation). Must be called on the main thread.
367   static void AddDestructionObserver(DestructionObserver* observer);
368   static void RemoveDestructionObserver(DestructionObserver* observer);
369 
370   // Instantiating a ParallelExecutionFence waits for all currently running
371   // ThreadPool tasks before the constructor returns and from then on prevents
372   // additional tasks from running during its lifetime.
373   //
374   // Must be instantiated from the test main thread.
375   class ParallelExecutionFence {
376    public:
377     // Instantiates a ParallelExecutionFence, crashes with an optional
378     // |error_message| if not invoked from test main thread.
379     explicit ParallelExecutionFence(const char* error_message = "");
380     ~ParallelExecutionFence();
381 
382     ParallelExecutionFence(const ParallelExecutionFence&) = delete;
383     ParallelExecutionFence& operator=(const ParallelExecutionFence& other) =
384         delete;
385 
386    private:
387     bool previously_allowed_to_run_ = false;
388   };
389 
390   // The number of foreground workers in the ThreadPool managed by a
391   // TaskEnvironment instance. This can be used to determine the maximum
392   // parallelism in tests that require each parallel task it spawns to be
393   // running at once. Having multiple threads prevents deadlocks should some
394   // blocking APIs not use ScopedBlockingCall. It also allows enough concurrency
395   // to allow TSAN to spot data races.
396   static constexpr int kNumForegroundThreadPoolThreads = 4;
397 
398  protected:
399   template <typename... TaskEnvironmentTraits>
400     requires trait_helpers::AreValidTraits<ValidTraits,
401                                            TaskEnvironmentTraits...>
CreateTaskEnvironmentWithPriorities(sequence_manager::SequenceManager::PrioritySettings priority_settings,TaskEnvironmentTraits...traits)402   NOINLINE static TaskEnvironment CreateTaskEnvironmentWithPriorities(
403       sequence_manager::SequenceManager::PrioritySettings priority_settings,
404       TaskEnvironmentTraits... traits) {
405     return TaskEnvironment(std::move(priority_settings), traits...);
406   }
407 
408   // Constructor accepts zero or more traits which customize the testing
409   // environment.
410   template <typename... TaskEnvironmentTraits>
411     requires trait_helpers::AreValidTraits<ValidTraits,
412                                            TaskEnvironmentTraits...>
TaskEnvironment(sequence_manager::SequenceManager::PrioritySettings priority_settings,TaskEnvironmentTraits...traits)413   NOINLINE explicit TaskEnvironment(
414       sequence_manager::SequenceManager::PrioritySettings priority_settings,
415       TaskEnvironmentTraits... traits)
416       : TaskEnvironment(
417             std::move(priority_settings),
418             trait_helpers::GetEnum<TimeSource, TimeSource::DEFAULT>(traits...),
419             trait_helpers::GetEnum<MainThreadType, MainThreadType::DEFAULT>(
420                 traits...),
421             trait_helpers::GetEnum<ThreadPoolExecutionMode,
422                                    ThreadPoolExecutionMode::DEFAULT>(traits...),
423             trait_helpers::GetEnum<ThreadingMode, ThreadingMode::DEFAULT>(
424                 traits...),
425             trait_helpers::GetEnum<ThreadPoolCOMEnvironment,
426                                    ThreadPoolCOMEnvironment::DEFAULT>(
427                 traits...),
428             trait_helpers::HasTrait<SubclassCreatesDefaultTaskRunner,
429                                     TaskEnvironmentTraits...>(),
430             trait_helpers::NotATraitTag()) {}
431 
432   TaskEnvironment(TaskEnvironment&& other);
433 
main_thread_type()434   constexpr MainThreadType main_thread_type() const {
435     return main_thread_type_;
436   }
437 
thread_pool_execution_mode()438   constexpr ThreadPoolExecutionMode thread_pool_execution_mode() const {
439     return thread_pool_execution_mode_;
440   }
441 
442   // Returns the MockTimeDomain driving this TaskEnvironment if this instance is
443   // using TimeSource::MOCK_TIME, nullptr otherwise.
444   sequence_manager::TimeDomain* GetMockTimeDomain() const;
445 
446   sequence_manager::SequenceManager* sequence_manager() const;
447 
448   void DeferredInitFromSubclass(
449       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
450 
451   // Derived classes may need to control when the task environment goes away
452   // (e.g. ~FooTaskEnvironment() may want to effectively trigger
453   // ~TaskEnvironment() before its members are destroyed).
454   void DestroyTaskEnvironment();
455 
456  private:
457   class MockTimeDomain;
458 
459   void InitializeThreadPool();
460   void ShutdownAndJoinThreadPool();
461   void DestroyThreadPool();
462 
463   void CompleteInitialization();
464 
465   void FastForwardByInternal(TimeDelta delta, bool advance_live_ticks);
466 
467   // The template constructor has to be in the header but it delegates to this
468   // constructor to initialize all other members out-of-line.
469   TaskEnvironment(
470       sequence_manager::SequenceManager::PrioritySettings priority_settings,
471       TimeSource time_source,
472       MainThreadType main_thread_type,
473       ThreadPoolExecutionMode thread_pool_execution_mode,
474       ThreadingMode threading_mode,
475       ThreadPoolCOMEnvironment thread_pool_com_environment,
476       bool subclass_creates_default_taskrunner,
477       trait_helpers::NotATraitTag tag);
478 
479   const MainThreadType main_thread_type_;
480   const ThreadPoolExecutionMode thread_pool_execution_mode_;
481   const ThreadingMode threading_mode_;
482   const ThreadPoolCOMEnvironment thread_pool_com_environment_;
483   const bool subclass_creates_default_taskrunner_;
484 
485   std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
486 
487   // Manages the clock under TimeSource::MOCK_TIME modes. Null in
488   // TimeSource::SYSTEM_TIME mode.
489   std::unique_ptr<MockTimeDomain> mock_time_domain_;
490 
491   // Overrides Time/TimeTicks::Now() under TimeSource::MOCK_TIME mode.
492   // Null in other modes.
493   std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
494 
495   sequence_manager::TaskQueue::Handle task_queue_;
496   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
497 
498   // Only set for instances using TimeSource::MOCK_TIME.
499   std::unique_ptr<Clock> mock_clock_;
500 
501 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
502   // Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
503   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
504 #endif
505 
506   // Owned by the ThreadPoolInstance.
507   raw_ptr<TestTaskTracker, DanglingUntriaged> task_tracker_ = nullptr;
508 
509   // Ensures destruction of lazy TaskRunners when this is destroyed.
510   std::unique_ptr<base::internal::ScopedLazyTaskRunnerListForTesting>
511       scoped_lazy_task_runner_list_for_testing_;
512 
513   // Sets RunLoop::Run() to LOG(FATAL) if not Quit() in a timely manner.
514   std::unique_ptr<ScopedRunLoopTimeout> run_loop_timeout_;
515 
516   std::unique_ptr<bool> owns_instance_ = std::make_unique<bool>(true);
517 
518   std::unique_ptr<RunLoop> run_until_quit_loop_;
519 
520   // Used to verify thread-affinity of operations that must occur on the main
521   // thread. This is the case for anything that modifies or drives the
522   // |sequence_manager_|.
523   THREAD_CHECKER(main_thread_checker_);
524 };
525 
526 // SingleThreadTaskEnvironment takes the same traits as TaskEnvironment and is
527 // used the exact same way. It's a short-form for
528 //   TaskEnvironment{TaskEnvironment::ThreadingMode::MAIN_THREAD_ONLY, ...};
529 class SingleThreadTaskEnvironment : public TaskEnvironment {
530  public:
531   template <class... ArgTypes>
SingleThreadTaskEnvironment(ArgTypes...args)532   SingleThreadTaskEnvironment(ArgTypes... args)
533       : TaskEnvironment(ThreadingMode::MAIN_THREAD_ONLY, args...) {}
534 };
535 
536 }  // namespace test
537 }  // namespace base
538 
539 #endif  // BASE_TEST_TASK_ENVIRONMENT_H_
540