summaryrefslogtreecommitdiff
path: root/chromium/base/threading/watchdog_unittest.cc
blob: 7a4be4c764ca72b1584b2bebac76d4bd71c874d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/threading/watchdog.h"

#include "base/logging.h"
#include "base/synchronization/spin_wait.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {

namespace {

//------------------------------------------------------------------------------
// Provide a derived class to facilitate testing.

class WatchdogCounter : public Watchdog {
 public:
  WatchdogCounter(const TimeDelta& duration,
                  const std::string& thread_watched_name,
                  bool enabled)
      : Watchdog(duration, thread_watched_name, enabled),
        alarm_counter_(0) {
  }

  virtual ~WatchdogCounter() {}

  virtual void Alarm() OVERRIDE {
    alarm_counter_++;
    Watchdog::Alarm();
  }

  int alarm_counter() { return alarm_counter_; }

 private:
  int alarm_counter_;

  DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
};

class WatchdogTest : public testing::Test {
 public:
  virtual void SetUp() OVERRIDE {
    Watchdog::ResetStaticData();
  }
};

}  // namespace

//------------------------------------------------------------------------------
// Actual tests

// Minimal constructor/destructor test.
TEST_F(WatchdogTest, StartupShutdownTest) {
  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
}

// Test ability to call Arm and Disarm repeatedly.
TEST_F(WatchdogTest, ArmDisarmTest) {
  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
  watchdog1.Arm();
  watchdog1.Disarm();
  watchdog1.Arm();
  watchdog1.Disarm();

  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
  watchdog2.Arm();
  watchdog2.Disarm();
  watchdog2.Arm();
  watchdog2.Disarm();
}

// Make sure a basic alarm fires when the time has expired.
TEST_F(WatchdogTest, AlarmTest) {
  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
  watchdog.Arm();
  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
                                   watchdog.alarm_counter() > 0);
  EXPECT_EQ(1, watchdog.alarm_counter());
}

// Make sure a basic alarm fires when the time has expired.
TEST_F(WatchdogTest, AlarmPriorTimeTest) {
  WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
  // Set a time in the past.
  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
  // It should instantly go off, but certainly in less than 5 minutes.
  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
                                   watchdog.alarm_counter() > 0);

  EXPECT_EQ(1, watchdog.alarm_counter());
}

// Make sure a disable alarm does nothing, even if we arm it.
TEST_F(WatchdogTest, ConstructorDisabledTest) {
  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
  watchdog.Arm();
  // Alarm should not fire, as it was disabled.
  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
  EXPECT_EQ(0, watchdog.alarm_counter());
}

// Make sure Disarming will prevent firing, even after Arming.
TEST_F(WatchdogTest, DisarmTest) {
  WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);

  TimeTicks start = TimeTicks::Now();
  watchdog.Arm();
  // Sleep a bit, but not past the alarm point.
  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
  watchdog.Disarm();
  TimeTicks end = TimeTicks::Now();

  if (end - start > TimeDelta::FromMilliseconds(500)) {
    LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
                 << "timing-sensitive test suspicious.  Aborting now.";
    return;
  }

  // Alarm should not have fired before it was disarmed.
  EXPECT_EQ(0, watchdog.alarm_counter());

  // Sleep past the point where it would have fired if it wasn't disarmed,
  // and verify that it didn't fire.
  PlatformThread::Sleep(TimeDelta::FromSeconds(1));
  EXPECT_EQ(0, watchdog.alarm_counter());

  // ...but even after disarming, we can still use the alarm...
  // Set a time greater than the timeout into the past.
  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
  // It should almost instantly go off, but certainly in less than 5 minutes.
  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
                                   watchdog.alarm_counter() > 0);

  EXPECT_EQ(1, watchdog.alarm_counter());
}

}  // namespace base