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
13namespace base {
14
15namespace {
16
17//------------------------------------------------------------------------------
18// Provide a derived class to facilitate testing.
19
20class 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
43class 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.
56TEST_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.
62TEST_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.
77TEST_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.
86TEST_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.
98TEST_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.
107TEST_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