13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 53f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/watchdog.h" 63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/logging.h" 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/spin_wait.h" 93f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/platform_thread.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/time.h" 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h" 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base { 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Provide a derived class to facilitate testing. 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass WatchdogCounter : public Watchdog { 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WatchdogCounter(const TimeDelta& duration, 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const std::string& thread_watched_name, 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool enabled) 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : Watchdog(duration, thread_watched_name, enabled), alarm_counter_(0) { 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual ~WatchdogCounter() {} 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Alarm() { 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott alarm_counter_++; 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog::Alarm(); 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int alarm_counter() { return alarm_counter_; } 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int alarm_counter_; 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DISALLOW_COPY_AND_ASSIGN(WatchdogCounter); 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass WatchdogTest : public testing::Test { 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void SetUp() { 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog::ResetStaticData(); 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//------------------------------------------------------------------------------ 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Actual tests 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Minimal constructor/destructor test. 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, StartupShutdownTest) { 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false); 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true); 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Test ability to call Arm and Disarm repeatedly. 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, ArmDisarmTest) { 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false); 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog1.Arm(); 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog1.Disarm(); 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog1.Arm(); 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog1.Disarm(); 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true); 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog2.Arm(); 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog2.Disarm(); 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog2.Arm(); 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog2.Disarm(); 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Make sure a basic alarm fires when the time has expired. 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, AlarmTest) { 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true); 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.Arm(); 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.alarm_counter() > 0); 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(1, watchdog.alarm_counter()); 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Make sure a basic alarm fires when the time has expired. 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, AlarmPriorTimeTest) { 8721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen WatchdogCounter watchdog(TimeDelta(), "Enabled2", true); 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Set a time in the past. 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2)); 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It should instantly go off, but certainly in less than 5 minutes. 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.alarm_counter() > 0); 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(1, watchdog.alarm_counter()); 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Make sure a disable alarm does nothing, even if we arm it. 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, ConstructorDisabledTest) { 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false); 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.Arm(); 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Alarm should not fire, as it was disabled. 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PlatformThread::Sleep(500); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(0, watchdog.alarm_counter()); 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Make sure Disarming will prevent firing, even after Arming. 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST_F(WatchdogTest, DisarmTest) { 1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true); 1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TimeTicks start = TimeTicks::Now(); 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.Arm(); 1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick PlatformThread::Sleep(100); // Sleep a bit, but not past the alarm point. 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.Disarm(); 1143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick TimeTicks end = TimeTicks::Now(); 1153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick if (end - start > TimeDelta::FromMilliseconds(500)) { 1173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick LOG(WARNING) << "100ms sleep took over 500ms, making the results of this " 1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick << "timing-sensitive test suspicious. Aborting now."; 1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick return; 1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick } 1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Alarm should not have fired before it was disarmed. 1233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick EXPECT_EQ(0, watchdog.alarm_counter()); 1243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick 1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // Sleep past the point where it would have fired if it wasn't disarmed, 1263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick // and verify that it didn't fire. 1273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick PlatformThread::Sleep(1000); 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(0, watchdog.alarm_counter()); 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // ...but even after disarming, we can still use the alarm... 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Set a time greater than the timeout into the past. 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10)); 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It should almost instantly go off, but certainly in less than 5 minutes. 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5), 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott watchdog.alarm_counter() > 0); 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(1, watchdog.alarm_counter()); 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 1403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace base 141