Skip to content

Commit 30a14c9

Browse files
committed
unit test for rpc client with transfer id map
1 parent e4dba00 commit 30a14c9

File tree

6 files changed

+152
-38
lines changed

6 files changed

+152
-38
lines changed

include/libcyphal/presentation/client_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class SharedClient : public common::cavl::Node<SharedClient>,
252252
if (auto* const transfer_id_map = delegate_.getTransferIdMap())
253253
{
254254
const SessionSpec session_spec{response_rx_params_.service_id, response_rx_params_.server_node_id};
255-
transfer_id_map->setIdFor(next_transfer_id_, session_spec);
255+
transfer_id_map->setIdFor(session_spec, next_transfer_id_);
256256
}
257257

258258
delegate_.forgetSharedClient(*this);

include/libcyphal/presentation/publisher_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class PublisherImpl final : public common::cavl::Node<PublisherImpl>, public Sha
106106
if (const auto local_node_id = delegate_.getLocalNodeId())
107107
{
108108
const SessionSpec session_spec{subject_id_, local_node_id.value()};
109-
transfer_id_map->setIdFor(next_transfer_id_, session_spec);
109+
transfer_id_map->setIdFor(session_spec, next_transfer_id_);
110110
}
111111
}
112112

include/libcyphal/transport/transfer_id_map.hpp

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class ITransferIdMap
6363
/// Depending on the implementation, the previously set transfer ids may be stored in memory
6464
/// or also persisted to a file (but probably on exit to fulfill the above performance expectations).
6565
///
66-
virtual void setIdFor(const TransferId transfer_id, const SessionSpec& session_spec) noexcept = 0;
66+
virtual void setIdFor(const SessionSpec& session_spec, const TransferId transfer_id) noexcept = 0;
6767

6868
protected:
6969
ITransferIdMap() = default;
@@ -108,36 +108,6 @@ class ITransferIdStorage
108108

109109
}; // ITransferIdStorage
110110

111-
/// Default implementation of the transfer ID storage.
112-
///
113-
/// It just stores given transfer id in memory.
114-
/// In use by the Presentation layer entities as a default fallback behavior.
115-
///
116-
class DefaultTransferIdStorage final : public ITransferIdStorage
117-
{
118-
public:
119-
explicit DefaultTransferIdStorage(const TransferId initial_transfer_id = 0) noexcept
120-
: transfer_id_{initial_transfer_id}
121-
{
122-
}
123-
124-
// ITransferIdMap
125-
126-
TransferId load() const noexcept override
127-
{
128-
return transfer_id_;
129-
}
130-
131-
void save(const TransferId transfer_id) noexcept override
132-
{
133-
transfer_id_ = transfer_id;
134-
}
135-
136-
private:
137-
TransferId transfer_id_;
138-
139-
}; // DefaultTransferIdStorage
140-
141111
/// @brief Defines a trivial transfer ID generator.
142112
///
143113
/// The generator is trivial in the sense that it simply increments the transfer ID.

test/unittest/presentation/test_client.cpp

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "tracking_memory_resource.hpp"
1212
#include "transport/scattered_buffer_storage_mock.hpp"
1313
#include "transport/svc_sessions_mock.hpp"
14+
#include "transport/transfer_id_map_mock.hpp"
1415
#include "transport/transport_gtest_helpers.hpp"
1516
#include "transport/transport_mock.hpp"
1617
#include "virtual_time_scheduler.hpp"
@@ -23,6 +24,7 @@
2324
#include <libcyphal/presentation/response_promise.hpp>
2425
#include <libcyphal/transport/errors.hpp>
2526
#include <libcyphal/transport/svc_sessions.hpp>
27+
#include <libcyphal/transport/transfer_id_map.hpp>
2628
#include <libcyphal/transport/types.hpp>
2729
#include <libcyphal/types.hpp>
2830

@@ -789,7 +791,7 @@ TEST_F(TestClient, raw_request_response_failures)
789791
State state{mr_, transport_mock_, rx_params};
790792

791793
// Emulate that transport supports only 2 concurrent transfers by having module equal to 2^1.
792-
// This will make the client fail to make more than 2 request.
794+
// This will make the client fail to make more than 2 requests.
793795
EXPECT_CALL(transport_mock_, getProtocolParams()).WillRepeatedly(Return(ProtocolParams{2, 0, 0}));
794796

