Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "base/bind.h" | |
| 6 #include "base/bind_helpers.h" | |
| 7 #include "base/macros.h" | |
| 8 #include "base/message_loop/message_loop.h" | |
| 9 #include "base/run_loop.h" | |
| 10 #include "base/threading/platform_thread.h" | |
| 11 #include "base/time/time.h" | |
| 12 #include "components/timer/alarm_timer.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 // Most of these tests have been lifted right out of timer_unittest.cc with only | |
| 16 // cosmetic changes (like replacing calls to MessageLoop::current()->Run() with | |
| 17 // a RunLoop). We want the AlarmTimer to be a drop-in replacement for the | |
| 18 // regular Timer so it should pass the same tests as the Timer class. | |
|
Daniel Erat
2014/10/23 03:44:54
i don't love the duplication here but don't have a
blundell
2014/10/23 05:54:20
This duplication seems pretty bad. Could you reach
Chirantan Ekbote
2014/10/23 23:53:30
I've filed crbug.com/426647. We'll land this for
| |
| 19 // | |
| 20 // The only new tests are the .*ConcurrentResetAndTimerFired tests, which test | |
| 21 // that race conditions that can come up in the AlarmTimer::Delegate are | |
| 22 // properly handled. | |
| 23 namespace { | |
| 24 // The message loops on which each timer should be tested. | |
| 25 const base::MessageLoop::Type testing_message_loops[] = { | |
| 26 base::MessageLoop::TYPE_DEFAULT, | |
| 27 base::MessageLoop::TYPE_IO, | |
| 28 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. | |
| 29 base::MessageLoop::TYPE_UI, | |
| 30 #endif | |
| 31 }; | |
| 32 | |
| 33 const int kNumTestingMessageLoops = arraysize(testing_message_loops); | |
| 34 const base::TimeDelta kTenMilliseconds = base::TimeDelta::FromMilliseconds(10); | |
| 35 | |
| 36 class OneShotAlarmTimerTester { | |
| 37 public: | |
| 38 OneShotAlarmTimerTester(bool* did_run, base::TimeDelta delay) | |
| 39 : did_run_(did_run), | |
| 40 delay_(delay), | |
| 41 timer_(new timer::AlarmTimer(false, false)) { | |
| 42 } | |
| 43 void Start() { | |
| 44 timer_->Start(FROM_HERE, | |
| 45 delay_, | |
| 46 base::Bind(&OneShotAlarmTimerTester::Run, | |
| 47 base::Unretained(this))); | |
| 48 } | |
| 49 | |
| 50 private: | |
| 51 void Run() { | |
| 52 *did_run_ = true; | |
| 53 | |
| 54 base::MessageLoop::current()->PostTask( | |
| 55 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 56 } | |
| 57 | |
| 58 bool* did_run_; | |
| 59 const base::TimeDelta delay_; | |
| 60 scoped_ptr<timer::AlarmTimer> timer_; | |
| 61 | |
| 62 DISALLOW_COPY_AND_ASSIGN(OneShotAlarmTimerTester); | |
| 63 }; | |
| 64 | |
| 65 class OneShotSelfDeletingAlarmTimerTester { | |
| 66 public: | |
| 67 OneShotSelfDeletingAlarmTimerTester(bool* did_run, base::TimeDelta delay) | |
| 68 : did_run_(did_run), | |
| 69 delay_(delay), | |
| 70 timer_(new timer::AlarmTimer(false, false)) { | |
| 71 } | |
| 72 void Start() { | |
| 73 timer_->Start(FROM_HERE, | |
| 74 delay_, | |
| 75 base::Bind(&OneShotSelfDeletingAlarmTimerTester::Run, | |
| 76 base::Unretained(this))); | |
| 77 } | |
| 78 | |
| 79 private: | |
| 80 void Run() { | |
| 81 *did_run_ = true; | |
| 82 timer_.reset(); | |
| 83 | |
| 84 base::MessageLoop::current()->PostTask( | |
| 85 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 86 } | |
| 87 | |
| 88 bool* did_run_; | |
| 89 const base::TimeDelta delay_; | |
| 90 scoped_ptr<timer::AlarmTimer> timer_; | |
| 91 | |
| 92 DISALLOW_COPY_AND_ASSIGN(OneShotSelfDeletingAlarmTimerTester); | |
| 93 }; | |
| 94 | |
| 95 class RepeatingAlarmTimerTester { | |
| 96 public: | |
| 97 RepeatingAlarmTimerTester(bool* did_run, base::TimeDelta delay) | |
| 98 : did_run_(did_run), | |
| 99 delay_(delay), | |
| 100 counter_(10), | |
| 101 timer_(new timer::AlarmTimer(true, true)) { | |
| 102 } | |
| 103 void Start() { | |
| 104 timer_->Start(FROM_HERE, | |
| 105 delay_, | |
| 106 base::Bind(&RepeatingAlarmTimerTester::Run, | |
| 107 base::Unretained(this))); | |
| 108 } | |
| 109 | |
| 110 private: | |
| 111 void Run() { | |
| 112 if (--counter_ == 0) { | |
| 113 *did_run_ = true; | |
| 114 timer_->Stop(); | |
| 115 | |
| 116 base::MessageLoop::current()->PostTask( | |
| 117 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 bool* did_run_; | |
| 122 const base::TimeDelta delay_; | |
| 123 int counter_; | |
| 124 scoped_ptr<timer::AlarmTimer> timer_; | |
| 125 | |
| 126 DISALLOW_COPY_AND_ASSIGN(RepeatingAlarmTimerTester); | |
| 127 }; | |
| 128 | |
| 129 void RunTest_OneShotAlarmTimer(base::MessageLoop::Type message_loop_type) { | |
| 130 base::MessageLoop loop(message_loop_type); | |
| 131 | |
| 132 bool did_run = false; | |
| 133 OneShotAlarmTimerTester f(&did_run, kTenMilliseconds); | |
| 134 f.Start(); | |
| 135 | |
| 136 base::RunLoop().Run(); | |
| 137 | |
| 138 EXPECT_TRUE(did_run); | |
| 139 } | |
| 140 | |
| 141 void RunTest_OneShotAlarmTimer_Cancel( | |
| 142 base::MessageLoop::Type message_loop_type) { | |
| 143 base::MessageLoop loop(message_loop_type); | |
| 144 | |
| 145 bool did_run_a = false; | |
| 146 OneShotAlarmTimerTester* a = new OneShotAlarmTimerTester(&did_run_a, | |
| 147 kTenMilliseconds); | |
| 148 | |
| 149 // This should run before the timer expires. | |
| 150 base::MessageLoop::current()->DeleteSoon(FROM_HERE, a); | |
| 151 | |
| 152 // Now start the timer. | |
| 153 a->Start(); | |
| 154 | |
| 155 bool did_run_b = false; | |
| 156 OneShotAlarmTimerTester b(&did_run_b, kTenMilliseconds); | |
| 157 b.Start(); | |
| 158 | |
| 159 base::RunLoop().Run(); | |
| 160 | |
| 161 EXPECT_FALSE(did_run_a); | |
| 162 EXPECT_TRUE(did_run_b); | |
| 163 } | |
| 164 | |
| 165 void RunTest_OneShotSelfDeletingAlarmTimer( | |
| 166 base::MessageLoop::Type message_loop_type) { | |
| 167 base::MessageLoop loop(message_loop_type); | |
| 168 | |
| 169 bool did_run = false; | |
| 170 OneShotSelfDeletingAlarmTimerTester f(&did_run, kTenMilliseconds); | |
| 171 f.Start(); | |
| 172 | |
| 173 base::RunLoop().Run(); | |
| 174 | |
| 175 EXPECT_TRUE(did_run); | |
| 176 } | |
| 177 | |
| 178 void RunTest_RepeatingAlarmTimer(base::MessageLoop::Type message_loop_type, | |
| 179 const base::TimeDelta& delay) { | |
| 180 base::MessageLoop loop(message_loop_type); | |
| 181 | |
| 182 bool did_run = false; | |
| 183 RepeatingAlarmTimerTester f(&did_run, delay); | |
| 184 f.Start(); | |
| 185 | |
| 186 base::RunLoop().Run(); | |
| 187 | |
| 188 EXPECT_TRUE(did_run); | |
| 189 } | |
| 190 | |
| 191 void RunTest_RepeatingAlarmTimer_Cancel( | |
| 192 base::MessageLoop::Type message_loop_type, const base::TimeDelta& delay) { | |
| 193 base::MessageLoop loop(message_loop_type); | |
| 194 | |
| 195 bool did_run_a = false; | |
| 196 RepeatingAlarmTimerTester* a = new RepeatingAlarmTimerTester(&did_run_a, | |
| 197 delay); | |
| 198 | |
| 199 // This should run before the timer expires. | |
| 200 base::MessageLoop::current()->DeleteSoon(FROM_HERE, a); | |
| 201 | |
| 202 // Now start the timer. | |
| 203 a->Start(); | |
| 204 | |
| 205 bool did_run_b = false; | |
| 206 RepeatingAlarmTimerTester b(&did_run_b, delay); | |
| 207 b.Start(); | |
| 208 | |
| 209 base::RunLoop().Run(); | |
| 210 | |
| 211 EXPECT_FALSE(did_run_a); | |
| 212 EXPECT_TRUE(did_run_b); | |
| 213 } | |
| 214 | |
| 215 } // namespace | |
| 216 | |
| 217 //----------------------------------------------------------------------------- | |
| 218 // Each test is run against each type of MessageLoop. That way we are sure | |
| 219 // that timers work properly in all configurations. | |
| 220 | |
| 221 TEST(AlarmTimerTest, OneShotAlarmTimer) { | |
| 222 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 223 RunTest_OneShotAlarmTimer(testing_message_loops[i]); | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 TEST(AlarmTimerTest, OneShotAlarmTimer_Cancel) { | |
| 228 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 229 RunTest_OneShotAlarmTimer_Cancel(testing_message_loops[i]); | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 // If underlying timer does not handle this properly, we will crash or fail | |
| 234 // in full page heap environment. | |
| 235 TEST(AlarmTimerTest, OneShotSelfDeletingAlarmTimer) { | |
| 236 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 237 RunTest_OneShotSelfDeletingAlarmTimer(testing_message_loops[i]); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 TEST(AlarmTimerTest, RepeatingAlarmTimer) { | |
| 242 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 243 RunTest_RepeatingAlarmTimer(testing_message_loops[i], | |
| 244 kTenMilliseconds); | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 TEST(AlarmTimerTest, RepeatingAlarmTimer_Cancel) { | |
| 249 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 250 RunTest_RepeatingAlarmTimer_Cancel(testing_message_loops[i], | |
| 251 kTenMilliseconds); | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 TEST(AlarmTimerTest, RepeatingAlarmTimerZeroDelay) { | |
| 256 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 257 RunTest_RepeatingAlarmTimer(testing_message_loops[i], | |
| 258 base::TimeDelta::FromMilliseconds(0)); | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 TEST(AlarmTimerTest, RepeatingAlarmTimerZeroDelay_Cancel) { | |
| 263 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 264 RunTest_RepeatingAlarmTimer_Cancel(testing_message_loops[i], | |
| 265 base::TimeDelta::FromMilliseconds(0)); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 TEST(AlarmTimerTest, MessageLoopShutdown) { | |
| 270 // This test is designed to verify that shutdown of the | |
| 271 // message loop does not cause crashes if there were pending | |
| 272 // timers not yet fired. It may only trigger exceptions | |
| 273 // if debug heap checking is enabled. | |
| 274 bool did_run = false; | |
| 275 { | |
| 276 OneShotAlarmTimerTester a(&did_run, kTenMilliseconds); | |
| 277 OneShotAlarmTimerTester b(&did_run, kTenMilliseconds); | |
| 278 OneShotAlarmTimerTester c(&did_run, kTenMilliseconds); | |
| 279 OneShotAlarmTimerTester d(&did_run, kTenMilliseconds); | |
| 280 { | |
| 281 base::MessageLoop loop; | |
| 282 a.Start(); | |
| 283 b.Start(); | |
| 284 } // MessageLoop destructs by falling out of scope. | |
| 285 } // OneShotTimers destruct. SHOULD NOT CRASH, of course. | |
| 286 | |
| 287 EXPECT_FALSE(did_run); | |
| 288 } | |
| 289 | |
| 290 TEST(AlarmTimerTest, NonRepeatIsRunning) { | |
| 291 { | |
| 292 base::MessageLoop loop; | |
| 293 timer::AlarmTimer timer(false, false); | |
| 294 EXPECT_FALSE(timer.IsRunning()); | |
| 295 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), | |
| 296 base::Bind(&base::DoNothing)); | |
| 297 EXPECT_TRUE(timer.IsRunning()); | |
| 298 timer.Stop(); | |
| 299 EXPECT_FALSE(timer.IsRunning()); | |
| 300 EXPECT_TRUE(timer.user_task().is_null()); | |
| 301 } | |
| 302 | |
| 303 { | |
| 304 timer::AlarmTimer timer(true, false); | |
| 305 base::MessageLoop loop; | |
| 306 EXPECT_FALSE(timer.IsRunning()); | |
| 307 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), | |
| 308 base::Bind(&base::DoNothing)); | |
| 309 EXPECT_TRUE(timer.IsRunning()); | |
| 310 timer.Stop(); | |
| 311 EXPECT_FALSE(timer.IsRunning()); | |
| 312 ASSERT_FALSE(timer.user_task().is_null()); | |
| 313 timer.Reset(); | |
| 314 EXPECT_TRUE(timer.IsRunning()); | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 TEST(AlarmTimerTest, NonRepeatMessageLoopDeath) { | |
| 319 timer::AlarmTimer timer(false, false); | |
| 320 { | |
| 321 base::MessageLoop loop; | |
| 322 EXPECT_FALSE(timer.IsRunning()); | |
| 323 timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), | |
| 324 base::Bind(&base::DoNothing)); | |
| 325 EXPECT_TRUE(timer.IsRunning()); | |
| 326 } | |
| 327 EXPECT_FALSE(timer.IsRunning()); | |
| 328 EXPECT_TRUE(timer.user_task().is_null()); | |
| 329 } | |
| 330 | |
| 331 TEST(AlarmTimerTest, RetainRepeatIsRunning) { | |
| 332 base::MessageLoop loop; | |
| 333 timer::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1), | |
| 334 base::Bind(&base::DoNothing), true); | |
| 335 EXPECT_FALSE(timer.IsRunning()); | |
| 336 timer.Reset(); | |
| 337 EXPECT_TRUE(timer.IsRunning()); | |
| 338 timer.Stop(); | |
| 339 EXPECT_FALSE(timer.IsRunning()); | |
| 340 timer.Reset(); | |
| 341 EXPECT_TRUE(timer.IsRunning()); | |
| 342 } | |
| 343 | |
| 344 TEST(AlarmTimerTest, RetainNonRepeatIsRunning) { | |
| 345 base::MessageLoop loop; | |
| 346 timer::AlarmTimer timer(FROM_HERE, base::TimeDelta::FromDays(1), | |
| 347 base::Bind(&base::DoNothing), false); | |
| 348 EXPECT_FALSE(timer.IsRunning()); | |
| 349 timer.Reset(); | |
| 350 EXPECT_TRUE(timer.IsRunning()); | |
| 351 timer.Stop(); | |
| 352 EXPECT_FALSE(timer.IsRunning()); | |
| 353 timer.Reset(); | |
| 354 EXPECT_TRUE(timer.IsRunning()); | |
| 355 } | |
| 356 | |
| 357 namespace { | |
| 358 | |
| 359 bool g_callback_happened1 = false; | |
| 360 bool g_callback_happened2 = false; | |
| 361 | |
| 362 void ClearAllCallbackHappened() { | |
| 363 g_callback_happened1 = false; | |
| 364 g_callback_happened2 = false; | |
| 365 } | |
| 366 | |
| 367 void SetCallbackHappened1() { | |
| 368 g_callback_happened1 = true; | |
| 369 base::MessageLoop::current()->PostTask( | |
| 370 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 371 } | |
| 372 | |
| 373 void SetCallbackHappened2() { | |
| 374 g_callback_happened2 = true; | |
| 375 base::MessageLoop::current()->PostTask( | |
| 376 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 377 } | |
| 378 | |
| 379 TEST(AlarmTimerTest, ContinuationStopStart) { | |
| 380 { | |
| 381 ClearAllCallbackHappened(); | |
| 382 base::MessageLoop loop; | |
| 383 timer::AlarmTimer timer(false, false); | |
| 384 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10), | |
| 385 base::Bind(&SetCallbackHappened1)); | |
| 386 timer.Stop(); | |
| 387 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(40), | |
| 388 base::Bind(&SetCallbackHappened2)); | |
| 389 base::RunLoop().Run(); | |
| 390 EXPECT_FALSE(g_callback_happened1); | |
| 391 EXPECT_TRUE(g_callback_happened2); | |
| 392 } | |
| 393 } | |
| 394 | |
| 395 TEST(AlarmTimerTest, ContinuationReset) { | |
| 396 { | |
| 397 ClearAllCallbackHappened(); | |
| 398 base::MessageLoop loop; | |
| 399 timer::AlarmTimer timer(false, false); | |
| 400 timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10), | |
| 401 base::Bind(&SetCallbackHappened1)); | |
| 402 timer.Reset(); | |
| 403 // Since Reset happened before task ran, the user_task must not be cleared: | |
| 404 ASSERT_FALSE(timer.user_task().is_null()); | |
| 405 base::RunLoop().Run(); | |
| 406 EXPECT_TRUE(g_callback_happened1); | |
| 407 } | |
| 408 } | |
| 409 | |
| 410 } // namespace | |
| 411 | |
| 412 | |
| 413 namespace { | |
| 414 void TimerRanCallback(bool* did_run) { | |
| 415 *did_run = true; | |
| 416 | |
| 417 base::MessageLoop::current()->PostTask( | |
| 418 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | |
| 419 } | |
| 420 | |
| 421 void RunTest_OneShotTimerConcurrentResetAndTimerFired( | |
| 422 base::MessageLoop::Type message_loop_type) { | |
| 423 base::MessageLoop loop(message_loop_type); | |
| 424 | |
| 425 timer::AlarmTimer timer(false, false); | |
| 426 bool did_run = false; | |
| 427 | |
| 428 timer.Start( | |
| 429 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run)); | |
| 430 | |
| 431 // Sleep twice as long as the timer to ensure that the timer task gets queued. | |
| 432 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); | |
| 433 | |
| 434 // Now reset the timer. This is attempting to simulate the timer firing and | |
| 435 // being reset at the same time. The previously queued task should be | |
| 436 // removed. | |
| 437 timer.Reset(); | |
| 438 | |
| 439 base::RunLoop().RunUntilIdle(); | |
| 440 EXPECT_FALSE(did_run); | |
| 441 | |
| 442 // If the previous check failed, running the message loop again will hang the | |
| 443 // test so we only do it if the callback has not run yet. | |
| 444 if (!did_run) { | |
| 445 base::RunLoop().Run(); | |
| 446 EXPECT_TRUE(did_run); | |
| 447 } | |
| 448 } | |
| 449 | |
| 450 void RunTest_RepeatingTimerConcurrentResetAndTimerFired( | |
| 451 base::MessageLoop::Type message_loop_type) { | |
| 452 base::MessageLoop loop(message_loop_type); | |
| 453 | |
| 454 timer::AlarmTimer timer(true, true); | |
| 455 bool did_run = false; | |
| 456 | |
| 457 timer.Start( | |
| 458 FROM_HERE, kTenMilliseconds, base::Bind(&TimerRanCallback, &did_run)); | |
| 459 | |
| 460 // Sleep more that three times as long as the timer duration to ensure that | |
| 461 // multiple tasks get queued. | |
| 462 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(35)); | |
| 463 | |
| 464 // Now reset the timer. This is attempting to simulate a very busy message | |
| 465 // loop where multiple tasks get queued but the timer gets reset before any of | |
| 466 // them have a chance to run. | |
| 467 timer.Reset(); | |
| 468 | |
| 469 base::RunLoop().RunUntilIdle(); | |
| 470 EXPECT_FALSE(did_run); | |
| 471 | |
| 472 // If the previous check failed, running the message loop again will hang the | |
| 473 // test so we only do it if the callback has not run yet. | |
| 474 if (!did_run) { | |
| 475 base::RunLoop().Run(); | |
| 476 EXPECT_TRUE(did_run); | |
| 477 } | |
| 478 } | |
| 479 | |
| 480 TEST(AlarmTimerTest, OneShotTimerConcurrentResetAndTimerFired) { | |
| 481 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 482 RunTest_OneShotTimerConcurrentResetAndTimerFired(testing_message_loops[i]); | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 TEST(AlarmTimerTest, RepeatingTimerConcurrentResetAndTimerFired) { | |
| 487 for (int i = 0; i < kNumTestingMessageLoops; i++) { | |
| 488 RunTest_RepeatingTimerConcurrentResetAndTimerFired( | |
| 489 testing_message_loops[i]); | |
| 490 } | |
| 491 } | |
| 492 | |
| 493 } // namespace | |
| OLD | NEW |