From 54dbed9885f88aaa69726a7b7332b5cde68689a6 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Mon, 21 Feb 2022 18:42:21 +0100 Subject: [PATCH 01/14] iox-#1142 Add ServiceDiscovery to C binding Signed-off-by: Marika Lehmann --- iceoryx_binding_c/CMakeLists.txt | 1 + .../include/iceoryx_binding_c/api.h | 3 +- .../iceoryx_binding_c/service_discovery.h | 49 +++++++++++++ .../include/iceoryx_binding_c/types.h | 8 +++ .../source/c_service_discovery.cpp | 71 +++++++++++++++++++ .../moduletests/test_service_discovery.cpp | 69 ++++++++++++++++++ .../test/moduletests/test_types.cpp | 10 ++- 7 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h create mode 100644 iceoryx_binding_c/source/c_service_discovery.cpp create mode 100644 iceoryx_binding_c/test/moduletests/test_service_discovery.cpp diff --git a/iceoryx_binding_c/CMakeLists.txt b/iceoryx_binding_c/CMakeLists.txt index 3c8dbffdef..faa8d74eee 100644 --- a/iceoryx_binding_c/CMakeLists.txt +++ b/iceoryx_binding_c/CMakeLists.txt @@ -73,6 +73,7 @@ add_library(${PROJECT_NAME} source/cpp2c_publisher.cpp source/cpp2c_subscriber.cpp source/cpp2c_service_description_translation.cpp + source/c_service_discovery.cpp ) add_library(${PROJECT_NAMESPACE}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/api.h b/iceoryx_binding_c/include/iceoryx_binding_c/api.h index b236c9d0d6..a5291b2f0f 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/api.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/api.h @@ -1,4 +1,4 @@ -// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. +// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ #include "runtime.h" #include "server.h" #include "service_description.h" +#include "service_discovery.h" #include "subscriber.h" #include "types.h" #include "user_trigger.h" diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h new file mode 100644 index 0000000000..c585db0b87 --- /dev/null +++ b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h @@ -0,0 +1,49 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_BINDING_C_SERVICE_DISCOVERY_H +#define IOX_BINDING_C_SERVICE_DISCOVERY_H + +#include "iceoryx_binding_c/internal/c2cpp_binding.h" +#include "iceoryx_binding_c/types.h" +#include "service_description.h" + +/////// @brief service discovery handle +////// typedef struct cpp2c_ServiceDiscovery* iox_service_discovery_t; +typedef CLASS ServiceDiscovery* iox_service_discovery_t; + +///// @brief initializes a listener struct from a storage struct pointer +///// @param[in] self pointer to raw memory which can hold a listener +///// @return an initialized iox_listener_t +iox_service_discovery_t iox_service_discovery_init(iox_service_discovery_storage_t* self); + +///// @brief after using an iox_listener_t it must be cleaned up with this function +///// @param[in] self the listener which should be deinitialized +void iox_service_discovery_deinit(iox_service_discovery_t const self); + +/// @brief Searches all services that match the provided service description and applies a function to each of them +/// @param[in] self handle of the service discovery +/// @param[in] service service string to search for, a nullptr corresponds to a wildcard +/// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard +/// @param[in] event event string to search for, a nullptr corresponds to a wildcard +/// @param[in] callable to apply to all matching services +void iox_service_discovery_find_service(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t)); + +#endif diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/types.h b/iceoryx_binding_c/include/iceoryx_binding_c/types.h index 0d0d649394..4be01d66c4 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/types.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/types.h @@ -120,5 +120,13 @@ typedef struct #endif } iox_server_storage_t; +/// @brief has exactly the size required to store the underlying object of iox_service_discovery_t +struct iox_service_discovery_storage_t +{ + // the value of the array size is the result of the following formula: + // sizeof(ServiceDiscovery) / 8 + uint64_t do_not_touch_me[196768]; +}; +typedef struct iox_service_discovery_storage_t iox_service_discovery_storage_t; #endif diff --git a/iceoryx_binding_c/source/c_service_discovery.cpp b/iceoryx_binding_c/source/c_service_discovery.cpp new file mode 100644 index 0000000000..76df4680d6 --- /dev/null +++ b/iceoryx_binding_c/source/c_service_discovery.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "iceoryx_binding_c/internal/cpp2c_service_description_translation.hpp" +#include "iceoryx_hoofs/cxx/optional.hpp" +#include "iceoryx_hoofs/cxx/requires.hpp" +#include "iceoryx_posh/runtime/service_discovery.hpp" + +using namespace iox; +using namespace iox::runtime; + +extern "C" { +#include "iceoryx_binding_c/service_discovery.h" +} + +iox_service_discovery_t iox_service_discovery_init(iox_service_discovery_storage_t* self) +{ + iox::cxx::Expects(self != nullptr); + + auto* me = new (self) ServiceDiscovery(); + return reinterpret_cast(me); +} + +void iox_service_discovery_deinit(iox_service_discovery_t const self) +{ + iox::cxx::Expects(self != nullptr); + + self->~ServiceDiscovery(); +} + +void iox_service_discovery_find_service(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t)) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(callable != nullptr); + + cxx::optional maybeService; + if (service != nullptr) + { + maybeService.emplace(cxx::TruncateToCapacity, service); + } + cxx::optional maybeInstance; + if (instance != nullptr) + { + maybeInstance.emplace(cxx::TruncateToCapacity, instance); + } + cxx::optional maybeEvent; + if (event != nullptr) + { + maybeEvent.emplace(cxx::TruncateToCapacity, event); + } + + auto filter = [&](const capro::ServiceDescription& s) { callable(TranslateServiceDescription(s)); }; + self->findService(maybeService, maybeInstance, maybeEvent, filter, iox::popo::MessagingPattern::PUB_SUB); +} diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp new file mode 100644 index 0000000000..abc982bbe5 --- /dev/null +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "iceoryx_posh/runtime/service_discovery.hpp" +#include "iceoryx_posh/testing/roudi_gtest.hpp" + +using namespace iox; +using namespace iox::runtime; + +extern "C" { +#include "iceoryx_binding_c/runtime.h" +#include "iceoryx_binding_c/service_discovery.h" +} + +namespace +{ +using namespace ::testing; + +class iox_service_discovery_test : public RouDi_GTest +{ + public: + void SetUp() override + { + iox_runtime_init(runtimeName.c_str()); + sut = iox_service_discovery_init(&sutStorage); + } + + void TearDown() override + { + iox_service_discovery_deinit(sut); + } + + std::string runtimeName = "runtime"; + iox_service_discovery_storage_t sutStorage; + iox_service_discovery_t sut; + + static cxx::vector searchResult; + static void findHandler(const iox_service_description_t s) + { + searchResult.emplace_back(s); + } +}; + +cxx::vector iox_service_discovery_test::searchResult; + + +TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventsReturnsAllServices) +{ + iox_service_discovery_find_service(sut, nullptr, nullptr, nullptr, findHandler); + for (const auto& service : searchResult) + { + EXPECT_THAT(service.instanceString, StrEq("RouDi_ID")); + } +} + +} // namespace diff --git a/iceoryx_binding_c/test/moduletests/test_types.cpp b/iceoryx_binding_c/test/moduletests/test_types.cpp index 5e755e6627..b49f647873 100644 --- a/iceoryx_binding_c/test/moduletests/test_types.cpp +++ b/iceoryx_binding_c/test/moduletests/test_types.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved. -// Copyright (c) 2020 - 2021 Apex.AI Inc. All rights reserved. +// Copyright (c) 2020 - 2022 Apex.AI Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,10 +22,12 @@ #include "iceoryx_posh/popo/untyped_server.hpp" #include "iceoryx_posh/popo/user_trigger.hpp" #include "iceoryx_posh/popo/wait_set.hpp" +#include "iceoryx_posh/runtime/service_discovery.hpp" using namespace iox; using namespace iox::popo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/types.h" @@ -86,4 +88,10 @@ TEST(iox_types_test, ServerStorageSizeFits) EXPECT_THAT(alignof(UntypedServer), Le(alignof(iox_server_storage_t))); } +TEST(iox_types_test, ServiceDiscoveryStorageSizeFits) +{ + ::testing::Test::RecordProperty("TEST_ID", "8fd3af84-ca73-4e38-a061-5e4638f48b77"); + EXPECT_THAT(sizeof(ServiceDiscovery), Le(sizeof(iox_service_discovery_storage_t))); + EXPECT_THAT(alignof(ServiceDiscovery), Le(alignof(iox_service_discovery_storage_t))); +} } // namespace From 7c7fe100140db990dfd35d543701900a0441caeb Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Tue, 22 Feb 2022 11:47:23 +0100 Subject: [PATCH 02/14] iox-#1142 Add functional find service test Signed-off-by: Marika Lehmann --- .../moduletests/test_service_discovery.cpp | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index abc982bbe5..f11dc957e2 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -21,6 +21,7 @@ using namespace iox; using namespace iox::runtime; extern "C" { +#include "iceoryx_binding_c/publisher.h" #include "iceoryx_binding_c/runtime.h" #include "iceoryx_binding_c/service_discovery.h" } @@ -34,16 +35,16 @@ class iox_service_discovery_test : public RouDi_GTest public: void SetUp() override { - iox_runtime_init(runtimeName.c_str()); + iox_runtime_init("runtime"); sut = iox_service_discovery_init(&sutStorage); } void TearDown() override { + searchResult.clear(); iox_service_discovery_deinit(sut); } - std::string runtimeName = "runtime"; iox_service_discovery_storage_t sutStorage; iox_service_discovery_t sut; @@ -56,9 +57,17 @@ class iox_service_discovery_test : public RouDi_GTest cxx::vector iox_service_discovery_test::searchResult; +TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageTerminates) +{ + ::testing::Test::RecordProperty("TEST_ID", "be551a9e-7dcf-406a-a74c-7dcb1ee16c30"); + EXPECT_DEATH({ iox_service_discovery_init(nullptr); }, ".*"); +} +/// @note We test only if the arguments of iox_service_discovery_find_service are correctly passed to +/// ServiceDiscovery::findService. TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventsReturnsAllServices) { + ::testing::Test::RecordProperty("TEST_ID", "09a2cd6c-fba9-4b9d-af96-c5a6cc168d98"); iox_service_discovery_find_service(sut, nullptr, nullptr, nullptr, findHandler); for (const auto& service : searchResult) { @@ -66,4 +75,25 @@ TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEven } } +TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) +{ + ::testing::Test::RecordProperty("TEST_ID", "bb12e514-e7af-4946-b098-98b3cd0f43a5"); + iox_pub_options_t options; + iox_pub_options_init(&options); + iox_pub_storage_t storage; + auto* publisher = iox_pub_init(&storage, "service", "instance", "event", &options); + ASSERT_NE(publisher, nullptr); + const iox_service_description_t SERVICE_DESCRIPTION = iox_pub_get_service_description(publisher); + + iox_service_discovery_find_service(sut, + SERVICE_DESCRIPTION.serviceString, + SERVICE_DESCRIPTION.instanceString, + SERVICE_DESCRIPTION.eventString, + findHandler); + ASSERT_THAT(searchResult.size(), Eq(1U)); + EXPECT_THAT(*searchResult.begin()->serviceString, Eq(*SERVICE_DESCRIPTION.serviceString)); + EXPECT_THAT(*searchResult.begin()->instanceString, Eq(*SERVICE_DESCRIPTION.instanceString)); + EXPECT_THAT(*searchResult.begin()->eventString, Eq(*SERVICE_DESCRIPTION.eventString)); +} + } // namespace From 075f6b288056a5b65e2c7d8270ed007102d8e349 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Tue, 22 Feb 2022 18:36:19 +0100 Subject: [PATCH 03/14] iox-#1142 Add find service function that stores result Signed-off-by: Marika Lehmann --- .../iceoryx_binding_c/service_discovery.h | 42 +++++++--- .../source/c_service_discovery.cpp | 57 +++++++++++-- .../moduletests/test_service_discovery.cpp | 81 ++++++++++++++++--- 3 files changed, 150 insertions(+), 30 deletions(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h index c585db0b87..f4fd8bca0a 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h @@ -21,29 +21,47 @@ #include "iceoryx_binding_c/types.h" #include "service_description.h" -/////// @brief service discovery handle -////// typedef struct cpp2c_ServiceDiscovery* iox_service_discovery_t; +/// @brief service discovery handle typedef CLASS ServiceDiscovery* iox_service_discovery_t; -///// @brief initializes a listener struct from a storage struct pointer -///// @param[in] self pointer to raw memory which can hold a listener -///// @return an initialized iox_listener_t +/// @brief initializes a service discovery from a storage struct pointer +/// @param[in] self pointer to raw memory which can hold a service discovery +/// @return an initialized iox_service_discovery_t iox_service_discovery_t iox_service_discovery_init(iox_service_discovery_storage_t* self); -///// @brief after using an iox_listener_t it must be cleaned up with this function -///// @param[in] self the listener which should be deinitialized +/// @brief after using an iox_service_discovery_t it must be cleaned up with this function +/// @param[in] self the service discovery which should be deinitialized void iox_service_discovery_deinit(iox_service_discovery_t const self); +/// @brief Searches all services that match the provided service description +/// @param[in] self handle of the service discovery +/// @param[in] service service string to search for, a nullptr corresponds to a wildcard +/// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard +/// @param[in] event event string to search for, a nullptr corresponds to a wildcard +/// @param[in] serviceContainer preallocated memory to an array of ***** in which the matching services can be written +/// @param[in] serviceContainerCapacity the capacity of the preallocated serviceContainer +/// @param[in] missedServices if the serviceContainer has insufficient size the number of missed services which could +/// not be written into the serviceContainer are stored here +/// @return the number of services which were written into the serviceContainer +uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + iox_service_description_t* const serviceContainer, + const uint64_t serviceContainerCapacity, + uint64_t* missedServices); + /// @brief Searches all services that match the provided service description and applies a function to each of them /// @param[in] self handle of the service discovery /// @param[in] service service string to search for, a nullptr corresponds to a wildcard /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard /// @param[in] event event string to search for, a nullptr corresponds to a wildcard /// @param[in] callable to apply to all matching services -void iox_service_discovery_find_service(iox_service_discovery_t const self, - const char* const service, - const char* const instance, - const char* const event, - void (*callable)(const iox_service_description_t)); +void iox_service_discovery_find_service_with_context_data(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t, void*), + void* const contextData); #endif diff --git a/iceoryx_binding_c/source/c_service_discovery.cpp b/iceoryx_binding_c/source/c_service_discovery.cpp index 76df4680d6..6009922014 100644 --- a/iceoryx_binding_c/source/c_service_discovery.cpp +++ b/iceoryx_binding_c/source/c_service_discovery.cpp @@ -41,11 +41,56 @@ void iox_service_discovery_deinit(iox_service_discovery_t const self) self->~ServiceDiscovery(); } -void iox_service_discovery_find_service(iox_service_discovery_t const self, - const char* const service, - const char* const instance, - const char* const event, - void (*callable)(const iox_service_description_t)) +uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + iox_service_description_t* const serviceContainer, + const uint64_t serviceContainerCapacity, + uint64_t* missedServices) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceContainer != nullptr); + + cxx::optional maybeService; + if (service != nullptr) + { + maybeService.emplace(cxx::TruncateToCapacity, service); + } + cxx::optional maybeInstance; + if (instance != nullptr) + { + maybeInstance.emplace(cxx::TruncateToCapacity, instance); + } + cxx::optional maybeEvent; + if (event != nullptr) + { + maybeEvent.emplace(cxx::TruncateToCapacity, event); + } + + uint64_t currentSize = 0U; + auto filter = [&](const capro::ServiceDescription& s) { + if (currentSize + 1U <= serviceContainerCapacity) + { + serviceContainer[currentSize] = TranslateServiceDescription(s); + ++currentSize; + } + else + { + ++(*missedServices); + } + }; + self->findService(maybeService, maybeInstance, maybeEvent, filter, iox::popo::MessagingPattern::PUB_SUB); + + return currentSize; +} + +void iox_service_discovery_find_service_with_context_data(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t, void*), + void* const contextData) { iox::cxx::Expects(self != nullptr); iox::cxx::Expects(callable != nullptr); @@ -66,6 +111,6 @@ void iox_service_discovery_find_service(iox_service_discovery_t const self, maybeEvent.emplace(cxx::TruncateToCapacity, event); } - auto filter = [&](const capro::ServiceDescription& s) { callable(TranslateServiceDescription(s)); }; + auto filter = [&](const capro::ServiceDescription& s) { callable(TranslateServiceDescription(s), contextData); }; self->findService(maybeService, maybeInstance, maybeEvent, filter, iox::popo::MessagingPattern::PUB_SUB); } diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index f11dc957e2..d2ecfec8ae 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -29,6 +29,7 @@ extern "C" { namespace { using namespace ::testing; +using description_vector = cxx::vector; class iox_service_discovery_test : public RouDi_GTest { @@ -48,14 +49,14 @@ class iox_service_discovery_test : public RouDi_GTest iox_service_discovery_storage_t sutStorage; iox_service_discovery_t sut; - static cxx::vector searchResult; - static void findHandler(const iox_service_description_t s) + static description_vector searchResult; + static void findHandler(const iox_service_description_t s, void* contextData) { - searchResult.emplace_back(s); + static_cast(contextData)->emplace_back(s); } }; -cxx::vector iox_service_discovery_test::searchResult; +description_vector iox_service_discovery_test::searchResult; TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageTerminates) { @@ -65,17 +66,17 @@ TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageT /// @note We test only if the arguments of iox_service_discovery_find_service are correctly passed to /// ServiceDiscovery::findService. -TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventsReturnsAllServices) +TEST_F(iox_service_discovery_test, FindServiceWithContextDataWithNullptrsForServiceInstanceEventReturnsAllServices) { ::testing::Test::RecordProperty("TEST_ID", "09a2cd6c-fba9-4b9d-af96-c5a6cc168d98"); - iox_service_discovery_find_service(sut, nullptr, nullptr, nullptr, findHandler); + iox_service_discovery_find_service_with_context_data(sut, nullptr, nullptr, nullptr, findHandler, &searchResult); for (const auto& service : searchResult) { EXPECT_THAT(service.instanceString, StrEq("RouDi_ID")); } } -TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) +TEST_F(iox_service_discovery_test, FindServiceWithContextDataReturnsOfferedService) { ::testing::Test::RecordProperty("TEST_ID", "bb12e514-e7af-4946-b098-98b3cd0f43a5"); iox_pub_options_t options; @@ -85,15 +86,71 @@ TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) ASSERT_NE(publisher, nullptr); const iox_service_description_t SERVICE_DESCRIPTION = iox_pub_get_service_description(publisher); - iox_service_discovery_find_service(sut, - SERVICE_DESCRIPTION.serviceString, - SERVICE_DESCRIPTION.instanceString, - SERVICE_DESCRIPTION.eventString, - findHandler); + iox_service_discovery_find_service_with_context_data(sut, + SERVICE_DESCRIPTION.serviceString, + SERVICE_DESCRIPTION.instanceString, + SERVICE_DESCRIPTION.eventString, + findHandler, + &searchResult); ASSERT_THAT(searchResult.size(), Eq(1U)); EXPECT_THAT(*searchResult.begin()->serviceString, Eq(*SERVICE_DESCRIPTION.serviceString)); EXPECT_THAT(*searchResult.begin()->instanceString, Eq(*SERVICE_DESCRIPTION.instanceString)); EXPECT_THAT(*searchResult.begin()->eventString, Eq(*SERVICE_DESCRIPTION.eventString)); } +TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventReturnsAllServices) +{ + const uint64_t SERVICE_CONTAINER_CAPACITY = 10U; + iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; + uint64_t missedServices = 0U; + const auto numberFoundServices = iox_service_discovery_find_service( + sut, nullptr, nullptr, nullptr, serviceContainer, SERVICE_CONTAINER_CAPACITY, &missedServices); + + EXPECT_THAT(numberFoundServices, Eq(6U)); + EXPECT_THAT(missedServices, Eq(0U)); + for (uint64_t i = 0U; i < numberFoundServices; ++i) + { + EXPECT_THAT(serviceContainer[i].instanceString, StrEq("RouDi_ID")); + } +} + +TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) +{ + iox_pub_options_t options; + iox_pub_options_init(&options); + iox_pub_storage_t storage; + auto* publisher = iox_pub_init(&storage, "service", "instance", "event", &options); + ASSERT_NE(publisher, nullptr); + const iox_service_description_t SERVICE_DESCRIPTION = iox_pub_get_service_description(publisher); + + const uint64_t SERVICE_CONTAINER_CAPACITY = 10U; + iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; + uint64_t missedServices = 0U; + const auto numberFoundServices = iox_service_discovery_find_service(sut, + SERVICE_DESCRIPTION.serviceString, + SERVICE_DESCRIPTION.instanceString, + SERVICE_DESCRIPTION.eventString, + serviceContainer, + SERVICE_CONTAINER_CAPACITY, + &missedServices); + + EXPECT_THAT(numberFoundServices, Eq(1U)); + EXPECT_THAT(missedServices, Eq(0U)); + EXPECT_THAT(serviceContainer[0U].serviceString, StrEq(SERVICE_DESCRIPTION.serviceString)); + EXPECT_THAT(serviceContainer[0U].instanceString, StrEq(SERVICE_DESCRIPTION.instanceString)); + EXPECT_THAT(serviceContainer[0U].eventString, StrEq(SERVICE_DESCRIPTION.eventString)); +} + +TEST_F(iox_service_discovery_test, FindServiceReturnsCorrectNumberOfServicesWhenServiceContainerTooSmall) +{ + const uint64_t SERVICE_CONTAINER_CAPACITY = 3U; + iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; + uint64_t missedServices = 0U; + const auto numberFoundServices = iox_service_discovery_find_service( + sut, nullptr, nullptr, nullptr, serviceContainer, SERVICE_CONTAINER_CAPACITY, &missedServices); + + EXPECT_THAT(numberFoundServices, Eq(SERVICE_CONTAINER_CAPACITY)); + EXPECT_THAT(missedServices, Eq(6U - SERVICE_CONTAINER_CAPACITY)); +} + } // namespace From 9a4f189adec1057ea5b5b333d65c5abb45085a7b Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Tue, 22 Feb 2022 19:53:42 +0100 Subject: [PATCH 04/14] iox-#1142 Add attach and detach functions to listener Signed-off-by: Marika Lehmann --- .../include/iceoryx_binding_c/enums.h | 6 +++ .../internal/c2cpp_enum_translation.hpp | 3 ++ .../include/iceoryx_binding_c/listener.h | 37 ++++++++++++++ .../source/c2cpp_enum_translation.cpp | 14 ++++++ iceoryx_binding_c/source/c_listener.cpp | 49 +++++++++++++++++++ .../test_c2cpp_enum_translation.cpp | 39 +++++++++++++++ .../moduletests/test_service_discovery.cpp | 3 ++ .../error_handling/error_handling.hpp | 1 + 8 files changed, 152 insertions(+) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/enums.h b/iceoryx_binding_c/include/iceoryx_binding_c/enums.h index 010c3f24a8..2725292e6b 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/enums.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/enums.h @@ -84,6 +84,12 @@ enum iox_ChunkReceiveResult ChunkReceiveResult_SUCCESS, }; +/// @brief describes events which can be triggered by a service discovery +enum iox_ServiceDiscoveryEvent +{ + ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED +}; + /// @brief Used by consumers to request a specific behavior from the producer; describes whether a producer blocks when /// consumer queue is full enum iox_QueueFullPolicy diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp b/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp index 64aacdcd5e..fba18f4c99 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp +++ b/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp @@ -21,6 +21,7 @@ #include "iceoryx_binding_c/enums.h" #include "iceoryx_posh/popo/base_subscriber.hpp" #include "iceoryx_posh/popo/subscriber.hpp" +#include "iceoryx_posh/runtime/service_discovery.hpp" namespace c2cpp { @@ -33,6 +34,8 @@ iox::popo::ClientEvent clientEvent(const iox_ClientEvent value) noexcept; iox::popo::ClientState clientState(const iox_ClientState value) noexcept; iox::popo::ServerEvent serverEvent(const iox_ServerEvent value) noexcept; iox::popo::ServerState serverState(const iox_ServerState value) noexcept; + +iox::runtime::ServiceDiscoveryEvent serviceDiscoveryEvent(const iox_ServiceDiscoveryEvent value) noexcept; } // namespace c2cpp #endif diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/listener.h b/iceoryx_binding_c/include/iceoryx_binding_c/listener.h index f427198a64..6aca47663d 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/listener.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/listener.h @@ -21,6 +21,7 @@ #include "iceoryx_binding_c/enums.h" #include "iceoryx_binding_c/internal/c2cpp_binding.h" #include "iceoryx_binding_c/server.h" +#include "iceoryx_binding_c/service_discovery.h" #include "iceoryx_binding_c/subscriber.h" #include "iceoryx_binding_c/types.h" #include "iceoryx_binding_c/user_trigger.h" @@ -174,4 +175,40 @@ ENUM iox_ListenerResult iox_listener_attach_server_event_with_context_data(iox_l void iox_listener_detach_server_event(iox_listener_t const self, iox_server_t const server, const ENUM iox_ServerEvent serverEvent); + +/// @brief Attaches a service discovery event to the listener +/// @param[in] self listener to which the event should be attached to +/// @param[in] serviceDiscovery service discovery which emits the event +/// @param[in] serviceDiscoveryEvent the event which should trigger the listener +/// @param[in] callback the callback which is called when an event triggers the listener +/// @return when successful iox_ListenerResult::ListenerResult_SUCCESS otherwise an enum which describes the error +ENUM iox_ListenerResult +iox_listener_attach_service_discovery_event(iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + void (*callback)(iox_service_discovery_t)); + +/// @brief Attaches a service discovery event to the listener. The callback has an additional contextData argument to +/// provide access to user defined data. +/// @param[in] self listener to which the event should be attached to +/// @param[in] serviceDiscovery service discovery which emits the event +/// @param[in] serviceDiscoveryEvent the event which should trigger the listener +/// @param[in] callback the callback which is called when an event triggers the listener +/// @param[in] contextData a void pointer which is provided as second argument to the callback +/// @return when successful iox_ListenerResult::ListenerResult_SUCCESS otherwise an enum which describes the error +ENUM iox_ListenerResult iox_listener_attach_service_discovery_event_with_context_data( + iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + void (*callback)(iox_service_discovery_t, void*), + void* const contextData); + +/// @brief Detaches a service discovery event from the listener +/// @param[in] self listener from which the event should be detached +/// @param[in] serviceDiscovery the service discovery which emits the event +/// @param[in] serviceDiscoveryEvent the service discovery event which should be removed from the listener +void iox_listener_detach_service_discovery_event(iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent); + #endif diff --git a/iceoryx_binding_c/source/c2cpp_enum_translation.cpp b/iceoryx_binding_c/source/c2cpp_enum_translation.cpp index 97b2a38f59..beaca9aa78 100644 --- a/iceoryx_binding_c/source/c2cpp_enum_translation.cpp +++ b/iceoryx_binding_c/source/c2cpp_enum_translation.cpp @@ -126,4 +126,18 @@ iox::popo::ServerState serverState(const iox_ServerState value) noexcept errorHandler(iox::Error::kBINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVER_STATE_VALUE); return iox::popo::ServerState::HAS_REQUEST; } + +iox::runtime::ServiceDiscoveryEvent serviceDiscoveryEvent(const iox_ServiceDiscoveryEvent value) noexcept +{ + switch (value) + { + case ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED: + return iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED; + } + + iox::LogFatal() << "invalid iox_ServiceDiscoveryEvent value"; + errorHandler(iox::Error::kBINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVICE_DISCOVERY_EVENT_VALUE); + return iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED; +} + } // namespace c2cpp diff --git a/iceoryx_binding_c/source/c_listener.cpp b/iceoryx_binding_c/source/c_listener.cpp index b489dc1173..48f24b950f 100644 --- a/iceoryx_binding_c/source/c_listener.cpp +++ b/iceoryx_binding_c/source/c_listener.cpp @@ -26,6 +26,7 @@ using namespace iox; using namespace iox::popo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/listener.h" @@ -251,3 +252,51 @@ void iox_listener_detach_server_event(iox_listener_t const self, self->detachEvent(*server, c2cpp::serverEvent(serverEvent)); } + +iox_ListenerResult +iox_listener_attach_service_discovery_event(iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + void (*callback)(iox_service_discovery_t)) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + iox::cxx::Expects(callback != nullptr); + + auto result = self->attachEvent(*serviceDiscovery, + c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent), + NotificationCallback{callback, nullptr}); + + return (result.has_error()) ? cpp2c::listenerResult(result.get_error()) + : iox_ListenerResult::ListenerResult_SUCCESS; +} + +iox_ListenerResult iox_listener_attach_service_discovery_event_with_context_data( + iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + void (*callback)(iox_service_discovery_t, void*), + void* const contextData) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + iox::cxx::Expects(callback != nullptr); + iox::cxx::Expects(contextData != nullptr); + + auto result = self->attachEvent(*serviceDiscovery, + c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent), + NotificationCallback{callback, contextData}); + + return (result.has_error()) ? cpp2c::listenerResult(result.get_error()) + : iox_ListenerResult::ListenerResult_SUCCESS; +} + +void iox_listener_detach_service_discovery_event(iox_listener_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + + self->detachEvent(*serviceDiscovery, c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent)); +} diff --git a/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp b/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp index d139d54461..b2d10c2792 100644 --- a/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp +++ b/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp @@ -327,4 +327,43 @@ TEST(c2cpp_enum_translation_test, ServerEvent) #endif #pragma GCC diagnostic pop } + +TEST(c2cpp_enum_translation_test, ServiceDiscoveryEvent) +{ + ::testing::Test::RecordProperty("TEST_ID", "9eb978fa-8fa9-452f-b0e3-cb26c0cecfbf"); + constexpr EnumMapping EVENTS[]{ + {iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED, + ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED}}; + + for (const auto event : EVENTS) + { + switch (event.cpp) + { + case iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED: + EXPECT_EQ(c2cpp::serviceDiscoveryEvent(event.c), event.cpp); + break; + // default intentionally left out in order to get a compiler warning if the enum gets extended and we forgot + // to extend the test + } + } + + // ignore the warning since we would like to test the behavior of an invalid enum value +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +// ignored for now since the undefined behavior sanitizer correctly detects the undefined behavior +// which is tested and handled here +// explicitly commented out since we are testing undefined behavior here and that we +// return the default value SERVICE_REGISTRY_CHANGED always in the undefined behavior case +// the clang sanitizer detects this successfully and this leads to termination, and with this the test fails +#if !defined(__clang__) + iox::Error errorValue = iox::Error::kNO_ERROR; + auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler( + [&](const iox::Error e, const std::function, const iox::ErrorLevel) { errorValue = e; }); + EXPECT_EQ(c2cpp::serviceDiscoveryEvent(static_cast(-1)), + iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED); + EXPECT_THAT(errorValue, Eq(iox::Error::kBINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVICE_DISCOVERY_EVENT_VALUE)); +#endif +#pragma GCC diagnostic pop +} + } // namespace diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index d2ecfec8ae..1f71d6ca52 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -100,6 +100,7 @@ TEST_F(iox_service_discovery_test, FindServiceWithContextDataReturnsOfferedServi TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventReturnsAllServices) { + ::testing::Test::RecordProperty("TEST_ID", "75b411d7-b8c7-42d5-8acd-3916fd172081"); const uint64_t SERVICE_CONTAINER_CAPACITY = 10U; iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; uint64_t missedServices = 0U; @@ -116,6 +117,7 @@ TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEven TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) { + ::testing::Test::RecordProperty("TEST_ID", "4bbd0b26-ed9d-4fcd-ae85-e7ea3783996d"); iox_pub_options_t options; iox_pub_options_init(&options); iox_pub_storage_t storage; @@ -143,6 +145,7 @@ TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) TEST_F(iox_service_discovery_test, FindServiceReturnsCorrectNumberOfServicesWhenServiceContainerTooSmall) { + ::testing::Test::RecordProperty("TEST_ID", "01047b88-f257-447c-8c5e-9bef7c358433"); const uint64_t SERVICE_CONTAINER_CAPACITY = 3U; iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; uint64_t missedServices = 0U; diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp index 6a75a92bab..544295852a 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp @@ -195,6 +195,7 @@ namespace iox error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_CLIENT_STATE_VALUE) \ error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVER_EVENT_VALUE) \ error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVER_STATE_VALUE) \ + error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVICE_DISCOVERY_EVENT_VALUE) \ error(EXPECTS_ENSURES_FAILED) // EXPECTS_ENSURES_FAILED is used as a temporary solution to make Expects/Ensures testable From 768a6f7a3cd8beff3d3a7c38dd92b10750e3a894 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Tue, 22 Feb 2022 21:49:08 +0100 Subject: [PATCH 05/14] iox-#1142 Add listener tests Signed-off-by: Marika Lehmann --- .../test/moduletests/test_listener.cpp | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/iceoryx_binding_c/test/moduletests/test_listener.cpp b/iceoryx_binding_c/test/moduletests/test_listener.cpp index 400f1dcbd4..65855c6d64 100644 --- a/iceoryx_binding_c/test/moduletests/test_listener.cpp +++ b/iceoryx_binding_c/test/moduletests/test_listener.cpp @@ -52,6 +52,7 @@ iox_user_trigger_t g_userTriggerCallbackArgument = nullptr; iox_sub_t g_subscriberCallbackArgument = nullptr; iox_client_t g_clientCallbackArgument = nullptr; iox_server_t g_serverCallbackArgument = nullptr; +iox_service_discovery_t g_serviceDiscoveryCallbackArgument = nullptr; void* g_contextData = nullptr; void userTriggerCallback(iox_user_trigger_t userTrigger) @@ -98,6 +99,17 @@ void serverCallbackWithContextData(iox_server_t server, void* const contextData) g_contextData = contextData; } +void serviceDiscoveryCallback(iox_service_discovery_t serviceDiscovery) +{ + g_serviceDiscoveryCallbackArgument = serviceDiscovery; +} + +void serviceDiscoveryCallbackWithContextData(iox_service_discovery_t serviceDiscovery, void* const contextData) +{ + g_serviceDiscoveryCallbackArgument = serviceDiscovery; + g_contextData = contextData; +} + class iox_listener_test : public Test { public: @@ -544,4 +556,88 @@ TIMING_TEST_F(iox_listener_test, NotifyingServerEventWithContextDataWorks, Repea /// END server tests ////////////////////// +TEST_F(iox_listener_test, AttachingServiceDiscoveryWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "75fd4e6f-ee2f-4e28-a2d8-8a0f01dbd91c"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_subscriberPortData[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); + iox_listener_attach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, &serviceDiscoveryCallback); + EXPECT_THAT(iox_listener_size(&m_sut), Eq(1)); + + iox_listener_detach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); +} + +TEST_F(iox_listener_test, AttachingServiceDiscoveryWithContextDataWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "2d7cbe60-bda1-4191-b2d5-d67c47312a48"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_subscriberPortData[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); + iox_listener_attach_service_discovery_event_with_context_data(&m_sut, + serviceDiscovery, + ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, + &serviceDiscoveryCallbackWithContextData, + &serviceDiscoveryStorage); + EXPECT_THAT(iox_listener_size(&m_sut), Eq(1)); + + iox_listener_detach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); +} + +void notifyServiceDiscovery(SubscriberPortData& portData) +{ + ConditionNotifier(*portData.m_chunkReceiverData.m_conditionVariableDataPtr, 0).notify(); +} + +TIMING_TEST_F(iox_listener_test, NotifyingServiceDiscoveryEventWorks, Repeat(5), [&] { + ::testing::Test::RecordProperty("TEST_ID", "538a50bc-60c8-4485-b70e-59d0c53f618b"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_subscriberPortData[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + iox_listener_attach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, &serviceDiscoveryCallback); + + notifyServiceDiscovery(m_subscriberPortData[0]); + std::this_thread::sleep_for(TIMEOUT); + TIMING_TEST_EXPECT_TRUE(g_serviceDiscoveryCallbackArgument == serviceDiscovery); + + iox_listener_detach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); +}); + +TIMING_TEST_F(iox_listener_test, NotifyingServiceDiscoveryEventWithContextDataWorks, Repeat(5), [&] { + ::testing::Test::RecordProperty("TEST_ID", "257c27a5-95c6-489d-919f-125471b399e8"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_subscriberPortData[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + iox_listener_attach_service_discovery_event_with_context_data(&m_sut, + serviceDiscovery, + ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, + &serviceDiscoveryCallbackWithContextData, + &serviceDiscoveryStorage); + + notifyServiceDiscovery(m_subscriberPortData[0]); + std::this_thread::sleep_for(TIMEOUT); + TIMING_TEST_EXPECT_TRUE(g_serviceDiscoveryCallbackArgument == serviceDiscovery); + TIMING_TEST_EXPECT_TRUE(g_contextData == static_cast(&serviceDiscoveryStorage)); + + iox_listener_detach_service_discovery_event( + &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); +}); + } // namespace From 59e432608d106025bb475917f1f443c3ca133678 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Wed, 23 Feb 2022 15:04:47 +0100 Subject: [PATCH 06/14] iox-#1142 Add missing functions to waitset and notification_info Signed-off-by: Marika Lehmann --- .../iceoryx_binding_c/notification_info.h | 13 ++ .../include/iceoryx_binding_c/wait_set.h | 41 +++++++ .../source/c_notification_info.cpp | 13 ++ iceoryx_binding_c/source/c_wait_set.cpp | 45 +++++++ .../test/moduletests/test_wait_set.cpp | 112 +++++++++++++++++- 5 files changed, 223 insertions(+), 1 deletion(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/notification_info.h b/iceoryx_binding_c/include/iceoryx_binding_c/notification_info.h index 221f218c3d..9ad8a80735 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/notification_info.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/notification_info.h @@ -20,6 +20,7 @@ #include "iceoryx_binding_c/client.h" #include "iceoryx_binding_c/internal/c2cpp_binding.h" #include "iceoryx_binding_c/server.h" +#include "iceoryx_binding_c/service_discovery.h" #include "iceoryx_binding_c/subscriber.h" #include "iceoryx_binding_c/user_trigger.h" @@ -57,6 +58,13 @@ bool iox_notification_info_does_originate_from_client(iox_notification_info_t co /// @return true if the notification originates from the server, otherwise false bool iox_notification_info_does_originate_from_server(iox_notification_info_t const self, iox_server_t const server); +/// @brief does the notification originate from a certain service discovery +/// @param[in] self handle to notification info +/// @param[in] serviceDiscovery handle to serviceDiscovery in question +/// @return true if the notifiaction originates from the service discovery, otherwise false +bool iox_notification_info_does_originate_from_service_discovery(iox_notification_info_t const self, + iox_service_discovery_t const serviceDiscovery); + /// @brief acquires the handle of the subscriber origin /// @param[in] self handle to notification info /// @return the handle to the subscriber if the notification originated from a subscriber, otherwise NULL @@ -77,6 +85,11 @@ iox_client_t iox_notification_info_get_client_origin(iox_notification_info_t con /// @return the handle to the server if the notification originated from a server, otherwise NULL iox_server_t iox_notification_info_get_server_origin(iox_notification_info_t const self); +/// @brief acquires the handle of the service discovery origin +/// @param[in] self handle to the notification info +/// @return the handle to the service discovery if the notification originated from a service discovery, otherwise NULL +iox_service_discovery_t iox_notification_info_get_service_discovery_origin(iox_notification_info_t const self); + /// @brief calls the callback of the notification /// @param[in] self handle to notification info void iox_notification_info_call(iox_notification_info_t const self); diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/wait_set.h b/iceoryx_binding_c/include/iceoryx_binding_c/wait_set.h index e687c09948..3624235d40 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/wait_set.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/wait_set.h @@ -22,6 +22,7 @@ #include "iceoryx_binding_c/enums.h" #include "iceoryx_binding_c/internal/c2cpp_binding.h" #include "iceoryx_binding_c/notification_info.h" +#include "iceoryx_binding_c/service_discovery.h" #include "iceoryx_binding_c/subscriber.h" #include "iceoryx_binding_c/types.h" #include "iceoryx_binding_c/user_trigger.h" @@ -333,4 +334,44 @@ void iox_ws_detach_server_event(iox_ws_t const self, iox_server_t const server, /// @param[in] server the server which should be detached /// @param[in] serverState the state which should be detached from the server void iox_ws_detach_server_state(iox_ws_t const self, iox_server_t const server, const ENUM iox_ServerState serverState); + +/// @brief attaches a service discovery event to a waitset +/// @param[in] self handle to the waitset +/// @param[in] serviceDiscovery service discovery which emits the event +/// @param[in] serviceDiscoveryEvent the event which should be attached +/// @param[in] eventId an arbitrary id which will be tagged to the event +/// @param[in] callback a callback which is attached to the event +/// @return if the attaching was successfull it returns WaitSetResult_SUCCESS, otherwise +/// an enum which describes the error +ENUM iox_WaitSetResult iox_ws_attach_service_discovery_event(const iox_ws_t self, + const iox_service_discovery_t serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + const uint64_t eventId, + void (*callback)(iox_service_discovery_t)); + +/// @brief attaches a service discovery event to a waitset with additional context data for the callback +/// @param[in] self handle to the waitset +/// @param[in] serviceDiscovery service discovery which emits the event +/// @param[in] serviceDiscoveryEvent the event which should be attached +/// @param[in] eventId an arbitrary id which will be tagged to the event +/// @param[in] callback a callback which is attached to the event +/// @param[in] contextData a void pointer which is provided as second argument to the callback +/// @return if the attaching was successfull it returns WaitSetResult_SUCCESS, otherwise +/// an enum which describes the error +ENUM iox_WaitSetResult +iox_ws_attach_service_discovery_event_with_context_data(iox_ws_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + const uint64_t eventId, + void (*callback)(iox_service_discovery_t, void*), + void* const contextData); + +/// @brief detaches a service discovery event from a waitset +/// @param[in] self handle to the waitset +/// @param[in] serviceDiscovery the service discovery which should be detached +/// @param[in] serviceDiscoveryEvent the event which should be detached from the service discovery +void iox_ws_detach_service_discovery_event(iox_ws_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent); + #endif diff --git a/iceoryx_binding_c/source/c_notification_info.cpp b/iceoryx_binding_c/source/c_notification_info.cpp index 7f605ca3ef..29d2143c85 100644 --- a/iceoryx_binding_c/source/c_notification_info.cpp +++ b/iceoryx_binding_c/source/c_notification_info.cpp @@ -19,9 +19,11 @@ #include "iceoryx_posh/popo/untyped_client.hpp" #include "iceoryx_posh/popo/untyped_server.hpp" #include "iceoryx_posh/popo/user_trigger.hpp" +#include "iceoryx_posh/runtime/service_discovery.hpp" using namespace iox; using namespace iox::popo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/notification_info.h" @@ -56,6 +58,12 @@ bool iox_notification_info_does_originate_from_server(iox_notification_info_t co return self->doesOriginateFrom(server); } +bool iox_notification_info_does_originate_from_service_discovery(iox_notification_info_t const self, + iox_service_discovery_t const serviceDiscovery) +{ + return self->doesOriginateFrom(serviceDiscovery); +} + iox_sub_t iox_notification_info_get_subscriber_origin(iox_notification_info_t const self) { return self->getOrigin(); @@ -76,6 +84,11 @@ iox_server_t iox_notification_info_get_server_origin(iox_notification_info_t con return self->getOrigin(); } +iox_service_discovery_t iox_notification_info_get_service_discovery_origin(iox_notification_info_t const self) +{ + return self->getOrigin(); +} + void iox_notification_info_call(iox_notification_info_t const self) { (*self)(); diff --git a/iceoryx_binding_c/source/c_wait_set.cpp b/iceoryx_binding_c/source/c_wait_set.cpp index 9b2db6d61d..906452c460 100644 --- a/iceoryx_binding_c/source/c_wait_set.cpp +++ b/iceoryx_binding_c/source/c_wait_set.cpp @@ -29,6 +29,7 @@ using namespace iox; using namespace iox::popo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/wait_set.h" @@ -395,3 +396,47 @@ void iox_ws_detach_server_state(iox_ws_t const self, iox_server_t const server, self->detachState(*server, c2cpp::serverState(serverState)); } + +iox_WaitSetResult iox_ws_attach_service_discovery_event(const iox_ws_t self, + const iox_service_discovery_t serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + const uint64_t eventId, + void (*callback)(iox_service_discovery_t)) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + + auto result = self->attachEvent( + *serviceDiscovery, c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent), eventId, {callback, nullptr}); + return (result.has_error()) ? cpp2c::waitSetResult(result.get_error()) : iox_WaitSetResult::WaitSetResult_SUCCESS; +} + +iox_WaitSetResult +iox_ws_attach_service_discovery_event_with_context_data(iox_ws_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent, + const uint64_t eventId, + void (*callback)(iox_service_discovery_t, void*), + void* const contextData) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + + NotificationCallback, void> notificationCallback; + notificationCallback.m_callback = callback; + notificationCallback.m_contextData = contextData; + + auto result = self->attachEvent( + *serviceDiscovery, c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent), eventId, notificationCallback); + return (result.has_error()) ? cpp2c::waitSetResult(result.get_error()) : iox_WaitSetResult::WaitSetResult_SUCCESS; +} + +void iox_ws_detach_service_discovery_event(iox_ws_t const self, + iox_service_discovery_t const serviceDiscovery, + const ENUM iox_ServiceDiscoveryEvent serviceDiscoveryEvent) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(serviceDiscovery != nullptr); + + self->detachEvent(*serviceDiscovery, c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent)); +} diff --git a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp index 673fa378a3..4423cee455 100644 --- a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp +++ b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved. -// Copyright (c) 2021 by Apex.AI Inc. All rights reserved. +// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #include "iceoryx_posh/popo/untyped_client.hpp" #include "iceoryx_posh/popo/untyped_server.hpp" #include "iceoryx_posh/popo/user_trigger.hpp" +#include "iceoryx_posh/runtime/service_discovery.hpp" #include "iceoryx_posh/testing/mocks/posh_runtime_mock.hpp" #include "mocks/wait_set_mock.hpp" @@ -156,6 +157,18 @@ void serverCallbackWithContextData(iox::popo::UntypedServer* server, void* const iox_ws_test::m_callbackOrigin = server; iox_ws_test::m_contextData = contextData; } + +void serviceDiscoveryCallback(iox_service_discovery_t serviceDiscovery) +{ + iox_ws_test::m_callbackOrigin = serviceDiscovery; +} + +void serviceDiscoveryCallbackWithContextData(iox_service_discovery_t serviceDiscovery, void* const contextData) +{ + iox_ws_test::m_callbackOrigin = serviceDiscovery; + iox_ws_test::m_contextData = contextData; +} + } // namespace /// @todo iox-#1106 will be enabled when worked on this issue @@ -1053,4 +1066,101 @@ TEST_F(iox_ws_test, NotifyingServerStateWithContextDataWorks) /// END server tests //////////////////// +TEST_F(iox_ws_test, AttachingServiceDiscoveryEventWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "a8be9cbd-d9b6-45a3-b34f-d58fb864d40d"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); + iox_ws_attach_service_discovery_event( + m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, 0, nullptr); + EXPECT_THAT(iox_ws_size(m_sut), Eq(1)); + + iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); +} + +TEST_F(iox_ws_test, AttachingServiceDiscoveryEventWithContextDataWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "69515627-1590-4616-8502-975cd9256ecf"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); + iox_ws_attach_service_discovery_event_with_context_data( + m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, 0, nullptr, nullptr); + EXPECT_THAT(iox_ws_size(m_sut), Eq(1)); + + iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); +} + +void notifyServiceDiscovery(SubscriberPortData& portData) +{ + iox::popo::ChunkQueuePusher pusher{&portData.m_chunkReceiverData}; + pusher.push(iox::mepoo::SharedChunk()); + portData.m_chunkReceiverData.m_conditionVariableDataPtr->m_semaphore.post(); +} + +TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "945dcf94-4679-469f-aa47-1a87d536da72"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + iox_ws_attach_service_discovery_event( + m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, 13, &serviceDiscoveryCallback); + + notifyServiceDiscovery(m_portDataVector[0]); + + ASSERT_THAT(iox_ws_wait(m_sut, m_eventInfoStorage, MAX_NUMBER_OF_ATTACHMENTS_PER_WAITSET, &m_missedElements), + Eq(1)); + EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(13)); + EXPECT_THAT(iox_notification_info_get_service_discovery_origin(m_eventInfoStorage[0]), Eq(serviceDiscovery)); + EXPECT_TRUE(iox_notification_info_does_originate_from_service_discovery(m_eventInfoStorage[0], serviceDiscovery)); + iox_notification_info_call(m_eventInfoStorage[0]); + + EXPECT_THAT(m_callbackOrigin, Eq(static_cast(serviceDiscovery))); + EXPECT_THAT(m_contextData, Eq(nullptr)); + + iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); +} + +TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) +{ + ::testing::Test::RecordProperty("TEST_ID", "510a0351-afeb-4c0f-a4b6-3032f1f3f831"); + iox_service_discovery_storage_t serviceDiscoveryStorage; + EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); + + iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); + + iox_ws_attach_service_discovery_event_with_context_data(m_sut, + serviceDiscovery, + ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, + 31, + &serviceDiscoveryCallbackWithContextData, + &serviceDiscoveryStorage); + + notifyServiceDiscovery(m_portDataVector[0]); + + ASSERT_THAT(iox_ws_wait(m_sut, m_eventInfoStorage, MAX_NUMBER_OF_ATTACHMENTS_PER_WAITSET, &m_missedElements), + Eq(1)); + EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(31)); + EXPECT_THAT(iox_notification_info_get_service_discovery_origin(m_eventInfoStorage[0]), Eq(serviceDiscovery)); + EXPECT_TRUE(iox_notification_info_does_originate_from_service_discovery(m_eventInfoStorage[0], serviceDiscovery)); + iox_notification_info_call(m_eventInfoStorage[0]); + + EXPECT_THAT(m_callbackOrigin, Eq(static_cast(serviceDiscovery))); + EXPECT_THAT(m_contextData, Eq(static_cast(&serviceDiscoveryStorage))); + + iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); +} + } // namespace From 2709b0c98210a0f03797c11d5c71cd5a6a7eba30 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Wed, 23 Feb 2022 15:15:12 +0100 Subject: [PATCH 07/14] iox-#1142 Update changelog Signed-off-by: Marika Lehmann --- doc/website/release-notes/iceoryx-v2-0-0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/website/release-notes/iceoryx-v2-0-0.md b/doc/website/release-notes/iceoryx-v2-0-0.md index 96a538832a..543c449642 100644 --- a/doc/website/release-notes/iceoryx-v2-0-0.md +++ b/doc/website/release-notes/iceoryx-v2-0-0.md @@ -36,6 +36,7 @@ - Replace IPC-channel-based `findService` with pub/sub-based on [#415](https://github.com/eclipse-iceoryx/iceoryx/issues/415) - Add `findService` method to `ServiceDiscovery` which applies a callable to all matching services [\#1105](https://github.com/eclipse-iceoryx/iceoryx/pull/1105) - Increase limits of `ServiceRegistry` to support the maximum number of publishers and servers that are configured in `iceoryx_posh_types.hpp` [\#1074](https://github.com/eclipse-iceoryx/iceoryx/issues/1074) +- C binding for service discovery [\#1142](https://github.com/eclipse-iceoryx/iceoryx/issues/1142) **Bugfixes:** From d80c49a8ede0734138a7939dbcd26d2ede8783b2 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Wed, 23 Feb 2022 17:31:15 +0100 Subject: [PATCH 08/14] iox-#1142 Introduce MessagingPattern in C binding Signed-off-by: Marika Lehmann --- .../include/iceoryx_binding_c/enums.h | 7 ++++ .../internal/c2cpp_enum_translation.hpp | 1 + .../iceoryx_binding_c/service_discovery.h | 12 ++++-- .../source/c2cpp_enum_translation.cpp | 15 +++++++ .../source/c_service_discovery.cpp | 11 +++-- .../test_c2cpp_enum_translation.cpp | 41 +++++++++++++++++++ .../moduletests/test_service_discovery.cpp | 29 +++++++++---- .../error_handling/error_handling.hpp | 1 + .../runtime/service_discovery.hpp | 3 +- 9 files changed, 105 insertions(+), 15 deletions(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/enums.h b/iceoryx_binding_c/include/iceoryx_binding_c/enums.h index 2725292e6b..e5632a9531 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/enums.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/enums.h @@ -149,4 +149,11 @@ enum iox_ServerRequestResult ServerRequestResult_SUCCESS }; +/// @brief used to describe the messaging pattern +enum iox_MessagingPattern +{ + MessagingPattern_PUB_SUB, + MessagingPattern_REQ_RES +}; + #endif diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp b/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp index fba18f4c99..56f39ef155 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp +++ b/iceoryx_binding_c/include/iceoryx_binding_c/internal/c2cpp_enum_translation.hpp @@ -36,6 +36,7 @@ iox::popo::ServerEvent serverEvent(const iox_ServerEvent value) noexcept; iox::popo::ServerState serverState(const iox_ServerState value) noexcept; iox::runtime::ServiceDiscoveryEvent serviceDiscoveryEvent(const iox_ServiceDiscoveryEvent value) noexcept; +iox::popo::MessagingPattern messagingPattern(const iox_MessagingPattern value) noexcept; } // namespace c2cpp #endif diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h index f4fd8bca0a..53beabe814 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h @@ -17,6 +17,7 @@ #ifndef IOX_BINDING_C_SERVICE_DISCOVERY_H #define IOX_BINDING_C_SERVICE_DISCOVERY_H +#include "iceoryx_binding_c/enums.h" #include "iceoryx_binding_c/internal/c2cpp_binding.h" #include "iceoryx_binding_c/types.h" #include "service_description.h" @@ -38,10 +39,12 @@ void iox_service_discovery_deinit(iox_service_discovery_t const self); /// @param[in] service service string to search for, a nullptr corresponds to a wildcard /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard /// @param[in] event event string to search for, a nullptr corresponds to a wildcard -/// @param[in] serviceContainer preallocated memory to an array of ***** in which the matching services can be written +/// @param[in] serviceContainer preallocated memory to an array of iox_service_description_t in which the matching +/// services can be written /// @param[in] serviceContainerCapacity the capacity of the preallocated serviceContainer /// @param[in] missedServices if the serviceContainer has insufficient size the number of missed services which could /// not be written into the serviceContainer are stored here +/// @param[in] pattern messaging pattern to which the service belongs /// @return the number of services which were written into the serviceContainer uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, const char* const service, @@ -49,7 +52,8 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, const char* const event, iox_service_description_t* const serviceContainer, const uint64_t serviceContainerCapacity, - uint64_t* missedServices); + uint64_t* missedServices, + const ENUM iox_MessagingPattern pattern); /// @brief Searches all services that match the provided service description and applies a function to each of them /// @param[in] self handle of the service discovery @@ -57,11 +61,13 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard /// @param[in] event event string to search for, a nullptr corresponds to a wildcard /// @param[in] callable to apply to all matching services +/// @param[in] pattern messaging pattern to which the service belongs void iox_service_discovery_find_service_with_context_data(iox_service_discovery_t const self, const char* const service, const char* const instance, const char* const event, void (*callable)(const iox_service_description_t, void*), - void* const contextData); + void* const contextData, + const ENUM iox_MessagingPattern pattern); #endif diff --git a/iceoryx_binding_c/source/c2cpp_enum_translation.cpp b/iceoryx_binding_c/source/c2cpp_enum_translation.cpp index beaca9aa78..3192de8e08 100644 --- a/iceoryx_binding_c/source/c2cpp_enum_translation.cpp +++ b/iceoryx_binding_c/source/c2cpp_enum_translation.cpp @@ -140,4 +140,19 @@ iox::runtime::ServiceDiscoveryEvent serviceDiscoveryEvent(const iox_ServiceDisco return iox::runtime::ServiceDiscoveryEvent::SERVICE_REGISTRY_CHANGED; } +iox::popo::MessagingPattern messagingPattern(const iox_MessagingPattern value) noexcept +{ + switch (value) + { + case MessagingPattern_PUB_SUB: + return iox::popo::MessagingPattern::PUB_SUB; + case MessagingPattern_REQ_RES: + return iox::popo::MessagingPattern::REQ_RES; + } + + iox::LogFatal() << "invalid iox_MessagingPattern value"; + errorHandler(iox::Error::kBINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_MESSAGING_PATTERN_VALUE); + return iox::popo::MessagingPattern::PUB_SUB; +} + } // namespace c2cpp diff --git a/iceoryx_binding_c/source/c_service_discovery.cpp b/iceoryx_binding_c/source/c_service_discovery.cpp index 6009922014..b6d1789806 100644 --- a/iceoryx_binding_c/source/c_service_discovery.cpp +++ b/iceoryx_binding_c/source/c_service_discovery.cpp @@ -14,6 +14,7 @@ // // SPDX-License-Identifier: Apache-2.0 +#include "iceoryx_binding_c/internal/c2cpp_enum_translation.hpp" #include "iceoryx_binding_c/internal/cpp2c_service_description_translation.hpp" #include "iceoryx_hoofs/cxx/optional.hpp" #include "iceoryx_hoofs/cxx/requires.hpp" @@ -47,7 +48,8 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, const char* const event, iox_service_description_t* const serviceContainer, const uint64_t serviceContainerCapacity, - uint64_t* missedServices) + uint64_t* missedServices, + const ENUM iox_MessagingPattern pattern) { iox::cxx::Expects(self != nullptr); iox::cxx::Expects(serviceContainer != nullptr); @@ -80,7 +82,7 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, ++(*missedServices); } }; - self->findService(maybeService, maybeInstance, maybeEvent, filter, iox::popo::MessagingPattern::PUB_SUB); + self->findService(maybeService, maybeInstance, maybeEvent, filter, c2cpp::messagingPattern(pattern)); return currentSize; } @@ -90,7 +92,8 @@ void iox_service_discovery_find_service_with_context_data(iox_service_discovery_ const char* const instance, const char* const event, void (*callable)(const iox_service_description_t, void*), - void* const contextData) + void* const contextData, + const ENUM iox_MessagingPattern pattern) { iox::cxx::Expects(self != nullptr); iox::cxx::Expects(callable != nullptr); @@ -112,5 +115,5 @@ void iox_service_discovery_find_service_with_context_data(iox_service_discovery_ } auto filter = [&](const capro::ServiceDescription& s) { callable(TranslateServiceDescription(s), contextData); }; - self->findService(maybeService, maybeInstance, maybeEvent, filter, iox::popo::MessagingPattern::PUB_SUB); + self->findService(maybeService, maybeInstance, maybeEvent, filter, c2cpp::messagingPattern(pattern)); } diff --git a/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp b/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp index b2d10c2792..d0947d96a2 100644 --- a/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp +++ b/iceoryx_binding_c/test/moduletests/test_c2cpp_enum_translation.cpp @@ -366,4 +366,45 @@ TEST(c2cpp_enum_translation_test, ServiceDiscoveryEvent) #pragma GCC diagnostic pop } +TEST(c2cpp_enum_translation_test, MessagingPattern) +{ + ::testing::Test::RecordProperty("TEST_ID", "934d1fa5-e345-4a3b-9730-5467ec03c281"); + constexpr EnumMapping VALUE[]{ + {iox::popo::MessagingPattern::PUB_SUB, MessagingPattern_PUB_SUB}, + {iox::popo::MessagingPattern::REQ_RES, MessagingPattern_REQ_RES}, + }; + + for (const auto value : VALUE) + { + switch (value.cpp) + { + case iox::popo::MessagingPattern::PUB_SUB: + EXPECT_EQ(c2cpp::messagingPattern(value.c), value.cpp); + break; + case iox::popo::MessagingPattern::REQ_RES: + EXPECT_EQ(c2cpp::messagingPattern(value.c), value.cpp); + break; + // default intentionally left out in order to get a compiler warning if the enum gets extended and we forgot + // to extend the test + } + } + + // ignore the warning since we would like to test the behavior of an invalid enum value +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +// ignored for now since the undefined behavior sanitizer correctly detects the undefined behavior +// which is tested and handled here +// explicitly commented out since we are testing undefined behavior here and that we +// return the default value PUB_SUB always in the undefined behavior case +// the clang sanitizer detects this successfully and this leads to termination, and with this the test fails +#if !defined(__clang__) + iox::Error errorValue = iox::Error::kNO_ERROR; + auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler( + [&](const iox::Error e, const std::function, const iox::ErrorLevel) { errorValue = e; }); + EXPECT_EQ(c2cpp::messagingPattern(static_cast(-1)), iox::popo::MessagingPattern::PUB_SUB); + EXPECT_THAT(errorValue, Eq(iox::Error::kBINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_MESSAGING_PATTERN_VALUE)); +#endif +#pragma GCC diagnostic pop +} + } // namespace diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index 1f71d6ca52..975be4acc0 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -69,7 +69,8 @@ TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageT TEST_F(iox_service_discovery_test, FindServiceWithContextDataWithNullptrsForServiceInstanceEventReturnsAllServices) { ::testing::Test::RecordProperty("TEST_ID", "09a2cd6c-fba9-4b9d-af96-c5a6cc168d98"); - iox_service_discovery_find_service_with_context_data(sut, nullptr, nullptr, nullptr, findHandler, &searchResult); + iox_service_discovery_find_service_with_context_data( + sut, nullptr, nullptr, nullptr, findHandler, &searchResult, MessagingPattern_PUB_SUB); for (const auto& service : searchResult) { EXPECT_THAT(service.instanceString, StrEq("RouDi_ID")); @@ -91,7 +92,8 @@ TEST_F(iox_service_discovery_test, FindServiceWithContextDataReturnsOfferedServi SERVICE_DESCRIPTION.instanceString, SERVICE_DESCRIPTION.eventString, findHandler, - &searchResult); + &searchResult, + MessagingPattern_PUB_SUB); ASSERT_THAT(searchResult.size(), Eq(1U)); EXPECT_THAT(*searchResult.begin()->serviceString, Eq(*SERVICE_DESCRIPTION.serviceString)); EXPECT_THAT(*searchResult.begin()->instanceString, Eq(*SERVICE_DESCRIPTION.instanceString)); @@ -104,8 +106,14 @@ TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEven const uint64_t SERVICE_CONTAINER_CAPACITY = 10U; iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; uint64_t missedServices = 0U; - const auto numberFoundServices = iox_service_discovery_find_service( - sut, nullptr, nullptr, nullptr, serviceContainer, SERVICE_CONTAINER_CAPACITY, &missedServices); + const auto numberFoundServices = iox_service_discovery_find_service(sut, + nullptr, + nullptr, + nullptr, + serviceContainer, + SERVICE_CONTAINER_CAPACITY, + &missedServices, + MessagingPattern_PUB_SUB); EXPECT_THAT(numberFoundServices, Eq(6U)); EXPECT_THAT(missedServices, Eq(0U)); @@ -134,7 +142,8 @@ TEST_F(iox_service_discovery_test, FindServiceReturnsOfferedService) SERVICE_DESCRIPTION.eventString, serviceContainer, SERVICE_CONTAINER_CAPACITY, - &missedServices); + &missedServices, + MessagingPattern_PUB_SUB); EXPECT_THAT(numberFoundServices, Eq(1U)); EXPECT_THAT(missedServices, Eq(0U)); @@ -149,8 +158,14 @@ TEST_F(iox_service_discovery_test, FindServiceReturnsCorrectNumberOfServicesWhen const uint64_t SERVICE_CONTAINER_CAPACITY = 3U; iox_service_description_t serviceContainer[SERVICE_CONTAINER_CAPACITY]; uint64_t missedServices = 0U; - const auto numberFoundServices = iox_service_discovery_find_service( - sut, nullptr, nullptr, nullptr, serviceContainer, SERVICE_CONTAINER_CAPACITY, &missedServices); + const auto numberFoundServices = iox_service_discovery_find_service(sut, + nullptr, + nullptr, + nullptr, + serviceContainer, + SERVICE_CONTAINER_CAPACITY, + &missedServices, + MessagingPattern_PUB_SUB); EXPECT_THAT(numberFoundServices, Eq(SERVICE_CONTAINER_CAPACITY)); EXPECT_THAT(missedServices, Eq(6U - SERVICE_CONTAINER_CAPACITY)); diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp index 544295852a..5b541aa7ca 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp @@ -196,6 +196,7 @@ namespace iox error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVER_EVENT_VALUE) \ error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVER_STATE_VALUE) \ error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_SERVICE_DISCOVERY_EVENT_VALUE) \ + error(BINDING_C__C2CPP_ENUM_TRANSLATION_INVALID_MESSAGING_PATTERN_VALUE) \ error(EXPECTS_ENSURES_FAILED) // EXPECTS_ENSURES_FAILED is used as a temporary solution to make Expects/Ensures testable diff --git a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp index 99f4f3b93b..fd0a3191b3 100644 --- a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp +++ b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp @@ -34,7 +34,7 @@ enum class MessagingPattern PUB_SUB, REQ_RES }; -} +} // namespace popo namespace runtime { enum class ServiceDiscoveryEvent : popo::EventEnumIdentifier @@ -57,6 +57,7 @@ class ServiceDiscovery /// @param[in] instance instance string to search for, a nullopt corresponds to a wildcard /// @param[in] event event string to search for, a nullopt corresponds to a wildcard /// @param[in] callableForEach callable to apply to all matching services + /// @param[in] pattern messaging pattern to which the service belongs void findService(const cxx::optional& service, const cxx::optional& instance, const cxx::optional& event, From f28d462b96159ead1f87f57f5f0b6c02ce473a45 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Wed, 23 Feb 2022 18:14:45 +0100 Subject: [PATCH 09/14] iox-#1142 Fix CI failures Check if Semaphore::post was successful and adapt array size of service discovery Signed-off-by: Marika Lehmann --- iceoryx_binding_c/include/iceoryx_binding_c/types.h | 6 +++++- iceoryx_binding_c/test/moduletests/test_listener.cpp | 1 + iceoryx_binding_c/test/moduletests/test_wait_set.cpp | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/types.h b/iceoryx_binding_c/include/iceoryx_binding_c/types.h index 4be01d66c4..c35fb86530 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/types.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/types.h @@ -125,7 +125,11 @@ struct iox_service_discovery_storage_t { // the value of the array size is the result of the following formula: // sizeof(ServiceDiscovery) / 8 - uint64_t do_not_touch_me[196768]; +#if defined(__APPLE__) + uint64_t do_not_touch_me[49175]; +#else + uint64_t do_not_touch_me[49172]; +#endif }; typedef struct iox_service_discovery_storage_t iox_service_discovery_storage_t; diff --git a/iceoryx_binding_c/test/moduletests/test_listener.cpp b/iceoryx_binding_c/test/moduletests/test_listener.cpp index 65855c6d64..3d7138daae 100644 --- a/iceoryx_binding_c/test/moduletests/test_listener.cpp +++ b/iceoryx_binding_c/test/moduletests/test_listener.cpp @@ -30,6 +30,7 @@ using namespace iox; using namespace iox::popo; using namespace iox::posix; using namespace iox::mepoo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/client.h" diff --git a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp index 4423cee455..9fb05c2c93 100644 --- a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp +++ b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp @@ -29,6 +29,7 @@ using namespace iox; using namespace iox::popo; +using namespace iox::runtime; extern "C" { #include "iceoryx_binding_c/subscriber.h" @@ -1104,7 +1105,7 @@ void notifyServiceDiscovery(SubscriberPortData& portData) { iox::popo::ChunkQueuePusher pusher{&portData.m_chunkReceiverData}; pusher.push(iox::mepoo::SharedChunk()); - portData.m_chunkReceiverData.m_conditionVariableDataPtr->m_semaphore.post(); + EXPECT_FALSE(portData.m_chunkReceiverData.m_conditionVariableDataPtr->m_semaphore.post().has_error()); } TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWorks) From 2a1fbe50ea0e0a3247b4daf1dab63fc3eafe50fb Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Thu, 24 Feb 2022 10:51:48 +0100 Subject: [PATCH 10/14] iox-#1142 Fix service discovery findings Add nullptr check for missed elements ptr, replace magic number in test, add findService function without context data, correct doxygen comments Signed-off-by: Marika Lehmann --- .../iceoryx_binding_c/service_discovery.h | 40 ++++++++++----- .../source/c_service_discovery.cpp | 48 +++++++++++++++--- .../moduletests/test_service_discovery.cpp | 49 ++++++++++++++----- .../runtime/service_discovery.hpp | 3 +- 4 files changed, 109 insertions(+), 31 deletions(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h index 53beabe814..1861f1526d 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h @@ -34,7 +34,7 @@ iox_service_discovery_t iox_service_discovery_init(iox_service_discovery_storage /// @param[in] self the service discovery which should be deinitialized void iox_service_discovery_deinit(iox_service_discovery_t const self); -/// @brief Searches all services that match the provided service description +/// @brief Searches all services with the given messaging pattern that match the provided service description /// @param[in] self handle of the service discovery /// @param[in] service service string to search for, a nullptr corresponds to a wildcard /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard @@ -44,7 +44,7 @@ void iox_service_discovery_deinit(iox_service_discovery_t const self); /// @param[in] serviceContainerCapacity the capacity of the preallocated serviceContainer /// @param[in] missedServices if the serviceContainer has insufficient size the number of missed services which could /// not be written into the serviceContainer are stored here -/// @param[in] pattern messaging pattern to which the service belongs +/// @param[in] pattern messaging pattern of the service /// @return the number of services which were written into the serviceContainer uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, const char* const service, @@ -55,19 +55,37 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, uint64_t* missedServices, const ENUM iox_MessagingPattern pattern); -/// @brief Searches all services that match the provided service description and applies a function to each of them +/// @brief Searches all services with the given messaging pattern that match the provided service description and +/// applies a function to each of them /// @param[in] self handle of the service discovery /// @param[in] service service string to search for, a nullptr corresponds to a wildcard /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard /// @param[in] event event string to search for, a nullptr corresponds to a wildcard /// @param[in] callable to apply to all matching services -/// @param[in] pattern messaging pattern to which the service belongs -void iox_service_discovery_find_service_with_context_data(iox_service_discovery_t const self, - const char* const service, - const char* const instance, - const char* const event, - void (*callable)(const iox_service_description_t, void*), - void* const contextData, - const ENUM iox_MessagingPattern pattern); +/// @param[in] pattern messaging pattern of the service +void iox_service_discovery_find_service_apply_callable(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t), + const ENUM iox_MessagingPattern pattern); + +/// @brief Searches all services with the given messaging pattern that match the provided service description and +/// applies a function to each of them. A second parameter for the function can be provided as contextData. +/// @param[in] self handle of the service discovery +/// @param[in] service service string to search for, a nullptr corresponds to a wildcard +/// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard +/// @param[in] event event string to search for, a nullptr corresponds to a wildcard +/// @param[in] callable to apply to all matching services +/// @param[in] contextData a void pointer which is provided as second argument to the callback +/// @param[in] pattern messaging pattern of the service +void iox_service_discovery_find_service_apply_callable_with_context_data( + iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t, void*), + void* const contextData, + const ENUM iox_MessagingPattern pattern); #endif diff --git a/iceoryx_binding_c/source/c_service_discovery.cpp b/iceoryx_binding_c/source/c_service_discovery.cpp index b6d1789806..8485e58de7 100644 --- a/iceoryx_binding_c/source/c_service_discovery.cpp +++ b/iceoryx_binding_c/source/c_service_discovery.cpp @@ -53,6 +53,7 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, { iox::cxx::Expects(self != nullptr); iox::cxx::Expects(serviceContainer != nullptr); + iox::cxx::Expects(missedServices != nullptr); cxx::optional maybeService; if (service != nullptr) @@ -72,7 +73,7 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, uint64_t currentSize = 0U; auto filter = [&](const capro::ServiceDescription& s) { - if (currentSize + 1U <= serviceContainerCapacity) + if (currentSize < serviceContainerCapacity) { serviceContainer[currentSize] = TranslateServiceDescription(s); ++currentSize; @@ -87,13 +88,44 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, return currentSize; } -void iox_service_discovery_find_service_with_context_data(iox_service_discovery_t const self, - const char* const service, - const char* const instance, - const char* const event, - void (*callable)(const iox_service_description_t, void*), - void* const contextData, - const ENUM iox_MessagingPattern pattern) +void iox_service_discovery_find_service_apply_callable(iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t), + const ENUM iox_MessagingPattern pattern) +{ + iox::cxx::Expects(self != nullptr); + iox::cxx::Expects(callable != nullptr); + + cxx::optional maybeService; + if (service != nullptr) + { + maybeService.emplace(cxx::TruncateToCapacity, service); + } + cxx::optional maybeInstance; + if (instance != nullptr) + { + maybeInstance.emplace(cxx::TruncateToCapacity, instance); + } + cxx::optional maybeEvent; + if (event != nullptr) + { + maybeEvent.emplace(cxx::TruncateToCapacity, event); + } + + auto filter = [&](const capro::ServiceDescription& s) { callable(TranslateServiceDescription(s)); }; + self->findService(maybeService, maybeInstance, maybeEvent, filter, c2cpp::messagingPattern(pattern)); +} + +void iox_service_discovery_find_service_apply_callable_with_context_data( + iox_service_discovery_t const self, + const char* const service, + const char* const instance, + const char* const event, + void (*callable)(const iox_service_description_t, void*), + void* const contextData, + const ENUM iox_MessagingPattern pattern) { iox::cxx::Expects(self != nullptr); iox::cxx::Expects(callable != nullptr); diff --git a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp index 975be4acc0..ea3e256783 100644 --- a/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp +++ b/iceoryx_binding_c/test/moduletests/test_service_discovery.cpp @@ -66,10 +66,11 @@ TEST(iox_service_discovery_DeathTest, InitServiceDiscoveryWithNullptrForStorageT /// @note We test only if the arguments of iox_service_discovery_find_service are correctly passed to /// ServiceDiscovery::findService. -TEST_F(iox_service_discovery_test, FindServiceWithContextDataWithNullptrsForServiceInstanceEventReturnsAllServices) +TEST_F(iox_service_discovery_test, + FindServiceWithCallableAndContextDataWithNullptrsForServiceInstanceEventReturnsAllServices) { ::testing::Test::RecordProperty("TEST_ID", "09a2cd6c-fba9-4b9d-af96-c5a6cc168d98"); - iox_service_discovery_find_service_with_context_data( + iox_service_discovery_find_service_apply_callable_with_context_data( sut, nullptr, nullptr, nullptr, findHandler, &searchResult, MessagingPattern_PUB_SUB); for (const auto& service : searchResult) { @@ -77,7 +78,7 @@ TEST_F(iox_service_discovery_test, FindServiceWithContextDataWithNullptrsForServ } } -TEST_F(iox_service_discovery_test, FindServiceWithContextDataReturnsOfferedService) +TEST_F(iox_service_discovery_test, FindServiceWithCallableAndContextDataReturnsOfferedService) { ::testing::Test::RecordProperty("TEST_ID", "bb12e514-e7af-4946-b098-98b3cd0f43a5"); iox_pub_options_t options; @@ -87,19 +88,45 @@ TEST_F(iox_service_discovery_test, FindServiceWithContextDataReturnsOfferedServi ASSERT_NE(publisher, nullptr); const iox_service_description_t SERVICE_DESCRIPTION = iox_pub_get_service_description(publisher); - iox_service_discovery_find_service_with_context_data(sut, - SERVICE_DESCRIPTION.serviceString, - SERVICE_DESCRIPTION.instanceString, - SERVICE_DESCRIPTION.eventString, - findHandler, - &searchResult, - MessagingPattern_PUB_SUB); + iox_service_discovery_find_service_apply_callable_with_context_data(sut, + SERVICE_DESCRIPTION.serviceString, + SERVICE_DESCRIPTION.instanceString, + SERVICE_DESCRIPTION.eventString, + findHandler, + &searchResult, + MessagingPattern_PUB_SUB); ASSERT_THAT(searchResult.size(), Eq(1U)); EXPECT_THAT(*searchResult.begin()->serviceString, Eq(*SERVICE_DESCRIPTION.serviceString)); EXPECT_THAT(*searchResult.begin()->instanceString, Eq(*SERVICE_DESCRIPTION.instanceString)); EXPECT_THAT(*searchResult.begin()->eventString, Eq(*SERVICE_DESCRIPTION.eventString)); } +TEST_F(iox_service_discovery_test, FindServiceWithCallableWithNullptrsForServiceInstanceEventFindsCorrectServices) +{ + ::testing::Test::RecordProperty("TEST_ID", "ec565ca3-7494-42d7-9440-2000f1513759"); + auto findHandler = [](const iox_service_description_t s) { EXPECT_THAT(s.instanceString, StrEq("RouDi_ID")); }; + iox_service_discovery_find_service_apply_callable( + sut, nullptr, nullptr, nullptr, findHandler, MessagingPattern_PUB_SUB); +} + +TEST_F(iox_service_discovery_test, FindServiceWithCallableReturnsFindsCorrectService) +{ + ::testing::Test::RecordProperty("TEST_ID", "3ac1f029-3c05-4f95-90e9-e848ceb2d4d7"); + iox_pub_options_t options; + iox_pub_options_init(&options); + iox_pub_storage_t storage; + auto* publisher = iox_pub_init(&storage, "service", "instance", "event", &options); + ASSERT_NE(publisher, nullptr); + + auto findHandler = [](const iox_service_description_t s) { + EXPECT_THAT(s.serviceString, StrEq("service")); + EXPECT_THAT(s.instanceString, StrEq("instance")); + EXPECT_THAT(s.eventString, StrEq("event")); + }; + iox_service_discovery_find_service_apply_callable( + sut, "service", "instance", "event", findHandler, MessagingPattern_PUB_SUB); +} + TEST_F(iox_service_discovery_test, FindServiceWithNullptrsForServiceInstanceEventReturnsAllServices) { ::testing::Test::RecordProperty("TEST_ID", "75b411d7-b8c7-42d5-8acd-3916fd172081"); @@ -168,7 +195,7 @@ TEST_F(iox_service_discovery_test, FindServiceReturnsCorrectNumberOfServicesWhen MessagingPattern_PUB_SUB); EXPECT_THAT(numberFoundServices, Eq(SERVICE_CONTAINER_CAPACITY)); - EXPECT_THAT(missedServices, Eq(6U - SERVICE_CONTAINER_CAPACITY)); + EXPECT_THAT(missedServices, Eq(NUMBER_OF_INTERNAL_PUBLISHERS - SERVICE_CONTAINER_CAPACITY)); } } // namespace diff --git a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp index fd0a3191b3..7106018a6a 100644 --- a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp +++ b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp @@ -52,7 +52,8 @@ class ServiceDiscovery ServiceDiscovery& operator=(ServiceDiscovery&&) = delete; ~ServiceDiscovery() noexcept = default; - /// @brief Searches all services that match the provided service description and applies a function to each of them + /// @brief Searches all services with the given messaging pattern that match the provided service description and + /// applies a function to each of them /// @param[in] service service string to search for, a nullopt corresponds to a wildcard /// @param[in] instance instance string to search for, a nullopt corresponds to a wildcard /// @param[in] event event string to search for, a nullopt corresponds to a wildcard From ba4e5c6ae0b6c35d5f9e142f19d802fb2d12ddaa Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Thu, 24 Feb 2022 12:01:23 +0100 Subject: [PATCH 11/14] iox-#1142 Fix listener findings Remove nullptr check for context data, reset callback pointer in test setup Signed-off-by: Marika Lehmann --- iceoryx_binding_c/source/c_listener.cpp | 1 - iceoryx_binding_c/test/moduletests/test_listener.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/iceoryx_binding_c/source/c_listener.cpp b/iceoryx_binding_c/source/c_listener.cpp index 48f24b950f..dce9b7bedc 100644 --- a/iceoryx_binding_c/source/c_listener.cpp +++ b/iceoryx_binding_c/source/c_listener.cpp @@ -281,7 +281,6 @@ iox_ListenerResult iox_listener_attach_service_discovery_event_with_context_data iox::cxx::Expects(self != nullptr); iox::cxx::Expects(serviceDiscovery != nullptr); iox::cxx::Expects(callback != nullptr); - iox::cxx::Expects(contextData != nullptr); auto result = self->attachEvent(*serviceDiscovery, c2cpp::serviceDiscoveryEvent(serviceDiscoveryEvent), diff --git a/iceoryx_binding_c/test/moduletests/test_listener.cpp b/iceoryx_binding_c/test/moduletests/test_listener.cpp index 3d7138daae..977157267b 100644 --- a/iceoryx_binding_c/test/moduletests/test_listener.cpp +++ b/iceoryx_binding_c/test/moduletests/test_listener.cpp @@ -128,6 +128,7 @@ class iox_listener_test : public Test g_userTriggerCallbackArgument = nullptr; g_subscriberCallbackArgument = nullptr; g_clientCallbackArgument = nullptr; + g_serviceDiscoveryCallbackArgument = nullptr; g_contextData = nullptr; m_mempoolconf.addMemPool({CHUNK_SIZE, NUM_CHUNKS_IN_POOL}); From cdb5207d6ea216abfd813b69d4ca407e72b79732 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Thu, 24 Feb 2022 12:06:42 +0100 Subject: [PATCH 12/14] iox-#1142 Introduce constexpr for event id in waitset tests Signed-off-by: Marika Lehmann --- iceoryx_binding_c/test/moduletests/test_wait_set.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp index 9fb05c2c93..6dbd663476 100644 --- a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp +++ b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp @@ -1111,19 +1111,20 @@ void notifyServiceDiscovery(SubscriberPortData& portData) TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWorks) { ::testing::Test::RecordProperty("TEST_ID", "945dcf94-4679-469f-aa47-1a87d536da72"); + constexpr uint64_t EVENT_ID = 13; iox_service_discovery_storage_t serviceDiscoveryStorage; EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); iox_service_discovery_t serviceDiscovery = iox_service_discovery_init(&serviceDiscoveryStorage); iox_ws_attach_service_discovery_event( - m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, 13, &serviceDiscoveryCallback); + m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, EVENT_ID, &serviceDiscoveryCallback); notifyServiceDiscovery(m_portDataVector[0]); ASSERT_THAT(iox_ws_wait(m_sut, m_eventInfoStorage, MAX_NUMBER_OF_ATTACHMENTS_PER_WAITSET, &m_missedElements), Eq(1)); - EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(13)); + EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(EVENT_ID)); EXPECT_THAT(iox_notification_info_get_service_discovery_origin(m_eventInfoStorage[0]), Eq(serviceDiscovery)); EXPECT_TRUE(iox_notification_info_does_originate_from_service_discovery(m_eventInfoStorage[0], serviceDiscovery)); iox_notification_info_call(m_eventInfoStorage[0]); @@ -1137,6 +1138,7 @@ TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWorks) TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) { ::testing::Test::RecordProperty("TEST_ID", "510a0351-afeb-4c0f-a4b6-3032f1f3f831"); + constexpr uint64_t EVENT_ID = 31; iox_service_discovery_storage_t serviceDiscoveryStorage; EXPECT_CALL(*runtimeMock, getMiddlewareSubscriber(_, _, _)).WillOnce(Return(&m_portDataVector[0])); @@ -1145,7 +1147,7 @@ TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) iox_ws_attach_service_discovery_event_with_context_data(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED, - 31, + EVENT_ID, &serviceDiscoveryCallbackWithContextData, &serviceDiscoveryStorage); @@ -1153,7 +1155,7 @@ TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) ASSERT_THAT(iox_ws_wait(m_sut, m_eventInfoStorage, MAX_NUMBER_OF_ATTACHMENTS_PER_WAITSET, &m_missedElements), Eq(1)); - EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(31)); + EXPECT_THAT(iox_notification_info_get_notification_id(m_eventInfoStorage[0]), Eq(EVENT_ID)); EXPECT_THAT(iox_notification_info_get_service_discovery_origin(m_eventInfoStorage[0]), Eq(serviceDiscovery)); EXPECT_TRUE(iox_notification_info_does_originate_from_service_discovery(m_eventInfoStorage[0], serviceDiscovery)); iox_notification_info_call(m_eventInfoStorage[0]); From 73df47762f36dcfd46fc21956b06e65d8c8f7a36 Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Thu, 24 Feb 2022 12:20:59 +0100 Subject: [PATCH 13/14] iox-#1142 Specify doxygen comments for service discovery Signed-off-by: Marika Lehmann --- .../include/iceoryx_binding_c/service_discovery.h | 6 +++--- .../include/iceoryx_posh/runtime/service_discovery.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h index 1861f1526d..b48d821143 100644 --- a/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h +++ b/iceoryx_binding_c/include/iceoryx_binding_c/service_discovery.h @@ -44,7 +44,7 @@ void iox_service_discovery_deinit(iox_service_discovery_t const self); /// @param[in] serviceContainerCapacity the capacity of the preallocated serviceContainer /// @param[in] missedServices if the serviceContainer has insufficient size the number of missed services which could /// not be written into the serviceContainer are stored here -/// @param[in] pattern messaging pattern of the service +/// @param[in] pattern messaging pattern of the service to search /// @return the number of services which were written into the serviceContainer uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, const char* const service, @@ -62,7 +62,7 @@ uint64_t iox_service_discovery_find_service(iox_service_discovery_t const self, /// @param[in] instance instance string to search for, a nullptr corresponds to a wildcard /// @param[in] event event string to search for, a nullptr corresponds to a wildcard /// @param[in] callable to apply to all matching services -/// @param[in] pattern messaging pattern of the service +/// @param[in] pattern messaging pattern of the service to search void iox_service_discovery_find_service_apply_callable(iox_service_discovery_t const self, const char* const service, const char* const instance, @@ -78,7 +78,7 @@ void iox_service_discovery_find_service_apply_callable(iox_service_discovery_t c /// @param[in] event event string to search for, a nullptr corresponds to a wildcard /// @param[in] callable to apply to all matching services /// @param[in] contextData a void pointer which is provided as second argument to the callback -/// @param[in] pattern messaging pattern of the service +/// @param[in] pattern messaging pattern of the service to search void iox_service_discovery_find_service_apply_callable_with_context_data( iox_service_discovery_t const self, const char* const service, diff --git a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp index 7106018a6a..cef7268d95 100644 --- a/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp +++ b/iceoryx_posh/include/iceoryx_posh/runtime/service_discovery.hpp @@ -58,7 +58,7 @@ class ServiceDiscovery /// @param[in] instance instance string to search for, a nullopt corresponds to a wildcard /// @param[in] event event string to search for, a nullopt corresponds to a wildcard /// @param[in] callableForEach callable to apply to all matching services - /// @param[in] pattern messaging pattern to which the service belongs + /// @param[in] pattern messaging pattern of the service to search void findService(const cxx::optional& service, const cxx::optional& instance, const cxx::optional& event, From c9a4d43062d3df57fba11f6cfb1ce1384c33beba Mon Sep 17 00:00:00 2001 From: Marika Lehmann Date: Thu, 24 Feb 2022 15:49:25 +0100 Subject: [PATCH 14/14] iox-#1142 Fix leak in waitset and listener tests Signed-off-by: Marika Lehmann --- iceoryx_binding_c/test/moduletests/test_listener.cpp | 8 ++++++++ iceoryx_binding_c/test/moduletests/test_wait_set.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/iceoryx_binding_c/test/moduletests/test_listener.cpp b/iceoryx_binding_c/test/moduletests/test_listener.cpp index 977157267b..1362d14754 100644 --- a/iceoryx_binding_c/test/moduletests/test_listener.cpp +++ b/iceoryx_binding_c/test/moduletests/test_listener.cpp @@ -574,6 +574,8 @@ TEST_F(iox_listener_test, AttachingServiceDiscoveryWorks) iox_listener_detach_service_discovery_event( &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); + + iox_service_discovery_deinit(serviceDiscovery); } TEST_F(iox_listener_test, AttachingServiceDiscoveryWithContextDataWorks) @@ -595,6 +597,8 @@ TEST_F(iox_listener_test, AttachingServiceDiscoveryWithContextDataWorks) iox_listener_detach_service_discovery_event( &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); EXPECT_THAT(iox_listener_size(&m_sut), Eq(0)); + + iox_service_discovery_deinit(serviceDiscovery); } void notifyServiceDiscovery(SubscriberPortData& portData) @@ -618,6 +622,8 @@ TIMING_TEST_F(iox_listener_test, NotifyingServiceDiscoveryEventWorks, Repeat(5), iox_listener_detach_service_discovery_event( &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + + iox_service_discovery_deinit(serviceDiscovery); }); TIMING_TEST_F(iox_listener_test, NotifyingServiceDiscoveryEventWithContextDataWorks, Repeat(5), [&] { @@ -640,6 +646,8 @@ TIMING_TEST_F(iox_listener_test, NotifyingServiceDiscoveryEventWithContextDataWo iox_listener_detach_service_discovery_event( &m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + + iox_service_discovery_deinit(serviceDiscovery); }); } // namespace diff --git a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp index 6dbd663476..b0f2159679 100644 --- a/iceoryx_binding_c/test/moduletests/test_wait_set.cpp +++ b/iceoryx_binding_c/test/moduletests/test_wait_set.cpp @@ -1082,6 +1082,8 @@ TEST_F(iox_ws_test, AttachingServiceDiscoveryEventWorks) iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); + + iox_service_discovery_deinit(serviceDiscovery); } TEST_F(iox_ws_test, AttachingServiceDiscoveryEventWithContextDataWorks) @@ -1099,6 +1101,8 @@ TEST_F(iox_ws_test, AttachingServiceDiscoveryEventWithContextDataWorks) iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); EXPECT_THAT(iox_ws_size(m_sut), Eq(0)); + + iox_service_discovery_deinit(serviceDiscovery); } void notifyServiceDiscovery(SubscriberPortData& portData) @@ -1133,6 +1137,8 @@ TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWorks) EXPECT_THAT(m_contextData, Eq(nullptr)); iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + + iox_service_discovery_deinit(serviceDiscovery); } TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) @@ -1164,6 +1170,8 @@ TEST_F(iox_ws_test, NotifyingServiceDiscoveryEventWithContextDataWorks) EXPECT_THAT(m_contextData, Eq(static_cast(&serviceDiscoveryStorage))); iox_ws_detach_service_discovery_event(m_sut, serviceDiscovery, ServiceDiscoveryEvent_SERVICE_REGISTRY_CHANGED); + + iox_service_discovery_deinit(serviceDiscovery); } } // namespace