• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
WatchdogCounter(const TimeDelta & duration,const std::string & thread_watched_name,bool enabled)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 
~WatchdogCounter()28   virtual ~WatchdogCounter() {}
29 
Alarm()30   virtual void Alarm() {
31     alarm_counter_++;
32     Watchdog::Alarm();
33   }
34 
alarm_counter()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:
SetUp()45   void SetUp() {
46     Watchdog::ResetStaticData();
47   }
48 };
49 
50 }  // namespace
51 
52 //------------------------------------------------------------------------------
53 // Actual tests
54 
55 // Minimal constructor/destructor test.
TEST_F(WatchdogTest,StartupShutdownTest)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.
TEST_F(WatchdogTest,ArmDisarmTest)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.
TEST_F(WatchdogTest,AlarmTest)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.
TEST_F(WatchdogTest,AlarmPriorTimeTest)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.
TEST_F(WatchdogTest,ConstructorDisabledTest)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.
TEST_F(WatchdogTest,DisarmTest)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