From 1f9330ab71eb2f6e6610731048bc411a0f934e99 Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Tue, 26 May 2026 10:02:33 +0530 Subject: [PATCH 1/6] Move proxy and skeleton containers from methods to common test resources --- score/mw/com/test/common_test_resources/BUILD | 22 +++++++++++++++ .../proxy_container.cpp | 2 +- .../proxy_container.h | 0 .../skeleton_container.cpp | 2 +- .../skeleton_container.h | 0 .../test/methods/methods_test_resources/BUILD | 28 +------------------ .../methods_test_resources/method_consumer.h | 2 +- .../methods/non_trivial_constructors/BUILD | 4 +-- .../non_trivial_constructors/consumer.cpp | 2 +- .../non_trivial_constructors/provider.cpp | 2 +- 10 files changed, 30 insertions(+), 34 deletions(-) rename score/mw/com/test/{methods/methods_test_resources => common_test_resources}/proxy_container.cpp (88%) rename score/mw/com/test/{methods/methods_test_resources => common_test_resources}/proxy_container.h (100%) rename score/mw/com/test/{methods/methods_test_resources => common_test_resources}/skeleton_container.cpp (87%) rename score/mw/com/test/{methods/methods_test_resources => common_test_resources}/skeleton_container.h (100%) diff --git a/score/mw/com/test/common_test_resources/BUILD b/score/mw/com/test/common_test_resources/BUILD index bf1686258..5d72faf9b 100644 --- a/score/mw/com/test/common_test_resources/BUILD +++ b/score/mw/com/test/common_test_resources/BUILD @@ -15,6 +15,28 @@ load("@rules_cc//cc:defs.bzl", "cc_library") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") load("//quality/unit_testing:unit_testing.bzl", "cc_unit_test") +cc_library( + name = "proxy_container", + srcs = ["proxy_container.cpp"], + hdrs = ["proxy_container.h"], + features = COMPILER_WARNING_FEATURES, + visibility = ["//score/mw/com/test:__subpackages__"], + deps = [ + "//score/mw/com", + ], +) + +cc_library( + name = "skeleton_container", + srcs = ["skeleton_container.cpp"], + hdrs = ["skeleton_container.h"], + features = COMPILER_WARNING_FEATURES, + visibility = ["//score/mw/com/test:__subpackages__"], + deps = [ + "//score/mw/com", + ], +) + cc_library( name = "bigdata_type", srcs = [ diff --git a/score/mw/com/test/methods/methods_test_resources/proxy_container.cpp b/score/mw/com/test/common_test_resources/proxy_container.cpp similarity index 88% rename from score/mw/com/test/methods/methods_test_resources/proxy_container.cpp rename to score/mw/com/test/common_test_resources/proxy_container.cpp index 85019bfaa..584767aed 100644 --- a/score/mw/com/test/methods/methods_test_resources/proxy_container.cpp +++ b/score/mw/com/test/common_test_resources/proxy_container.cpp @@ -10,4 +10,4 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/mw/com/test/methods/methods_test_resources/proxy_container.h" +#include "score/mw/com/test/common_test_resources/proxy_container.h" diff --git a/score/mw/com/test/methods/methods_test_resources/proxy_container.h b/score/mw/com/test/common_test_resources/proxy_container.h similarity index 100% rename from score/mw/com/test/methods/methods_test_resources/proxy_container.h rename to score/mw/com/test/common_test_resources/proxy_container.h diff --git a/score/mw/com/test/methods/methods_test_resources/skeleton_container.cpp b/score/mw/com/test/common_test_resources/skeleton_container.cpp similarity index 87% rename from score/mw/com/test/methods/methods_test_resources/skeleton_container.cpp rename to score/mw/com/test/common_test_resources/skeleton_container.cpp index 70f7eca86..e0a4e3508 100644 --- a/score/mw/com/test/methods/methods_test_resources/skeleton_container.cpp +++ b/score/mw/com/test/common_test_resources/skeleton_container.cpp @@ -10,4 +10,4 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -#include "score/mw/com/test/methods/methods_test_resources/skeleton_container.h" +#include "score/mw/com/test/common_test_resources/skeleton_container.h" diff --git a/score/mw/com/test/methods/methods_test_resources/skeleton_container.h b/score/mw/com/test/common_test_resources/skeleton_container.h similarity index 100% rename from score/mw/com/test/methods/methods_test_resources/skeleton_container.h rename to score/mw/com/test/common_test_resources/skeleton_container.h diff --git a/score/mw/com/test/methods/methods_test_resources/BUILD b/score/mw/com/test/methods/methods_test_resources/BUILD index 6801003e3..64912499d 100644 --- a/score/mw/com/test/methods/methods_test_resources/BUILD +++ b/score/mw/com/test/methods/methods_test_resources/BUILD @@ -14,32 +14,6 @@ load("@rules_cc//cc:defs.bzl", "cc_library") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") -cc_library( - name = "proxy_container", - srcs = ["proxy_container.cpp"], - hdrs = ["proxy_container.h"], - features = COMPILER_WARNING_FEATURES, - visibility = [ - "//score/mw/com/test/methods:__subpackages__", - ], - deps = [ - "//score/mw/com", - ], -) - -cc_library( - name = "skeleton_container", - srcs = ["skeleton_container.cpp"], - hdrs = ["skeleton_container.h"], - features = COMPILER_WARNING_FEATURES, - visibility = [ - "//score/mw/com/test/methods:__subpackages__", - ], - deps = [ - "//score/mw/com", - ], -) - cc_library( name = "method_provider", srcs = ["method_provider.cpp"], @@ -69,8 +43,8 @@ cc_library( "//score/mw/com", "//score/mw/com:runtime", "//score/mw/com/test/common_test_resources:assert_handler", + "//score/mw/com/test/common_test_resources:proxy_container", "//score/mw/com/test/common_test_resources:sctf_test_runner", - "//score/mw/com/test/methods/methods_test_resources:proxy_container", "@score_baselibs//score/mw/log", ], ) diff --git a/score/mw/com/test/methods/methods_test_resources/method_consumer.h b/score/mw/com/test/methods/methods_test_resources/method_consumer.h index 2ce415dd4..a0f34f8ef 100644 --- a/score/mw/com/test/methods/methods_test_resources/method_consumer.h +++ b/score/mw/com/test/methods/methods_test_resources/method_consumer.h @@ -13,7 +13,7 @@ #ifndef SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_METHOD_CONSUMER_H #define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_METHOD_CONSUMER_H -#include "score/mw/com/test/methods/methods_test_resources/proxy_container.h" +#include "score/mw/com/test/common_test_resources/proxy_container.h" #include diff --git a/score/mw/com/test/methods/non_trivial_constructors/BUILD b/score/mw/com/test/methods/non_trivial_constructors/BUILD index b4e596360..626c5a96c 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/BUILD +++ b/score/mw/com/test/methods/non_trivial_constructors/BUILD @@ -40,8 +40,8 @@ cc_library( implementation_deps = [ ":test_method_datatype", "//score/mw/com", + "//score/mw/com/test/common_test_resources:proxy_container", "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", - "//score/mw/com/test/methods/methods_test_resources:proxy_container", ], deps = [ "@score_baselibs//score/language/futurecpp", @@ -56,8 +56,8 @@ cc_library( deps = [ ":test_method_datatype", "//score/mw/com", + "//score/mw/com/test/common_test_resources:skeleton_container", "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", - "//score/mw/com/test/methods/methods_test_resources:skeleton_container", ], ) diff --git a/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp b/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp index 6f7b7e321..faf4d3564 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp @@ -12,8 +12,8 @@ ********************************************************************************/ #include "score/mw/com/test/methods/non_trivial_constructors/consumer.h" +#include "score/mw/com/test/common_test_resources/proxy_container.h" #include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" -#include "score/mw/com/test/methods/methods_test_resources/proxy_container.h" #include "score/mw/com/test/methods/non_trivial_constructors/test_method_datatype.h" #include "score/mw/com/types.h" diff --git a/score/mw/com/test/methods/non_trivial_constructors/provider.cpp b/score/mw/com/test/methods/non_trivial_constructors/provider.cpp index 5ee46c003..d4091e2df 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/provider.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/provider.cpp @@ -12,8 +12,8 @@ ********************************************************************************/ #include "score/mw/com/test/methods/non_trivial_constructors/provider.h" +#include "score/mw/com/test/common_test_resources/skeleton_container.h" #include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" -#include "score/mw/com/test/methods/methods_test_resources/skeleton_container.h" #include "score/mw/com/test/methods/non_trivial_constructors/test_method_datatype.h" #include From bf10d924df111dd849517d4fc1ef8b51a29e3ed7 Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Tue, 26 May 2026 10:41:48 +0530 Subject: [PATCH 2/6] Update traits and traits tests for field get/set/notifier parameters --- score/mw/com/impl/traits.h | 4 ++-- score/mw/com/impl/traits_test.cpp | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/score/mw/com/impl/traits.h b/score/mw/com/impl/traits.h index 1c51a0587..9768b6d0d 100644 --- a/score/mw/com/impl/traits.h +++ b/score/mw/com/impl/traits.h @@ -142,7 +142,7 @@ class ProxyTrait // Note : at the moment the SkeletonField::Get implementation is not in the branch which means the skeleton and // proxy side does not have same template parameters. template - using Field = ProxyField; + using Field = ProxyField; template using Method = ProxyMethod; @@ -164,7 +164,7 @@ class SkeletonTrait template using Event = SkeletonEvent; - template + template using Field = SkeletonField; template diff --git a/score/mw/com/impl/traits_test.cpp b/score/mw/com/impl/traits_test.cpp index f99961ee5..4229738b4 100644 --- a/score/mw/com/impl/traits_test.cpp +++ b/score/mw/com/impl/traits_test.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -67,10 +68,13 @@ class MyInterface : public InterfaceTrait::Base public: using InterfaceTrait::Base::Base; + static constexpr bool kEnableSet{std::is_same_v}; + typename InterfaceTrait::template Event some_event{*this, kEventName}; - typename InterfaceTrait::template Field some_field{*this, kFieldName}; + typename InterfaceTrait::template Field some_field{*this, kFieldName}; typename InterfaceTrait::template Method some_method{*this, kMethodName}; }; + using MyProxy = AsProxy; using MySkeleton = AsSkeleton; From 40121facdc51990da07e684a9bbbd5ec97a00e7e Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Fri, 29 May 2026 13:19:02 +0530 Subject: [PATCH 3/6] mw/com: move field_initial_value test package under fields --- .../test/{ => fields}/field_initial_value/BUILD | 16 ++++++++++++---- .../{ => fields}/field_initial_value/client.cpp | 3 +-- .../field_initial_value/config/logging.json | 1 - .../config/mw_com_config.json | 7 +++---- .../field_initial_value/integration_test/BUILD | 4 ++-- .../integration_test/test_field_initial_value.py | 0 .../{ => fields}/field_initial_value/service.cpp | 5 ++--- .../field_initial_value/test_datatype.cpp | 2 +- .../field_initial_value/test_datatype.h | 8 ++++---- 9 files changed, 25 insertions(+), 21 deletions(-) rename score/mw/com/test/{ => fields}/field_initial_value/BUILD (82%) rename score/mw/com/test/{ => fields}/field_initial_value/client.cpp (97%) rename score/mw/com/test/{ => fields}/field_initial_value/config/logging.json (99%) rename score/mw/com/test/{ => fields}/field_initial_value/config/mw_com_config.json (78%) rename score/mw/com/test/{ => fields}/field_initial_value/integration_test/BUILD (87%) rename score/mw/com/test/{ => fields}/field_initial_value/integration_test/test_field_initial_value.py (100%) rename score/mw/com/test/{ => fields}/field_initial_value/service.cpp (96%) rename score/mw/com/test/{ => fields}/field_initial_value/test_datatype.cpp (88%) rename score/mw/com/test/{ => fields}/field_initial_value/test_datatype.h (82%) diff --git a/score/mw/com/test/field_initial_value/BUILD b/score/mw/com/test/fields/field_initial_value/BUILD similarity index 82% rename from score/mw/com/test/field_initial_value/BUILD rename to score/mw/com/test/fields/field_initial_value/BUILD index e68fbbd18..c08fa4b75 100644 --- a/score/mw/com/test/field_initial_value/BUILD +++ b/score/mw/com/test/fields/field_initial_value/BUILD @@ -40,7 +40,7 @@ cc_binary( features = COMPILER_WARNING_FEATURES + [ "aborts_upon_exception", ], - visibility = ["//score/mw/com/test/field_initial_value:__pkg__"], + visibility = ["//score/mw/com/test/fields/field_initial_value:__pkg__"], deps = [ ":test_datatype", "//score/mw/com", @@ -56,7 +56,7 @@ cc_binary( features = COMPILER_WARNING_FEATURES + [ "aborts_upon_exception", ], - visibility = ["//score/mw/com/test/field_initial_value:__pkg__"], + visibility = ["//score/mw/com/test/fields/field_initial_value:__pkg__"], deps = [ ":test_datatype", "//score/mw/com", @@ -75,7 +75,7 @@ pkg_application( ], visibility = [ "//platform/aas/test/mw/com:__pkg__", - "//score/mw/com/test/field_initial_value:__subpackages__", + "//score/mw/com/test/fields/field_initial_value:__subpackages__", ], ) @@ -89,6 +89,14 @@ pkg_application( ], visibility = [ "//platform/aas/test/mw/com:__pkg__", - "//score/mw/com/test/field_initial_value:__subpackages__", + "//score/mw/com/test/fields/field_initial_value:__subpackages__", ], ) + +test_suite( + name = "component_tests", + tests = [ + "//score/mw/com/test/fields/field_initial_value/integration_test:test_field_initial_value", + ], + visibility = ["//score/mw/com/test/fields:__pkg__"], +) diff --git a/score/mw/com/test/field_initial_value/client.cpp b/score/mw/com/test/fields/field_initial_value/client.cpp similarity index 97% rename from score/mw/com/test/field_initial_value/client.cpp rename to score/mw/com/test/fields/field_initial_value/client.cpp index b58464eab..bdf0b1b11 100644 --- a/score/mw/com/test/field_initial_value/client.cpp +++ b/score/mw/com/test/fields/field_initial_value/client.cpp @@ -12,7 +12,7 @@ *******************************************************************************/ #include "score/mw/com/test/common_test_resources/sctf_test_runner.h" -#include "score/mw/com/test/field_initial_value/test_datatype.h" +#include "score/mw/com/test/fields/field_initial_value/test_datatype.h" #include "score/mw/com/types.h" #include @@ -122,7 +122,6 @@ int main(int argc, const char** argv) const auto& run_parameters = test_runner.GetRunParameters(); const auto num_retries = run_parameters.GetNumRetries(); const auto retry_backoff_time = run_parameters.GetRetryBackoffTime(); - const auto stop_token = test_runner.GetStopToken(); return score::mw::com::test::run_client(num_retries, retry_backoff_time); } diff --git a/score/mw/com/test/field_initial_value/config/logging.json b/score/mw/com/test/fields/field_initial_value/config/logging.json similarity index 99% rename from score/mw/com/test/field_initial_value/config/logging.json rename to score/mw/com/test/fields/field_initial_value/config/logging.json index f224f16f9..de20e5520 100644 --- a/score/mw/com/test/field_initial_value/config/logging.json +++ b/score/mw/com/test/fields/field_initial_value/config/logging.json @@ -5,4 +5,3 @@ "logLevelThresholdConsole": "kDebug", "logMode": "kRemote|kConsole" } - diff --git a/score/mw/com/test/field_initial_value/config/mw_com_config.json b/score/mw/com/test/fields/field_initial_value/config/mw_com_config.json similarity index 78% rename from score/mw/com/test/field_initial_value/config/mw_com_config.json rename to score/mw/com/test/fields/field_initial_value/config/mw_com_config.json index bbb0beba5..36b40fe8e 100644 --- a/score/mw/com/test/field_initial_value/config/mw_com_config.json +++ b/score/mw/com/test/fields/field_initial_value/config/mw_com_config.json @@ -1,7 +1,7 @@ { "serviceTypes": [ { - "serviceTypeName": "/score/mw/com/test/field_initial_value", + "serviceTypeName": "/score/mw/com/test/fields/field_initial_value", "version": { "major": 1, "minor": 0 @@ -22,8 +22,8 @@ ], "serviceInstances": [ { - "instanceSpecifier": "test/field_initial_value", - "serviceTypeName": "/score/mw/com/test/field_initial_value", + "instanceSpecifier": "test/fields/field_initial_value", + "serviceTypeName": "/score/mw/com/test/fields/field_initial_value", "version": { "major": 1, "minor": 0 @@ -45,4 +45,3 @@ } ] } - diff --git a/score/mw/com/test/field_initial_value/integration_test/BUILD b/score/mw/com/test/fields/field_initial_value/integration_test/BUILD similarity index 87% rename from score/mw/com/test/field_initial_value/integration_test/BUILD rename to score/mw/com/test/fields/field_initial_value/integration_test/BUILD index 0c75b747b..85fe56d70 100644 --- a/score/mw/com/test/field_initial_value/integration_test/BUILD +++ b/score/mw/com/test/fields/field_initial_value/integration_test/BUILD @@ -16,8 +16,8 @@ load("//quality/integration_testing:integration_testing.bzl", "integration_test" pkg_filegroup( name = "filesystem", srcs = [ - "//score/mw/com/test/field_initial_value:client-pkg", - "//score/mw/com/test/field_initial_value:service-pkg", + "//score/mw/com/test/fields/field_initial_value:client-pkg", + "//score/mw/com/test/fields/field_initial_value:service-pkg", ], ) diff --git a/score/mw/com/test/field_initial_value/integration_test/test_field_initial_value.py b/score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py similarity index 100% rename from score/mw/com/test/field_initial_value/integration_test/test_field_initial_value.py rename to score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py diff --git a/score/mw/com/test/field_initial_value/service.cpp b/score/mw/com/test/fields/field_initial_value/service.cpp similarity index 96% rename from score/mw/com/test/field_initial_value/service.cpp rename to score/mw/com/test/fields/field_initial_value/service.cpp index b17710b43..c77c39b6e 100644 --- a/score/mw/com/test/field_initial_value/service.cpp +++ b/score/mw/com/test/fields/field_initial_value/service.cpp @@ -12,11 +12,12 @@ *******************************************************************************/ #include "score/mw/com/test/common_test_resources/sctf_test_runner.h" -#include "score/mw/com/test/field_initial_value/test_datatype.h" +#include "score/mw/com/test/fields/field_initial_value/test_datatype.h" #include #include +#include #include #include @@ -26,8 +27,6 @@ namespace score::mw::com::test namespace { -using namespace std::chrono_literals; - int run_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) { auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); diff --git a/score/mw/com/test/field_initial_value/test_datatype.cpp b/score/mw/com/test/fields/field_initial_value/test_datatype.cpp similarity index 88% rename from score/mw/com/test/field_initial_value/test_datatype.cpp rename to score/mw/com/test/fields/field_initial_value/test_datatype.cpp index ab6b0f1ac..3a2a65351 100644 --- a/score/mw/com/test/field_initial_value/test_datatype.cpp +++ b/score/mw/com/test/fields/field_initial_value/test_datatype.cpp @@ -11,4 +11,4 @@ * SPDX-License-Identifier: Apache-2.0 *******************************************************************************/ -#include "score/mw/com/test/field_initial_value/test_datatype.h" +#include "score/mw/com/test/fields/field_initial_value/test_datatype.h" diff --git a/score/mw/com/test/field_initial_value/test_datatype.h b/score/mw/com/test/fields/field_initial_value/test_datatype.h similarity index 82% rename from score/mw/com/test/field_initial_value/test_datatype.h rename to score/mw/com/test/fields/field_initial_value/test_datatype.h index 3f7348692..42d0278bf 100644 --- a/score/mw/com/test/field_initial_value/test_datatype.h +++ b/score/mw/com/test/fields/field_initial_value/test_datatype.h @@ -11,8 +11,8 @@ * SPDX-License-Identifier: Apache-2.0 *******************************************************************************/ -#ifndef SCORE_MW_COM_TEST_FIELD_INITIAL_VALUE_TEST_DATATYPE_H -#define SCORE_MW_COM_TEST_FIELD_INITIAL_VALUE_TEST_DATATYPE_H +#ifndef SCORE_MW_COM_TEST_FIELDS_FIELD_INITIAL_VALUE_TEST_DATATYPE_H +#define SCORE_MW_COM_TEST_FIELDS_FIELD_INITIAL_VALUE_TEST_DATATYPE_H #include "score/mw/com/types.h" @@ -22,7 +22,7 @@ namespace score::mw::com::test { -constexpr const char* const kInstanceSpecifierString = "test/field_initial_value"; +constexpr const char* const kInstanceSpecifierString = "test/fields/field_initial_value"; const std::int32_t kTestValue = 18; template @@ -39,4 +39,4 @@ using TestDataSkeleton = score::mw::com::AsSkeleton; } // namespace score::mw::com::test -#endif // SCORE_MW_COM_TEST_FIELD_RECEIVE_HANDLER_SRC_LOLA_H +#endif // SCORE_MW_COM_TEST_FIELDS_FIELD_INITIAL_VALUE_TEST_DATATYPE_H From 8a0bf06f6ea273fe63095d81c09f010f6f6105b6 Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Fri, 29 May 2026 13:19:31 +0530 Subject: [PATCH 4/6] mw/com: add fields test suite root package --- score/mw/com/test/fields/BUILD | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 score/mw/com/test/fields/BUILD diff --git a/score/mw/com/test/fields/BUILD b/score/mw/com/test/fields/BUILD new file mode 100644 index 000000000..7bf308537 --- /dev/null +++ b/score/mw/com/test/fields/BUILD @@ -0,0 +1,21 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + +test_suite( + name = "component_tests", + tests = [ + "//score/mw/com/test/fields/field_initial_value:component_tests", + "//score/mw/com/test/fields/set_and_notifier:component_tests", + ], + visibility = ["//score/mw/com/test:__pkg__"], +) From 4039570efdf10eb5579341a90fffcb35e5200ba0 Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Fri, 29 May 2026 13:19:31 +0530 Subject: [PATCH 5/6] mw/com: add set_and_notifier field integration tests --- .../mw/com/test/fields/set_and_notifier/BUILD | 92 ++++++ .../set_and_notifier/config/logging.json | 7 + .../config/mw_com_config.json | 48 +++ .../fields_test_resources/BUILD | 56 ++++ .../fields_test_resources/field_consumer.cpp | 300 ++++++++++++++++++ .../fields_test_resources/field_consumer.h | 28 ++ .../fields_test_resources/field_provider.cpp | 149 +++++++++ .../fields_test_resources/field_provider.h | 31 ++ .../fields_test_resources/test_datatype.cpp | 14 + .../fields_test_resources/test_datatype.h | 59 ++++ .../set_and_notifier/integration_test/BUILD | 32 ++ .../test_field_set_and_notifier.py | 39 +++ .../fields/set_and_notifier/main_client.cpp | 30 ++ .../fields/set_and_notifier/main_service.cpp | 29 ++ 14 files changed, 914 insertions(+) create mode 100644 score/mw/com/test/fields/set_and_notifier/BUILD create mode 100644 score/mw/com/test/fields/set_and_notifier/config/logging.json create mode 100644 score/mw/com/test/fields/set_and_notifier/config/mw_com_config.json create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/BUILD create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py create mode 100644 score/mw/com/test/fields/set_and_notifier/main_client.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/main_service.cpp diff --git a/score/mw/com/test/fields/set_and_notifier/BUILD b/score/mw/com/test/fields/set_and_notifier/BUILD new file mode 100644 index 000000000..6933ede4d --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/BUILD @@ -0,0 +1,92 @@ +# ******************************************************************************* +# 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("//bazel/tools:json_schema_validator.bzl", "validate_json_schema_test") +load("//score/mw/com/test:pkg_application.bzl", "pkg_application") + +validate_json_schema_test( + name = "validate_lola_schema", + json = "config/mw_com_config.json", + schema = "//score/mw/com:config_schema", + tags = ["lint"], +) + +cc_binary( + name = "main_service", + srcs = ["main_service.cpp"], + data = ["config/mw_com_config.json"], + features = COMPILER_WARNING_FEATURES + [ + "aborts_upon_exception", + ], + visibility = ["//score/mw/com/test/fields:__pkg__"], + deps = [ + "//score/mw/com", + "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/fields/set_and_notifier/fields_test_resources:field_provider", + "@score_baselibs//score/mw/log", + ], +) + +cc_binary( + name = "main_client", + srcs = ["main_client.cpp"], + data = ["config/mw_com_config.json"], + features = COMPILER_WARNING_FEATURES + [ + "aborts_upon_exception", + ], + visibility = ["//score/mw/com/test/fields:__pkg__"], + deps = [ + "//score/mw/com", + "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/fields/set_and_notifier/fields_test_resources:field_consumer", + "@score_baselibs//score/mw/log", + ], +) + +pkg_application( + name = "main_service-pkg", + app_name = "MainServiceApp", + bin = [":main_service"], + etc = [ + "config/mw_com_config.json", + "config/logging.json", + ], + visibility = [ + "//platform/aas/test/mw/com:__pkg__", + "//score/mw/com/test/fields/set_and_notifier:__subpackages__", + ], +) + +pkg_application( + name = "main_client-pkg", + app_name = "MainClientApp", + bin = [":main_client"], + etc = [ + "config/mw_com_config.json", + "config/logging.json", + ], + visibility = [ + "//platform/aas/test/mw/com:__pkg__", + "//score/mw/com/test/fields/set_and_notifier:__subpackages__", + ], +) + +test_suite( + name = "component_tests", + tests = [ + "//score/mw/com/test/fields/set_and_notifier/integration_test:test_field_set_and_notifier", + ], + visibility = ["//score/mw/com/test/fields:__pkg__"], +) diff --git a/score/mw/com/test/fields/set_and_notifier/config/logging.json b/score/mw/com/test/fields/set_and_notifier/config/logging.json new file mode 100644 index 000000000..de20e5520 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/config/logging.json @@ -0,0 +1,7 @@ +{ + "appId": "FRH", + "appDesc": "field_initial_value", + "logLevel": "kDebug", + "logLevelThresholdConsole": "kDebug", + "logMode": "kRemote|kConsole" +} diff --git a/score/mw/com/test/fields/set_and_notifier/config/mw_com_config.json b/score/mw/com/test/fields/set_and_notifier/config/mw_com_config.json new file mode 100644 index 000000000..60df3e6a9 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/config/mw_com_config.json @@ -0,0 +1,48 @@ +{ + "serviceTypes": [ + { + "serviceTypeName": "/score/mw/com/test/fields/set_and_notifier", + "version": { + "major": 1, + "minor": 0 + }, + "bindings": [ + { + "binding": "SHM", + "serviceId": 3428, + "fields": [ + { + "fieldName": "test_field", + "fieldId": 1, + "Set": true + } + ] + } + ] + } + ], + "serviceInstances": [ + { + "instanceSpecifier": "test/fields/set_and_notifier", + "serviceTypeName": "/score/mw/com/test/fields/set_and_notifier", + "version": { + "major": 1, + "minor": 0 + }, + "instances": [ + { + "instanceId": 1024, + "asil-level": "QM", + "binding": "SHM", + "fields": [ + { + "fieldName": "test_field", + "maxSubscribers": 1, + "numberOfSampleSlots": 1 + } + ] + } + ] + } + ] +} diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD new file mode 100644 index 000000000..f0d4d4ffc --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD @@ -0,0 +1,56 @@ +# ******************************************************************************* +# 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_library") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") + +cc_library( + name = "test_datatype", + srcs = ["test_datatype.cpp"], + hdrs = ["test_datatype.h"], + features = COMPILER_WARNING_FEATURES, + visibility = [ + "//score/mw/com/test/fields/set_and_notifier:__subpackages__", + ], + deps = [ + "//score/mw/com", + ], +) + +cc_library( + name = "field_consumer", + srcs = ["field_consumer.cpp"], + hdrs = ["field_consumer.h"], + features = COMPILER_WARNING_FEATURES, + visibility = [ + "//score/mw/com/test/fields/set_and_notifier:__subpackages__", + ], + deps = [ + ":test_datatype", + "//score/mw/com", + ], +) + +cc_library( + name = "field_provider", + srcs = ["field_provider.cpp"], + hdrs = ["field_provider.h"], + features = COMPILER_WARNING_FEATURES, + visibility = [ + "//score/mw/com/test/fields/set_and_notifier:__subpackages__", + ], + deps = [ + ":test_datatype", + "//score/mw/com", + ], +) diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp new file mode 100644 index 000000000..1cee8398a --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp @@ -0,0 +1,300 @@ +/******************************************************************************* + * 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/test/fields/set_and_notifier/fields_test_resources/field_consumer.h" + +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h" +#include "score/mw/com/types.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace score::mw::com::test +{ +namespace +{ + +constexpr auto kMaxNumSamples{1U}; + +template +bool WaitForSubscription(FieldType& field, std::size_t retries, const std::chrono::milliseconds retry_backoff_time) +{ + while (field.GetSubscriptionState() != score::mw::com::impl::SubscriptionState::kSubscribed) + { + std::this_thread::sleep_for(retry_backoff_time); + if (retries == 0) + { + return false; + } + --retries; + } + return true; +} + +template +bool PollForValue(FieldType& field, + const std::int32_t expected_value, + std::size_t retries, + const std::chrono::milliseconds retry_backoff_time) +{ + while (retries > 0) + { + score::cpp::optional received_value; + const auto samples_result = field.GetNewSamples( + [&received_value](const auto& sample_ptr) noexcept { + received_value = *sample_ptr; + }, + kMaxNumSamples); + + if (samples_result.has_value() && received_value.has_value() && received_value.value() == expected_value) + { + return true; + } + + std::this_thread::sleep_for(retry_backoff_time); + --retries; + } + + return false; +} + +template +bool SetWithRetries(FieldType& field, + std::int32_t& requested_value, + std::int32_t& accepted_value, + std::size_t retries, + const std::chrono::milliseconds retry_backoff_time, + std::string& last_error) +{ + while (true) + { + const auto set_result = field.Set(requested_value); + if (set_result.has_value()) + { + accepted_value = *(set_result.value()); + return true; + } + + std::ostringstream error_stream; + error_stream << set_result.error(); + last_error = error_stream.str(); + + if (retries == 0) + { + return false; + } + + --retries; + std::this_thread::sleep_for(retry_backoff_time); + } +} + +int run_notifier_client(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) +{ + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) + { + std::cerr << "Unable to create instance specifier, terminating\n"; + return -7; + } + auto instance_specifier = std::move(instance_specifier_result).value(); + + std::promise> service_discovery_promise{}; + auto service_discovery_future = service_discovery_promise.get_future(); + auto handles_result = InitialOnlyProxy::StartFindService( + [moved_service_discovery_promise = std::move(service_discovery_promise)](auto handles, auto handle) mutable { + moved_service_discovery_promise.set_value(handles); + score::cpp::ignore = InitialOnlyProxy::StopFindService(handle); + }, + std::move(instance_specifier)); + if (!handles_result.has_value()) + { + std::cerr << "Unable to get handles, terminating\n"; + return -1; + } + + auto handles = service_discovery_future.get(); + if (handles.empty()) + { + std::cerr << "Unable to find lola service, terminating\n"; + return -2; + } + + auto proxy_result = InitialOnlyProxy::Create(handles[0]); + if (!proxy_result.has_value()) + { + std::cerr << "Unable to create InitialOnlyProxy: " << proxy_result.error() << "\n"; + return -3; + } + + auto& proxy = proxy_result.value(); + std::ignore = proxy.test_field.Subscribe(kMaxNumSamples); + if (!WaitForSubscription(proxy.test_field, num_retries, retry_backoff_time)) + { + std::cerr << "Subscription failed in notifier scenario.\n"; + return -4; + } + + const bool initial_value_received = PollForValue(proxy.test_field, kInitialValue, num_retries, retry_backoff_time); + proxy.test_field.Unsubscribe(); + + if (!initial_value_received) + { + std::cerr << "Did not receive expected initial value " << kInitialValue << " in notifier scenario.\n"; + return -5; + } + + return 0; +} + +int run_set_client(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) +{ + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) + { + std::cerr << "Unable to create instance specifier, terminating\n"; + return -27; + } + auto instance_specifier = std::move(instance_specifier_result).value(); + + std::promise> service_discovery_promise{}; + auto service_discovery_future = service_discovery_promise.get_future(); + auto handles_result = SetEnabledProxy::StartFindService( + [moved_service_discovery_promise = std::move(service_discovery_promise)](auto handles, auto handle) mutable { + moved_service_discovery_promise.set_value(handles); + score::cpp::ignore = SetEnabledProxy::StopFindService(handle); + }, + std::move(instance_specifier)); + if (!handles_result.has_value()) + { + std::cerr << "Unable to get handles, terminating\n"; + return -21; + } + + auto handles = service_discovery_future.get(); + if (handles.empty()) + { + std::cerr << "Unable to find lola service, terminating\n"; + return -22; + } + + auto proxy_result = SetEnabledProxy::Create(handles[0]); + if (!proxy_result.has_value()) + { + std::cerr << "Unable to create SetEnabledProxy: " << proxy_result.error() << "\n"; + return -13; + } + + auto& proxy = proxy_result.value(); + std::ignore = proxy.test_field.Subscribe(kMaxNumSamples); + if (!WaitForSubscription(proxy.test_field, num_retries, retry_backoff_time)) + { + std::cerr << "Subscription failed in set scenario.\n"; + return -14; + } + + const bool initial_value_received = PollForValue(proxy.test_field, kInitialValue, num_retries, retry_backoff_time); + if (!initial_value_received) + { + std::cerr << "Did not receive initial value " << kInitialValue << " in set scenario.\n"; + return -18; + } + + std::int32_t valid_requested_value = kSetValidValue; + std::int32_t valid_accepted_value{0}; + std::string valid_set_error; + if (!SetWithRetries(proxy.test_field, + valid_requested_value, + valid_accepted_value, + num_retries, + retry_backoff_time, + valid_set_error)) + { + std::cerr << "Valid Set call failed: " << valid_set_error << "\n"; + return -19; + } + + if (valid_accepted_value != kSetValidValue) + { + std::cerr << "Valid Set accepted value mismatch. Expected " << kSetValidValue << " but got " + << valid_accepted_value << "\n"; + return -20; + } + + const bool valid_value_received = PollForValue(proxy.test_field, kSetValidValue, num_retries, retry_backoff_time); + if (!valid_value_received) + { + std::cerr << "Did not receive valid set value " << kSetValidValue << " after Set call.\n"; + return -21; + } + + std::int32_t requested_value = kSetRequestValue; + std::int32_t accepted_value{0}; + std::string invalid_set_error; + if (!SetWithRetries( + proxy.test_field, requested_value, accepted_value, num_retries, retry_backoff_time, invalid_set_error)) + { + std::cerr << "Set call failed: " << invalid_set_error << "\n"; + return -22; + } + + if (accepted_value != kSetAcceptedValue) + { + std::cerr << "Set accepted value mismatch. Expected " << kSetAcceptedValue << " but got " << accepted_value + << "\n"; + return -23; + } + + const bool clamped_value_received = + PollForValue(proxy.test_field, kSetAcceptedValue, num_retries, retry_backoff_time); + proxy.test_field.Unsubscribe(); + + if (!clamped_value_received) + { + std::cerr << "Did not receive clamped value " << kSetAcceptedValue << " after Set call.\n"; + return -24; + } + + return 0; +} + +} // namespace + +int run_client(const std::size_t num_retries, + const std::chrono::milliseconds retry_backoff_time, + const std::string& mode) +{ + if (mode == "notifier") + { + return run_notifier_client(num_retries, retry_backoff_time); + } + if (mode == "set") + { + return run_set_client(num_retries, retry_backoff_time); + } + + // TODO: Add "get" mode client scenario coverage once getter-enabled field variant is introduced. + std::cerr << "Unsupported mode passed to client: " << mode << "\n"; + return -1; +} + +} // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h new file mode 100644 index 000000000..c7455e770 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_CONSUMER_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_CONSUMER_H + +#include +#include +#include + +namespace score::mw::com::test +{ + +int run_client(std::size_t num_retries, std::chrono::milliseconds retry_backoff_time, const std::string& mode); + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_CONSUMER_H diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp new file mode 100644 index 000000000..c945f8e63 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp @@ -0,0 +1,149 @@ +/******************************************************************************* + * 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/test/fields/set_and_notifier/fields_test_resources/field_provider.h" + +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h" + +#include +#include +#include +#include +#include + +namespace score::mw::com::test +{ +namespace +{ + +int run_notifier_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) +{ + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) + { + std::cerr << "Unable to create instance specifier, terminating\n"; + return -3; + } + auto instance_specifier = std::move(instance_specifier_result).value(); + + auto service_result = InitialOnlySkeleton::Create(std::move(instance_specifier)); + if (!service_result.has_value()) + { + std::cerr << "Unable to construct InitialOnlySkeleton: " << service_result.error() << ", bailing!\n"; + return -4; + } + + InitialOnlySkeleton& service{service_result.value()}; + + const auto update_result = service.test_field.Update(kInitialValue); + if (!update_result.has_value()) + { + std::cerr << "Unable to update initial field value: " << update_result.error() << ", bailing!\n"; + return -6; + } + const auto offer_result = service.OfferService(); + if (!offer_result.has_value()) + { + std::cerr << "Unable to offer InitialOnlySkeleton: " << offer_result.error() << ", bailing!\n"; + return -5; + } + + while (!stop_token.stop_requested()) + { + std::this_thread::sleep_for(cycle_time); + } + + service.StopOfferService(); + + return 0; +} + +int run_set_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) +{ + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) + { + std::cerr << "Unable to create instance specifier, terminating\n"; + return -13; + } + auto instance_specifier = std::move(instance_specifier_result).value(); + + auto service_result = SetEnabledSkeleton::Create(std::move(instance_specifier)); + if (!service_result.has_value()) + { + std::cerr << "Unable to construct SetEnabledSkeleton: " << service_result.error() << ", bailing!\n"; + return -14; + } + + SetEnabledSkeleton& service{service_result.value()}; + const auto register_handler_result = service.test_field.RegisterSetHandler([](std::int32_t& value) noexcept { + if (value > kSetAcceptedValue) + { + value = kSetAcceptedValue; + } + if (value < 0) + { + value = 0; + } + }); + if (!register_handler_result.has_value()) + { + std::cerr << "Unable to register set handler: " << register_handler_result.error() << ", bailing!\n"; + return -15; + } + + const auto update_result = service.test_field.Update(kInitialValue); + if (!update_result.has_value()) + { + std::cerr << "Unable to update initial field value: " << update_result.error() << ", bailing!\n"; + return -16; + } + + const auto offer_result = service.OfferService(); + if (!offer_result.has_value()) + { + std::cerr << "Unable to offer SetEnabledSkeleton: " << offer_result.error() << ", bailing!\n"; + return -17; + } + + while (!stop_token.stop_requested()) + { + std::this_thread::sleep_for(cycle_time); + } + + service.StopOfferService(); + + return 0; +} + +} // namespace + +int run_service(const std::chrono::milliseconds& cycle_time, + const score::cpp::stop_token& stop_token, + const std::string& mode) +{ + if (mode == "notifier") + { + return run_notifier_service(cycle_time, stop_token); + } + if (mode == "set") + { + return run_set_service(cycle_time, stop_token); + } + + // TODO: Add "get" mode service scenario coverage once getter-enabled field variant is introduced. + std::cerr << "Unsupported mode passed to service: " << mode << "\n"; + return -1; +} + +} // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h new file mode 100644 index 000000000..6d6d2386c --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_PROVIDER_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_PROVIDER_H + +#include + +#include +#include + +namespace score::mw::com::test +{ + +int run_service(const std::chrono::milliseconds& cycle_time, + const score::cpp::stop_token& stop_token, + const std::string& mode); + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_FIELD_PROVIDER_H diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.cpp b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.cpp new file mode 100644 index 000000000..1acbc6aac --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.cpp @@ -0,0 +1,14 @@ +/******************************************************************************* + * 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/test/fields/set_and_notifier/fields_test_resources/test_datatype.h" diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h new file mode 100644 index 000000000..b938631e4 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h @@ -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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_DATATYPE_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_DATATYPE_H + +#include "score/mw/com/types.h" + +#include + +namespace score::mw::com::test +{ + +constexpr const char* const kInstanceSpecifierString = "test/fields/set_and_notifier"; + +const std::int32_t kInitialValue = 18; +const std::int32_t kSetValidValue = 42; +const std::int32_t kSetRequestValue = 1234; +const std::int32_t kSetAcceptedValue = 100; + +template +class InitialOnlyInterface : public T::Base +{ + public: + using T::Base::Base; + + typename T::template Field test_field{*this, "test_field"}; +}; + +template +class SetEnabledInterface : public T::Base +{ + public: + using T::Base::Base; + + typename T::template Field test_field{*this, "test_field"}; +}; + +using InitialOnlyProxy = score::mw::com::AsProxy; +using InitialOnlySkeleton = score::mw::com::AsSkeleton; + +using SetEnabledProxy = score::mw::com::AsProxy; +using SetEnabledSkeleton = score::mw::com::AsSkeleton; + +// TODO: Add a getter-enabled field interface type for dedicated "get" mode integration scenarios. + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_DATATYPE_H diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD b/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD new file mode 100644 index 000000000..14c2344a3 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/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:mappings.bzl", "pkg_filegroup") +load("//quality/integration_testing:integration_testing.bzl", "integration_test") + +pkg_filegroup( + name = "filesystem", + srcs = [ + "//score/mw/com/test/fields/set_and_notifier:main_client-pkg", + "//score/mw/com/test/fields/set_and_notifier:main_service-pkg", + ], +) + +integration_test( + name = "test_field_set_and_notifier", + timeout = "moderate", + srcs = [ + "test_field_set_and_notifier.py", + ], + filesystem = ":filesystem", +) diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py new file mode 100644 index 000000000..aeb530512 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py @@ -0,0 +1,39 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + + +def client(target, mode, **kwargs): + args = ["--num-retries", "20", "--backoff-time", "50", "--mode", mode] + return target.wrap_exec("bin/main_client", args, cwd="/opt/MainClientApp", wait_on_exit=True, **kwargs) + + +def service(target, mode, **kwargs): + args = ["--cycle-time", "250", "--mode", mode] + return target.wrap_exec("bin/main_service", args, cwd="/opt/MainServiceApp", **kwargs) + + +def test_field_notifier_initial_value(target): + """Test field initial value exchange between service and client.""" + with service(target, "notifier"): + with client(target, "notifier"): + pass + + +def test_field_set_value(target): + """Test field set exchange and accepted value propagation between service and client.""" + with service(target, "set"): + with client(target, "set"): + pass + + +# TODO: Add a dedicated get scenario test once getter-enabled field mode is available. diff --git a/score/mw/com/test/fields/set_and_notifier/main_client.cpp b/score/mw/com/test/fields/set_and_notifier/main_client.cpp new file mode 100644 index 000000000..0adb5a6d9 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/main_client.cpp @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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/test/common_test_resources/sctf_test_runner.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h" + +#include + +int main(int argc, const char** argv) +{ + using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; + + const std::vector allowed_parameters{ + Parameters::NUM_RETRIES, Parameters::RETRY_BACKOFF_TIME, Parameters::MODE}; + score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); + const auto& run_parameters = test_runner.GetRunParameters(); + + return score::mw::com::test::run_client( + run_parameters.GetNumRetries(), run_parameters.GetRetryBackoffTime(), run_parameters.GetMode()); +} diff --git a/score/mw/com/test/fields/set_and_notifier/main_service.cpp b/score/mw/com/test/fields/set_and_notifier/main_service.cpp new file mode 100644 index 000000000..c912b689d --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/main_service.cpp @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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/test/common_test_resources/sctf_test_runner.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h" + +#include + +int main(int argc, const char** argv) +{ + using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; + + const std::vector allowed_parameters{Parameters::CYCLE_TIME, Parameters::MODE}; + score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); + const auto& run_parameters = test_runner.GetRunParameters(); + + return score::mw::com::test::run_service( + run_parameters.GetCycleTime(), test_runner.GetStopToken(), run_parameters.GetMode()); +} From 7e2254f75be1e3551e1a428d30b887d6d76e1b54 Mon Sep 17 00:00:00 2001 From: sahithinukala Date: Tue, 2 Jun 2026 14:40:21 +0530 Subject: [PATCH 6/6] mw/com: Address review comments for fields integration tests --- score/mw/com/test/fields/BUILD | 9 - .../com/test/fields/field_initial_value/BUILD | 13 +- .../fields/field_initial_value/client.cpp | 12 ++ .../test_field_initial_value.py | 2 +- .../fields/field_initial_value/service.cpp | 53 +++--- .../mw/com/test/fields/set_and_notifier/BUILD | 35 ++-- .../set_and_notifier/config/logging.json | 4 +- .../test/fields/set_and_notifier/consumer.cpp | 72 ++++++++ .../fields_test_resources/BUILD | 13 +- .../fields_test_resources/field_consumer.cpp | 165 ++++++++---------- .../fields_test_resources/field_consumer.h | 2 +- .../fields_test_resources/field_provider.cpp | 93 +++++----- .../fields_test_resources/field_provider.h | 5 +- .../initial_only_interface.h | 33 ++++ .../set_enabled_interface.h | 33 ++++ .../fields_test_resources/test_constants.h | 31 ++++ .../fields_test_resources/test_datatype.h | 29 +-- .../set_and_notifier/integration_test/BUILD | 24 ++- .../integration_test/test_fixture.py | 23 +++ .../integration_test/test_get.py | 18 ++ .../integration_test/test_get_and_notifier.py | 19 ++ .../integration_test/test_notifier.py | 21 +++ .../integration_test/test_set_and_get.py | 20 +++ ...d_notifier.py => test_set_and_notifier.py} | 23 +-- .../test_set_get_and_notifier.py | 20 +++ .../fields/set_and_notifier/main_client.cpp | 30 ---- .../fields/set_and_notifier/main_service.cpp | 29 --- .../test/fields/set_and_notifier/provider.cpp | 64 +++++++ .../test/methods/methods_test_resources/BUILD | 1 + 29 files changed, 572 insertions(+), 324 deletions(-) create mode 100644 score/mw/com/test/fields/set_and_notifier/consumer.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/initial_only_interface.h create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/set_enabled_interface.h create mode 100644 score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_fixture.py create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_get.py create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_get_and_notifier.py create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_notifier.py create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_get.py rename score/mw/com/test/fields/set_and_notifier/integration_test/{test_field_set_and_notifier.py => test_set_and_notifier.py} (51%) create mode 100644 score/mw/com/test/fields/set_and_notifier/integration_test/test_set_get_and_notifier.py delete mode 100644 score/mw/com/test/fields/set_and_notifier/main_client.cpp delete mode 100644 score/mw/com/test/fields/set_and_notifier/main_service.cpp create mode 100644 score/mw/com/test/fields/set_and_notifier/provider.cpp diff --git a/score/mw/com/test/fields/BUILD b/score/mw/com/test/fields/BUILD index 7bf308537..ca5de742e 100644 --- a/score/mw/com/test/fields/BUILD +++ b/score/mw/com/test/fields/BUILD @@ -10,12 +10,3 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* - -test_suite( - name = "component_tests", - tests = [ - "//score/mw/com/test/fields/field_initial_value:component_tests", - "//score/mw/com/test/fields/set_and_notifier:component_tests", - ], - visibility = ["//score/mw/com/test:__pkg__"], -) diff --git a/score/mw/com/test/fields/field_initial_value/BUILD b/score/mw/com/test/fields/field_initial_value/BUILD index c08fa4b75..d32a1198b 100644 --- a/score/mw/com/test/fields/field_initial_value/BUILD +++ b/score/mw/com/test/fields/field_initial_value/BUILD @@ -44,7 +44,9 @@ cc_binary( deps = [ ":test_datatype", "//score/mw/com", - "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/common_test_resources:fail_test", + "//score/mw/com/test/common_test_resources:stop_token_sig_term_handler", + "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", "@score_baselibs//score/mw/log", ], ) @@ -61,6 +63,7 @@ cc_binary( ":test_datatype", "//score/mw/com", "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", "@score_baselibs//score/mw/log", ], ) @@ -92,11 +95,3 @@ pkg_application( "//score/mw/com/test/fields/field_initial_value:__subpackages__", ], ) - -test_suite( - name = "component_tests", - tests = [ - "//score/mw/com/test/fields/field_initial_value/integration_test:test_field_initial_value", - ], - visibility = ["//score/mw/com/test/fields:__pkg__"], -) diff --git a/score/mw/com/test/fields/field_initial_value/client.cpp b/score/mw/com/test/fields/field_initial_value/client.cpp index bdf0b1b11..9a7a2862b 100644 --- a/score/mw/com/test/fields/field_initial_value/client.cpp +++ b/score/mw/com/test/fields/field_initial_value/client.cpp @@ -13,6 +13,7 @@ #include "score/mw/com/test/common_test_resources/sctf_test_runner.h" #include "score/mw/com/test/fields/field_initial_value/test_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" #include "score/mw/com/types.h" #include @@ -21,6 +22,7 @@ #include #include #include +#include #include namespace score::mw::com::test @@ -31,10 +33,19 @@ namespace constexpr auto kMaxNumSamples{1U}; +const std::string kInterprocessNotificationShmPath{"/field_initial_value_interprocess_notification"}; + int run_client(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) { using score::mw::com::test::TestDataProxy; + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) + { + std::cerr << "Unable to create ProcessSynchronizer, terminating\n"; + return -8; + } + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); if (!instance_specifier_result.has_value()) { @@ -106,6 +117,7 @@ int run_client(const std::size_t num_retries, const std::chrono::milliseconds re return -6; } + process_synchronizer_result->Notify(); return 0; } diff --git a/score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py b/score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py index e0dd9c991..1bf5b0f00 100644 --- a/score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py +++ b/score/mw/com/test/fields/field_initial_value/integration_test/test_field_initial_value.py @@ -18,7 +18,7 @@ def client(target, **kwargs): def service(target, **kwargs): - args = ["--cycle-time", "250"] + args = [] return target.wrap_exec("bin/service", args, cwd="/opt/ServiceApp", **kwargs) diff --git a/score/mw/com/test/fields/field_initial_value/service.cpp b/score/mw/com/test/fields/field_initial_value/service.cpp index c77c39b6e..56d613853 100644 --- a/score/mw/com/test/fields/field_initial_value/service.cpp +++ b/score/mw/com/test/fields/field_initial_value/service.cpp @@ -11,14 +11,17 @@ * SPDX-License-Identifier: Apache-2.0 *******************************************************************************/ -#include "score/mw/com/test/common_test_resources/sctf_test_runner.h" +#include "score/mw/com/runtime.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/mw/com/test/common_test_resources/stop_token_sig_term_handler.h" #include "score/mw/com/test/fields/field_initial_value/test_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" #include -#include +#include #include -#include +#include #include namespace score::mw::com::test @@ -27,21 +30,27 @@ namespace score::mw::com::test namespace { -int run_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) +const std::string kInterprocessNotificationShmPath{"/field_initial_value_interprocess_notification"}; + +void run_service(const score::cpp::stop_token& stop_token) { + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) + { + FailTest("Service: Unable to create ProcessSynchronizer"); + } + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); if (!instance_specifier_result.has_value()) { - std::cerr << "Unable to create instance specifier, terminating\n"; - return -3; + FailTest("Service: Unable to create instance specifier"); } auto instance_specifier = std::move(instance_specifier_result).value(); auto service_result = TestDataSkeleton::Create(std::move(instance_specifier)); if (!service_result.has_value()) { - std::cerr << "Unable to construct TestDataSkeleton: " << service_result.error() << ", bailing!\n"; - return -4; + FailTest("Service: Unable to construct TestDataSkeleton: ", service_result.error()); } TestDataSkeleton& lola_service{service_result.value()}; @@ -49,24 +58,20 @@ int run_service(const std::chrono::milliseconds& cycle_time, const score::cpp::s const auto update_result = lola_service.test_field.Update(kTestValue); if (!update_result.has_value()) { - std::cerr << "Unable to update test field: " << update_result.error() << ", bailing!\n"; - return -6; + FailTest("Service: Unable to update test field: ", update_result.error()); } const auto offer_result = lola_service.OfferService(); if (!offer_result.has_value()) { - std::cerr << "Unable to offer service for TestDataSkeleton: " << offer_result.error() << ", bailing!\n"; - return -5; + FailTest("Service: Unable to offer service for TestDataSkeleton: ", offer_result.error()); } - while (!stop_token.stop_requested()) + if (!process_synchronizer_result->WaitWithAbort(stop_token)) { - std::this_thread::sleep_for(cycle_time); + FailTest("Service: WaitWithAbort was stopped by stop_token instead of notification"); } lola_service.StopOfferService(); - - return 0; } } // namespace @@ -75,13 +80,15 @@ int run_service(const std::chrono::milliseconds& cycle_time, const score::cpp::s int main(int argc, const char** argv) { - using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; + score::mw::com::runtime::InitializeRuntime(argc, argv); - const std::vector allowed_parameters{Parameters::CYCLE_TIME}; - score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); - const auto& run_parameters = test_runner.GetRunParameters(); - const auto cycle_time = run_parameters.GetCycleTime(); - const auto stop_token = test_runner.GetStopToken(); + score::cpp::stop_source stop_source{}; + const bool sig_term_handler_setup_success = score::mw::com::SetupStopTokenSigTermHandler(stop_source); + if (!sig_term_handler_setup_success) + { + std::cerr << "Unable to set signal handler for SIGINT and/or SIGTERM, cautiously continuing\n"; + } - return score::mw::com::test::run_service(cycle_time, stop_token); + score::mw::com::test::run_service(stop_source.get_token()); + return EXIT_SUCCESS; } diff --git a/score/mw/com/test/fields/set_and_notifier/BUILD b/score/mw/com/test/fields/set_and_notifier/BUILD index 6933ede4d..6a0b0840b 100644 --- a/score/mw/com/test/fields/set_and_notifier/BUILD +++ b/score/mw/com/test/fields/set_and_notifier/BUILD @@ -24,8 +24,8 @@ validate_json_schema_test( ) cc_binary( - name = "main_service", - srcs = ["main_service.cpp"], + name = "provider", + srcs = ["provider.cpp"], data = ["config/mw_com_config.json"], features = COMPILER_WARNING_FEATURES + [ "aborts_upon_exception", @@ -33,15 +33,17 @@ cc_binary( visibility = ["//score/mw/com/test/fields:__pkg__"], deps = [ "//score/mw/com", - "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/common_test_resources:command_line_parser", + "//score/mw/com/test/common_test_resources:fail_test", + "//score/mw/com/test/common_test_resources:stop_token_sig_term_handler", "//score/mw/com/test/fields/set_and_notifier/fields_test_resources:field_provider", "@score_baselibs//score/mw/log", ], ) cc_binary( - name = "main_client", - srcs = ["main_client.cpp"], + name = "consumer", + srcs = ["consumer.cpp"], data = ["config/mw_com_config.json"], features = COMPILER_WARNING_FEATURES + [ "aborts_upon_exception", @@ -49,16 +51,17 @@ cc_binary( visibility = ["//score/mw/com/test/fields:__pkg__"], deps = [ "//score/mw/com", - "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/common_test_resources:command_line_parser", + "//score/mw/com/test/common_test_resources:fail_test", "//score/mw/com/test/fields/set_and_notifier/fields_test_resources:field_consumer", "@score_baselibs//score/mw/log", ], ) pkg_application( - name = "main_service-pkg", - app_name = "MainServiceApp", - bin = [":main_service"], + name = "provider-pkg", + app_name = "MainProviderApp", + bin = [":provider"], etc = [ "config/mw_com_config.json", "config/logging.json", @@ -70,9 +73,9 @@ pkg_application( ) pkg_application( - name = "main_client-pkg", - app_name = "MainClientApp", - bin = [":main_client"], + name = "consumer-pkg", + app_name = "MainConsumerApp", + bin = [":consumer"], etc = [ "config/mw_com_config.json", "config/logging.json", @@ -82,11 +85,3 @@ pkg_application( "//score/mw/com/test/fields/set_and_notifier:__subpackages__", ], ) - -test_suite( - name = "component_tests", - tests = [ - "//score/mw/com/test/fields/set_and_notifier/integration_test:test_field_set_and_notifier", - ], - visibility = ["//score/mw/com/test/fields:__pkg__"], -) diff --git a/score/mw/com/test/fields/set_and_notifier/config/logging.json b/score/mw/com/test/fields/set_and_notifier/config/logging.json index de20e5520..a49f8cded 100644 --- a/score/mw/com/test/fields/set_and_notifier/config/logging.json +++ b/score/mw/com/test/fields/set_and_notifier/config/logging.json @@ -1,6 +1,6 @@ { - "appId": "FRH", - "appDesc": "field_initial_value", + "appId": "FSAN", + "appDesc": "field_set_and_notifier", "logLevel": "kDebug", "logLevelThresholdConsole": "kDebug", "logMode": "kRemote|kConsole" diff --git a/score/mw/com/test/fields/set_and_notifier/consumer.cpp b/score/mw/com/test/fields/set_and_notifier/consumer.cpp new file mode 100644 index 000000000..4db24f4db --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/consumer.cpp @@ -0,0 +1,72 @@ +/******************************************************************************* + * 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/runtime.h" +#include "score/mw/com/test/common_test_resources/command_line_parser.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h" + +#include +#include +#include +#include +#include +#include + +int main(int argc, const char** argv) +{ + constexpr auto kNumRetriesArg = "num-retries"; + constexpr auto kBackoffTimeArg = "backoff-time"; + constexpr auto kModeArg = "mode"; + constexpr auto kServiceInstanceManifestArg = "service-instance-manifest"; + + const std::vector> parameter_description_pairs{ + {kNumRetriesArg, "Number of retries"}, + {kBackoffTimeArg, "Retry backoff time in milliseconds"}, + {kModeArg, "Consumer mode: notifier or set"}, + {kServiceInstanceManifestArg, "Path to the service instance manifest"}, + }; + + const auto args = score::mw::com::test::ParseCommandLineArguments(argc, argv, parameter_description_pairs); + + const auto num_retries_result = score::mw::com::test::GetValueIfProvided(args, kNumRetriesArg); + if (!num_retries_result.has_value()) + { + score::mw::com::test::FailTest("Consumer: missing or invalid --", kNumRetriesArg, " argument"); + } + + const auto backoff_time_result = score::mw::com::test::GetValueIfProvided(args, kBackoffTimeArg); + if (!backoff_time_result.has_value()) + { + score::mw::com::test::FailTest("Consumer: missing or invalid --", kBackoffTimeArg, " argument"); + } + + const auto mode_result = score::mw::com::test::GetValueIfProvided(args, kModeArg); + if (!mode_result.has_value()) + { + score::mw::com::test::FailTest("Consumer: missing or invalid --", kModeArg, " argument"); + } + + const auto manifest_result = + score::mw::com::test::GetValueIfProvided(args, kServiceInstanceManifestArg); + if (!manifest_result.has_value()) + { + score::mw::com::test::FailTest("Consumer: missing or invalid --", kServiceInstanceManifestArg, " argument"); + } + + score::mw::com::runtime::InitializeRuntime(score::mw::com::runtime::RuntimeConfiguration{manifest_result.value()}); + + score::mw::com::test::run_consumer( + num_retries_result.value(), std::chrono::milliseconds{backoff_time_result.value()}, mode_result.value()); + return EXIT_SUCCESS; +} diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD index f0d4d4ffc..36de65c78 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/BUILD @@ -17,7 +17,12 @@ load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER cc_library( name = "test_datatype", srcs = ["test_datatype.cpp"], - hdrs = ["test_datatype.h"], + hdrs = [ + "initial_only_interface.h", + "set_enabled_interface.h", + "test_constants.h", + "test_datatype.h", + ], features = COMPILER_WARNING_FEATURES, visibility = [ "//score/mw/com/test/fields/set_and_notifier:__subpackages__", @@ -38,6 +43,9 @@ cc_library( deps = [ ":test_datatype", "//score/mw/com", + "//score/mw/com/test/common_test_resources:fail_test", + "//score/mw/com/test/common_test_resources:proxy_container", + "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", ], ) @@ -52,5 +60,8 @@ cc_library( deps = [ ":test_datatype", "//score/mw/com", + "//score/mw/com/test/common_test_resources:fail_test", + "//score/mw/com/test/common_test_resources:skeleton_container", + "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", ], ) diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp index 1cee8398a..378eae826 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.cpp @@ -13,20 +13,22 @@ #include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/mw/com/test/common_test_resources/proxy_container.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h" #include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" #include "score/mw/com/types.h" #include #include #include -#include #include #include #include #include #include -#include namespace score::mw::com::test { @@ -34,6 +36,14 @@ namespace { constexpr auto kMaxNumSamples{1U}; +const std::string kInterprocessNotificationShmPath{"/fields_set_and_notifier_interprocess_notification"}; + +template +void NotifyAndFail(ProcessSynchronizer& process_synchronizer, Args&&... args) +{ + process_synchronizer.Notify(); + FailTest(std::forward(args)...); +} template bool WaitForSubscription(FieldType& field, std::size_t retries, const std::chrono::milliseconds retry_backoff_time) @@ -108,50 +118,33 @@ bool SetWithRetries(FieldType& field, } } -int run_notifier_client(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) +void run_notifier_consumer(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) { - auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); - if (!instance_specifier_result.has_value()) + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) { - std::cerr << "Unable to create instance specifier, terminating\n"; - return -7; + FailTest("Consumer: Could not create ProcessSynchronizer"); } - auto instance_specifier = std::move(instance_specifier_result).value(); + auto& process_synchronizer = process_synchronizer_result.value(); - std::promise> service_discovery_promise{}; - auto service_discovery_future = service_discovery_promise.get_future(); - auto handles_result = InitialOnlyProxy::StartFindService( - [moved_service_discovery_promise = std::move(service_discovery_promise)](auto handles, auto handle) mutable { - moved_service_discovery_promise.set_value(handles); - score::cpp::ignore = InitialOnlyProxy::StopFindService(handle); - }, - std::move(instance_specifier)); - if (!handles_result.has_value()) - { - std::cerr << "Unable to get handles, terminating\n"; - return -1; - } - - auto handles = service_discovery_future.get(); - if (handles.empty()) + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) { - std::cerr << "Unable to find lola service, terminating\n"; - return -2; + NotifyAndFail(process_synchronizer, "Consumer: Unable to create instance specifier"); } + auto instance_specifier = std::move(instance_specifier_result).value(); - auto proxy_result = InitialOnlyProxy::Create(handles[0]); - if (!proxy_result.has_value()) + ProxyContainer proxy_container{}; + if (!proxy_container.CreateProxy(std::move(instance_specifier))) { - std::cerr << "Unable to create InitialOnlyProxy: " << proxy_result.error() << "\n"; - return -3; + NotifyAndFail(process_synchronizer, "Consumer: Unable to create InitialOnlyProxy"); } - auto& proxy = proxy_result.value(); + auto& proxy = proxy_container.GetProxy(); std::ignore = proxy.test_field.Subscribe(kMaxNumSamples); if (!WaitForSubscription(proxy.test_field, num_retries, retry_backoff_time)) { - std::cerr << "Subscription failed in notifier scenario.\n"; - return -4; + NotifyAndFail(process_synchronizer, "Consumer: Subscription failed in notifier scenario"); } const bool initial_value_received = PollForValue(proxy.test_field, kInitialValue, num_retries, retry_backoff_time); @@ -159,64 +152,49 @@ int run_notifier_client(const std::size_t num_retries, const std::chrono::millis if (!initial_value_received) { - std::cerr << "Did not receive expected initial value " << kInitialValue << " in notifier scenario.\n"; - return -5; + NotifyAndFail(process_synchronizer, + "Consumer: Did not receive expected initial value ", + kInitialValue, + " in notifier scenario"); } - return 0; + process_synchronizer.Notify(); } -int run_set_client(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) +void run_set_consumer(const std::size_t num_retries, const std::chrono::milliseconds retry_backoff_time) { - auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); - if (!instance_specifier_result.has_value()) - { - std::cerr << "Unable to create instance specifier, terminating\n"; - return -27; - } - auto instance_specifier = std::move(instance_specifier_result).value(); - - std::promise> service_discovery_promise{}; - auto service_discovery_future = service_discovery_promise.get_future(); - auto handles_result = SetEnabledProxy::StartFindService( - [moved_service_discovery_promise = std::move(service_discovery_promise)](auto handles, auto handle) mutable { - moved_service_discovery_promise.set_value(handles); - score::cpp::ignore = SetEnabledProxy::StopFindService(handle); - }, - std::move(instance_specifier)); - if (!handles_result.has_value()) + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) { - std::cerr << "Unable to get handles, terminating\n"; - return -21; + FailTest("Consumer: Could not create ProcessSynchronizer"); } + auto& process_synchronizer = process_synchronizer_result.value(); - auto handles = service_discovery_future.get(); - if (handles.empty()) + auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); + if (!instance_specifier_result.has_value()) { - std::cerr << "Unable to find lola service, terminating\n"; - return -22; + NotifyAndFail(process_synchronizer, "Consumer: Unable to create instance specifier"); } + auto instance_specifier = std::move(instance_specifier_result).value(); - auto proxy_result = SetEnabledProxy::Create(handles[0]); - if (!proxy_result.has_value()) + ProxyContainer proxy_container{}; + if (!proxy_container.CreateProxy(std::move(instance_specifier))) { - std::cerr << "Unable to create SetEnabledProxy: " << proxy_result.error() << "\n"; - return -13; + NotifyAndFail(process_synchronizer, "Consumer: Unable to create SetEnabledProxy"); } - auto& proxy = proxy_result.value(); + auto& proxy = proxy_container.GetProxy(); std::ignore = proxy.test_field.Subscribe(kMaxNumSamples); if (!WaitForSubscription(proxy.test_field, num_retries, retry_backoff_time)) { - std::cerr << "Subscription failed in set scenario.\n"; - return -14; + NotifyAndFail(process_synchronizer, "Consumer: Subscription failed in set scenario"); } const bool initial_value_received = PollForValue(proxy.test_field, kInitialValue, num_retries, retry_backoff_time); if (!initial_value_received) { - std::cerr << "Did not receive initial value " << kInitialValue << " in set scenario.\n"; - return -18; + NotifyAndFail( + process_synchronizer, "Consumer: Did not receive initial value ", kInitialValue, " in set scenario"); } std::int32_t valid_requested_value = kSetValidValue; @@ -229,22 +207,23 @@ int run_set_client(const std::size_t num_retries, const std::chrono::millisecond retry_backoff_time, valid_set_error)) { - std::cerr << "Valid Set call failed: " << valid_set_error << "\n"; - return -19; + NotifyAndFail(process_synchronizer, "Consumer: Valid Set call failed: ", valid_set_error); } if (valid_accepted_value != kSetValidValue) { - std::cerr << "Valid Set accepted value mismatch. Expected " << kSetValidValue << " but got " - << valid_accepted_value << "\n"; - return -20; + NotifyAndFail(process_synchronizer, + "Consumer: Valid Set accepted value mismatch. Expected ", + kSetValidValue, + " but got ", + valid_accepted_value); } const bool valid_value_received = PollForValue(proxy.test_field, kSetValidValue, num_retries, retry_backoff_time); if (!valid_value_received) { - std::cerr << "Did not receive valid set value " << kSetValidValue << " after Set call.\n"; - return -21; + NotifyAndFail( + process_synchronizer, "Consumer: Did not receive valid set value ", kSetValidValue, " after Set call"); } std::int32_t requested_value = kSetRequestValue; @@ -253,15 +232,16 @@ int run_set_client(const std::size_t num_retries, const std::chrono::millisecond if (!SetWithRetries( proxy.test_field, requested_value, accepted_value, num_retries, retry_backoff_time, invalid_set_error)) { - std::cerr << "Set call failed: " << invalid_set_error << "\n"; - return -22; + NotifyAndFail(process_synchronizer, "Consumer: Set call failed: ", invalid_set_error); } if (accepted_value != kSetAcceptedValue) { - std::cerr << "Set accepted value mismatch. Expected " << kSetAcceptedValue << " but got " << accepted_value - << "\n"; - return -23; + NotifyAndFail(process_synchronizer, + "Consumer: Set accepted value mismatch. Expected ", + kSetAcceptedValue, + " but got ", + accepted_value); } const bool clamped_value_received = @@ -270,31 +250,32 @@ int run_set_client(const std::size_t num_retries, const std::chrono::millisecond if (!clamped_value_received) { - std::cerr << "Did not receive clamped value " << kSetAcceptedValue << " after Set call.\n"; - return -24; + NotifyAndFail( + process_synchronizer, "Consumer: Did not receive clamped value ", kSetAcceptedValue, " after Set call"); } - return 0; + process_synchronizer.Notify(); } } // namespace -int run_client(const std::size_t num_retries, - const std::chrono::milliseconds retry_backoff_time, - const std::string& mode) +void run_consumer(const std::size_t num_retries, + const std::chrono::milliseconds retry_backoff_time, + const std::string& mode) { if (mode == "notifier") { - return run_notifier_client(num_retries, retry_backoff_time); + run_notifier_consumer(num_retries, retry_backoff_time); + return; } if (mode == "set") { - return run_set_client(num_retries, retry_backoff_time); + run_set_consumer(num_retries, retry_backoff_time); + return; } - // TODO: Add "get" mode client scenario coverage once getter-enabled field variant is introduced. - std::cerr << "Unsupported mode passed to client: " << mode << "\n"; - return -1; + // TODO: Add "get" mode consumer scenario coverage once getter-enabled field variant is introduced. + FailTest("Consumer: Unsupported mode: ", mode); } } // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h index c7455e770..0aa22fd85 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h @@ -21,7 +21,7 @@ namespace score::mw::com::test { -int run_client(std::size_t num_retries, std::chrono::milliseconds retry_backoff_time, const std::string& mode); +void run_consumer(std::size_t num_retries, std::chrono::milliseconds retry_backoff_time, const std::string& mode); } // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp index c945f8e63..9f631366b 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.cpp @@ -13,12 +13,15 @@ #include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/mw/com/test/common_test_resources/skeleton_container.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h" #include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/process_synchronizer.h" #include #include #include -#include #include namespace score::mw::com::test @@ -26,66 +29,57 @@ namespace score::mw::com::test namespace { -int run_notifier_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) +const std::string kInterprocessNotificationShmPath{"/fields_set_and_notifier_interprocess_notification"}; + +void run_notifier_provider(const score::cpp::stop_token& stop_token) { - auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); - if (!instance_specifier_result.has_value()) + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) { - std::cerr << "Unable to create instance specifier, terminating\n"; - return -3; + FailTest("Provider: Could not create ProcessSynchronizer"); } - auto instance_specifier = std::move(instance_specifier_result).value(); - auto service_result = InitialOnlySkeleton::Create(std::move(instance_specifier)); - if (!service_result.has_value()) + SkeletonContainer skeleton_container{kInstanceSpecifierString}; + if (!skeleton_container.CreateSkeleton()) { - std::cerr << "Unable to construct InitialOnlySkeleton: " << service_result.error() << ", bailing!\n"; - return -4; + FailTest("Provider: Unable to construct InitialOnlySkeleton"); } - InitialOnlySkeleton& service{service_result.value()}; + auto& service = skeleton_container.GetSkeleton(); const auto update_result = service.test_field.Update(kInitialValue); if (!update_result.has_value()) { - std::cerr << "Unable to update initial field value: " << update_result.error() << ", bailing!\n"; - return -6; + FailTest("Provider: Unable to update initial field value: ", update_result.error()); } - const auto offer_result = service.OfferService(); - if (!offer_result.has_value()) + if (!skeleton_container.OfferService()) { - std::cerr << "Unable to offer InitialOnlySkeleton: " << offer_result.error() << ", bailing!\n"; - return -5; + FailTest("Provider: Unable to offer InitialOnlySkeleton"); } - while (!stop_token.stop_requested()) + if (!process_synchronizer_result->WaitWithAbort(stop_token)) { - std::this_thread::sleep_for(cycle_time); + FailTest("Provider: WaitWithAbort was stopped by stop_token instead of notification"); } service.StopOfferService(); - - return 0; } -int run_set_service(const std::chrono::milliseconds& cycle_time, const score::cpp::stop_token& stop_token) +void run_set_provider(const score::cpp::stop_token& stop_token) { - auto instance_specifier_result = InstanceSpecifier::Create(std::string{kInstanceSpecifierString}); - if (!instance_specifier_result.has_value()) + auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); + if (!process_synchronizer_result.has_value()) { - std::cerr << "Unable to create instance specifier, terminating\n"; - return -13; + FailTest("Provider: Could not create ProcessSynchronizer"); } - auto instance_specifier = std::move(instance_specifier_result).value(); - auto service_result = SetEnabledSkeleton::Create(std::move(instance_specifier)); - if (!service_result.has_value()) + SkeletonContainer skeleton_container{kInstanceSpecifierString}; + if (!skeleton_container.CreateSkeleton()) { - std::cerr << "Unable to construct SetEnabledSkeleton: " << service_result.error() << ", bailing!\n"; - return -14; + FailTest("Provider: Unable to construct SetEnabledSkeleton"); } - SetEnabledSkeleton& service{service_result.value()}; + auto& service = skeleton_container.GetSkeleton(); const auto register_handler_result = service.test_field.RegisterSetHandler([](std::int32_t& value) noexcept { if (value > kSetAcceptedValue) { @@ -98,52 +92,45 @@ int run_set_service(const std::chrono::milliseconds& cycle_time, const score::cp }); if (!register_handler_result.has_value()) { - std::cerr << "Unable to register set handler: " << register_handler_result.error() << ", bailing!\n"; - return -15; + FailTest("Provider: Unable to register set handler: ", register_handler_result.error()); } const auto update_result = service.test_field.Update(kInitialValue); if (!update_result.has_value()) { - std::cerr << "Unable to update initial field value: " << update_result.error() << ", bailing!\n"; - return -16; + FailTest("Provider: Unable to update initial field value: ", update_result.error()); } - const auto offer_result = service.OfferService(); - if (!offer_result.has_value()) + if (!skeleton_container.OfferService()) { - std::cerr << "Unable to offer SetEnabledSkeleton: " << offer_result.error() << ", bailing!\n"; - return -17; + FailTest("Provider: Unable to offer SetEnabledSkeleton"); } - while (!stop_token.stop_requested()) + if (!process_synchronizer_result->WaitWithAbort(stop_token)) { - std::this_thread::sleep_for(cycle_time); + FailTest("Provider: WaitWithAbort was stopped by stop_token instead of notification"); } service.StopOfferService(); - - return 0; } } // namespace -int run_service(const std::chrono::milliseconds& cycle_time, - const score::cpp::stop_token& stop_token, - const std::string& mode) +void run_provider(const score::cpp::stop_token& stop_token, const std::string& mode) { if (mode == "notifier") { - return run_notifier_service(cycle_time, stop_token); + run_notifier_provider(stop_token); + return; } if (mode == "set") { - return run_set_service(cycle_time, stop_token); + run_set_provider(stop_token); + return; } - // TODO: Add "get" mode service scenario coverage once getter-enabled field variant is introduced. - std::cerr << "Unsupported mode passed to service: " << mode << "\n"; - return -1; + // TODO: Add "get" mode provider scenario coverage once getter-enabled field variant is introduced. + FailTest("Provider: Unsupported mode: ", mode); } } // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h index 6d6d2386c..95a5dc32f 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h @@ -16,15 +16,12 @@ #include -#include #include namespace score::mw::com::test { -int run_service(const std::chrono::milliseconds& cycle_time, - const score::cpp::stop_token& stop_token, - const std::string& mode); +void run_provider(const score::cpp::stop_token& stop_token, const std::string& mode); } // namespace score::mw::com::test diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/initial_only_interface.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/initial_only_interface.h new file mode 100644 index 000000000..bca864504 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/initial_only_interface.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_INITIAL_ONLY_INTERFACE_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_INITIAL_ONLY_INTERFACE_H + +#include + +namespace score::mw::com::test +{ + +template +class InitialOnlyInterface : public T::Base +{ + public: + using T::Base::Base; + + typename T::template Field test_field{*this, "test_field"}; +}; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_INITIAL_ONLY_INTERFACE_H diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/set_enabled_interface.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/set_enabled_interface.h new file mode 100644 index 000000000..d2fb237a5 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/set_enabled_interface.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_SET_ENABLED_INTERFACE_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_SET_ENABLED_INTERFACE_H + +#include + +namespace score::mw::com::test +{ + +template +class SetEnabledInterface : public T::Base +{ + public: + using T::Base::Base; + + typename T::template Field test_field{*this, "test_field"}; +}; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_SET_ENABLED_INTERFACE_H diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h new file mode 100644 index 000000000..ec0c36aaf --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_constants.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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 + *******************************************************************************/ + +#ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_CONSTANTS_H +#define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_CONSTANTS_H + +#include + +namespace score::mw::com::test +{ + +constexpr const char* const kInstanceSpecifierString = "test/fields/set_and_notifier"; + +constexpr std::int32_t kInitialValue = 18; +constexpr std::int32_t kSetValidValue = 42; +constexpr std::int32_t kSetRequestValue = 1234; +constexpr std::int32_t kSetAcceptedValue = 100; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_CONSTANTS_H diff --git a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h index b938631e4..e26a70eb6 100644 --- a/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h +++ b/score/mw/com/test/fields/set_and_notifier/fields_test_resources/test_datatype.h @@ -14,38 +14,13 @@ #ifndef SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_DATATYPE_H #define SCORE_MW_COM_TEST_FIELDS_SET_AND_NOTIFIER_FIELDS_TEST_RESOURCES_TEST_DATATYPE_H +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/initial_only_interface.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/set_enabled_interface.h" #include "score/mw/com/types.h" -#include - namespace score::mw::com::test { -constexpr const char* const kInstanceSpecifierString = "test/fields/set_and_notifier"; - -const std::int32_t kInitialValue = 18; -const std::int32_t kSetValidValue = 42; -const std::int32_t kSetRequestValue = 1234; -const std::int32_t kSetAcceptedValue = 100; - -template -class InitialOnlyInterface : public T::Base -{ - public: - using T::Base::Base; - - typename T::template Field test_field{*this, "test_field"}; -}; - -template -class SetEnabledInterface : public T::Base -{ - public: - using T::Base::Base; - - typename T::template Field test_field{*this, "test_field"}; -}; - using InitialOnlyProxy = score::mw::com::AsProxy; using InitialOnlySkeleton = score::mw::com::AsSkeleton; diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD b/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD index 14c2344a3..77cc6f923 100644 --- a/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/BUILD @@ -17,16 +17,32 @@ load("//quality/integration_testing:integration_testing.bzl", "integration_test" pkg_filegroup( name = "filesystem", srcs = [ - "//score/mw/com/test/fields/set_and_notifier:main_client-pkg", - "//score/mw/com/test/fields/set_and_notifier:main_service-pkg", + "//score/mw/com/test/fields/set_and_notifier:consumer-pkg", + "//score/mw/com/test/fields/set_and_notifier:provider-pkg", ], ) +py_library( + name = "test_fixture", + srcs = ["test_fixture.py"], +) + +integration_test( + name = "test_notifier", + timeout = "moderate", + srcs = [ + "test_notifier.py", + ":test_fixture", + ], + filesystem = ":filesystem", +) + integration_test( - name = "test_field_set_and_notifier", + name = "test_set_and_notifier", timeout = "moderate", srcs = [ - "test_field_set_and_notifier.py", + "test_set_and_notifier.py", + ":test_fixture", ], filesystem = ":filesystem", ) diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_fixture.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_fixture.py new file mode 100644 index 000000000..414fc716b --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_fixture.py @@ -0,0 +1,23 @@ +# ******************************************************************************* +# 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 +# ******************************************************************************* + + +def consumer(target, mode, **kwargs): + args = ["--num-retries", "20", "--backoff-time", "50", "--mode", mode, + "--service-instance-manifest", "./etc/mw_com_config.json"] + return target.wrap_exec("bin/consumer", args, cwd="/opt/MainConsumerApp", wait_on_exit=True, **kwargs) + + +def provider(target, mode, **kwargs): + args = ["--mode", mode, "--service-instance-manifest", "./etc/mw_com_config.json"] + return target.wrap_exec("bin/provider", args, cwd="/opt/MainProviderApp", **kwargs) diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_get.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_get.py new file mode 100644 index 000000000..af068eba8 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_get.py @@ -0,0 +1,18 @@ +# ******************************************************************************* +# 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 test_fixture import consumer, provider + +# TODO: Implement once get mode is supported by the provider and consumer binaries. +# Scenarios to cover: +# 1. calling Update / send -> calling get returns value set with send diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_get_and_notifier.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_get_and_notifier.py new file mode 100644 index 000000000..21648aabc --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_get_and_notifier.py @@ -0,0 +1,19 @@ +# ******************************************************************************* +# 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 test_fixture import consumer, provider + +# TODO: Implement once get_and_notifier mode is supported by the provider and consumer binaries. +# Scenarios to cover (same as notifier and get, verifying result of both GetNewSamples and getter): +# 1. calling Update / send -> calling get returns value set with send +# 2. calling Update / send -> calling GetNewSamples returns value set with send diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_notifier.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_notifier.py new file mode 100644 index 000000000..13d2b3800 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_notifier.py @@ -0,0 +1,21 @@ +# ******************************************************************************* +# 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 test_fixture import consumer, provider + + +def test_field_notifier_initial_value(target): + """Test field initial value exchange between provider and consumer.""" + with provider(target, "notifier"): + with consumer(target, "notifier"): + pass diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_get.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_get.py new file mode 100644 index 000000000..ce184446b --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_get.py @@ -0,0 +1,20 @@ +# ******************************************************************************* +# 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 test_fixture import consumer, provider + +# TODO: Implement once set_and_get mode is supported by the provider and consumer binaries. +# Scenarios to cover: +# 1. calling set with valid value -> calling get returns value set with setter +# 2. calling set with invalid value (set handler clamps the value) -> calling get returns clamped value +# 3. calling Update / send -> calling get returns value set with send diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_notifier.py similarity index 51% rename from score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py rename to score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_notifier.py index aeb530512..65574c804 100644 --- a/score/mw/com/test/fields/set_and_notifier/integration_test/test_field_set_and_notifier.py +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_and_notifier.py @@ -11,28 +11,13 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* - -def client(target, mode, **kwargs): - args = ["--num-retries", "20", "--backoff-time", "50", "--mode", mode] - return target.wrap_exec("bin/main_client", args, cwd="/opt/MainClientApp", wait_on_exit=True, **kwargs) - - -def service(target, mode, **kwargs): - args = ["--cycle-time", "250", "--mode", mode] - return target.wrap_exec("bin/main_service", args, cwd="/opt/MainServiceApp", **kwargs) - - -def test_field_notifier_initial_value(target): - """Test field initial value exchange between service and client.""" - with service(target, "notifier"): - with client(target, "notifier"): - pass +from test_fixture import consumer, provider def test_field_set_value(target): - """Test field set exchange and accepted value propagation between service and client.""" - with service(target, "set"): - with client(target, "set"): + """Test field set exchange and accepted value propagation between provider and consumer.""" + with provider(target, "set"): + with consumer(target, "set"): pass diff --git a/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_get_and_notifier.py b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_get_and_notifier.py new file mode 100644 index 000000000..c7e39ac8a --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/integration_test/test_set_get_and_notifier.py @@ -0,0 +1,20 @@ +# ******************************************************************************* +# 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 test_fixture import consumer, provider + +# TODO: Implement once set_get_and_notifier mode is supported by the provider and consumer binaries. +# Scenarios to cover (same as set_and_notifier, but also verify result of getter): +# 1. calling set with valid value -> calling get and GetNewSamples both return value set with setter +# 2. calling set with invalid value (set handler clamps the value) -> calling get and GetNewSamples both return clamped value +# 3. calling Update / send -> calling get and GetNewSamples both return value set with send diff --git a/score/mw/com/test/fields/set_and_notifier/main_client.cpp b/score/mw/com/test/fields/set_and_notifier/main_client.cpp deleted file mode 100644 index 0adb5a6d9..000000000 --- a/score/mw/com/test/fields/set_and_notifier/main_client.cpp +++ /dev/null @@ -1,30 +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 "score/mw/com/test/common_test_resources/sctf_test_runner.h" -#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_consumer.h" - -#include - -int main(int argc, const char** argv) -{ - using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; - - const std::vector allowed_parameters{ - Parameters::NUM_RETRIES, Parameters::RETRY_BACKOFF_TIME, Parameters::MODE}; - score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); - const auto& run_parameters = test_runner.GetRunParameters(); - - return score::mw::com::test::run_client( - run_parameters.GetNumRetries(), run_parameters.GetRetryBackoffTime(), run_parameters.GetMode()); -} diff --git a/score/mw/com/test/fields/set_and_notifier/main_service.cpp b/score/mw/com/test/fields/set_and_notifier/main_service.cpp deleted file mode 100644 index c912b689d..000000000 --- a/score/mw/com/test/fields/set_and_notifier/main_service.cpp +++ /dev/null @@ -1,29 +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 "score/mw/com/test/common_test_resources/sctf_test_runner.h" -#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h" - -#include - -int main(int argc, const char** argv) -{ - using Parameters = score::mw::com::test::SctfTestRunner::RunParameters::Parameters; - - const std::vector allowed_parameters{Parameters::CYCLE_TIME, Parameters::MODE}; - score::mw::com::test::SctfTestRunner test_runner(argc, argv, allowed_parameters); - const auto& run_parameters = test_runner.GetRunParameters(); - - return score::mw::com::test::run_service( - run_parameters.GetCycleTime(), test_runner.GetStopToken(), run_parameters.GetMode()); -} diff --git a/score/mw/com/test/fields/set_and_notifier/provider.cpp b/score/mw/com/test/fields/set_and_notifier/provider.cpp new file mode 100644 index 000000000..456108489 --- /dev/null +++ b/score/mw/com/test/fields/set_and_notifier/provider.cpp @@ -0,0 +1,64 @@ +/******************************************************************************* + * 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/runtime.h" +#include "score/mw/com/test/common_test_resources/command_line_parser.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/mw/com/test/common_test_resources/stop_token_sig_term_handler.h" +#include "score/mw/com/test/fields/set_and_notifier/fields_test_resources/field_provider.h" + +#include +#include +#include +#include +#include + +int main(int argc, const char** argv) +{ + constexpr auto kModeArg = "mode"; + constexpr auto kServiceInstanceManifestArg = "service-instance-manifest"; + + const std::vector> parameter_description_pairs{ + {kModeArg, "Provider mode: notifier or set"}, + {kServiceInstanceManifestArg, "Path to the service instance manifest"}, + }; + + const auto args = score::mw::com::test::ParseCommandLineArguments(argc, argv, parameter_description_pairs); + + const auto mode_result = score::mw::com::test::GetValueIfProvided(args, kModeArg); + if (!mode_result.has_value()) + { + score::mw::com::test::FailTest("Provider: missing or invalid --", kModeArg, " argument"); + } + + const auto manifest_result = + score::mw::com::test::GetValueIfProvided(args, kServiceInstanceManifestArg); + if (!manifest_result.has_value()) + { + score::mw::com::test::FailTest("Provider: missing or invalid --", kServiceInstanceManifestArg, " argument"); + } + + score::mw::com::runtime::InitializeRuntime(score::mw::com::runtime::RuntimeConfiguration{manifest_result.value()}); + + score::cpp::stop_source stop_source{}; + const bool sig_term_handler_setup_success = score::mw::com::SetupStopTokenSigTermHandler(stop_source); + if (!sig_term_handler_setup_success) + { + std::cerr << "Unable to set signal handler for SIGINT and/or SIGTERM, cautiously continuing\n"; + } + + const auto& mode = mode_result.value(); + + score::mw::com::test::run_provider(stop_source.get_token(), mode); + return EXIT_SUCCESS; +} diff --git a/score/mw/com/test/methods/methods_test_resources/BUILD b/score/mw/com/test/methods/methods_test_resources/BUILD index 64912499d..4627c3fb8 100644 --- a/score/mw/com/test/methods/methods_test_resources/BUILD +++ b/score/mw/com/test/methods/methods_test_resources/BUILD @@ -55,6 +55,7 @@ cc_library( hdrs = ["process_synchronizer.h"], features = COMPILER_WARNING_FEATURES, visibility = [ + "//score/mw/com/test/fields:__subpackages__", "//score/mw/com/test/methods:__subpackages__", ], deps = [