sequenced_task_runner_test_template.h 12 KB

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