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