test_mock_time_task_runner.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. // Copyright 2015 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. #include "base/test/test_mock_time_task_runner.h"
  5. #include <utility>
  6. #include "base/check_op.h"
  7. #include "base/containers/circular_deque.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/memory/ref_counted.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "third_party/abseil-cpp/absl/types/optional.h"
  13. namespace base {
  14. // A SingleThreadTaskRunner which forwards everything to its |target_|. This
  15. // serves two purposes:
  16. // 1) If a ThreadTaskRunnerHandle owned by TestMockTimeTaskRunner were to be
  17. // set to point to that TestMockTimeTaskRunner, a reference cycle would
  18. // result. As |target_| here is a non-refcounting raw pointer, the cycle is
  19. // broken.
  20. // 2) Since SingleThreadTaskRunner is ref-counted, it's quite easy for it to
  21. // accidentally get captured between tests in a singleton somewhere.
  22. // Indirecting via NonOwningProxyTaskRunner permits TestMockTimeTaskRunner
  23. // to be cleaned up (removing the RunLoop::Delegate in the kBoundToThread
  24. // mode), and to also cleanly flag any actual attempts to use the leaked
  25. // task runner.
  26. class TestMockTimeTaskRunner::NonOwningProxyTaskRunner
  27. : public SingleThreadTaskRunner {
  28. public:
  29. explicit NonOwningProxyTaskRunner(SingleThreadTaskRunner* target)
  30. : target_(target) {
  31. DCHECK(target_);
  32. }
  33. NonOwningProxyTaskRunner(const NonOwningProxyTaskRunner&) = delete;
  34. NonOwningProxyTaskRunner& operator=(const NonOwningProxyTaskRunner&) = delete;
  35. // Detaches this NonOwningProxyTaskRunner instance from its |target_|. It is
  36. // invalid to post tasks after this point but RunsTasksInCurrentSequence()
  37. // will still pass on the original thread for convenience with legacy code.
  38. void Detach() {
  39. AutoLock scoped_lock(lock_);
  40. target_ = nullptr;
  41. }
  42. // SingleThreadTaskRunner:
  43. bool RunsTasksInCurrentSequence() const override {
  44. AutoLock scoped_lock(lock_);
  45. if (target_)
  46. return target_->RunsTasksInCurrentSequence();
  47. return thread_checker_.CalledOnValidThread();
  48. }
  49. bool PostDelayedTask(const Location& from_here,
  50. OnceClosure task,
  51. TimeDelta delay) override {
  52. AutoLock scoped_lock(lock_);
  53. if (target_)
  54. return target_->PostDelayedTask(from_here, std::move(task), delay);
  55. // The associated TestMockTimeTaskRunner is dead, so fail this PostTask.
  56. return false;
  57. }
  58. bool PostNonNestableDelayedTask(const Location& from_here,
  59. OnceClosure task,
  60. TimeDelta delay) override {
  61. AutoLock scoped_lock(lock_);
  62. if (target_) {
  63. return target_->PostNonNestableDelayedTask(from_here, std::move(task),
  64. delay);
  65. }
  66. // The associated TestMockTimeTaskRunner is dead, so fail this PostTask.
  67. return false;
  68. }
  69. private:
  70. friend class RefCountedThreadSafe<NonOwningProxyTaskRunner>;
  71. ~NonOwningProxyTaskRunner() override = default;
  72. mutable Lock lock_;
  73. raw_ptr<SingleThreadTaskRunner> target_; // guarded by lock_
  74. // Used to implement RunsTasksInCurrentSequence, without relying on |target_|.
  75. ThreadCheckerImpl thread_checker_;
  76. };
  77. // TestMockTimeTaskRunner::TestOrderedPendingTask -----------------------------
  78. // Subclass of TestPendingTask which has a strictly monotonically increasing ID
  79. // for every task, so that tasks posted with the same 'time to run' can be run
  80. // in the order of being posted.
  81. struct TestMockTimeTaskRunner::TestOrderedPendingTask
  82. : public base::TestPendingTask {
  83. TestOrderedPendingTask();
  84. TestOrderedPendingTask(const Location& location,
  85. OnceClosure task,
  86. TimeTicks post_time,
  87. TimeDelta delay,
  88. size_t ordinal,
  89. TestNestability nestability);
  90. TestOrderedPendingTask(const TestOrderedPendingTask&) = delete;
  91. TestOrderedPendingTask& operator=(const TestOrderedPendingTask&) = delete;
  92. TestOrderedPendingTask(TestOrderedPendingTask&&);
  93. ~TestOrderedPendingTask();
  94. TestOrderedPendingTask& operator=(TestOrderedPendingTask&&);
  95. size_t ordinal;
  96. };
  97. TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask()
  98. : ordinal(0) {
  99. }
  100. TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
  101. TestOrderedPendingTask&&) = default;
  102. TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
  103. const Location& location,
  104. OnceClosure task,
  105. TimeTicks post_time,
  106. TimeDelta delay,
  107. size_t ordinal,
  108. TestNestability nestability)
  109. : base::TestPendingTask(location,
  110. std::move(task),
  111. post_time,
  112. delay,
  113. nestability),
  114. ordinal(ordinal) {}
  115. TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() =
  116. default;
  117. TestMockTimeTaskRunner::TestOrderedPendingTask&
  118. TestMockTimeTaskRunner::TestOrderedPendingTask::operator=(
  119. TestOrderedPendingTask&&) = default;
  120. // TestMockTimeTaskRunner -----------------------------------------------------
  121. // TODO(gab): This should also set the SequenceToken for the current thread.
  122. // Ref. TestMockTimeTaskRunner::RunsTasksInCurrentSequence().
  123. TestMockTimeTaskRunner::ScopedContext::ScopedContext(
  124. scoped_refptr<TestMockTimeTaskRunner> scope)
  125. : thread_task_runner_handle_override_(scope) {
  126. scope->RunUntilIdle();
  127. }
  128. TestMockTimeTaskRunner::ScopedContext::~ScopedContext() = default;
  129. bool TestMockTimeTaskRunner::TemporalOrder::operator()(
  130. const TestOrderedPendingTask& first_task,
  131. const TestOrderedPendingTask& second_task) const {
  132. if (first_task.GetTimeToRun() == second_task.GetTimeToRun())
  133. return first_task.ordinal > second_task.ordinal;
  134. return first_task.GetTimeToRun() > second_task.GetTimeToRun();
  135. }
  136. TestMockTimeTaskRunner::TestMockTimeTaskRunner(Type type)
  137. : TestMockTimeTaskRunner(Time::UnixEpoch(), TimeTicks(), type) {}
  138. TestMockTimeTaskRunner::TestMockTimeTaskRunner(Time start_time,
  139. TimeTicks start_ticks,
  140. Type type)
  141. : now_(start_time),
  142. now_ticks_(start_ticks),
  143. tasks_lock_cv_(&tasks_lock_),
  144. proxy_task_runner_(MakeRefCounted<NonOwningProxyTaskRunner>(this)),
  145. mock_clock_(this) {
  146. if (type == Type::kBoundToThread) {
  147. RunLoop::RegisterDelegateForCurrentThread(this);
  148. thread_task_runner_handle_ =
  149. std::make_unique<ThreadTaskRunnerHandle>(proxy_task_runner_);
  150. }
  151. }
  152. TestMockTimeTaskRunner::~TestMockTimeTaskRunner() {
  153. proxy_task_runner_->Detach();
  154. }
  155. void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) {
  156. DCHECK(thread_checker_.CalledOnValidThread());
  157. DCHECK_GE(delta, TimeDelta());
  158. const TimeTicks original_now_ticks = NowTicks();
  159. ProcessTasksNoLaterThan(delta);
  160. ForwardClocksUntilTickTime(original_now_ticks + delta);
  161. }
  162. void TestMockTimeTaskRunner::AdvanceMockTickClock(TimeDelta delta) {
  163. ForwardClocksUntilTickTime(NowTicks() + delta);
  164. }
  165. void TestMockTimeTaskRunner::AdvanceWallClock(TimeDelta delta) {
  166. now_ += delta;
  167. OnAfterTimePassed();
  168. }
  169. void TestMockTimeTaskRunner::RunUntilIdle() {
  170. DCHECK(thread_checker_.CalledOnValidThread());
  171. ProcessTasksNoLaterThan(TimeDelta());
  172. }
  173. void TestMockTimeTaskRunner::ProcessNextNTasks(int n) {
  174. DCHECK(thread_checker_.CalledOnValidThread());
  175. ProcessTasksNoLaterThan(TimeDelta::Max(), n);
  176. }
  177. void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() {
  178. DCHECK(thread_checker_.CalledOnValidThread());
  179. ProcessTasksNoLaterThan(TimeDelta::Max());
  180. }
  181. void TestMockTimeTaskRunner::ClearPendingTasks() {
  182. AutoLock scoped_lock(tasks_lock_);
  183. // This is repeated in case task destruction triggers further tasks.
  184. while (!tasks_.empty()) {
  185. TaskPriorityQueue cleanup_tasks;
  186. tasks_.swap(cleanup_tasks);
  187. // Destroy task objects with |tasks_lock_| released. Task deletion can cause
  188. // calls to NonOwningProxyTaskRunner::RunsTasksInCurrentSequence()
  189. // (e.g. for DCHECKs), which causes |NonOwningProxyTaskRunner::lock_| to be
  190. // grabbed.
  191. //
  192. // On the other hand, calls from NonOwningProxyTaskRunner::PostTask ->
  193. // TestMockTimeTaskRunner::PostTask acquire locks as
  194. // |NonOwningProxyTaskRunner::lock_| followed by |tasks_lock_|, so it's
  195. // desirable to avoid the reverse order, for deadlock freedom.
  196. AutoUnlock scoped_unlock(tasks_lock_);
  197. while (!cleanup_tasks.empty())
  198. cleanup_tasks.pop();
  199. }
  200. }
  201. Time TestMockTimeTaskRunner::Now() const {
  202. AutoLock scoped_lock(tasks_lock_);
  203. return now_;
  204. }
  205. TimeTicks TestMockTimeTaskRunner::NowTicks() const {
  206. AutoLock scoped_lock(tasks_lock_);
  207. return now_ticks_;
  208. }
  209. Clock* TestMockTimeTaskRunner::GetMockClock() const {
  210. DCHECK(thread_checker_.CalledOnValidThread());
  211. return &mock_clock_;
  212. }
  213. const TickClock* TestMockTimeTaskRunner::GetMockTickClock() const {
  214. DCHECK(thread_checker_.CalledOnValidThread());
  215. return &mock_clock_;
  216. }
  217. base::circular_deque<TestPendingTask>
  218. TestMockTimeTaskRunner::TakePendingTasks() {
  219. AutoLock scoped_lock(tasks_lock_);
  220. base::circular_deque<TestPendingTask> tasks;
  221. while (!tasks_.empty()) {
  222. // It's safe to remove const and consume |task| here, since |task| is not
  223. // used for ordering the item.
  224. if (!tasks_.top().task.IsCancelled()) {
  225. tasks.push_back(
  226. std::move(const_cast<TestOrderedPendingTask&>(tasks_.top())));
  227. }
  228. tasks_.pop();
  229. }
  230. return tasks;
  231. }
  232. bool TestMockTimeTaskRunner::HasPendingTask() {
  233. DCHECK(thread_checker_.CalledOnValidThread());
  234. AutoLock scoped_lock(tasks_lock_);
  235. while (!tasks_.empty() && tasks_.top().task.IsCancelled())
  236. tasks_.pop();
  237. return !tasks_.empty();
  238. }
  239. size_t TestMockTimeTaskRunner::GetPendingTaskCount() {
  240. DCHECK(thread_checker_.CalledOnValidThread());
  241. AutoLock scoped_lock(tasks_lock_);
  242. TaskPriorityQueue preserved_tasks;
  243. while (!tasks_.empty()) {
  244. if (!tasks_.top().task.IsCancelled()) {
  245. preserved_tasks.push(
  246. std::move(const_cast<TestOrderedPendingTask&>(tasks_.top())));
  247. }
  248. tasks_.pop();
  249. }
  250. tasks_.swap(preserved_tasks);
  251. return tasks_.size();
  252. }
  253. TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() {
  254. DCHECK(thread_checker_.CalledOnValidThread());
  255. AutoLock scoped_lock(tasks_lock_);
  256. while (!tasks_.empty() && tasks_.top().task.IsCancelled())
  257. tasks_.pop();
  258. return tasks_.empty() ? TimeDelta::Max()
  259. : tasks_.top().GetTimeToRun() - now_ticks_;
  260. }
  261. void TestMockTimeTaskRunner::DetachFromThread() {
  262. thread_checker_.DetachFromThread();
  263. }
  264. // TODO(gab): Combine |thread_checker_| with a SequenceToken to differentiate
  265. // between tasks running in the scope of this TestMockTimeTaskRunner and other
  266. // task runners sharing this thread. http://crbug.com/631186
  267. bool TestMockTimeTaskRunner::RunsTasksInCurrentSequence() const {
  268. return thread_checker_.CalledOnValidThread();
  269. }
  270. bool TestMockTimeTaskRunner::PostDelayedTask(const Location& from_here,
  271. OnceClosure task,
  272. TimeDelta delay) {
  273. AutoLock scoped_lock(tasks_lock_);
  274. tasks_.push(TestOrderedPendingTask(from_here, std::move(task), now_ticks_,
  275. delay, next_task_ordinal_++,
  276. TestPendingTask::NESTABLE));
  277. tasks_lock_cv_.Signal();
  278. return true;
  279. }
  280. bool TestMockTimeTaskRunner::PostDelayedTaskAt(
  281. subtle::PostDelayedTaskPassKey,
  282. const Location& from_here,
  283. OnceClosure task,
  284. TimeTicks delayed_run_time,
  285. subtle::DelayPolicy deadline_policy) {
  286. return PostDelayedTask(
  287. from_here, std::move(task),
  288. delayed_run_time.is_null() ? TimeDelta() : delayed_run_time - now_ticks_);
  289. }
  290. bool TestMockTimeTaskRunner::PostNonNestableDelayedTask(
  291. const Location& from_here,
  292. OnceClosure task,
  293. TimeDelta delay) {
  294. return PostDelayedTask(from_here, std::move(task), delay);
  295. }
  296. void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
  297. // Empty default implementation.
  298. }
  299. void TestMockTimeTaskRunner::OnAfterTimePassed() {
  300. // Empty default implementation.
  301. }
  302. void TestMockTimeTaskRunner::OnAfterTaskRun() {
  303. // Empty default implementation.
  304. }
  305. void TestMockTimeTaskRunner::ProcessTasksNoLaterThan(TimeDelta max_delta,
  306. int limit) {
  307. DCHECK(thread_checker_.CalledOnValidThread());
  308. DCHECK_GE(max_delta, TimeDelta());
  309. // Multiple test task runners can share the same thread for determinism in
  310. // unit tests. Make sure this TestMockTimeTaskRunner's tasks run in its scope.
  311. absl::optional<ThreadTaskRunnerHandleOverrideForTesting> ttrh_override;
  312. if (!ThreadTaskRunnerHandle::IsSet() ||
  313. ThreadTaskRunnerHandle::Get() != proxy_task_runner_.get()) {
  314. ttrh_override.emplace(proxy_task_runner_.get());
  315. }
  316. const TimeTicks original_now_ticks = NowTicks();
  317. for (int i = 0; !quit_run_loop_ && (limit < 0 || i < limit); i++) {
  318. OnBeforeSelectingTask();
  319. TestPendingTask task_info;
  320. if (!DequeueNextTask(original_now_ticks, max_delta, &task_info))
  321. break;
  322. if (task_info.task.IsCancelled())
  323. continue;
  324. // If tasks were posted with a negative delay, task_info.GetTimeToRun() will
  325. // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not
  326. // moving the clock backwards in this case.
  327. ForwardClocksUntilTickTime(task_info.GetTimeToRun());
  328. std::move(task_info.task).Run();
  329. OnAfterTaskRun();
  330. }
  331. }
  332. void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) {
  333. DCHECK(thread_checker_.CalledOnValidThread());
  334. {
  335. AutoLock scoped_lock(tasks_lock_);
  336. if (later_ticks <= now_ticks_)
  337. return;
  338. now_ += later_ticks - now_ticks_;
  339. now_ticks_ = later_ticks;
  340. }
  341. OnAfterTimePassed();
  342. }
  343. bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference,
  344. const TimeDelta& max_delta,
  345. TestPendingTask* next_task) {
  346. DCHECK(thread_checker_.CalledOnValidThread());
  347. AutoLock scoped_lock(tasks_lock_);
  348. if (!tasks_.empty() &&
  349. (tasks_.top().GetTimeToRun() - reference) <= max_delta) {
  350. // It's safe to remove const and consume |task| here, since |task| is not
  351. // used for ordering the item.
  352. *next_task = std::move(const_cast<TestOrderedPendingTask&>(tasks_.top()));
  353. tasks_.pop();
  354. return true;
  355. }
  356. return false;
  357. }
  358. void TestMockTimeTaskRunner::Run(bool application_tasks_allowed,
  359. TimeDelta timeout) {
  360. DCHECK(thread_checker_.CalledOnValidThread());
  361. // Since TestMockTimeTaskRunner doesn't process system messages: there's no
  362. // hope for anything but an application task to call Quit(). If this RunLoop
  363. // can't process application tasks (i.e. disallowed by default in nested
  364. // RunLoops) it's guaranteed to hang...
  365. DCHECK(application_tasks_allowed)
  366. << "This is a nested RunLoop instance and needs to be of "
  367. "Type::kNestableTasksAllowed.";
  368. // This computation relies on saturated arithmetic.
  369. TimeTicks run_until = now_ticks_ + timeout;
  370. while (!quit_run_loop_ && now_ticks_ < run_until) {
  371. RunUntilIdle();
  372. if (quit_run_loop_ || ShouldQuitWhenIdle())
  373. break;
  374. // Peek into |tasks_| to perform one of two things:
  375. // A) If there are no remaining tasks, wait until one is posted and
  376. // restart from the top.
  377. // B) If there is a remaining delayed task. Fast-forward to reach the next
  378. // round of tasks.
  379. TimeDelta auto_fast_forward_by;
  380. {
  381. AutoLock scoped_lock(tasks_lock_);
  382. if (tasks_.empty()) {
  383. while (tasks_.empty())
  384. tasks_lock_cv_.Wait();
  385. continue;
  386. }
  387. auto_fast_forward_by =
  388. std::min(run_until, tasks_.top().GetTimeToRun()) - now_ticks_;
  389. }
  390. FastForwardBy(auto_fast_forward_by);
  391. }
  392. quit_run_loop_ = false;
  393. }
  394. void TestMockTimeTaskRunner::Quit() {
  395. DCHECK(thread_checker_.CalledOnValidThread());
  396. quit_run_loop_ = true;
  397. }
  398. void TestMockTimeTaskRunner::EnsureWorkScheduled() {
  399. // Nothing to do: TestMockTimeTaskRunner::Run() will always process tasks and
  400. // doesn't need an extra kick on nested runs.
  401. }
  402. TimeTicks TestMockTimeTaskRunner::MockClock::NowTicks() const {
  403. return task_runner_->NowTicks();
  404. }
  405. Time TestMockTimeTaskRunner::MockClock::Now() const {
  406. return task_runner_->Now();
  407. }
  408. } // namespace base