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 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 |
531 } // namespace | 733 } // namespace |
OLD | NEW |