diff --git a/src/socom/doc/design/40_behavioral_view.adoc b/src/socom/doc/design/40_behavioral_view.adoc index 19a4e9cf..83ea72d3 100644 --- a/src/socom/doc/design/40_behavioral_view.adoc +++ b/src/socom/doc/design/40_behavioral_view.adoc @@ -101,18 +101,6 @@ Consequently, update_event() satisfies the event update request implicitly. include::models/interaction_diagram_field_notification_communication.puml[] .... -== Service Gateway - find service - -The creation of client connectors is forwarded to bridges as request_service() calls. -Service bridges look up the required service instance within their domain. -If available, they connect to the remote counterpart and locally create a proxy server connector (forwarding all communication). - -.Interaction diagram: Service Gateway - find service -[plantuml, svg, align="center"] -.... -include::models/interaction_diagram_service_gateway_find_service.puml[] -.... - == Service Gateway - require service The creation of client connectors is forwarded to bridges as request_service() calls. @@ -127,9 +115,9 @@ include::models/interaction_diagram_service_gateway_require_service.puml[] == Service Gateway - provide service -The creation of server connectors is found by service bridges using the SOCom subscribe_find_service() API. +The creation of server connectors is found by service bridges using the client connector Service_state_change_callback. Service bridges provide this information within their domain. -If any domain partner requests the service instance, the service bridge creates a proxy client connector (forwarding all communication). +If any domain partner requests the service instance, the service bridge forwards all communication using this proxy client connector. .Interaction diagram: Service Gateway - provide service [plantuml, svg, align="center"] diff --git a/src/socom/doc/design/models/interaction_diagram_service_gateway_find_service.puml b/src/socom/doc/design/models/interaction_diagram_service_gateway_find_service.puml deleted file mode 100644 index 076560d7..00000000 --- a/src/socom/doc/design/models/interaction_diagram_service_gateway_find_service.puml +++ /dev/null @@ -1,88 +0,0 @@ -' ******************************************************************************* -' Copyright (c) 2025 Contributors to the Eclipse Foundation -' -' See the NOTICE file(s) distributed with this work for additional -' information regarding copyright ownership. -' -' This program and the accompanying materials are made available under the -' terms of the Apache License Version 2.0 which is available at -' https://www.apache.org/licenses/LICENSE-2.0 -' -' SPDX-License-Identifier: Apache-2.0 -' ******************************************************************************* - -@startuml -participant app as "Application" <> -participant socom as "SOCom" -participant bridge as "Generic service bridge" <> -autonumber - -== Initialization == - -activate app -app -> socom ** : create_runtime() - -app -> bridge ** : create_bridge_component() -activate bridge - -bridge -> socom : register_service_bridge\n(bridge_subscribe_find_service, bridge_request_service) -activate socom -return - -bridge -> socom : subscribe_find_service\n(bridge_find_callback) -activate socom -return - -note right -A generic service bridge (e.g. bridge::ipc) -is interested in every service instance -within the local process. -This enables a config-free (dynamic) -implementation of service discovery functionality -based on the pure internal service instance identifiers. -end note - - -== Application searches for a service instance == - -app -> socom : subscribe_find_service\n(app_find_callback, interface_A, instance_1) -activate socom -socom -> bridge : bridge_subscribe_find_service\n(socom_find_callback, interface_A, instance_1) -activate bridge - -group Implementation detail -bridge -> bridge -note right -The generic service bridge -searches for the service instance on -its remote counterparts. -end note -end -return - -return - - -== service instance remote search result changed (added)== - -group Implementation detail -bridge -> bridge -note right -Found a service instance on a remote counterpart. -end note -end - -bridge -> socom : socom_find_callback\n(interface_A, instance_1, State::added) -activate socom -socom -> app : app_find_callback\n(interface_A, instance_1, State::added) -activate app -return - -return - -note right -Important: SOCom does not forward find results to -service-interface wildcard finds -(subscribe_find_service(callback)). -end note -@enduml diff --git a/src/socom/doc/design/models/interaction_diagram_service_gateway_provide_service.puml b/src/socom/doc/design/models/interaction_diagram_service_gateway_provide_service.puml index 3c3728a8..c60332db 100644 --- a/src/socom/doc/design/models/interaction_diagram_service_gateway_provide_service.puml +++ b/src/socom/doc/design/models/interaction_diagram_service_gateway_provide_service.puml @@ -25,45 +25,14 @@ activate socom app -> bridge ** : create_bridge_component() activate bridge -bridge -> socom : register_service_bridge(bridge_subscribe_find_service, bridge_request_service) +bridge -> socom : register_service_bridge(bridge_request_service) activate socom return -bridge -> socom : subscribe_find_service(bridge_find_callback) -activate socom -return - -note right -A generic service bridge (e.g. bridge::ipc) -is interested in every service instance -within the local process. -This enables a config-free (dynamic) -implementation of service discovery functionality -based on the pure internal service instance identifiers. -end note - - -== Application creates a service instance == - -app -> socom : make_server_connector(interface_A, instance_1) -activate socom -socom -> bridge : bridge_find_callback(interface_A, instance_1, State::added) -activate bridge - -group Implementation detail -bridge -> bridge note right -The generic service bridge -informs its remote counterparts -about the availability -of a new service instance -interface_A, instance_1 -at the local endpoint. +To get information about services the +bridge needs to create a client connector. end note -end -return - -return == service instance remote usage == @@ -71,8 +40,8 @@ group Implementation detail bridge -> bridge note right A remote counterpart is interested -in the local service and informed the -generic service bridge about. +in a service and informed the +service bridge about. end note end @@ -88,8 +57,31 @@ only if service instance is locally not available. end note end +== Application creates a service instance == + +app -> socom : make_server_connector(interface_A, instance_1) +activate socom socom -> socom note right SOCom connects client_connector to server_connector. end note + +socom -> bridge : Client_connector::Service_state_change_callback(Service_state::available) +activate bridge + +group Implementation detail +bridge -> bridge +note right +The generic service bridge +informs its remote counterparts +about the availability +of a new service instance +interface_A, instance_1 +at the local endpoint. +end note +end +return + +return + @enduml diff --git a/src/socom/doc/design/models/interaction_diagram_service_gateway_require_service.puml b/src/socom/doc/design/models/interaction_diagram_service_gateway_require_service.puml index f5a1e7d2..23179002 100644 --- a/src/socom/doc/design/models/interaction_diagram_service_gateway_require_service.puml +++ b/src/socom/doc/design/models/interaction_diagram_service_gateway_require_service.puml @@ -26,24 +26,15 @@ activate socom app -> bridge ** : create_bridge_component() activate bridge -bridge -> socom : register_service_bridge\n(bridge_subscribe_find_service, bridge_request_service) -activate socom -return - -bridge -> socom : subscribe_find_service(bridge_find_callback) +bridge -> socom : register_service_bridge(bridge_request_service) activate socom return note right -A generic service bridge (e.g. bridge::ipc) -is interested in every service instance -within the local process. -This enables a config-free (dynamic) -implementation of service discovery functionality -based on the pure internal service instance identifiers. +To get information about services the +bridge needs to create a client connector. end note - == Application requests a service instance == app -> socom : make_client_connector(interface_A, instance_1) diff --git a/src/socom/include/score/socom/runtime.hpp b/src/socom/include/score/socom/runtime.hpp index 9adba5f8..ad995a61 100644 --- a/src/socom/include/score/socom/runtime.hpp +++ b/src/socom/include/score/socom/runtime.hpp @@ -16,13 +16,11 @@ #include #include -#include #include #include #include #include #include -#include namespace score::socom { @@ -60,19 +58,6 @@ inline bool operator!=(Bridge_identity const& lhs, Bridge_identity const& rhs) { return !(lhs == rhs); } -/// \brief Interface class for Find_subscription RAII type (see Runtime). -class Find_subscription_handle { - public: - Find_subscription_handle() = default; - virtual ~Find_subscription_handle() = default; - - Find_subscription_handle(Find_subscription_handle const&) = delete; - Find_subscription_handle(Find_subscription_handle&&) = delete; - - Find_subscription_handle& operator=(Find_subscription_handle const&) = delete; - Find_subscription_handle& operator=(Find_subscription_handle&&) = delete; -}; - /// \brief Interface class for Service_bridge_registration RAII type (see Runtime). class Service_bridge_registration_handle { public: @@ -104,9 +89,6 @@ class Service_request_handle { Service_request_handle& operator=(Service_request_handle&&) = delete; }; -/// \brief RAII object that represents an active find service subscription, see -/// Runtime::subscribe_find_service(). -using Find_subscription = std::unique_ptr; /// \brief RAII object that represents a service bridge registration at the runtime, see /// Runtime::register_service_bridge() using Service_bridge_registration = std::unique_ptr; @@ -114,28 +96,6 @@ using Service_bridge_registration = std::unique_ptr; -/// \brief [[deprecated]] Find service result type, see Runtime::subscribe_find_service(). -using Find_result_container = std::vector; - -/// \brief Status of reported service. -enum class Find_result_status : std::uint8_t { - added, ///< A new service is found. - deleted ///< A service is removed. -}; - -/// \brief [[deprecated]] Find service result indication callback type, see -/// Runtime::subscribe_find_service(). -using Find_result_callback = std::function; - -/// \brief Find service result indication callback type, see Runtime::subscribe_find_service(). -using Find_result_change_callback = std::function; - -/// \brief Subscribe_find_service interface type signature. -using Subscribe_find_service_function = std::function)>; - /// \brief Request_service interface type signature. using Request_service_function = std::function; @@ -245,80 +205,14 @@ class Runtime { Disabled_server_connector::Callbacks callbacks, Posix_credentials const& credentials) noexcept = 0; - /// \brief Offers the same functionality as the subscribe_find_service() below. - /// \details The complete list of currently available services is passed into the callback on - /// every change. - /// - /// If the set of known services matching the parameters interface and instance changes compared - /// to the last invocation of callback on_result_set, on_result_set is called with the complete - /// list of currently available services. - /// \param on_result_set_change Callback function. - /// \param interface Service interface. - /// \param instance Optional service instance. - /// \return Object that represents an active find service subscription. - [[nodiscard]] [[deprecated( - "Removed due to complexity. Use Client_connectors Service_state_change_callback instead.")]] - virtual Find_subscription subscribe_find_service( - Find_result_callback on_result_set_change, Service_interface_identifier const& interface, - std::optional instance) noexcept = 0; - - /// \brief Calls on_result_change when a new service is found or a service is removed. - /// \note Interface and instance are used to filter for specific services. - /// \details Immediately reports the all currently known service instances matching the given - /// interface and instance to the callback on_result_change and returns a RAII object - /// representing this find subscription. - /// - /// If the set of known services matching the parameters interface and instance changes compared - /// to the last invocation of the callback on_result_change, on_result_change is called - /// with the new set of known service instances. - /// - /// If the object representing a find subscription is released, then any further changes are no - /// longer indicated through the callback on_result_change. - /// - /// If the parameter instance has no value, all instances matching the interface are part of the - /// result. - /// - /// If the callback on_result_change is nullptr, find subscription is not performed and the - /// callback on_result_change is never called. - /// - /// The method subscribe_find_service(interface, instance) is called on every already registered - /// or later registered bridge and the Service_request RAII objects are stored. - /// - /// If the last find service subscription for [interface, instance] is destroyed, - /// subscribe_find_service() deletes all associated find service subscription RAII objects. - /// - /// A service bridge contributes to the result-set of find service subscriptions by calling the - /// Find_result_change_callback for the specific bridge which is part of the - /// subscribe_find_service interface. Thus changes on the set of known service instances must be - /// indicated as locally created services. Duplicate services indicate a system configuration - /// error. - /// - /// If the one and only find service subscriber is a bridge that indicates the existence of the - /// parameter identity, then no find service request forwarding to the respective bridge - /// is active. - /// \param on_result_change Callback function. - /// \param interface Service interface. - /// \param instance Service instance. - /// \param identity Optional bridge identity. - /// \return Object that represents an active find service subscription. - [[nodiscard]] [[deprecated( - "Removed due to complexity. Use Client_connectors Service_state_change_callback instead.")]] - virtual Find_subscription subscribe_find_service( - Find_result_change_callback on_result_change, - std::optional interface, - std::optional instance, - std::optional identity) noexcept = 0; - /// \brief Registers a bridge which transports events or method calls over an IPC channel. /// \param identity Bridge identity. - /// \param subscribe_find_service Function to call in order to search for services. /// \param request_service Function to call if the requested service is not present locally. /// \return A registration RAII object in case of successful operation, otherwise an error. /// \note Construction_error::callback_missing is returned if any of the callbacks is not set. [[nodiscard]] virtual Result register_service_bridge( - Bridge_identity identity, Subscribe_find_service_function subscribe_find_service, - Request_service_function request_service) noexcept = 0; + Bridge_identity identity, Request_service_function request_service) noexcept = 0; }; /// \brief Function to instantiate a Runtime object. diff --git a/src/socom/mock/score/socom/callback_mocks.hpp b/src/socom/mock/score/socom/callback_mocks.hpp index 5082b329..0af81867 100644 --- a/src/socom/mock/score/socom/callback_mocks.hpp +++ b/src/socom/mock/score/socom/callback_mocks.hpp @@ -23,10 +23,6 @@ namespace score::socom { -// Runtime callbacks -using Find_result_change_callback_mock = ::testing::MockFunction; -using Legacy_find_result_callback_mock = ::testing::MockFunction; - // Client_connector callbacks using Service_state_change_callback_mock = Move_only_function_mock; using Event_update_callback_mock = Move_only_function_mock; @@ -48,8 +44,6 @@ using Method_call_credentials_callback_mock = using Method_reply_callback_mock = Move_only_function_mock; // Bridge callbacks -using Subscribe_find_service_function_mock = - ::testing::MockFunction; using Request_service_function_mock = ::testing::MockFunction; } // namespace score::socom diff --git a/src/socom/mock/score/socom/runtime_mock.hpp b/src/socom/mock/score/socom/runtime_mock.hpp index 60db69ea..d3f4f0ed 100644 --- a/src/socom/mock/score/socom/runtime_mock.hpp +++ b/src/socom/mock/score/socom/runtime_mock.hpp @@ -44,17 +44,8 @@ class Runtime_mock : public Runtime { (Server_service_interface_definition, Service_instance, Disabled_server_connector::Callbacks, Posix_credentials const&), (noexcept, override)); - MOCK_METHOD(Find_subscription, subscribe_find_service, - (Find_result_callback, Service_interface_identifier const&, - std::optional), - (noexcept, override)); - MOCK_METHOD(Find_subscription, subscribe_find_service, - (Find_result_change_callback, std::optional, - std::optional, std::optional), - (noexcept, override)); MOCK_METHOD(Result, register_service_bridge, - (Bridge_identity, Subscribe_find_service_function, Request_service_function), - (noexcept, override)); + (Bridge_identity, Request_service_function), (noexcept, override)); }; } // namespace score::socom diff --git a/src/socom/src/runtime_impl.cpp b/src/socom/src/runtime_impl.cpp index 52cb7669..d21d8e62 100644 --- a/src/socom/src/runtime_impl.cpp +++ b/src/socom/src/runtime_impl.cpp @@ -50,108 +50,6 @@ std::vector get_keys(Map const& map) { return keys; } -std::optional const& any_interface() { - static auto const any = std::optional{}; - return any; -} - -std::optional const& any_instance() { - static auto const any = std::optional{}; - return any; -} - -void get_callbacks_to_notify_helper( - std::vector& result, - Runtime_impl::Service_instance_to_callbacks const& instances_to_callbacks, - std::optional const& instance) { - auto const filter_callbacks = instances_to_callbacks.find(instance); - if (std::end(instances_to_callbacks) != filter_callbacks) { - result.insert(std::end(result), std::begin(filter_callbacks->second), - std::end(filter_callbacks->second)); - } -} - -std::vector get_callbacks_to_notify( - Runtime_impl::Interface_to_instance_to_callbacks const& interface_to_callbacks, - Service_interface_identifier const& interface, Service_instance const& instance, - bool const local) { - std::vector result; - - if (local) { - auto const any_interface_instances_to_callbacks = - interface_to_callbacks.find(any_interface()); - if (std::end(interface_to_callbacks) != any_interface_instances_to_callbacks) { - get_callbacks_to_notify_helper(result, any_interface_instances_to_callbacks->second, - any_instance()); - } - } - - auto const instances_to_callbacks = - interface_to_callbacks.find(std::optional{interface}); - if (std::end(interface_to_callbacks) != instances_to_callbacks) { - get_callbacks_to_notify_helper(result, instances_to_callbacks->second, any_instance()); - get_callbacks_to_notify_helper(result, instances_to_callbacks->second, - std::optional{instance}); - } - - return result; -} - -std::thread::id get_invalid_thread_id() { return {}; } - -void notify_subscribed_callbacks( - Currently_running_subscribe_find_service_report& running_service_report, - std::vector const& callbacks_to_notify, - Service_interface_identifier const& interface, Service_instance const& instance, - Find_result_status const status) { - auto const call_callbacks_to_notify = [&callbacks_to_notify, &interface, &instance, &status]() { - for (auto const& cb : callbacks_to_notify) { - auto const locked_cb = cb.lock(); - if (nullptr != locked_cb) { - (*locked_cb)(interface, instance, status); - } - } - }; - - // check if thread id was already set and matches this_thread::id, if yes Server_connector - // creation was triggered by callback and skip locking - if (std::this_thread::get_id() == running_service_report.data) { - call_callbacks_to_notify(); - } else { - // Serialize Find_result_callback calls to reliably detect callback self deletion - // save and remove current thread id, which is checked in stop_subscription() - std::lock_guard const lock{running_service_report.mutex}; - running_service_report.data = std::this_thread::get_id(); - Final_action const reset_data{ - [&running_service_report]() { running_service_report.data = get_invalid_thread_id(); }}; - - call_callbacks_to_notify(); - } -} - -/// \brief Removes all weak_ptrs from list that are either expired or point to item. -/// -/// \param list List of weak_ptrs to clean up. -/// \param item Item to remove from list. All weak_ptrs that point to this item will be removed. -template -void cleanup(std::list>& list, - std::shared_ptr const& item) noexcept { - auto const equals_cb = [&item](auto const& cb_ref) { - auto const locked_cb = cb_ref.lock(); - - // Defensive programming. The true case for the condition (nullptr == locked_cb) will not - // occur because Runtime_impl implements Stop_subscription which further calls - // stop_subscribe when Find_subscription_handle_impl gets destroyed. This will trigger the - // cleanup function and the Find_result_callback gets removed from the list. - // Find_result_callback can not be destroyed from outside in a test to trigger the true - // case for (nullptr == locked_cb). - - return (nullptr == locked_cb) || (item == locked_cb); - }; - - list.remove_if(equals_cb); -} - /// \brief Removes key from map if value is empty /// /// \param map Map to clean up. @@ -305,10 +203,9 @@ void register_bridge(Bridge_registration_id const& bridge_id, } } else { auto const bridge_to_request = std::get<0>(request.second).lock(); - // if destruction of Client_connector or subscribe_find_service handle is - // concurrently happening there might be a nullptr in the map until the map is - // cleaned. Thus because the map is going to be cleaned do not bother to call the - // callback of the bridge + // if destruction of Client_connector is concurrently happening there might be a + // nullptr in the map until the map is cleaned. Thus because the map is going to be + // cleaned do not bother to call the callback of the bridge if (nullptr != bridge_to_request) { bridge_to_request->emplace(bridge_id, std::move(cb_result_iter->second)); @@ -408,16 +305,6 @@ std::shared_ptr get_bridge_requests( return result; } -void call_find_result_callback_with_currently_known_services( - Find_result_change_callback const& on_result_set_change, Interfaces_instances const& services) { - for (auto const& interface_with_instances : services) { - for (auto const& instance : interface_with_instances.second) { - on_result_set_change(interface_with_instances.first, instance, - Find_result_status::added); - } - } -} - } // namespace Service_database::Service_database(std::mutex& runtime_mutex) : m_runtime_mutex{runtime_mutex} {} @@ -562,198 +449,24 @@ Result Runtime_impl::make_server_connector( std::move(callbacks), std::move(final_action), credentials)}; } -namespace { - -class Find_aggregation { - public: - explicit Find_aggregation(Find_result_callback cb); - - void initial_indicate() const; - void on_result_set_change(Service_instance const& instance, Find_result_status status); - - private: - void add(Service_instance const& instance); - void remove(Service_instance const& instance); - void indicate() const; - - mutable std::mutex m_mutex{}; - mutable bool m_collecting_initial_result{true}; - Find_result_container m_results{}; - Find_result_callback const m_on_result_set_change; -}; - -Find_aggregation::Find_aggregation(Find_result_callback cb) - : m_on_result_set_change{std::move(cb)} {} - -void Find_aggregation::initial_indicate() const { - std::lock_guard const guard{m_mutex}; - m_on_result_set_change(m_results); - m_collecting_initial_result = false; -} - -void Find_aggregation::on_result_set_change(Service_instance const& instance, - Find_result_status status) { - if (status == Find_result_status::added) { - add(instance); - } else { - assert(status == Find_result_status::deleted); - remove(instance); - } -} - -void Find_aggregation::add(Service_instance const& instance) { - std::lock_guard const guard{m_mutex}; - m_results.push_back(instance); - indicate(); -} - -void Find_aggregation::remove(Service_instance const& instance) { - std::lock_guard const guard{m_mutex}; - auto const it_end = m_results.end(); - auto const it = std::find(m_results.begin(), it_end, instance); - if (it != it_end) { - m_results.erase(it); - indicate(); - } -} - -void Find_aggregation::indicate() const { - if (!m_collecting_initial_result) { - m_on_result_set_change(m_results); - } -} - -class Find_aggregation_subscription_handle : public Find_subscription_handle { - public: - Find_aggregation_subscription_handle(Find_subscription fs, std::shared_ptr fa) - : m_find_aggregation{std::move(fa)}, m_handle{std::move(fs)} { - m_find_aggregation->initial_indicate(); - } - - Find_aggregation_subscription_handle(Find_aggregation_subscription_handle const& other) = - delete; - Find_aggregation_subscription_handle(Find_aggregation_subscription_handle&& other) = delete; - - ~Find_aggregation_subscription_handle() override = default; - - Find_aggregation_subscription_handle& operator=( - Find_aggregation_subscription_handle const& other) = delete; - Find_aggregation_subscription_handle& operator=(Find_aggregation_subscription_handle&& other) = - delete; - - private: - std::shared_ptr m_find_aggregation; - Find_subscription m_handle; -}; - -} // namespace - -Find_subscription Runtime_impl::subscribe_find_service( - Find_result_callback on_result_set_change, Service_interface_identifier const& interface, - std::optional instance) noexcept { - if (!on_result_set_change) { - return std::make_unique(); - } - - // shared context between multiple copies of the callback handler - auto find_aggregation = std::make_shared(std::move(on_result_set_change)); - - auto update_find_result_container_handler = - [find_aggregation](auto const& /*interface*/, auto const& instance, auto status) mutable { - find_aggregation->on_result_set_change(instance, status); - }; - - // Wrap the subscription handle in order to tie the scope of shared context with that of the - // subscription handle. - Find_subscription find_subscription{std::make_unique( - subscribe_find_service(std::move(update_find_result_container_handler), interface, instance, - std::optional{}), - find_aggregation)}; - - return find_subscription; -} - -Find_subscription Runtime_impl::subscribe_find_service( - Find_result_change_callback on_result_change, - std::optional interface, std::optional instance, - std::optional identity) noexcept { - // interface can be specified without instance, but not the other way around - // Logic expression: instance -> interface - assert(interface || !instance); - - if (!on_result_change) { - return std::make_unique(); - } - - // call callback with current active services - std::unique_lock lock{m_runtime_mutex}; - - auto find_handle = std::make_unique(*this); - auto const inserted_element = m_find_service_subscriptions.emplace( - find_handle.get(), - std::make_tuple(std::make_shared(on_result_change), interface, - instance, nullptr)); - assert(inserted_element.second); - m_interface_to_callbacks[interface][instance].emplace_back( - std::get<0>(inserted_element.first->second)); - - auto const current_interfaces_instances = m_database.get_instances(interface, instance); - lock.unlock(); - - try { - call_find_result_callback_with_currently_known_services(on_result_change, - current_interfaces_instances); - - if (interface) { - auto const bridge_instances = get_bridge_reported_instances(*interface, instance); - call_find_result_callback_with_currently_known_services(on_result_change, - bridge_instances); - } - } catch (...) { - } - - // wildcard interface searches shall not be forwarded to bridges - if (interface) { - auto bridge_find_subscriptions = - get_or_create_find_services(*interface, instance, identity); - lock.lock(); - std::get<3>(inserted_element.first->second) = std::move(bridge_find_subscriptions); - } - - return find_handle; -} - Result Runtime_impl::register_service_bridge( - Bridge_identity identity, Subscribe_find_service_function subscribe_find_service, - Request_service_function request_service) noexcept { - if (!subscribe_find_service || !request_service) { + Bridge_identity identity, Request_service_function request_service) noexcept { + if (!request_service) { return MakeUnexpected(Construction_error::callback_missing); } // false positive, registration is moved at return // stack allocation not possible as the object needs a stable memory address auto registration = std::make_unique(*this, identity); - auto const create_find_subscription = - [this, subscribe_find_service, - bridge_id = registration.get()](auto const& interface_configuration) { - auto const& interface = std::get<0>(interface_configuration).interface; - auto const& instance = std::get<1>(interface_configuration); - Find_result_change_callback cb = this->create_bridge_find_result_callback(bridge_id); - - return subscribe_find_service(std::move(cb), interface, instance); - }; - auto const create_service_request = [request_service](auto const& interface_configuration) { return request_service(std::get<0>(interface_configuration), std::get<1>(interface_configuration)); }; std::unique_lock lock{m_bridge_mutex}; - m_bridge_to_callbacks[registration.get()] = std::make_tuple( - std::move(subscribe_find_service), std::move(request_service), Interfaces_instances{}); + m_bridge_to_callbacks[registration.get()] = + std::make_tuple(std::move(request_service), Interfaces_instances{}); - register_bridge(registration.get(), lock, m_active_bridge_find_services, - create_find_subscription); register_bridge(registration.get(), lock, m_service_requests, create_service_request); return Result{std::move(registration)}; @@ -794,8 +507,6 @@ Registration Runtime_impl::register_connector(Service_interface_identifier const std::unique_lock lock{m_runtime_mutex}; auto& sii_record = m_database.get_record(interface, instance); auto result = sii_record.register_server_connector(interface, endpoint); - auto const callbacks_to_notify = - get_callbacks_to_notify(m_interface_to_callbacks, interface, instance, true); lock.unlock(); auto const connect_client = [&endpoint, &interface, &instance](auto const& client) { @@ -812,156 +523,15 @@ Registration Runtime_impl::register_connector(Service_interface_identifier const std::for_each(std::begin(result.current_clients), std::end(result.current_clients), connect_client); - notify_subscribed_callbacks(m_currently_running_service_report, callbacks_to_notify, interface, - instance, Find_result_status::added); - - auto inform_subscribers = [this, interface, instance]() { - call_subscribe_find_service_callbacks(interface, instance, Find_result_status::deleted, - true); - }; - - return std::make_unique( - std::make_unique(Final_action(std::move(inform_subscribers))), - std::move(result.registration)); -} - -void Runtime_impl::stop_subscription(Find_subscription_id const& id) noexcept { - std::unique_lock lock{m_runtime_mutex}; - auto const subscription_it = m_find_service_subscriptions.find(id); - - // Defensive programming. The true case will not occur because Runtime_impl implements - // Stop_subscription which further calls stop_subscribe when Find_subscription_handle_impl gets - // destroyed. This means the callback must be in the map. Furthermore, the function - // stop_subscription itself cannot be tested as it is not an interface function. - - if (std::end(m_find_service_subscriptions) == subscription_it) { - return; - } - - auto const& cb_id = subscription_it->second; - - auto const interface = std::get<1>(cb_id); - auto const instance = std::get<2>(cb_id); - - Service_instance_to_callbacks& instances_to_callbacks = m_interface_to_callbacks.at(interface); - Find_result_callbacks& callbacks = instances_to_callbacks.at(instance); - cleanup(callbacks, std::get<0>(cb_id)); - cleanup(instances_to_callbacks, instance, callbacks); - cleanup(m_interface_to_callbacks, interface, instances_to_callbacks); - m_find_service_subscriptions.erase(subscription_it); - lock.unlock(); - - // cleanup bridge find subscription - if (interface) { - std::lock_guard const bridge_lock{m_bridge_mutex}; - auto const configuration = Service_interface_definition{*interface}; - cleanup(m_active_bridge_find_services, std::make_tuple(configuration, instance)); - } - - // no data race, if run from same thread - if (m_currently_running_service_report.data != std::this_thread::get_id()) { - // sync deletion with running callbacks to ensure that all shared_ptr are deleted. - std::lock_guard const calling_callbacks_lock{ - m_currently_running_service_report.mutex}; - } + return std::move(result.registration); } void Runtime_impl::stop_registration(Bridge_registration_id const& id) noexcept { std::unique_lock bridge_lock{m_bridge_mutex}; - auto const provided_services = std::get<2>(m_bridge_to_callbacks.at(id)); m_bridge_to_callbacks.erase(id); - cleanup(m_active_bridge_find_services, id); cleanup(m_service_requests, id); bridge_lock.unlock(); - - for (auto const& interface_with_instances : provided_services) { - for (auto const& instance : interface_with_instances.second) { - try { - call_subscribe_find_service_callbacks(interface_with_instances.first, instance, - Find_result_status::deleted, false); - } - - catch (...) { - } - } - } -} - -void Runtime_impl::update_bridges_provided_services(Bridge_registration_id const& bridge_id, - Service_interface_identifier const& interface, - Service_instance const& instance, - Find_result_status status) { - std::lock_guard const lock{m_bridge_mutex}; - auto const bridge_to_callbacks = m_bridge_to_callbacks.find(bridge_id); - - // If statement expression may evaluate to true because Runtime_impl implements - // Stop_registration where map element with bridge_id is removed. For that reason further access - // to m_bridge_to_callbacks map element makes no sense. An early return takes place. - // - // Sporadically in TEST_F(RuntimeMultiThreadingTest, - // BridgesAndSubscribeFindServiceHaveNoRaceConditions) where tight loops of - // register_service_bridge are made, could be observed early return takes on place because of - // thread aware, concurrent API calls. Code is excluded from Bullseye coverage to prevent false - // reports. - - if (std::end(m_bridge_to_callbacks) == bridge_to_callbacks) { - return; - } - - auto& available_services = std::get<2>(bridge_to_callbacks->second); - if (Find_result_status::added == status) { - available_services[interface].emplace_back(instance); - } else { - auto const if_iter = available_services.find(interface); - if (std::end(available_services) == if_iter) { - return; - } - Instances& instances = if_iter->second; - auto const end = - std::remove_if(std::begin(instances), std::end(instances), - [&instance](Service_instance const& elem) { return instance == elem; }); - instances.erase(end, std::end(instances)); - cleanup(available_services, interface, instances); - } -} - -void Runtime_impl::call_subscribe_find_service_callbacks( - Service_interface_identifier const& interface, Service_instance const& instance, - Find_result_status const status, bool const local) { - std::unique_lock runtime_lock{m_runtime_mutex}; - auto const callbacks_to_notify = - get_callbacks_to_notify(m_interface_to_callbacks, interface, instance, local); - runtime_lock.unlock(); - notify_subscribed_callbacks(m_currently_running_service_report, callbacks_to_notify, interface, - instance, status); -} - -Find_result_change_callback Runtime_impl::create_bridge_find_result_callback( - Bridge_registration_id const& bridge_id) { - assert(nullptr != bridge_id); - return [this, bridge_id](Service_interface_identifier const& interface, - Service_instance const& instance, Find_result_status status) { - update_bridges_provided_services(bridge_id, interface, instance, status); - call_subscribe_find_service_callbacks(interface, instance, status, false); - }; -} - -std::shared_ptr Runtime_impl::get_or_create_find_services( - Service_interface_identifier const& interface, std::optional const& instance, - std::optional identity) { - auto const create_value = [this](auto const& callbacks, auto const& configuration, - auto const& instance) { - auto const notify_find_subscriptions = - this->create_bridge_find_result_callback(callbacks.first); - return std::get<0>(callbacks.second)(notify_find_subscriptions, configuration.interface, - instance); - }; - - std::unique_lock bridge_lock{m_bridge_mutex}; - return get_bridge_requests( - Service_interface_definition{interface}, instance, std::move(identity), bridge_lock, - m_active_bridge_find_services, m_bridge_to_callbacks, create_value); } Registration Runtime_impl::bridge_service_requests( @@ -984,7 +554,7 @@ std::shared_ptr Runtime_impl::get_or_create_service_reques Service_interface_definition const& configuration, Service_instance const& instance) { auto const create_value = [](auto const& callbacks, auto const& configuration, auto const& instance) { - return std::get<1>(callbacks.second)(configuration, instance); + return std::get<0>(callbacks.second)(configuration, instance); }; std::unique_lock bridge_lock{m_bridge_mutex}; return get_bridge_requests(configuration, instance, {}, bridge_lock, @@ -1004,7 +574,7 @@ Interfaces_instances Runtime_impl::get_bridge_reported_instances( std::lock_guard const bridge_lock{m_bridge_mutex}; Instances result; for (auto const& bridge_data : m_bridge_to_callbacks) { - auto bridge_services = std::get<2>(bridge_data.second); + auto bridge_services = std::get<1>(bridge_data.second); auto const& instances = bridge_services.find(interface); if (std::end(bridge_services) != instances) { static_cast(std::copy_if(std::begin(instances->second), diff --git a/src/socom/src/runtime_impl.hpp b/src/socom/src/runtime_impl.hpp index 2f549dcc..0dfc0afa 100644 --- a/src/socom/src/runtime_impl.hpp +++ b/src/socom/src/runtime_impl.hpp @@ -14,7 +14,6 @@ #ifndef SCORE_SOCOM_RUNTIME_IMPL_HPP #define SCORE_SOCOM_RUNTIME_IMPL_HPP -#include #include #include #include @@ -22,7 +21,6 @@ #include #include #include -#include #include #include @@ -38,13 +36,11 @@ namespace socom { using CC_impl = client_connector::Impl; using SC_impl = server_connector::Impl; -using Find_subscription_id = Find_subscription_handle const*; using Bridge_registration_id = Service_bridge_registration_handle const*; template using Bridge_id_to = std::map; -using Bridge_id_to_subscription = Bridge_id_to; using Bridge_id_to_request = Bridge_id_to; template @@ -58,9 +54,6 @@ struct Mutexed_variable { T data{}; }; -using Currently_running_subscribe_find_service_report = - Mutexed_variable>; - using Service_identifiers = Mutexed_variable>; class Service_record { @@ -153,24 +146,9 @@ struct Stop_subscription { Stop_subscription& operator=(Stop_subscription const&) = delete; Stop_subscription& operator=(Stop_subscription&&) = delete; - virtual void stop_subscription(Find_subscription_id const& id) noexcept = 0; virtual void stop_registration(Bridge_registration_id const& id) noexcept = 0; }; -class Void_find_subscription_handle final : public Find_subscription_handle {}; - -class Find_subscription_handle_impl final : public Find_subscription_handle { - Stop_subscription& m_stopper; - - public: - explicit Find_subscription_handle_impl(Stop_subscription& stopper) : m_stopper{stopper} {} - Find_subscription_handle_impl(Find_subscription_handle_impl const&) = delete; - Find_subscription_handle_impl(Find_subscription_handle_impl&&) = delete; - Find_subscription_handle_impl& operator=(Find_subscription_handle_impl const&) = delete; - Find_subscription_handle_impl& operator=(Find_subscription_handle_impl&&) = delete; - ~Find_subscription_handle_impl() noexcept override { m_stopper.stop_subscription(this); } -}; - class Bridge_registration_handle_impl final : public Service_bridge_registration_handle { public: explicit Bridge_registration_handle_impl(Stop_subscription& stopper, Bridge_identity identity) @@ -190,22 +168,8 @@ class Bridge_registration_handle_impl final : public Service_bridge_registration // both base classes delete the operator= in question class Runtime_impl final : public Runtime, public Stop_subscription { public: - using Find_result_callback_wptr = std::weak_ptr; - using Find_result_callback_sptr = std::shared_ptr; - using Find_result_callbacks = std::list; - using Callback_with_id = - std::tuple, - std::optional, std::shared_ptr>; - using Subscription_to_callback = std::map; - using Service_instance_to_callbacks = - std::unordered_map, Find_result_callbacks>; - using Interface_to_instance_to_callbacks = - std::unordered_map, - Service_instance_to_callbacks>; - using Bridge_registration_to_callbacks = - Bridge_id_to>; + Bridge_id_to>; Result make_client_connector( Service_interface_definition configuration, Service_instance instance, @@ -225,20 +189,9 @@ class Runtime_impl final : public Runtime, public Stop_subscription { Disabled_server_connector::Callbacks callbacks, Posix_credentials const& credentials) noexcept override; - Find_subscription subscribe_find_service( - Find_result_callback on_result_set_change, Service_interface_identifier const& interface, - std::optional instance) noexcept override; - - Find_subscription subscribe_find_service( - Find_result_change_callback on_result_change, - std::optional interface, - std::optional instance, - std::optional identity) noexcept override; - // NOLINTBEGIN(bugprone-exception-escape)(ClangTidy Android Warning) Result register_service_bridge( - Bridge_identity identity, Subscribe_find_service_function subscribe_find_service, - Request_service_function request_service) noexcept override; + Bridge_identity identity, Request_service_function request_service) noexcept override; // NOLINTEND(bugprone-exception-escape) Registration register_connector(Service_interface_definition const& configuration, @@ -249,8 +202,6 @@ class Runtime_impl final : public Runtime, public Stop_subscription { Service_instance const& instance, SC_impl::Listen_endpoint endpoint); - void stop_subscription(Find_subscription_id const& id) noexcept override; - void stop_registration(Bridge_registration_id const& id) noexcept override; private: @@ -263,22 +214,6 @@ class Runtime_impl final : public Runtime, public Stop_subscription { Registration bridge_service_requests(Service_interface_definition const& configuration, Service_instance const& instance); - void update_bridges_provided_services(Bridge_registration_id const& bridge_id, - Service_interface_identifier const& interface, - Service_instance const& instance, - Find_result_status status); - - void call_subscribe_find_service_callbacks(Service_interface_identifier const& interface, - Service_instance const& instance, - Find_result_status status, bool local); - - Find_result_change_callback create_bridge_find_result_callback( - Bridge_registration_id const& bridge_id); - - std::shared_ptr get_or_create_find_services( - Service_interface_identifier const& interface, - std::optional const& instance, std::optional identity); - Interfaces_instances get_bridge_reported_instances( Service_interface_identifier const& interface, std::optional const& instance) const; @@ -286,22 +221,13 @@ class Runtime_impl final : public Runtime, public Stop_subscription { mutable std::mutex m_runtime_mutex{}; Service_database m_database{m_runtime_mutex}; - Subscription_to_callback m_find_service_subscriptions{}; - Interface_to_instance_to_callbacks m_interface_to_callbacks{}; - mutable std::mutex m_bridge_mutex; Bridge_registration_to_callbacks m_bridge_to_callbacks{}; - Active_bridge_requests, Find_subscription> - m_active_bridge_find_services{}; - Active_bridge_requests m_service_requests{}; std::shared_ptr m_service_identifiers{ std::make_shared()}; - - // Serialize Find_result_callback calls to reliably detect callback self deletion - Currently_running_subscribe_find_service_report m_currently_running_service_report; }; } // namespace socom diff --git a/src/socom/test/framework/inc/score/socom/bridge_t.hpp b/src/socom/test/framework/inc/score/socom/bridge_t.hpp index b40a0578..832a08fa 100644 --- a/src/socom/test/framework/inc/score/socom/bridge_t.hpp +++ b/src/socom/test/framework/inc/score/socom/bridge_t.hpp @@ -29,17 +29,12 @@ namespace score::socom { class Bridge_data { public: /// \brief Expect which callbacks will be called and thus need to be configured - enum Expect { nothing, subscribe_find_service, request_service_function, both }; + enum Expect { nothing, request_service_function }; private: Bridge_identity m_identity{Bridge_identity::make(*this)}; - Subscribe_find_service_function_mock m_sfsf_mock; Request_service_function_mock m_rsf_mock; - Find_result_change_callback m_find_result_callback; - - std::atomic m_subscribe_find_service_created{false}; - std::atomic m_subscribe_find_service_destroyed{true}; std::atomic m_request_find_service_created{false}; std::atomic m_request_find_service_destroyed{true}; @@ -55,20 +50,16 @@ class Bridge_data { /// the runtime enum Creation_sequence { bridge_then_expect, expect_then_bridge }; - static Subscribe_find_service_function sfs_do_nothing(); - /// \brief Create new Bridge facade /// /// \param[in] sequence whether to register or configure callbacks first /// \param[in] expect which callbacks will be called /// \param[in] connector_factory the runtime facade to register to /// \param[in] ctor_callback will be called from constructor - /// \param[in] sfs_callback will be called during create_value for subscribe_find_service Bridge_data( Creation_sequence const& sequence, Expect const& expect, Connector_factory& connector_factory, - std::function&& ctor_callback = [](Bridge_data& /*unused*/) {}, - Subscribe_find_service_function const& sfs_callback = sfs_do_nothing()); + std::function&& ctor_callback = [](Bridge_data& /*unused*/) {}); Bridge_data(Bridge_data const&) = delete; Bridge_data(Bridge_data&&) = delete; @@ -82,41 +73,12 @@ class Bridge_data { /// /// \param[in] expect which callbacks will be called /// \param[in] connector_factory container of configuration and instance id - /// \param[in] sfs_callback will be called during create_value for subscribe_find_service - void expect_callbacks(Expect const& expect, Connector_factory const& connector_factory, - Subscribe_find_service_function const& sfs_callback = sfs_do_nothing()); + void expect_callbacks(Expect const& expect, Connector_factory const& connector_factory); /// \brief Allow the Bridge_data instance to be destroyed before the expectations of the /// callbacks have been fulfilled void no_destroyed_check(); - /// \brief Report found service to the runtime - /// - /// \param[in] interface the interface to be reported - /// \param[in] instance the instance to be reported - /// \param[in] status the status of the reported service - void find_service(Service_interface_identifier const& interface, - Service_instance const& instance, Find_result_status const& status) const; - - /// \brief Expect call to subscribe_find_service() - /// - /// \param[in] interface - /// \param[in] instance - /// \param[in] sfs_callback will be called during create_value for subscribe_find_service - void expect_subscribe_find_service( - Service_interface_identifier const& interface, std::optional instance, - Subscribe_find_service_function const& sfs_callback = sfs_do_nothing()); - - /// \brief Expect call to subscribe_find_service(), callback only, for use with additional - /// requests not managed by Bridge_data - /// - /// \param[in] interface - /// \param[in] instance - /// \param[in] sfs_callback will be called during create_value for subscribe_find_service - void expect_another_subscribe_find_service( - Service_interface_identifier const& interface, std::optional instance, - Subscribe_find_service_function const& sfs_callback = sfs_do_nothing()); - /// \brief Expect call to request_find_service() /// /// \param[in] configuration @@ -133,12 +95,6 @@ class Bridge_data { /// \return atomic to check if request_find_service handle was destroyed by the runtime std::atomic const& get_request_find_service_destroyed() const; - /// \return atomic to check if runtime called subscribe_find_service - std::atomic const& get_subscribe_find_service_created() const; - - /// \return atomic to check if subscribe_find_service handle was destroyed by the runtime - std::atomic const& get_subscribe_find_service_destroyed() const; - std::optional get_identity() const; }; diff --git a/src/socom/test/framework/inc/score/socom/connector_factory.hpp b/src/socom/test/framework/inc/score/socom/connector_factory.hpp index a4bc6cf4..42f21320 100644 --- a/src/socom/test/framework/inc/score/socom/connector_factory.hpp +++ b/src/socom/test/framework/inc/score/socom/connector_factory.hpp @@ -62,64 +62,16 @@ class Connector_factory { Connector_factory& operator=(Connector_factory const&) = delete; Connector_factory& operator=(Connector_factory&&) = delete; - /// \return Service_finder instance of the internal runtime object - Runtime& get_service_finder(); - - /// \brief Subscribe to availability changes of running servers/services - /// - /// During execution of subscribe_find_service() the on_result_change callback - /// will be called with the already known set of services. - /// After the function has been called and on each service availability change - /// the callback on_result_change will be called. The callback will be - /// called as long as the returned Find_subscription object is not destroyed. - /// - /// \param[in] on_result_change callback which is called when service state changes - /// \param[in] instance filter for a specific service instance - /// \return RAII object which keeps the subscription alive until it is destroyed - Find_subscription subscribe_find_service(Find_result_change_callback on_result_change, - std::optional instance = {}, - std::optional identity = {}); - - /// \brief Legacy subscribe to availability changes of running servers/services - /// - /// During execution of legacy subscribe_find_service() the on_result_set_change callback - /// will be called with the already known set of services. - /// After the function has been called and on each service availability change - /// the callback on_result_set_change will be called. The callback will be - /// called as long as the returned Find_subscription object is not destroyed. - /// - /// \param[in] on_result_set_change callback which is called when service state changes - /// \param[in] instance filter for a specific service instance - /// \return RAII object which keeps the subscription alive until it is destroyed - Find_subscription subscribe_find_service(Find_result_callback on_result_set_change, - std::optional instance = {}); - - /// \brief Subscribe to availability changes of running servers/services - /// - /// During execution of subscribe_find_service() the on_result_change callback - /// will be called with the already known set of services. - /// After the function has been called and on each service availability change - /// the callback on_result_change will be called. The callback will be - /// called as long as the returned Find_subscription object is not destroyed. - /// - /// Results of bridges are not forwarded to on_result_change and only Runtime - /// local services are reported. - /// - /// \param[in] on_result_change callback which is called when service state changes - /// \return RAII object which keeps the subscription alive until it is destroyed - Find_subscription subscribe_find_service_wildcard(Find_result_change_callback on_result_change); - /// \brief Registers bridge callbacks at the runtime until registration is destroyed /// /// Bridges can provide additional services via IPC. The callbacks are used the query the /// bridges for services. /// - /// \param[in] subscribe_find_service Callback to call to search for services + /// \param[in] identity identity of the bridge to register, used for later identification /// \param[in] request_service /// \return RAII object which keeps the registration alive until it is destroyed ::score::Result register_service_bridge( - Bridge_identity identity, Subscribe_find_service_function subscribe_find_service, - Request_service_function request_service); + Bridge_identity identity, Request_service_function request_service); /// \brief Create server connector with default configuration /// diff --git a/src/socom/test/framework/src/bridge_t.cpp b/src/socom/test/framework/src/bridge_t.cpp index 3008d3be..33b72275 100644 --- a/src/socom/test/framework/src/bridge_t.cpp +++ b/src/socom/test/framework/src/bridge_t.cpp @@ -15,29 +15,21 @@ #include "score/socom/runtime.hpp" -using ::testing::_; using ::testing::Assign; using ::testing::ByMove; using ::testing::Return; -using ::testing::SaveArg; namespace score::socom { namespace { -bool enable_subscribe_find_service(Bridge_data::Expect const& expect) { - return (Bridge_data::Expect::both == expect) || - (Bridge_data::Expect::subscribe_find_service == expect); -} - bool enable_request_find_service(Bridge_data::Expect const& expect) { - return (Bridge_data::Expect::both == expect) || - (Bridge_data::Expect::request_service_function == expect); + return (Bridge_data::Expect::request_service_function == expect); } } // namespace -class Handle_mock final : public Service_request_handle, public Find_subscription_handle { +class Handle_mock final : public Service_request_handle { std::atomic& m_destroyed; public: @@ -51,27 +43,11 @@ class Handle_mock final : public Service_request_handle, public Find_subscriptio score::Result Bridge_data::register_at_runtime( Connector_factory& connector_factory) { - auto registration = connector_factory.register_service_bridge( - m_identity, m_sfsf_mock.AsStdFunction(), m_rsf_mock.AsStdFunction()); + auto registration = + connector_factory.register_service_bridge(m_identity, m_rsf_mock.AsStdFunction()); return registration; } -void Bridge_data::expect_subscribe_find_service( - Service_interface_identifier const& interface, std::optional instance, - Subscribe_find_service_function const& sfs_callback) { - EXPECT_CALL(m_sfsf_mock, Call(_, interface, instance)) - .WillOnce(DoAll( - SaveArg<0>(&m_find_result_callback), Assign(&m_subscribe_find_service_created, true), - Assign(&m_subscribe_find_service_destroyed, false), sfs_callback, - Return(ByMove(std::make_unique(m_subscribe_find_service_destroyed))))); -} - -void Bridge_data::expect_another_subscribe_find_service( - Service_interface_identifier const& interface, std::optional instance, - Subscribe_find_service_function const& sfs_callback) { - EXPECT_CALL(m_sfsf_mock, Call(_, interface, instance)).WillOnce(sfs_callback); -} - void Bridge_data::expect_request_find_service( Service_interface_definition const& configuration, Service_instance const& instance, std::function&& rsf) { @@ -82,62 +58,37 @@ void Bridge_data::expect_request_find_service( Return(ByMove(std::make_unique(m_request_find_service_destroyed))))); } -void Bridge_data::expect_callbacks(Expect const& expect, Connector_factory const& connector_factory, - Subscribe_find_service_function const& sfs_callback) { - if (enable_subscribe_find_service(expect)) { - expect_subscribe_find_service(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), sfs_callback); - } +void Bridge_data::expect_callbacks(Expect const& expect, + Connector_factory const& connector_factory) { if (enable_request_find_service(expect)) { expect_request_find_service(connector_factory.get_configuration(), connector_factory.get_instance()); } } -Subscribe_find_service_function Bridge_data::sfs_do_nothing() { - return [](auto /*unused*/, auto /*unused*/, auto /*unused*/) { - return std::make_unique(); - }; -} - Bridge_data::Bridge_data(Creation_sequence const& sequence, Expect const& expect, Connector_factory& connector_factory, - std::function&& ctor_callback, - Subscribe_find_service_function const& sfs_callback) { + std::function&& ctor_callback) { score::Result tmp_registration = score::MakeUnexpected(Construction_error::callback_missing); if (Creation_sequence::bridge_then_expect == sequence) { tmp_registration = register_at_runtime(connector_factory); ctor_callback(*this); - expect_callbacks(expect, connector_factory, sfs_callback); + expect_callbacks(expect, connector_factory); } else { ctor_callback(*this); - expect_callbacks(expect, connector_factory, sfs_callback); + expect_callbacks(expect, connector_factory); tmp_registration = register_at_runtime(connector_factory); EXPECT_TRUE(!enable_request_find_service(expect) || !m_request_find_service_destroyed); - EXPECT_TRUE(!enable_subscribe_find_service(expect) || !m_subscribe_find_service_destroyed); } EXPECT_TRUE(tmp_registration); m_bridge_registration = std::move(tmp_registration).value(); EXPECT_NE(nullptr, m_bridge_registration); } -Bridge_data::~Bridge_data() { - wait_for_atomics(m_request_find_service_destroyed, m_subscribe_find_service_destroyed); -} - -void Bridge_data::no_destroyed_check() { - m_request_find_service_destroyed = true; - m_subscribe_find_service_destroyed = true; -} +Bridge_data::~Bridge_data() { wait_for_atomics(m_request_find_service_destroyed); } -void Bridge_data::find_service(Service_interface_identifier const& interface, - Service_instance const& instance, - Find_result_status const& status) const { - wait_for_atomics(get_subscribe_find_service_created()); - ASSERT_TRUE(get_subscribe_find_service_created()); - m_find_result_callback(interface, instance, status); -} +void Bridge_data::no_destroyed_check() { m_request_find_service_destroyed = true; } std::atomic const& Bridge_data::get_request_find_service_created() const { return m_request_find_service_created; @@ -147,14 +98,6 @@ std::atomic const& Bridge_data::get_request_find_service_destroyed() const return m_request_find_service_destroyed; } -std::atomic const& Bridge_data::get_subscribe_find_service_created() const { - return m_subscribe_find_service_created; -} - -std::atomic const& Bridge_data::get_subscribe_find_service_destroyed() const { - return m_subscribe_find_service_destroyed; -} - std::optional Bridge_data::get_identity() const { return std::optional{m_identity}; } diff --git a/src/socom/test/framework/src/connector_factory.cpp b/src/socom/test/framework/src/connector_factory.cpp index 7e18b86a..52a1eb1f 100644 --- a/src/socom/test/framework/src/connector_factory.cpp +++ b/src/socom/test/framework/src/connector_factory.cpp @@ -43,33 +43,9 @@ Connector_factory::Connector_factory(Connector_factory const& con_fac) Runtime& Connector_factory::get_runtime() { return *m_runtime; } -Runtime& Connector_factory::get_service_finder() { return get_runtime(); } - -Find_subscription Connector_factory::subscribe_find_service( - Find_result_change_callback on_result_change, std::optional instance, - std::optional identity) { - return get_service_finder().subscribe_find_service(std::move(on_result_change), - m_configuration.get_interface(), instance, - std::move(identity)); -} - -Find_subscription Connector_factory::subscribe_find_service( - Find_result_callback on_result_set_change, std::optional instance) { - return get_service_finder().subscribe_find_service(std::move(on_result_set_change), - m_configuration.get_interface(), instance); -} - -Find_subscription Connector_factory::subscribe_find_service_wildcard( - Find_result_change_callback on_result_change) { - return get_service_finder().subscribe_find_service(std::move(on_result_change), std::nullopt, - std::nullopt, std::nullopt); -} - score::Result Connector_factory::register_service_bridge( - Bridge_identity identity, Subscribe_find_service_function subscribe_find_service, - Request_service_function request_service) { - return m_runtime->register_service_bridge(identity, std::move(subscribe_find_service), - std::move(request_service)); + Bridge_identity identity, Request_service_function request_service) { + return m_runtime->register_service_bridge(identity, std::move(request_service)); } Disabled_server_connector::Uptr Connector_factory::create_server_connector( diff --git a/src/socom/test/stress/runtime_multi_threading_tests.cpp b/src/socom/test/stress/runtime_multi_threading_tests.cpp index 397f5a02..7e203618 100644 --- a/src/socom/test/stress/runtime_multi_threading_tests.cpp +++ b/src/socom/test/stress/runtime_multi_threading_tests.cpp @@ -108,38 +108,12 @@ class Client_to_connect { } }; -struct Subscribe_find_service_to_call { - std::atomic cb_called{false}; - Find_result_change_callback_mock fsus_mock; - - explicit Subscribe_find_service_to_call(Connector_factory const& connector_factory) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .Times(AnyNumber()) - .WillRepeatedly(Assign(&cb_called, true)); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)) - .Times(AnyNumber()); - } - - Loop_function_t create_thread_function(Connector_factory& connector_factory) { - cb_called = false; - return [&connector_factory, cb = fsus_mock.AsStdFunction()]() { - auto const find_subscription = connector_factory.subscribe_find_service(cb); - }; - } -}; - class RuntimeMultiThreadingTest : public SingleConnectionTest { protected: std::vector const input_find_result{ Service_instance{"first instance", Literal_tag{}}, Service_instance{"second instance", Literal_tag{}}, connector_factory.get_instance()}; - Find_result_change_callback_mock fsus_mock; - - Subscribe_find_service_function_mock sfsf_mock; Request_service_function_mock rsf_mock; Loop_function_t create_servers_thread_main() { @@ -155,10 +129,9 @@ class RuntimeMultiThreadingTest : public SingleConnectionTest { } Loop_function_t create_bridges_thread_main() { - auto const register_bridges = [this, sfsf_mock_function = sfsf_mock.AsStdFunction(), - rsf_mock_function = rsf_mock.AsStdFunction()]() { + auto const register_bridges = [this, rsf_mock_function = rsf_mock.AsStdFunction()]() { auto const registration = connector_factory.register_service_bridge( - Bridge_identity::make(*this), sfsf_mock_function, rsf_mock_function); + Bridge_identity::make(*this), rsf_mock_function); ASSERT_TRUE(registration); }; return register_bridges; @@ -184,29 +157,6 @@ TEST_F(RuntimeMultiThreadingTest, CreationOfServerAndClientConnectorsCallsCallba [&client]() { return static_cast(client.is_satisfied()); }); } -TEST_F(RuntimeMultiThreadingTest, - SubscribeFindServiceAndServerConnectorCreationHasNoRaceCondition) { - Subscribe_find_service_to_call subscribe{connector_factory}; - - auto const start_subscription = subscribe.create_thread_function(connector_factory); - - multi_threaded_test_template({create_servers_thread_main(), start_subscription}, - [&subscribe]() { return static_cast(subscribe.cb_called); }); -} - -TEST_F(RuntimeMultiThreadingTest, - MultipleSubscribeFindServiceAndServerConnectorCreationHasNoRaceCondition) { - Subscribe_find_service_to_call subscribe0{connector_factory}; - auto const start_subscription0 = subscribe0.create_thread_function(connector_factory); - - Subscribe_find_service_to_call subscribe1{connector_factory}; - auto const start_subscription1 = subscribe1.create_thread_function(connector_factory); - - multi_threaded_test_template( - {create_servers_thread_main(), start_subscription0, start_subscription1}, - [&subscribe0, &subscribe1]() { return subscribe0.cb_called && subscribe1.cb_called; }); -} - TEST_F(RuntimeMultiThreadingTest, BridgesWhichCreateServerConnectorsAndClientConnectorsHaveNoRaceCondition) { EXPECT_CALL(rsf_mock, Call(_, _)) @@ -249,38 +199,4 @@ TEST_F(RuntimeMultiThreadingTest, BridgesAndClientConnectorsHaveNoRaceCondition) []() { return true; }); } -TEST_F(RuntimeMultiThreadingTest, BridgesAndSubscribeFindServiceHaveNoRaceConditions) { - EXPECT_CALL(sfsf_mock, Call(_, _, _)) - .Times(AnyNumber()) - .WillRepeatedly([this](auto cb, auto const& /*interface*/, auto /*instance*/) { - for (auto const& result : input_find_result) { - cb(connector_factory.get_configuration().get_interface(), result, - Find_result_status::added); - } - return nullptr; - }); - std::atomic fsus_called_added{false}; - std::atomic fsus_called_delete{false}; - for (auto const& result : input_find_result) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), result, - Find_result_status::added)) - .Times(AnyNumber()) - .WillRepeatedly(Assign(&fsus_called_added, true)); - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), result, - Find_result_status::deleted)) - .Times(AnyNumber()) - .WillRepeatedly(Assign(&fsus_called_delete, true)); - } - - auto const subscribe_find_service = [this, fsus_mock_function = fsus_mock.AsStdFunction()]() { - auto const handle = connector_factory.subscribe_find_service(fsus_mock_function); - }; - - multi_threaded_test_template({create_bridges_thread_main(), subscribe_find_service}, - [&fsus_called_added, &fsus_called_delete]() { - return static_cast(fsus_called_added) && - static_cast(fsus_called_delete); - }); -} - } // namespace score::socom diff --git a/src/socom/test/unit/runtime_tests.cpp b/src/socom/test/unit/runtime_tests.cpp index db69adf2..18ad5482 100644 --- a/src/socom/test/unit/runtime_tests.cpp +++ b/src/socom/test/unit/runtime_tests.cpp @@ -12,13 +12,10 @@ ********************************************************************************/ #include -#include -#include #include #include #include #include -#include #include #include "score/socom/bridge_t.hpp" @@ -34,14 +31,9 @@ using namespace std::chrono_literals; using ::testing::_; -using ::testing::Assign; using ::testing::Bool; -using ::testing::ByMove; using ::testing::Combine; using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::InvokeWithoutArgs; -using ::testing::Return; using ::testing::TestParamInfo; using ::testing::Values; using ::testing::WithParamInterface; @@ -50,7 +42,6 @@ namespace score::socom { enum class Destruction_order { requests_first, bridges_first }; using Bridge_param_tuple = std::tuple; -using Subscribe_find_service_param_tuple = std::tuple; using Bridges = std::vector>; using Atomic_getter = std::atomic const& (Bridge_data::*)() const; @@ -92,46 +83,6 @@ struct Bridge_param { } }; -struct Subscribe_find_service_params { - size_t num_interfaces; - size_t num_instances; - size_t num_subscriptions_before_server_creation; - size_t num_subscriptions_after_server_creation; - bool clear_subscriptions_first; - - explicit Subscribe_find_service_params(Subscribe_find_service_param_tuple const& tuple) - : num_interfaces{std::get<0>(tuple)}, - num_instances{std::get<1>(tuple)}, - num_subscriptions_before_server_creation{std::get<2>(tuple)}, - num_subscriptions_after_server_creation{std::get<3>(tuple)}, - clear_subscriptions_first{std::get<4>(tuple)} {} - - size_t get_total_subsciptions() const { - return num_subscriptions_before_server_creation + num_subscriptions_after_server_creation; - } -}; - -std::string readable_test_names_wildcard( - TestParamInfo const& param_info) { - Subscribe_find_service_params const params{param_info.param}; - std::stringstream ss; - ss << params.num_interfaces << "_interfaces__and_"; - ss << params.num_instances << "_instances__and_"; - ss << params.num_subscriptions_before_server_creation - << "_subscriptions_before_server_creation__and_"; - ss << params.num_subscriptions_after_server_creation - << "_subscriptions_after_server_creation__and_"; - ss << "deleting_"; - if (params.clear_subscriptions_first) { - ss << "subscriptions"; - } else { - ss << "servers"; - } - ss << "_first"; - - return ss.str(); -} - std::string readable_test_names_bridge(TestParamInfo const& param_info) { auto const param = Bridge_param{param_info.param}; std::stringstream ss; @@ -157,31 +108,6 @@ std::string readable_test_names_bridge(TestParamInfo const& return ss.str(); } -std::vector create_subscriptions(size_t const num_find_services, - Find_result_change_callback_mock& fsus_mock, - Connector_factory& connector_factory) { - auto handles = std::vector{}; - handles.reserve(num_find_services); - for (auto i = size_t{0}; i < num_find_services; i++) { - handles.emplace_back(connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance())); - } - - return handles; -} - -template -std::vector create_wildcard_subscriptions(size_t const num, - SubscriptionMockT& mock, - Connector_factory& factory) { - std::vector subscriptions; - subscriptions.reserve(num); - for (size_t i = 0; i < num; i++) { - subscriptions.emplace_back(factory.subscribe_find_service_wildcard(mock.AsStdFunction())); - } - return subscriptions; -} - template void pop_empty(std::vector& v, std::function const& get_atom, Destruction_order const& order) { @@ -210,14 +136,6 @@ bool request_service_destroyed(Bridges const& bridges) { return std::all_of(std::begin(bridges), std::end(bridges), request_find_service_destroyed); } -bool subscribe_find_service_destroyed(Bridges const& bridges) { - auto const find_service_destroyed = [](Bridges::value_type const& bridge) { - return bridge->get_subscribe_find_service_destroyed().load(); - }; - - return std::all_of(std::begin(bridges), std::end(bridges), find_service_destroyed); -} - std::function create_get_destroyed( Bridges const& bridges, std::function const& get_destroyed_fun) { auto const get_destroyed = [&bridges, get_destroyed_fun]() { @@ -329,17 +247,7 @@ class RuntimeTest : public SingleConnectionTest { Service_instance{"second instance", Literal_tag{}}, connector_factory.get_instance()}; Service_instance const expected_find_result{connector_factory.get_instance()}; - std::atomic subscribe_find_service_cb_called{false}; - Find_result_change_callback_mock fsus_mock; - Legacy_find_result_callback_mock legacy_fsus_mock; - - Subscribe_find_service_function_mock sfsf_mock; Request_service_function_mock rsf_mock; - - RuntimeTest() { - ON_CALL(fsus_mock, Call(_, _, _)) - .WillByDefault(Assign(&subscribe_find_service_cb_called, true)); - } }; class RuntimeLegacySubscribeFindServiceTest : public RuntimeTest {}; @@ -351,470 +259,18 @@ MATCHER_P(Multi_set_equal, expected, "") { return (input_set == expected_set); } -TEST_F(RuntimeTest, SubscribeFindServiceWithNoServersDoesNotCallCallback) { - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithDisabledServerConnectorDoesNotCallCallback) { - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - Server_connector_callbacks_mock sc_callbacks; - auto const disabled_server = connector_factory.create_server_connector(sc_callbacks); -} - -TEST_F(RuntimeTest, - SubscribeFindServiceWithLaterStartedServerCallsCallbackWhenServerIsStartedAndStopped) { - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - { - InSequence const is; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - Server_data server{connector_factory}; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - } - - wait_for_atomics(subscribe_find_service_cb_called); -} - -TEST_F(RuntimeTest, - SubscribeFindServiceWithLaterCreatedServerCallsCallbackAfterServerAndClientAreConnected) { - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - { - InSequence const is; - - Client_data client{connector_factory, Client_data::no_connect}; - auto const& client_connected = client.expect_service_state_change(Service_state::available); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - Server_data server{connector_factory}; - - wait_for_atomics(client_connected); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - client.expect_service_state_change(Service_state::not_available); - } - - wait_for_atomics(subscribe_find_service_cb_called); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithLaterCreatedServerCallsMethodCall) { - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - Client_data client{connector_factory, Client_data::might_connect}; - - auto call_method = [this, &client](auto const& /*interface*/, auto const& /*instance*/, - auto const /*status*/) { - client.call_method(method_id, real_payload); - }; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce(DoAll(call_method, Assign(&subscribe_find_service_cb_called, true))); - - auto const& client_connected = client.expect_service_state_change(Service_state::available); - Server_data server{connector_factory, method_id, real_payload}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - client.expect_service_state_change(Service_state::not_available); - - wait_for_atomics(subscribe_find_service_cb_called, client_connected); -} - -TEST_F( - RuntimeTest, - SubscribeFindServiceWithConcurrentlyStartedServerCallsCallbackWhenServerIsStartedAndStopped) { - for (int i = -100; i < 100; i++) { - auto const server_sweep_delay = i > 0 ? i : 0; - auto const find_sweep_delay = i < 0 ? (i * -1) : 0; - - { - InSequence const is; - EXPECT_CALL(fsus_mock, - Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - EXPECT_CALL(fsus_mock, - Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - } - - std::atomic_bool find_subscription_completed{false}; - auto server_thread = - std::thread([this, server_sweep_delay, &find_subscription_completed]() { - std::this_thread::sleep_for(std::chrono::nanoseconds(server_sweep_delay)); - - Server_data server{connector_factory}; - - wait_for_atomics(find_subscription_completed); - }); - - std::this_thread::sleep_for(std::chrono::nanoseconds(find_sweep_delay)); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - find_subscription_completed = true; - server_thread.join(); - } -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithCreatedAndDestroyedStartedServerCallsNoCallback) { - std::unique_ptr client{}; - { - Server_data server{connector_factory}; - client = std::make_unique( - connector_factory, Client_data::No_connect_helper::might_connect, - [](auto&& /*unused*/, auto&& /*unused*/, auto&& /*unused*/) {}); - } - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - EXPECT_FALSE(subscribe_find_service_cb_called); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithStartedServerReturnsInterfaceAndInstanceId) { - Server_data const server{connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - EXPECT_TRUE(subscribe_find_service_cb_called); - - wait_for_atomics(subscribe_find_service_cb_called); -} - -TEST_F( - RuntimeTest, - SubscribeFindServiceWithStartedServerReturnsInterfaceAndInstanceIdAndCreatesClientConnector) { - Server_data const server{connector_factory}; - std::optional client; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce(DoAll( - [this, &client](Service_interface_identifier const& /*ignore*/, - Service_instance const& /*ignore*/, - Find_result_status /*ignore*/) { client.emplace(connector_factory); }, - Assign(&subscribe_find_service_cb_called, true))); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - wait_for_atomics(subscribe_find_service_cb_called); -} - -TEST_F( - RuntimeTest, - SubscribeFindServiceWithLaterStartedServerReturnsInterfaceAndInstanceIdAndCreatesClientConnector) { - std::atomic available{false}; - Client_connector_callbacks_mock client_mocks; - std::optional client; - - { - InSequence const is; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce(DoAll( - [this, &client, &client_mocks, &available]( - Service_interface_identifier const& /*ignore*/, - Service_instance const& /*ignore*/, Find_result_status /*ignore*/) { - // switch to Enabled_server_connector - EXPECT_CALL(client_mocks, - on_service_state_change(_, Service_state::available, _)) - .WillOnce(Assign(&available, true)); - client.emplace(connector_factory.create_client_connector(client_mocks)); - }, - Assign(&subscribe_find_service_cb_called, true))); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - } - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - Server_data const server{connector_factory}; - - wait_for_atomics(subscribe_find_service_cb_called, available); - EXPECT_TRUE(client); - EXPECT_CALL(client_mocks, on_service_state_change(_, Service_state::not_available, _)); -} - -TEST_F(RuntimeTest, SubscribeFindServiceCallbackDeletesClientOnServerDestructionWithoutDeadlock) { - std::atomic available{false}; - Client_connector_callbacks_mock client_mocks; - std::optional client; - - { - InSequence const is; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - auto const destroy_client = [&client](auto const& /* interface*/, auto const& /* instance*/, - auto const& /*status*/) { client.reset(); }; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)) - .WillOnce(destroy_client); - } - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - { - Server_data const server{connector_factory}; - - EXPECT_CALL(client_mocks, on_service_state_change(_, Service_state::available, _)) - .WillOnce(Assign(&available, true)); - client.emplace(connector_factory.create_client_connector(client_mocks)); - - wait_for_atomics(available); - EXPECT_TRUE(client); - } - EXPECT_FALSE(client); -} - -TEST_F(RuntimeTest, SubscribeFindServiceCallbackResetsItself) { - Find_subscription find_subscription{}; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce([&find_subscription](auto const& /*ignore*/, auto const& /*ignore*/, - auto /*ignore*/) { find_subscription.reset(); }); - find_subscription = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - Server_data server{connector_factory}; -} - -TEST_F(RuntimeTest, - SubscribeFindServiceCallbackResetsItselfAndCreatesServerToOwnSubscriptionWhichIsNotCalled) { - Find_subscription find_subscription{}; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce([this, &find_subscription](auto const& /*ignore*/, auto const& /*ignore*/, - auto /*ignore*/) { - static int instance_number = 0; - auto instance = Service_instance{std::to_string(instance_number++)}; - find_subscription.reset(); - Server_data server{this->connector_factory, this->connector_factory.get_configuration(), - instance}; // Replace with another factory - }); - find_subscription = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - Server_data server{connector_factory}; -} - -TEST_F(RuntimeTest, SubscribeFindServiceCallbackResetsItselfAndCreatesClient) { - Find_subscription find_subscription{}; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce([this, &find_subscription](auto const& /*ignore*/, auto const& /*ignore*/, - auto /*ignore*/) { - find_subscription.reset(); - Client_data server{this->connector_factory}; - }); - find_subscription = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - Server_data server{connector_factory}; -} - -TEST_F(RuntimeTest, SubscribeFindServiceCallbackIsResetWhileRuntimeCallsCallbacks) { - Find_subscription find_subscription{}; - Find_result_change_callback_mock fsus_mock2; - Find_subscription find_subscription2{}; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce([&find_subscription2](auto const& /*ignore*/, auto const& /*ignore*/, - auto /*ignore*/) { find_subscription2.reset(); }); - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - find_subscription = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - find_subscription2 = connector_factory.subscribe_find_service(fsus_mock2.AsStdFunction()); - Server_data server{connector_factory}; -} - -TEST_F(RuntimeTest, - SubscribeFindServiceCallbackDestructionIsBlockedUntilCallbackExecutionIsFinished) { - std::promise callback_called; - std::promise proceed_in_callback; - - auto wait_for_subscription_reset = [&callback_called, &proceed_in_callback]() { - auto const timeout = 10ms; - // the other thread is continuing after setting the promise, thus taking this as the - // start time to be sure 100ms really have elapsed on any server load - callback_called.set_value(); - EXPECT_EQ(std::future_status::timeout, proceed_in_callback.get_future().wait_for(timeout)); - }; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce(InvokeWithoutArgs(wait_for_subscription_reset)); - - auto find_subscription = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - auto delete_subscription = std::async( - std::launch::async, [&callback_called, &proceed_in_callback, &find_subscription]() { - callback_called.get_future().wait(); - find_subscription.reset(); - proceed_in_callback.set_value(); - }); - - Server_data server{connector_factory}; - - delete_subscription.wait(); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithWildcardReturnsInterfaceAndInstanceId) { - Server_data const server{connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - wait_for_atomics(subscribe_find_service_cb_called); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithUnknownServiceInstanceDoesNotCallCallback) { - Server_data const server{connector_factory}; - - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - - auto const find_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), Service_instance{"not_to_be_known_by_anyone", Literal_tag{}}); -} - -TEST_F(RuntimeTest, DeletingSubscribeFindServiceHandleStopsReporting) { - Find_result_change_callback_mock sanity_fsus_mock; - std::atomic sanity_cb_called{false}; - - { - InSequence const is; - EXPECT_CALL(sanity_fsus_mock, - Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)) - .WillOnce(Assign(&sanity_cb_called, true)); - - EXPECT_CALL(sanity_fsus_mock, - Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - } - - auto const sanity_find_subscription = - connector_factory.subscribe_find_service(sanity_fsus_mock.AsStdFunction()); - - { - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - } - - Server_data const server{connector_factory}; - - wait_for_atomics(sanity_cb_called); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithInvalidCallbackHasNoEffect) { - Server_data const server{connector_factory}; - - EXPECT_NO_FATAL_FAILURE(auto const find_subscription = connector_factory.subscribe_find_service( - Find_result_change_callback{})); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithWildCardWithInvalidCallbackHasNoEffect) { - Server_data const server{connector_factory}; - - EXPECT_NO_FATAL_FAILURE( - auto const find_subscription = - connector_factory.subscribe_find_service_wildcard(Find_result_change_callback{})); -} - -TEST_F(RuntimeTest, SubscribeFindServiceDuringRegisterServiceBridge) { - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - auto instance_2 = Service_instance{"TestInstance2", Literal_tag{}}; - Find_subscription normal_subscription_2; - - Bridge_data* bridge_ptr{nullptr}; - auto bridge_sfs_expect = [&bridge_ptr](Bridge_data& bridge) { bridge_ptr = &bridge; }; - - auto bridge_sfs_callback{[this, &instance_2, &normal_subscription_2, &bridge_ptr]( - auto cb, auto interface, auto ref_instance) { - bridge_ptr->expect_another_subscribe_find_service( - connector_factory.get_configuration().get_interface(), - std::optional(instance_2)); - - normal_subscription_2 = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction(), instance_2); - - bridge_ptr->expect_another_subscribe_find_service( - connector_factory.get_configuration().get_interface(), - std::optional(instance_2)); - - return Bridge_data::sfs_do_nothing()(cb, interface, ref_instance); - }}; - - Bridge_data bridge{Bridge_data::expect_then_bridge, Bridge_data::subscribe_find_service, - connector_factory, bridge_sfs_expect, bridge_sfs_callback}; - bridge.no_destroyed_check(); -} - -TEST_F(RuntimeTest, SubscribeFindServiceWithoutInstanceBeforeRegisterServiceBridge) { - auto const normal_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - Subscribe_find_service_function_mock m_sfsf_mock; - Request_service_function_mock m_rsf_mock; - - std::optional opt_ref_instance_empty{}; - - EXPECT_CALL(m_sfsf_mock, Call(_, connector_factory.get_configuration().get_interface(), - opt_ref_instance_empty)) - .WillOnce(Return(ByMove(std::make_unique()))); - - auto const registration = connector_factory.register_service_bridge( - Bridge_identity::make(*this), m_sfsf_mock.AsStdFunction(), m_rsf_mock.AsStdFunction()); -} - TEST_F(RuntimeTest, RegisterServiceBridgeWithIncompleteCallbacksReturnsCallbacksMissing) { auto const callback_missing = score::MakeUnexpected(Construction_error::callback_missing); - auto const callbacks = - std::vector>{ - {nullptr, nullptr}, - {sfsf_mock.AsStdFunction(), nullptr}, - {nullptr, rsf_mock.AsStdFunction()}}; - - for (auto const& cb : callbacks) { - auto const registration = connector_factory.register_service_bridge( - Bridge_identity::make(*this), cb.first, cb.second); - EXPECT_EQ(registration, callback_missing); - } + auto const registration = + connector_factory.register_service_bridge(Bridge_identity::make(*this), nullptr); + EXPECT_EQ(registration, callback_missing); } TEST_F(RuntimeTest, RegisterServiceBridgeWitCallbacksReturnsRegistration) { score::Result const registration = - connector_factory.register_service_bridge( - Bridge_identity::make(*this), sfsf_mock.AsStdFunction(), rsf_mock.AsStdFunction()); + connector_factory.register_service_bridge(Bridge_identity::make(*this), + rsf_mock.AsStdFunction()); ASSERT_TRUE(registration); EXPECT_TRUE(registration.value()); } @@ -858,226 +314,6 @@ TEST_F(RuntimeTest, state_change_callback.as_function()}; } -TEST_F(RuntimeTest, SubscribeFindServiceWithWildcardReturnsBridgesMultipleFoundServices) { - Bridge_data bridge{Bridge_data::bridge_then_expect, Bridge_data::nothing, connector_factory}; - bridge.expect_subscribe_find_service(connector_factory.get_configuration().get_interface(), {}); - - auto const find_handle = connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - wait_for_atomics(bridge.get_subscribe_find_service_created()); - std::atomic fsus_with_input_called{false}; - for (auto const& result : input_find_result) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), result, - Find_result_status::added)) - .WillOnce(Assign(&fsus_with_input_called, true)); - fsus_with_input_called = false; - bridge.find_service(connector_factory.get_configuration().get_interface(), result, - Find_result_status::added); - wait_for_atomics(fsus_with_input_called); - } -} - -TEST_F(RuntimeTest, BridgeDeletionWillReportFoundServicesDeleted) { - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - Bridge_data bridge{Bridge_data::expect_then_bridge, Bridge_data::subscribe_find_service, - connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - bridge.find_service(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - - bridge.no_destroyed_check(); -} - -TEST_F(RuntimeTest, BridgeDeletionOfNonAvailableService) { - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - Bridge_data bridge{Bridge_data::expect_then_bridge, Bridge_data::subscribe_find_service, - connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)) - .Times(0U); - - auto const interface = Service_interface_identifier{"TestInterface1", Literal_tag{}, {9U, 1U}}; - bridge.find_service(interface, connector_factory.get_instance(), Find_result_status::deleted); - - bridge.no_destroyed_check(); -} - -TEST_F(RuntimeTest, BridgeDoesNotReceiveWildcardSubscription) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::nothing, - connector_factory}; - - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - auto const subscription = - connector_factory.subscribe_find_service_wildcard(fsus_mock.AsStdFunction()); - - EXPECT_FALSE(bridge.get_subscribe_find_service_created()); -} - -TEST_F(RuntimeTest, BridgeDoesNotReceiveWildcardSubscriptionsWhenItIsRegisteredLater) { - EXPECT_CALL(fsus_mock, Call(_, _, _)).Times(0); - auto const subscription = - connector_factory.subscribe_find_service_wildcard(fsus_mock.AsStdFunction()); - - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::nothing, - connector_factory}; - - EXPECT_FALSE(bridge.get_subscribe_find_service_created()); -} - -TEST_F(RuntimeTest, BridgeFindResultsAreNotForwardedToWildcardSubscriptions) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::subscribe_find_service, - connector_factory}; - - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - Find_result_change_callback_mock wildcard_mock; - auto const subscription = - connector_factory.subscribe_find_service_wildcard(wildcard_mock.AsStdFunction()); - - EXPECT_CALL(wildcard_mock, Call(_, _, _)).Times(0); - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - bridge.find_service(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added); -} - -TEST_F(RuntimeTest, BridgeFindResultsFromCacheAreNotForwardedToWildcardSubscription) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::subscribe_find_service, - connector_factory}; - - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - bridge.find_service(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added); - - Find_result_change_callback_mock wildcard_mock; - EXPECT_CALL(wildcard_mock, Call(_, _, _)).Times(0); - auto const subscription = - connector_factory.subscribe_find_service_wildcard(wildcard_mock.AsStdFunction()); -} - -TEST_F(RuntimeTest, BridgeDeletionWillNotCallWildcardSubscription) { - auto const normal_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - Find_result_change_callback_mock wildcard_mock; - EXPECT_CALL(wildcard_mock, Call(_, _, _)).Times(0); - auto const subscription = - connector_factory.subscribe_find_service_wildcard(wildcard_mock.AsStdFunction()); - - Bridge_data bridge{Bridge_data::expect_then_bridge, Bridge_data::subscribe_find_service, - connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - bridge.find_service(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added); - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)); - - bridge.no_destroyed_check(); -} - -TEST_F(RuntimeTest, FindSubscriptionsNoLoopBridgeOnly) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::nothing, - connector_factory}; - - auto const self_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), bridge.get_identity()); -} - -TEST_F(RuntimeTest, FindSubscriptionsNoLoopBridgeOnly2Times) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::nothing, - connector_factory}; - - { - auto const self_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), bridge.get_identity()); - } - - { - auto const self_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), bridge.get_identity()); - } -} - -TEST_F(RuntimeTest, FindSubscriptionsNoLoopBridgeSecondAndOther) { - Bridge_data const bridge{Bridge_data::bridge_then_expect, Bridge_data::subscribe_find_service, - connector_factory}; - - auto const other_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance()); - - ASSERT_TRUE(bridge.get_subscribe_find_service_created()); - { - auto const self_subscription = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), bridge.get_identity()); - - ASSERT_TRUE(bridge.get_subscribe_find_service_created()); - ASSERT_FALSE(bridge.get_subscribe_find_service_destroyed()); - } - EXPECT_FALSE(bridge.get_subscribe_find_service_destroyed()); -} - -TEST_F(RuntimeTest, FindSubscriptionsNoLoopTwoBridgesSecondAndOther) { - Bridge_data first_bridge{Bridge_data::bridge_then_expect, Bridge_data::subscribe_find_service, - connector_factory}; - - Bridge_data second_bridge{Bridge_data::bridge_then_expect, Bridge_data::subscribe_find_service, - connector_factory}; - - auto const self_subscription_first_bridge = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), first_bridge.get_identity()); - - EXPECT_TRUE(second_bridge.get_subscribe_find_service_created()); - - auto const self_subscription_second_bridge = connector_factory.subscribe_find_service( - fsus_mock.AsStdFunction(), connector_factory.get_instance(), second_bridge.get_identity()); - - EXPECT_TRUE(first_bridge.get_subscribe_find_service_created()); - EXPECT_TRUE(second_bridge.get_subscribe_find_service_created()); - - EXPECT_FALSE(first_bridge.get_subscribe_find_service_destroyed()); - EXPECT_FALSE(second_bridge.get_subscribe_find_service_destroyed()); - - first_bridge.no_destroyed_check(); - second_bridge.no_destroyed_check(); -} - -TEST_F(RuntimeTest, AllExceptionsAreCatchedWhileInformingSubscribersAtServerDestruction) { - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - - EXPECT_NO_THROW({ - InSequence const is; - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::added)); - - Server_data server{connector_factory}; - - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), Find_result_status::deleted)) - .WillOnce([](auto, auto, auto) { throw std::exception(); }); - }); - wait_for_atomics(subscribe_find_service_cb_called); -} - TEST_F(RuntimeTest, ConstructDuplicateReturnsDuplicateServiceError) { Server_connector_callbacks_mock callbacks; auto const scd = connector_factory.create_server_connector_with_result(callbacks); @@ -1135,256 +371,6 @@ TEST_F(RuntimeTest, ConnectorDestroyedAfterRuntimeDoesNotCrash) { } } -TEST_F(RuntimeTest, SubscribeFindServiceWithStartedServerFindResultCallbackThrowsException) { - Server_data const server{connector_factory}; - - EXPECT_NO_THROW({ - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - connector_factory.get_instance(), _)) - .WillOnce( - Invoke([this](Service_interface_identifier const& /*ignore*/, - Service_instance const& /*ignore*/, Find_result_status /*ignore*/) { - subscribe_find_service_cb_called = true; - throw std::runtime_error("fatal error"); - })); - - auto const find_subscription = - connector_factory.subscribe_find_service(fsus_mock.AsStdFunction()); - }); - - wait_for_atomics(subscribe_find_service_cb_called); -} - -class RuntimeSubscribeFindServiceTest - : public RuntimeTest, - public WithParamInterface { - protected: - Subscribe_find_service_params const m_param{GetParam()}; -}; - -TEST_P(RuntimeSubscribeFindServiceTest, SubscribeFindServiceWithWildCardReportsServices) { - auto const interfaces = create_service_interfaces(m_param.num_interfaces); - auto const instances = create_instances(m_param.num_instances); - - auto subscriptions = create_wildcard_subscriptions( - m_param.num_subscriptions_before_server_creation, fsus_mock, connector_factory); - - std::vector> servers; - for (auto const& interface : interfaces) { - for (auto const& instance : instances) { - EXPECT_CALL(fsus_mock, - Call(interface.get_interface(), instance, Find_result_status::added)) - .Times(static_cast(m_param.get_total_subsciptions())); - servers.emplace_back( - std::make_unique(connector_factory, interface, instance)); - EXPECT_CALL(fsus_mock, - Call(interface.get_interface(), instance, Find_result_status::deleted)) - .Times(static_cast( - m_param.get_total_subsciptions() * - static_cast(!m_param.clear_subscriptions_first))); - } - } - - append(subscriptions, - create_wildcard_subscriptions(m_param.num_subscriptions_after_server_creation, fsus_mock, - connector_factory)); - if (m_param.clear_subscriptions_first) { - subscriptions.clear(); - } -} - -INSTANTIATE_TEST_SUITE_P(Wildcard, RuntimeSubscribeFindServiceTest, - Combine(Values(0, 1, 10), Values(1, 10), Values(0, 1, 10), - Values(0, 1, 10), Bool()), - readable_test_names_wildcard); - -TEST_F(RuntimeLegacySubscribeFindServiceTest, SubscriptionTriggersCallback) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - Server_data const server{connector_factory, interface, instance}; - - Find_result_container expected_container{instance}; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(1); - (void)connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), instance); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, SubscriptionTriggersCallbackForMultipleInstances) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - std::size_t const instance_id0{0}; - auto const instance0 = create_service_instance(instance_id0); - std::size_t const instance_id1{1}; - auto const instance1 = create_service_instance(instance_id1); - std::size_t const instance_id2{2}; - auto const instance2 = create_service_instance(instance_id2); - - Server_data const server0{connector_factory, interface, instance0}; - Server_data const server1{connector_factory, interface, instance1}; - Server_data const server2{connector_factory, interface, instance2}; - - Find_result_container expected_container{instance0, instance1, instance2}; - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(1); - (void)connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), {}); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, SubscriptionTriggersCallbackForMultipleInterfaces) { - std::size_t const interface_id0{0}; - auto const interface0 = create_service_interface_configuration(interface_id0); - std::size_t const interface_id1{1}; - auto const interface1 = create_service_interface_configuration(interface_id1); - std::size_t const interface_id2{2}; - auto const interface2 = create_service_interface_configuration(interface_id2); - - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - Server_data const server0{connector_factory, interface0, instance}; - Server_data const server1{connector_factory, interface1, instance}; - Server_data const server2{connector_factory, interface2, instance}; - - Find_result_container expected_container{instance}; - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(3); - (void)connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface0.get_interface(), instance); - (void)connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface1.get_interface(), instance); - (void)connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface2.get_interface(), instance); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, EachSubscriptionTriggersCallback) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - Server_data const server{connector_factory, interface, instance}; - - Find_result_container expected_container{instance}; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(2); - - auto subscription0 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), instance); - auto subscription1 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), instance); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, ServerCreationTriggersCallback) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - auto subscription = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), instance); - Find_result_container const expected_container{instance}; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(1); - - Server_data const server{connector_factory, interface, instance}; - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{}))).Times(1); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, - EmptyInstanceSetWontTriggerCallbackAtServerDestruction) { - auto const interface = create_service_interface_configuration(0); - auto const instance = create_service_instance(0); - - auto subscription = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), instance); - - { - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{instance}))) - .WillOnce([](Find_result_container const& result) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) - const_cast(result).clear(); - }); - - Server_data const server{connector_factory, interface, instance}; - - EXPECT_CALL(legacy_fsus_mock, Call(_)).Times(0); - } -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, ServerCreationTriggersCallbackForMultipleInstances) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - - std::size_t const instance_id0{0}; - auto const instance0 = create_service_instance(instance_id0); - std::size_t const instance_id1{1}; - auto const instance1 = create_service_instance(instance_id1); - - auto subscription = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), {}); - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{instance0}))); - - std::vector> servers; - servers.emplace_back(std::make_unique(connector_factory, interface, instance0)); - // callback is invoked for the second server - EXPECT_CALL(legacy_fsus_mock, - Call(Multi_set_equal(Find_result_container{instance0, instance1}))); - servers.emplace_back(std::make_unique(connector_factory, interface, instance1)); - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{instance1}))); - servers.erase(std::begin(servers)); - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{}))); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, ServerCreationTriggersCallbackForMultipleInterfaces) { - std::size_t const interface_id0{0}; - auto const interface0 = create_service_interface_configuration(interface_id0); - std::size_t const interface_id1{1}; - auto const interface1 = create_service_interface_configuration(interface_id1); - - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - auto subscription0 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface0.get_interface(), {}); - auto subscription1 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface1.get_interface(), {}); - - std::vector> servers; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{instance}))); - servers.emplace_back(std::make_unique(connector_factory, interface0, instance)); - - // callback is invoked for second server - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{instance}))); - servers.emplace_back(std::make_unique(connector_factory, interface1, instance)); - - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{}))).Times(2); -} - -TEST_F(RuntimeLegacySubscribeFindServiceTest, CreateServerTriggersCallbackForEachSubscription) { - std::size_t const interface_id{0}; - auto const interface = create_service_interface_configuration(interface_id); - - std::size_t const instance_id{0}; - auto const instance = create_service_instance(instance_id); - - auto subscription0 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), {}); - auto subscription1 = connector_factory.get_service_finder().subscribe_find_service( - legacy_fsus_mock.AsStdFunction(), interface.get_interface(), {}); - - Find_result_container expected_container{instance}; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(expected_container))).Times(2); - - Server_data const server{connector_factory, interface, instance}; - EXPECT_CALL(legacy_fsus_mock, Call(Multi_set_equal(Find_result_container{}))).Times(2); -} - class RuntimeBridgeTest : public RuntimeTest, public WithParamInterface { protected: Bridge_param m_param = Bridge_param{GetParam()}; @@ -1403,89 +389,6 @@ TEST_P(RuntimeBridgeTest, CreationOfClientsWillCallRequestServiceFunction) { &Bridge_data::get_request_find_service_created, post_check); } -TEST_P(RuntimeBridgeTest, SubscribeFindServiceWillCallCallbackOfBridges) { - auto const create_requests = [this](size_t num_requests) { - return create_subscriptions(num_requests, fsus_mock, connector_factory); - }; - - auto const post_check = [this](Bridge_data const& bridge) { - InSequence const is; - - // immediately delete services to prevent usage of cache - std::array const stati = {Find_result_status::added, - Find_result_status::deleted}; - for (auto const& status : stati) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, status)) - .Times(m_param.get_total_requests()); - bridge.find_service(connector_factory.get_configuration().get_interface(), - expected_find_result, status); - } - }; - - bridge_test_template(create_requests, m_param, connector_factory, - Bridge_data::subscribe_find_service, subscribe_find_service_destroyed, - &Bridge_data::get_subscribe_find_service_created, post_check); -} - -TEST_P(RuntimeBridgeTest, SubscribeFindServiceWithCachedServicesUpdatesCacheOnBridgeChanges) { - size_t check_called{0}; - auto const create_requests = [this, &check_called](size_t num_requests) { - // prepare for deletion of found services when bridges are going to be destroyed - if (1 == check_called && m_param.delete_and_recreate_bridges) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::deleted)) - .Times(static_cast( - m_param.get_total_requests() * m_param.num_bridges * - (1 + static_cast( - !m_param.delete_and_recreate_requests && - (Destruction_order::bridges_first == m_param.order))))); - } - - // Callback is called last time, prepare callbacks for Bridge destruction - if (1 == check_called && !m_param.delete_and_recreate_bridges && - !m_param.delete_and_recreate_requests && - Destruction_order::bridges_first == m_param.order) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::deleted)) - .Times(static_cast(m_param.get_total_requests() * m_param.num_bridges)); - } - - // requests are recreated and possible already reported Services by Bridges need to be - // expected - if (2 == check_called) { - // expect already reported services - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::added)) - .Times(static_cast(m_param.get_total_requests() * m_param.num_bridges)); - if (Destruction_order::bridges_first == m_param.order) { - // expect destruction of previously reported services and soon to be reported - // services - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::deleted)) - .Times(static_cast( - m_param.get_total_requests() * m_param.num_bridges * - (1 + static_cast(!m_param.delete_and_recreate_bridges || - m_param.delete_and_recreate_requests)))); - } - } - check_called++; - return create_subscriptions(num_requests, fsus_mock, connector_factory); - }; - - auto const post_check = [this](Bridge_data const& bridge) { - EXPECT_CALL(fsus_mock, Call(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::added)) - .Times(static_cast(m_param.get_total_requests())); - bridge.find_service(connector_factory.get_configuration().get_interface(), - expected_find_result, Find_result_status::added); - }; - - bridge_test_template(create_requests, m_param, connector_factory, - Bridge_data::subscribe_find_service, subscribe_find_service_destroyed, - &Bridge_data::get_subscribe_find_service_created, post_check); -} - INSTANTIATE_TEST_SUITE_P(Bridge, RuntimeBridgeTest, Combine(Values(0, 1, 10), Values(0, 1, 10), Values(1, 10), Values(Destruction_order::requests_first, diff --git a/src/socom/test/unit/smoke_test.cpp b/src/socom/test/unit/smoke_test.cpp index d6ee8119..1d3b80e3 100644 --- a/src/socom/test/unit/smoke_test.cpp +++ b/src/socom/test/unit/smoke_test.cpp @@ -18,7 +18,6 @@ #include using ::testing::_; -using ::testing::MockFunction; namespace score::socom { @@ -31,9 +30,6 @@ class Runtime_test : public ::testing::Test { Runtime::Uptr runtime = create_runtime(); - // Runtime mocks - Find_result_change_callback_mock m_find_result_mock; - // Client_connector mocks Service_state_change_callback_mock m_service_state_change_mock; Event_update_callback_mock m_event_update_mock; @@ -106,23 +102,6 @@ TEST_F(Runtime_test, server_connector_construction_works) { EXPECT_TRUE(server_connector_result); } -TEST_F(Runtime_test, subscribe_find_service_finds_server) { - auto const find_subscription = runtime->subscribe_find_service( - m_find_result_mock.AsStdFunction(), config.get_interface(), std::nullopt, std::nullopt); - - EXPECT_CALL(m_find_result_mock, Call(_, _, Find_result_status::added)).Times(1); - - auto server_connector_result = - runtime->make_server_connector(config, instance, make_server_callbacks()); - ASSERT_TRUE(server_connector_result); - auto enabled_server_connector = - Disabled_server_connector::enable(std::move(server_connector_result.value())); - - EXPECT_CALL(m_find_result_mock, Call(_, _, Find_result_status::deleted)).Times(1); - - enabled_server_connector.reset(); -} - TEST_F(Runtime_test, connection_setup_works) { auto const client_connector_result = runtime->make_client_connector(config, instance, make_client_callbacks());