blob: 36c36b60b71abcce80e07401fe962a38cfbd6716 [file] [log] [blame]
// Copyright 2017 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 "chromecast/base/thread_health_checker.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_mock_time_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromecast {
namespace {
const base::TimeDelta kInterval = base::TimeDelta::FromSeconds(3);
const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(2);
} // namespace
class ThreadHealthCheckerTest : public ::testing::Test {
protected:
ThreadHealthCheckerTest()
: patient_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
doctor_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
~ThreadHealthCheckerTest() override{};
scoped_refptr<base::TestMockTimeTaskRunner> patient_;
scoped_refptr<base::TestMockTimeTaskRunner> doctor_;
base::WaitableEvent event_;
};
#define CREATE_THREAD_HEALTH_CHECKER(name) \
ThreadHealthChecker name(patient_, doctor_, kInterval, kTimeout, \
base::BindRepeating(&base::WaitableEvent::Signal, \
base::Unretained(&event_)))
TEST_F(ThreadHealthCheckerTest, FiresTimeoutWhenTaskRunnerDoesNotFlush) {
CREATE_THREAD_HEALTH_CHECKER(thc);
// Do not flush the patient, so that the health check sentinel task won't run.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(6));
EXPECT_TRUE(event_.IsSignaled());
}
TEST_F(ThreadHealthCheckerTest, DoesNotFireTimeoutWhenTaskRunnerFlushesInTime) {
CREATE_THREAD_HEALTH_CHECKER(thc);
// Advance the doctor by enough time to post the health check, but not to time
// out.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(4));
// Advance the patient to let the sentinel task run.
patient_->FastForwardBy(base::TimeDelta::FromSeconds(4));
// Advance the doctor by enough time such that the sentinel not running would
// cause the failure callback to run.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_FALSE(event_.IsSignaled());
}
TEST_F(ThreadHealthCheckerTest, FiresTimeoutWhenTaskRunnerFlushesTooLate) {
CREATE_THREAD_HEALTH_CHECKER(thc);
// Advance the doctor before the patient, to simulate a task in the patient
// that takes too long.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(6));
patient_->FastForwardBy(base::TimeDelta::FromSeconds(6));
// Flush the task runner so the health check sentinel task is run.
EXPECT_TRUE(event_.IsSignaled());
}
TEST_F(ThreadHealthCheckerTest, FiresTimeoutOnLaterIteration) {
CREATE_THREAD_HEALTH_CHECKER(thc);
// Advance the doctor enough to start the check.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(4));
// Advance the patient enough to run the task.
patient_->FastForwardBy(base::TimeDelta::FromSeconds(4));
// Advance the doctor enough to start the check again.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(4));
EXPECT_FALSE(event_.IsSignaled());
// Advance the doctor enough for the timeout from the second check to fire.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(event_.IsSignaled());
}
TEST_F(ThreadHealthCheckerTest, NoCrashWhenDestroyed) {
{
CREATE_THREAD_HEALTH_CHECKER(thc);
doctor_->RunUntilIdle();
}
doctor_->RunUntilIdle();
}
TEST_F(ThreadHealthCheckerTest, DropPendingEventsAfterDestruction) {
{
CREATE_THREAD_HEALTH_CHECKER(thc);
// Fast forward by enough time to have scheduled a health check.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(4));
EXPECT_FALSE(event_.IsSignaled());
}
// Fast forward by enough time for the health check to have executed.
// However, we want all pending events to be dropped after the destructor is
// called, so the event should not be signalled.
doctor_->FastForwardBy(base::TimeDelta::FromSeconds(2));
EXPECT_FALSE(event_.IsSignaled());
}
} // namespace chromecast