| // 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/macros.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) { |
| } |
| |
| ~WatchdogCounter() override = default; |
| |
| 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: |
| 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 |