// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // SPDX-License-Identifier: Apache-2.0 #include "iceoryx_posh/popo/server.hpp" #include "iceoryx_posh/testing/mocks/chunk_mock.hpp" #include "mocks/server_mock.hpp" #include "test.hpp" namespace { using namespace ::testing; using namespace iox::capro; using namespace iox::popo; using ::testing::_; struct DummyRequest { uint64_t data{0}; }; struct DummyResponse { uint64_t data{0}; }; using TestServer = ServerImpl; class Server_test : public Test { public: void SetUp() override { } void TearDown() override { } static constexpr uint64_t PAYLOAD_SIZE{sizeof(DummyResponse)}; static constexpr uint64_t PAYLOAD_ALIGNMENT{alignof(DummyResponse)}; ChunkMock requestMock; ChunkMock responseMock; ServiceDescription sd{"go", "go", "go"}; static constexpr uint64_t REQUEST_QUEUE_CAPACITY{3U}; ServerOptions options{REQUEST_QUEUE_CAPACITY}; TestServer sut{sd, options}; }; TEST_F(Server_test, ConstructorForwardsArgumentsToBaseClient) { ::testing::Test::RecordProperty("TEST_ID", "6b98a782-dddf-4e17-99ac-90c7bc03fa7d"); EXPECT_THAT(sut.serviceDescription, Eq(sd)); EXPECT_THAT(sut.serverOptions, Eq(options)); } TEST_F(Server_test, TakeCallsUnderlyingPortWithSuccessResult) { ::testing::Test::RecordProperty("TEST_ID", "a8a76781-7599-4bb9-b3fc-1c9f06ae372b"); const iox::cxx::expected getRequestResult = iox::cxx::success{requestMock.userHeader()}; EXPECT_CALL(sut.mockPort, getRequest()).WillOnce(Return(getRequestResult)); const auto takeResult = sut.take(); ASSERT_FALSE(takeResult.has_error()); EXPECT_THAT(&takeResult.value().getRequestHeader(), Eq(requestMock.userHeader())); EXPECT_CALL(sut.mockPort, releaseRequest(requestMock.userHeader())).Times(1); } TEST_F(Server_test, TakeCallsUnderlyingPortWithErrorResult) { ::testing::Test::RecordProperty("TEST_ID", "a9049459-99b6-4567-b022-99299bd423b6"); constexpr ServerRequestResult SERVER_REQUEST_RESULT{ServerRequestResult::TOO_MANY_REQUESTS_HELD_IN_PARALLEL}; const iox::cxx::expected getRequestResult = iox::cxx::error{SERVER_REQUEST_RESULT}; EXPECT_CALL(sut.mockPort, getRequest()).WillOnce(Return(getRequestResult)); auto takeResult = sut.take(); ASSERT_TRUE(takeResult.has_error()); EXPECT_THAT(takeResult.get_error(), Eq(SERVER_REQUEST_RESULT)); } TEST_F(Server_test, LoanCallsUnderlyingPortWithSuccessResult) { ::testing::Test::RecordProperty("TEST_ID", "926d394d-2a8f-486a-a422-28e424cf266a"); const iox::cxx::expected getRequestResult = iox::cxx::success{requestMock.userHeader()}; EXPECT_CALL(sut.mockPort, getRequest()).WillOnce(Return(getRequestResult)); auto takeResult = sut.take(); ASSERT_FALSE(takeResult.has_error()); const auto request = std::move(takeResult.value()); const iox::cxx::expected allocateResponseResult = iox::cxx::success{responseMock.userHeader()}; EXPECT_CALL(sut.mockPort, allocateResponse(requestMock.userHeader(), PAYLOAD_SIZE, PAYLOAD_ALIGNMENT)) .WillOnce(Return(allocateResponseResult)); auto loanResult = sut.loan(request); ASSERT_FALSE(loanResult.has_error()); EXPECT_THAT(&loanResult.value().getResponseHeader(), Eq(responseMock.userHeader())); EXPECT_CALL(sut.mockPort, releaseRequest(requestMock.userHeader())).Times(1); EXPECT_CALL(sut.mockPort, releaseResponse(responseMock.userHeader())).Times(1); } TEST_F(Server_test, LoanCallsUnderlyingPortWithErrorResult) { ::testing::Test::RecordProperty("TEST_ID", "2302a61f-bc18-4cad-babb-9a4aeabf1cc7"); const iox::cxx::expected getRequestResult = iox::cxx::success{requestMock.userHeader()}; EXPECT_CALL(sut.mockPort, getRequest()).WillOnce(Return(getRequestResult)); auto takeResult = sut.take(); ASSERT_FALSE(takeResult.has_error()); const auto request = std::move(takeResult.value()); constexpr AllocationError ALLOCATION_ERROR{AllocationError::RUNNING_OUT_OF_CHUNKS}; const iox::cxx::expected allocateResponseResult = iox::cxx::error{ALLOCATION_ERROR}; EXPECT_CALL(sut.mockPort, allocateResponse(requestMock.userHeader(), PAYLOAD_SIZE, PAYLOAD_ALIGNMENT)) .WillOnce(Return(allocateResponseResult)); auto loanResult = sut.loan(request); ASSERT_TRUE(loanResult.has_error()); EXPECT_THAT(loanResult.get_error(), Eq(ALLOCATION_ERROR)); EXPECT_CALL(sut.mockPort, releaseRequest(requestMock.userHeader())).Times(1); } TEST_F(Server_test, SendCallsUnderlyingPort) { ::testing::Test::RecordProperty("TEST_ID", "535414bd-1846-4254-8fa1-78a296c185b5"); const iox::cxx::expected getRequestResult = iox::cxx::success{requestMock.userHeader()}; EXPECT_CALL(sut.mockPort, getRequest()).WillOnce(Return(getRequestResult)); auto takeResult = sut.take(); ASSERT_FALSE(takeResult.has_error()); const auto request = std::move(takeResult.value()); const iox::cxx::expected allocateResponseResult = iox::cxx::success{responseMock.userHeader()}; EXPECT_CALL(sut.mockPort, allocateResponse(requestMock.userHeader(), PAYLOAD_SIZE, PAYLOAD_ALIGNMENT)) .WillOnce(Return(allocateResponseResult)); auto loanResult = sut.loan(request); auto response = std::move(loanResult.value()); EXPECT_CALL(sut.mockPort, sendResponse(responseMock.userHeader())).WillOnce(Return(iox::cxx::success())); sut.send(std::move(response)) .and_then([&]() { GTEST_SUCCEED() << "Response successfully sent"; }) .or_else([&](auto error) { GTEST_FAIL() << "Expected response to be sent but got error: " << static_cast(error); }); EXPECT_CALL(sut.mockPort, releaseRequest(requestMock.userHeader())).Times(1); } } // namespace