From 235e6f9219759fcb8c4f28fd4c549918dfd56524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arkadiusz=20J=C4=99drzejewski?= Date: Thu, 26 Mar 2026 09:14:45 +0100 Subject: [PATCH] hmon: add C++ HMON unit tests C++ wrapper unit tests. --- score/health_monitor/src/cpp/BUILD | 23 +- .../src/cpp/tests/deadline_monitor_test.cpp | 111 +++++++++ .../src/cpp/tests/health_monitor_test.cpp | 232 ++++++++++++++++++ .../src/cpp/tests/heartbeat_monitor_test.cpp | 51 ++++ .../integrated_test.cpp} | 25 +- .../src/cpp/tests/logic_monitor_test.cpp | 107 ++++++++ .../src/cpp/tests/time_range_test.cpp | 38 +++ 7 files changed, 577 insertions(+), 10 deletions(-) create mode 100644 score/health_monitor/src/cpp/tests/deadline_monitor_test.cpp create mode 100644 score/health_monitor/src/cpp/tests/health_monitor_test.cpp create mode 100644 score/health_monitor/src/cpp/tests/heartbeat_monitor_test.cpp rename score/health_monitor/src/cpp/{health_monitor_test.cpp => tests/integrated_test.cpp} (86%) create mode 100644 score/health_monitor/src/cpp/tests/logic_monitor_test.cpp create mode 100644 score/health_monitor/src/cpp/tests/time_range_test.cpp diff --git a/score/health_monitor/src/cpp/BUILD b/score/health_monitor/src/cpp/BUILD index 043bde81..8fbace30 100644 --- a/score/health_monitor/src/cpp/BUILD +++ b/score/health_monitor/src/cpp/BUILD @@ -68,9 +68,28 @@ cc_library( ) cc_gtest_unit_test( - name = "cpp_tests", + name = "cpp_unit_tests", srcs = [ - "health_monitor_test.cpp", + "tests/deadline_monitor_test.cpp", + "tests/health_monitor_test.cpp", + "tests/heartbeat_monitor_test.cpp", + "tests/logic_monitor_test.cpp", + "tests/time_range_test.cpp", + ], + linkopts = select({ + "@platforms//os:qnx": ["-lsocket"], + "@platforms//os:linux": [], + }), + deps = [ + "//score/health_monitor/src/cpp:health_monitoring_cc_stub_supervisor", + "//score/health_monitor/src/cpp/details:log_init", + ], +) + +cc_gtest_unit_test( + name = "cpp_integration_tests", + srcs = [ + "tests/integrated_test.cpp", ], linkopts = select({ "@platforms//os:qnx": ["-lsocket"], diff --git a/score/health_monitor/src/cpp/tests/deadline_monitor_test.cpp b/score/health_monitor/src/cpp/tests/deadline_monitor_test.cpp new file mode 100644 index 00000000..fd3b8a5e --- /dev/null +++ b/score/health_monitor/src/cpp/tests/deadline_monitor_test.cpp @@ -0,0 +1,111 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/mw/health/deadline_monitor.h" +#include "score/mw/health/health_monitor.h" +#include + +using namespace score::mw::health; +using namespace score::mw::health::deadline; + +TEST(DeadlineMonitorBuilder, New_Succeeds) +{ + DeadlineMonitorBuilder deadline_monitor_builder; +} + +TEST(DeadlineMonitorBuilder, AddDeadline_Succeeds) +{ + using namespace std::chrono_literals; + DeadlineTag deadline_tag{"deadline"}; + TimeRange range{50ms, 150ms}; + auto deadline_monitor_builder{DeadlineMonitorBuilder{}.add_deadline(deadline_tag, range)}; +} + +class DeadlineMonitorFixture : public ::testing::Test +{ + protected: + std::optional deadline_monitor_; + + void SetUp() override + { + // Monitor must be obtained from HMON. + // Initialize deadline monitor builder. + using namespace std::chrono_literals; + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineTag deadline_tag{"deadline"}; + TimeRange range{50ms, 150ms}; + auto deadline_monitor_builder{DeadlineMonitorBuilder{}.add_deadline(deadline_tag, range)}; + + // Build HMON, including deadline monitor. + auto hmon_build_result{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .build()}; + ASSERT_TRUE(hmon_build_result.has_value()); + auto hmon{std::move(hmon_build_result.value())}; + + // Get deadline monitor. + auto get_deadline_monitor_result{hmon.get_deadline_monitor(deadline_monitor_tag)}; + ASSERT_TRUE(get_deadline_monitor_result.has_value()); + deadline_monitor_ = std::move(get_deadline_monitor_result.value()); + } +}; + +TEST_F(DeadlineMonitorFixture, GetDeadline_Succeeds) +{ + // Get deadline. + auto get_deadline_result{deadline_monitor_->get_deadline(DeadlineTag{"deadline"})}; + ASSERT_TRUE(get_deadline_result.has_value()); +} + +TEST_F(DeadlineMonitorFixture, GetDeadline_Unknown) +{ + // Get deadline. + auto get_deadline_result{deadline_monitor_->get_deadline(DeadlineTag{"unknown"})}; + ASSERT_FALSE(get_deadline_result.has_value()); + ASSERT_EQ(get_deadline_result.error(), Error::NotFound); +} + +class DeadlineFixture : public DeadlineMonitorFixture +{ +}; + +TEST_F(DeadlineFixture, Start_Succeeds) +{ + // Get deadline. + DeadlineTag deadline_tag{"deadline"}; + auto get_deadline_result{deadline_monitor_->get_deadline(deadline_tag)}; + ASSERT_TRUE(get_deadline_result.has_value()); + auto deadline{std::move(get_deadline_result.value())}; + + // Try to start and stop deadline. + auto deadline_start_result{deadline.start()}; + ASSERT_TRUE(deadline_start_result.has_value()); + auto deadline_handle{std::move(deadline_start_result.value())}; + + deadline_handle.stop(); +} + +TEST_F(DeadlineFixture, Start_AlreadyRunning) +{ + // Get deadline. + DeadlineTag deadline_tag{"deadline"}; + auto get_deadline_result{deadline_monitor_->get_deadline(deadline_tag)}; + ASSERT_TRUE(get_deadline_result.has_value()); + auto deadline{std::move(get_deadline_result.value())}; + + // Try to start the deadline twice. + deadline.start(); + auto deadline_start_result{deadline.start()}; + ASSERT_FALSE(deadline_start_result.has_value()); + ASSERT_EQ(deadline_start_result.error(), Error::Failed); +} diff --git a/score/health_monitor/src/cpp/tests/health_monitor_test.cpp b/score/health_monitor/src/cpp/tests/health_monitor_test.cpp new file mode 100644 index 00000000..ee5d679b --- /dev/null +++ b/score/health_monitor/src/cpp/tests/health_monitor_test.cpp @@ -0,0 +1,232 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/mw/health/health_monitor.h" +#include "score/mw/health/deadline_monitor.h" +#include "score/mw/health/heartbeat_monitor.h" +#include "score/mw/health/logic_monitor.h" +#include + +using namespace score::mw::health; +using namespace score::mw::health::deadline; +using namespace score::mw::health::heartbeat; +using namespace score::mw::health::logic; + +HeartbeatMonitorBuilder def_heartbeat_monitor_builder() +{ + using namespace std::chrono_literals; + TimeRange range{100ms, 200ms}; + return HeartbeatMonitorBuilder{range}; +} + +LogicMonitorBuilder def_logic_monitor_builder() +{ + StateTag state1{"state1"}; + StateTag state2{"state2"}; + return LogicMonitorBuilder{state1}.add_state(state1, {state2}).add_state(state2, {state1}); +} + +TEST(HealthMonitorBuilder, New_Succeeds) +{ + // Check able to construct and destruct only. + HealthMonitorBuilder health_monitor_builder; +} + +TEST(HealthMonitorBuilder, Build_Succeeds) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + auto heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + MonitorTag logic_monitor_tag{"logic_monitor"}; + auto logic_monitor_builder{def_logic_monitor_builder()}; + + auto result{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)) + .build()}; + ASSERT_TRUE(result.has_value()); +} + +TEST(HealthMonitorBuilder, Build_InvalidCycles) +{ + using namespace std::chrono_literals; + auto result{HealthMonitorBuilder{}.with_supervisor_api_cycle(123ms).with_internal_processing_cycle(100ms).build()}; + ASSERT_FALSE(result.has_value()); + ASSERT_EQ(result.error(), Error::InvalidArgument); +} + +TEST(HealthMonitorBuilder, Build_NoMonitors) +{ + auto result{HealthMonitorBuilder{}.build()}; + ASSERT_FALSE(result.has_value()); + ASSERT_EQ(result.error(), Error::WrongState); +} + +TEST(HealthMonitor, GetDeadlineMonitor_Available) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + auto health_monitor{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .build() + .value()}; + + auto result{health_monitor.get_deadline_monitor(deadline_monitor_tag)}; + ASSERT_TRUE(result.has_value()); +} + +TEST(HealthMonitor, GetDeadlineMonitor_Taken) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + auto health_monitor{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .build() + .value()}; + + health_monitor.get_deadline_monitor(deadline_monitor_tag); + auto result{health_monitor.get_deadline_monitor(deadline_monitor_tag)}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, GetDeadlineMonitor_Unknown) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + auto health_monitor{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .build() + .value()}; + + auto result{health_monitor.get_deadline_monitor(MonitorTag{"undefined_monitor"})}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, GetHeartbeatMonitor_Available) +{ + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + auto heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + auto health_monitor{HealthMonitorBuilder{} + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .build() + .value()}; + + auto result{health_monitor.get_heartbeat_monitor(heartbeat_monitor_tag)}; + ASSERT_TRUE(result.has_value()); +} + +TEST(HealthMonitor, GetHeartbeatMonitor_Taken) +{ + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + HeartbeatMonitorBuilder heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + auto health_monitor{HealthMonitorBuilder{} + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .build() + .value()}; + + health_monitor.get_heartbeat_monitor(heartbeat_monitor_tag); + auto result{health_monitor.get_heartbeat_monitor(heartbeat_monitor_tag)}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, GetHeartbeatMonitor_Unknown) +{ + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + HeartbeatMonitorBuilder heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + auto health_monitor{HealthMonitorBuilder{} + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .build() + .value()}; + + auto result{health_monitor.get_heartbeat_monitor(MonitorTag{"undefined_monitor"})}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, GetLogicMonitor_Available) +{ + MonitorTag logic_monitor_tag{"logic_monitor"}; + auto logic_monitor_builder{def_logic_monitor_builder()}; + auto health_monitor{ + HealthMonitorBuilder{}.add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)).build().value()}; + + auto result{health_monitor.get_logic_monitor(logic_monitor_tag)}; + ASSERT_TRUE(result.has_value()); +} + +TEST(HealthMonitor, GetLogicMonitor_Taken) +{ + MonitorTag logic_monitor_tag{"logic_monitor"}; + LogicMonitorBuilder logic_monitor_builder{def_logic_monitor_builder()}; + auto health_monitor{ + HealthMonitorBuilder{}.add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)).build().value()}; + + health_monitor.get_logic_monitor(logic_monitor_tag); + auto result{health_monitor.get_logic_monitor(logic_monitor_tag)}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, GetLogicMonitor_Unknown) +{ + MonitorTag logic_monitor_tag{"logic_monitor"}; + LogicMonitorBuilder logic_monitor_builder{def_logic_monitor_builder()}; + auto health_monitor{ + HealthMonitorBuilder{}.add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)).build().value()}; + + auto result{health_monitor.get_logic_monitor(MonitorTag{"undefined_monitor"})}; + ASSERT_FALSE(result.has_value()); +} + +TEST(HealthMonitor, Start_Succeeds) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + auto heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + MonitorTag logic_monitor_tag{"logic_monitor"}; + auto logic_monitor_builder{def_logic_monitor_builder()}; + + auto health_monitor{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)) + .build() + .value()}; + + health_monitor.get_deadline_monitor(deadline_monitor_tag); + health_monitor.get_heartbeat_monitor(heartbeat_monitor_tag); + health_monitor.get_logic_monitor(logic_monitor_tag); + + health_monitor.start(); +} + +TEST(HealthMonitor, Start_MonitorsNotTaken) +{ + MonitorTag deadline_monitor_tag{"deadline_monitor"}; + DeadlineMonitorBuilder deadline_monitor_builder; + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + auto heartbeat_monitor_builder{def_heartbeat_monitor_builder()}; + MonitorTag logic_monitor_tag{"logic_monitor"}; + auto logic_monitor_builder{def_logic_monitor_builder()}; + + auto health_monitor{HealthMonitorBuilder{} + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)) + .build() + .value()}; + + // `SIGABRT` is expected. + ASSERT_DEATH({ health_monitor.start(); }, ""); +} diff --git a/score/health_monitor/src/cpp/tests/heartbeat_monitor_test.cpp b/score/health_monitor/src/cpp/tests/heartbeat_monitor_test.cpp new file mode 100644 index 00000000..28b3e9c7 --- /dev/null +++ b/score/health_monitor/src/cpp/tests/heartbeat_monitor_test.cpp @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/mw/health/heartbeat_monitor.h" +#include "score/mw/health/health_monitor.h" +#include + +using namespace score::mw::health; +using namespace score::mw::health::heartbeat; + +TEST(HeartbeatMonitorBuilder, New_Succeeds) +{ + using namespace std::chrono_literals; + TimeRange range{100ms, 200ms}; + HeartbeatMonitorBuilder heartbeat_monitor_builder{range}; +} + +TEST(HeartbeatMonitor, Heartbeat_Succeeds) +{ + // Monitor must be obtained from HMON. + // Initialize heartbeat monitor builder. + using namespace std::chrono_literals; + MonitorTag heartbeat_monitor_tag{"heartbeat_monitor"}; + TimeRange range{100ms, 200ms}; + HeartbeatMonitorBuilder heartbeat_monitor_builder{range}; + + // Build HMON, including heartbeat monitor. + auto hmon_build_result{HealthMonitorBuilder{} + .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) + .build()}; + ASSERT_TRUE(hmon_build_result.has_value()); + auto hmon{std::move(hmon_build_result.value())}; + + // Get heartbeat monitor. + auto get_heartbeat_monitor_result{hmon.get_heartbeat_monitor(heartbeat_monitor_tag)}; + ASSERT_TRUE(get_heartbeat_monitor_result.has_value()); + auto heartbeat_monitor{std::move(get_heartbeat_monitor_result.value())}; + + // Check heartbeat is not failing. + heartbeat_monitor.heartbeat(); +} diff --git a/score/health_monitor/src/cpp/health_monitor_test.cpp b/score/health_monitor/src/cpp/tests/integrated_test.cpp similarity index 86% rename from score/health_monitor/src/cpp/health_monitor_test.cpp rename to score/health_monitor/src/cpp/tests/integrated_test.cpp index 53f3e2f6..fa6b4fae 100644 --- a/score/health_monitor/src/cpp/health_monitor_test.cpp +++ b/score/health_monitor/src/cpp/tests/integrated_test.cpp @@ -10,10 +10,9 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/mw/health/health_monitor.h" #include "score/mw/health/common.h" +#include "score/mw/health/health_monitor.h" #include "score/mw/health/tag.h" -#include #include using namespace score::mw::health; @@ -29,12 +28,19 @@ class HealthMonitorTest : public ::testing::Test }; // For first review round, only single test case to show up API -TEST_F(HealthMonitorTest, TestName) +TEST_F(HealthMonitorTest, Integrated) { RecordProperty( "Description", "This test demonstrates the usage of HealthMonitor and DeadlineMonitor APIs. It creates a HealthMonitor with a " "DeadlineMonitor, retrieves the DeadlineMonitor, and tests starting a deadline."); + + // Setup thread parameters. + // - Affinity set to first core. + // - Stack size set to common default stack size. + // - Scheduler not set - avoid additional caps required. + auto thread_parameters{ThreadParameters{}.affinity({0}).stack_size(8 * 1024 * 1024)}; + // Setup deadline monitor construction. const MonitorTag deadline_monitor_tag{"deadline_monitor"}; auto deadline_monitor_builder = @@ -56,9 +62,6 @@ TEST_F(HealthMonitorTest, TestName) auto logic_monitor_builder = logic::LogicMonitorBuilder{from_state}.add_state(from_state, std::vector{to_state}).add_state(to_state, {}); - // Thread parameters. - auto thread_parameters{ThreadParameters().affinity(std::vector{0})}; - auto hmon_result{HealthMonitorBuilder() .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) .add_heartbeat_monitor(heartbeat_monitor_tag, std::move(heartbeat_monitor_builder)) @@ -117,11 +120,17 @@ TEST_F(HealthMonitorTest, TestName) EXPECT_EQ(current_state_res.value(), to_state); auto deadline_res = deadline_mon.get_deadline(DeadlineTag("deadline_1")); + ASSERT_TRUE(deadline_res.has_value()); + auto& deadline{deadline_res.value()}; { - auto deadline_guard = deadline_res.value().start().value(); + auto first_start_res{deadline.start()}; + EXPECT_TRUE(first_start_res.has_value()); + auto deadline_guard{std::move(first_start_res.value())}; - EXPECT_EQ(deadline_res.value().start().error(), ::score::mw::health::Error::WrongState); + auto second_start_res{deadline_res.value().start()}; + EXPECT_FALSE(second_start_res.has_value()); + EXPECT_EQ(second_start_res.error(), ::score::mw::health::Error::WrongState); deadline_guard.stop(); } } diff --git a/score/health_monitor/src/cpp/tests/logic_monitor_test.cpp b/score/health_monitor/src/cpp/tests/logic_monitor_test.cpp new file mode 100644 index 00000000..13c5e8db --- /dev/null +++ b/score/health_monitor/src/cpp/tests/logic_monitor_test.cpp @@ -0,0 +1,107 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/mw/health/logic_monitor.h" +#include "score/mw/health/health_monitor.h" +#include + +using namespace score::mw::health; +using namespace score::mw::health::logic; + +TEST(LogicMonitorBuilder, New_Succeeds) +{ + StateTag state1{"state1"}; + LogicMonitorBuilder logic_monitor_builder{state1}; +} + +TEST(LogicMonitorBuilder, AddState_Succeeds) +{ + StateTag state1{"state1"}; + StateTag state2{"state2"}; + auto logic_monitor_builder{LogicMonitorBuilder{state1}.add_state(state1, {state2})}; +} + +class LogicMonitorFixture : public ::testing::Test +{ + protected: + std::optional logic_monitor_; + StateTag state1_{"state1"}; + StateTag state2_{"state2"}; + + void SetUp() override + { + // Monitor must be obtained from HMON. + // Initialize logic monitor builder. + MonitorTag logic_monitor_tag{"logic_monitor"}; + auto logic_monitor_builder{LogicMonitorBuilder{state1_}.add_state(state1_, {state2_}).add_state(state2_, {})}; + + // Build HMON, including logic monitor. + auto hmon_build_result{ + HealthMonitorBuilder{}.add_logic_monitor(logic_monitor_tag, std::move(logic_monitor_builder)).build()}; + ASSERT_TRUE(hmon_build_result.has_value()); + auto hmon{std::move(hmon_build_result.value())}; + + // Get logic monitor. + auto get_logic_monitor_result{hmon.get_logic_monitor(logic_monitor_tag)}; + ASSERT_TRUE(get_logic_monitor_result.has_value()); + logic_monitor_ = std::move(get_logic_monitor_result.value()); + } +}; + +TEST_F(LogicMonitorFixture, Transition_Succeeds) +{ // State transition. + auto transition_result{logic_monitor_->transition(state2_)}; + ASSERT_TRUE(transition_result.has_value()); + ASSERT_EQ(transition_result.value(), state2_); +} + +TEST_F(LogicMonitorFixture, Transition_Unknown) +{ + // State transition. + auto transition_result{logic_monitor_->transition(StateTag{"unknown"})}; + ASSERT_FALSE(transition_result.has_value()); + ASSERT_EQ(transition_result.error(), Error::Failed); +} + +TEST_F(LogicMonitorFixture, Transition_Invalid) +{ + // State transition into invalid state. + logic_monitor_->transition(StateTag{"unknown"}); + + // State transition. + auto transition_result{logic_monitor_->transition(state2_)}; + ASSERT_FALSE(transition_result.has_value()); + ASSERT_EQ(transition_result.error(), Error::Failed); +} + +TEST_F(LogicMonitorFixture, State_Succeeds) +{ + // State transition. + logic_monitor_->transition(state2_); + + // Get state. + auto state_result{logic_monitor_->state()}; + ASSERT_TRUE(state_result.has_value()); + ASSERT_EQ(state_result.value(), state2_); +} + +TEST_F(LogicMonitorFixture, State_Invalid) +{ + // State transition. + logic_monitor_->transition(StateTag{"unknown"}); + + // Get state. + auto state_result{logic_monitor_->state()}; + ASSERT_FALSE(state_result.has_value()); + ASSERT_EQ(state_result.error(), Error::Failed); +} diff --git a/score/health_monitor/src/cpp/tests/time_range_test.cpp b/score/health_monitor/src/cpp/tests/time_range_test.cpp new file mode 100644 index 00000000..b5b13dcd --- /dev/null +++ b/score/health_monitor/src/cpp/tests/time_range_test.cpp @@ -0,0 +1,38 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include "score/mw/health/common.h" +#include + +using namespace score::mw::health; + +TEST(TimeRange, New_Succeeds) +{ + using namespace std::chrono_literals; + TimeRange range{100ms, 200ms}; +} + +TEST(TimeRange, New_InvalidOrder) +{ + using namespace std::chrono_literals; + // `SIGABRT` is expected. + ASSERT_DEATH({ TimeRange range(200ms, 100ms); }, ""); +} + +TEST(TimeRange, MinMax) +{ + using namespace std::chrono_literals; + TimeRange range{123ms, 456ms}; + ASSERT_EQ(range.min_ms(), 123); + ASSERT_EQ(range.max_ms(), 456); +}