1 // Copyright 2017 The Chromium Authors. All rights reserved.
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_SCOPED_TASK_ENVIRONMENT_H_
6 #define BASE_TEST_SCOPED_TASK_ENVIRONMENT_H_
7 
8 #include "base/macros.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/task_scheduler/lazy_task_runner.h"
12 #include "build/build_config.h"
13 
14 namespace base {
15 
16 namespace internal {
17 class ScopedSetSequenceLocalStorageMapForCurrentThread;
18 class SequenceLocalStorageMap;
19 }  // namespace internal
20 
21 class FileDescriptorWatcher;
22 class MessageLoop;
23 class TaskScheduler;
24 class TestMockTimeTaskRunner;
25 class TickClock;
26 
27 namespace test {
28 
29 // ScopedTaskEnvironment allows usage of these APIs within its scope:
30 // - (Thread|Sequenced)TaskRunnerHandle, on the thread where it lives
31 // - base/task_scheduler/post_task.h, on any thread
32 //
33 // Tests that need either of these APIs should instantiate a
34 // ScopedTaskEnvironment.
35 //
36 // Tasks posted to the (Thread|Sequenced)TaskRunnerHandle run synchronously when
37 // RunLoop::Run(UntilIdle) or ScopedTaskEnvironment::RunUntilIdle is called on
38 // the thread where the ScopedTaskEnvironment lives.
39 //
40 // Tasks posted through base/task_scheduler/post_task.h run on dedicated
41 // threads. If ExecutionMode is QUEUED, they run when RunUntilIdle() or
42 // ~ScopedTaskEnvironment is called. If ExecutionMode is ASYNC, they run
43 // as they are posted.
44 //
45 // All methods of ScopedTaskEnvironment must be called from the same thread.
46 //
47 // Usage:
48 //
49 //   class MyTestFixture : public testing::Test {
50 //    public:
51 //     (...)
52 //
53 //    protected:
54 //     // Must be the first member (or at least before any member that cares
55 //     // about tasks) to be initialized first and destroyed last. protected
56 //     // instead of private visibility will allow controlling the task
57 //     // environment (e.g. clock) once such features are added (see design doc
58 //     // below for details), until then it at least doesn't hurt :).
59 //     base::test::ScopedTaskEnvironment scoped_task_environment_;
60 //
61 //     // Other members go here (or further below in private section.)
62 //   };
63 //
64 // Design and future improvements documented in
65 // https://docs.google.com/document/d/1QabRo8c7D9LsYY3cEcaPQbOCLo8Tu-6VLykYXyl3Pkk/edit
66 class ScopedTaskEnvironment {
67  public:
68   enum class MainThreadType {
69     // The main thread doesn't pump system messages.
70     DEFAULT,
71     // The main thread doesn't pump system messages and uses a mock clock for
72     // delayed tasks (controllable via FastForward*() methods).
73     // TODO(gab): Make this the default |main_thread_type|.
74     // TODO(gab): Also mock the TaskScheduler's clock simultaneously (this
75     // currently only mocks the main thread's clock).
76     MOCK_TIME,
77     // The main thread pumps UI messages.
78     UI,
79     // The main thread pumps asynchronous IO messages and supports the
80     // FileDescriptorWatcher API on POSIX.
81     IO,
82   };
83 
84   enum class ExecutionMode {
85     // Tasks are queued and only executed when RunUntilIdle() is explicitly
86     // called.
87     QUEUED,
88     // Tasks run as they are posted. RunUntilIdle() can still be used to block
89     // until done.
90     ASYNC,
91   };
92 
93   ScopedTaskEnvironment(
94       MainThreadType main_thread_type = MainThreadType::DEFAULT,
95       ExecutionMode execution_control_mode = ExecutionMode::ASYNC);
96 
97   // Waits until no undelayed TaskScheduler tasks remain. Then, unregisters the
98   // TaskScheduler and the (Thread|Sequenced)TaskRunnerHandle.
99   ~ScopedTaskEnvironment();
100 
101   // Returns a TaskRunner that schedules tasks on the main thread.
102   scoped_refptr<base::SingleThreadTaskRunner> GetMainThreadTaskRunner();
103 
104   // Returns whether the main thread's TaskRunner has pending tasks.
105   bool MainThreadHasPendingTask() const;
106 
107   // Runs tasks until both the (Thread|Sequenced)TaskRunnerHandle and the
108   // TaskScheduler's non-delayed queues are empty.
109   void RunUntilIdle();
110 
111   // Only valid for instances with a MOCK_TIME MainThreadType. Fast-forwards
112   // virtual time by |delta|, causing all tasks on the main thread with a
113   // remaining delay less than or equal to |delta| to be executed before this
114   // returns. |delta| must be non-negative.
115   // TODO(gab): Make this apply to TaskScheduler delayed tasks as well
116   // (currently only main thread time is mocked).
117   void FastForwardBy(TimeDelta delta);
118 
119   // Only valid for instances with a MOCK_TIME MainThreadType.
120   // Short for FastForwardBy(TimeDelta::Max()).
121   void FastForwardUntilNoTasksRemain();
122 
123   // Only valid for instances with a MOCK_TIME MainThreadType.  Returns a
124   // TickClock whose time is updated by FastForward(By|UntilNoTasksRemain).
125   const TickClock* GetMockTickClock();
126   std::unique_ptr<TickClock> DeprecatedGetMockTickClock();
127 
128   // Only valid for instances with a MOCK_TIME MainThreadType.
129   // Returns the number of pending tasks of the main thread's TaskRunner.
130   size_t GetPendingMainThreadTaskCount() const;
131 
132   // Only valid for instances with a MOCK_TIME MainThreadType.
133   // Returns the delay until the next delayed pending task of the main thread's
134   // TaskRunner.
135   TimeDelta NextMainThreadPendingTaskDelay() const;
136 
137  private:
138   class TestTaskTracker;
139 
140   const ExecutionMode execution_control_mode_;
141 
142   // Exactly one of these will be non-null to provide the task environment on
143   // the main thread. Users of this class should NOT rely on the presence of a
144   // MessageLoop beyond (Thread|Sequenced)TaskRunnerHandle and RunLoop as
145   // the backing implementation of each MainThreadType may change over time.
146   const std::unique_ptr<MessageLoop> message_loop_;
147   const scoped_refptr<TestMockTimeTaskRunner> mock_time_task_runner_;
148 
149   // Non-null in MOCK_TIME, where an explicit SequenceLocalStorageMap needs to
150   // be provided. TODO(gab): This can be removed once mock time support is added
151   // to MessageLoop directly.
152   const std::unique_ptr<internal::SequenceLocalStorageMap> slsm_for_mock_time_;
153   const std::unique_ptr<
154       internal::ScopedSetSequenceLocalStorageMapForCurrentThread>
155       slsm_registration_for_mock_time_;
156 
157 #if defined(OS_POSIX)
158   // Enables the FileDescriptorWatcher API iff running a MainThreadType::IO.
159   const std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher_;
160 #endif
161 
162   const TaskScheduler* task_scheduler_ = nullptr;
163 
164   // Owned by |task_scheduler_|.
165   TestTaskTracker* const task_tracker_;
166 
167   // Ensures destruction of lazy TaskRunners when this is destroyed.
168   internal::ScopedLazyTaskRunnerListForTesting
169       scoped_lazy_task_runner_list_for_testing_;
170 
171   DISALLOW_COPY_AND_ASSIGN(ScopedTaskEnvironment);
172 };
173 
174 }  // namespace test
175 }  // namespace base
176 
177 #endif  // BASE_TEST_SCOPED_ASYNC_TASK_SCHEDULER_H_
178