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