sequenced_task_runner_test_template.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Copyright (c) 2012 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. // SequencedTaskRunnerTest defines tests that implementations of
  5. // SequencedTaskRunner should pass in order to be conformant.
  6. // See task_runner_test_template.h for a description of how to use the
  7. // constructs in this file; these work the same.
  8. #ifndef BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
  9. #define BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
  10. #include <cstddef>
  11. #include <iosfwd>
  12. #include <vector>
  13. #include "base/bind.h"
  14. #include "base/callback.h"
  15. #include "base/memory/ref_counted.h"
  16. #include "base/synchronization/condition_variable.h"
  17. #include "base/synchronization/lock.h"
  18. #include "base/task/sequenced_task_runner.h"
  19. #include "base/threading/platform_thread.h"
  20. #include "base/time/time.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. namespace base {
  23. namespace internal {
  24. struct TaskEvent {
  25. enum Type { POST, START, END };
  26. TaskEvent(int i, Type type);
  27. int i;
  28. Type type;
  29. };
  30. // Utility class used in the tests below.
  31. class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
  32. public:
  33. SequencedTaskTracker();
  34. SequencedTaskTracker(const SequencedTaskTracker&) = delete;
  35. SequencedTaskTracker& operator=(const SequencedTaskTracker&) = delete;
  36. // Posts the non-nestable task |task|, and records its post event.
  37. void PostWrappedNonNestableTask(SequencedTaskRunner* task_runner,
  38. OnceClosure task);
  39. // Posts the nestable task |task|, and records its post event.
  40. void PostWrappedNestableTask(SequencedTaskRunner* task_runner,
  41. OnceClosure task);
  42. // Posts the delayed non-nestable task |task|, and records its post event.
  43. void PostWrappedDelayedNonNestableTask(SequencedTaskRunner* task_runner,
  44. OnceClosure task,
  45. TimeDelta delay);
  46. // Posts |task_count| non-nestable tasks.
  47. void PostNonNestableTasks(SequencedTaskRunner* task_runner, int task_count);
  48. const std::vector<TaskEvent>& GetTaskEvents() const;
  49. // Returns after the tracker observes a total of |count| task completions.
  50. void WaitForCompletedTasks(int count);
  51. private:
  52. friend class RefCountedThreadSafe<SequencedTaskTracker>;
  53. ~SequencedTaskTracker();
  54. // A task which runs |task|, recording the start and end events.
  55. void RunTask(OnceClosure task, int task_i);
  56. // Records a post event for task |i|. The owner is expected to be holding
  57. // |lock_| (unlike |TaskStarted| and |TaskEnded|).
  58. void TaskPosted(int i);
  59. // Records a start event for task |i|.
  60. void TaskStarted(int i);
  61. // Records a end event for task |i|.
  62. void TaskEnded(int i);
  63. // Protects events_, next_post_i_, task_end_count_ and task_end_cv_.
  64. Lock lock_;
  65. // The events as they occurred for each task (protected by lock_).
  66. std::vector<TaskEvent> events_;
  67. // The ordinal to be used for the next task-posting task (protected by
  68. // lock_).
  69. int next_post_i_;
  70. // The number of task end events we've received.
  71. int task_end_count_;
  72. ConditionVariable task_end_cv_;
  73. };
  74. void PrintTo(const TaskEvent& event, std::ostream* os);
  75. // Checks the non-nestable task invariants for all tasks in |events|.
  76. //
  77. // The invariants are:
  78. // 1) Events started and ended in the same order that they were posted.
  79. // 2) Events for an individual tasks occur in the order {POST, START, END},
  80. // and there is only one instance of each event type for a task.
  81. // 3) The only events between a task's START and END events are the POSTs of
  82. // other tasks. I.e. tasks were run sequentially, not interleaved.
  83. ::testing::AssertionResult CheckNonNestableInvariants(
  84. const std::vector<TaskEvent>& events,
  85. int task_count);
  86. } // namespace internal
  87. template <typename TaskRunnerTestDelegate>
  88. class SequencedTaskRunnerTest : public testing::Test {
  89. protected:
  90. SequencedTaskRunnerTest()
  91. : task_tracker_(new internal::SequencedTaskTracker()) {}
  92. const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
  93. TaskRunnerTestDelegate delegate_;
  94. };
  95. TYPED_TEST_SUITE_P(SequencedTaskRunnerTest);
  96. // This test posts N non-nestable tasks in sequence, and expects them to run
  97. // in FIFO order, with no part of any two tasks' execution
  98. // overlapping. I.e. that each task starts only after the previously-posted
  99. // one has finished.
  100. TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
  101. const int kTaskCount = 1000;
  102. this->delegate_.StartTaskRunner();
  103. const scoped_refptr<SequencedTaskRunner> task_runner =
  104. this->delegate_.GetTaskRunner();
  105. this->task_tracker_->PostWrappedNonNestableTask(
  106. task_runner.get(), BindOnce(&PlatformThread::Sleep, Seconds(1)));
  107. for (int i = 1; i < kTaskCount; ++i) {
  108. this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
  109. OnceClosure());
  110. }
  111. this->delegate_.StopTaskRunner();
  112. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  113. kTaskCount));
  114. }
  115. // This test posts N nestable tasks in sequence. It has the same expectations
  116. // as SequentialNonNestable because even though the tasks are nestable, they
  117. // will not be run nestedly in this case.
  118. TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
  119. const int kTaskCount = 1000;
  120. this->delegate_.StartTaskRunner();
  121. const scoped_refptr<SequencedTaskRunner> task_runner =
  122. this->delegate_.GetTaskRunner();
  123. this->task_tracker_->PostWrappedNestableTask(
  124. task_runner.get(), BindOnce(&PlatformThread::Sleep, Seconds(1)));
  125. for (int i = 1; i < kTaskCount; ++i) {
  126. this->task_tracker_->PostWrappedNestableTask(task_runner.get(),
  127. OnceClosure());
  128. }
  129. this->delegate_.StopTaskRunner();
  130. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  131. kTaskCount));
  132. }
  133. // This test posts non-nestable tasks in order of increasing delay, and checks
  134. // that that the tasks are run in FIFO order and that there is no execution
  135. // overlap whatsoever between any two tasks.
  136. TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
  137. const int kTaskCount = 20;
  138. const int kDelayIncrementMs = 50;
  139. this->delegate_.StartTaskRunner();
  140. const scoped_refptr<SequencedTaskRunner> task_runner =
  141. this->delegate_.GetTaskRunner();
  142. for (int i = 0; i < kTaskCount; ++i) {
  143. this->task_tracker_->PostWrappedDelayedNonNestableTask(
  144. task_runner.get(), OnceClosure(), Milliseconds(kDelayIncrementMs * i));
  145. }
  146. this->task_tracker_->WaitForCompletedTasks(kTaskCount);
  147. this->delegate_.StopTaskRunner();
  148. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  149. kTaskCount));
  150. }
  151. // This test posts a fast, non-nestable task from within each of a number of
  152. // slow, non-nestable tasks and checks that they all run in the sequence they
  153. // were posted in and that there is no execution overlap whatsoever.
  154. TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
  155. const int kParentCount = 10;
  156. const int kChildrenPerParent = 10;
  157. this->delegate_.StartTaskRunner();
  158. const scoped_refptr<SequencedTaskRunner> task_runner =
  159. this->delegate_.GetTaskRunner();
  160. for (int i = 0; i < kParentCount; ++i) {
  161. auto task = BindOnce(&internal::SequencedTaskTracker::PostNonNestableTasks,
  162. this->task_tracker_, RetainedRef(task_runner),
  163. kChildrenPerParent);
  164. this->task_tracker_->PostWrappedNonNestableTask(task_runner.get(),
  165. std::move(task));
  166. }
  167. this->delegate_.StopTaskRunner();
  168. EXPECT_TRUE(CheckNonNestableInvariants(
  169. this->task_tracker_->GetTaskEvents(),
  170. kParentCount * (kChildrenPerParent + 1)));
  171. }
  172. // This test posts two tasks with the same delay, and checks that the tasks are
  173. // run in the order in which they were posted.
  174. //
  175. // NOTE: This is actually an approximate test since the API only takes a
  176. // "delay" parameter, so we are not exactly simulating two tasks that get
  177. // posted at the exact same time. It would be nice if the API allowed us to
  178. // specify the desired run time.
  179. TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
  180. const int kTaskCount = 2;
  181. const TimeDelta kDelay = Milliseconds(100);
  182. this->delegate_.StartTaskRunner();
  183. const scoped_refptr<SequencedTaskRunner> task_runner =
  184. this->delegate_.GetTaskRunner();
  185. this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
  186. OnceClosure(), kDelay);
  187. this->task_tracker_->PostWrappedDelayedNonNestableTask(task_runner.get(),
  188. OnceClosure(), kDelay);
  189. this->task_tracker_->WaitForCompletedTasks(kTaskCount);
  190. this->delegate_.StopTaskRunner();
  191. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  192. kTaskCount));
  193. }
  194. // This test posts a normal task and a delayed task, and checks that the
  195. // delayed task runs after the normal task even if the normal task takes
  196. // a long time to run.
  197. TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
  198. const int kTaskCount = 2;
  199. this->delegate_.StartTaskRunner();
  200. const scoped_refptr<SequencedTaskRunner> task_runner =
  201. this->delegate_.GetTaskRunner();
  202. this->task_tracker_->PostWrappedNonNestableTask(
  203. task_runner.get(),
  204. base::BindOnce(&PlatformThread::Sleep, Milliseconds(50)));
  205. this->task_tracker_->PostWrappedDelayedNonNestableTask(
  206. task_runner.get(), OnceClosure(), Milliseconds(10));
  207. this->task_tracker_->WaitForCompletedTasks(kTaskCount);
  208. this->delegate_.StopTaskRunner();
  209. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  210. kTaskCount));
  211. }
  212. // Test that a pile of normal tasks and a delayed task run in the
  213. // time-to-run order.
  214. TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
  215. const int kTaskCount = 11;
  216. this->delegate_.StartTaskRunner();
  217. const scoped_refptr<SequencedTaskRunner> task_runner =
  218. this->delegate_.GetTaskRunner();
  219. for (int i = 0; i < kTaskCount - 1; i++) {
  220. this->task_tracker_->PostWrappedNonNestableTask(
  221. task_runner.get(),
  222. base::BindOnce(&PlatformThread::Sleep, Milliseconds(50)));
  223. }
  224. this->task_tracker_->PostWrappedDelayedNonNestableTask(
  225. task_runner.get(), OnceClosure(), Milliseconds(10));
  226. this->task_tracker_->WaitForCompletedTasks(kTaskCount);
  227. this->delegate_.StopTaskRunner();
  228. EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
  229. kTaskCount));
  230. }
  231. // TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
  232. // some tasked nestedly (which should be implemented in the test
  233. // delegate). Also add, to the test delegate, a predicate which checks
  234. // whether the implementation supports nested tasks.
  235. //
  236. // The SequencedTaskRunnerTest test case verifies behaviour that is expected
  237. // from a sequenced task runner in order to be conformant.
  238. REGISTER_TYPED_TEST_SUITE_P(SequencedTaskRunnerTest,
  239. SequentialNonNestable,
  240. SequentialNestable,
  241. SequentialDelayedNonNestable,
  242. NonNestablePostFromNonNestableTask,
  243. DelayedTasksSameDelay,
  244. DelayedTaskAfterLongTask,
  245. DelayedTaskAfterManyLongTasks);
  246. } // namespace base
  247. #endif // BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_