blob: 07a8bbd6dd452cea7a5b21ac75812317fccc5699 [file] [log] [blame]
// Copyright (c) 2006-2008 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/idle_timer.h"
#include "base/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
using base::TimeDelta;
using base::IdleTimer;
// If the timers fire too quickly, it can be tricky to make timer tests
// reliable on all buildbots. This constant sets a minimum timer delta where
// we expect that we should be able to reliably count timers without problems
// due to slight clock/scheduling variances.
const int kSafeTestIntervalMs = 500;
namespace {
// We Mock the GetLastInputInfo function to return
// the time stored here.
static Time mock_timer_started;
bool MockIdleTimeSource(int32 *milliseconds_interval_since_last_event) {
TimeDelta delta = Time::Now() - mock_timer_started;
*milliseconds_interval_since_last_event =
static_cast<int32>(delta.InMilliseconds());
return true;
}
// TestIdle task fires after 100ms of idle time.
class TestIdleTask : public IdleTimer {
public:
TestIdleTask(bool repeat)
: IdleTimer(TimeDelta::FromMilliseconds(kSafeTestIntervalMs), repeat),
idle_counter_(0) {
set_idle_time_source(MockIdleTimeSource);
}
int get_idle_counter() { return idle_counter_; }
virtual void OnIdle() {
idle_counter_++;
}
private:
int idle_counter_;
};
// A task to help us quit the test.
class TestFinishedTask {
public:
TestFinishedTask() {}
void Run() {
MessageLoop::current()->Quit();
}
};
// A timer which resets the idle clock.
class ResetIdleTask {
public:
ResetIdleTask() {}
void Run() {
mock_timer_started = Time::Now();
}
};
class IdleTimerTest : public testing::Test {
private:
// IdleTimer requires a UI message loop on the current thread.
MessageLoopForUI message_loop_;
};
///////////////////////////////////////////////////////////////////////////////
// NoRepeat tests:
// A non-repeating idle timer will fire once on idle, and
// then will not fire again unless it goes non-idle first.
TEST_F(IdleTimerTest, NoRepeatIdle) {
// Create an IdleTimer, which should fire once after 500ms.
// Create a Quit timer which will fire after 1s.
// Verify that we fired exactly once.
mock_timer_started = Time::Now();
TestIdleTask test_task(false);
TestFinishedTask finish_task;
base::OneShotTimer<TestFinishedTask> timer;
timer.Start(TimeDelta::FromMilliseconds(2 * kSafeTestIntervalMs),
&finish_task, &TestFinishedTask::Run);
test_task.Start();
MessageLoop::current()->Run();
EXPECT_EQ(test_task.get_idle_counter(), 1);
}
TEST_F(IdleTimerTest, NoRepeatFlipIdleOnce) {
// Create an IdleTimer, which should fire once after 500ms.
// Create a Quit timer which will fire after 5s.
// Create a timer to reset once, idle after 2s.
// Verify that we fired exactly twice.
mock_timer_started = Time::Now();
TestIdleTask test_task(false);
TestFinishedTask finish_task;
ResetIdleTask reset_task;
base::OneShotTimer<TestFinishedTask> t1;
t1.Start(TimeDelta::FromMilliseconds(10 * kSafeTestIntervalMs), &finish_task,
&TestFinishedTask::Run);
base::OneShotTimer<ResetIdleTask> t2;
t2.Start(TimeDelta::FromMilliseconds(4 * kSafeTestIntervalMs), &reset_task,
&ResetIdleTask::Run);
test_task.Start();
MessageLoop::current()->Run();
EXPECT_EQ(test_task.get_idle_counter(), 2);
}
TEST_F(IdleTimerTest, NoRepeatNotIdle) {
// Create an IdleTimer, which should fire once after 500ms.
// Create a Quit timer which will fire after 5s.
// Create a timer to reset idle every 50ms.
// Verify that we never fired.
mock_timer_started = Time::Now();
TestIdleTask test_task(false);
TestFinishedTask finish_task;
ResetIdleTask reset_task;
base::OneShotTimer<TestFinishedTask> t;
t.Start(TimeDelta::FromMilliseconds(10 * kSafeTestIntervalMs), &finish_task,
&TestFinishedTask::Run);
base::RepeatingTimer<ResetIdleTask> reset_timer;
reset_timer.Start(TimeDelta::FromMilliseconds(50), &reset_task,
&ResetIdleTask::Run);
test_task.Start();
MessageLoop::current()->Run();
reset_timer.Stop();
EXPECT_EQ(test_task.get_idle_counter(), 0);
}
///////////////////////////////////////////////////////////////////////////////
// Repeat tests:
// A repeating idle timer will fire repeatedly on each interval, as long
// as it has been idle. So, if the machine remains idle, it will continue
// firing over and over.
TEST_F(IdleTimerTest, Repeat) {
// Create an IdleTimer, which should fire repeatedly after 500ms.
// Create a Quit timer which will fire after 1.5s.
// Verify that we fired 2-3 times.
mock_timer_started = Time::Now();
TestIdleTask test_task(true);
TestFinishedTask finish_task;
base::OneShotTimer<TestFinishedTask> t;
t.Start(TimeDelta::FromMilliseconds(kSafeTestIntervalMs * 3), &finish_task,
&TestFinishedTask::Run);
test_task.Start();
MessageLoop::current()->Run();
// In a perfect world, the idle_counter should be 2. However,
// due to timer 'slop', accept 2 or 3.
EXPECT_GE(test_task.get_idle_counter(), 2);
EXPECT_LE(test_task.get_idle_counter(), 3);
}
TEST_F(IdleTimerTest, RepeatIdleReset) {
// Create an IdleTimer, which should fire repeatedly after 500ms.
// Create a Quit timer which will fire after 5s.
// Create a reset timer, which fires after 2500ms
// Verify that we fired 8-10 times.
mock_timer_started = Time::Now();
TestIdleTask test_task(true);
ResetIdleTask reset_task;
TestFinishedTask finish_task;
base::OneShotTimer<TestFinishedTask> t1;
t1.Start(TimeDelta::FromMilliseconds(10 * kSafeTestIntervalMs), &finish_task,
&TestFinishedTask::Run);
base::OneShotTimer<ResetIdleTask> t2;
t2.Start(TimeDelta::FromMilliseconds(5 * kSafeTestIntervalMs), &reset_task,
&ResetIdleTask::Run);
test_task.Start();
MessageLoop::current()->Run();
// In a perfect world, the idle_counter should be 9. However,
// since timers aren't guaranteed to fire perfectly, this can
// be less. Accept 8-10.
EXPECT_GE(test_task.get_idle_counter(), 8);
EXPECT_LE(test_task.get_idle_counter(), 10);
}
TEST_F(IdleTimerTest, RepeatNotIdle) {
// Create an IdleTimer, which should fire repeatedly after 500ms.
// Create a Quit timer which will fire after 4s.
// Create a timer to reset idle every 50ms.
// Verify that we never fired.
mock_timer_started = Time::Now();
TestIdleTask test_task(true);
TestFinishedTask finish_task;
ResetIdleTask reset_task;
base::OneShotTimer<TestFinishedTask> t;
t.Start(TimeDelta::FromMilliseconds(8 * kSafeTestIntervalMs), &finish_task,
&TestFinishedTask::Run);
base::RepeatingTimer<ResetIdleTask> reset_timer;
reset_timer.Start(TimeDelta::FromMilliseconds(50), &reset_task,
&ResetIdleTask::Run);
test_task.Start();
MessageLoop::current()->Run();
reset_timer.Stop();
EXPECT_EQ(test_task.get_idle_counter(), 0);
}
} // namespace