| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "base/timer/timer.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/bind_helpers.h" | 
 | #include "base/callback.h" | 
 | #include "base/macros.h" | 
 | #include "base/memory/ptr_util.h" | 
 | #include "base/memory/ref_counted.h" | 
 | #include "base/message_loop/message_loop.h" | 
 | #include "base/metrics/statistics_recorder.h" | 
 | #include "base/run_loop.h" | 
 | #include "base/sequenced_task_runner.h" | 
 | #include "base/synchronization/waitable_event.h" | 
 | #include "base/task/post_task.h" | 
 | #include "base/test/scoped_task_environment.h" | 
 | #include "base/test/test_mock_time_task_runner.h" | 
 | #include "base/threading/platform_thread.h" | 
 | #include "base/threading/sequenced_task_runner_handle.h" | 
 | #include "base/threading/thread.h" | 
 | #include "base/time/tick_clock.h" | 
 | #include "base/time/time.h" | 
 | #include "build/build_config.h" | 
 | #include "starboard/types.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace base { | 
 |  | 
 | namespace { | 
 |  | 
 | // The message loops on which each timer should be tested. | 
 | const MessageLoop::Type testing_message_loops[] = { | 
 |     MessageLoop::TYPE_DEFAULT, MessageLoop::TYPE_IO, | 
 | #if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop. | 
 |     MessageLoop::TYPE_UI, | 
 | #endif | 
 | }; | 
 |  | 
 | const int kNumTestingMessageLoops = arraysize(testing_message_loops); | 
 |  | 
 | class Receiver { | 
 |  public: | 
 |   Receiver() : count_(0) {} | 
 |   void OnCalled() { count_++; } | 
 |   bool WasCalled() { return count_ > 0; } | 
 |   int TimesCalled() { return count_; } | 
 |  | 
 |  private: | 
 |   int count_; | 
 | }; | 
 |  | 
 | // A basic helper class that can start a one-shot timer and signal a | 
 | // WaitableEvent when this timer fires. | 
 | class OneShotTimerTesterBase { | 
 |  public: | 
 |   // |did_run|, if provided, will be signaled when Run() fires. | 
 |   explicit OneShotTimerTesterBase( | 
 |       WaitableEvent* did_run = nullptr, | 
 |       const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) | 
 |       : did_run_(did_run), delay_(delay) {} | 
 |  | 
 |   virtual ~OneShotTimerTesterBase() = default; | 
 |  | 
 |   void Start() { | 
 |     started_time_ = TimeTicks::Now(); | 
 |     timer_->Start(FROM_HERE, delay_, this, &OneShotTimerTesterBase::Run); | 
 |   } | 
 |  | 
 |   bool IsRunning() { return timer_->IsRunning(); } | 
 |  | 
 |   TimeTicks started_time() const { return started_time_; } | 
 |   TimeDelta delay() const { return delay_; } | 
 |  | 
 |  protected: | 
 |   virtual void Run() { | 
 |     if (did_run_) { | 
 |       EXPECT_FALSE(did_run_->IsSignaled()); | 
 |       did_run_->Signal(); | 
 |     } | 
 |   } | 
 |  | 
 |   std::unique_ptr<OneShotTimer> timer_ = std::make_unique<OneShotTimer>(); | 
 |  | 
 |  private: | 
 |   WaitableEvent* const did_run_; | 
 |   const TimeDelta delay_; | 
 |   TimeTicks started_time_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(OneShotTimerTesterBase); | 
 | }; | 
 |  | 
 | // Extends functionality of OneShotTimerTesterBase with the abilities to wait | 
 | // until the timer fires and to change task runner for the timer. | 
 | class OneShotTimerTester : public OneShotTimerTesterBase { | 
 |  public: | 
 |   // |did_run|, if provided, will be signaled when Run() fires. | 
 |   explicit OneShotTimerTester( | 
 |       WaitableEvent* did_run = nullptr, | 
 |       const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) | 
 |       : OneShotTimerTesterBase(did_run, delay), | 
 |         quit_closure_(run_loop_.QuitClosure()) {} | 
 |  | 
 |   ~OneShotTimerTester() override = default; | 
 |  | 
 |   void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { | 
 |     timer_->SetTaskRunner(std::move(task_runner)); | 
 |  | 
 |     // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure | 
 |     // needs to run on this thread (where the MessageLoop lives). | 
 |     quit_closure_ = BindOnce(IgnoreResult(&SequencedTaskRunner::PostTask), | 
 |                              SequencedTaskRunnerHandle::Get(), FROM_HERE, | 
 |                              run_loop_.QuitClosure()); | 
 |   } | 
 |  | 
 |   // Blocks until Run() executes and confirms that Run() didn't fire before | 
 |   // |delay_| expired. | 
 |   void WaitAndConfirmTimerFiredAfterDelay() { | 
 |     run_loop_.Run(); | 
 |  | 
 |     EXPECT_NE(TimeTicks(), started_time()); | 
 |     EXPECT_GE(TimeTicks::Now() - started_time(), delay()); | 
 |   } | 
 |  | 
 |  protected: | 
 |   // Overridable method to do things on Run() before signaling events/closures | 
 |   // managed by this helper. | 
 |   virtual void OnRun() {} | 
 |  | 
 |  private: | 
 |   void Run() override { | 
 |     OnRun(); | 
 |     OneShotTimerTesterBase::Run(); | 
 |     std::move(quit_closure_).Run(); | 
 |   } | 
 |  | 
 |   RunLoop run_loop_; | 
 |   OnceClosure quit_closure_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(OneShotTimerTester); | 
 | }; | 
 |  | 
 | class OneShotSelfDeletingTimerTester : public OneShotTimerTester { | 
 |  protected: | 
 |   void OnRun() override { timer_.reset(); } | 
 | }; | 
 |  | 
 | constexpr int kNumRepeats = 10; | 
 |  | 
 | class RepeatingTimerTester { | 
 |  public: | 
 |   explicit RepeatingTimerTester(WaitableEvent* did_run, const TimeDelta& delay) | 
 |       : counter_(kNumRepeats), | 
 |         quit_closure_(run_loop_.QuitClosure()), | 
 |         did_run_(did_run), | 
 |         delay_(delay) {} | 
 |  | 
 |   void Start() { | 
 |     started_time_ = TimeTicks::Now(); | 
 |     timer_.Start(FROM_HERE, delay_, this, &RepeatingTimerTester::Run); | 
 |   } | 
 |  | 
 |   void WaitAndConfirmTimerFiredRepeatedlyAfterDelay() { | 
 |     run_loop_.Run(); | 
 |  | 
 |     EXPECT_NE(TimeTicks(), started_time_); | 
 |     EXPECT_GE(TimeTicks::Now() - started_time_, kNumRepeats * delay_); | 
 |   } | 
 |  | 
 |  private: | 
 |   void Run() { | 
 |     if (--counter_ == 0) { | 
 |       if (did_run_) { | 
 |         EXPECT_FALSE(did_run_->IsSignaled()); | 
 |         did_run_->Signal(); | 
 |       } | 
 |       timer_.Stop(); | 
 |       quit_closure_.Run(); | 
 |     } | 
 |   } | 
 |  | 
 |   RepeatingTimer timer_; | 
 |   int counter_; | 
 |  | 
 |   RunLoop run_loop_; | 
 |   Closure quit_closure_; | 
 |   WaitableEvent* const did_run_; | 
 |  | 
 |   const TimeDelta delay_; | 
 |   TimeTicks started_time_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(RepeatingTimerTester); | 
 | }; | 
 |  | 
 | // Basic test with same setup as RunTest_OneShotTimers_Cancel below to confirm | 
 | // that |did_run_a| would be signaled in that test if it wasn't for the | 
 | // deletion. | 
 | void RunTest_OneShotTimers(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, | 
 |                           WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   OneShotTimerTester a(&did_run_a); | 
 |   a.Start(); | 
 |  | 
 |   OneShotTimerTester b; | 
 |   b.Start(); | 
 |  | 
 |   b.WaitAndConfirmTimerFiredAfterDelay(); | 
 |  | 
 |   EXPECT_TRUE(did_run_a.IsSignaled()); | 
 | } | 
 |  | 
 | void RunTest_OneShotTimers_Cancel(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, | 
 |                           WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   OneShotTimerTester* a = new OneShotTimerTester(&did_run_a); | 
 |  | 
 |   // This should run before the timer expires. | 
 |   SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a); | 
 |  | 
 |   // Now start the timer. | 
 |   a->Start(); | 
 |  | 
 |   OneShotTimerTester b; | 
 |   b.Start(); | 
 |  | 
 |   b.WaitAndConfirmTimerFiredAfterDelay(); | 
 |  | 
 |   EXPECT_FALSE(did_run_a.IsSignaled()); | 
 | } | 
 |  | 
 | void RunTest_OneShotSelfDeletingTimer(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   OneShotSelfDeletingTimerTester f; | 
 |   f.Start(); | 
 |   f.WaitAndConfirmTimerFiredAfterDelay(); | 
 | } | 
 |  | 
 | void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type, | 
 |                             const TimeDelta& delay) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   RepeatingTimerTester f(nullptr, delay); | 
 |   f.Start(); | 
 |   f.WaitAndConfirmTimerFiredRepeatedlyAfterDelay(); | 
 | } | 
 |  | 
 | void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type, | 
 |                                    const TimeDelta& delay) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   WaitableEvent did_run_a(WaitableEvent::ResetPolicy::MANUAL, | 
 |                           WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a, delay); | 
 |  | 
 |   // This should run before the timer expires. | 
 |   SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, a); | 
 |  | 
 |   // Now start the timer. | 
 |   a->Start(); | 
 |  | 
 |   RepeatingTimerTester b(nullptr, delay); | 
 |   b.Start(); | 
 |  | 
 |   b.WaitAndConfirmTimerFiredRepeatedlyAfterDelay(); | 
 |  | 
 |   // |a| should not have fired despite |b| starting after it on the same | 
 |   // sequence and being complete by now. | 
 |   EXPECT_FALSE(did_run_a.IsSignaled()); | 
 | } | 
 |  | 
 | class DelayTimerTarget { | 
 |  public: | 
 |   bool signaled() const { return signaled_; } | 
 |  | 
 |   void Signal() { | 
 |     ASSERT_FALSE(signaled_); | 
 |     signaled_ = true; | 
 |   } | 
 |  | 
 |  private: | 
 |   bool signaled_ = false; | 
 | }; | 
 |  | 
 | void RunTest_DelayTimer_NoCall(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   // If Delay is never called, the timer shouldn't go off. | 
 |   DelayTimerTarget target; | 
 |   DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target, | 
 |                    &DelayTimerTarget::Signal); | 
 |  | 
 |   OneShotTimerTester tester; | 
 |   tester.Start(); | 
 |   tester.WaitAndConfirmTimerFiredAfterDelay(); | 
 |  | 
 |   ASSERT_FALSE(target.signaled()); | 
 | } | 
 |  | 
 | void RunTest_DelayTimer_OneCall(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   DelayTimerTarget target; | 
 |   DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(1), &target, | 
 |                    &DelayTimerTarget::Signal); | 
 |   timer.Reset(); | 
 |  | 
 |   OneShotTimerTester tester(nullptr, TimeDelta::FromMilliseconds(100)); | 
 |   tester.Start(); | 
 |   tester.WaitAndConfirmTimerFiredAfterDelay(); | 
 |  | 
 |   ASSERT_TRUE(target.signaled()); | 
 | } | 
 |  | 
 | struct ResetHelper { | 
 |   ResetHelper(DelayTimer* timer, DelayTimerTarget* target) | 
 |       : timer_(timer), target_(target) {} | 
 |  | 
 |   void Reset() { | 
 |     ASSERT_FALSE(target_->signaled()); | 
 |     timer_->Reset(); | 
 |   } | 
 |  | 
 |  private: | 
 |   DelayTimer* const timer_; | 
 |   DelayTimerTarget* const target_; | 
 | }; | 
 |  | 
 | void RunTest_DelayTimer_Reset(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   // If Delay is never called, the timer shouldn't go off. | 
 |   DelayTimerTarget target; | 
 |   DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target, | 
 |                    &DelayTimerTarget::Signal); | 
 |   timer.Reset(); | 
 |  | 
 |   ResetHelper reset_helper(&timer, &target); | 
 |  | 
 |   OneShotTimer timers[20]; | 
 |   for (size_t i = 0; i < arraysize(timers); ++i) { | 
 |     timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10), | 
 |                     &reset_helper, &ResetHelper::Reset); | 
 |   } | 
 |  | 
 |   OneShotTimerTester tester(nullptr, TimeDelta::FromMilliseconds(300)); | 
 |   tester.Start(); | 
 |   tester.WaitAndConfirmTimerFiredAfterDelay(); | 
 |  | 
 |   ASSERT_TRUE(target.signaled()); | 
 | } | 
 |  | 
 | class DelayTimerFatalTarget { | 
 |  public: | 
 |   void Signal() { | 
 |     ASSERT_TRUE(false); | 
 |   } | 
 | }; | 
 |  | 
 | void RunTest_DelayTimer_Deleted(MessageLoop::Type message_loop_type) { | 
 | #if defined(STARBOARD) | 
 |   if (message_loop_type == MessageLoop::TYPE_UI) { | 
 |     return; | 
 |   } | 
 | #endif | 
 |  | 
 |   MessageLoop loop(message_loop_type); | 
 |  | 
 |   DelayTimerFatalTarget target; | 
 |  | 
 |   { | 
 |     DelayTimer timer(FROM_HERE, TimeDelta::FromMilliseconds(50), &target, | 
 |                      &DelayTimerFatalTarget::Signal); | 
 |     timer.Reset(); | 
 |   } | 
 |  | 
 |   // When the timer is deleted, the DelayTimerFatalTarget should never be | 
 |   // called. | 
 |   PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | //----------------------------------------------------------------------------- | 
 | // Each test is run against each type of MessageLoop.  That way we are sure | 
 | // that timers work properly in all configurations. | 
 |  | 
 | TEST(TimerTest, OneShotTimers) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_OneShotTimers(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, OneShotTimers_Cancel) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_OneShotTimers_Cancel(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | // If underline timer does not handle properly, we will crash or fail | 
 | // in full page heap environment. | 
 | TEST(TimerTest, OneShotSelfDeletingTimer) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, OneShotTimer_CustomTaskRunner) { | 
 |   // A MessageLoop is required for the timer events on the other thread to | 
 |   // communicate back to the Timer under test. | 
 |   MessageLoop loop; | 
 |  | 
 |   Thread other_thread("OneShotTimer_CustomTaskRunner"); | 
 |   other_thread.Start(); | 
 |  | 
 |   WaitableEvent did_run(WaitableEvent::ResetPolicy::MANUAL, | 
 |                         WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   OneShotTimerTester f(&did_run); | 
 |   f.SetTaskRunner(other_thread.task_runner()); | 
 |   f.Start(); | 
 |   EXPECT_TRUE(f.IsRunning() || did_run.IsSignaled()); | 
 |  | 
 |   f.WaitAndConfirmTimerFiredAfterDelay(); | 
 |   EXPECT_TRUE(did_run.IsSignaled()); | 
 |  | 
 |   // |f| should already have communicated back to this |loop| before invoking | 
 |   // Run() and as such this thread should already be aware that |f| is no longer | 
 |   // running. | 
 |   EXPECT_TRUE(loop.IsIdleForTesting()); | 
 |   EXPECT_FALSE(f.IsRunning()); | 
 | } | 
 |  | 
 | TEST(TimerTest, OneShotTimerWithTickClock) { | 
 |   scoped_refptr<TestMockTimeTaskRunner> task_runner( | 
 |       new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); | 
 |   MessageLoop message_loop; | 
 |   message_loop.SetTaskRunner(task_runner); | 
 |   Receiver receiver; | 
 |   OneShotTimer timer(task_runner->GetMockTickClock()); | 
 |   timer.Start(FROM_HERE, TimeDelta::FromSeconds(1), | 
 |               BindOnce(&Receiver::OnCalled, Unretained(&receiver))); | 
 |   task_runner->FastForwardBy(TimeDelta::FromSeconds(1)); | 
 |   EXPECT_TRUE(receiver.WasCalled()); | 
 | } | 
 |  | 
 | TEST(TimerTest, RepeatingTimer) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_RepeatingTimer(testing_message_loops[i], | 
 |                            TimeDelta::FromMilliseconds(10)); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, RepeatingTimer_Cancel) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_RepeatingTimer_Cancel(testing_message_loops[i], | 
 |                                   TimeDelta::FromMilliseconds(10)); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, RepeatingTimerZeroDelay) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_RepeatingTimer(testing_message_loops[i], | 
 |                            TimeDelta::FromMilliseconds(0)); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_RepeatingTimer_Cancel(testing_message_loops[i], | 
 |                                   TimeDelta::FromMilliseconds(0)); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, RepeatingTimerWithTickClock) { | 
 |   scoped_refptr<TestMockTimeTaskRunner> task_runner( | 
 |       new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); | 
 |   MessageLoop message_loop; | 
 |   message_loop.SetTaskRunner(task_runner); | 
 |   Receiver receiver; | 
 |   const int expected_times_called = 10; | 
 |   RepeatingTimer timer(task_runner->GetMockTickClock()); | 
 |   timer.Start(FROM_HERE, TimeDelta::FromSeconds(1), | 
 |               BindRepeating(&Receiver::OnCalled, Unretained(&receiver))); | 
 |   task_runner->FastForwardBy(TimeDelta::FromSeconds(expected_times_called)); | 
 |   timer.Stop(); | 
 |   EXPECT_EQ(expected_times_called, receiver.TimesCalled()); | 
 | } | 
 |  | 
 | TEST(TimerTest, DelayTimer_NoCall) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_DelayTimer_NoCall(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, DelayTimer_OneCall) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_DelayTimer_OneCall(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | // It's flaky on the buildbot, http://crbug.com/25038. | 
 | TEST(TimerTest, DISABLED_DelayTimer_Reset) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_DelayTimer_Reset(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, DelayTimer_Deleted) { | 
 |   for (int i = 0; i < kNumTestingMessageLoops; i++) { | 
 |     RunTest_DelayTimer_Deleted(testing_message_loops[i]); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, DelayTimerWithTickClock) { | 
 |   scoped_refptr<TestMockTimeTaskRunner> task_runner( | 
 |       new TestMockTimeTaskRunner(Time::Now(), TimeTicks::Now())); | 
 |   MessageLoop message_loop; | 
 |   message_loop.SetTaskRunner(task_runner); | 
 |   Receiver receiver; | 
 |   DelayTimer timer(FROM_HERE, TimeDelta::FromSeconds(1), &receiver, | 
 |                    &Receiver::OnCalled, task_runner->GetMockTickClock()); | 
 |   task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999)); | 
 |   EXPECT_FALSE(receiver.WasCalled()); | 
 |   timer.Reset(); | 
 |   task_runner->FastForwardBy(TimeDelta::FromMilliseconds(999)); | 
 |   EXPECT_FALSE(receiver.WasCalled()); | 
 |   timer.Reset(); | 
 |   task_runner->FastForwardBy(TimeDelta::FromSeconds(1)); | 
 |   EXPECT_TRUE(receiver.WasCalled()); | 
 | } | 
 |  | 
 | TEST(TimerTest, MessageLoopShutdown) { | 
 |   // This test is designed to verify that shutdown of the | 
 |   // message loop does not cause crashes if there were pending | 
 |   // timers not yet fired.  It may only trigger exceptions | 
 |   // if debug heap checking is enabled. | 
 |   WaitableEvent did_run(WaitableEvent::ResetPolicy::MANUAL, | 
 |                         WaitableEvent::InitialState::NOT_SIGNALED); | 
 |   { | 
 |     OneShotTimerTesterBase a(&did_run); | 
 |     OneShotTimerTesterBase b(&did_run); | 
 |     OneShotTimerTesterBase c(&did_run); | 
 |     OneShotTimerTesterBase d(&did_run); | 
 |     { | 
 |       MessageLoop loop; | 
 |       a.Start(); | 
 |       b.Start(); | 
 |     }  // MessageLoop destructs by falling out of scope. | 
 |   }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course. | 
 |  | 
 |   EXPECT_FALSE(did_run.IsSignaled()); | 
 | } | 
 |  | 
 | // Ref counted class which owns a Timer. The class passes a reference to itself | 
 | // via the |user_task| parameter in Timer::Start(). |Timer::user_task_| might | 
 | // end up holding the last reference to the class. | 
 | class OneShotSelfOwningTimerTester | 
 |     : public RefCounted<OneShotSelfOwningTimerTester> { | 
 |  public: | 
 |   OneShotSelfOwningTimerTester() = default; | 
 |  | 
 |   void StartTimer() { | 
 |     // Start timer with long delay in order to test the timer getting destroyed | 
 |     // while a timer task is still pending. | 
 |     timer_.Start(FROM_HERE, TimeDelta::FromDays(1), | 
 |                  BindOnce(&OneShotSelfOwningTimerTester::Run, this)); | 
 |   } | 
 |  | 
 |  private: | 
 |   friend class RefCounted<OneShotSelfOwningTimerTester>; | 
 |   ~OneShotSelfOwningTimerTester() = default; | 
 |  | 
 |   void Run() { | 
 |     ADD_FAILURE() << "Timer unexpectedly fired."; | 
 |   } | 
 |  | 
 |   OneShotTimer timer_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(OneShotSelfOwningTimerTester); | 
 | }; | 
 |  | 
 | TEST(TimerTest, MessageLoopShutdownSelfOwningTimer) { | 
 |   // This test verifies that shutdown of the message loop does not cause crashes | 
 |   // if there is a pending timer not yet fired and |Timer::user_task_| owns the | 
 |   // timer. The test may only trigger exceptions if debug heap checking is | 
 |   // enabled. | 
 |  | 
 |   MessageLoop loop; | 
 |   scoped_refptr<OneShotSelfOwningTimerTester> tester = | 
 |       new OneShotSelfOwningTimerTester(); | 
 |  | 
 |   std::move(tester)->StartTimer(); | 
 |   // |Timer::user_task_| owns sole reference to |tester|. | 
 |  | 
 |   // MessageLoop destructs by falling out of scope. SHOULD NOT CRASH. | 
 | } | 
 |  | 
 | void TimerTestCallback() { | 
 | } | 
 |  | 
 | TEST(TimerTest, NonRepeatIsRunning) { | 
 |   { | 
 |     MessageLoop loop; | 
 |     OneShotTimer timer; | 
 |     EXPECT_FALSE(timer.IsRunning()); | 
 |     timer.Start(FROM_HERE, TimeDelta::FromDays(1), | 
 |                 BindOnce(&TimerTestCallback)); | 
 |     EXPECT_TRUE(timer.IsRunning()); | 
 |     timer.Stop(); | 
 |     EXPECT_FALSE(timer.IsRunning()); | 
 |   } | 
 |  | 
 |   { | 
 |     RetainingOneShotTimer timer; | 
 |     MessageLoop loop; | 
 |     EXPECT_FALSE(timer.IsRunning()); | 
 |     timer.Start(FROM_HERE, TimeDelta::FromDays(1), | 
 |                 BindRepeating(&TimerTestCallback)); | 
 |     EXPECT_TRUE(timer.IsRunning()); | 
 |     timer.Stop(); | 
 |     EXPECT_FALSE(timer.IsRunning()); | 
 |     ASSERT_FALSE(timer.user_task().is_null()); | 
 |     timer.Reset(); | 
 |     EXPECT_TRUE(timer.IsRunning()); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, NonRepeatMessageLoopDeath) { | 
 |   OneShotTimer timer; | 
 |   { | 
 |     MessageLoop loop; | 
 |     EXPECT_FALSE(timer.IsRunning()); | 
 |     timer.Start(FROM_HERE, TimeDelta::FromDays(1), | 
 |                 BindOnce(&TimerTestCallback)); | 
 |     EXPECT_TRUE(timer.IsRunning()); | 
 |   } | 
 |   EXPECT_FALSE(timer.IsRunning()); | 
 | } | 
 |  | 
 | TEST(TimerTest, RetainRepeatIsRunning) { | 
 |   MessageLoop loop; | 
 |   RepeatingTimer timer(FROM_HERE, TimeDelta::FromDays(1), | 
 |                        BindRepeating(&TimerTestCallback)); | 
 |   EXPECT_FALSE(timer.IsRunning()); | 
 |   timer.Reset(); | 
 |   EXPECT_TRUE(timer.IsRunning()); | 
 |   timer.Stop(); | 
 |   EXPECT_FALSE(timer.IsRunning()); | 
 |   timer.Reset(); | 
 |   EXPECT_TRUE(timer.IsRunning()); | 
 | } | 
 |  | 
 | TEST(TimerTest, RetainNonRepeatIsRunning) { | 
 |   MessageLoop loop; | 
 |   RetainingOneShotTimer timer(FROM_HERE, TimeDelta::FromDays(1), | 
 |                               BindRepeating(&TimerTestCallback)); | 
 |   EXPECT_FALSE(timer.IsRunning()); | 
 |   timer.Reset(); | 
 |   EXPECT_TRUE(timer.IsRunning()); | 
 |   timer.Stop(); | 
 |   EXPECT_FALSE(timer.IsRunning()); | 
 |   timer.Reset(); | 
 |   EXPECT_TRUE(timer.IsRunning()); | 
 | } | 
 |  | 
 | //----------------------------------------------------------------------------- | 
 |  | 
 | namespace { | 
 |  | 
 | bool g_callback_happened1 = false; | 
 | bool g_callback_happened2 = false; | 
 |  | 
 | void ClearAllCallbackHappened() { | 
 |   g_callback_happened1 = false; | 
 |   g_callback_happened2 = false; | 
 | } | 
 |  | 
 | void SetCallbackHappened1() { | 
 |   g_callback_happened1 = true; | 
 |   RunLoop::QuitCurrentWhenIdleDeprecated(); | 
 | } | 
 |  | 
 | void SetCallbackHappened2() { | 
 |   g_callback_happened2 = true; | 
 |   RunLoop::QuitCurrentWhenIdleDeprecated(); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST(TimerTest, ContinuationStopStart) { | 
 |   { | 
 |     ClearAllCallbackHappened(); | 
 |     MessageLoop loop; | 
 |     OneShotTimer timer; | 
 |     timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 
 |                 BindOnce(&SetCallbackHappened1)); | 
 |     timer.Stop(); | 
 |     timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40), | 
 |                 BindOnce(&SetCallbackHappened2)); | 
 |     RunLoop().Run(); | 
 |     EXPECT_FALSE(g_callback_happened1); | 
 |     EXPECT_TRUE(g_callback_happened2); | 
 |   } | 
 | } | 
 |  | 
 | TEST(TimerTest, ContinuationReset) { | 
 |   { | 
 |     ClearAllCallbackHappened(); | 
 |     MessageLoop loop; | 
 |     OneShotTimer timer; | 
 |     timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 
 |                 BindOnce(&SetCallbackHappened1)); | 
 |     timer.Reset(); | 
 |     // // Since Reset happened before task ran, the user_task must not be | 
 |     // cleared: ASSERT_FALSE(timer.user_task().is_null()); | 
 |     RunLoop().Run(); | 
 |     EXPECT_TRUE(g_callback_happened1); | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // Fixture for tests requiring ScopedTaskEnvironment. Includes a WaitableEvent | 
 | // so that cases may Wait() on one thread and Signal() (explicitly, or | 
 | // implicitly via helper methods) on another. | 
 | class TimerSequenceTest : public testing::Test { | 
 |  public: | 
 |   TimerSequenceTest() | 
 |       : recorder_for_testing_(StatisticsRecorder::CreateTemporaryForTesting()), | 
 |         event_(WaitableEvent::ResetPolicy::AUTOMATIC, | 
 |                WaitableEvent::InitialState::NOT_SIGNALED) {} | 
 |  | 
 |   // Block until Signal() is called on another thread. | 
 |   void Wait() { event_.Wait(); } | 
 |  | 
 |   void Signal() { event_.Signal(); } | 
 |  | 
 |   // Helper to augment a task with a subsequent call to Signal(). | 
 |   OnceClosure TaskWithSignal(OnceClosure task) { | 
 |     return BindOnce(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), | 
 |                     std::move(task)); | 
 |   } | 
 |  | 
 |   // Create the timer. | 
 |   void CreateTimer() { timer_.reset(new OneShotTimer); } | 
 |  | 
 |   // Schedule an event on the timer. | 
 |   void StartTimer(TimeDelta delay, OnceClosure task) { | 
 |     timer_->Start(FROM_HERE, delay, std::move(task)); | 
 |   } | 
 |  | 
 |   void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) { | 
 |     timer_->SetTaskRunner(std::move(task_runner)); | 
 |   } | 
 |  | 
 |   // Tell the timer to abandon the task. | 
 |   void AbandonTask() { | 
 |     EXPECT_TRUE(timer_->IsRunning()); | 
 |     // Reset() to call Timer::AbandonScheduledTask() | 
 |     timer_->Reset(); | 
 |     EXPECT_TRUE(timer_->IsRunning()); | 
 |     timer_->Stop(); | 
 |     EXPECT_FALSE(timer_->IsRunning()); | 
 |   } | 
 |  | 
 |   static void VerifyAffinity(const SequencedTaskRunner* task_runner) { | 
 |     EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence()); | 
 |   } | 
 |  | 
 |   // Delete the timer. | 
 |   void DeleteTimer() { timer_.reset(); } | 
 |  | 
 |  private: | 
 |   void RunTaskAndSignal(OnceClosure task) { | 
 |     std::move(task).Run(); | 
 |     Signal(); | 
 |   } | 
 |  | 
 |   std::unique_ptr<StatisticsRecorder> recorder_for_testing_; | 
 |   base::test::ScopedTaskEnvironment scoped_task_environment_; | 
 |   WaitableEvent event_; | 
 |   std::unique_ptr<OneShotTimer> timer_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolSequence) { | 
 |   scoped_refptr<SequencedTaskRunner> task_runner = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |  | 
 |   base::RunLoop run_loop_; | 
 |  | 
 |   // Timer is created on this thread. | 
 |   CreateTimer(); | 
 |  | 
 |   // Task will execute on a pool thread. | 
 |   SetTaskRunnerForTimer(task_runner); | 
 |   StartTimer(TimeDelta::FromMilliseconds(1), | 
 |              BindOnce(IgnoreResult(&SequencedTaskRunner::PostTask), | 
 |                       SequencedTaskRunnerHandle::Get(), FROM_HERE, | 
 |                       run_loop_.QuitClosure())); | 
 |  | 
 |   // Spin the loop so that the delayed task fires on it, which will forward it | 
 |   // to |task_runner|. And since the Timer's task is one that posts back to this | 
 |   // MessageLoop to quit, we finally unblock. | 
 |   run_loop_.Run(); | 
 |  | 
 |   // Timer will be destroyed on this thread. | 
 |   DeleteTimer(); | 
 | } | 
 |  | 
 | TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolSequence) { | 
 |   scoped_refptr<SequencedTaskRunner> task_runner = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |  | 
 |   // Timer is created on this thread. | 
 |   CreateTimer(); | 
 |  | 
 |   // Task will be scheduled from a pool thread. | 
 |   task_runner->PostTask( | 
 |       FROM_HERE, | 
 |       BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), | 
 |                TimeDelta::FromMilliseconds(1), | 
 |                BindOnce(&TimerSequenceTest::Signal, Unretained(this)))); | 
 |   Wait(); | 
 |  | 
 |   // Timer must be destroyed on pool thread, too. | 
 |   task_runner->PostTask(FROM_HERE, | 
 |                         TaskWithSignal(BindOnce(&TimerSequenceTest::DeleteTimer, | 
 |                                                 Unretained(this)))); | 
 |   Wait(); | 
 | } | 
 |  | 
 | TEST_F(TimerSequenceTest, OneShotTimerTwoSequencesAbandonTask) { | 
 |   scoped_refptr<SequencedTaskRunner> task_runner1 = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |   scoped_refptr<SequencedTaskRunner> task_runner2 = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |  | 
 |   // Create timer on sequence #1. | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, TaskWithSignal(BindOnce(&TimerSequenceTest::CreateTimer, | 
 |                                          Unretained(this)))); | 
 |   Wait(); | 
 |  | 
 |   // And tell it to execute on a different sequence (#2). | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, | 
 |       TaskWithSignal(BindOnce(&TimerSequenceTest::SetTaskRunnerForTimer, | 
 |                               Unretained(this), task_runner2))); | 
 |   Wait(); | 
 |  | 
 |   // Task will be scheduled from sequence #1. | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), | 
 |                           TimeDelta::FromHours(1), DoNothing().Once())); | 
 |  | 
 |   // Abandon task - must be called from scheduling sequence (#1). | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, TaskWithSignal(BindOnce(&TimerSequenceTest::AbandonTask, | 
 |                                          Unretained(this)))); | 
 |   Wait(); | 
 |  | 
 |   // Timer must be destroyed on the sequence it was scheduled from (#1). | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, TaskWithSignal(BindOnce(&TimerSequenceTest::DeleteTimer, | 
 |                                          Unretained(this)))); | 
 |   Wait(); | 
 | } | 
 |  | 
 | TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentSequences) { | 
 |   scoped_refptr<SequencedTaskRunner> task_runner1 = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |   scoped_refptr<SequencedTaskRunner> task_runner2 = | 
 |       base::CreateSequencedTaskRunnerWithTraits({}); | 
 |  | 
 |   // Create timer on sequence #1. | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, TaskWithSignal(BindOnce(&TimerSequenceTest::CreateTimer, | 
 |                                          Unretained(this)))); | 
 |   Wait(); | 
 |  | 
 |   // And tell it to execute on a different sequence (#2). | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, | 
 |       TaskWithSignal(BindOnce(&TimerSequenceTest::SetTaskRunnerForTimer, | 
 |                               Unretained(this), task_runner2))); | 
 |   Wait(); | 
 |  | 
 |   // Task will be scheduled from sequence #1. | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, | 
 |       BindOnce(&TimerSequenceTest::StartTimer, Unretained(this), | 
 |                TimeDelta::FromMilliseconds(1), | 
 |                TaskWithSignal(BindOnce(&TimerSequenceTest::VerifyAffinity, | 
 |                                        Unretained(task_runner2.get()))))); | 
 |  | 
 |   Wait(); | 
 |  | 
 |   // Timer must be destroyed on the sequence it was scheduled from (#1). | 
 |   task_runner1->PostTask( | 
 |       FROM_HERE, TaskWithSignal(BindOnce(&TimerSequenceTest::DeleteTimer, | 
 |                                          Unretained(this)))); | 
 |   Wait(); | 
 | } | 
 |  | 
 | }  // namespace base |