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