OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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 #include "content/child/scheduler/worker_scheduler_impl.h" |
| 6 |
| 7 #include "base/callback.h" |
| 8 #include "cc/test/ordered_simple_task_runner.h" |
| 9 #include "content/child/scheduler/nestable_task_runner_for_test.h" |
| 10 #include "content/child/scheduler/scheduler_message_loop_delegate.h" |
| 11 #include "testing/gmock/include/gmock/gmock.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" |
| 13 |
| 14 namespace content { |
| 15 |
| 16 namespace { |
| 17 void NopTask() { |
| 18 } |
| 19 |
| 20 void AppendToVectorTestTask(std::vector<std::string>* vector, |
| 21 std::string value) { |
| 22 vector->push_back(value); |
| 23 } |
| 24 |
| 25 void AppendToVectorIdleTestTask(std::vector<std::string>* vector, |
| 26 std::string value, |
| 27 base::TimeTicks deadline) { |
| 28 AppendToVectorTestTask(vector, value); |
| 29 } |
| 30 |
| 31 void IdleTestTask(base::TimeTicks* deadline_out, base::TimeTicks deadline) { |
| 32 *deadline_out = deadline; |
| 33 } |
| 34 |
| 35 void CountingIdleTestTask(int* run_count, |
| 36 base::TimeTicks* deadline_out, |
| 37 base::TimeTicks deadline) { |
| 38 (*run_count)++; |
| 39 *deadline_out = deadline; |
| 40 } |
| 41 |
| 42 }; // namespace |
| 43 |
| 44 class WorkerSchedulerImplTest : public testing::Test { |
| 45 public: |
| 46 WorkerSchedulerImplTest() |
| 47 : clock_(cc::TestNowSource::Create(5000)), |
| 48 mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, true)), |
| 49 nestable_task_runner_( |
| 50 NestableTaskRunnerForTest::Create(mock_task_runner_)), |
| 51 scheduler_(new WorkerSchedulerImpl(nestable_task_runner_)) { |
| 52 scheduler_->SetTimeSourceForTesting(clock_); |
| 53 } |
| 54 |
| 55 ~WorkerSchedulerImplTest() override {} |
| 56 |
| 57 void TearDown() override { |
| 58 // Check that all tests stop posting tasks. |
| 59 while (mock_task_runner_->RunUntilIdle()) { |
| 60 } |
| 61 } |
| 62 |
| 63 void Init() { |
| 64 scheduler_->Init(); |
| 65 default_task_runner_ = scheduler_->DefaultTaskRunner(); |
| 66 idle_task_runner_ = scheduler_->IdleTaskRunner(); |
| 67 } |
| 68 |
| 69 void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); } |
| 70 |
| 71 void InitAndPostDelayedWakeupTask() { |
| 72 Init(); |
| 73 // WorkerSchedulerImpl::Init causes a delayed task to be posted on the |
| 74 // after wakeup control runner. We need a task to wake the system up |
| 75 // AFTER the delay for this has expired. |
| 76 default_task_runner_->PostDelayedTask( |
| 77 FROM_HERE, base::Bind(&NopTask), |
| 78 base::TimeDelta::FromMilliseconds(100)); |
| 79 } |
| 80 |
| 81 // Helper for posting several tasks of specific types. |task_descriptor| is a |
| 82 // string with space delimited task identifiers. The first letter of each |
| 83 // task identifier specifies the task type: |
| 84 // - 'D': Default task |
| 85 // - 'I': Idle task |
| 86 void PostTestTasks(std::vector<std::string>* run_order, |
| 87 const std::string& task_descriptor) { |
| 88 std::istringstream stream(task_descriptor); |
| 89 while (!stream.eof()) { |
| 90 std::string task; |
| 91 stream >> task; |
| 92 switch (task[0]) { |
| 93 case 'D': |
| 94 default_task_runner_->PostTask( |
| 95 FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task)); |
| 96 break; |
| 97 case 'I': |
| 98 idle_task_runner_->PostIdleTask( |
| 99 FROM_HERE, |
| 100 base::Bind(&AppendToVectorIdleTestTask, run_order, task)); |
| 101 break; |
| 102 default: |
| 103 NOTREACHED(); |
| 104 } |
| 105 } |
| 106 } |
| 107 |
| 108 static base::TimeDelta maximum_idle_period_duration() { |
| 109 return base::TimeDelta::FromMilliseconds( |
| 110 SchedulerHelper::kMaximumIdlePeriodMillis); |
| 111 } |
| 112 |
| 113 protected: |
| 114 scoped_refptr<cc::TestNowSource> clock_; |
| 115 // Only one of mock_task_runner_ or message_loop_ will be set. |
| 116 scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; |
| 117 |
| 118 scoped_refptr<NestableSingleThreadTaskRunner> nestable_task_runner_; |
| 119 scoped_ptr<WorkerSchedulerImpl> scheduler_; |
| 120 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_; |
| 121 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; |
| 122 |
| 123 DISALLOW_COPY_AND_ASSIGN(WorkerSchedulerImplTest); |
| 124 }; |
| 125 |
| 126 TEST_F(WorkerSchedulerImplTest, TestPostDefaultTask) { |
| 127 InitAndPostDelayedWakeupTask(); |
| 128 |
| 129 std::vector<std::string> run_order; |
| 130 PostTestTasks(&run_order, "D1 D2 D3 D4"); |
| 131 |
| 132 RunUntilIdle(); |
| 133 EXPECT_THAT(run_order, |
| 134 testing::ElementsAre(std::string("D1"), std::string("D2"), |
| 135 std::string("D3"), std::string("D4"))); |
| 136 } |
| 137 |
| 138 TEST_F(WorkerSchedulerImplTest, TestPostIdleTask) { |
| 139 InitAndPostDelayedWakeupTask(); |
| 140 |
| 141 std::vector<std::string> run_order; |
| 142 PostTestTasks(&run_order, "I1"); |
| 143 |
| 144 RunUntilIdle(); |
| 145 EXPECT_THAT(run_order, testing::ElementsAre(std::string("I1"))); |
| 146 } |
| 147 |
| 148 TEST_F(WorkerSchedulerImplTest, TestPostIdleTask_NoWakeup) { |
| 149 Init(); |
| 150 std::vector<std::string> run_order; |
| 151 PostTestTasks(&run_order, "I1"); |
| 152 |
| 153 RunUntilIdle(); |
| 154 EXPECT_TRUE(run_order.empty()); |
| 155 } |
| 156 |
| 157 TEST_F(WorkerSchedulerImplTest, TestPostDefaultAndIdleTasks) { |
| 158 InitAndPostDelayedWakeupTask(); |
| 159 |
| 160 std::vector<std::string> run_order; |
| 161 PostTestTasks(&run_order, "I1 D2 D3 D4"); |
| 162 |
| 163 RunUntilIdle(); |
| 164 EXPECT_THAT(run_order, |
| 165 testing::ElementsAre(std::string("D2"), std::string("D3"), |
| 166 std::string("D4"), std::string("I1"))); |
| 167 } |
| 168 |
| 169 TEST_F(WorkerSchedulerImplTest, TestPostIdleTaskWithWakeupNeeded_NoWakeup) { |
| 170 InitAndPostDelayedWakeupTask(); |
| 171 |
| 172 RunUntilIdle(); |
| 173 // The delayed call to InitiateLongIdlePeriod happened and it posted a call to |
| 174 // InitiateLongIdlePeriod on the after wakeup control queue. |
| 175 |
| 176 std::vector<std::string> run_order; |
| 177 PostTestTasks(&run_order, "I1"); |
| 178 |
| 179 RunUntilIdle(); |
| 180 EXPECT_TRUE(run_order.empty()); |
| 181 } |
| 182 |
| 183 TEST_F(WorkerSchedulerImplTest, TestPostDefaultDelayedAndIdleTasks) { |
| 184 InitAndPostDelayedWakeupTask(); |
| 185 |
| 186 std::vector<std::string> run_order; |
| 187 PostTestTasks(&run_order, "I1 D2 D3 D4"); |
| 188 |
| 189 default_task_runner_->PostDelayedTask( |
| 190 FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"), |
| 191 base::TimeDelta::FromMilliseconds(1000)); |
| 192 |
| 193 RunUntilIdle(); |
| 194 EXPECT_THAT(run_order, |
| 195 testing::ElementsAre(std::string("D2"), std::string("D3"), |
| 196 std::string("D4"), std::string("I1"), |
| 197 std::string("DELAYED"))); |
| 198 } |
| 199 |
| 200 TEST_F(WorkerSchedulerImplTest, TestIdleDeadlineWithPendingDelayedTask) { |
| 201 InitAndPostDelayedWakeupTask(); |
| 202 |
| 203 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(140); |
| 204 default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); |
| 205 base::TimeTicks deadline; |
| 206 idle_task_runner_->PostIdleTask(FROM_HERE, |
| 207 base::Bind(&IdleTestTask, &deadline)); |
| 208 |
| 209 base::TimeTicks expected_deadline = clock_->Now() + delay; |
| 210 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(100)); |
| 211 |
| 212 RunUntilIdle(); |
| 213 EXPECT_EQ(expected_deadline, deadline); |
| 214 } |
| 215 |
| 216 TEST_F(WorkerSchedulerImplTest, |
| 217 TestIdleDeadlineWithPendingDelayedTaskFarInTheFuture) { |
| 218 InitAndPostDelayedWakeupTask(); |
| 219 |
| 220 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(1000); |
| 221 base::TimeTicks task_run_time = clock_->Now() + delay; |
| 222 default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); |
| 223 base::TimeTicks deadline; |
| 224 idle_task_runner_->PostIdleTask(FROM_HERE, |
| 225 base::Bind(&IdleTestTask, &deadline)); |
| 226 |
| 227 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(100)); |
| 228 |
| 229 RunUntilIdle(); |
| 230 EXPECT_LT(deadline, task_run_time); |
| 231 } |
| 232 |
| 233 TEST_F(WorkerSchedulerImplTest, |
| 234 TestPostIdleTaskAfterRunningUntilIdle_NoWakeUp) { |
| 235 InitAndPostDelayedWakeupTask(); |
| 236 |
| 237 default_task_runner_->PostDelayedTask( |
| 238 FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); |
| 239 RunUntilIdle(); |
| 240 |
| 241 // The delayed call to InitiateLongIdlePeriod happened and it posted a call to |
| 242 // InitiateLongIdlePeriod on the after wakeup control queue. Without an other |
| 243 // non-idle task posted, the idle tasks won't run. |
| 244 std::vector<std::string> run_order; |
| 245 PostTestTasks(&run_order, "I1 I2"); |
| 246 |
| 247 RunUntilIdle(); |
| 248 EXPECT_TRUE(run_order.empty()); |
| 249 } |
| 250 |
| 251 TEST_F(WorkerSchedulerImplTest, |
| 252 TestPostIdleTaskAfterRunningUntilIdle_WithWakeUp) { |
| 253 InitAndPostDelayedWakeupTask(); |
| 254 |
| 255 default_task_runner_->PostDelayedTask( |
| 256 FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000)); |
| 257 RunUntilIdle(); |
| 258 // The delayed call to InitiateLongIdlePeriod happened and it posted a call to |
| 259 // InitiateLongIdlePeriod on the after wakeup control queue. Without an other |
| 260 // non-idle task posted, the idle tasks won't run. |
| 261 |
| 262 std::vector<std::string> run_order; |
| 263 PostTestTasks(&run_order, "I1 I2 D3"); |
| 264 |
| 265 RunUntilIdle(); |
| 266 EXPECT_THAT(run_order, |
| 267 testing::ElementsAre(std::string("D3"), std::string("I1"), |
| 268 std::string("I2"))); |
| 269 } |
| 270 |
| 271 TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodDoesNotWakeScheduler) { |
| 272 mock_task_runner_->SetAutoAdvanceNowToPendingTasks(false); |
| 273 Init(); |
| 274 |
| 275 base::TimeTicks deadline_in_task; |
| 276 int run_count = 0; |
| 277 |
| 278 // The scheduler should not run the initiate_next_long_idle_period task if |
| 279 // there are no idle tasks and no other task woke up the scheduler, thus |
| 280 // the idle period deadline shouldn't update at the end of the current long |
| 281 // idle period. |
| 282 base::TimeTicks idle_period_deadline = |
| 283 scheduler_->CurrentIdleTaskDeadlineForTesting(); |
| 284 clock_->AdvanceNow(maximum_idle_period_duration()); |
| 285 RunUntilIdle(); |
| 286 |
| 287 base::TimeTicks new_idle_period_deadline = |
| 288 scheduler_->CurrentIdleTaskDeadlineForTesting(); |
| 289 EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); |
| 290 |
| 291 // Posting a after-wakeup idle task also shouldn't wake the scheduler or |
| 292 // initiate the next long idle period. |
| 293 idle_task_runner_->PostIdleTaskAfterWakeup( |
| 294 FROM_HERE, |
| 295 base::Bind(&CountingIdleTestTask, &run_count, &deadline_in_task)); |
| 296 RunUntilIdle(); |
| 297 new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); |
| 298 EXPECT_EQ(idle_period_deadline, new_idle_period_deadline); |
| 299 EXPECT_EQ(0, run_count); |
| 300 |
| 301 // Running a normal task should initiate a new long idle period though. |
| 302 default_task_runner_->PostTask(FROM_HERE, base::Bind(&NopTask)); |
| 303 RunUntilIdle(); |
| 304 new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting(); |
| 305 EXPECT_EQ(idle_period_deadline + maximum_idle_period_duration(), |
| 306 new_idle_period_deadline); |
| 307 |
| 308 EXPECT_EQ(1, run_count); |
| 309 mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true); |
| 310 } |
| 311 |
| 312 } // namespace content |
OLD | NEW |