diff --git a/tests/integration/switch_run_target/BUILD b/tests/integration/switch_run_target/BUILD index 714a09b606..58c489b5ba 100644 --- a/tests/integration/switch_run_target/BUILD +++ b/tests/integration/switch_run_target/BUILD @@ -45,19 +45,27 @@ cc_binary( for component in [ "component_a", "component_b", - "component_d", ] ] -cc_binary( - name = "component_e", - srcs = ["//tests/utils/test_helper:reporting_process.cpp"], - deps = [ - "//score/launch_manager:lifecycle_cc", - "//tests/utils/test_helper", - "@googletest//:gtest_main", - ], -) +# Components D and E share component_d_or_e.cpp; the component ("d" or "e") is +# passed on the command line (see switch_run_target.json). +[ + cc_binary( + name = "component_" + component, + srcs = ["component_d_or_e.cpp"], + deps = [ + ":switch_run_target_common", + "//score/launch_manager:lifecycle_cc", + "//tests/utils/test_helper", + "@googletest//:gtest_main", + ], + ) + for component in [ + "d", + "e", + ] +] integration_test( name = "switch_run_target", diff --git a/tests/integration/switch_run_target/common.hpp b/tests/integration/switch_run_target/common.hpp index 0f5847e8d4..e876639eb6 100644 --- a/tests/integration/switch_run_target/common.hpp +++ b/tests/integration/switch_run_target/common.hpp @@ -28,5 +28,4 @@ PROC_FILES(d) PROC_FILES(e) #undef PROC_FILES - #endif diff --git a/tests/integration/switch_run_target/component_d.cpp b/tests/integration/switch_run_target/component_d.cpp deleted file mode 100644 index 8e1376e122..0000000000 --- a/tests/integration/switch_run_target/component_d.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************** - * 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 "common.hpp" -#include "tests/utils/test_helper/test_helper.hpp" -#include - -TEST(ComponentD, RunAndVerify) -{ - TEST_STEP("Report running") - { - EXPECT_TRUE(touch_file(d_started)) << "failed to deploy file"; - score::mw::lifecycle::report_running(); - } - while (!TestRunner::exitRequested) - { - pause(); - } - EXPECT_TRUE(touch_file(d_terminating)) << "Failed to deploy file"; -} - -int main() -{ - return TestRunner(__FILE__).RunTests(); -} diff --git a/tests/integration/switch_run_target/component_d_or_e.cpp b/tests/integration/switch_run_target/component_d_or_e.cpp new file mode 100644 index 0000000000..e06670a4ec --- /dev/null +++ b/tests/integration/switch_run_target/component_d_or_e.cpp @@ -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 + ********************************************************************************/ +#include +#include +#include +#include + +#include "common.hpp" +#include "tests/utils/test_helper/test_helper.hpp" +#include + +/// @file component_d_or_e.cpp +/// @brief Shared source for components D and E of the switch_run_target test. +/// The component is selected by the single command line argument "d" or +/// "e"; the process writes its "started" marker once it has reported +/// running and its "terminating" marker just before it exits. + +namespace +{ +std::string_view g_started; +std::string_view g_terminating; +std::string g_xml_name; +} // namespace + +TEST(Component, RunAndVerify) +{ + TEST_STEP("Report running") + { + EXPECT_TRUE(touch_file(g_started)) << "failed to deploy file"; + score::mw::lifecycle::report_running(); + } + while (!TestRunner::exitRequested) + { + pause(); + } + EXPECT_TRUE(touch_file(g_terminating)) << "Failed to deploy file"; +} + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Usage: component_d_or_e " << std::endl; + return EXIT_FAILURE; + } + + const std::string_view component{argv[1]}; + if (component == "d") + { + g_started = d_started; + g_terminating = d_terminating; + } + else if (component == "e") + { + g_started = e_started; + g_terminating = e_terminating; + } + else + { + std::cerr << "Invalid argument '" << component << "', expected 'd' or 'e'" << std::endl; + return EXIT_FAILURE; + } + + // Name the GTest XML result file per component so the two binaries built from + // this source write distinct results. + g_xml_name = "component_" + std::string{component}; + return TestRunner(g_xml_name).RunTests(); +} diff --git a/tests/integration/switch_run_target/control_client_mock.cpp b/tests/integration/switch_run_target/control_client_mock.cpp index be7cd17043..2b3f3f5b51 100644 --- a/tests/integration/switch_run_target/control_client_mock.cpp +++ b/tests/integration/switch_run_target/control_client_mock.cpp @@ -43,7 +43,10 @@ TEST(SwitchRunTarget, ControlClientMock) } // When we switch run to run target A // Then - // Processes A and B verify that B is started before A and terminated after A. + // Processes A and B verify that B is started before A and terminated after A when switching run targets + const auto running_processes = {a_started, b_started, d_started}; + const auto terminating_processes = {a_terminating, b_terminating, d_terminating}; + TEST_STEP("Activate run target A") { score::cpp::stop_token stop_token; @@ -52,8 +55,7 @@ TEST(SwitchRunTarget, ControlClientMock) } TEST_STEP("Verify running processes") { - const auto running = {a_started, b_started, d_started}; - for (const auto proc : running) + for (const auto proc : running_processes) { EXPECT_TRUE(std::filesystem::exists(proc)) << "A process depended on by run target A was not started!"; } @@ -65,14 +67,22 @@ TEST(SwitchRunTarget, ControlClientMock) auto result = client.ActivateRunTarget("Startup").Get(stop_token); EXPECT_TRUE(result.has_value()) << "Activating target Startup failed: " << result.error().Message(); } - TEST_STEP("Activate RunTarget Off") + + TEST_STEP("Verify terminated processes") + { + for (const auto proc : terminating_processes) + { + EXPECT_TRUE(std::filesystem::exists(proc)) << "A process depended on by run target A was not terminated!"; + } + } + + TEST_STEP("Verify that component E was never started") { - client.ActivateRunTarget("Off"); - EXPECT_FALSE(std::filesystem::exists(e_started)) << "Component E should not be launched"; + EXPECT_FALSE(std::filesystem::exists(e_started)) << "Component E should not have been started!"; } } int main() { - return TestRunner(__FILE__, TerminationBehavior::kWait, TerminationNotification::kTestEnd).RunTests(); + return TestRunner(__FILE__, TerminationBehavior::kContinue, TerminationNotification::kTestEnd).RunTests(); } diff --git a/tests/integration/switch_run_target/switch_run_target.json b/tests/integration/switch_run_target/switch_run_target.json index b9e1825a04..f27c94c503 100644 --- a/tests/integration/switch_run_target/switch_run_target.json +++ b/tests/integration/switch_run_target/switch_run_target.json @@ -3,13 +3,6 @@ "defaults": { "deployment_config": { "bin_dir": "/tmp/tests/switch_run_target", - "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" @@ -24,21 +17,6 @@ "scheduling_policy": "SCHED_OTHER", "scheduling_priority": 0 } - }, - "component_properties": { - "application_profile": { - "application_type": "Reporting", - "is_self_terminating": false, - "alive_supervision": { - "reporting_cycle": 0.1, - "min_indications": 1, - "max_indications": 3, - "failed_cycles_tolerance": 1 - } - }, - "ready_condition": { - "process_state": "Running" - } } }, "components": { @@ -83,7 +61,10 @@ }, "component_e": { "component_properties": { - "binary_name": "reporting_process" + "binary_name": "component_e", + "process_arguments": [ + "e" + ] }, "deployment_config": { "environmental_variables": { @@ -93,7 +74,10 @@ }, "component_d": { "component_properties": { - "binary_name": "component_d" + "binary_name": "component_d", + "process_arguments": [ + "d" + ] }, "deployment_config": { "environmental_variables": { @@ -125,9 +109,6 @@ } }, "initial_run_target": "Startup", - "alive_supervision": { - "evaluation_cycle": 0.05 - }, "fallback_run_target": { "depends_on": [] } diff --git a/tests/integration/switch_run_target/switch_run_target.py b/tests/integration/switch_run_target/switch_run_target.py index 849daaf17d..7a458a1258 100644 --- a/tests/integration/switch_run_target/switch_run_target.py +++ b/tests/integration/switch_run_target/switch_run_target.py @@ -23,16 +23,18 @@ "comp_req__launch_man__process_state_comm", "feat_req__lifecycle__process_termination", "feat_req__lifecycle__terminationn_dependency", + "feat_req__lifecycle__process_ordering", + "comp_req__launch_man__launch_manager_shutdown", ], test_type="requirements-based", derivation_technique="requirements-analysis", ) def test_switch_run_target(target, setup_test, assert_test_results, remote_test_dir): """ - Objective: Verifies that the launch manager respects component and run target dependencies when switching run targets, enforcing correct startup and termination order. + Objective: Verifies that the launch manager respects component and run target dependencies when switching run targets and shuting down, enforcing correct startup and termination order. - The control client activates run_target_a, which depends on run_target_c (containing component_d) and component_a (which depends on component_b). After activation it switches back to Startup and then Off. - Expected Behaviour: Component B starts before component A, component D is started, component A terminates before component B, and component E (not in the dependency chain) is never launched. + The control client activates run_target_a, which depends on run_target_c (containing component_d) and component_a (which depends on component_b). After activation it switches back to Startup, and then Off. + Expected Behaviour: During activation resp. deactivation of run_target_a, component B starts before component A, component D is started, component A terminates before component B, and component E (not in the dependency chain) is never launched. """ config_path = str(remote_test_dir / "etc/switch_run_target.bin")