diff --git a/score/mw/com/test/common_test_resources/BUILD b/score/mw/com/test/common_test_resources/BUILD index a63635201..458aaf8ac 100644 --- a/score/mw/com/test/common_test_resources/BUILD +++ b/score/mw/com/test/common_test_resources/BUILD @@ -61,9 +61,15 @@ cc_library( "fail_test.h", ], features = COMPILER_WARNING_FEATURES, + implementation_deps = [ + "@score_baselibs//score/language/futurecpp", + ], visibility = [ "//score/mw/com/test:__subpackages__", ], + deps = [ + "@score_baselibs//score/result", + ], ) cc_library( @@ -154,6 +160,7 @@ cc_library( "//score/mw/com/test:__subpackages__", ], deps = [ + ":fail_test", "//score/mw/com", "//score/mw/com/test/common_test_resources:test_error_domain", "@boost.program_options", diff --git a/score/mw/com/test/common_test_resources/command_line_parser.h b/score/mw/com/test/common_test_resources/command_line_parser.h index 263d14e46..0f91659b0 100644 --- a/score/mw/com/test/common_test_resources/command_line_parser.h +++ b/score/mw/com/test/common_test_resources/command_line_parser.h @@ -14,13 +14,14 @@ #ifndef SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_COMMAND_LINE_PARSER_H #define 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/test_error_domain.h" -#include - -#include -#include #include "score/result/result.h" + +#include +#include +#include #include #include #include @@ -30,7 +31,8 @@ namespace score::mw::com::test using CommandLineArgsMapType = std::unordered_map; -/// \brief Get a value represented as a string, from an arguments map and parse it into the appropriate type +/// \brief Get a value represented as a string (if it exists), from an arguments map and parse it into the appropriate +/// type /// /// \tparam ReturnType Target type of the parsed argument. Must be std::string, integral or floating point type. /// \param args Map of provided command line arguments, where the key is the argument name and the value is the argument @@ -41,11 +43,11 @@ using CommandLineArgsMapType = std::unordered_map; template auto GetValueIfProvided(const CommandLineArgsMapType& args, const std::string& arg_string) -> Result { + std::cout << "Trying to get value for argument: " << arg_string << std::endl; if (args.count(arg_string) == 0U) { - std::string error_msg = "could not find the requested parameter: " + arg_string; return score::MakeUnexpected( - MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, error_msg)); + MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, "Could not find the requested parameter.")); } std::string value_str = args.at(arg_string); @@ -66,9 +68,8 @@ auto GetValueIfProvided(const CommandLineArgsMapType& args, const std::string& a } return score::MakeUnexpected( MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, - "Failed during parsing of: " + arg_string + " . Provided value " + value_str + - "could not be parsed into bool! Boolean fields can only have one of the following values: " - "true, 1, false, 0 \n")); + "Failed during parsing. Provided value could not be parsed into bool! Boolean fields can only " + "have one of the following values: true, 1, false, 0.")); } else if constexpr (std::is_integral_v) { @@ -81,26 +82,23 @@ auto GetValueIfProvided(const CommandLineArgsMapType& args, const std::string& a if (conversion_result.ec == std::errc::invalid_argument) { - return score::MakeUnexpected(MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, - "Failed during parsing of: " + arg_string + - " . Provided value " + value_str + - "could not be parsed into the required type!\n")); + return score::MakeUnexpected( + MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, + "Failed during parsing. Provided value could not be parsed into the required type!")); } if (conversion_result.ec == std::errc::result_out_of_range) { - return score::MakeUnexpected(MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, - "Failed during parsing of: " + arg_string + - " . Provided value " + value_str + - "Is Larger than requested type!\n")); + return score::MakeUnexpected( + MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, + "Failed during parsing. Provided value is Larger than requested type!")); } if (conversion_result.ec != std::errc{}) { - return score::MakeUnexpected( - MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, - "Failed during parsing of: " + arg_string + " . Provided value " + value_str + - "could not be parsed into the required type for an unknown reason!\n")); + return score::MakeUnexpected(MakeError(TestErrorCode::kParsingCommandLineArgumentFailed, + "Failed during parsing. Provided value could not be " + "parsed into the required type for an unknown reason!")); } return parsed_value; @@ -112,6 +110,20 @@ auto GetValueIfProvided(const CommandLineArgsMapType& args, const std::string& a } } +/// \brief Get a value represented as a string, from an arguments map and parse it into the appropriate type. +/// +/// Same as `GetValueIfProvided`, but terminates the program if the argument is not provided or could not be parsed. +template +auto GetValue(const CommandLineArgsMapType& args, const std::string& arg_string) -> ReturnType +{ + auto value_opt = GetValueIfProvided(args, arg_string); + if (!value_opt.has_value()) + { + FailTest("Failed to get value for argument. Error: ", value_opt.error()); + } + return value_opt.value(); +} + /// \brief A generic command line parser which can parse any kind of arguments and return an argument value map. /// /// Every argument is parsed as a string and stored in the map with the argument name as key. diff --git a/score/mw/com/test/common_test_resources/fail_test.cpp b/score/mw/com/test/common_test_resources/fail_test.cpp index cde12b4ac..fe3902ef7 100644 --- a/score/mw/com/test/common_test_resources/fail_test.cpp +++ b/score/mw/com/test/common_test_resources/fail_test.cpp @@ -13,17 +13,50 @@ #include "score/mw/com/test/common_test_resources/fail_test.h" +#include "score/assert.hpp" + #include +#include #include +#include + +namespace score::mw::com::test +{ +namespace +{ + +thread_local std::optional> g_fail_test_exit_function{}; + +} -namespace score::mw::com::test::detail +namespace detail { void FailTest(std::stringstream&& strstr) { + if (g_fail_test_exit_function.has_value()) + { + std::invoke(g_fail_test_exit_function.value()); + g_fail_test_exit_function.reset(); + } strstr << "\033[0m \033[1m\033[41mTEST FAILED\033[0m\n"; - std::cerr << strstr.str() << std::flush; + std::cout << strstr.str() << std::flush; std::_Exit(EXIT_FAILURE); } -} // namespace score::mw::com::test::detail +} // namespace detail + +ExitFunctionGuard::ExitFunctionGuard(ExitFunction exit_function) +{ + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(!g_fail_test_exit_function.has_value(), + "A test exit function is already set for this thread! Only one " + "ExitFunctionGuard can be created per thread."); + g_fail_test_exit_function.emplace(std::move(exit_function)); +} + +ExitFunctionGuard::~ExitFunctionGuard() +{ + std::invoke(g_fail_test_exit_function.value()); + g_fail_test_exit_function.reset(); +} +} // namespace score::mw::com::test diff --git a/score/mw/com/test/common_test_resources/fail_test.h b/score/mw/com/test/common_test_resources/fail_test.h index 45e6f4c52..5ea1efcc2 100644 --- a/score/mw/com/test/common_test_resources/fail_test.h +++ b/score/mw/com/test/common_test_resources/fail_test.h @@ -13,6 +13,9 @@ #ifndef SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_FAIL_TEST_H #define SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_FAIL_TEST_H +#include "score/result/error.h" + +#include #include #include @@ -21,12 +24,23 @@ namespace score::mw::com::test namespace detail { + void FailTest(std::stringstream&& strstr); template void FailTest(std::stringstream&& strstr, Start&& start, Tail&&... tail) { - strstr << std::forward(start); + // Since score::result::Error does not have an operator<< overload for a stringstream and no method to convert it to + // a string, we manually stringify it here. + if constexpr (std::is_same_v, score::result::Error>) + { + strstr << start.Message() << " / " << start.UserMessage(); + } + else + { + strstr << std::forward(start); + } + if constexpr (sizeof...(Tail) > 0U) { FailTest(std::move(strstr), std::forward(tail)...); @@ -36,8 +50,25 @@ void FailTest(std::stringstream&& strstr, Start&& start, Tail&&... tail) FailTest(std::move(strstr)); } } + } // namespace detail +/// \brief RAII guard to set a test exit function that will be called when FailTest is invoked or when the guard is +/// destroyed. +class ExitFunctionGuard +{ + public: + using ExitFunction = std::function; + + explicit ExitFunctionGuard(ExitFunction exit_function); + ~ExitFunctionGuard(); + + ExitFunctionGuard(const ExitFunctionGuard&) = delete; + ExitFunctionGuard& operator=(const ExitFunctionGuard&) = delete; + ExitFunctionGuard(ExitFunctionGuard&&) = delete; + ExitFunctionGuard& operator=(ExitFunctionGuard&&) = delete; +}; + /// \brief Fail a test by exiting the program with EXIT_FAILURE and printing a message to stderr. /// \param args variadic number of arguments, each one must be streamable to a standard stringstream. template diff --git a/score/mw/com/test/methods/BUILD b/score/mw/com/test/methods/BUILD deleted file mode 100644 index 14a042885..000000000 --- a/score/mw/com/test/methods/BUILD +++ /dev/null @@ -1,21 +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 -# ******************************************************************************* - -test_suite( - name = "component_tests", - tests = [ - "//score/mw/com/test/methods/basic_acceptance_test:component_tests", - "//score/mw/com/test/methods/signature_variations:component_tests", - ], - visibility = ["//score/mw/com/test:__pkg__"], -) diff --git a/score/mw/com/test/methods/basic_acceptance_test/BUILD b/score/mw/com/test/methods/basic_acceptance_test/BUILD index 6ad36400f..0b5290280 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/BUILD +++ b/score/mw/com/test/methods/basic_acceptance_test/BUILD @@ -41,8 +41,8 @@ cc_library( implementation_deps = [ ":test_method_datatype", "//score/mw/com", - "//score/mw/com/test/methods/methods_test_resources:method_consumer", "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", + "//score/mw/com/test/methods/methods_test_resources:proxy_container", ], ) @@ -54,8 +54,8 @@ cc_library( implementation_deps = [ ":test_method_datatype", "//score/mw/com", - "//score/mw/com/test/methods/methods_test_resources:method_provider", "//score/mw/com/test/methods/methods_test_resources:process_synchronizer", + "//score/mw/com/test/methods/methods_test_resources:skeleton_container", ], deps = [ "@score_baselibs//score/language/futurecpp", @@ -145,9 +145,3 @@ pkg_application( "//score/mw/com/test/methods/basic_acceptance_test:__subpackages__", ], ) - -test_suite( - name = "component_tests", - tests = [], - visibility = ["//score/mw/com/test/methods:__pkg__"], -) diff --git a/score/mw/com/test/methods/basic_acceptance_test/consumer.cpp b/score/mw/com/test/methods/basic_acceptance_test/consumer.cpp index 2550f3b9e..31389579e 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/consumer.cpp +++ b/score/mw/com/test/methods/basic_acceptance_test/consumer.cpp @@ -12,9 +12,10 @@ ********************************************************************************/ #include "score/mw/com/test/methods/basic_acceptance_test/consumer.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" #include "score/mw/com/test/methods/basic_acceptance_test/test_method_datatype.h" -#include "score/mw/com/test/methods/methods_test_resources/method_consumer.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/types.h" #include @@ -35,50 +36,90 @@ constexpr std::int32_t kTestValueB = 17; const InstanceSpecifier kInstanceSpecifier = InstanceSpecifier::Create(std::string{"test/methods/basic_acceptance_test/TestMethods"}).value(); +void CallMethodWithCopy(TestMethodProxy& proxy) +{ + std::cout << "\n=== Test: with_in_args_and_return (copy call) ===" << std::endl; + auto method_return_result = proxy.with_in_args_and_return(kTestValueA, kTestValueB); + if (!(method_return_result.has_value())) + { + FailTest("Consumer: with_in_args_and_return call failed: ", method_return_result.error()); + } + const auto actual_return_value = *(method_return_result.value()); + + const auto expected_result_value = kTestValueA + kTestValueB; + if (actual_return_value != expected_result_value) + { + FailTest( + "Consumer: with_in_args_and_return expected ", expected_result_value, " but got ", actual_return_value); + } + + std::cout << "Consumer: with_in_args_and_return returned correct result: " << actual_return_value << std::endl; +} + +void CallMethodZeroCopy(TestMethodProxy& proxy) +{ + std::cout << "\n=== Test: with_in_args_and_return (zero-copy) ===" << std::endl; + auto allocated_args_result = proxy.with_in_args_and_return.Allocate(); + if (!allocated_args_result.has_value()) + { + FailTest("Consumer: Could not allocate method args: ", allocated_args_result.error()); + } + + auto& [arg1_ptr, arg2_ptr] = allocated_args_result.value(); + *arg1_ptr = kTestValueA; + *arg2_ptr = kTestValueB; + + auto method_return_result = proxy.with_in_args_and_return(std::move(arg1_ptr), std::move(arg2_ptr)); + if (!(method_return_result.has_value())) + { + FailTest("Consumer: with_in_args_and_return zero-copy call failed: ", method_return_result.error()); + } + const auto actual_return_value = *(method_return_result.value()); + + const auto expected_result_value = kTestValueA + kTestValueB; + if (actual_return_value != expected_result_value) + { + FailTest("Consumer: with_in_args_and_return zero-copy expected ", + expected_result_value, + " but got ", + actual_return_value); + } + + std::cout << "Consumer: with_in_args_and_return zero-copy returned correct result: " << actual_return_value + << std::endl; +} + } // namespace -int run_consumer() +void run_consumer() { - MethodConsumer consumer{}; auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); if (!(process_synchronizer_result.has_value())) { - std::cerr << "Methods basic_acceptance_test consumer failed: Could not create ProcessSynchronizer" << std::endl; - return EXIT_FAILURE; + FailTest("Methods basic_acceptance_test consumer failed: Could not create ProcessSynchronizer"); } + // Set an exit function to notify the provider in case of failure in calls to FailTest, so that it does not wait + // indefinitely for the consumer to finish. Will also be called when the guard goes out of scope at the end of this + // function. + ExitFunctionGuard process_synchronizer_guard{[&process_synchronizer_result]() { + process_synchronizer_result->Notify(); + }}; + + ProxyContainer proxy_container{}; + // Step 1. Find service and create proxy std::cout << "\nConsumer: Step 1" << std::endl; - if (!consumer.CreateProxy(kInstanceSpecifier)) - { - std::cerr << "Methods basic_acceptance_test consumer failed: CreateProxy" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + proxy_container.CreateProxy(kInstanceSpecifier, "basic_acceptance_test"); + auto& proxy = proxy_container.GetProxy(); // Step 2. Call method with copy std::cout << "\nConsumer: Step 2" << std::endl; - if (!consumer.CallMethodWithInArgsAndReturn( - kTestValueA, kTestValueB, MethodConsumer::CopyMode::WITH_COPY)) - { - std::cerr << "Methods basic_acceptance_test consumer failed: CallMethodWithCopy" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + CallMethodWithCopy(proxy); // Step 3. Call zero-copy method std::cout << "\nConsumer: Step 3" << std::endl; - if (!consumer.CallMethodWithInArgsAndReturn( - kTestValueA, kTestValueB, MethodConsumer::CopyMode::ZERO_COPY)) - { - std::cerr << "Methods basic_acceptance_test consumer failed: CallZeroCopyMethod" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } - - process_synchronizer_result->Notify(); - - return EXIT_SUCCESS; + CallMethodZeroCopy(proxy); } } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/basic_acceptance_test/consumer.h b/score/mw/com/test/methods/basic_acceptance_test/consumer.h index 1e7467b08..04f353a45 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/consumer.h +++ b/score/mw/com/test/methods/basic_acceptance_test/consumer.h @@ -16,7 +16,7 @@ namespace score::mw::com::test { -int run_consumer(); +void run_consumer(); } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/basic_acceptance_test/integration_test/BUILD b/score/mw/com/test/methods/basic_acceptance_test/integration_test/BUILD index bfbc211fa..6d0fe1384 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/integration_test/BUILD +++ b/score/mw/com/test/methods/basic_acceptance_test/integration_test/BUILD @@ -37,11 +37,3 @@ integration_test( ], filesystem = ":different_processes_filesystem", ) - -test_suite( - name = "component_tests", - tests = [ - ":basic_acceptance_different_processes_test", - ":basic_acceptance_same_process_test", - ], -) diff --git a/score/mw/com/test/methods/basic_acceptance_test/main_consumer.cpp b/score/mw/com/test/methods/basic_acceptance_test/main_consumer.cpp index 73230fb43..fc11704b7 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/main_consumer.cpp +++ b/score/mw/com/test/methods/basic_acceptance_test/main_consumer.cpp @@ -19,5 +19,6 @@ int main(int argc, const char** argv) { score::mw::com::test::SetupAssertHandler(); score::mw::com::runtime::InitializeRuntime(argc, argv); - return score::mw::com::test::run_consumer(); + score::mw::com::test::run_consumer(); + return EXIT_SUCCESS; } diff --git a/score/mw/com/test/methods/basic_acceptance_test/main_consumer_and_provider.cpp b/score/mw/com/test/methods/basic_acceptance_test/main_consumer_and_provider.cpp index 1a2c0d0ad..17d88ece2 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/main_consumer_and_provider.cpp +++ b/score/mw/com/test/methods/basic_acceptance_test/main_consumer_and_provider.cpp @@ -33,14 +33,13 @@ int main(int argc, const char** argv) std::cerr << "Unable to set signal handler for SIGINT and/or SIGTERM, cautiously continuing\n"; } - auto provider_return_value_future = std::async(score::mw::com::test::run_provider, stop_source.get_token()); - auto consumer_return_value_future = std::async(score::mw::com::test::run_consumer); + auto provider_future = std::async(score::mw::com::test::run_provider, stop_source.get_token()); + auto consumer_future = std::async(score::mw::com::test::run_consumer); - const auto provider_return_value = provider_return_value_future.get(); - const auto consumer_return_value = consumer_return_value_future.get(); + provider_future.get(); + consumer_future.get(); - std::cout << "BasicAcceptanceSameProcessTest: Provider result: " << provider_return_value - << " / Consumer result: " << consumer_return_value << std::endl; + std::cout << "BasicAcceptanceSameProcessTest: Provider and Consumer completed successfully" << std::endl; - return (provider_return_value && consumer_return_value); + return EXIT_SUCCESS; } diff --git a/score/mw/com/test/methods/basic_acceptance_test/main_provider.cpp b/score/mw/com/test/methods/basic_acceptance_test/main_provider.cpp index 111640723..faaa24d1c 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/main_provider.cpp +++ b/score/mw/com/test/methods/basic_acceptance_test/main_provider.cpp @@ -30,5 +30,6 @@ int main(int argc, const char** argv) std::cerr << "Unable to set signal handler for SIGINT and/or SIGTERM, cautiously continuing\n"; } - return score::mw::com::test::run_provider(stop_source.get_token()); + score::mw::com::test::run_provider(stop_source.get_token()); + return EXIT_SUCCESS; } diff --git a/score/mw/com/test/methods/basic_acceptance_test/provider.cpp b/score/mw/com/test/methods/basic_acceptance_test/provider.cpp index 0b5ee6546..6f0bcc18d 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/provider.cpp +++ b/score/mw/com/test/methods/basic_acceptance_test/provider.cpp @@ -12,9 +12,10 @@ ********************************************************************************/ #include "score/mw/com/test/methods/basic_acceptance_test/provider.h" +#include "score/mw/com/test/common_test_resources/fail_test.h" #include "score/mw/com/test/methods/basic_acceptance_test/test_method_datatype.h" -#include "score/mw/com/test/methods/methods_test_resources/method_provider.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/types.h" #include "score/result/result.h" @@ -36,49 +37,48 @@ const InstanceSpecifier kInstanceSpecifier = } // namespace -bool run_provider(const score::cpp::stop_token& stop_token) +void run_provider(const score::cpp::stop_token& stop_token) { - MethodProvider provider{}; + SkeletonContainer skeleton_container{}; auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); if (!(process_synchronizer_result.has_value())) { - std::cerr << "Methods basic_acceptance_test provider failed: Could not create ProcessSynchronizer" << std::endl; - return EXIT_FAILURE; + FailTest("Methods basic_acceptance_test provider failed: Could not create ProcessSynchronizer"); } // Step 1. Create skeleton - if (!provider.CreateSkeleton(kInstanceSpecifier)) - { - std::cerr << "Methods basic_acceptance_test provider failed: CreateSkeleton" << std::endl; - return EXIT_FAILURE; - } + std::cout << "\nProvider: Step 1" << std::endl; + skeleton_container.CreateSkeleton(kInstanceSpecifier, "basic_acceptance_test"); + auto& skeleton = skeleton_container.GetSkeleton(); - // Step 2. Register method handlers - if (!provider.RegisterMethodHandlerWithInArgsAndReturn()) + // Step 2. Register method handler + std::cout << "\nProvider: Step 2" << std::endl; + auto handler_with_in_args_and_return = [](std::int32_t a, std::int32_t b) -> std::int32_t { + std::cout << "Provider: with_in_args_and_return called with " << a << " + " << b << std::endl; + return a + b; + }; + const auto register_result = + skeleton.with_in_args_and_return.RegisterHandler(std::move(handler_with_in_args_and_return)); + if (!register_result) { - std::cerr << "Methods basic_acceptance_test provider failed: RegisterMethodHandlers" << std::endl; - return EXIT_FAILURE; + FailTest("Provider: Failed to register with_in_args_and_return handler"); } // Step 3. Offer service - if (!provider.OfferService()) - { - std::cerr << "Methods basic_acceptance_test provider failed: OfferService" << std::endl; - return EXIT_FAILURE; - } + std::cout << "\nProvider: Step 3" << std::endl; + skeleton_container.OfferService("basic_acceptance_test"); // Step 4. Wait for proxy test to finish + std::cout << "\nProvider: Step 4" << std::endl; std::cout << "Provider: Ready for method calls" << std::endl; if (!process_synchronizer_result->WaitWithAbort(stop_token)) { - std::cerr << "Methods basic_acceptance_test provider failed: WaitForProxyTestToFinish was stopped by " - "stop_token instead of notification" - << std::endl; - return EXIT_FAILURE; + FailTest( + "Methods basic_acceptance_test provider failed: WaitForProxyTestToFinish was stopped by " + "stop_token instead of notification"); } std::cout << "Provider: Shutting down" << std::endl; - return EXIT_SUCCESS; } } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/basic_acceptance_test/provider.h b/score/mw/com/test/methods/basic_acceptance_test/provider.h index 6e906c5a3..49aad54dc 100644 --- a/score/mw/com/test/methods/basic_acceptance_test/provider.h +++ b/score/mw/com/test/methods/basic_acceptance_test/provider.h @@ -18,7 +18,7 @@ namespace score::mw::com::test { -bool run_provider(const score::cpp::stop_token& stop_token); +void run_provider(const score::cpp::stop_token& stop_token); } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/methods_test_resources/BUILD b/score/mw/com/test/methods/methods_test_resources/BUILD index 6801003e3..e74a95f50 100644 --- a/score/mw/com/test/methods/methods_test_resources/BUILD +++ b/score/mw/com/test/methods/methods_test_resources/BUILD @@ -13,6 +13,7 @@ load("@rules_cc//cc:defs.bzl", "cc_library") load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") +load("//bazel/tools:json_schema_validator.bzl", "validate_json_schema_test") cc_library( name = "proxy_container", @@ -24,6 +25,7 @@ cc_library( ], deps = [ "//score/mw/com", + "//score/mw/com/test/common_test_resources:fail_test", ], ) @@ -37,6 +39,7 @@ cc_library( ], deps = [ "//score/mw/com", + "//score/mw/com/test/common_test_resources:fail_test", ], ) diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/BUILD b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/BUILD new file mode 100644 index 000000000..d6bd49bd1 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/BUILD @@ -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 +# ******************************************************************************* +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@score_baselibs//score/language/safecpp:toolchain_features.bzl", "COMPILER_WARNING_FEATURES") + +cc_library( + name = "all_signatures_datatype", + srcs = ["all_signatures_datatype.cpp"], + hdrs = ["all_signatures_datatype.h"], + features = COMPILER_WARNING_FEATURES, + visibility = ["//score/mw/com/test/methods:__subpackages__"], + deps = [ + "//score/mw/com", + ], +) + +cc_library( + name = "all_signatures_method_provider", + srcs = ["all_signatures_method_provider.cpp"], + hdrs = ["all_signatures_method_provider.h"], + features = COMPILER_WARNING_FEATURES, + visibility = ["//score/mw/com/test/methods:__subpackages__"], + deps = [ + ":all_signatures_datatype", + "//score/mw/com", + "//score/mw/com/test/common_test_resources:assert_handler", + "//score/mw/com/test/common_test_resources:sctf_test_runner", + "//score/mw/com/test/methods/methods_test_resources:skeleton_container", + "@score_baselibs//score/mw/log", + "@score_baselibs//score/result", + ], +) + +cc_library( + name = "all_signatures_method_consumer", + srcs = ["all_signatures_method_consumer.cpp"], + hdrs = ["all_signatures_method_consumer.h"], + features = COMPILER_WARNING_FEATURES, + visibility = ["//score/mw/com/test/methods:__subpackages__"], + deps = [ + ":all_signatures_datatype", + "//score/mw/com", + "//score/mw/com:runtime", + "//score/mw/com/test/common_test_resources:assert_handler", + "//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/all_signatures_datatype/all_signatures_datatype.cpp b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.cpp new file mode 100644 index 000000000..afd1f6a97 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.cpp @@ -0,0 +1,13 @@ +/******************************************************************************** + * 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/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h" diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h new file mode 100644 index 000000000..6676832f4 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#ifndef SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATATYPE_ALL_SIGNATURES_DATATYPE_H +#define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATATYPE_ALL_SIGNATURES_DATATYPE_H + +#include "score/mw/com/types.h" + +#include + +namespace score::mw::com::test +{ + +/// \brief Test interface with methods covering all signature variations +/// \tparam T Either ProxyTrait or SkeletonTrait +template +class AllSignaturesInterface : public T::Base +{ + public: + using T::Base::Base; + + /// \brief Method with both InArgs and Result + typename T::template Method with_in_args_and_return{ + *this, + "with_in_args_and_return"}; + + /// \brief Method with only InArgs, no Result (void return) + typename T::template Method with_in_args_only{*this, "with_in_args_only"}; + + /// \brief Method with only Result, no InArgs + typename T::template Method with_return_only{*this, "with_return_only"}; + + /// \brief Method without InArgs or Result + typename T::template Method without_args_or_return{*this, "without_args_or_return"}; +}; + +/// \brief Proxy side of the test service +using AllSignaturesProxy = score::mw::com::AsProxy; + +/// \brief Skeleton side of the test service +using AllSignaturesSkeleton = score::mw::com::AsSkeleton; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATATYPE_ALL_SIGNATURES_DATATYPE_H diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.cpp b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.cpp new file mode 100644 index 000000000..f1fc7f491 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.cpp @@ -0,0 +1,161 @@ +/******************************************************************************** + * 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/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.h" + +#include "score/mw/com/test/common_test_resources/fail_test.h" + +namespace score::mw::com::test +{ + +void AllSignaturesMethodConsumer::CreateProxy(InstanceSpecifier instance_specifier, + const std::string& failure_message_prefix) +{ + proxy_container_.CreateProxy(std::move(instance_specifier), failure_message_prefix); +} + +AllSignaturesProxy& AllSignaturesMethodConsumer::GetProxy() +{ + return proxy_container_.GetProxy(); +} + +void AllSignaturesMethodConsumer::CallMethodWithInArgsAndReturn(const std::int32_t input_argument_a, + const std::int32_t input_argument_b, + const CopyMode copy_mode, + const std::string& failure_message_prefix) +{ + auto& proxy = GetProxy(); + + auto call_result = [&proxy, + copy_mode, + input_argument_a, + input_argument_b]() -> score::Result> { + SCORE_LANGUAGE_FUTURECPP_ASSERT(copy_mode == CopyMode::WITH_COPY || copy_mode == CopyMode::ZERO_COPY); + if (copy_mode == CopyMode::ZERO_COPY) + { + std::cout << "\n=== Test: with_in_args_and_return (zero-copy) ===" << std::endl; + auto allocated_args_result = proxy.with_in_args_and_return.Allocate(); + if (!allocated_args_result.has_value()) + { + std::cerr << "Consumer: Could not allocate method args: " << allocated_args_result.error() << std::endl; + return Unexpected(allocated_args_result.error()); + } + + auto& [arg1_ptr, arg2_ptr] = allocated_args_result.value(); + *arg1_ptr = input_argument_a; + *arg2_ptr = input_argument_b; + + return proxy.with_in_args_and_return(std::move(arg1_ptr), std::move(arg2_ptr)); + } + else + { + std::cout << "\n=== Test: with_in_args_and_return (copy call) ===" << std::endl; + return proxy.with_in_args_and_return(input_argument_a, input_argument_b); + } + }(); + if (!call_result.has_value()) + { + FailTest(failure_message_prefix, " Consumer: with_in_args_and_return call failed: ", call_result.error()); + return; + } + const auto return_value = *(call_result.value()); + + const auto expected_result_value = input_argument_a + input_argument_b; + if (return_value != expected_result_value) + { + FailTest(failure_message_prefix, " Consumer: Expected ", expected_result_value, " but got ", return_value); + return; + } + + std::cout << "Consumer: with_in_args_and_return returned correct result: " << return_value << std::endl; +} + +void AllSignaturesMethodConsumer::CallMethodWithInArgsOnly(const std::int32_t input_argument_a, + const std::int32_t input_argument_b, + const CopyMode copy_mode, + const std::string& failure_message_prefix) +{ + auto& proxy = GetProxy(); + + auto call_result = [&proxy, copy_mode, input_argument_a, input_argument_b]() -> Result { + SCORE_LANGUAGE_FUTURECPP_ASSERT(copy_mode == CopyMode::WITH_COPY || copy_mode == CopyMode::ZERO_COPY); + if (copy_mode == CopyMode::ZERO_COPY) + { + std::cout << "\n=== Test: with_in_args_only (zero-copy) ===" << std::endl; + auto allocated_args_result = proxy.with_in_args_only.Allocate(); + if (!allocated_args_result.has_value()) + { + std::cerr << "Consumer: Could not allocate method args: " << allocated_args_result.error() << std::endl; + return Unexpected(allocated_args_result.error()); + } + + auto& [arg1_ptr, arg2_ptr] = allocated_args_result.value(); + *arg1_ptr = input_argument_a; + *arg2_ptr = input_argument_b; + + return proxy.with_in_args_only(std::move(arg1_ptr), std::move(arg2_ptr)); + } + else + { + std::cout << "\n=== Test: with_in_args_only (copy call) ===" << std::endl; + return proxy.with_in_args_only(input_argument_a, input_argument_b); + } + }(); + if (!call_result.has_value()) + { + FailTest(failure_message_prefix, " Consumer: with_in_args_only call failed: ", call_result.error()); + return; + } + + std::cout << "Consumer: with_in_args_only returned without error" << std::endl; +} + +void AllSignaturesMethodConsumer::CallMethodWithReturnOnly(const std::int32_t expected_return_value, + const std::string& failure_message_prefix) +{ + auto& proxy = GetProxy(); + + std::cout << "\n=== Test: with_return_only (copy call) ===" << std::endl; + const auto call_result = proxy.with_return_only(); + if (!call_result.has_value()) + { + FailTest(failure_message_prefix, " Consumer: with_return_only call failed: ", call_result.error()); + return; + } + const auto return_value = *(call_result.value()); + + if (return_value != expected_return_value) + { + FailTest(failure_message_prefix, " Consumer: Expected ", expected_return_value, " but got ", return_value); + return; + } + + std::cout << "Consumer: with_return_only returned correct result: " << return_value << std::endl; +} + +void AllSignaturesMethodConsumer::CallMethodWithoutInArgsOrReturn(const std::string& failure_message_prefix) +{ + auto& proxy = GetProxy(); + + std::cout << "\n=== Test: without_args_or_return (copy call) ===" << std::endl; + const auto return_type_ptr_result = proxy.without_args_or_return(); + if (!return_type_ptr_result.has_value()) + { + FailTest( + failure_message_prefix, " Consumer: without_args_or_return call failed: ", return_type_ptr_result.error()); + return; + } + + std::cout << "Consumer: without_args_or_return returned without error" << std::endl; +} + +} // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.h b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.h new file mode 100644 index 000000000..5a1ba63a8 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_consumer.h @@ -0,0 +1,62 @@ +/******************************************************************************** + * 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_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_CONSUMER_H +#define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_CONSUMER_H + +#include "score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/proxy_container.h" + +#include +#include + +namespace score::mw::com::test +{ + +/// \brief Helper class which provides consumer side method functionality for testing +/// +/// This class can be used in conjunction with MethodProvider for abstracting method-related boilerplate code out of +/// tests. The Proxy type is generated from the AllSignaturesInterface. +class AllSignaturesMethodConsumer +{ + public: + enum class CopyMode + { + ZERO_COPY, + WITH_COPY + }; + + AllSignaturesProxy& GetProxy(); + + void CreateProxy(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix); + + void CallMethodWithInArgsAndReturn(const std::int32_t input_argument_a, + const std::int32_t input_argument_b, + const CopyMode copy_mode, + const std::string& failure_message_prefix); + + void CallMethodWithInArgsOnly(const std::int32_t input_argument_a, + const std::int32_t input_argument_b, + const CopyMode copy_mode, + const std::string& failure_message_prefix); + + void CallMethodWithReturnOnly(const std::int32_t expected_return_value, const std::string& failure_message_prefix); + + void CallMethodWithoutInArgsOrReturn(const std::string& failure_message_prefix); + + private: + ProxyContainer proxy_container_; +}; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_CONSUMER_H diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.cpp b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.cpp new file mode 100644 index 000000000..01f8ae1d9 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.cpp @@ -0,0 +1,104 @@ +/******************************************************************************** + * 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/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.h" + +#include "score/mw/com/test/common_test_resources/fail_test.h" + +namespace score::mw::com::test +{ + +void AllSignaturesMethodProvider::CreateSkeleton(InstanceSpecifier instance_specifier, + const std::string& failure_message_prefix) +{ + skeleton_container_.CreateSkeleton(std::move(instance_specifier), failure_message_prefix); +} + +void AllSignaturesMethodProvider::OfferService(const std::string& failure_message_prefix) +{ + skeleton_container_.OfferService(failure_message_prefix); +} + +AllSignaturesSkeleton& AllSignaturesMethodProvider::GetSkeleton() +{ + return skeleton_container_.GetSkeleton(); +} + +void AllSignaturesMethodProvider::RegisterMethodHandlerWithInArgsAndReturn(const std::string& failure_message_prefix) +{ + auto handler_with_in_args_and_return = [](std::int32_t a, std::int32_t b) -> std::int32_t { + std::cout << "Provider: with_in_args_and_return called with " << a << " + " << b << std::endl; + return a + b; + }; + const auto register_result = skeleton_container_.GetSkeleton().with_in_args_and_return.RegisterHandler( + std::move(handler_with_in_args_and_return)); + if (!register_result) + { + FailTest(failure_message_prefix, " Provider: Failed to register with_in_args_and_return handler"); + } + + std::cout << "Provider: Successfully registered with_in_args_and_return handler" << std::endl; +} + +void AllSignaturesMethodProvider::RegisterMethodHandlerWithInArgsOnly(const std::int32_t expected_input_argument_a, + const std::int32_t expected_input_argument_b, + const std::string& failure_message_prefix) +{ + auto handler_with_in_args_only = [expected_input_argument_a, expected_input_argument_b](std::int32_t a, + std::int32_t b) { + std::cout << "Provider: with_in_args_only called with " << a << " + " << b << std::endl; + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(a == expected_input_argument_a, "Unexpected first InArg received!"); + SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE(b == expected_input_argument_b, "Unexpected second InArg received!"); + }; + const auto register_result = + skeleton_container_.GetSkeleton().with_in_args_only.RegisterHandler(std::move(handler_with_in_args_only)); + if (!register_result) + { + FailTest(failure_message_prefix, " Provider: Failed to register with_in_args_only handler"); + } + + std::cout << "Provider: Successfully registered with_in_args_only handler" << std::endl; +} + +void AllSignaturesMethodProvider::RegisterMethodHandlerWithReturnOnly(const std::int32_t expected_return_value, + const std::string& failure_message_prefix) +{ + auto handler_with_return_only = [expected_return_value]() -> std::int32_t { + std::cout << "Provider: with_return_only called. Returning " << expected_return_value << std::endl; + return expected_return_value; + }; + const auto register_result = + skeleton_container_.GetSkeleton().with_return_only.RegisterHandler(std::move(handler_with_return_only)); + if (!register_result) + { + FailTest(failure_message_prefix, " Provider: Failed to register with_return_only handler"); + } + + std::cout << "Provider: Successfully registered with_return_only handler" << std::endl; +} + +void AllSignaturesMethodProvider::RegisterWithoutInArgsOrReturn(const std::string& failure_message_prefix) +{ + auto handler_without_in_args_or_return = []() { + std::cout << "Provider: without_args_or_return called." << std::endl; + }; + const auto register_result = skeleton_container_.GetSkeleton().without_args_or_return.RegisterHandler( + std::move(handler_without_in_args_or_return)); + if (!register_result) + { + FailTest(failure_message_prefix, " Provider: Failed to register without_args_or_return handler"); + } + + std::cout << "Provider: Successfully registered without_args_or_return handler" << std::endl; +} + +} // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.h b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.h new file mode 100644 index 000000000..f9d0c7a20 --- /dev/null +++ b/score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_method_provider.h @@ -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 + ********************************************************************************/ +#ifndef SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_PROVIDER_H +#define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_PROVIDER_H + +#include "score/mw/com/test/methods/methods_test_resources/all_signatures_datatype/all_signatures_datatype.h" +#include "score/mw/com/test/methods/methods_test_resources/skeleton_container.h" +#include "score/mw/com/types.h" + +#include +#include + +namespace score::mw::com::test +{ + +/// \brief Helper class which provides provider side method functionality for testing +/// +/// This class can be used in conjunction with MethodConsumer for abstracting method-related boilerplate code out of +/// tests. The Skeleton type is generated from the AllSignaturesInterface. +class AllSignaturesMethodProvider +{ + public: + void CreateSkeleton(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix); + + void OfferService(const std::string& failure_message_prefix); + + AllSignaturesSkeleton& GetSkeleton(); + + void RegisterMethodHandlerWithInArgsAndReturn(const std::string& failure_message_prefix); + + void RegisterMethodHandlerWithInArgsOnly(const std::int32_t expected_input_argument_a, + const std::int32_t expected_input_argument_b, + const std::string& failure_message_prefix); + + void RegisterMethodHandlerWithReturnOnly(const std::int32_t expected_return_value, + const std::string& failure_message_prefix); + + void RegisterWithoutInArgsOrReturn(const std::string& failure_message_prefix); + + private: + SkeletonContainer skeleton_container_; +}; + +} // namespace score::mw::com::test + +#endif // SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_ALL_SIGNATURES_DATA_TYPE_ALL_SIGNATURES_METHOD_PROVIDER_H diff --git a/score/mw/com/test/methods/methods_test_resources/base_mw_com_config.json b/score/mw/com/test/methods/methods_test_resources/base_mw_com_config.json deleted file mode 100644 index 364059d69..000000000 --- a/score/mw/com/test/methods/methods_test_resources/base_mw_com_config.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "serviceTypes": [ - { - "serviceTypeName": "/test/methods/methods_test_resources/MultiMethodProvider", - "version": { - "major": 1, - "minor": 0 - }, - "bindings": [ - { - "binding": "SHM", - "serviceId": 3000, - "methods": [ - { - "methodName": "method0", - "methodId": 1 - }, - { - "methodName": "method1", - "methodId": 2 - }, - { - "methodName": "method2", - "methodId": 3 - }, - { - "methodName": "method3", - "methodId": 4 - }, - { - "methodName": "method4", - "methodId": 5 - } - ] - } - ] - } - ], - "serviceInstances": [ - { - "instanceSpecifier": "methods_test_resources/MultiMethodProvider", - "serviceTypeName": "/test/methods/methods_test_resources/MultiMethodProvider", - "version": { - "major": 1, - "minor": 0 - }, - "instances": [ - { - "instanceId": 1, - "asil-level": "QM", - "binding": "SHM", - "methods": [ - { - "methodName": "method0", - "queueSize": 5 - }, - { - "methodName": "method1", - "queueSize": 5 - }, - { - "methodName": "method2", - "queueSize": 5 - }, - { - "methodName": "method3", - "queueSize": 5 - }, - { - "methodName": "method4", - "queueSize": 5 - } - ], - "allowedConsumer": { - "QM": [ - 0 - ], - "B": [ - 0 - ] - }, - "allowedProvider": { - "QM": [ - 0 - ], - "B": [ - 0 - ] - } - } - ] - } - ], - "global": { - "asil-level": "QM" - } -} diff --git a/score/mw/com/test/methods/methods_test_resources/config_generator.py b/score/mw/com/test/methods/methods_test_resources/config_generator.py deleted file mode 100644 index fccea51a2..000000000 --- a/score/mw/com/test/methods/methods_test_resources/config_generator.py +++ /dev/null @@ -1,75 +0,0 @@ -import json -import sys -import os -from typing import Dict - - -def load_json(json_path: str) -> Dict: - with open(json_path, 'r') as json_file: - loaded_json = json.load(json_file) - return loaded_json - - -def save_json(json_path: str, json_data: Dict): - os.makedirs(os.path.dirname(json_path), exist_ok=True) - with open(json_path, "w") as json_file: - json.dump(json_data, json_file, indent=4, sort_keys=True) - - -def create_mw_com_config(base_config_json: dict, - asil_level_app: str, - asil_level_communication_partner: str, - app_id: int | None): - result = dict(base_config_json) - result["global"]["asil-level"] = asil_level_app - result["serviceInstances"][0]["instances"][0]["asil-level"] = asil_level_communication_partner - if app_id is not None: - result["global"]["applicationID"] = app_id - return result - - -def parse_key(arg_dict, key): - try: - return arg_dict[key] - except KeyError as e: - print(f"json string must contain '{key}' key.") - print(f"Error: {e}. Exiting.") - sys.exit(1) - - -def main(): - base_mw_com_config_path = str(sys.argv[1]) - out_mw_com_config_path = str(sys.argv[2]) - try: - arg_dict = json.loads(sys.argv[3]) - except json.decoder.JSONDecodeError as e: - print("Third command line argument must be a valid json string.") - print(f"Error: {e}. Exiting.") - sys.exit(1) - - asil_level_app = parse_key(arg_dict, "asil-level-app") - asil_level_communication_partner = parse_key( - arg_dict, "asil-level-communication-partner") - - app_id_str = parse_key(arg_dict, "applicationID") - if app_id_str == "": - app_id = None - else: - try: - app_id = int(app_id_str) - except ValueError as e: - print( - "The value of 'applicationID' key must be either empty or a string that can be converted to an integer.") - print(f"Error: {e}. Exiting.") - sys.exit(1) - - base_config_json = load_json(base_mw_com_config_path) - - config_json = create_mw_com_config( - base_config_json, asil_level_app, asil_level_communication_partner, app_id) - save_json(out_mw_com_config_path, config_json) - print("config saved") - - -if __name__ == "__main__": - main() diff --git a/score/mw/com/test/methods/methods_test_resources/config_generator_rule.bzl b/score/mw/com/test/methods/methods_test_resources/config_generator_rule.bzl deleted file mode 100644 index d08612327..000000000 --- a/score/mw/com/test/methods/methods_test_resources/config_generator_rule.bzl +++ /dev/null @@ -1,70 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 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 _make_configs(ctx): - config_json = ctx.file.base_config_json_path - generated_configs_out = ctx.actions.declare_file(ctx.attr.out_config_name) - further_args = str(ctx.attr.further_args) - - ctx.actions.run( - executable = ctx.executable.tool, - inputs = [config_json], - outputs = [generated_configs_out], - arguments = [config_json.path, generated_configs_out.path, further_args], - ) - - return [DefaultInfo(files = depset([generated_configs_out]))] - -make_config_json = rule( - implementation = _make_configs, - attrs = { - "base_config_json_path": attr.label(allow_single_file = True), - "out_config_name": attr.string(mandatory = True), - "further_args": attr.string_dict( - default = {}, - doc = "Any list of additional arguments that can be provider to the tool specified in the 'tool' attribute.", - ), - "tool": attr.label( - default = "//score/mw/com/test/multiple_proxies/config_generator:config_generator", - executable = True, - cfg = "exec", - allow_files = True, - ), - }, -) - -def _make_default_configs_impl(name, visibility, applicationID, asil_level_app, asil_level_communication_partner, **kwargs): - out_config_name = "{}.json".format(name) - - make_config_json( - name = name, - base_config_json_path = "//score/mw/com/test/methods/methods_test_resources:base_mw_com_config_json", - out_config_name = out_config_name, - further_args = { - "asil-level-app": asil_level_app, - "asil-level-communication-partner": asil_level_communication_partner, - "applicationID": applicationID, - }, - tool = "//score/mw/com/test/methods/methods_test_resources:config_generator", - visibility = visibility, - **kwargs - ) - -make_default_configs = macro( - implementation = _make_default_configs_impl, - attrs = { - "applicationID": attr.string(configurable = False), - "asil_level_app": attr.string(configurable = False, default = "QM"), - "asil_level_communication_partner": attr.string(configurable = False, default = "QM"), - }, -) 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..a342c3819 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 @@ -61,7 +61,7 @@ class MethodConsumer WITH_COPY }; - bool CreateProxy(InstanceSpecifier instance_specifier); + void CreateProxy(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix); bool CallMethodWithInArgsAndReturn(const std::int32_t input_argument_a, const std::int32_t input_argument_b, @@ -80,9 +80,9 @@ class MethodConsumer }; template -bool MethodConsumer::CreateProxy(InstanceSpecifier instance_specifier) +void MethodConsumer::CreateProxy(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix) { - return proxy_container_.CreateProxy(std::move(instance_specifier)); + proxy_container_.CreateProxy(std::move(instance_specifier), failure_message_prefix); } template diff --git a/score/mw/com/test/methods/methods_test_resources/process_synchronizer.cpp b/score/mw/com/test/methods/methods_test_resources/process_synchronizer.cpp index 814be84db..cabc5a3f1 100644 --- a/score/mw/com/test/methods/methods_test_resources/process_synchronizer.cpp +++ b/score/mw/com/test/methods/methods_test_resources/process_synchronizer.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace score::mw::com::test { @@ -42,6 +43,23 @@ std::optional ProcessSynchronizer::Create(const std::string return std::optional{std::in_place_t{}, std::move(interprocess_notification_result).value()}; } +auto ProcessSynchronizer::CreateUniquePtr(const std::string& interprocess_notification_shm_path) + -> std::unique_ptr +{ + auto interprocess_notification_result = + SharedMemoryObjectCreator::CreateOrOpenObject(interprocess_notification_shm_path); + if (!interprocess_notification_result.has_value()) + { + std::stringstream ss; + ss << "Consumer: Creating or opening interprocess notification object failed:" + << interprocess_notification_result.error(); + std::cerr << ss.str() << std::endl; + return nullptr; + } + + return std::make_unique(std::move(interprocess_notification_result).value()); +} + ProcessSynchronizer::ProcessSynchronizer( SharedMemoryObjectCreator interprocess_notifier_creator) : interprocess_notifier_creator_{std::move(interprocess_notifier_creator)}, diff --git a/score/mw/com/test/methods/methods_test_resources/process_synchronizer.h b/score/mw/com/test/methods/methods_test_resources/process_synchronizer.h index 8a30c2897..0afdb0008 100644 --- a/score/mw/com/test/methods/methods_test_resources/process_synchronizer.h +++ b/score/mw/com/test/methods/methods_test_resources/process_synchronizer.h @@ -31,6 +31,8 @@ class ProcessSynchronizer { public: static std::optional Create(const std::string& interprocess_notification_shm_path); + static auto CreateUniquePtr(const std::string& interprocess_notification_shm_path) + -> std::unique_ptr; ProcessSynchronizer(SharedMemoryObjectCreator interprocess_notifier_creator); diff --git a/score/mw/com/test/methods/methods_test_resources/proxy_container.h b/score/mw/com/test/methods/methods_test_resources/proxy_container.h index 61a9f9fc9..62665117c 100644 --- a/score/mw/com/test/methods/methods_test_resources/proxy_container.h +++ b/score/mw/com/test/methods/methods_test_resources/proxy_container.h @@ -13,6 +13,7 @@ #ifndef SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_PROXY_CONTAINER_H #define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_PROXY_CONTAINER_H +#include "score/mw/com/test/common_test_resources/fail_test.h" #include "score/mw/com/types.h" #include @@ -20,7 +21,7 @@ #include #include #include -#include +#include namespace score::mw::com::test { @@ -29,9 +30,7 @@ template class ProxyContainer { public: - ProxyContainer(); - - bool CreateProxy(InstanceSpecifier instance_specifier); + void CreateProxy(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix); Proxy& GetProxy() { @@ -41,21 +40,15 @@ class ProxyContainer } private: - std::unique_ptr handle_; - std::mutex proxy_creation_mutex_; - std::condition_variable proxy_creation_condition_variable_; + std::unique_ptr handle_{nullptr}; + std::mutex proxy_creation_mutex_{}; + std::condition_variable proxy_creation_condition_variable_{}; - std::unique_ptr proxy_; + std::unique_ptr proxy_{nullptr}; }; template -ProxyContainer::ProxyContainer() - : handle_{nullptr}, proxy_creation_mutex_{}, proxy_creation_condition_variable_{}, proxy_{nullptr} -{ -} - -template -bool ProxyContainer::CreateProxy(InstanceSpecifier instance_specifier) +void ProxyContainer::CreateProxy(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix) { bool callback_called{false}; auto find_service_callback = [this, &callback_called](auto service_handle_container, @@ -79,8 +72,7 @@ bool ProxyContainer::CreateProxy(InstanceSpecifier instance_specifier) auto start_find_service_result = Proxy::StartFindService(find_service_callback, instance_specifier); if (!start_find_service_result.has_value()) { - std::cerr << "Consumer: StartFindService() failed:" << start_find_service_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: StartFindService() failed: ", start_find_service_result.error()); } std::cout << "Consumer: StartFindService called" << std::endl; @@ -93,21 +85,18 @@ bool ProxyContainer::CreateProxy(InstanceSpecifier instance_specifier) }); if (!service_found || handle_ == nullptr) { - std::cerr << "Consumer: StartFindService() failed to get handle" << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: StartFindService() failed to get handle"); } auto proxy_result = Proxy::Create(*handle_); proxy_creation_lock.unlock(); if (!proxy_result.has_value()) { - std::cerr << "Consumer: Unable to construct proxy: " << proxy_result.error() << ", bailing!\n"; - return false; + FailTest(failure_message_prefix, " Consumer: Unable to construct proxy: ", proxy_result.error()); } proxy_ = std::make_unique(std::move(proxy_result).value()); std::cout << "Consumer: Proxy created successfully" << std::endl; - return true; } } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/methods_test_resources/skeleton_container.h b/score/mw/com/test/methods/methods_test_resources/skeleton_container.h index 31d6f1922..dbef02d3b 100644 --- a/score/mw/com/test/methods/methods_test_resources/skeleton_container.h +++ b/score/mw/com/test/methods/methods_test_resources/skeleton_container.h @@ -13,10 +13,12 @@ #ifndef SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_SKELETON_CONTAINER_H #define SCORE_MW_COM_TEST_METHODS_METHODS_TEST_RESOURCES_SKELETON_CONTAINER_H +#include "score/mw/com/test/common_test_resources/fail_test.h" #include "score/mw/com/types.h" #include #include +#include namespace score::mw::com::test { @@ -25,10 +27,8 @@ template class SkeletonContainer { public: - SkeletonContainer(std::string instance_specifier_string); - - bool CreateSkeleton(); - bool OfferService(); + void CreateSkeleton(InstanceSpecifier instance_specifier, const std::string& failure_message_prefix); + void OfferService(const std::string& failure_message_prefix); Skeleton& GetSkeleton() { @@ -38,50 +38,33 @@ class SkeletonContainer } private: - std::string instance_specifier_string_; std::unique_ptr skeleton_; }; template -SkeletonContainer::SkeletonContainer(std::string instance_specifier_string) - : instance_specifier_string_{std::move(instance_specifier_string)} -{ -} - -template -bool SkeletonContainer::CreateSkeleton() +void SkeletonContainer::CreateSkeleton(InstanceSpecifier instance_specifier, + const std::string& failure_message_prefix) { - auto instance_specifier = InstanceSpecifier::Create(std::string{instance_specifier_string_}); - if (!instance_specifier.has_value()) - { - std::cerr << "Provider: Could not create InstanceSpecifier from: " << instance_specifier_string_ << std::endl; - return false; - } - - auto skeleton_result = Skeleton::Create(instance_specifier.value()); + auto skeleton_result = Skeleton::Create(std::move(instance_specifier)); if (!skeleton_result.has_value()) { - std::cerr << "Provider: Could not create skeleton: " << skeleton_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Provider: Could not create skeleton: ", skeleton_result.error()); } skeleton_ = std::make_unique(std::move(skeleton_result).value()); - return true; } template -bool SkeletonContainer::OfferService() +void SkeletonContainer::OfferService(const std::string& failure_message_prefix) { SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(skeleton_ != nullptr); auto offer_result = skeleton_->OfferService(); if (!(offer_result.has_value())) { - std::cerr << "Provider: Could not offer service: " << offer_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Provider: Could not offer service: ", offer_result.error()); } std::cout << "Provider: Service offered successfully" << std::endl; - return true; } } // namespace score::mw::com::test 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..acd37a435 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/consumer.cpp @@ -12,6 +12,7 @@ ********************************************************************************/ #include "score/mw/com/test/methods/non_trivial_constructors/consumer.h" +#include "score/mw/com/test/common_test_resources/fail_test.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" @@ -33,14 +34,14 @@ const std::string kInterprocessNotificationShmPath{"/non_trivial_constructors_te const InstanceSpecifier kInstanceSpecifier = InstanceSpecifier::Create(std::string{"test/methods/non_trivial_constructors/MethodSignature"}).value(); -bool CallMethodWithInArgsAndReturn(NonTrivialConstructorProxy& proxy) +void CallMethodWithInArgsAndReturn(NonTrivialConstructorProxy& proxy, const std::string& failure_message_prefix) { - auto call_result = [&proxy]() -> score::Result> { + auto call_result = + [&proxy, &failure_message_prefix]() -> score::Result> { std::cout << "\n=== Test: with_in_args_and_return (zero-copy) ===" << std::endl; auto allocated_args_result = proxy.with_in_args_and_return.Allocate(); if (!allocated_args_result.has_value()) { - std::cerr << "Consumer: Could not allocate method args: " << allocated_args_result.error() << std::endl; return Unexpected(allocated_args_result.error()); } @@ -49,8 +50,7 @@ bool CallMethodWithInArgsAndReturn(NonTrivialConstructorProxy& proxy) }(); if (!call_result.has_value()) { - std::cerr << "Consumer: with_in_args_and_return call failed: " << call_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: with_in_args_and_return call failed: ", call_result.error()); } const auto return_value = *(call_result.value()); @@ -58,22 +58,19 @@ bool CallMethodWithInArgsAndReturn(NonTrivialConstructorProxy& proxy) const auto expected_return_value = NonTriviallyConstructibleType{} + NonTriviallyConstructibleType{}; if (return_value != expected_return_value) { - std::cerr << "Consumer: Expected " << expected_return_value << " but got " << return_value << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: Expected ", expected_return_value, " but got ", return_value); } std::cout << "Consumer: with_in_args_and_return returned correct result: " << return_value << std::endl; - return true; } -bool CallMethodWithInArgsOnly(NonTrivialConstructorProxy& proxy) +void CallMethodWithInArgsOnly(NonTrivialConstructorProxy& proxy, const std::string& failure_message_prefix) { - auto call_result = [&proxy]() -> Result { + auto call_result = [&proxy, &failure_message_prefix]() -> Result { std::cout << "\n=== Test: with_in_args_only (zero-copy) ===" << std::endl; auto allocated_args_result = proxy.with_in_args_only.Allocate(); if (!allocated_args_result.has_value()) { - std::cerr << "Consumer: Could not allocate method args: " << allocated_args_result.error() << std::endl; return Unexpected(allocated_args_result.error()); } @@ -83,90 +80,65 @@ bool CallMethodWithInArgsOnly(NonTrivialConstructorProxy& proxy) }(); if (!call_result.has_value()) { - std::cerr << "Consumer: with_in_args_only call failed: " << call_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: with_in_args_only call failed: ", call_result.error()); } std::cout << "Consumer: with_in_args_only returned without error" << std::endl; - return true; } -bool CallMethodWithReturnOnly(NonTrivialConstructorProxy& proxy) +void CallMethodWithReturnOnly(NonTrivialConstructorProxy& proxy, const std::string& failure_message_prefix) { std::cout << "\n=== Test: with_return_only (copy call) ===" << std::endl; const auto call_result = proxy.with_return_only(); if (!call_result.has_value()) { - std::cerr << "Consumer: with_return_only call failed: " << call_result.error() << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: with_return_only call failed: ", call_result.error()); } const auto return_value = *(call_result.value()); const auto expected_return_value = NonTriviallyConstructibleType{}; if (return_value != expected_return_value) { - std::cerr << "Consumer: Expected " << expected_return_value << " but got " << return_value << std::endl; - return false; + FailTest(failure_message_prefix, " Consumer: Expected ", expected_return_value, " but got ", return_value); } std::cout << "Consumer: with_return_only returned correct result: " << return_value << std::endl; - return true; } } // namespace -int run_consumer() +void run_consumer() { auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); if (!(process_synchronizer_result.has_value())) { - std::cerr << "Methods non_trivial_constructors consumer failed: Could not create ProcessSynchronizer" - << std::endl; - return EXIT_FAILURE; + FailTest("Methods non_trivial_constructors consumer failed: Could not create ProcessSynchronizer"); } + // Set an exit function to notify the provider in case of failure in calls to FailTest, so that it does not wait + // indefinitely for the consumer to finish. Will also be called when the guard goes out of scope at the end of this + // function. + ExitFunctionGuard process_synchronizer_guard{[&process_synchronizer_result]() { + process_synchronizer_result->Notify(); + }}; + ProxyContainer consumer{}; // Step 1. Find service and create proxy std::cout << "\nConsumer: Step 1" << std::endl; - if (!consumer.CreateProxy(kInstanceSpecifier)) - { - std::cerr << "Methods non_trivial_constructors consumer failed: CreateProxy" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + consumer.CreateProxy(kInstanceSpecifier, "non_trivial_constructors"); // Step 2. Call zero-copy method with InArgs and Return std::cout << "\nConsumer: Step 2" << std::endl; - if (!CallMethodWithInArgsAndReturn(consumer.GetProxy())) - { - std::cerr << "Methods non_trivial_constructors consumer failed: CallMethodWithInArgsAndReturnZeroCopy" - << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + CallMethodWithInArgsAndReturn(consumer.GetProxy(), "non_trivial_constructors"); // Step 3. Call zero-copy method with InArgs only std::cout << "\nConsumer: Step 3" << std::endl; - if (!CallMethodWithInArgsOnly(consumer.GetProxy())) - { - std::cerr << "Methods non_trivial_constructors consumer failed: CallMethodWithInArgsOnlyZeroCopy" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + CallMethodWithInArgsOnly(consumer.GetProxy(), "non_trivial_constructors"); // Step 4. Call method with return only with copy std::cout << "\nConsumer: Step 4" << std::endl; - if (!CallMethodWithReturnOnly(consumer.GetProxy())) - { - std::cerr << "Methods non_trivial_constructors consumer failed: CallMethodWithReturnOnly" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } - - process_synchronizer_result->Notify(); - - return EXIT_SUCCESS; + CallMethodWithReturnOnly(consumer.GetProxy(), "non_trivial_constructors"); } } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/non_trivial_constructors/consumer.h b/score/mw/com/test/methods/non_trivial_constructors/consumer.h index 2e29d24fb..a153d3044 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/consumer.h +++ b/score/mw/com/test/methods/non_trivial_constructors/consumer.h @@ -16,7 +16,7 @@ namespace score::mw::com::test { -int run_consumer(); +void run_consumer(); } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/non_trivial_constructors/integration_test/BUILD b/score/mw/com/test/methods/non_trivial_constructors/integration_test/BUILD index 17d83054e..364b465cb 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/integration_test/BUILD +++ b/score/mw/com/test/methods/non_trivial_constructors/integration_test/BUILD @@ -30,10 +30,3 @@ integration_test( filesystem = ":filesystem", flaky = True, # TODO: Remove flaky tag once test is stable: Refer to issue 386 ) - -test_suite( - name = "component_tests", - tests = [ - ":non_trivial_constructors_test", - ], -) diff --git a/score/mw/com/test/methods/non_trivial_constructors/main_consumer.cpp b/score/mw/com/test/methods/non_trivial_constructors/main_consumer.cpp index f4a0fc68b..0c4a9141d 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/main_consumer.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/main_consumer.cpp @@ -18,5 +18,6 @@ int main(int argc, const char** argv) { score::mw::com::test::SetupAssertHandler(); score::mw::com::runtime::InitializeRuntime(argc, argv); - return score::mw::com::test::run_consumer(); + score::mw::com::test::run_consumer(); + return EXIT_SUCCESS; } diff --git a/score/mw/com/test/methods/non_trivial_constructors/main_provider.cpp b/score/mw/com/test/methods/non_trivial_constructors/main_provider.cpp index 756f6d73f..f53e67426 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/main_provider.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/main_provider.cpp @@ -29,5 +29,6 @@ int main(int argc, const char** argv) std::cerr << "Unable to set signal handler for SIGINT and/or SIGTERM, cautiously continuing\n"; } - return score::mw::com::test::run_provider(stop_source.get_token()); + score::mw::com::test::run_provider(stop_source.get_token()); + return EXIT_SUCCESS; } 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..1d29c8e43 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/provider.cpp +++ b/score/mw/com/test/methods/non_trivial_constructors/provider.cpp @@ -12,10 +12,12 @@ ********************************************************************************/ #include "score/mw/com/test/methods/non_trivial_constructors/provider.h" +#include "score/mw/com/test/common_test_resources/fail_test.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 "score/mw/com/types.h" #include #include @@ -27,9 +29,11 @@ namespace { const std::string kInterprocessNotificationShmPath{"/non_trivial_constructors_test_interprocess_notification"}; -const std::string kInstanceSpecifier{"test/methods/non_trivial_constructors/MethodSignature"}; +const auto kInstanceSpecifier{ + InstanceSpecifier::Create(std::string{"test/methods/non_trivial_constructors/MethodSignature"}).value()}; -bool RegisterMethodHandlerWithInArgsAndReturn(NonTrivialConstructorSkeleton& skeleton) +void RegisterMethodHandlerWithInArgsAndReturn(NonTrivialConstructorSkeleton& skeleton, + const std::string& failure_message_prefix) { auto handler_with_in_args_and_return = [](NonTriviallyConstructibleType a, NonTriviallyConstructibleType b) -> NonTriviallyConstructibleType { @@ -40,15 +44,14 @@ bool RegisterMethodHandlerWithInArgsAndReturn(NonTrivialConstructorSkeleton& ske skeleton.with_in_args_and_return.RegisterHandler(std::move(handler_with_in_args_and_return)); if (!register_result) { - std::cerr << "Provider: Failed to register with_in_args_and_return handler" << std::endl; - return false; + FailTest(failure_message_prefix, " Provider: Failed to register with_in_args_and_return handler"); } std::cout << "Provider: Successfully registered with_in_args_and_return handler" << std::endl; - return true; } -bool RegisterMethodHandlerWithInArgsOnly(NonTrivialConstructorSkeleton& skeleton) +void RegisterMethodHandlerWithInArgsOnly(NonTrivialConstructorSkeleton& skeleton, + const std::string& failure_message_prefix) { auto handler_with_in_args_only = [](NonTriviallyConstructibleType a, NonTriviallyConstructibleType b) { std::cout << "Provider: with_in_args_only called with " << a << " + " << b << std::endl; @@ -60,15 +63,14 @@ bool RegisterMethodHandlerWithInArgsOnly(NonTrivialConstructorSkeleton& skeleton const auto register_result = skeleton.with_in_args_only.RegisterHandler(std::move(handler_with_in_args_only)); if (!register_result) { - std::cerr << "Provider: Failed to register with_in_args_only handler" << std::endl; - return false; + FailTest(failure_message_prefix, " Provider: Failed to register with_in_args_only handler"); } std::cout << "Provider: Successfully registered with_in_args_only handler" << std::endl; - return true; } -bool RegisterMethodHandlerWithReturnOnly(NonTrivialConstructorSkeleton& skeleton) +void RegisterMethodHandlerWithReturnOnly(NonTrivialConstructorSkeleton& skeleton, + const std::string& failure_message_prefix) { auto handler_with_return_only = []() -> NonTriviallyConstructibleType { std::cout << "Provider: with_return_only called. Returning " << NonTriviallyConstructibleType{} << std::endl; @@ -77,75 +79,50 @@ bool RegisterMethodHandlerWithReturnOnly(NonTrivialConstructorSkeleton& skeleton const auto register_result = skeleton.with_return_only.RegisterHandler(std::move(handler_with_return_only)); if (!register_result) { - std::cerr << "Provider: Failed to register with_return_only handler" << std::endl; - return false; + FailTest(failure_message_prefix, " Provider: Failed to register with_return_only handler"); } std::cout << "Provider: Successfully registered with_return_only handler" << std::endl; - return true; } } // namespace -bool run_provider(const score::cpp::stop_token& stop_token) +void run_provider(const score::cpp::stop_token& stop_token) { auto process_synchronizer_result = ProcessSynchronizer::Create(kInterprocessNotificationShmPath); if (!(process_synchronizer_result.has_value())) { - std::cerr << "Methods non_trivial_constructors provider failed: Could not create ProcessSynchronizer" - << std::endl; - return EXIT_FAILURE; + FailTest("Methods non_trivial_constructors provider failed: Could not create ProcessSynchronizer"); } - SkeletonContainer skeleton_container{kInstanceSpecifier}; + SkeletonContainer skeleton_container{}; // Step 1. Create skeleton - if (!skeleton_container.CreateSkeleton()) - { - std::cerr << "Non trivial constructors provider failed: CreateSkeleton" << std::endl; - return EXIT_FAILURE; - } + skeleton_container.CreateSkeleton(kInstanceSpecifier, "non_trivial_constructors"); // Step 2. Register method handler for method with InArgs and return value - if (!RegisterMethodHandlerWithInArgsAndReturn(skeleton_container.GetSkeleton())) - { - std::cerr << "Non trivial constructors provider failed: RegisterMethodHandlerWithInArgsAndReturn" << std::endl; - return EXIT_FAILURE; - } + RegisterMethodHandlerWithInArgsAndReturn(skeleton_container.GetSkeleton(), "non_trivial_constructors"); // Step 3. Register method handler for method with only InArgs - if (!RegisterMethodHandlerWithInArgsOnly(skeleton_container.GetSkeleton())) - { - std::cerr << "Non trivial constructors provider failed: RegisterMethodHandlerWithInArgsOnly" << std::endl; - return EXIT_FAILURE; - } + RegisterMethodHandlerWithInArgsOnly(skeleton_container.GetSkeleton(), "non_trivial_constructors"); // Step 4. Register method handler for method with only return value - if (!RegisterMethodHandlerWithReturnOnly(skeleton_container.GetSkeleton())) - { - std::cerr << "Non trivial constructors provider failed: RegisterMethodHandlerWithReturnOnly" << std::endl; - return EXIT_FAILURE; - } + RegisterMethodHandlerWithReturnOnly(skeleton_container.GetSkeleton(), "non_trivial_constructors"); // Step 5. Offer service - if (!skeleton_container.OfferService()) - { - std::cerr << "Non trivial constructors provider failed: OfferService" << std::endl; - return EXIT_FAILURE; - } + skeleton_container.OfferService("non_trivial_constructors"); // Step 6. Wait for proxy test to finish std::cout << "Provider: Ready for method calls" << std::endl; if (!process_synchronizer_result->WaitWithAbort(stop_token)) { - std::cerr << "Non trivial constructors provider failed: WaitForProxyTestToFinish was stopped by " - "stop_token instead of notification" - << std::endl; - return EXIT_FAILURE; + FailTest( + "Non trivial constructors provider failed: WaitForProxyTestToFinish was stopped by " + "stop_token instead of notification"); + return; } std::cout << "Provider: Shutting down" << std::endl; - return EXIT_SUCCESS; } } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/non_trivial_constructors/provider.h b/score/mw/com/test/methods/non_trivial_constructors/provider.h index 96dd13c12..bbb646c71 100644 --- a/score/mw/com/test/methods/non_trivial_constructors/provider.h +++ b/score/mw/com/test/methods/non_trivial_constructors/provider.h @@ -20,7 +20,7 @@ namespace score::mw::com::test { -bool run_provider(const score::cpp::stop_token& stop_token); +void run_provider(const score::cpp::stop_token& stop_token); } // namespace score::mw::com::test diff --git a/score/mw/com/test/methods/signature_variations/consumer.cpp b/score/mw/com/test/methods/signature_variations/consumer.cpp index f7f4d45e0..2d6123f00 100644 --- a/score/mw/com/test/methods/signature_variations/consumer.cpp +++ b/score/mw/com/test/methods/signature_variations/consumer.cpp @@ -58,12 +58,7 @@ int run_consumer() // Step 1. Find service and create proxy std::cout << "\nConsumer: Step 1" << std::endl; - if (!consumer.CreateProxy(kInstanceSpecifier)) - { - std::cerr << "Methods signature_variations consumer failed: CreateProxy" << std::endl; - process_synchronizer_result->Notify(); - return EXIT_FAILURE; - } + consumer.CreateProxy(kInstanceSpecifier, "signature_variations"); // Step 2. Call method with InArgs and Return with copy std::cout << "\nConsumer: Step 2" << std::endl;