Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions score/health_monitor/src/cpp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
111 changes: 111 additions & 0 deletions score/health_monitor/src/cpp/tests/deadline_monitor_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <gtest/gtest.h>

using namespace score::mw::health;
using namespace score::mw::health::deadline;

TEST(DeadlineMonitorBuilder, New_Succeeds)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the RecordProperty calls defined in Score Process to define TestType, DerivationTechnique, the Description and possible requirements links.

{
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)};
Comment thread
NicolasFussberger marked this conversation as resolved.
}

class DeadlineMonitorFixture : public ::testing::Test
{
protected:
std::optional<DeadlineMonitor> 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);
}
232 changes: 232 additions & 0 deletions score/health_monitor/src/cpp/tests/health_monitor_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <gtest/gtest.h>

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(); }, "");
}
Loading
Loading