diff --git a/tests/integration/crash_on_startup/crash_on_startup.py b/tests/integration/crash_on_startup/crash_on_startup.py index b88bc439f..b6670dbd8 100644 --- a/tests/integration/crash_on_startup/crash_on_startup.py +++ b/tests/integration/crash_on_startup/crash_on_startup.py @@ -17,7 +17,11 @@ @add_test_properties( - fully_verifies=["feat_req__lifecycle__failure_detect"], + fully_verifies=[ + "feat_req__lifecycle__failure_detect", + "feat_req__lifecycle__recov_run_target_switch", + ], + partially_verifies=["feat_req__lifecycle__recovery_action_support"], test_type="requirements-based", derivation_technique="requirements-analysis", ) diff --git a/tests/integration/process_complex_rep_failure/BUILD b/tests/integration/process_complex_rep_failure/BUILD new file mode 100644 index 000000000..18adcc32c --- /dev/null +++ b/tests/integration/process_complex_rep_failure/BUILD @@ -0,0 +1,78 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* +load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files") +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//:defs.bzl", "launch_manager_config") +load("//tests/utils/bazel:integration.bzl", "integration_test") + +launch_manager_config( + name = "lm_process_complex_rep_failure_config", + config = "//tests/integration/process_complex_rep_failure:process_complex_rep_failure.json", + flatbuffer_out_dir = "etc", +) + +cc_binary( + name = "control_client_mock", + srcs = ["control_client_mock.cpp"], + deps = [ + "//score/launch_manager:control_cc", + "//score/launch_manager:lifecycle_cc", + "//tests/utils/test_helper", + "@googletest//:gtest_main", + ], +) + +cc_binary( + name = "complex_reporting_process", + srcs = ["//tests/utils/test_helper:complex_reporting_process.cpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + "//score/launch_manager:lifecycle_cc", + "//tests/utils/test_helper", + "@googletest//:gtest_main", + ], +) + +pkg_files( + name = "process_complex_rep_failure_main_files", + srcs = [ + ":complex_reporting_process", + ":control_client_mock", + "//score/launch_manager", + "//tests/utils/test_helper:verification_process", + ], + attributes = pkg_attributes(mode = "0755"), + prefix = "tests/process_complex_rep_failure", +) + +pkg_files( + name = "process_complex_rep_failure_etc_files", + srcs = [":lm_process_complex_rep_failure_config"], + prefix = "tests/process_complex_rep_failure", +) + +pkg_tar( + name = "process_complex_rep_failure_binaries", + srcs = [ + ":process_complex_rep_failure_etc_files", + ":process_complex_rep_failure_main_files", + ], +) + +integration_test( + name = "process_complex_rep_failure", + srcs = ["process_complex_rep_failure.py"], + tags = ["integration"], + test_binaries = ":process_complex_rep_failure_binaries", + deps = ["//tests/utils/testing_utils"], +) diff --git a/tests/integration/process_complex_rep_failure/control_client_mock.cpp b/tests/integration/process_complex_rep_failure/control_client_mock.cpp new file mode 100644 index 000000000..42b32d3f3 --- /dev/null +++ b/tests/integration/process_complex_rep_failure/control_client_mock.cpp @@ -0,0 +1,86 @@ +/******************************************************************************** + * 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 + +#include "tests/utils/test_helper/test_helper.hpp" +#include +#include + +// Given a correct configuration with: +// - An initial Run Target named "Startup" containing component named +// "control_client_mock" +// - A Run Target named "run_target_app_does_report_krunning_in_time" +// containing "control_client_mock" and +// "component_does_report_krunning_in_time" +// - A Run Target named "run_target_app_does_not_report_krunning_in_time" +// containing "control_client_mock" and +// "component_does_not_report_krunning_in_time" + +TEST(RecoveryActionComplexRepFailure, ControlClientMock) { + score::mw::lifecycle::ControlClient client; + + ASSERT_TRUE(check_clean({test_end_location, fallback_file})); + + // Establish communication with launch manager + TEST_STEP("Report kRunning from ControlClientMock") { + auto result = score::mw::lifecycle::LifecycleClient{}.ReportExecutionState( + score::mw::lifecycle::ExecutionState::kRunning); + ASSERT_TRUE(result.has_value()) + << "ReportExecutionState() failed: " << result.error().Message(); + } + // Start the run target run_target_app_does_report_krunning_in_time + TEST_STEP("Activate RunTarget run_target_app_does_report_krunning_in_time") { + score::cpp::stop_token stop_token; + auto result = + client.ActivateRunTarget("run_target_app_does_report_krunning_in_time") + .Get(stop_token); + EXPECT_TRUE(result.has_value()) + << "Activating target run_target_app_does_report_krunning_in_time " + "failed: " + << result.error().Message(); + } + // Limitation: we cannot wait for the transition to fallback to complete + sleep(1); + // Then, the LM should continue without triggering the fallback + TEST_STEP("Verify fallback run target has not been activated") { + EXPECT_FALSE(std::filesystem::exists(fallback_file)) + << "Fallback run target should have not been activated"; + } + // Start the run target run_target_app_does_not_report_krunning_in_time + TEST_STEP( + "Activate RunTarget run_target_app_does_not_report_krunning_in_time") { + score::cpp::stop_token stop_token; + auto result = client + .ActivateRunTarget( + "run_target_app_does_not_report_krunning_in_time") + .Get(stop_token); + EXPECT_FALSE(result.has_value()) + << "Activating target run_target_app_does_not_report_krunning_in_time " + "did not fail as expected."; + } + // Limitation: we cannot wait for the transition to fallback to complete + sleep(1); + // Then, the LM should exhaust retries and trigger the fallback + TEST_STEP("Verify fallback run target was activated") { + EXPECT_TRUE(std::filesystem::exists(fallback_file)) + << "Fallback run target should have been activated"; + } + + TEST_STEP("Activate RunTarget Off") { client.ActivateRunTarget("Off"); } +} + +int main(int argc, char **argv) { + return TestRunner(__FILE__, TerminationBehavior::kContinue, + TerminationNotification::kTestEnd) + .RunTests(); +} diff --git a/tests/integration/process_complex_rep_failure/process_complex_rep_failure.json b/tests/integration/process_complex_rep_failure/process_complex_rep_failure.json new file mode 100644 index 000000000..1d1bac8c9 --- /dev/null +++ b/tests/integration/process_complex_rep_failure/process_complex_rep_failure.json @@ -0,0 +1,153 @@ +{ + "schema_version": 1, + "defaults": { + "deployment_config": { + "bin_dir": "/tmp/tests/process_complex_rep_failure", + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "ready_recovery_action": { + "restart": { + "number_of_attempts": 0 + } + }, + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + }, + "environmental_variables": { + "LD_LIBRARY_PATH": "/opt/lib" + }, + "sandbox": { + "uid": 0, + "gid": 0, + "scheduling_policy": "SCHED_OTHER", + "scheduling_priority": 0 + } + }, + "component_properties": { + "application_profile": { + "application_type": "Reporting", + "is_self_terminating": true, + "alive_supervision": { + "reporting_cycle": 0.1, + "min_indications": 1, + "max_indications": 3, + "failed_cycles_tolerance": 1 + } + }, + "ready_condition": { + "process_state": "Running" + } + } + }, + "components": { + "control_client_mock": { + "component_properties": { + "binary_name": "control_client_mock", + "application_profile": { + "application_type": "State_Manager", + "alive_supervision": { + "min_indications": 0 + } + } + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "control_client_mock" + } + } + }, + "component_does_report_krunning_in_time": { + "component_properties": { + "binary_name": "complex_reporting_process", + "process_arguments": [ + "500.0" + ] + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "component_does_report_krunning_in_time" + } + } + }, + "component_does_not_report_krunning_in_time": { + "component_properties": { + "binary_name": "complex_reporting_process", + "process_arguments": [ + "1500.0" + ] + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "component_does_not_report_krunning_in_time" + } + } + }, + "verification_component": { + "component_properties": { + "binary_name": "verification_process", + "application_profile": { + "application_type": "Native", + "is_self_terminating": true + }, + "ready_condition": { + "process_state": "Terminated" + } + } + } + }, + "run_targets": { + "Startup": { + "depends_on": [ + "control_client_mock" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "run_target_app_does_report_krunning_in_time": { + "depends_on": [ + "control_client_mock", + "component_does_report_krunning_in_time" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "run_target_app_does_not_report_krunning_in_time": { + "depends_on": [ + "control_client_mock", + "component_does_not_report_krunning_in_time" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "Off": { + "depends_on": [] + } + }, + "initial_run_target": "Startup", + "alive_supervision": { + "evaluation_cycle": 0.05 + }, + "fallback_run_target": { + "depends_on": [ + "control_client_mock", + "verification_component" + ] + } +} diff --git a/tests/integration/process_complex_rep_failure/process_complex_rep_failure.py b/tests/integration/process_complex_rep_failure/process_complex_rep_failure.py new file mode 100644 index 000000000..b3b5753fe --- /dev/null +++ b/tests/integration/process_complex_rep_failure/process_complex_rep_failure.py @@ -0,0 +1,52 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* +from tests.utils.testing_utils.run_until_file_deployed import run_until_file_deployed +from tests.utils.testing_utils.setup_test import setup_test +from tests.utils.testing_utils.test_results import assert_test_results +from attribute_plugin import add_test_properties + + +@add_test_properties( + partially_verifies=[ + "feat_req__lifecycle__recov_run_target_switch", + "feat_req__lifecycle__recovery_action_support", + ], + fully_verifies=[ + "feat_req__lifecycle__failure_detect", + ], + test_type="requirements-based", + derivation_technique="requirements-analysis", +) +def test_recovery_action_complex_rep_failure( + target, setup_test, assert_test_results, remote_test_dir +): + """ + Objective: Verifies that recovery action is executed when the reporting of kRunning via mw::lifecycle library (named "complex reporting" in the following) is not happening in time and vice versa. + + Case 1: Using complex reporting, the process does report kRunning in time (500ms below boundary) + Expected Behaviour: Reporting kRunning is successful, recovery action is not executed. + + Case 2: Using complex reporting, the process does not report kRunning in time (500ms above boundary) + Expected Behaviour: Reporting kRunning is not successful, recovery action is executed. + The recovery action switches to the fallback run target, the activation of the fallback run target is verified in the test. + """ + + run_until_file_deployed( + target=target, + binary_path=str(remote_test_dir / "launch_manager"), + file_path=remote_test_dir.parent / "test_end", + cwd=str(remote_test_dir), + timeout_s=10.0, + ) + + assert_test_results({"control_client_mock.xml", "complex_reporting_process.xml"}) diff --git a/tests/integration/process_simple_rep_failure/BUILD b/tests/integration/process_simple_rep_failure/BUILD new file mode 100644 index 000000000..fae8ce6f4 --- /dev/null +++ b/tests/integration/process_simple_rep_failure/BUILD @@ -0,0 +1,77 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* +load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files") +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("//:defs.bzl", "launch_manager_config") +load("//tests/utils/bazel:integration.bzl", "integration_test") + +launch_manager_config( + name = "lm_process_simple_rep_failure_config", + config = "//tests/integration/process_simple_rep_failure:process_simple_rep_failure.json", + flatbuffer_out_dir = "etc", +) + +cc_binary( + name = "control_client_mock", + srcs = ["control_client_mock.cpp"], + deps = [ + "//score/launch_manager:control_cc", + "//score/launch_manager:lifecycle_cc", + "//tests/utils/test_helper", + "@googletest//:gtest_main", + ], +) + +cc_binary( + name = "process_simple_reporting", + srcs = ["process_simple_reporting.cpp"], + deps = [ + "//score/launch_manager:lifecycle_cc", + "//tests/utils/test_helper", + "@googletest//:gtest_main", + ], +) + +pkg_files( + name = "process_simple_rep_failure_main_files", + srcs = [ + ":control_client_mock", + ":process_simple_reporting", + "//score/launch_manager", + "//tests/utils/test_helper:verification_process", + ], + attributes = pkg_attributes(mode = "0755"), + prefix = "tests/process_simple_rep_failure", +) + +pkg_files( + name = "process_simple_rep_failure_etc_files", + srcs = [":lm_process_simple_rep_failure_config"], + prefix = "tests/process_simple_rep_failure", +) + +pkg_tar( + name = "process_simple_rep_failure_binaries", + srcs = [ + ":process_simple_rep_failure_etc_files", + ":process_simple_rep_failure_main_files", + ], +) + +integration_test( + name = "process_simple_rep_failure", + srcs = ["process_simple_rep_failure.py"], + tags = ["integration"], + test_binaries = ":process_simple_rep_failure_binaries", + deps = ["//tests/utils/testing_utils"], +) diff --git a/tests/integration/process_simple_rep_failure/control_client_mock.cpp b/tests/integration/process_simple_rep_failure/control_client_mock.cpp new file mode 100644 index 000000000..7b6f96870 --- /dev/null +++ b/tests/integration/process_simple_rep_failure/control_client_mock.cpp @@ -0,0 +1,86 @@ +/******************************************************************************** + * 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 + +#include "tests/utils/test_helper/test_helper.hpp" +#include +#include + +// Given a correct configuration with: +// - An initial Run Target named "Startup" containing component named +// "control_client_mock" +// - A Run Target named "run_target_app_does_report_krunning_in_time" +// containing "control_client_mock" and +// "component_does_report_krunning_in_time" +// - A Run Target named "run_target_app_does_not_report_krunning_in_time" +// containing "control_client_mock" and +// "component_does_not_report_krunning_in_time" + +TEST(RecoveryActionSimpleRepFailure, ControlClientMock) { + score::mw::lifecycle::ControlClient client; + + ASSERT_TRUE(check_clean({test_end_location, fallback_file})); + + // Establish communication with launch manager + TEST_STEP("Report kRunning from ControlClientMock") { + auto result = score::mw::lifecycle::LifecycleClient{}.ReportExecutionState( + score::mw::lifecycle::ExecutionState::kRunning); + ASSERT_TRUE(result.has_value()) + << "ReportExecutionState() failed: " << result.error().Message(); + } + // Start the run target run_target_app_does_report_krunning_in_time + TEST_STEP("Activate RunTarget run_target_app_does_report_krunning_in_time") { + score::cpp::stop_token stop_token; + auto result = + client.ActivateRunTarget("run_target_app_does_report_krunning_in_time") + .Get(stop_token); + EXPECT_TRUE(result.has_value()) + << "Activating target run_target_app_does_report_krunning_in_time " + "failed: " + << result.error().Message(); + } + // Limitation: we cannot wait for the transition to fallback to complete + sleep(1); + // Then, the LM should continue without triggering the fallback + TEST_STEP("Verify fallback run target has not been activated") { + EXPECT_FALSE(std::filesystem::exists(fallback_file)) + << "Fallback run target should have not been activated"; + } + // Start the run target run_target_app_does_not_report_krunning_in_time + TEST_STEP( + "Activate RunTarget run_target_app_does_not_report_krunning_in_time") { + score::cpp::stop_token stop_token; + auto result = client + .ActivateRunTarget( + "run_target_app_does_not_report_krunning_in_time") + .Get(stop_token); + EXPECT_FALSE(result.has_value()) + << "Activating target run_target_app_does_not_report_krunning_in_time " + "did not fail as expected."; + } + // Limitation: we cannot wait for the transition to fallback to complete + sleep(1); + // Then, the LM should exhaust retries and trigger the fallback + TEST_STEP("Verify fallback run target was activated") { + EXPECT_TRUE(std::filesystem::exists(fallback_file)) + << "Fallback run target should have been activated"; + } + + TEST_STEP("Activate RunTarget Off") { client.ActivateRunTarget("Off"); } +} + +int main(int argc, char **argv) { + return TestRunner(__FILE__, TerminationBehavior::kContinue, + TerminationNotification::kTestEnd) + .RunTests(); +} diff --git a/tests/integration/process_simple_rep_failure/process_simple_rep_failure.json b/tests/integration/process_simple_rep_failure/process_simple_rep_failure.json new file mode 100644 index 000000000..ae234cd2f --- /dev/null +++ b/tests/integration/process_simple_rep_failure/process_simple_rep_failure.json @@ -0,0 +1,153 @@ +{ + "schema_version": 1, + "defaults": { + "deployment_config": { + "bin_dir": "/tmp/tests/process_simple_rep_failure", + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "ready_recovery_action": { + "restart": { + "number_of_attempts": 0 + } + }, + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + }, + "environmental_variables": { + "LD_LIBRARY_PATH": "/opt/lib" + }, + "sandbox": { + "uid": 0, + "gid": 0, + "scheduling_policy": "SCHED_OTHER", + "scheduling_priority": 0 + } + }, + "component_properties": { + "application_profile": { + "application_type": "Reporting", + "is_self_terminating": true, + "alive_supervision": { + "reporting_cycle": 0.1, + "min_indications": 1, + "max_indications": 3, + "failed_cycles_tolerance": 1 + } + }, + "ready_condition": { + "process_state": "Running" + } + } + }, + "components": { + "control_client_mock": { + "component_properties": { + "binary_name": "control_client_mock", + "application_profile": { + "application_type": "State_Manager", + "alive_supervision": { + "min_indications": 0 + } + } + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "control_client_mock" + } + } + }, + "component_does_report_krunning_in_time": { + "component_properties": { + "binary_name": "process_simple_reporting", + "process_arguments": [ + "500.0" + ] + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "component_does_report_krunning_in_time" + } + } + }, + "component_does_not_report_krunning_in_time": { + "component_properties": { + "binary_name": "process_simple_reporting", + "process_arguments": [ + "1500.0" + ] + }, + "deployment_config": { + "ready_timeout": 1.0, + "shutdown_timeout": 1.0, + "environmental_variables": { + "PROCESSIDENTIFIER": "component_does_not_report_krunning_in_time" + } + } + }, + "verification_component": { + "component_properties": { + "binary_name": "verification_process", + "application_profile": { + "application_type": "Native", + "is_self_terminating": true + }, + "ready_condition": { + "process_state": "Terminated" + } + } + } + }, + "run_targets": { + "Startup": { + "depends_on": [ + "control_client_mock" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "run_target_app_does_report_krunning_in_time": { + "depends_on": [ + "control_client_mock", + "component_does_report_krunning_in_time" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "run_target_app_does_not_report_krunning_in_time": { + "depends_on": [ + "control_client_mock", + "component_does_not_report_krunning_in_time" + ], + "recovery_action": { + "switch_run_target": { + "run_target": "fallback_run_target" + } + } + }, + "Off": { + "depends_on": [] + } + }, + "initial_run_target": "Startup", + "alive_supervision": { + "evaluation_cycle": 0.05 + }, + "fallback_run_target": { + "depends_on": [ + "control_client_mock", + "verification_component" + ] + } +} diff --git a/tests/integration/process_simple_rep_failure/process_simple_rep_failure.py b/tests/integration/process_simple_rep_failure/process_simple_rep_failure.py new file mode 100644 index 000000000..77cfc5e5f --- /dev/null +++ b/tests/integration/process_simple_rep_failure/process_simple_rep_failure.py @@ -0,0 +1,52 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* +from tests.utils.testing_utils.run_until_file_deployed import run_until_file_deployed +from tests.utils.testing_utils.setup_test import setup_test +from tests.utils.testing_utils.test_results import assert_test_results +from attribute_plugin import add_test_properties + + +@add_test_properties( + partially_verifies=[ + "feat_req__lifecycle__recov_run_target_switch", + "feat_req__lifecycle__recovery_action_support", + ], + fully_verifies=[ + "feat_req__lifecycle__failure_detect", + ], + test_type="requirements-based", + derivation_technique="requirements-analysis", +) +def test_recovery_action_simple_rep_failure( + target, setup_test, assert_test_results, remote_test_dir +): + """ + Objective: Verifies that recovery action is executed when the reporting of kRunning via LifecycleClient API (named "simple reporting" in the following) is not happening in time and vice versa. + + Case 1: Using simple reporting, the process does report kRunning in time (500ms below boundary) + Expected Behaviour: Reporting kRunning is successful, recovery action is not executed. + + Case 2: Using simple reporting, the process does not report kRunning in time (500ms above boundary) + Expected Behaviour: Reporting kRunning is not successful, recovery action is executed. + The recovery action switches to the fallback run target, the activation of the fallback run target is verified in the test. + """ + + run_until_file_deployed( + target=target, + binary_path=str(remote_test_dir / "launch_manager"), + file_path=remote_test_dir.parent / "test_end", + cwd=str(remote_test_dir), + timeout_s=10.0, + ) + + assert_test_results({"control_client_mock.xml", "process_simple_reporting.xml"}) diff --git a/tests/integration/process_simple_rep_failure/process_simple_reporting.cpp b/tests/integration/process_simple_rep_failure/process_simple_reporting.cpp new file mode 100644 index 000000000..9258315ed --- /dev/null +++ b/tests/integration/process_simple_rep_failure/process_simple_reporting.cpp @@ -0,0 +1,48 @@ +/******************************************************************************** + * 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 +#include + +#include + +#include "tests/utils/test_helper/test_helper.hpp" +#include + +int g_argc; +char** g_argv; + +TEST(ProcessSimpleRepFailure, ProcessSimpleReporting) +{ + // Check arguments + TEST_STEP("Check args") + { + ASSERT_GT(g_argc, 1) << "Wrong number of arguments"; + ASSERT_FALSE((g_argv[1][0] != '0') && (atoi(g_argv[1])) == 0) << "Argument must be a number"; + } + // Report kRunning with the appropriate delay + TEST_STEP("Report kRunning from ProcessSimpleReporting") + { + std::this_thread::sleep_for(std::chrono::milliseconds(atoi(g_argv[1]))); + + auto result = score::mw::lifecycle::LifecycleClient{}.ReportExecutionState(score::mw::lifecycle::ExecutionState::kRunning); + EXPECT_TRUE(result.has_value()) << "ReportExecutionState() failed: " << result.error().Message(); + } +} + +int main(int argc, char** argv) +{ + g_argc = argc; + g_argv = argv; + + return TestRunner(__FILE__, TerminationBehavior::kContinue).RunTests(); +} diff --git a/tests/utils/test_helper/BUILD b/tests/utils/test_helper/BUILD index 553e23972..85de2e91f 100644 --- a/tests/utils/test_helper/BUILD +++ b/tests/utils/test_helper/BUILD @@ -15,6 +15,7 @@ exports_files( [ "reporting_process.cpp", "verification_process.cpp", + "complex_reporting_process.cpp", ], visibility = ["//tests:__subpackages__"], ) @@ -39,6 +40,17 @@ cc_binary( ], ) +cc_binary( + name = "complex_reporting_process", + srcs = ["complex_reporting_process.cpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + ":test_helper", + "//score/launch_manager:lifecycle_cc", + "@googletest//:gtest_main", + ], +) + cc_binary( name = "verification_process", srcs = ["verification_process.cpp"], diff --git a/tests/utils/test_helper/complex_reporting_process.cpp b/tests/utils/test_helper/complex_reporting_process.cpp new file mode 100644 index 000000000..bcbeaaef3 --- /dev/null +++ b/tests/utils/test_helper/complex_reporting_process.cpp @@ -0,0 +1,65 @@ +/******************************************************************************** + * 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 +#include + +#include + +#include "tests/utils/test_helper/test_helper.hpp" +#include "score/mw/lifecycle/application.h" +#include "score/mw/lifecycle/runapplication.h" +#include + +/// @file complex_reporting_process.cpp +/// @brief Monitored test process using mw::lifecycle (score::mw::lifecycle::Application / +/// run_application) to simulate configurable start, run, and crash +/// behaviours for integration tests of the lifecycle manager. + +int g_argc; +char **g_argv; + +class LifecycleApp final : public score::mw::lifecycle::Application { +public: + std::int32_t + Initialize(const score::mw::lifecycle::ApplicationContext &appCtx) override { + optind = 1; + + return 0; + } + + std::int32_t Run(const score::cpp::stop_token &stopToken) override { + return EXIT_SUCCESS; + } +}; + +TEST(ComplexReportingProcess, ReportsRunning) { + // Check arguments + TEST_STEP("Check args") { + ASSERT_GT(g_argc, 1) << "Wrong number of arguments"; + ASSERT_FALSE((g_argv[1][0] != '0') && (atoi(g_argv[1])) == 0) + << "Argument must be a number"; + } + // Report kRunning with the appropriate delay + TEST_STEP("Report kRunning from ProcessComplexReporting") { + std::this_thread::sleep_for(std::chrono::milliseconds(atoi(g_argv[1]))); + + score::mw::lifecycle::run_application(g_argc, g_argv); + } +} + +int main(int argc, char **argv) { + g_argc = argc; + g_argv = argv; + + return TestRunner(__FILE__, TerminationBehavior::kContinue).RunTests(); +}