| // 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/heartbeat_manager.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/notreached.h> |
| #include <base/test/task_environment.h> |
| #include <base/test/test_future.h> |
| #include <base/time/time.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <mojo/public/cpp/bindings/remote.h> |
| |
| #include "heartd/daemon/test_utils/mock_dbus_connector.h" |
| #include "heartd/mojom/heartd.mojom.h" |
| |
| namespace heartd { |
| |
| namespace { |
| |
| namespace mojom = ::ash::heartd::mojom; |
| |
| using ::testing::_; |
| using ::testing::Exactly; |
| |
| class HeartbeatManagerTest : public testing::Test { |
| public: |
| HeartbeatManagerTest() { |
| heartbeat_manager_ = std::make_unique<HeartbeatManager>(&action_runner_); |
| } |
| ~HeartbeatManagerTest() override = default; |
| |
| void EstablishHeartbeatTracker() { |
| auto action_reboot = mojom::Action::New( |
| /*failure_count = */ 2, mojom::ActionType::kNormalReboot); |
| auto argument = mojom::HeartbeatServiceArgument::New(); |
| |
| argument->actions.push_back(std::move(action_reboot)); |
| heartbeat_manager_->EstablishHeartbeatTracker( |
| mojom::ServiceName::kKiosk, pacemaker_.BindNewPipeAndPassReceiver(), |
| std::move(argument)); |
| } |
| |
| protected: |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| mojo::Remote<mojom::Pacemaker> pacemaker_; |
| MockDbusConnector mock_dbus_connector_; |
| ActionRunner action_runner_{&mock_dbus_connector_}; |
| std::unique_ptr<HeartbeatManager> heartbeat_manager_ = nullptr; |
| }; |
| |
| TEST_F(HeartbeatManagerTest, IsPacemakerBound) { |
| EXPECT_FALSE( |
| heartbeat_manager_->IsPacemakerBound(mojom::ServiceName::kKiosk)); |
| |
| EstablishHeartbeatTracker(); |
| |
| EXPECT_TRUE(heartbeat_manager_->IsPacemakerBound(mojom::ServiceName::kKiosk)); |
| } |
| |
| TEST_F(HeartbeatManagerTest, RebindPacemaker) { |
| EstablishHeartbeatTracker(); |
| |
| pacemaker_.reset(); |
| task_environment_.RunUntilIdle(); |
| EXPECT_FALSE( |
| heartbeat_manager_->IsPacemakerBound(mojom::ServiceName::kKiosk)); |
| |
| // Rebind pacemaker. |
| EstablishHeartbeatTracker(); |
| |
| EXPECT_TRUE(heartbeat_manager_->IsPacemakerBound(mojom::ServiceName::kKiosk)); |
| } |
| |
| TEST_F(HeartbeatManagerTest, RemoveUnusedHeartbeatTrackers) { |
| EXPECT_FALSE(heartbeat_manager_->AnyHeartbeatTracker()); |
| EstablishHeartbeatTracker(); |
| EXPECT_TRUE(heartbeat_manager_->AnyHeartbeatTracker()); |
| |
| base::test::TestFuture<void> test_future; |
| pacemaker_->StopMonitor(test_future.GetCallback()); |
| if (!test_future.Wait()) { |
| NOTREACHED_NORETURN(); |
| } |
| |
| // This should remove the unused heartbeat trackers. |
| heartbeat_manager_->VerifyHeartbeatAndTakeAction(); |
| EXPECT_FALSE( |
| heartbeat_manager_->IsPacemakerBound(mojom::ServiceName::kKiosk)); |
| EXPECT_FALSE(heartbeat_manager_->AnyHeartbeatTracker()); |
| } |
| |
| TEST_F(HeartbeatManagerTest, TakeRebootAction) { |
| action_runner_.EnableNormalRebootAction(); |
| EstablishHeartbeatTracker(); |
| EXPECT_CALL(*mock_dbus_connector_.power_manager_proxy(), |
| RequestRestartAsync(_, _, _, _, _)) |
| .Times(Exactly(1)); |
| |
| // Forward the time so that the gap of the current time and the previous |
| // heartbeat will exceed the threshold. |
| task_environment_.FastForwardBy(base::Minutes(3)); |
| heartbeat_manager_->VerifyHeartbeatAndTakeAction(); |
| heartbeat_manager_->VerifyHeartbeatAndTakeAction(); |
| } |
| |
| TEST_F(HeartbeatManagerTest, NotEnableRebootAction) { |
| EstablishHeartbeatTracker(); |
| EXPECT_CALL(*mock_dbus_connector_.power_manager_proxy(), |
| RequestRestartAsync(_, _, _, _, _)) |
| .Times(Exactly(0)); |
| |
| // Forward the time so that the gap of the current time and the previous |
| // heartbeat will exceed the threshold. |
| task_environment_.FastForwardBy(base::Minutes(3)); |
| heartbeat_manager_->VerifyHeartbeatAndTakeAction(); |
| heartbeat_manager_->VerifyHeartbeatAndTakeAction(); |
| } |
| |
| } // namespace |
| |
| } // namespace heartd |