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. Here's how you use it to test your |
| 7 // implementation. |
| 8 // |
| 9 // See task_runner_test_template.h for a description of how to use the |
| 10 // constructs in this file; these work the same. |
| 11 |
| 12 #ifndef BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_ |
| 13 #define BASE_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_ |
| 14 #pragma once |
| 15 |
| 16 #include <cstddef> |
| 17 |
| 18 #include <algorithm> |
| 19 #include <vector> |
| 20 |
| 21 #include "base/basictypes.h" |
| 22 #include "base/bind.h" |
| 23 #include "base/memory/ref_counted.h" |
| 24 #include "base/sequenced_task_runner.h" |
| 25 #include "base/synchronization/lock.h" |
| 26 #include "base/tracked_objects.h" |
| 27 #include "testing/gtest/include/gtest/gtest.h" |
| 28 |
| 29 namespace base { |
| 30 |
| 31 namespace internal { |
| 32 |
| 33 // Utility class used in the tests below. |
| 34 class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> { |
| 35 public: |
| 36 SequencedTaskTracker(); |
| 37 |
| 38 int GetNextPostOrdinal(); |
| 39 |
| 40 void TaskPosted(int i); |
| 41 void TaskStarted(int i); |
| 42 void TaskEnded(int i); |
| 43 |
| 44 const std::vector<int>& GetPostOrder() const; |
| 45 const std::vector<int>& GetStartOrder() const; |
| 46 const std::vector<int>& GetEndOrder() const; |
| 47 |
| 48 void FastTask(int i); |
| 49 void SlowTask(int i); |
| 50 |
| 51 // Task which posts a fast, non-nestable task. |
| 52 void PostFastNonNestableFromSlowNonNestable( |
| 53 scoped_refptr<SequencedTaskRunner> task_runner, |
| 54 const int base_status_i, |
| 55 const int child_count); |
| 56 |
| 57 private: |
| 58 friend class RefCountedThreadSafe<SequencedTaskTracker>; |
| 59 |
| 60 ~SequencedTaskTracker(); |
| 61 |
| 62 public: |
| 63 std::vector<int> post_events_; |
| 64 mutable Lock post_lock_; |
| 65 |
| 66 private: |
| 67 std::vector<int> start_events_; |
| 68 mutable Lock start_lock_; |
| 69 |
| 70 std::vector<int> end_events_; |
| 71 mutable Lock end_lock_; |
| 72 |
| 73 int next_post_i_; |
| 74 |
| 75 DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker); |
| 76 }; |
| 77 |
| 78 } // namespace internal |
| 79 |
| 80 template <typename TaskRunnerTestDelegate> |
| 81 class SequencedTaskRunnerTest : public testing::Test { |
| 82 protected: |
| 83 SequencedTaskRunnerTest() |
| 84 : task_tracker_(new internal::SequencedTaskTracker()) {} |
| 85 |
| 86 const scoped_refptr<internal::SequencedTaskTracker> task_tracker_; |
| 87 TaskRunnerTestDelegate delegate_; |
| 88 }; |
| 89 |
| 90 TYPED_TEST_CASE_P(SequencedTaskRunnerTest); |
| 91 |
| 92 // This test posts N non-nestable tasks in sequence, and expects them to run |
| 93 // in FIFO order, with no part of any two tasks' execution overlapping. |
| 94 // |
| 95 // It checks that task0 was done by the time task1 started, and task2 only |
| 96 // started after task1 had executed to completion, etc. |
| 97 // |
| 98 // The first task it starts is a slow one which runs for a second, giving the |
| 99 // subsequent ones plenty of time to run if the implementation fails to |
| 100 // enforce the non-nestable property. |
| 101 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) { |
| 102 const int task_count = 1000; |
| 103 |
| 104 this->delegate_.StartTaskRunner(); |
| 105 scoped_refptr<SequencedTaskRunner> task_runner = |
| 106 this->delegate_.GetTaskRunner(); |
| 107 |
| 108 for (int i = 0; i < task_count; ++i) { |
| 109 Closure task; |
| 110 if (i == 0) { |
| 111 task = Bind(&internal::SequencedTaskTracker::SlowTask, |
| 112 this->task_tracker_, i); |
| 113 } else { |
| 114 task = Bind(&internal::SequencedTaskTracker::FastTask, |
| 115 this->task_tracker_, i); |
| 116 } |
| 117 this->task_tracker_->TaskPosted(i); |
| 118 task_runner->PostNonNestableTask(FROM_HERE, task); |
| 119 } |
| 120 |
| 121 this->delegate_.StopTaskRunner(); |
| 122 |
| 123 EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
| 124 this->task_tracker_->GetStartOrder()); |
| 125 EXPECT_EQ(this->task_tracker_->GetEndOrder(), |
| 126 this->task_tracker_->GetStartOrder()); |
| 127 } |
| 128 |
| 129 // This test posts N nestable tasks in sequence, and expects them to run in |
| 130 // FIFO order; overlapping execution is allowed. |
| 131 // |
| 132 // It checks only that task_i had started by the time task_i+1 started, for |
| 133 // increasing values of i. Thus it verifies the SequencedTaskRunner guarantee |
| 134 // that nested tasks are run in FIFO order. |
| 135 // |
| 136 // The first task it starts is a slow one which runs for a second, giving the |
| 137 // subsequent ones plenty of time to run in if the implementation fails to |
| 138 // enforce the FIFO property for nestable tasks. |
| 139 TYPED_TEST_P(SequencedTaskRunnerTest, FAILS_SequentialNestable) { |
| 140 const int task_count = 10; |
| 141 |
| 142 this->delegate_.StartTaskRunner(); |
| 143 scoped_refptr<SequencedTaskRunner> task_runner = |
| 144 this->delegate_.GetTaskRunner(); |
| 145 |
| 146 for (int i = 0; i < task_count; ++i) { |
| 147 Closure task; |
| 148 if (i == 0) { |
| 149 task = Bind(&internal::SequencedTaskTracker::SlowTask, |
| 150 this->task_tracker_, i); |
| 151 } else { |
| 152 task = Bind(&internal::SequencedTaskTracker::FastTask, |
| 153 this->task_tracker_, i); |
| 154 } |
| 155 this->task_tracker_->TaskPosted(i); |
| 156 task_runner->PostTask(FROM_HERE, task); |
| 157 } |
| 158 |
| 159 this->delegate_.StopTaskRunner(); |
| 160 |
| 161 const std::vector<int>& post_events = this->task_tracker_->GetPostOrder(); |
| 162 const std::vector<int>& end_events = this->task_tracker_->GetEndOrder(); |
| 163 |
| 164 EXPECT_EQ(post_events, this->task_tracker_->GetStartOrder()); |
| 165 |
| 166 // Check that all posted tasks finished. |
| 167 for (std::size_t i = 0; i < post_events.size(); ++i) { |
| 168 EXPECT_NE(std::find(end_events.begin(), end_events.end(), post_events[i]), |
| 169 end_events.end()); |
| 170 } |
| 171 } |
| 172 |
| 173 // This test posts non-nestable tasks in order of increasing delay, and checks |
| 174 // that that the tasks are run in FIFO order and that there is no execution |
| 175 // overlap whatsoever between any two tasks. |
| 176 // |
| 177 // If there are 10 tasks, task1 is posted first with a delay of zero, followed |
| 178 // by task2 with a delay of, say, 1, and so forth, until task10 is posted with |
| 179 // a delay of 10. It then checks that task2 started after task1, and only |
| 180 // after task1 had finished, and so forth. |
| 181 TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) { |
| 182 const int task_count = 20; |
| 183 const int delay_increment_ms = 50; |
| 184 |
| 185 this->delegate_.StartTaskRunner(); |
| 186 scoped_refptr<SequencedTaskRunner> task_runner = |
| 187 this->delegate_.GetTaskRunner(); |
| 188 |
| 189 for (int i = 0; i < task_count; ++i) { |
| 190 Closure task = Bind(&internal::SequencedTaskTracker::FastTask, |
| 191 this->task_tracker_, i); |
| 192 this->task_tracker_->TaskPosted(i); |
| 193 task_runner->PostNonNestableDelayedTask( |
| 194 FROM_HERE, |
| 195 task, |
| 196 TimeDelta::FromMilliseconds(delay_increment_ms * i)); |
| 197 } |
| 198 |
| 199 this->delegate_.StopTaskRunner(); |
| 200 |
| 201 EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
| 202 this->task_tracker_->GetStartOrder()); |
| 203 EXPECT_EQ(this->task_tracker_->GetStartOrder(), |
| 204 this->task_tracker_->GetEndOrder()); |
| 205 } |
| 206 |
| 207 // This test posts a fast, non-nestable task from within each of a number of |
| 208 // slow, non-nestable tasks and checks that they all run in the sequence they |
| 209 // were posted in and that there is no execution overlap whatsoever. |
| 210 TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) { |
| 211 const int parent_count = 1000; |
| 212 const int children_per_parent = 2; |
| 213 |
| 214 this->delegate_.StartTaskRunner(); |
| 215 scoped_refptr<SequencedTaskRunner> task_runner = |
| 216 this->delegate_.GetTaskRunner(); |
| 217 |
| 218 const int end = parent_count; |
| 219 for (int i = 0; i < end; ++i) { |
| 220 base::PlatformThread::YieldCurrentThread(); |
| 221 AutoLock post_lock(this->task_tracker_->post_lock_); |
| 222 const int post_i = this->task_tracker_->GetNextPostOrdinal(); |
| 223 Closure task = Bind( |
| 224 &internal::SequencedTaskTracker::PostFastNonNestableFromSlowNonNestable, |
| 225 this->task_tracker_, |
| 226 task_runner, |
| 227 post_i, |
| 228 children_per_parent); |
| 229 this->task_tracker_->post_events_.push_back(post_i); |
| 230 task_runner->PostNonNestableTask(FROM_HERE, task); |
| 231 } |
| 232 |
| 233 this->delegate_.StopTaskRunner(); |
| 234 |
| 235 EXPECT_EQ(this->task_tracker_->GetPostOrder(), |
| 236 this->task_tracker_->GetStartOrder()); |
| 237 EXPECT_EQ(this->task_tracker_->GetEndOrder(), |
| 238 this->task_tracker_->GetStartOrder()); |
| 239 } |
| 240 |
| 241 // TODO(francoisk777@gmail.com) Add a test, similiar to the above, which which |
| 242 // runs some tasked nestedly (which should be implemented in the test |
| 243 // delegate). Also add, to the the test delegate, a predicate which checks |
| 244 // whether the implementation supports nested tasks. |
| 245 |
| 246 REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest, |
| 247 SequentialNonNestable, |
| 248 FAILS_SequentialNestable, |
| 249 SequentialDelayedNonNestable, |
| 250 NonNestablePostFromNonNestableTask); |
| 251 |
| 252 } // namespace base |
| 253 |
| 254 #endif // BASE_TASK_RUNNER_TEST_TEMPLATE_H_ |
OLD | NEW |