diff --git a/CHANGELOG.md b/CHANGELOG.md index c7f68b1a0c..4dbeb8a3d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -108,6 +108,20 @@ ServiceDescription("First", "Second", "DontCare") myServiceDescription2; ServiceDescription("Foo", "Bar", "Baz") myServiceDescription3; ``` +The service-related methods have been moved from `PoshRuntime` to a separate class (TBD): + +```cpp +// before +poshRuntime.offerService(myServiceDescription); +poshRuntime.stopOfferService(myServiceDescription); +poshRuntime.findService({"ServiceA", iox::capro::AnyInstanceString}); + +// after +discoveryInfo.offerService(myServiceDescription); +discoveryInfo.stopOfferService(myServiceDescription); +discoveryInfo.findService("ServiceA", Wildcard); +``` + ## [v1.0.1](https://github.com/eclipse-iceoryx/iceoryx/tree/v1.0.0) (2021-06-15) [Full Changelog](https://github.com/eclipse-iceoryx/iceoryx/compare/v1.0.0...v1.0.1) 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 c705f5369e..d391d2ec3a 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp @@ -56,6 +56,7 @@ namespace iox error(POSH__RUNTIME_NAME_EMPTY) \ error(POSH__RUNTIME_LEADING_SLASH_PROVIDED) \ error(POSH__PORT_MANAGER_PUBLISHERPORT_NOT_UNIQUE) \ + error(POSH__PORT_MANAGER_COULD_NOT_ADD_SERVICE_TO_REGISTRY) \ error(POSH__MEMPOOL_POSSIBLE_DOUBLE_FREE) \ error(POSH__RECEIVERPORT_DELIVERYFIFO_OVERFLOW) \ error(POSH__SENDERPORT_SAMPLE_SIZE_CHANGED_FOR_ACTIVE_PORT) \ diff --git a/iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp b/iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp index 3841ae933b..1d62ec0bd5 100644 --- a/iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp +++ b/iceoryx_posh/include/iceoryx_posh/iceoryx_posh_types.hpp @@ -42,6 +42,10 @@ class PublisherPortUser; class SubscriberPortRouDi; class SubscriberPortUser; } // namespace popo +namespace capro +{ +class ServiceDescription; +} using PublisherPortRouDiType = iox::popo::PublisherPortRouDi; using PublisherPortUserType = iox::popo::PublisherPortUser; @@ -131,10 +135,11 @@ constexpr uint32_t APP_MESSAGE_SIZE = 512U; // Processes constexpr uint32_t MAX_PROCESS_NUMBER = 300U; -/// Maximum number of instances of a given service, which can be found. +/// Maximum number of services, which can be found. /// This limitation is coming due to the fixed capacity of the cxx::vector (This doesn't limit the offered number of /// instances) -constexpr uint32_t MAX_NUMBER_OF_INSTANCES = 50U; +/// @todo #415 increase number back to 50 once service registry is available via shared memory +constexpr uint32_t MAX_NUMBER_OF_SERVICES = 10U; // Nodes constexpr uint32_t MAX_NODE_NUMBER = 1000U; @@ -249,7 +254,7 @@ using TimePointNs_t = std::chrono::time_point; namespace runtime { -using InstanceContainer = iox::cxx::vector; +using ServiceContainer = iox::cxx::vector; using namespace units::duration_literals; constexpr units::Duration PROCESS_WAITING_FOR_ROUDI_TIMEOUT = 60_s; constexpr units::Duration PROCESS_KEEP_ALIVE_INTERVAL = 3 * roudi::DISCOVERY_INTERVAL; // > DISCOVERY_INTERVAL diff --git a/iceoryx_posh/include/iceoryx_posh/internal/roudi/port_manager.hpp b/iceoryx_posh/include/iceoryx_posh/internal/roudi/port_manager.hpp index 859590c44a..cfb9299d08 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/roudi/port_manager.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/roudi/port_manager.hpp @@ -132,8 +132,8 @@ class PortManager void sendToAllMatchingInterfacePorts(const capro::CaproMessage& message) noexcept; - void addEntryToServiceRegistry(const capro::IdString_t& service, const capro::IdString_t& instance) noexcept; - void removeEntryFromServiceRegistry(const capro::IdString_t& service, const capro::IdString_t& instance) noexcept; + void addEntryToServiceRegistry(const capro::ServiceDescription& service) noexcept; + void removeEntryFromServiceRegistry(const capro::ServiceDescription& service) noexcept; template ::value>* = nullptr> cxx::optional diff --git a/iceoryx_posh/include/iceoryx_posh/internal/roudi/service_registry.hpp b/iceoryx_posh/include/iceoryx_posh/internal/roudi/service_registry.hpp index f457629d3d..fee392d1bb 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/roudi/service_registry.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/roudi/service_registry.hpp @@ -17,12 +17,13 @@ #ifndef IOX_POSH_ROUDI_SERVICE_REGISTRY_HPP #define IOX_POSH_ROUDI_SERVICE_REGISTRY_HPP +#include "iceoryx_hoofs/cxx/expected.hpp" #include "iceoryx_hoofs/cxx/vector.hpp" -#include "iceoryx_hoofs/internal/cxx/set.hpp" #include "iceoryx_posh/capro/service_description.hpp" #include #include +#include namespace iox { @@ -32,23 +33,50 @@ static const capro::IdString_t Wildcard{"*"}; class ServiceRegistry { public: - static constexpr uint32_t MAX_INSTANCES_PER_SERVICE = 100u; - using InstanceSet_t = cxx::vector; - struct instance_t + enum class Error { - InstanceSet_t instanceSet; + INVALID_STATE, + SERVICE_REGISTRY_FULL, }; - using serviceMap_t = std::map; - void add(const capro::IdString_t& service, const capro::IdString_t& instance); - void remove(const capro::IdString_t& service, const capro::IdString_t& instance); - void find(InstanceSet_t& instances, - const capro::IdString_t& service, - const capro::IdString_t& instance = Wildcard) const; - const serviceMap_t& getServiceMap() const; + using ReferenceCounter_t = uint64_t; + struct ServiceDescriptionEntry + { + capro::ServiceDescription serviceDescription{}; + ReferenceCounter_t referenceCounter = 0U; + }; + + /// @todo #415 should be connected with iox::MAX_NUMBER_OF_SERVICES + static constexpr uint32_t MAX_SERVICE_DESCRIPTIONS = 100U; + using ServiceDescriptionVector_t = cxx::vector; + + /// @brief Adds given service description to registry + /// @param[in] serviceDescription, service to be added + /// @return ServiceRegistryError, error wrapped in cxx::expected + cxx::expected add(const capro::ServiceDescription& serviceDescription) noexcept; + + /// @brief Removes given service description from registry + /// @param[in] serviceDescription, service to be removed + /// @return true, if service description was removed, false otherwise + bool remove(const capro::ServiceDescription& serviceDescription) noexcept; + + /// @brief Removes given service description from registry + /// @param[in] searchResult, reference to the vector which will be filled with the results + /// @param[in] service, string or wildcard to search for + /// @param[in] instance, string or wildcard to search for + void find(ServiceDescriptionVector_t& searchResult, + const capro::IdString_t& service = Wildcard, + const capro::IdString_t& instance = Wildcard) const noexcept; + + /// @brief Returns all service descriptions as copy + /// @return ServiceDescriptionVector_t, copy of complete service registry + const ServiceDescriptionVector_t getServices() const noexcept; private: - mutable serviceMap_t m_serviceMap; + /// @todo #859 replace std::multimap with prefix tree + ::std::multimap m_serviceMap; + ::std::multimap m_instanceMap; + ServiceDescriptionVector_t m_serviceDescriptionVector; }; } // namespace roudi } // namespace iox diff --git a/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp b/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp index 8f8b55b793..229e76f283 100644 --- a/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp +++ b/iceoryx_posh/include/iceoryx_posh/internal/runtime/posh_runtime_impl.hpp @@ -44,9 +44,9 @@ class PoshRuntimeImpl : public PoshRuntime virtual ~PoshRuntimeImpl() noexcept; /// @copydoc PoshRuntime::findService - cxx::expected - findService(const cxx::variant service, - const cxx::variant instance) noexcept override; + cxx::expected + findService(const cxx::variant service, + const cxx::variant instance) noexcept override; /// @copydoc PoshRuntime::offerService bool offerService(const capro::ServiceDescription& serviceDescription) noexcept override; diff --git a/iceoryx_posh/include/iceoryx_posh/runtime/posh_runtime.hpp b/iceoryx_posh/include/iceoryx_posh/runtime/posh_runtime.hpp index 698717261c..91e50d3088 100644 --- a/iceoryx_posh/include/iceoryx_posh/runtime/posh_runtime.hpp +++ b/iceoryx_posh/include/iceoryx_posh/runtime/posh_runtime.hpp @@ -47,12 +47,12 @@ class NodeData; enum class FindServiceError { INVALID_STATE, - UNABLE_TO_WRITE_TO_ROUDI_CHANNEL, - INSTANCE_CONTAINER_OVERFLOW + UNABLE_TO_WRITE_TO_ROUDI_CHANNEL, /// @todo #415 remove as IPC channel won't be used + INSTANCE_CONTAINER_OVERFLOW /// @todo #415 set container to iox::MAX_NUMBER_OF_SERVICES and remove error }; -/// @brief Used to search for any string (wildcard) -struct Any_t +/// @brief Used to search for any string +struct Wildcard_t { }; @@ -89,12 +89,12 @@ class PoshRuntime /// @brief find all services that match the provided service description /// @param[in] service service string to search for (wildcards allowed) /// @param[in] instance instance string to search for (wildcards allowed) - /// @return cxx::expected - /// InstanceContainer: on success, container that is filled with all matching instances + /// @return cxx::expected + /// ServiceContainer: on success, container that is filled with all matching instances /// FindServiceError: if any, encountered during the operation - virtual cxx::expected - findService(const cxx::variant service, - const cxx::variant instance) noexcept = 0; + virtual cxx::expected + findService(const cxx::variant service, + const cxx::variant instance) noexcept = 0; /// @brief offer the provided service, sends the offer from application to RouDi daemon /// @param[in] service valid ServiceDescription to offer diff --git a/iceoryx_posh/source/capro/service_description.cpp b/iceoryx_posh/source/capro/service_description.cpp index 2bbae2b586..8321c31eb5 100644 --- a/iceoryx_posh/source/capro/service_description.cpp +++ b/iceoryx_posh/source/capro/service_description.cpp @@ -120,11 +120,6 @@ ServiceDescription::ServiceDescription(const IdString_t& service, bool ServiceDescription::operator==(const ServiceDescription& rhs) const { - if (!isValid() || !rhs.isValid()) - { - return false; - } - if (m_serviceString != rhs.m_serviceString) { return false; diff --git a/iceoryx_posh/source/roudi/port_manager.cpp b/iceoryx_posh/source/roudi/port_manager.cpp index eb8aecc541..16ecdef6a9 100644 --- a/iceoryx_posh/source/roudi/port_manager.cpp +++ b/iceoryx_posh/source/roudi/port_manager.cpp @@ -155,13 +155,11 @@ void PortManager::doDiscoveryForPublisherPort(PublisherPortRouDiType& publisherP m_portIntrospection.reportMessage(caproMessage); if (capro::CaproMessageType::OFFER == caproMessage.m_type) { - this->addEntryToServiceRegistry(caproMessage.m_serviceDescription.getServiceIDString(), - caproMessage.m_serviceDescription.getInstanceIDString()); + this->addEntryToServiceRegistry(caproMessage.m_serviceDescription); } else if (capro::CaproMessageType::STOP_OFFER == caproMessage.m_type) { - this->removeEntryFromServiceRegistry(caproMessage.m_serviceDescription.getServiceIDString(), - caproMessage.m_serviceDescription.getInstanceIDString()); + this->removeEntryFromServiceRegistry(caproMessage.m_serviceDescription); } else { @@ -268,21 +266,19 @@ void PortManager::handleInterfaces() noexcept } } // also forward services from service registry - auto serviceMap = m_serviceRegistry.getServiceMap(); + /// @todo #415 do we still need this? yes but return a copy here to be stored in shared memory via new + /// StatusPort's + auto serviceVector = m_serviceRegistry.getServices(); caproMessage.m_subType = capro::CaproMessageSubType::SERVICE; - for (auto const& x : serviceMap) + for (auto const& element : serviceVector) { - for (auto& instance : x.second.instanceSet) - { - caproMessage.m_serviceDescription = capro::ServiceDescription(x.first, instance, roudi::Wildcard); + caproMessage.m_serviceDescription = element.serviceDescription; - for (auto& interfacePortData : interfacePortsForInitialForwarding) - { - auto interfacePort = popo::InterfacePort(interfacePortData); - interfacePort.dispatchCaProMessage(caproMessage); - } + for (auto& interfacePortData : interfacePortsForInitialForwarding) + { + popo::InterfacePort(interfacePortData).dispatchCaProMessage(caproMessage); } } } @@ -306,14 +302,12 @@ void PortManager::handleApplications() noexcept { case capro::CaproMessageType::OFFER: { - addEntryToServiceRegistry(serviceDescription.getServiceIDString(), - serviceDescription.getInstanceIDString()); + addEntryToServiceRegistry(caproMessage.m_serviceDescription); break; } case capro::CaproMessageType::STOP_OFFER: { - removeEntryFromServiceRegistry(serviceDescription.getServiceIDString(), - serviceDescription.getInstanceIDString()); + removeEntryFromServiceRegistry(caproMessage.m_serviceDescription); break; } default: @@ -550,8 +544,7 @@ void PortManager::destroyPublisherPort(PublisherPortRouDiType::MemberType_t* con cxx::Ensures(caproMessage.m_type == capro::CaproMessageType::STOP_OFFER); m_portIntrospection.reportMessage(caproMessage); - this->removeEntryFromServiceRegistry(caproMessage.m_serviceDescription.getServiceIDString(), - caproMessage.m_serviceDescription.getInstanceIDString()); + this->removeEntryFromServiceRegistry(caproMessage.m_serviceDescription); this->sendToAllMatchingSubscriberPorts(caproMessage, publisherPortRoudi); this->sendToAllMatchingInterfacePorts(caproMessage); }); @@ -600,17 +593,16 @@ runtime::IpcMessage PortManager::findService(const capro::IdString_t& service, interfacePort.dispatchCaProMessage(caproMessage); } - // add all found instances to instanceString - runtime::IpcMessage instanceMessage; + runtime::IpcMessage response; - ServiceRegistry::InstanceSet_t instances; - m_serviceRegistry.find(instances, service, instance); - for (auto& instance : instances) + ServiceRegistry::ServiceDescriptionVector_t searchResult; + m_serviceRegistry.find(searchResult, service, instance); + for (auto& service : searchResult) { - instanceMessage << instance; + response << static_cast(service.serviceDescription).toString(); } - return instanceMessage; + return response; } const std::atomic* PortManager::serviceRegistryChangeCounter() noexcept @@ -721,17 +713,18 @@ popo::ApplicationPortData* PortManager::acquireApplicationPortData(const Runtime } } -void PortManager::addEntryToServiceRegistry(const capro::IdString_t& service, - const capro::IdString_t& instance) noexcept +void PortManager::addEntryToServiceRegistry(const capro::ServiceDescription& service) noexcept { - m_serviceRegistry.add(service, instance); + m_serviceRegistry.add(service).or_else([&](auto&) { + LogWarn() << "Could not add service " << service.getServiceIDString() << " to service registry!"; + errorHandler(Error::kPOSH__PORT_MANAGER_COULD_NOT_ADD_SERVICE_TO_REGISTRY, nullptr, ErrorLevel::MODERATE); + }); m_portPool->serviceRegistryChangeCounter()->fetch_add(1, std::memory_order_relaxed); } -void PortManager::removeEntryFromServiceRegistry(const capro::IdString_t& service, - const capro::IdString_t& instance) noexcept +void PortManager::removeEntryFromServiceRegistry(const capro::ServiceDescription& service) noexcept { - m_serviceRegistry.remove(service, instance); + m_serviceRegistry.remove(service); m_portPool->serviceRegistryChangeCounter()->fetch_add(1, std::memory_order_relaxed); } diff --git a/iceoryx_posh/source/roudi/process_manager.cpp b/iceoryx_posh/source/roudi/process_manager.cpp index fef533562e..c61c1207bd 100644 --- a/iceoryx_posh/source/roudi/process_manager.cpp +++ b/iceoryx_posh/source/roudi/process_manager.cpp @@ -352,11 +352,10 @@ void ProcessManager::findServiceForProcess(const RuntimeName_t& name, searchForProcessAndThen( name, [&](Process& process) { - runtime::IpcMessage instanceString({m_portManager.findService(service, instance)}); - process.sendViaIpcChannel(instanceString); - LogDebug() << "Sent InstanceString to application " << name; + process.sendViaIpcChannel({m_portManager.findService(service, instance)}); + LogDebug() << "Sent all found services to application " << name; }, - [&]() { LogWarn() << "Unknown process " << name << " requested an InstanceString."; }); + [&]() { LogWarn() << "Unknown process " << name << " requested to find services."; }); } void ProcessManager::addInterfaceForProcess(const RuntimeName_t& name, diff --git a/iceoryx_posh/source/roudi/service_registry.cpp b/iceoryx_posh/source/roudi/service_registry.cpp index dc79b4c723..7ce87d8061 100644 --- a/iceoryx_posh/source/roudi/service_registry.cpp +++ b/iceoryx_posh/source/roudi/service_registry.cpp @@ -17,45 +17,156 @@ #include "iceoryx_posh/internal/roudi/service_registry.hpp" +#include + namespace iox { namespace roudi { -void ServiceRegistry::add(const capro::IdString_t& service, const capro::IdString_t& instance) +cxx::expected ServiceRegistry::add(const capro::ServiceDescription& serviceDescription) noexcept { - cxx::set::add(m_serviceMap[service].instanceSet, instance); + // Forbid duplicate service descriptions entries + for (auto& element : m_serviceDescriptionVector) + { + if (element.serviceDescription == serviceDescription) + { + // Due to n:m communication we don't store twice but increase the reference counter + element.referenceCounter++; + return cxx::success<>(); + } + } + uint64_t referenceCounter = 1U; + if (!m_serviceDescriptionVector.push_back({serviceDescription, referenceCounter})) + { + return cxx::error(Error::SERVICE_REGISTRY_FULL); + } + + auto serviceIndex = m_serviceDescriptionVector.size() - 1; + m_serviceMap.insert({serviceDescription.getServiceIDString(), serviceIndex}); + m_instanceMap.insert({serviceDescription.getInstanceIDString(), serviceIndex}); + return cxx::success<>(); } -void ServiceRegistry::remove(const capro::IdString_t& service, const capro::IdString_t& instance) +bool ServiceRegistry::remove(const capro::ServiceDescription& serviceDescription) noexcept { - cxx::set::remove(m_serviceMap[service].instanceSet, instance); + bool removedElement{false}; + uint64_t index = 0U; + for (auto iterator = m_serviceDescriptionVector.begin(); iterator != m_serviceDescriptionVector.end();) + { + auto& element = m_serviceDescriptionVector[index].serviceDescription; + if (element == serviceDescription) + { + auto& refCounter = m_serviceDescriptionVector[index].referenceCounter; + --refCounter; + if (refCounter == 0) + { + m_serviceDescriptionVector.erase(iterator); + removedElement = true; + } + else + { + return true; + } + // There can't be more than one element + break; + } + ++index; + ++iterator; + } + + auto removeIndexFromMap = [](std::multimap& map, uint64_t index) { + for (auto it = map.begin(); it != map.end();) + { + if (it->second == index) + { + it = map.erase(it); + continue; + } + else if (it->second > index) + { + // update index due to removed element + it->second--; + } + it++; + } + }; + + if (removedElement) + { + removeIndexFromMap(m_serviceMap, index); + removeIndexFromMap(m_instanceMap, index); + } + + return removedElement; } -void ServiceRegistry::find(InstanceSet_t& instances, +void ServiceRegistry::find(ServiceDescriptionVector_t& searchResult, const capro::IdString_t& service, - const capro::IdString_t& instance) const + const capro::IdString_t& instance) const noexcept { - if (instance == Wildcard) + cxx::vector intersection; + + // Find (K1, K2) + // O(log n + log n + max(#PossibleServices + #possiblesInstances) + #intersection) + if (instance != Wildcard && service != Wildcard) + { + cxx::vector possibleServices; + cxx::vector possibleInstances; + + auto rangeServiceMap = m_serviceMap.equal_range(service); + for (auto entry = rangeServiceMap.first; entry != rangeServiceMap.second; ++entry) + { + possibleServices.push_back(entry->second); + } + + auto rangeInstanceMap = m_instanceMap.equal_range(instance); + for (auto entry = rangeInstanceMap.first; entry != rangeInstanceMap.second; ++entry) + { + possibleInstances.push_back(entry->second); + } + + ::std::set_intersection(possibleServices.begin(), + possibleServices.end(), + possibleInstances.begin(), + possibleInstances.end(), + ::std::back_inserter(intersection)); + + for (auto& value : intersection) + { + searchResult.push_back(m_serviceDescriptionVector[value]); + } + } + // Find (*, K2) + // O(log n + #result) + else if (service == Wildcard && instance != Wildcard) { - for (auto& instance : m_serviceMap[service].instanceSet) + auto range = m_instanceMap.equal_range(instance); + for (auto entry = range.first; entry != range.second; ++entry) { - instances.push_back(instance); + searchResult.push_back(m_serviceDescriptionVector[entry->second]); } } - else + // Find (K1, *) + // O(log n + #result) + else if (instance == Wildcard && service != Wildcard) { - auto& instanceSet = m_serviceMap[service].instanceSet; - auto iter = std::find(instanceSet.begin(), instanceSet.end(), instance); - if (iter != instanceSet.end()) + auto range = m_serviceMap.equal_range(service); + for (auto entry = range.first; entry != range.second; ++entry) { - instances.push_back(*iter); + searchResult.push_back(m_serviceDescriptionVector[entry->second]); } } + else + { + // Find (*, *) + // O(n) + searchResult = m_serviceDescriptionVector; + } } -const ServiceRegistry::serviceMap_t& ServiceRegistry::getServiceMap() const +const ServiceRegistry::ServiceDescriptionVector_t ServiceRegistry::getServices() const noexcept { - return m_serviceMap; + return m_serviceDescriptionVector; } } // namespace roudi } // namespace iox diff --git a/iceoryx_posh/source/runtime/ipc_interface_base.cpp b/iceoryx_posh/source/runtime/ipc_interface_base.cpp index 9f7a326764..fd293d8eb0 100644 --- a/iceoryx_posh/source/runtime/ipc_interface_base.cpp +++ b/iceoryx_posh/source/runtime/ipc_interface_base.cpp @@ -120,7 +120,7 @@ bool IpcInterfaceBase::send(const IpcMessage& msg) const noexcept { const size_t messageSize = static_cast(msg.getMessage().size()) + platform::IoxIpcChannelType::NULL_TERMINATOR_SIZE; - LogError() << "msg size of " << messageSize << "bigger than configured max message size"; + LogError() << "msg size of " << messageSize << " bigger than configured max message size"; } }; return !m_ipcChannel.send(msg.getMessage()).or_else(logLengthError).has_error(); @@ -140,7 +140,7 @@ bool IpcInterfaceBase::timedSend(const IpcMessage& msg, units::Duration timeout) { const size_t messageSize = static_cast(msg.getMessage().size()) + platform::IoxIpcChannelType::NULL_TERMINATOR_SIZE; - LogError() << "msg size of " << messageSize << "bigger than configured max message size"; + LogError() << "msg size of " << messageSize << " bigger than configured max message size"; } }; return !m_ipcChannel.timedSend(msg.getMessage(), timeout).or_else(logLengthError).has_error(); diff --git a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp index a8f446f546..6513707b0d 100644 --- a/iceoryx_posh/source/runtime/posh_runtime_impl.cpp +++ b/iceoryx_posh/source/runtime/posh_runtime_impl.cpp @@ -17,6 +17,7 @@ #include "iceoryx_posh/internal/runtime/posh_runtime_impl.hpp" +#include "iceoryx_hoofs/cxx/algorithm.hpp" #include "iceoryx_hoofs/cxx/convert.hpp" #include "iceoryx_hoofs/cxx/helplets.hpp" #include "iceoryx_hoofs/cxx/variant.hpp" @@ -372,9 +373,9 @@ NodeData* PoshRuntimeImpl::createNode(const NodeProperty& nodeProperty) noexcept return nullptr; } -cxx::expected -PoshRuntimeImpl::findService(const cxx::variant service, - const cxx::variant instance) noexcept +cxx::expected +PoshRuntimeImpl::findService(const cxx::variant service, + const cxx::variant instance) noexcept { /// @todo #415 remove the string mapping, once the find call is done via shared memory capro::IdString_t serviceString; @@ -410,26 +411,26 @@ PoshRuntimeImpl::findService(const cxx::variant servic return cxx::error(FindServiceError::UNABLE_TO_WRITE_TO_ROUDI_CHANNEL); } - InstanceContainer instanceContainer; + ServiceContainer serviceContainer; uint32_t numberOfElements = requestResponse.getNumberOfElements(); - uint32_t capacity = static_cast(instanceContainer.capacity()); + uint32_t capacity = static_cast(serviceContainer.capacity()); - // Limit the instances (max value is the capacity of instanceContainer) - uint32_t numberOfInstances = ((numberOfElements > capacity) ? capacity : numberOfElements); - for (uint32_t i = 0; i < numberOfInstances; ++i) + // Limit the services (max value is the capacity of serviceContainer) + uint32_t numberOfServices = algorithm::min(capacity, numberOfElements); + for (uint32_t i = 0U; i < numberOfServices; ++i) { - capro::IdString_t instance(iox::cxx::TruncateToCapacity, requestResponse.getElementAtIndex(i).c_str()); - instanceContainer.push_back(instance); + capro::ServiceDescription service(cxx::Serialization(requestResponse.getElementAtIndex(i))); + serviceContainer.push_back(service); } if (numberOfElements > capacity) { LogWarn() << numberOfElements << " instances found for service \"" << serviceString - << "\" which is more than supported number of instances(" << MAX_NUMBER_OF_INSTANCES << "\n"; + << "\" which is more than supported number of services(" << MAX_NUMBER_OF_SERVICES << "\n"; errorHandler(Error::kPOSH__SERVICE_DISCOVERY_INSTANCE_CONTAINER_OVERFLOW, nullptr, ErrorLevel::MODERATE); return cxx::error(FindServiceError::INSTANCE_CONTAINER_OVERFLOW); } - return {cxx::success(instanceContainer)}; + return {cxx::success(serviceContainer)}; } diff --git a/iceoryx_posh/test/integrationtests/test_roudi_findservice.cpp b/iceoryx_posh/test/integrationtests/test_roudi_findservice.cpp index 4cde978afb..b42263163c 100644 --- a/iceoryx_posh/test/integrationtests/test_roudi_findservice.cpp +++ b/iceoryx_posh/test/integrationtests/test_roudi_findservice.cpp @@ -22,7 +22,8 @@ namespace { using iox::capro::IdString_t; -using iox::runtime::InstanceContainer; +using iox::capro::ServiceDescription; +using iox::runtime::ServiceContainer; class RoudiFindService_test : public RouDi_GTest { @@ -44,10 +45,11 @@ TEST_F(RoudiFindService_test, OfferSingleMethodServiceSingleInstance) auto isServiceOffered = senderRuntime->offerService({"service1", "instance1", "event1"}); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); ASSERT_EQ(true, isServiceOffered); } @@ -86,10 +88,11 @@ TEST_F(RoudiFindService_test, ReofferedServiceWithValidServiceDescriptionCanBeFo EXPECT_TRUE(senderRuntime->offerService({"service1", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); } TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant) @@ -99,10 +102,11 @@ TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant) EXPECT_TRUE(senderRuntime->offerService({"service1", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); } TEST_F(RoudiFindService_test, FindSameServiceMultipleTimesReturnsSingleInstance) @@ -110,13 +114,15 @@ TEST_F(RoudiFindService_test, FindSameServiceMultipleTimesReturnsSingleInstance) EXPECT_TRUE(senderRuntime->offerService({"service1", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); } TEST_F(RoudiFindService_test, OfferMultiMethodServiceSingleInstance) @@ -126,17 +132,20 @@ TEST_F(RoudiFindService_test, OfferMultiMethodServiceSingleInstance) EXPECT_TRUE(senderRuntime->offerService({"service3", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service3"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + serviceContainer = receiverRuntime->findService(IdString_t("service3"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service3", "instance1", "event1"})); } TEST_F(RoudiFindService_test, OfferMultiMethodServiceWithDistinctSingleInstance) @@ -145,16 +154,19 @@ TEST_F(RoudiFindService_test, OfferMultiMethodServiceWithDistinctSingleInstance) EXPECT_TRUE(senderRuntime->offerService({"service2", "instance2", "event2"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance2")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance2"))); + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance2")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance2", "event2"})); } TEST_F(RoudiFindService_test, SubscribeAnyInstance) @@ -163,16 +175,15 @@ TEST_F(RoudiFindService_test, SubscribeAnyInstance) EXPECT_TRUE(senderRuntime->offerService({"service1", "instance2", "event2"})); EXPECT_TRUE(senderRuntime->offerService({"service1", "instance3", "event3"})); this->InterOpWait(); - InstanceContainer instanceContainerExp; - instanceContainerExp.push_back("instance1"); - instanceContainerExp.push_back("instance2"); - instanceContainerExp.push_back("instance3"); - - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), iox::runtime::Any_t()); - - - ASSERT_THAT(instanceContainer.value().size(), Eq(3u)); - EXPECT_TRUE(instanceContainer.value() == instanceContainerExp); + ServiceContainer serviceContainerExp; + serviceContainerExp.push_back({"service1", "instance1", "event1"}); + serviceContainerExp.push_back({"service1", "instance2", "event2"}); + serviceContainerExp.push_back({"service1", "instance3", "event3"}); + + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), iox::runtime::Wildcard_t()); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(3u)); + EXPECT_TRUE(serviceContainer.value() == serviceContainerExp); } TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance) @@ -182,17 +193,20 @@ TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance) EXPECT_TRUE(senderRuntime->offerService({"service1", "instance3", "event3"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance2")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance2"))); + serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance2")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance2", "event2"})); - instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance3")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance3"))); + serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance3")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance3", "event3"})); } TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance) @@ -205,29 +219,35 @@ TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance) EXPECT_TRUE(senderRuntime->offerService({"service2", "instance3", "event3"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); - - instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance2")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance2"))); - - instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance3")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance3"))); - - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); - - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance2")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance2"))); - - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance3")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance3"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); + + serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance2")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance2", "event2"})); + + serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance3")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance3", "event3"})); + + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance1", "event1"})); + + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance2")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance2", "event2"})); + + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance3")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance3", "event3"})); } TEST_F(RoudiFindService_test, StopOfferWithInvalidServiceDescriptionFails) @@ -243,8 +263,9 @@ TEST_F(RoudiFindService_test, StopOfferSingleMethodServiceSingleInstance) EXPECT_TRUE(senderRuntime->stopOfferService({"service1", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); } TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance) @@ -257,15 +278,18 @@ TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance) EXPECT_TRUE(senderRuntime->stopOfferService({"service3", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); - instanceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(1u)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + serviceContainer = receiverRuntime->findService(IdString_t("service2"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1u)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service2", "instance1", "event1"})); - instanceContainer = receiverRuntime->findService(IdString_t("service3"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + serviceContainer = receiverRuntime->findService(IdString_t("service3"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); } TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall) @@ -277,9 +301,9 @@ TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall) EXPECT_TRUE(senderRuntime->stopOfferService({"service1", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); } @@ -290,10 +314,10 @@ TEST_F(RoudiFindService_test, StopNonExistingService) EXPECT_TRUE(senderRuntime->stopOfferService({"service2", "instance2", "event2"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); - - ASSERT_THAT(instanceContainer.value().size(), Eq(1)); - ASSERT_THAT(*instanceContainer.value().begin(), Eq(IdString_t("instance1"))); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(1)); + ASSERT_THAT(*serviceContainer.value().begin(), Eq(ServiceDescription{"service1", "instance1", "event1"})); } TEST_F(RoudiFindService_test, FindNonExistingServices) @@ -303,14 +327,17 @@ TEST_F(RoudiFindService_test, FindNonExistingServices) EXPECT_TRUE(senderRuntime->offerService({"service3", "instance1", "event1"})); this->InterOpWait(); - auto instanceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("schlomo")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + auto serviceContainer = receiverRuntime->findService(IdString_t("service1"), IdString_t("schlomo")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); - instanceContainer = receiverRuntime->findService(IdString_t("ignatz"), IdString_t("instance1")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + serviceContainer = receiverRuntime->findService(IdString_t("ignatz"), IdString_t("instance1")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); - instanceContainer = receiverRuntime->findService(IdString_t("ignatz"), IdString_t("schlomo")); - ASSERT_THAT(instanceContainer.value().size(), Eq(0u)); + serviceContainer = receiverRuntime->findService(IdString_t("ignatz"), IdString_t("schlomo")); + ASSERT_FALSE(serviceContainer.has_error()); + ASSERT_THAT(serviceContainer.value().size(), Eq(0u)); } TEST_F(RoudiFindService_test, InterfacePort) @@ -328,7 +355,7 @@ TEST_F(RoudiFindService_test, InterfacePort) auto caproMessage = maybeCaProMessage.value(); if ((caproMessage.m_serviceDescription.getServiceIDString() == IdString_t("service1")) && (caproMessage.m_serviceDescription.getInstanceIDString() == IdString_t("instance1")) - && ((caproMessage.m_serviceDescription.getEventIDString() == IdString_t(iox::roudi::Wildcard)))) + && ((caproMessage.m_serviceDescription.getEventIDString() == IdString_t("event1")))) { serviceFound = true; break; @@ -338,42 +365,41 @@ TEST_F(RoudiFindService_test, InterfacePort) EXPECT_THAT(serviceFound, Eq(true)); } -TEST_F(RoudiFindService_test, findServiceMaxInstances) +TEST_F(RoudiFindService_test, findServiceMaxServices) { - size_t noOfInstances = iox::MAX_NUMBER_OF_INSTANCES; - InstanceContainer instanceContainerExp; - for (size_t i = 0; i < noOfInstances; i++) + ServiceContainer serviceContainerExp; + for (size_t i = 0; i < iox::MAX_NUMBER_OF_SERVICES; i++) { // Service & Instance string is kept short , to reduce the response size in find service request , // (message queue has a limit of 512) std::string instance = "i" + iox::cxx::convert::toString(i); EXPECT_TRUE(senderRuntime->offerService({"s", IdString_t(iox::cxx::TruncateToCapacity, instance), "foo"})); - instanceContainerExp.push_back(IdString_t(iox::cxx::TruncateToCapacity, instance)); + serviceContainerExp.push_back({"s", IdString_t(iox::cxx::TruncateToCapacity, instance), "foo"}); this->InterOpWait(); } - auto instanceContainer = receiverRuntime->findService(IdString_t("s"), iox::runtime::Any_t()); + auto serviceContainer = receiverRuntime->findService(IdString_t("s"), iox::runtime::Wildcard_t()); - EXPECT_THAT(instanceContainer.value().size(), Eq(iox::MAX_NUMBER_OF_INSTANCES)); - EXPECT_TRUE(instanceContainer.value() == instanceContainerExp); - ASSERT_THAT(instanceContainer.has_error(), Eq(false)); -} // namespace + ASSERT_FALSE(serviceContainer.has_error()); + EXPECT_THAT(serviceContainer.value().size(), Eq(iox::MAX_NUMBER_OF_SERVICES)); + EXPECT_TRUE(serviceContainer.value() == serviceContainerExp); +} -TEST_F(RoudiFindService_test, findServiceInstanceContainerOverflowError) +TEST_F(RoudiFindService_test, findServiceserviceContainerOverflowError) { - size_t noOfInstances = (iox::MAX_NUMBER_OF_INSTANCES + 1); - InstanceContainer instanceContainerExp; + size_t noOfInstances = (iox::MAX_NUMBER_OF_SERVICES + 1); + ServiceContainer serviceContainerExp; for (size_t i = 0; i < noOfInstances; i++) { std::string instance = "i" + iox::cxx::convert::toString(i); EXPECT_TRUE(senderRuntime->offerService({"s", IdString_t(iox::cxx::TruncateToCapacity, instance), "foo"})); - instanceContainerExp.push_back(IdString_t(iox::cxx::TruncateToCapacity, instance)); + serviceContainerExp.push_back({"s", IdString_t(iox::cxx::TruncateToCapacity, instance), "foo"}); this->InterOpWait(); } - auto instanceContainer = receiverRuntime->findService(IdString_t("s"), iox::runtime::Any_t()); + auto serviceContainer = receiverRuntime->findService(IdString_t("s"), iox::runtime::Wildcard_t()); - ASSERT_THAT(instanceContainer.has_error(), Eq(true)); + ASSERT_THAT(serviceContainer.has_error(), Eq(true)); } } // namespace diff --git a/iceoryx_posh/test/mocks/posh_runtime_mock.hpp b/iceoryx_posh/test/mocks/posh_runtime_mock.hpp index fef3e5bdcd..aecd923ff7 100644 --- a/iceoryx_posh/test/mocks/posh_runtime_mock.hpp +++ b/iceoryx_posh/test/mocks/posh_runtime_mock.hpp @@ -47,9 +47,9 @@ class PoshRuntimeMock : public iox::runtime::PoshRuntime /// @todo iox-#841 simplify this when we switch to gmock v1.10 MOCK_METHOD2(findServiceMock, - iox::cxx::expected( - const iox::cxx::variant, - const iox::cxx::variant)); + iox::cxx::expected( + const iox::cxx::variant, + const iox::cxx::variant)); MOCK_METHOD1(offerServiceMock, bool(const iox::capro::ServiceDescription&)); MOCK_METHOD1(stopOfferServiceMock, bool(const iox::capro::ServiceDescription&)); MOCK_METHOD3(getMiddlewarePublisherMock, @@ -89,9 +89,9 @@ class PoshRuntimeMock : public iox::runtime::PoshRuntime return runtime; } - iox::cxx::expected - findService(const iox::cxx::variant service, - const iox::cxx::variant instance) noexcept override + iox::cxx::expected + findService(const iox::cxx::variant service, + const iox::cxx::variant instance) noexcept override { return findServiceMock(service, instance); } diff --git a/iceoryx_posh/test/moduletests/test_base_port.cpp b/iceoryx_posh/test/moduletests/test_base_port.cpp index 946b85c9b9..2f1f2cd105 100644 --- a/iceoryx_posh/test/moduletests/test_base_port.cpp +++ b/iceoryx_posh/test/moduletests/test_base_port.cpp @@ -104,12 +104,12 @@ const ServiceDescription& expectedServiceDescription() template <> const ServiceDescription& expectedServiceDescription() { - return SERVICE_DESCRIPTION_EMPTY; + return SERVICE_DESCRIPTION_VALID; } template <> const ServiceDescription& expectedServiceDescription() { - return SERVICE_DESCRIPTION_EMPTY; + return SERVICE_DESCRIPTION_VALID; } // expected ProcessName factories @@ -169,7 +169,7 @@ class BasePort_test : public Test TYPED_TEST(BasePort_test, CallingGetCaProServiceDescriptionWorks) { using PortData_t = typename TestFixture::PortData_t; - EXPECT_THAT(this->sut.getCaProServiceDescription(), Ne(expectedServiceDescription())); + EXPECT_THAT(this->sut.getCaProServiceDescription(), Eq(expectedServiceDescription())); } TYPED_TEST(BasePort_test, CallingGetRuntimeNameWorks) diff --git a/iceoryx_posh/test/moduletests/test_posh_runtime.cpp b/iceoryx_posh/test/moduletests/test_posh_runtime.cpp index 5127d4bc5e..54a073b28f 100644 --- a/iceoryx_posh/test/moduletests/test_posh_runtime.cpp +++ b/iceoryx_posh/test/moduletests/test_posh_runtime.cpp @@ -672,15 +672,22 @@ TEST_F(PoshRuntime_test, OfferEmptyServiceIsInvalid) EXPECT_FALSE(isServiceOffered); } -TEST_F(PoshRuntime_test, FindServiceReturnsNoInstanceForDefaultDescription) +TEST_F(PoshRuntime_test, FindServiceWithWildcardsReturnsOnlyIntrospectionServices) { PoshRuntime* m_receiverRuntime{&iox::runtime::PoshRuntime::initRuntime("subscriber")}; - m_runtime->offerService(iox::capro::ServiceDescription()); + EXPECT_FALSE(m_runtime->offerService(iox::capro::ServiceDescription())); this->InterOpWait(); - auto instanceContainer = m_receiverRuntime->findService(iox::runtime::Any_t(), iox::runtime::Any_t()); - EXPECT_THAT(0u, instanceContainer.value().size()); + auto serviceContainer = m_receiverRuntime->findService(iox::runtime::Wildcard_t(), iox::runtime::Wildcard_t()); + ASSERT_FALSE(serviceContainer.has_error()); + + auto searchResult = serviceContainer.value(); + + for (auto& service : searchResult) + { + EXPECT_THAT(service.getServiceIDString().c_str(), StrEq("Introspection")); + } } TEST_F(PoshRuntime_test, ShutdownUnblocksBlockingPublisher) diff --git a/iceoryx_posh/test/moduletests/test_roudi_service_registry.cpp b/iceoryx_posh/test/moduletests/test_roudi_service_registry.cpp index 56c9ddf03d..ed640d0b54 100644 --- a/iceoryx_posh/test/moduletests/test_roudi_service_registry.cpp +++ b/iceoryx_posh/test/moduletests/test_roudi_service_registry.cpp @@ -43,23 +43,175 @@ class ServiceRegistry_test : public Test } } iox::roudi::ServiceRegistry registry; - iox::roudi::ServiceRegistry::InstanceSet_t searchResults; + + iox::roudi::ServiceRegistry::ServiceDescriptionVector_t searchResults; }; -TEST_F(ServiceRegistry_test, SingleAdd) +TEST_F(ServiceRegistry_test, AddNoServiceDescriptionsAndWildcardSearchReturnsNothing) +{ + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(0)); +} + +TEST_F(ServiceRegistry_test, AddMaximumNumberOfServiceDescriptionsWorks) +{ + iox::cxx::vector services; + + for (uint64_t i = 0U; i < ServiceRegistry::MAX_SERVICE_DESCRIPTIONS; i++) + { + services.push_back(iox::capro::ServiceDescription( + "Foo", "Bar", iox::capro::IdString_t(iox::cxx::TruncateToCapacity, iox::cxx::convert::toString(i)))); + } + + for (auto& service : services) + { + auto result = registry.add(service); + ASSERT_FALSE(result.has_error()); + } +} + +TEST_F(ServiceRegistry_test, AddMoreThanMaximumNumberOfServiceDescriptionsFails) { - registry.add("a", "b"); + iox::cxx::vector services; + + for (uint64_t i = 0U; i < ServiceRegistry::MAX_SERVICE_DESCRIPTIONS; i++) + { + services.push_back(iox::capro::ServiceDescription( + "Foo", "Bar", iox::capro::IdString_t(iox::cxx::TruncateToCapacity, iox::cxx::convert::toString(i)))); + } + + for (auto& service : services) + { + auto result = registry.add(service); + ASSERT_FALSE(result.has_error()); + } + + auto result = registry.add(iox::capro::ServiceDescription("Foo", "Bar", "Baz")); + ASSERT_TRUE(result.has_error()); + EXPECT_THAT(result.get_error(), Eq(ServiceRegistry::Error::SERVICE_REGISTRY_FULL)); +} + +TEST_F(ServiceRegistry_test, AddServiceDescriptionsWhichWasAlreadyAddedAndReturnsOneResult) +{ + auto result1 = registry.add(ServiceDescription("Li", "La", "Launebaer")); + ASSERT_FALSE(result1.has_error()); + + auto result2 = registry.add(ServiceDescription("Li", "La", "Launebaer")); + ASSERT_FALSE(result2.has_error()); + + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription("Li", "La", "Launebaer"))); + EXPECT_THAT(searchResults[0].referenceCounter, Eq(2)); +} + +TEST_F(ServiceRegistry_test, AddServiceDescriptionsTwiceAndRemoveOnceAndReturnsOneResult) +{ + auto result1 = registry.add(ServiceDescription("Li", "La", "Launebaerli")); + ASSERT_FALSE(result1.has_error()); + + auto result2 = registry.add(ServiceDescription("Li", "La", "Launebaerli")); + ASSERT_FALSE(result2.has_error()); + + registry.remove(ServiceDescription("Li", "La", "Launebaerli")); + + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription("Li", "La", "Launebaerli"))); + EXPECT_THAT(searchResults[0].referenceCounter, Eq(1)); +} + +TEST_F(ServiceRegistry_test, AddInvalidServiceDescriptionsWorks) +{ + auto result = registry.add(ServiceDescription()); + ASSERT_FALSE(result.has_error()); +} + +TEST_F(ServiceRegistry_test, RemovingServiceDescriptionsWhichWasntAddedFails) +{ + EXPECT_FALSE(registry.remove(ServiceDescription("Sim", "Sa", "Lambim"))); +} + +TEST_F(ServiceRegistry_test, RemovingInvalidServiceDescriptionsWorks) +{ + ASSERT_FALSE(registry.add(ServiceDescription()).has_error()); + EXPECT_TRUE(registry.remove(ServiceDescription())); +} + +TEST_F(ServiceRegistry_test, SingleInvalidServiceDescriptionsCanBeFoundWithWildcardSearch) +{ + ASSERT_FALSE(registry.add(ServiceDescription()).has_error()); + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription())); +} + +TEST_F(ServiceRegistry_test, SingleInvalidServiceDescriptionsCanBeFoundWithEmptyString) +{ + ASSERT_FALSE(registry.add(ServiceDescription()).has_error()); + registry.find(searchResults, "", ""); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription())); +} + +TEST_F(ServiceRegistry_test, SingleServiceDescriptionCanBeFoundWithWildcardSearch) +{ + auto result = registry.add(ServiceDescription("Foo", "Bar", "Baz")); + ASSERT_FALSE(result.has_error()); + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription("Foo", "Bar", "Baz"))); +} + +TEST_F(ServiceRegistry_test, SingleServiceDescriptionCanBeFoundWithInstanceName) +{ + auto result = registry.add(ServiceDescription("Baz", "Bar", "Foo")); + ASSERT_FALSE(result.has_error()); + registry.find(searchResults, Wildcard, "Bar"); + + EXPECT_THAT(searchResults.size(), Eq(1)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(ServiceDescription("Baz", "Bar", "Foo"))); +} + +TEST_F(ServiceRegistry_test, SingleServiceDescriptionCanBeFoundWithServiceName) +{ + iox::capro::ServiceDescription service1("a", "b", "c"); + ASSERT_FALSE(registry.add(service1).has_error()); registry.find(searchResults, "a", Wildcard); EXPECT_THAT(searchResults.size(), Eq(1)); - EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b"))); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(service1)); +} + +TEST_F(ServiceRegistry_test, ValidAndInvalidServiceDescriptionsCanAllBeFoundWithWildcardSearch) +{ + ServiceDescription service1; + ServiceDescription service2("alpha", "bravo", "charlie"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + registry.find(searchResults, Wildcard, Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(2)); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(service1)); + EXPECT_THAT(searchResults[1].serviceDescription, Eq(service2)); } -TEST_F(ServiceRegistry_test, SingleMultiAdd) +TEST_F(ServiceRegistry_test, MultipleServiceDescriptionWithSameServiceNameCanAllBeFound) { - registry.add("a", "b"); - registry.add("a", "c"); - registry.add("a", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); registry.find(searchResults, "a", Wildcard); EXPECT_THAT(searchResults.size(), Eq(3)); @@ -70,123 +222,175 @@ TEST_F(ServiceRegistry_test, SingleMultiAdd) for (auto& e : searchResults) { - if (e == iox::cxx::string<100>("b")) + if (e.serviceDescription == service1) hasFoundB = true; - if (e == iox::cxx::string<100>("c")) + if (e.serviceDescription == service2) hasFoundC = true; - if (e == iox::cxx::string<100>("d")) + if (e.serviceDescription == service3) hasFoundD = true; } EXPECT_THAT(hasFoundB && hasFoundC && hasFoundD, Eq(true)); } -TEST_F(ServiceRegistry_test, SingleAddMultiService) +TEST_F(ServiceRegistry_test, MultipleServiceDescriptionWithDifferentServiceNameCanAllBeFound) { - registry.add("a", "b"); - registry.add("c", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("c", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); registry.find(searchResults, "a", Wildcard); EXPECT_THAT(searchResults.size(), Eq(1)); - EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("b"))); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(service1)); searchResults.clear(); registry.find(searchResults, "c", Wildcard); EXPECT_THAT(searchResults.size(), Eq(1)); - EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("d"))); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(service2)); } -TEST_F(ServiceRegistry_test, FindSpecificInstance) +TEST_F(ServiceRegistry_test, MultipleServiceDescriptionWithSameServiceNameFindsSpecificService) { - registry.add("a", "b"); - registry.add("a", "c"); - registry.add("a", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); registry.find(searchResults, "a", "c"); EXPECT_THAT(searchResults.size(), Eq(1)); - EXPECT_THAT(searchResults[0], Eq(iox::cxx::string<100>("c"))); + EXPECT_THAT(searchResults[0].serviceDescription, Eq(service2)); } -TEST_F(ServiceRegistry_test, FindSpecificNonExistingInstance) +TEST_F(ServiceRegistry_test, MultipleServiceDescriptionAddedInNonLinearOrderFindsCorrectServices) { - registry.add("a", "b"); - registry.add("a", "c"); - registry.add("a", "d"); + iox::capro::ServiceDescription service1("a", "1", "moep"); + iox::capro::ServiceDescription service2("b", "2", "moep"); + iox::capro::ServiceDescription service3("c", "3", "moep"); + iox::capro::ServiceDescription service4("d", "4", "moep"); + iox::capro::ServiceDescription service5("e", "5", "moep"); + + ASSERT_FALSE(registry.add(service5).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); + ASSERT_FALSE(registry.add(service4).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service1).has_error()); + + ASSERT_TRUE(registry.remove(service5)); + ASSERT_TRUE(registry.remove(service1)); + registry.find(searchResults, "a", Wildcard); + + EXPECT_THAT(searchResults.size(), Eq(0)); +} + +TEST_F(ServiceRegistry_test, FindSpecificNonExistingServiceDescriptionFails) +{ + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); registry.find(searchResults, "a", "g"); EXPECT_THAT(searchResults.size(), Eq(0)); } -TEST_F(ServiceRegistry_test, RemoveSingle) +TEST_F(ServiceRegistry_test, AddingMultipleServiceDescriptionWithSameServicesAndRemovingSpecificDoesNotFindSpecific) { - registry.add("a", "b"); - registry.add("a", "c"); - registry.add("a", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); - registry.remove("a", "c"); + EXPECT_TRUE(registry.remove(service2)); registry.find(searchResults, "a", "c"); EXPECT_THAT(searchResults.size(), Eq(0)); } -TEST_F(ServiceRegistry_test, RemoveSingleFromMultipleServices) +TEST_F(ServiceRegistry_test, + AddingMultipleServiceDescriptionWithDifferentServicesAndRemovingSpecificDoesNotFindSpecific) { - registry.add("a", "b"); - registry.add("b", "c"); - registry.add("c", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("b", "c", "c"); + iox::capro::ServiceDescription service3("c", "d", "d"); - registry.remove("b", "c"); + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); + + EXPECT_TRUE(registry.remove(service2)); registry.find(searchResults, "b", "c"); EXPECT_THAT(searchResults.size(), Eq(0)); } -TEST_F(ServiceRegistry_test, RemoveAll) +TEST_F(ServiceRegistry_test, AddingMultipleServiceDescriptionAndRemovingAllDoesNotFindAnything) { - registry.add("a", "b"); - registry.add("a", "c"); - registry.add("a", "d"); + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + + ASSERT_FALSE(registry.add(service1).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); - registry.remove("a", "b"); - registry.remove("a", "c"); - registry.remove("a", "d"); + EXPECT_TRUE(registry.remove(service1)); + EXPECT_TRUE(registry.remove(service2)); + EXPECT_TRUE(registry.remove(service3)); registry.find(searchResults, "a", Wildcard); EXPECT_THAT(searchResults.size(), Eq(0)); } -TEST_F(ServiceRegistry_test, GetServiceMap) +TEST_F(ServiceRegistry_test, AddingVariousServiceDescriptionAndGetServicesDoesNotReturnDuplicate) { - iox::roudi::ServiceRegistry::serviceMap_t serviceMap; + iox::capro::ServiceDescription service1("a", "b", "b"); + iox::capro::ServiceDescription service2("a", "c", "c"); + iox::capro::ServiceDescription service3("a", "d", "d"); + iox::capro::ServiceDescription service4("e", "f", "f"); - registry.add("a", "b"); + ASSERT_FALSE(registry.add(service1).has_error()); // add same service a, instance c to check if in registry only one entry is created - registry.add("a", "c"); - registry.add("a", "c"); - registry.add("a", "d"); - registry.add("e", "f"); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service2).has_error()); + ASSERT_FALSE(registry.add(service3).has_error()); + ASSERT_FALSE(registry.add(service4).has_error()); - serviceMap = registry.getServiceMap(); + auto serviceDescriptionVector = registry.getServices(); - bool mapA = false; - bool mapE = false; + bool service1Found = false; + bool service2Found = false; + bool service4Found = false; - for (auto const& x : serviceMap) + for (auto const& element : serviceDescriptionVector) { - if (x.first == iox::cxx::string<100>("a")) + if (element.serviceDescription == service1) { - ASSERT_THAT(x.second.instanceSet.size(), Eq(3)); - mapA = true; - EXPECT_THAT(x.second.instanceSet[0], Eq(iox::cxx::string<100>("b"))); - EXPECT_THAT(x.second.instanceSet[1], Eq(iox::cxx::string<100>("c"))); - EXPECT_THAT(x.second.instanceSet[2], Eq(iox::cxx::string<100>("d"))); + service1Found = true; } - if (x.first == iox::cxx::string<100>("e")) - mapE = true; - } + if (element.serviceDescription == service2) + { + service2Found = true; + } - EXPECT_THAT(mapA && mapE, Eq(true)); + if (element.serviceDescription == service4) + { + service4Found = true; + } + } + EXPECT_THAT(serviceDescriptionVector.size(), Eq(4)); + EXPECT_THAT(service1Found && service2Found && service4Found, Eq(true)); } } // namespace