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 |