| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "heartd/daemon/top_sheriff.h" |
| |
| #include <base/test/task_environment.h> |
| #include <base/time/time.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "heartd/daemon/sheriffs/sheriff.h" |
| |
| namespace heartd { |
| |
| namespace { |
| |
| class TestSheriff final : public Sheriff { |
| public: |
| explicit TestSheriff(bool has_shift_work) : has_shift_work_(has_shift_work) {} |
| TestSheriff(const TestSheriff&) = delete; |
| TestSheriff& operator=(const TestSheriff&) = delete; |
| ~TestSheriff() override{}; |
| |
| // heartd::Sheriff override: |
| void OneShotWork() override { ++number_one_shot_work_called_; } |
| bool HasShiftWork() override { return has_shift_work_; } |
| void AdjustSchedule() override {} |
| void ShiftWork() override { ++number_shift_work_called_; } |
| void CleanUp() override { ++number_clean_up_called_; } |
| |
| void AdjustSchedule(const base::TimeDelta& schedule) { schedule_ = schedule; } |
| int number_one_shot_work_called() { return number_one_shot_work_called_; } |
| int number_main_work_called() { return number_shift_work_called_; } |
| int number_clean_up_called() { return number_clean_up_called_; } |
| |
| private: |
| bool has_shift_work_ = false; |
| int number_one_shot_work_called_ = 0; |
| int number_shift_work_called_ = 0; |
| int number_clean_up_called_ = 0; |
| }; |
| |
| class TopSheriffTest : public testing::Test { |
| public: |
| TopSheriffTest() = default; |
| ~TopSheriffTest() override = default; |
| |
| void QuitCallback() { quit_callback_is_called_ = true; } |
| |
| bool IsQuitCallbackCalled() { return quit_callback_is_called_; } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| std::unique_ptr<TopSheriff> top_sheriff_ = std::make_unique<TopSheriff>( |
| base::BindOnce(&TopSheriffTest::QuitCallback, base::Unretained(this))); |
| |
| private: |
| bool quit_callback_is_called_ = false; |
| }; |
| |
| } // namespace |
| |
| TEST_F(TopSheriffTest, NoShiftWork) { |
| TestSheriff* test_sheriff = new TestSheriff(/* has_shift_work */ false); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff)); |
| top_sheriff_->GetToWork(); |
| |
| EXPECT_EQ(test_sheriff->number_one_shot_work_called(), 1); |
| |
| // Heartd should be terminated after 2 minutes. |
| task_environment_.FastForwardBy(base::Minutes(2)); |
| EXPECT_TRUE(IsQuitCallbackCalled()); |
| } |
| |
| TEST_F(TopSheriffTest, HasShiftWorkWithDefaultFrequency) { |
| TestSheriff* test_sheriff = new TestSheriff(/* has_shift_work */ true); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff)); |
| top_sheriff_->GetToWork(); |
| |
| EXPECT_EQ(test_sheriff->number_one_shot_work_called(), 1); |
| |
| // The default shift frequency is 60 minutes. |
| task_environment_.FastForwardBy(base::Minutes(60)); |
| EXPECT_EQ(test_sheriff->number_main_work_called(), 1); |
| task_environment_.FastForwardBy(base::Minutes(60)); |
| EXPECT_EQ(test_sheriff->number_main_work_called(), 2); |
| } |
| |
| TEST_F(TopSheriffTest, AdjustSchedule) { |
| TestSheriff* test_sheriff = new TestSheriff(/* has_shift_work */ true); |
| test_sheriff->AdjustSchedule(base::Minutes(10)); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff)); |
| top_sheriff_->GetToWork(); |
| |
| EXPECT_EQ(test_sheriff->number_one_shot_work_called(), 1); |
| |
| task_environment_.FastForwardBy(base::Minutes(60)); |
| EXPECT_EQ(test_sheriff->number_main_work_called(), 6); |
| } |
| |
| TEST_F(TopSheriffTest, MultipleSheriffs) { |
| TestSheriff* test_sheriff_1 = new TestSheriff(/* has_shift_work */ true); |
| TestSheriff* test_sheriff_2 = new TestSheriff(/* has_shift_work */ true); |
| TestSheriff* test_sheriff_3 = new TestSheriff(/* has_shift_work */ false); |
| test_sheriff_1->AdjustSchedule(base::Minutes(10)); |
| test_sheriff_2->AdjustSchedule(base::Minutes(20)); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff_1)); |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff_2)); |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff_3)); |
| top_sheriff_->GetToWork(); |
| |
| EXPECT_EQ(test_sheriff_1->number_one_shot_work_called(), 1); |
| EXPECT_EQ(test_sheriff_2->number_one_shot_work_called(), 1); |
| EXPECT_EQ(test_sheriff_3->number_one_shot_work_called(), 1); |
| |
| task_environment_.FastForwardBy(base::Minutes(60)); |
| EXPECT_EQ(test_sheriff_1->number_main_work_called(), 6); |
| EXPECT_EQ(test_sheriff_2->number_main_work_called(), 3); |
| EXPECT_EQ(test_sheriff_3->number_main_work_called(), 0); |
| } |
| |
| TEST_F(TopSheriffTest, OneShotWorkOnlyRunOnce) { |
| TestSheriff* test_sheriff = new TestSheriff(/* has_shift_work */ false); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff)); |
| top_sheriff_->GetToWork(); |
| |
| EXPECT_EQ(test_sheriff->number_one_shot_work_called(), 1); |
| |
| // Start shift again. |
| top_sheriff_->GetToWork(); |
| EXPECT_EQ(test_sheriff->number_one_shot_work_called(), 1); |
| } |
| |
| TEST_F(TopSheriffTest, CleanUpTask) { |
| TestSheriff* test_sheriff = new TestSheriff(/* has_shift_work */ true); |
| |
| top_sheriff_->AddSheriff(std::unique_ptr<Sheriff>(test_sheriff)); |
| top_sheriff_->GetToWork(); |
| |
| // For every 1 hour, we call managed sheriff's CleanUp() periodically. |
| task_environment_.FastForwardBy(base::Hours(1)); |
| EXPECT_EQ(test_sheriff->number_clean_up_called(), 1); |
| |
| task_environment_.FastForwardBy(base::Hours(1)); |
| EXPECT_EQ(test_sheriff->number_clean_up_called(), 2); |
| } |
| |
| } // namespace heartd |