795797
Presentation presentation{mr_, scheduler_, transport_mock_};
@@ -829,6 +831,84 @@ TEST_F(TestClient, raw_request_response_failures)
829831
scheduler_.spinFor(10s);
830832
}
831833

834+
TEST_F(TestClient, multiple_clients_with_transfer_id_map)
835+
{
836+
using SvcResPromise = ResponsePromise<void>;
837+
using SessionSpec = ITransferIdMap::SessionSpec;
838+
839+
StrictMock<TransferIdMapMock> transfer_id_map_mock;
840+
841+
constexpr ResponseRxParams rx_params_n31{4, 147, 0x31};
842+
constexpr ResponseRxParams rx_params_n32{4, 147, 0x32};
843+
844+
State state_31{mr_, transport_mock_, rx_params_n31};
845+
State state_32{mr_, transport_mock_, rx_params_n32};
846+
847+
Presentation presentation{mr_, scheduler_, transport_mock_};
848+
presentation.setTransferIdMap(&transfer_id_map_mock);
849+
850+
EXPECT_CALL(transfer_id_map_mock, getIdFor(SessionSpec{rx_params_n31.service_id, rx_params_n31.server_node_id}))
851+
.WillOnce(Return(0x310));
852+
EXPECT_CALL(transfer_id_map_mock, getIdFor(SessionSpec{rx_params_n32.service_id, rx_params_n32.server_node_id}))
853+
.WillOnce(Return(0x320));
854+
855+
auto maybe_client_n31 = presentation.makeClient( //
856+
rx_params_n31.server_node_id,
857+
rx_params_n31.service_id,
858+
rx_params_n31.extent_bytes);
859+
ASSERT_THAT(maybe_client_n31, VariantWith<RawServiceClient>(_));
860+
cetl::optional<RawServiceClient> client_n31 = cetl::get<RawServiceClient>(std::move(maybe_client_n31));
861+
862+
auto maybe_client_n32 = presentation.makeClient( //
863+
rx_params_n32.server_node_id,
864+
rx_params_n32.service_id,
865+
rx_params_n32.extent_bytes);
866+
ASSERT_THAT(maybe_client_n32, VariantWith<RawServiceClient>(_));
867+
cetl::optional<RawServiceClient> client_n32 = cetl::get<RawServiceClient>(std::move(maybe_client_n32));
868+
869+
scheduler_.scheduleAt(1s, [&](const auto&) {
870+
//
871+
EXPECT_CALL(state_31.req_tx_session_mock_, send(_, _)) //
872+
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
873+
//
874+
EXPECT_THAT(metadata.base.transfer_id, 0x310);
875+
return cetl::nullopt;
876+
}));
877+
878+
const auto maybe_promise = client_n31->request(now() + 100ms, {}, now() + 2s);
879+
EXPECT_THAT(maybe_promise, VariantWith<SvcResPromise>(_));
880+
});
881+
scheduler_.scheduleAt(2s, [&](const auto&) {
882+
//
883+
EXPECT_CALL(state_32.req_tx_session_mock_, send(_, _)) //
884+
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
885+
//
886+
EXPECT_THAT(metadata.base.transfer_id, 0x320);
887+
return cetl::nullopt;
888+
}));
889+
890+
const auto maybe_promise = client_n32->request(now() + 100ms, {}, now() + 2s);
891+
EXPECT_THAT(maybe_promise, VariantWith<SvcResPromise>(_));
892+
});
893+
scheduler_.scheduleAt(8s, [&](const auto&) {
894+
//
895+
EXPECT_CALL(transfer_id_map_mock,
896+
setIdFor(SessionSpec{rx_params_n32.service_id, rx_params_n32.server_node_id}, 0x320 + 1))
897+
.WillOnce(Return());
898+
899+
client_n32.reset();
900+
});
901+
scheduler_.scheduleAt(9s, [&](const auto&) {
902+
//
903+
EXPECT_CALL(transfer_id_map_mock,
904+
setIdFor(SessionSpec{rx_params_n31.service_id, rx_params_n31.server_node_id}, 0x310 + 1))
905+
.WillOnce(Return());
906+
907+
client_n31.reset();
908+
});
909+
scheduler_.spinFor(10s);
910+
}
911+
832912
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers, *-function-cognitive-complexity)
833913

