| 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" | |
| 7 #include "base/memory/scoped_ptr.h" | 5 #include "base/memory/scoped_ptr.h" |
| 8 #include "base/message_loop/message_loop.h" | 6 #include "base/message_loop/message_loop.h" |
| 9 #include "base/synchronization/waitable_event.h" | |
| 10 #include "base/test/sequenced_worker_pool_owner.h" | |
| 11 #include "base/test/test_simple_task_runner.h" | 7 #include "base/test/test_simple_task_runner.h" |
| 12 #include "base/timer/timer.h" | 8 #include "base/timer/timer.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 10 |
| 15 using base::DoNothing; | |
| 16 using base::SequencedTaskRunner; | |
| 17 using base::TimeDelta; | 11 using base::TimeDelta; |
| 12 using base::SingleThreadTaskRunner; |
| 18 | 13 |
| 19 namespace { | 14 namespace { |
| 20 | 15 |
| 21 // The message loops on which each timer should be tested. | 16 // The message loops on which each timer should be tested. |
| 22 const base::MessageLoop::Type testing_message_loops[] = { | 17 const base::MessageLoop::Type testing_message_loops[] = { |
| 23 base::MessageLoop::TYPE_DEFAULT, | 18 base::MessageLoop::TYPE_DEFAULT, |
| 24 base::MessageLoop::TYPE_IO, | 19 base::MessageLoop::TYPE_IO, |
| 25 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. | 20 #if !defined(OS_IOS) // iOS does not allow direct running of the UI loop. |
| 26 base::MessageLoop::TYPE_UI, | 21 base::MessageLoop::TYPE_UI, |
| 27 #endif | 22 #endif |
| 28 }; | 23 }; |
| 29 | 24 |
| 30 const int kNumTestingMessageLoops = arraysize(testing_message_loops); | 25 const int kNumTestingMessageLoops = arraysize(testing_message_loops); |
| 31 | 26 |
| 32 class OneShotTimerTester { | 27 class OneShotTimerTester { |
| 33 public: | 28 public: |
| 34 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) | 29 explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10) |
| 35 : did_run_(did_run), | 30 : did_run_(did_run), |
| 36 delay_ms_(milliseconds), | 31 delay_ms_(milliseconds), |
| 37 quit_message_loop_(true) { | 32 quit_message_loop_(true) { |
| 38 } | 33 } |
| 39 | 34 |
| 40 void Start() { | 35 void Start() { |
| 41 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, | 36 timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this, |
| 42 &OneShotTimerTester::Run); | 37 &OneShotTimerTester::Run); |
| 43 } | 38 } |
| 44 | 39 |
| 45 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { | 40 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { |
| 46 quit_message_loop_ = false; | 41 quit_message_loop_ = false; |
| 47 timer_.SetTaskRunner(task_runner); | 42 timer_.SetTaskRunner(task_runner); |
| 48 } | 43 } |
| 49 | 44 |
| 50 private: | 45 private: |
| 51 void Run() { | 46 void Run() { |
| 52 *did_run_ = true; | 47 *did_run_ = true; |
| 53 if (quit_message_loop_) { | 48 if (quit_message_loop_) { |
| 54 base::MessageLoop::current()->QuitWhenIdle(); | 49 base::MessageLoop::current()->QuitWhenIdle(); |
| 55 } | 50 } |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 526 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 521 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
| 527 base::Bind(&SetCallbackHappened1)); | 522 base::Bind(&SetCallbackHappened1)); |
| 528 timer.Reset(); | 523 timer.Reset(); |
| 529 // Since Reset happened before task ran, the user_task must not be cleared: | 524 // Since Reset happened before task ran, the user_task must not be cleared: |
| 530 ASSERT_FALSE(timer.user_task().is_null()); | 525 ASSERT_FALSE(timer.user_task().is_null()); |
| 531 base::MessageLoop::current()->Run(); | 526 base::MessageLoop::current()->Run(); |
| 532 EXPECT_TRUE(g_callback_happened1); | 527 EXPECT_TRUE(g_callback_happened1); |
| 533 } | 528 } |
| 534 } | 529 } |
| 535 | 530 |
| 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 void SetTaskRunnerForTimer(SequencedTaskRunner* task_runner) { | |
| 573 timer_->SetTaskRunner(task_runner); | |
| 574 } | |
| 575 | |
| 576 // Tell the timer to abandon the task. | |
| 577 void AbandonTask() { | |
| 578 ASSERT_TRUE(timer_->IsRunning()); | |
| 579 // Reset() to call Timer::AbandonScheduledTask() | |
| 580 timer_->Reset(); | |
| 581 ASSERT_TRUE(timer_->IsRunning()); | |
| 582 timer_->Stop(); | |
| 583 ASSERT_FALSE(timer_->IsRunning()); | |
| 584 } | |
| 585 | |
| 586 static void VerifyAffinity(SequencedTaskRunner* task_runner) { | |
| 587 ASSERT_TRUE(task_runner->RunsTasksOnCurrentThread()); | |
| 588 } | |
| 589 | |
| 590 // Delete the timer. | |
| 591 void DeleteTimer() { timer_.reset(); } | |
| 592 | |
| 593 protected: | |
| 594 const scoped_refptr<base::SequencedWorkerPool>& pool1() { | |
| 595 return pool1_owner_->pool(); | |
| 596 } | |
| 597 const scoped_refptr<base::SequencedWorkerPool>& pool2() { | |
| 598 return pool2_owner_->pool(); | |
| 599 } | |
| 600 | |
| 601 // Destroys the SequencedWorkerPool instance, blocking until it is fully shut | |
| 602 // down, and creates a new instance. | |
| 603 void ResetPools() { | |
| 604 pool1_owner_.reset( | |
| 605 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); | |
| 606 pool2_owner_.reset( | |
| 607 new base::SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); | |
| 608 } | |
| 609 | |
| 610 private: | |
| 611 void RunTaskAndSignal(const base::Closure& task) { | |
| 612 task.Run(); | |
| 613 Signal(); | |
| 614 } | |
| 615 | |
| 616 base::WaitableEvent event_; | |
| 617 | |
| 618 base::MessageLoop message_loop_; | |
| 619 scoped_ptr<base::SequencedWorkerPoolOwner> pool1_owner_; | |
| 620 scoped_ptr<base::SequencedWorkerPoolOwner> pool2_owner_; | |
| 621 | |
| 622 scoped_ptr<base::OneShotTimer> timer_; | |
| 623 | |
| 624 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); | |
| 625 }; | |
| 626 | |
| 627 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { | |
| 628 scoped_refptr<SequencedTaskRunner> task_runner = | |
| 629 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 630 | |
| 631 // Timer is created on this thread. | |
| 632 CreateTimer(); | |
| 633 | |
| 634 // Task will execute on a pool thread. | |
| 635 SetTaskRunnerForTimer(task_runner.get()); | |
| 636 StartTimer(TimeDelta::FromMilliseconds(1), | |
| 637 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this))); | |
| 638 Wait(); | |
| 639 | |
| 640 // Timer will be destroyed on this thread. | |
| 641 DeleteTimer(); | |
| 642 } | |
| 643 | |
| 644 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { | |
| 645 scoped_refptr<SequencedTaskRunner> task_runner = | |
| 646 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 647 | |
| 648 // Timer is created on this thread. | |
| 649 CreateTimer(); | |
| 650 | |
| 651 // Task will be scheduled from a pool thread. | |
| 652 task_runner->PostTask( | |
| 653 FROM_HERE, | |
| 654 base::Bind( | |
| 655 &TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 656 TimeDelta::FromMilliseconds(1), | |
| 657 base::Bind(&TimerSequenceTest::Signal, base::Unretained(this)))); | |
| 658 Wait(); | |
| 659 | |
| 660 // Timer must be destroyed on pool thread, too. | |
| 661 task_runner->PostTask( | |
| 662 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 663 base::Unretained(this)))); | |
| 664 Wait(); | |
| 665 } | |
| 666 | |
| 667 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { | |
| 668 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
| 669 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 670 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
| 671 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
| 672 | |
| 673 // Create timer on pool #1. | |
| 674 task_runner1->PostTask( | |
| 675 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
| 676 base::Unretained(this)))); | |
| 677 Wait(); | |
| 678 | |
| 679 // Task will execute on a different pool (#2). | |
| 680 SetTaskRunnerForTimer(task_runner2.get()); | |
| 681 | |
| 682 // Task will be scheduled from pool #1. | |
| 683 task_runner1->PostTask( | |
| 684 FROM_HERE, | |
| 685 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 686 TimeDelta::FromHours(1), base::Bind(&DoNothing))); | |
| 687 | |
| 688 // Abandon task - must be called from scheduling pool (#1). | |
| 689 task_runner1->PostTask( | |
| 690 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::AbandonTask, | |
| 691 base::Unretained(this)))); | |
| 692 Wait(); | |
| 693 | |
| 694 // Timer must be destroyed on the pool it was scheduled from (#1). | |
| 695 task_runner1->PostTask( | |
| 696 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 697 base::Unretained(this)))); | |
| 698 Wait(); | |
| 699 } | |
| 700 | |
| 701 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { | |
| 702 scoped_refptr<SequencedTaskRunner> task_runner1 = | |
| 703 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); | |
| 704 scoped_refptr<SequencedTaskRunner> task_runner2 = | |
| 705 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); | |
| 706 | |
| 707 // Create timer on pool #1. | |
| 708 task_runner1->PostTask( | |
| 709 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::CreateTimer, | |
| 710 base::Unretained(this)))); | |
| 711 Wait(); | |
| 712 | |
| 713 // Task will execute on a different pool (#2). | |
| 714 SetTaskRunnerForTimer(task_runner2.get()); | |
| 715 | |
| 716 // Task will be scheduled from pool #1. | |
| 717 task_runner1->PostTask( | |
| 718 FROM_HERE, | |
| 719 base::Bind(&TimerSequenceTest::StartTimer, base::Unretained(this), | |
| 720 TimeDelta::FromMilliseconds(1), | |
| 721 TaskWithSignal(base::Bind(&TimerSequenceTest::VerifyAffinity, | |
| 722 task_runner2)))); | |
| 723 | |
| 724 Wait(); | |
| 725 | |
| 726 // Timer must be destroyed on the pool it was scheduled from (#1). | |
| 727 task_runner1->PostTask( | |
| 728 FROM_HERE, TaskWithSignal(base::Bind(&TimerSequenceTest::DeleteTimer, | |
| 729 base::Unretained(this)))); | |
| 730 Wait(); | |
| 731 } | |
| 732 | |
| 733 } // namespace | 531 } // namespace |
| OLD | NEW |