xref: /aosp_15_r20/external/cronet/base/threading/watchdog_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 The Chromium Authors
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 <atomic>
8 
9 #include "base/logging.h"
10 #include "base/test/spin_wait.h"
11 #include "base/threading/platform_thread.h"
12 #include "base/time/time.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 namespace base {
16 
17 namespace {
18 
19 //------------------------------------------------------------------------------
20 // Provide a derived class to facilitate testing.
21 
22 class WatchdogCounter : public Watchdog::Delegate {
23  public:
WatchdogCounter(const TimeDelta & duration,const std::string & thread_watched_name,bool enabled)24   WatchdogCounter(const TimeDelta& duration,
25                   const std::string& thread_watched_name,
26                   bool enabled)
27       : watchdog_(duration, thread_watched_name, enabled, this) {}
28 
29   WatchdogCounter(const WatchdogCounter&) = delete;
30   WatchdogCounter& operator=(const WatchdogCounter&) = delete;
31 
32   ~WatchdogCounter() override = default;
33 
Alarm()34   void Alarm() override {
35     alarm_counter_++;
36     watchdog_.DefaultAlarm();
37   }
38 
watchdog()39   Watchdog& watchdog() { return watchdog_; }
alarm_counter()40   int alarm_counter() { return alarm_counter_.load(); }
41 
42  private:
43   std::atomic<int> alarm_counter_{0};
44   Watchdog watchdog_;
45 };
46 
47 class WatchdogTest : public testing::Test {
48  public:
SetUp()49   void SetUp() override { Watchdog::ResetStaticData(); }
50 };
51 
52 }  // namespace
53 
54 //------------------------------------------------------------------------------
55 // Actual tests
56 
57 // Minimal constructor/destructor test.
TEST_F(WatchdogTest,StartupShutdownTest)58 TEST_F(WatchdogTest, StartupShutdownTest) {
59   Watchdog watchdog1(Milliseconds(300), "Disabled", false);
60   Watchdog watchdog2(Milliseconds(300), "Enabled", true);
61 }
62 
63 // Test ability to call Arm and Disarm repeatedly.
TEST_F(WatchdogTest,ArmDisarmTest)64 TEST_F(WatchdogTest, ArmDisarmTest) {
65   Watchdog watchdog1(Milliseconds(300), "Disabled", false);
66   watchdog1.Arm();
67   watchdog1.Disarm();
68   watchdog1.Arm();
69   watchdog1.Disarm();
70 
71   Watchdog watchdog2(Milliseconds(300), "Enabled", true);
72   watchdog2.Arm();
73   watchdog2.Disarm();
74   watchdog2.Arm();
75   watchdog2.Disarm();
76 }
77 
78 // Make sure a basic alarm fires when the time has expired.
TEST_F(WatchdogTest,AlarmTest)79 TEST_F(WatchdogTest, AlarmTest) {
80   WatchdogCounter watchdog(Milliseconds(10), "Enabled", true);
81   watchdog.watchdog().Arm();
82   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), 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.
TEST_F(WatchdogTest,AlarmPriorTimeTest)87 TEST_F(WatchdogTest, AlarmPriorTimeTest) {
88   WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
89   // Set a time in the past.
90   watchdog.watchdog().ArmSomeTimeDeltaAgo(Seconds(2));
91   // It should instantly go off, but certainly in less than 5 minutes.
92   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), 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(Milliseconds(10), "Disabled", false);
100   watchdog.watchdog().Arm();
101   // Alarm should not fire, as it was disabled.
102   PlatformThread::Sleep(Milliseconds(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(Seconds(1), "Enabled3", true);
109 
110   TimeTicks start = TimeTicks::Now();
111   watchdog.watchdog().Arm();
112   // Sleep a bit, but not past the alarm point.
113   PlatformThread::Sleep(Milliseconds(100));
114   watchdog.watchdog().Disarm();
115   TimeTicks end = TimeTicks::Now();
116 
117   if (end - start > Milliseconds(500)) {
118     LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
119                  << "timing-sensitive test suspicious.  Aborting now.";
120     return;
121   }
122 
123   // Alarm should not have fired before it was disarmed.
124   EXPECT_EQ(0, watchdog.alarm_counter());
125 
126   // Sleep past the point where it would have fired if it wasn't disarmed,
127   // and verify that it didn't fire.
128   PlatformThread::Sleep(Seconds(1));
129   EXPECT_EQ(0, watchdog.alarm_counter());
130 
131   // ...but even after disarming, we can still use the alarm...
132   // Set a time greater than the timeout into the past.
133   watchdog.watchdog().ArmSomeTimeDeltaAgo(Seconds(10));
134   // It should almost instantly go off, but certainly in less than 5 minutes.
135   SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(Minutes(5), watchdog.alarm_counter() > 0);
136 
137   EXPECT_EQ(1, watchdog.alarm_counter());
138 }
139 
140 }  // namespace base
141