Home | History | Annotate | Download | only in threading
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/threading/watchdog.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/spin_wait.h"
      9 #include "base/threading/platform_thread.h"
     10 #include "base/time.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace base {
     14 
     15 namespace {
     16 
     17 //------------------------------------------------------------------------------
     18 // Provide a derived class to facilitate testing.
     19 
     20 class WatchdogCounter : public Watchdog {
     21  public:
     22   WatchdogCounter(const TimeDelta& duration,
     23                   const std::string& thread_watched_name,
     24                   bool enabled)
     25       : Watchdog(duration, thread_watched_name, enabled), alarm_counter_(0) {
     26   }
     27 
     28   virtual ~WatchdogCounter() {}
     29 
     30   virtual void Alarm() {
     31     alarm_counter_++;
     32     Watchdog::Alarm();
     33   }
     34 
     35   int alarm_counter() { return alarm_counter_; }
     36 
     37  private:
     38   int alarm_counter_;
     39 
     40   DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
     41 };
     42 
     43 class WatchdogTest : public testing::Test {
     44  public:
     45   void SetUp() {
     46     Watchdog::ResetStaticData();
     47   }
     48 };
     49 
     50 }  // namespace
     51 
     52 //------------------------------------------------------------------------------
     53 // Actual tests
     54 
     55 // Minimal constructor/destructor test.
     56 TEST_F(WatchdogTest, StartupShutdownTest) {
     57   Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
     58   Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
     59 }
     60 
     61 // Test ability to call Arm and Disarm repeatedly.
     62 TEST_F(WatchdogTest, ArmDisarmTest) {
     63   Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
     64   watchdog1.Arm();
     65   watchdog1.Disarm();
     66   watchdog1.Arm();
     67   watchdog1.Disarm();
     68 
     69   Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
     70   watchdog2.Arm();
     71   watchdog2.Disarm();
     72   watchdog2.Arm();
     73   watchdog2.Disarm();
     74 }
     75 
     76 // Make sure a basic alarm fires when the time has expired.
     77 TEST_F(WatchdogTest, AlarmTest) {
     78   WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
     79   watchdog.Arm();
     80   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
     81                                    watchdog.alarm_counter() > 0);
     82   EXPECT_EQ(1, watchdog.alarm_counter());
     83 }
     84 
     85 // Make sure a basic alarm fires when the time has expired.
     86 TEST_F(WatchdogTest, AlarmPriorTimeTest) {
     87   WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
     88   // Set a time in the past.
     89   watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
     90   // It should instantly go off, but certainly in less than 5 minutes.
     91   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
     92                                    watchdog.alarm_counter() > 0);
     93 
     94   EXPECT_EQ(1, watchdog.alarm_counter());
     95 }
     96 
     97 // Make sure a disable alarm does nothing, even if we arm it.
     98 TEST_F(WatchdogTest, ConstructorDisabledTest) {
     99   WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
    100   watchdog.Arm();
    101   // Alarm should not fire, as it was disabled.
    102   PlatformThread::Sleep(500);
    103   EXPECT_EQ(0, watchdog.alarm_counter());
    104 }
    105 
    106 // Make sure Disarming will prevent firing, even after Arming.
    107 TEST_F(WatchdogTest, DisarmTest) {
    108   WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
    109 
    110   TimeTicks start = TimeTicks::Now();
    111   watchdog.Arm();
    112   PlatformThread::Sleep(100);  // Sleep a bit, but not past the alarm point.
    113   watchdog.Disarm();
    114   TimeTicks end = TimeTicks::Now();
    115 
    116   if (end - start > TimeDelta::FromMilliseconds(500)) {
    117     LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
    118                  << "timing-sensitive test suspicious.  Aborting now.";
    119     return;
    120   }
    121 
    122   // Alarm should not have fired before it was disarmed.
    123   EXPECT_EQ(0, watchdog.alarm_counter());
    124 
    125   // Sleep past the point where it would have fired if it wasn't disarmed,
    126   // and verify that it didn't fire.
    127   PlatformThread::Sleep(1000);
    128   EXPECT_EQ(0, watchdog.alarm_counter());
    129 
    130   // ...but even after disarming, we can still use the alarm...
    131   // Set a time greater than the timeout into the past.
    132   watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
    133   // It should almost instantly go off, but certainly in less than 5 minutes.
    134   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
    135                                    watchdog.alarm_counter() > 0);
    136 
    137   EXPECT_EQ(1, watchdog.alarm_counter());
    138 }
    139 
    140 }  // namespace base
    141