From 367c1247a5075c6beef6274e1aab264e8ab4e54f Mon Sep 17 00:00:00 2001 From: AnaMaheshwari Date: Thu, 7 May 2026 01:00:25 +0200 Subject: [PATCH] ipc com test --- .../mw/com/test/feat_com_communication/BUILD | 54 +++++++++++++++ .../feat_com_communication_app.cpp | 67 +++++++++++++++++++ .../integration_test/BUILD | 32 +++++++++ .../test_feat_com_communication.py | 51 ++++++++++++++ .../integration_test/test_recovery.py | 59 ++++++++++++++++ .../test/feat_com_communication/logging.json | 14 ++++ .../feat_com_communication/mw_com_config.json | 59 ++++++++++++++++ .../mw_com_config_alt.json | 59 ++++++++++++++++ .../mw_com_config_recv1.json | 59 ++++++++++++++++ .../mw_com_config_recv2.json | 59 ++++++++++++++++ .../mw_com_config_recv3.json | 59 ++++++++++++++++ 11 files changed, 572 insertions(+) create mode 100644 score/mw/com/test/feat_com_communication/BUILD create mode 100644 score/mw/com/test/feat_com_communication/feat_com_communication_app.cpp create mode 100644 score/mw/com/test/feat_com_communication/integration_test/BUILD create mode 100644 score/mw/com/test/feat_com_communication/integration_test/test_feat_com_communication.py create mode 100644 score/mw/com/test/feat_com_communication/integration_test/test_recovery.py create mode 100644 score/mw/com/test/feat_com_communication/logging.json create mode 100644 score/mw/com/test/feat_com_communication/mw_com_config.json create mode 100644 score/mw/com/test/feat_com_communication/mw_com_config_alt.json create mode 100644 score/mw/com/test/feat_com_communication/mw_com_config_recv1.json create mode 100644 score/mw/com/test/feat_com_communication/mw_com_config_recv2.json create mode 100644 score/mw/com/test/feat_com_communication/mw_com_config_recv3.json diff --git a/score/mw/com/test/feat_com_communication/BUILD b/score/mw/com/test/feat_com_communication/BUILD new file mode 100644 index 000000000..2c0783ea8 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/BUILD @@ -0,0 +1,54 @@ +# ******************************************************************************* +# 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_cc//cc:defs.bzl", "cc_binary") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +load("//score/mw/com/test:pkg_application.bzl", "pkg_application") + +exports_files( + ["logging.json"], + visibility = ["//score/mw/com/test:__subpackages__"], +) + +cc_binary( + name = "feat_com_communication_app", + srcs = [ + "feat_com_communication_app.cpp", + ], + data = ["mw_com_config.json"], + features = COMPILER_WARNING_FEATURES + [ + "aborts_upon_exception", + ], + deps = [ + "//score/mw/com", + "//score/mw/com/test/common_test_resources:assert_handler", + "//score/mw/com/test/common_test_resources:sample_sender_receiver", + "//score/mw/com/test/common_test_resources:sctf_test_runner", + ], +) + +pkg_application( + name = "feat_com_communication-pkg", + app_name = "feat_com_communication", + bin = [":feat_com_communication_app"], + etc = [ + "logging.json", + "mw_com_config.json", + "mw_com_config_recv1.json", + "mw_com_config_recv2.json", + "mw_com_config_recv3.json", + ], + visibility = [ + "//score/mw/com/test/feat_com_communication:__subpackages__", + ], +) diff --git a/score/mw/com/test/feat_com_communication/feat_com_communication_app.cpp b/score/mw/com/test/feat_com_communication/feat_com_communication_app.cpp new file mode 100644 index 000000000..abcc716fb --- /dev/null +++ b/score/mw/com/test/feat_com_communication/feat_com_communication_app.cpp @@ -0,0 +1,67 @@ +/******************************************************************************* + * 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/com/impl/instance_specifier.h" +#include "score/mw/com/test/common_test_resources/assert_handler.h" +#include "score/mw/com/test/common_test_resources/sample_sender_receiver.h" +#include "score/mw/com/test/common_test_resources/sctf_test_runner.h" + +#include +#include +#include + +using namespace std::chrono_literals; + +int main(int argc, const char** argv) +{ + score::mw::com::test::SetupAssertHandler(); + using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; + + const std::vector allowed_parameters{ + Parameters::MODE, Parameters::NUM_CYCLES, Parameters::CYCLE_TIME, Parameters::SERVICE_INSTANCE_MANIFEST, Parameters::UID}; + score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); + + const auto& run_parameters = test_runner.GetRunParameters(); + const auto mode = run_parameters.GetMode(); + const auto num_cycles = run_parameters.GetNumCycles(); + const auto stop_token = test_runner.GetStopToken(); + + score::mw::com::test::EventSenderReceiver event_sender_receiver{}; + + const auto instance_specifier_result = + score::mw::com::InstanceSpecifier::Create(std::string{"score/cp60/MapApiLanesStamped"}); + if (!instance_specifier_result.has_value()) + { + std::cerr << "Invalid instance specifier, terminating." << std::endl; + return EXIT_FAILURE; + } + const auto& instance_specifier = instance_specifier_result.value(); + + std::cout << "Starting application in mode: " << mode << std::endl; + + if (mode == "send" || mode == "skeleton") + { + const auto cycle_time = run_parameters.GetCycleTime(); + return event_sender_receiver.RunAsSkeleton(instance_specifier, cycle_time, num_cycles, stop_token); + } + else if (mode == "recv" || mode == "proxy") + { + const auto cycle_time = run_parameters.GetOptionalCycleTime(); + return event_sender_receiver.RunAsProxy(instance_specifier, cycle_time, num_cycles, stop_token); + } + else + { + std::cerr << "Unknown mode " << mode << ", terminating." << std::endl; + return EXIT_FAILURE; + } +} diff --git a/score/mw/com/test/feat_com_communication/integration_test/BUILD b/score/mw/com/test/feat_com_communication/integration_test/BUILD new file mode 100644 index 000000000..9b6eac05f --- /dev/null +++ b/score/mw/com/test/feat_com_communication/integration_test/BUILD @@ -0,0 +1,32 @@ +# ******************************************************************************* +# 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:tar.bzl", "pkg_tar") +load("//quality/integration_testing:integration_testing.bzl", "integration_test") + +pkg_tar( + name = "filesystem", + deps = [ + "//score/mw/com/test/feat_com_communication:feat_com_communication-pkg", + ], +) + +integration_test( + name = "test_feat_com_communication", + timeout = "moderate", + srcs = [ + "test_feat_com_communication.py", + "test_recovery.py", + + ], + filesystem = ":filesystem", +) diff --git a/score/mw/com/test/feat_com_communication/integration_test/test_feat_com_communication.py b/score/mw/com/test/feat_com_communication/integration_test/test_feat_com_communication.py new file mode 100644 index 000000000..463ae3b24 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/integration_test/test_feat_com_communication.py @@ -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 +# ******************************************************************************* + +"""Integration test to verify primary feat__com_communication communication framework robustness.""" + +import time + +def test_feat_com_communication(sut): + """Verifies that the proxy receives IPC events from the skeleton concurrently over standard configurations.""" + with sut.start_process("./bin/feat_com_communication_app --mode send -t 50 -n 20", cwd="/opt/feat_com_communication/") as sender_process: + with sut.start_process("./bin/feat_com_communication_app --mode recv -n 15", cwd="/opt/feat_com_communication/") as receiver_process: + assert receiver_process.wait_for_exit(timeout=60) == 0 + + assert sender_process.wait_for_exit(timeout=60) == 0 + +def test_feat_com_broadcasting_multiple_receivers(sut): + """Verifies that multiple proxies can concurrently receive data from a single skeleton.""" + with sut.start_process("./bin/feat_com_communication_app --mode send -t 50 -n 400", cwd="/opt/feat_com_communication/") as sender_process: + + with sut.start_process("./bin/feat_com_communication_app --mode recv -n 15 --service_instance_manifest etc/mw_com_config_recv1.json", cwd="/opt/feat_com_communication/") as recv1: + time.sleep(1.0) + with sut.start_process("./bin/feat_com_communication_app --mode recv -n 15 --service_instance_manifest etc/mw_com_config_recv2.json", cwd="/opt/feat_com_communication/") as recv2: + time.sleep(1.0) + with sut.start_process("./bin/feat_com_communication_app --mode recv -n 15 --service_instance_manifest etc/mw_com_config_recv3.json", cwd="/opt/feat_com_communication/") as recv3: + + + assert recv1.wait_for_exit(timeout=90) == 0 + assert recv2.wait_for_exit(timeout=90) == 0 + assert recv3.wait_for_exit(timeout=90) == 0 + + assert sender_process.wait_for_exit(timeout=90) == 0 + +def test_feat_com_late_subscriber_joins(sut): + """Verifies that a proxy can successfully discover and receive data after the skeleton has already started publishing.""" + with sut.start_process("./bin/feat_com_communication_app --mode send -t 50 -n 40", cwd="/opt/feat_com_communication/") as sender_process: + + time.sleep(1.0) + with sut.start_process("./bin/feat_com_communication_app --mode recv -n 15", cwd="/opt/feat_com_communication/") as receiver_process: + assert receiver_process.wait_for_exit(timeout=60) == 0 + + assert sender_process.wait_for_exit(timeout=60) == 0 diff --git a/score/mw/com/test/feat_com_communication/integration_test/test_recovery.py b/score/mw/com/test/feat_com_communication/integration_test/test_recovery.py new file mode 100644 index 000000000..029dec96c --- /dev/null +++ b/score/mw/com/test/feat_com_communication/integration_test/test_recovery.py @@ -0,0 +1,59 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + +"""Integration test to verify Skeleton crash recovery and system integrity.""" + +import time +import pytest + +def test_skeleton_restart_integrity(sut): + """Verifies that a new skeleton can be started and discovered after a previous one was killed.""" + + app_bin = "./bin/feat_com_communication_app" + app_cwd = "/opt/feat_com_communication/" + + # 1. Start the first Skeleton + print("Starting Skeleton A...") + with sut.start_process(f"{app_bin} --mode send -t 50 -n 200", cwd=app_cwd) as skeleton_a: + time.sleep(3.0) + + print("Starting Proxy A...") + with sut.start_process(f"{app_bin} --mode recv -n 5", cwd=app_cwd) as proxy_a: + assert proxy_a.wait_for_exit(timeout=30) == 0 + print("Proxy A finished successfully.") + + print("Force-killing Skeleton A (SIGKILL)...") + sut.execute("pkill -9 -f mode\\ send") + + for _ in range(5): + exit_code, output = sut.execute("pgrep -f mode\\ send") + if exit_code != 0: + print("Confirmed: Skeleton A process is gone.") + break + time.sleep(1.0) + else: + print(f"Warning: Skeleton A might still be running! pgrep output: {output}") + + print("Waiting for system to settle and cleaning artifacts...") + time.sleep(5.0) + sut.execute("rm -rf /tmp/mw_com_lola") + + print("Starting Skeleton B (Recovery instance)...") + with sut.start_process(f"{app_bin} --mode send -t 50 -n 100", cwd=app_cwd) as skeleton_b: + time.sleep(3.0) + print("Starting Proxy B...") + with sut.start_process(f"{app_bin} --mode recv -n 5", cwd=app_cwd) as proxy_b: + assert proxy_b.wait_for_exit(timeout=30) == 0 + print("Proxy B finished successfully. System recovered.") + + assert skeleton_b.wait_for_exit(timeout=60) == 0 diff --git a/score/mw/com/test/feat_com_communication/logging.json b/score/mw/com/test/feat_com_communication/logging.json new file mode 100644 index 000000000..a3f560b86 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/logging.json @@ -0,0 +1,14 @@ +{ + "appId": "feat_com", + "appDesc": "communication test", + "logLevel": "kDebug", + "logLevelThresholdConsole": "kDebug", + "logMode": "kConsole", + "dynamicDatarouterIdentifiers": true, + "service_types": { + "score/cp60/MapApiLanesStamped": { + "instance_id": "default", + "binding": "ipc" + } + } +} \ No newline at end of file diff --git a/score/mw/com/test/feat_com_communication/mw_com_config.json b/score/mw/com/test/feat_com_communication/mw_com_config.json new file mode 100644 index 000000000..dd97b56c9 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/mw_com_config.json @@ -0,0 +1,59 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 99, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "score/cp60/MapApiLanesStamped", + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "asil-level": "QM", + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + }, + { + "eventName": "dummy_data_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + } + ] + } + ] + } + ], + "global": { + "asil-level": "QM" + } +} diff --git a/score/mw/com/test/feat_com_communication/mw_com_config_alt.json b/score/mw/com/test/feat_com_communication/mw_com_config_alt.json new file mode 100644 index 000000000..648d9f42e --- /dev/null +++ b/score/mw/com/test/feat_com_communication/mw_com_config_alt.json @@ -0,0 +1,59 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 99, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "score/cp60/MapApiLanesStamped", + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "asil-level": "QM", "applicationID": 1234, + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + }, + { + "eventName": "dummy_data_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + } + ] + } + ] + } + ], + "global": { + "asil-level": "QM", "applicationID": 1234 + } +} diff --git a/score/mw/com/test/feat_com_communication/mw_com_config_recv1.json b/score/mw/com/test/feat_com_communication/mw_com_config_recv1.json new file mode 100644 index 000000000..c1996a376 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/mw_com_config_recv1.json @@ -0,0 +1,59 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 99, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "score/cp60/MapApiLanesStamped", + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "asil-level": "QM", + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + }, + { + "eventName": "dummy_data_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + } + ] + } + ] + } + ], + "global": {"applicationID": 1001, + "asil-level": "QM" + } +} diff --git a/score/mw/com/test/feat_com_communication/mw_com_config_recv2.json b/score/mw/com/test/feat_com_communication/mw_com_config_recv2.json new file mode 100644 index 000000000..d05203e10 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/mw_com_config_recv2.json @@ -0,0 +1,59 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 99, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "score/cp60/MapApiLanesStamped", + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "asil-level": "QM", + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + }, + { + "eventName": "dummy_data_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + } + ] + } + ] + } + ], + "global": {"applicationID": 1002, + "asil-level": "QM" + } +} diff --git a/score/mw/com/test/feat_com_communication/mw_com_config_recv3.json b/score/mw/com/test/feat_com_communication/mw_com_config_recv3.json new file mode 100644 index 000000000..d92f0dab3 --- /dev/null +++ b/score/mw/com/test/feat_com_communication/mw_com_config_recv3.json @@ -0,0 +1,59 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 99, + "events": [ + { + "eventName": "map_api_lanes_stamped", + "eventId": 1 + }, + { + "eventName": "dummy_data_stamped", + "eventId": 2 + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "score/cp60/MapApiLanesStamped", + "serviceTypeName": "BigDataService", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1, + "asil-level": "QM", + "binding": "SHM", + "events": [ + { + "eventName": "map_api_lanes_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + }, + { + "eventName": "dummy_data_stamped", + "maxSubscribers": 10, + "numberOfSampleSlots": 15 + } + ] + } + ] + } + ], + "global": {"applicationID": 1003, + "asil-level": "QM" + } +}