834914
} // namespace

test/unittest/transport/test_transfer_id_map.cpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,34 @@ using testing::StrictMock;
2727
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers)
2828

2929
class TestTransferIdMapAndGens : public testing::Test
30-
{};
30+
{
31+
protected:
32+
class TransferIdStorage final : public detail::ITransferIdStorage
33+
{
34+
public:
35+
explicit TransferIdStorage(const TransferId initial_transfer_id = 0) noexcept
36+
: transfer_id_{initial_transfer_id}
37+
{
38+
}
39+
40+
// detail::ITransferIdStorage
41+
42+
TransferId load() const noexcept override
43+
{
44+
return transfer_id_;
45+
}
46+
47+
void save(const TransferId transfer_id) noexcept override
48+
{
49+
transfer_id_ = transfer_id;
50+
}
51+
52+
private:
53+
TransferId transfer_id_;
54+
55+
}; // TransferIdStorage
56+
57+
}; // TestTransferIdMapAndGens
3158

3259
// MARK: - Tests:
3360

@@ -77,11 +104,11 @@ TEST_F(TestTransferIdMapAndGens, trivial_max_tf_id)
77104

78105
TEST_F(TestTransferIdMapAndGens, small_range_with_default_map)
79106
{
80-
detail::DefaultTransferIdStorage default_transfer_id_storage{9};
107+
TransferIdStorage transfer_id_storage{9}; // on purpose bigger than modulo 4
81108

82-
detail::SmallRangeTransferIdGenerator<8> tf_id_gen{4, default_transfer_id_storage};
109+
detail::SmallRangeTransferIdGenerator<8> tf_id_gen{4, transfer_id_storage};
83110

84-
EXPECT_THAT(tf_id_gen.nextTransferId(), Optional(1));
111+
EXPECT_THAT(tf_id_gen.nextTransferId(), Optional(1)); // 9 % 4 -> 1
85112
EXPECT_THAT(tf_id_gen.nextTransferId(), Optional(2));
86113
EXPECT_THAT(tf_id_gen.nextTransferId(), Optional(3));
87114
EXPECT_THAT(tf_id_gen.nextTransferId(), Optional(0));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/// @copyright
2+
/// Copyright (C) OpenCyphal Development Team <opencyphal.org>
3+
/// Copyright Amazon.com Inc. or its affiliates.
4+
/// SPDX-License-Identifier: MIT
5+
6+
#ifndef LIBCYPHAL_TRANSPORT_TRANSFER_ID_MAP_MOCK_HPP_INCLUDED
7+
#define LIBCYPHAL_TRANSPORT_TRANSFER_ID_MAP_MOCK_HPP_INCLUDED
8+
9+
#include <libcyphal/transport/transfer_id_map.hpp>
10+
11+
#include <gmock/gmock.h>
12+
13+
namespace libcyphal
14+
{
15+
namespace transport
16+
{
17+
18+
class TransferIdMapMock : public ITransferIdMap
19+
{
20+
public:
21+
TransferIdMapMock() = default;
22+
virtual ~TransferIdMapMock() = default;
23+
24+
TransferIdMapMock(const TransferIdMapMock&) = delete;
25+
TransferIdMapMock(TransferIdMapMock&&) noexcept = delete;
26+
TransferIdMapMock& operator=(const TransferIdMapMock&) = delete;
27+
TransferIdMapMock& operator=(TransferIdMapMock&&) noexcept = delete;
28+
29+
MOCK_METHOD(TransferId, getIdFor, (const SessionSpec& session_spec), (const, noexcept, override));
30+
MOCK_METHOD(void, setIdFor, (const SessionSpec& session_spec, const TransferId transfer_id), (noexcept, override));
31+
32+
}; // TransferIdMapMock
33+
34+
} // namespace transport
35+
} // namespace libcyphal
36+
37+
#endif // LIBCYPHAL_TRANSPORT_TRANSFER_ID_MAP_MOCK_HPP_INCLUDED

0 commit comments

Comments
 (0)