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