Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/bind_helpers.h" | |
| 6 #include "base/callback.h" | |
| 5 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
| 6 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/synchronization/waitable_event.h" | |
| 10 #include "base/test/sequenced_worker_pool_owner.h" | |
| 7 #include "base/test/test_simple_task_runner.h" | 11 #include "base/test/test_simple_task_runner.h" |
| 8 #include "base/timer/timer.h" | 12 #include "base/timer/timer.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 10 | 14 |
| 15 using base::DoNothing; | |
| 16 using base::SequencedTaskRunner; | |
| 11 using base::TimeDelta; | 17 using base::TimeDelta; |
| 12 using base::SingleThreadTaskRunner; | |
| 13 | 18 |
| 14 namespace { | 19 namespace { |
| 15 | 20 |
| 16 // The message loops on which each timer should be tested. | 21 // The message loops on which each timer should be tested. |
| 17 const base::MessageLoop::Type testing_message_loops[] = { | 22 const base::MessageLoop::Type testing_message_loops[] = { |
| 18 base::MessageLoop::TYPE_DEFAULT, | 23 base::MessageLoop::TYPE_DEFAULT, |
| 19 base::MessageLoop::TYPE_IO, | 24 base::MessageLoop::TYPE_IO, |
| 20 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. | 25 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. |
| 21 base::MessageLoop::TYPE_UI, | 26 base::MessageLoop::TYPE_UI, |
| 22 #endif | 27 #endif |
| 23 }; | 28 }; |
| 24 | 29 |
| 25 const int kNumTestingMessageLoops = arraysize(testing_message_loops); | 30 const int kNumTestingMessageLoops = arraysize(testing_message_loops); |
| 26 | 31 |
| 27 class OneShotTimerTester { | 32 class OneShotTimerTester { |
| 28 public: | 33 public: |
| 29 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) | 34 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) |
| 30 : did_run_(did_run), | 35 : did_run_(did_run), |
| 31 delay_ms_(milliseconds), | 36 delay_ms_(milliseconds), |
| 32 quit_message_loop_(true) { | 37 quit_message_loop_(true) { |
| 33 } | 38 } |
| 34 | 39 |
| 35 void Start() { | 40 void Start() { |
| 36 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, | 41 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, |
| 37 &OneShotTimerTester::Run); | 42 &OneShotTimerTester::Run); |
| 38 } | 43 } |
| 39 | 44 |
| 40 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { | 45 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { |
| 41 quit_message_loop_ = false; | 46 quit_message_loop_ = false; |
| 42 timer_.SetTaskRunner(task_runner); | 47 timer_.SetTaskRunner(task_runner); |
| 43 } | 48 } |
| 44 | 49 |
| 45 private: | 50 private: |
| 46 void Run() { | 51 void Run() { |
| 47 *did_run_ = true; | 52 *did_run_ = true; |
| 48 if (quit_message_loop_) { | 53 if (quit_message_loop_) { |
| 49 base::MessageLoop::current()->QuitWhenIdle(); | 54 base::MessageLoop::current()->QuitWhenIdle(); |
| 50 } | 55 } |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 521 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 526 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
| 522 base::Bind(&SetCallbackHappened1)); | 527 base::Bind(&SetCallbackHappened1)); |
| 523 timer.Reset(); | 528 timer.Reset(); |
| 524 // Since Reset happened before task ran, the user_task must not be cleared: | 529 // Since Reset happened before task ran, the user_task must not be cleared: |
| 525 ASSERT_FALSE(timer.user_task().is_null()); | 530 ASSERT_FALSE(timer.user_task().is_null()); |
| 526 base::MessageLoop::current()->Run(); | 531 base::MessageLoop::current()->Run(); |
| 527 EXPECT_TRUE(g_callback_happened1); | 532 EXPECT_TRUE(g_callback_happened1); |
| 528 } | 533 } |
| 529 } | 534 } |
| 530 | 535 |
| 536 const size_t kNumWorkerThreads = 3; | |
| 537 | |
| 538 // Fixture for tests requiring a worker pool. Includes a WaitableEvent so | |
| 539 // that cases may Wait() on one thread and Signal() (explicitly, or implicitly | |
| 540 // via helper methods) on another. | |
| 541 class TimerSequenceTest : public testing::Test { | |
| 542 public: | |
| 543 TimerSequenceTest() | |
| 544 : event_(false /* manual_reset */, false /* initially_signaled */) {} | |
| 545 | |
| 546 void SetUp() override { ResetPools(); } | |
| 547 | |
| 548 void TearDown() override { | |
| 549 pool1()->Shutdown(); | |
| 550 pool2()->Shutdown(); | |
| 551 } | |
| 552 | |
| 553 // Block until Signal() is called on another thread. | |
| 554 void Wait() { event_.Wait(); } | |
| 555 | |
| 556 void Signal() { event_.Signal(); } | |
| 557 | |
| 558 // Helper to augment a task with a subsequent call to Signal(). | |
| 559 base::Closure TaskWithSignal(const base::Closure& task) { | |
| 560 return base::Bind(&TimerSequenceTest::RunTaskAndSignal, | |
| 561 base::Unretained(this), task); | |
| 562 } | |
| 563 | |
| 564 // Create the timer. | |
| 565 void CreateTimer() { timer_.reset(new base::OneShotTimer); } | |
| 566 | |
| 567 // Schedule an event on the timer. | |
| 568 void StartTimer(TimeDelta delay, const base::Closure& task) { | |
| 569 timer_->Start(FROM_HERE, delay, task); | |
| 570 } | |
| 571 | |
| 572 // Tell the timer to abandon the task. | |
| 573 void AbandonTask() { | |
| 574 ASSERT_TRUE(timer_->IsRunning()); | |
| 575 // Reset() to call Timer::AbandonScheduledTask() | |
| 576 timer_->Reset(); | |
| 577 ASSERT_TRUE(timer_->IsRunning()); | |
| 578 timer_->Stop(); | |
| 579 ASSERT_FALSE(timer_->IsRunning()); | |
| 580 } | |
| 581 | |
| 582 static void VerifyAffinity(scoped_refptr<SequencedTaskRunner> task_runner) { | |
| 583 ASSERT_TRUE(task_runner->RunsTasksOnCurrentThread()); | |
| 584 } | |
| 585 | |
| 586 // Delete the timer. | |
| 587 void DeleteTimer() { timer_.reset(); } | |
| 588 | |
| 589 protected: | |
| 590 const scoped_refptr<base::SequencedWorkerPool>& pool1() { | |
| 591 return pool1_owner_->pool(); | |
| 592 } | |
| 593 const scoped_refptr<base::SequencedWorkerPool>& pool2() { | |
| 594 return pool2_owner_->pool(); | |
| 595 } | |
| 596 | |
| 597 // Destroys the SequencedWorkerPool instance, blocking until it is fully shut | |
| 598 // down, and creates a new instance. | |
| 599 void ResetPools() { | |
| 600 pool1_owner_.reset( | |
| 601 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); | |
| 602 pool2_owner_.reset( | |
| 603 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); | |
| 604 } | |
| 605 | |
| 606 scoped_ptr<base::OneShotTimer> timer_; | |
|
gab
2015/12/15 16:47:41
Feels like this should either be private (i.e. als
jsbell
2015/12/15 18:54:05
Done.
| |
| 607 | |
| 608 private: | |
| 609 void RunTaskAndSignal(const base::Closure& task) { | |
| 610 task.Run(); | |
| 611 Signal(); | |
| 612 } | |
| 613 | |
| 614 base::WaitableEvent event_; | |
| 615 | |
| 616 base::MessageLoop message_loop_; | |
| 617 scoped_ptr<base::SequencedWorkerPoolOwner> pool1_owner_; | |
| 618 scoped_ptr<base::SequencedWorkerPoolOwner> pool2_owner_; | |
| 619 | |
| 620 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); | |
| 621 }; | |
| 622 | |
| 623 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { | |
| 624 scoped_refptr<SequencedTaskRunner> task_runner = | |
| 625 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 626 | |
| 627 // Timer is created on this thread. | |
| 628 CreateTimer(); | |
| 629 | |
| 630 // Task will execute on a pool thread. | |
| 631 timer_->SetTaskRunner(task_runner.get()); | |
| 632 StartTimer(TimeDelta::FromMilliseconds(1), | |
| 633 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this))); | |
| 634 Wait(); | |
| 635 | |
| 636 // Timer will be destroyed on this thread. | |
| 637 timer_.reset(); | |
| 638 } | |
| 639 | |
| 640 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { | |
| 641 scoped_refptr<SequencedTaskRunner> task_runner = | |
| 642 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 643 | |
| 644 // Timer is created on this thread. | |
| 645 CreateTimer(); | |
| 646 | |
| 647 // Task will be scheduled from a pool thread. | |
| 648 task_runner->PostTask( | |
| 649 FROM_HERE, | |
| 650 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 651 TimeDelta::FromMilliseconds(1), | |
| 652 TaskWithSignal(base::Bind(&DoNothing)))); | |
|
gab
2015/12/15 16:47:41
Isn't TaskWithSignal(base::Bind(&DoNothing)) just
jsbell
2015/12/15 18:54:05
Done.
| |
| 653 Wait(); | |
| 654 | |
| 655 // Timer must be destroyed on pool thread, too. | |
| 656 task_runner->PostTask( | |
| 657 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 658 base::Unretained(this)))); | |
| 659 Wait(); | |
| 660 } | |
| 661 | |
| 662 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { | |
| 663 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
| 664 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 665 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
| 666 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
| 667 | |
| 668 // Create timer on pool #1. | |
| 669 task_runner1->PostTask( | |
| 670 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
| 671 base::Unretained(this)))); | |
| 672 Wait(); | |
| 673 | |
| 674 // Task will execute on a different pool (#2). | |
| 675 timer_->SetTaskRunner(task_runner2.get()); | |
| 676 | |
| 677 // Task will be scheduled from pool #1. | |
| 678 task_runner1->PostTask( | |
| 679 FROM_HERE, | |
| 680 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 681 TimeDelta::FromHours(1), base::Bind(&DoNothing))); | |
| 682 | |
| 683 // Abandon task - must be called from scheduling pool (#1). | |
| 684 task_runner1->PostTask( | |
| 685 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::AbandonTask, | |
| 686 base::Unretained(this)))); | |
| 687 Wait(); | |
| 688 | |
| 689 // Timer must be destroyed on the pool it was scheduled from (#1). | |
| 690 task_runner1->PostTask( | |
| 691 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 692 base::Unretained(this)))); | |
| 693 Wait(); | |
| 694 } | |
| 695 | |
| 696 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { | |
| 697 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
| 698 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 699 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
| 700 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
| 701 | |
| 702 // Create timer on pool #1. | |
| 703 task_runner1->PostTask( | |
| 704 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
| 705 base::Unretained(this)))); | |
| 706 Wait(); | |
| 707 | |
| 708 // Task will execute on a different pool (#2). | |
| 709 timer_->SetTaskRunner(task_runner2.get()); | |
| 710 | |
| 711 // Task will be scheduled from pool #1. | |
| 712 task_runner1->PostTask( | |
| 713 FROM_HERE, | |
| 714 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 715 TimeDelta::FromMilliseconds(1), | |
| 716 TaskWithSignal(base::Bind(&TimerSequenceTest::VerifyAffinity, | |
| 717 task_runner2)))); | |
| 718 | |
| 719 Wait(); | |
| 720 | |
| 721 // Timer must be destroyed on the pool it was scheduled from (#1). | |
| 722 task_runner1->PostTask( | |
| 723 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 724 base::Unretained(this)))); | |
| 725 Wait(); | |
| 726 } | |
| 727 | |
| 531 } // namespace | 728 } // namespace |
| OLD | NEW |