diff --git a/iceoryx_posh/test/moduletests/test_roudi_portmanager_client_server.cpp b/iceoryx_posh/test/moduletests/test_roudi_portmanager_client_server.cpp new file mode 100644 index 00000000000..5ef218fef21 --- /dev/null +++ b/iceoryx_posh/test/moduletests/test_roudi_portmanager_client_server.cpp @@ -0,0 +1,155 @@ +// Copyright (c) 2019 - 2021 by Robert Bosch GmbH. All rights reserved. +// Copyright (c) 2021 - 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "test_roudi_portmanager_fixture.hpp" + +namespace iox_test_roudi_portmanager +{ +using namespace iox::popo; + +constexpr uint64_t RESPONSE_QUEUE_CAPACITY{2U}; +constexpr uint64_t REQUEST_QUEUE_CAPACITY{2U}; + +ClientOptions createTestClientOptions() +{ + return ClientOptions{RESPONSE_QUEUE_CAPACITY, iox::NodeName_t("node")}; +} + +ServerOptions createTestServerOptions() +{ + return ServerOptions{REQUEST_QUEUE_CAPACITY, iox::NodeName_t("node")}; +} + +// BEGIN aquireClientPortData tests + +TEST_F(PortManager_test, AcquireClientPortDataReturnsPort) +{ + ::testing::Test::RecordProperty("TEST_ID", "92225f2c-619a-425b-bba0-6a014822c4c3"); + const ServiceDescription sd{"hyp", "no", "toad"}; + const RuntimeName_t runtimeName{"hypnotoad"}; + auto clientOptions = createTestClientOptions(); + clientOptions.connectOnCreate = false; + clientOptions.responseQueueFullPolicy = QueueFullPolicy::BLOCK_PRODUCER; + clientOptions.serverTooSlowPolicy = ConsumerTooSlowPolicy::WAIT_FOR_CONSUMER; + m_portManager->acquireClientPortData(sd, clientOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .and_then([&](const auto& clientPortData) { + EXPECT_THAT(clientPortData->m_serviceDescription, Eq(sd)); + EXPECT_THAT(clientPortData->m_runtimeName, Eq(runtimeName)); + EXPECT_THAT(clientPortData->m_nodeName, Eq(clientOptions.nodeName)); + EXPECT_THAT(clientPortData->m_toBeDestroyed, Eq(false)); + EXPECT_THAT(clientPortData->m_chunkReceiverData.m_queue.capacity() , Eq(clientOptions.responseQueueCapacity)); + EXPECT_THAT(clientPortData->m_connectRequested, Eq(clientOptions.connectOnCreate)); + EXPECT_THAT(clientPortData->m_chunkReceiverData.m_queueFullPolicy, Eq(clientOptions.responseQueueFullPolicy)); + EXPECT_THAT(clientPortData->m_chunkSenderData.m_consumerTooSlowPolicy, Eq(clientOptions.serverTooSlowPolicy)); + }) + .or_else([&](const auto& error) { + GTEST_FAIL() << "Expected ClientPortData but got PortPoolError: " << static_cast(error); + }); +} + +// END aquireClientPortData tests + +// BEGIN aquireServerPortData tests + +TEST_F(PortManager_test, AcquireServerPortDataReturnsPort) +{ + ::testing::Test::RecordProperty("TEST_ID", "776c51c4-074a-4404-b6a7-ed08f59f05a0"); + const ServiceDescription sd{"hyp", "no", "toad"}; + const RuntimeName_t runtimeName{"hypnotoad"}; + auto serverOptions = createTestServerOptions(); + serverOptions.offerOnCreate = false; + serverOptions.requestQueueFullPolicy = QueueFullPolicy::BLOCK_PRODUCER; + serverOptions.clientTooSlowPolicy = ConsumerTooSlowPolicy::WAIT_FOR_CONSUMER; + m_portManager->acquireServerPortData(sd, serverOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .and_then([&](const auto& serverPortData) { + EXPECT_THAT(serverPortData->m_serviceDescription, Eq(sd)); + EXPECT_THAT(serverPortData->m_runtimeName, Eq(runtimeName)); + EXPECT_THAT(serverPortData->m_nodeName, Eq(serverOptions.nodeName)); + EXPECT_THAT(serverPortData->m_toBeDestroyed, Eq(false)); + EXPECT_THAT(serverPortData->m_chunkReceiverData.m_queue.capacity(), Eq(serverOptions.requestQueueCapacity)); + EXPECT_THAT(serverPortData->m_offeringRequested, Eq(serverOptions.offerOnCreate)); + EXPECT_THAT(serverPortData->m_chunkReceiverData.m_queueFullPolicy, Eq(serverOptions.requestQueueFullPolicy)); + EXPECT_THAT(serverPortData->m_chunkSenderData.m_consumerTooSlowPolicy, Eq(serverOptions.clientTooSlowPolicy)); + }) + .or_else([&](const auto& error) { + GTEST_FAIL() << "Expected ClientPortData but got PortPoolError: " << static_cast(error); + }); +} + +TEST_F(PortManager_test, AcquireServerPortDataWithSameServiceDescriptionTwiceCallsErrorHandlerAndReturnsError) +{ + ::testing::Test::RecordProperty("TEST_ID", "9f2c24ba-192d-4ce8-a61a-fe40b42c655b"); + const ServiceDescription sd{"hyp", "no", "toad"}; + const RuntimeName_t runtimeName{"hypnotoad"}; + auto serverOptions = createTestServerOptions(); + + // first call must be successful + m_portManager->acquireServerPortData(sd, serverOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .or_else([&](const auto& error) { + GTEST_FAIL() << "Expected ClientPortData but got PortPoolError: " << static_cast(error); + }); + + iox::cxx::optional detectedError; + auto errorHandlerGuard = + iox::ErrorHandler::setTemporaryErrorHandler([&](const auto error, const auto, const auto errorLevel) { + EXPECT_THAT(error, Eq(iox::Error::kPOSH__PORT_MANAGER_SERVERPORT_NOT_UNIQUE)); + EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::MODERATE)); + detectedError.emplace(error); + }); + + // second call must fail + m_portManager->acquireServerPortData(sd, serverOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .and_then([&](const auto&) { + GTEST_FAIL() << "Expected PortPoolError::UNIQUE_SERVER_PORT_ALREADY_EXISTS but got ServerPortData"; + }) + .or_else([&](const auto& error) { EXPECT_THAT(error, Eq(PortPoolError::UNIQUE_SERVER_PORT_ALREADY_EXISTS)); }); + + EXPECT_TRUE(detectedError.has_value()); +} + +TEST_F(PortManager_test, AcquireServerPortDataWithSameServiceDescriptionTwiceAndFirstPortMarkedToBeDestroyedReturnsPort) +{ + ::testing::Test::RecordProperty("TEST_ID", "d7f2815d-f1ea-403d-9355-69470d92a10f"); + const ServiceDescription sd{"hyp", "no", "toad"}; + const RuntimeName_t runtimeName{"hypnotoad"}; + auto serverOptions = createTestServerOptions(); + + // first call must be successful + auto serverPortDataResult = + m_portManager->acquireServerPortData(sd, serverOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}); + + ASSERT_FALSE(serverPortDataResult.has_error()); + + serverPortDataResult.value()->m_toBeDestroyed = true; + + iox::cxx::optional detectedError; + auto errorHandlerGuard = iox::ErrorHandler::setTemporaryErrorHandler( + [&](const auto error, const auto, const auto) { detectedError.emplace(error); }); + + // second call must now also succeed + m_portManager->acquireServerPortData(sd, serverOptions, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .or_else([&](const auto& error) { + GTEST_FAIL() << "Expected ClientPortData but got PortPoolError: " << static_cast(error); + }); + + detectedError.and_then( + [&](const auto& error) { GTEST_FAIL() << "Expected error handler to not be called but got: " << error; }); +} + +// END aquireServerPortData tests + +} // namespace iox_test_roudi_portmanager diff --git a/iceoryx_posh/test/moduletests/test_roudi_portmanager_fixture.hpp b/iceoryx_posh/test/moduletests/test_roudi_portmanager_fixture.hpp index 405538fd910..5c76c443979 100644 --- a/iceoryx_posh/test/moduletests/test_roudi_portmanager_fixture.hpp +++ b/iceoryx_posh/test/moduletests/test_roudi_portmanager_fixture.hpp @@ -22,28 +22,29 @@ #include "iceoryx_hoofs/testing/watch_dog.hpp" #include "iceoryx_posh/iceoryx_posh_types.hpp" #include "iceoryx_posh/internal/capro/capro_message.hpp" +#include "iceoryx_posh/internal/popo/ports/client_port_user.hpp" #include "iceoryx_posh/internal/popo/ports/publisher_port_user.hpp" +#include "iceoryx_posh/internal/popo/ports/server_port_user.hpp" +#include "iceoryx_posh/internal/popo/ports/subscriber_port_user.hpp" #include "iceoryx_posh/internal/roudi/port_manager.hpp" +#include "iceoryx_posh/popo/client_options.hpp" +#include "iceoryx_posh/popo/server_options.hpp" #include "iceoryx_posh/roudi/memory/iceoryx_roudi_memory_manager.hpp" #include "test.hpp" #include -#include // std::numeric_limits +#include namespace iox_test_roudi_portmanager { using namespace ::testing; +using namespace iox; +using namespace iox::capro; using namespace iox::cxx; +using namespace iox::popo; +using namespace iox::roudi; -using iox::popo::PublisherOptions; -using iox::popo::PublisherPortUser; -using iox::popo::QueueFullPolicy; -using iox::popo::SubscriberOptions; -using iox::popo::SubscriberPortUser; -using iox::roudi::IceOryxRouDiMemoryManager; -using iox::roudi::PortManager; -using iox::roudi::PortPoolError; using iox::runtime::PortConfigInfo; class PortManagerTester : public PortManager @@ -70,6 +71,8 @@ class PortManager_test : public Test iox::RuntimeName_t m_runtimeName{"TestApp"}; + cxx::GenericRAII suppressLogging = iox::LoggerPosh().SetLogLevelForScope(iox::log::LogLevel::kOff); + void SetUp() override { m_instIdCounter = m_sIdCounter = 1U; @@ -192,6 +195,24 @@ class PortManager_test : public Test return SubscriberPortUser( m_portManager->acquireSubscriberPortData({"1", "1", "1"}, options, "schlomo", PortConfigInfo()).value()); } + + ClientPortUser createClient(const ClientOptions& options) + { + const ServiceDescription sd{"1", "1", "1"}; + const RuntimeName_t runtimeName{"guiseppe"}; + return ClientPortUser( + *m_portManager->acquireClientPortData(sd, options, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .value()); + } + + ServerPortUser createServer(const ServerOptions& options) + { + const ServiceDescription sd{"1", "1", "1"}; + const RuntimeName_t runtimeName{"schlomo"}; + return ServerPortUser( + *m_portManager->acquireServerPortData(sd, options, runtimeName, m_payloadDataSegmentMemoryManager, {}) + .value()); + } }; template