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_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_ 10#define BASE_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 26namespace base { 27 28namespace internal { 29 30struct 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. 38class 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 103void 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 119template <typename TaskRunnerTestDelegate> 120class 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 129TYPED_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. 135TYPED_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. 157TYPED_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. 180TYPED_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. 205TYPED_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. 231TYPED_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. 258TYPED_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. 280TYPED_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. 301TYPED_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 329REGISTER_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_TASK_RUNNER_TEST_TEMPLATE_H_ 342