Skip to content

Commit f36dd73

Browse files
committed
unit test for multi publishers with transfer id map
1 parent 1e60d54 commit f36dd73

File tree

6 files changed

+137
-22
lines changed

6 files changed

+137
-22
lines changed

include/libcyphal/presentation/client.hpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,13 @@ class Client final : public detail::ClientBase
237237
// For request (and the following response) we need to allocate a transfer ID,
238238
// which will be in use to pair the request with the response.
239239
//
240-
auto& shared_client = getSharedClient();
241-
auto opt_transfer_id = shared_client.nextTransferId();
240+
auto& shared_client = getSharedClient();
241+
const auto opt_transfer_id = shared_client.nextTransferId();
242242
if (!opt_transfer_id)
243243
{
244244
return TooManyPendingRequestsError{};
245245
}
246-
const auto transfer_id = *opt_transfer_id;
246+
const auto transfer_id = opt_transfer_id.value();
247247

248248
// Create and register a response promise object, which will be used to handle the response.
249249
// Its done specifically before sending the request, so that we will be ready to handle a response
@@ -325,13 +325,13 @@ class RawServiceClient final : public detail::ClientBase
325325
// 1. For request (and following response) we need to allocate a transfer ID,
326326
// which will be in use to pair the request with the response.
327327
//
328-
auto& shared_client = getSharedClient();
329-
auto opt_transfer_id = shared_client.nextTransferId();
328+
auto& shared_client = getSharedClient();
329+
const auto opt_transfer_id = shared_client.nextTransferId();
330330
if (!opt_transfer_id)
331331
{
332332
return TooManyPendingRequestsError{};
333333
}
334-
const auto transfer_id = *opt_transfer_id;
334+
const auto transfer_id = opt_transfer_id.value();
335335

336336
// 2. Create and register a response promise object, which will be used to handle the response.
337337
// Its done specifically before sending the request, so that we will be ready to handle a response

include/libcyphal/presentation/client_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace detail
3636

3737
class SharedClient : public common::cavl::Node<SharedClient>,
3838
public SharedObject,
39-
public transport::detail::ITransferIdStorage
39+
protected transport::detail::ITransferIdStorage
4040
{
4141
public:
4242
using Node::remove;

include/libcyphal/presentation/publisher_impl.hpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ namespace presentation
3333
namespace detail
3434
{
3535

36-
class PublisherImpl final : public common::cavl::Node<PublisherImpl>, public SharedObject
36+
class PublisherImpl final : public common::cavl::Node<PublisherImpl>,
37+
public SharedObject,
38+
private transport::detail::ITransferIdStorage
3739
{
3840
public:
3941
using Node::remove;
@@ -44,6 +46,7 @@ class PublisherImpl final : public common::cavl::Node<PublisherImpl>, public Sha
4446
, msg_tx_session_{std::move(msg_tx_session)}
4547
, subject_id_{msg_tx_session_->getParams().subject_id}
4648
, next_transfer_id_{0}
49+
, transfer_id_generator_{*this}
4750
{
4851
CETL_DEBUG_ASSERT(msg_tx_session_ != nullptr, "");
4952

@@ -69,11 +72,11 @@ class PublisherImpl final : public common::cavl::Node<PublisherImpl>, public Sha
6972

7073
cetl::optional<transport::AnyFailure> publishRawData(const TimePoint deadline,
7174
const transport::Priority priority,
72-
const transport::PayloadFragments payload_fragments)
75+
const transport::PayloadFragments payload_fragments) const
7376
{
74-
next_transfer_id_ += 1;
75-
const transport::TransferTxMetadata metadata{{next_transfer_id_, priority}, deadline};
77+
const auto transfer_id = transfer_id_generator_.nextTransferId();
7678

79+
const transport::TransferTxMetadata metadata{{transfer_id, priority}, deadline};
7780
return msg_tx_session_->send(metadata, payload_fragments);
7881
}
7982

@@ -114,12 +117,25 @@ class PublisherImpl final : public common::cavl::Node<PublisherImpl>, public Sha
114117
destroyWithPmr(this, delegate_.memory());
115118
}
116119

120+
// MARK: ITransferIdStorage
121+
122+
transport::TransferId load() const noexcept override
123+
{
124+
return next_transfer_id_;
125+
}
126+
127+
void save(const transport::TransferId transfer_id) noexcept override
128+
{
129+
next_transfer_id_ = transfer_id;
130+
}
131+
117132
// MARK: Data members:
118133

119134
IPresentationDelegate& delegate_;
120135
const UniquePtr<transport::IMessageTxSession> msg_tx_session_;
121136
const transport::PortId subject_id_;
122137
transport::TransferId next_transfer_id_;
138+
transport::detail::TrivialTransferIdGenerator transfer_id_generator_;
123139

124140
}; // PublisherImpl
125141

test/unittest/application/node/test_heartbeat_producer.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ TEST_F(TestHeartbeatProducer, make)
126126
});
127127
scheduler_.scheduleAt(3s, [&](const auto&) {
128128
//
129-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{1, Priority::Nominal}, now() + 1s}), _)) //
129+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{0, Priority::Nominal}, now() + 1s}), _)) //
130130
.WillOnce(Return(cetl::nullopt));
131131
});
132132
scheduler_.scheduleAt(3s + 500ms, [&](const auto&) {
@@ -143,12 +143,12 @@ TEST_F(TestHeartbeatProducer, make)
143143
});
144144
scheduler_.scheduleAt(4s, [&](const auto&) {
145145
//
146-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{2, Priority::Nominal}, now() + 1s}), _)) //
146+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{1, Priority::Nominal}, now() + 1s}), _)) //
147147
.WillOnce(Return(cetl::nullopt));
148148
});
149149
scheduler_.scheduleAt(5s, [&](const auto&) {
150150
//
151-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{3, Priority::Nominal}, now() + 1s}), _)) //
151+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{2, Priority::Nominal}, now() + 1s}), _)) //
152152
.WillOnce(Return(cetl::nullopt));
153153
});
154154
scheduler_.scheduleAt(5s + 500ms, [&](const auto&) {
@@ -161,7 +161,7 @@ TEST_F(TestHeartbeatProducer, make)
161161
});
162162
scheduler_.scheduleAt(6s, [&](const auto&) {
163163
//
164-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{4, Priority::Nominal}, now() + 1s}), _)) //
164+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{3, Priority::Nominal}, now() + 1s}), _)) //
165165
.WillOnce(Return(cetl::nullopt));
166166
});
167167
scheduler_.scheduleAt(6s + 500ms, [&](const auto&) {
@@ -173,12 +173,12 @@ TEST_F(TestHeartbeatProducer, make)
173173
});
174174
scheduler_.scheduleAt(7s, [&](const auto&) {
175175
//
176-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{5, Priority::Nominal}, now() + 1s}), _)) //
176+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{4, Priority::Nominal}, now() + 1s}), _)) //
177177
.WillOnce(Return(cetl::nullopt));
178178
});
179179
scheduler_.scheduleAt(8s, [&](const auto&) {
180180
//
181-
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{6, Priority::Nominal}, now() + 1s}), _)) //
181+
EXPECT_CALL(msg_tx_session_mock, send(TransferTxMetadataEq({{5, Priority::Nominal}, now() + 1s}), _)) //
182182
.WillOnce(Return(cetl::nullopt));
183183

184184
heartbeat_producer->message().health.value = uavcan::node::Health_1_0::CAUTION;

test/unittest/presentation/test_publisher.cpp

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "my_custom/bar_1_0.hpp"
88
#include "tracking_memory_resource.hpp"
99
#include "transport/msg_sessions_mock.hpp"
10+
#include "transport/transfer_id_map_mock.hpp"
1011
#include "transport/transport_gtest_helpers.hpp"
1112
#include "transport/transport_mock.hpp"
1213
#include "verification_utilities.hpp"
@@ -17,6 +18,7 @@
1718
#include <libcyphal/presentation/publisher.hpp>
1819
#include <libcyphal/transport/errors.hpp>
1920
#include <libcyphal/transport/msg_sessions.hpp>
21+
#include <libcyphal/transport/transfer_id_map.hpp>
2022
#include <libcyphal/transport/types.hpp>
2123
#include <libcyphal/types.hpp>
2224

@@ -176,7 +178,7 @@ TEST_F(TestPublisher, publish)
176178
EXPECT_CALL(msg_tx_session_mock, send(_, _)) //
177179
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
178180
//
179-
EXPECT_THAT(metadata.base.transfer_id, 1);
181+
EXPECT_THAT(metadata.base.transfer_id, 0);
180182
EXPECT_THAT(metadata.base.priority, Priority::Exceptional);
181183
EXPECT_THAT(metadata.deadline, now + 200ms);
182184
return cetl::nullopt;
@@ -189,7 +191,7 @@ TEST_F(TestPublisher, publish)
189191
EXPECT_CALL(msg_tx_session_mock, send(_, _)) //
190192
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
191193
//
192-
EXPECT_THAT(metadata.base.transfer_id, 2);
194+
EXPECT_THAT(metadata.base.transfer_id, 1);
193195
EXPECT_THAT(metadata.base.priority, Priority::Fast);
194196
EXPECT_THAT(metadata.deadline, now + 100ms);
195197
return cetl::nullopt;
@@ -283,7 +285,7 @@ TEST_F(TestPublisher, publishRawData)
283285
EXPECT_CALL(msg_tx_session_mock, send(_, _)) //
284286
.WillOnce(Invoke([now = now()](const auto& metadata, const auto frags) {
285287
//
286-
EXPECT_THAT(metadata.base.transfer_id, 1);
288+
EXPECT_THAT(metadata.base.transfer_id, 0);
287289
EXPECT_THAT(metadata.base.priority, Priority::Nominal);
288290
EXPECT_THAT(metadata.deadline, now + 200ms);
289291
EXPECT_THAT(frags.size(), 1);
@@ -303,6 +305,103 @@ TEST_F(TestPublisher, publishRawData)
303305
scheduler_.spinFor(10s);
304306
}
305307

308+
TEST_F(TestPublisher, multiple_publishers_with_transfer_id_map)
309+
{
310+
using Message = uavcan::node::Heartbeat_1_0;
311+
using SessionSpec = ITransferIdMap::SessionSpec;
312+
313+
StrictMock<TransferIdMapMock> transfer_id_map_mock;
314+
315+
Presentation presentation{mr_, scheduler_, transport_mock_};
316+
presentation.setTransferIdMap(&transfer_id_map_mock);
317+
318+
EXPECT_CALL(transport_mock_, getLocalNodeId()) //
319+
.WillOnce(Return(cetl::nullopt));
320+
321+
StrictMock<MessageTxSessionMock> msg7_tx_session_mock;
322+
constexpr MessageTxParams tx7_params{7};
323+
cetl::optional<Publisher<Message>> publisher7;
324+
{
325+
EXPECT_CALL(msg7_tx_session_mock, getParams()).WillOnce(Return(tx7_params));
326+
327+
EXPECT_CALL(transport_mock_, makeMessageTxSession(MessageTxParamsEq(tx7_params))) //
328+
.WillOnce(Invoke([&](const auto&) { //
329+
return libcyphal::detail::makeUniquePtr<UniquePtrMsgTxSpec>(mr_, msg7_tx_session_mock);
330+
}));
331+
332+
auto maybe_pub7 = presentation.makePublisher<Message>(tx7_params.subject_id);
333+
ASSERT_THAT(maybe_pub7, VariantWith<Publisher<Message>>(_));
334+
335+
publisher7.emplace(cetl::get<Publisher<Message>>(std::move(maybe_pub7)));
336+
}
337+
338+
constexpr NodeId local_node_id = 0x13;
339+
EXPECT_CALL(transport_mock_, getLocalNodeId()) //
340+
.WillRepeatedly(Return(cetl::optional<NodeId>{NodeId{local_node_id}}));
341+
342+
StrictMock<MessageTxSessionMock> msg9_tx_session_mock;
343+
constexpr MessageTxParams tx9_params{9};
344+
cetl::optional<Publisher<Message>> publisher9;
345+
{
346+
EXPECT_CALL(msg9_tx_session_mock, getParams()).WillOnce(Return(tx9_params));
347+
348+
EXPECT_CALL(transport_mock_, makeMessageTxSession(MessageTxParamsEq(tx9_params))) //
349+
.WillOnce(Invoke([&](const auto&) { //
350+
return libcyphal::detail::makeUniquePtr<UniquePtrMsgTxSpec>(mr_, msg9_tx_session_mock);
351+
}));
352+
353+
EXPECT_CALL(transfer_id_map_mock, getIdFor(SessionSpec{tx9_params.subject_id, local_node_id}))
354+
.WillOnce(Return(90));
355+
356+
auto maybe_pub9 = presentation.makePublisher<Message>(tx9_params.subject_id);
357+
ASSERT_THAT(maybe_pub9, VariantWith<Publisher<Message>>(_));
358+
359+
publisher9.emplace(cetl::get<Publisher<Message>>(std::move(maybe_pub9)));
360+
}
361+
362+
scheduler_.scheduleAt(1s, [&](const auto&) {
363+
//
364+
EXPECT_CALL(msg7_tx_session_mock, send(_, _)) //
365+
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
366+
//
367+
EXPECT_THAT(metadata.base.transfer_id, 0);
368+
return cetl::nullopt;
369+
}));
370+
371+
EXPECT_THAT(publisher7->publish(now() + 200ms, Message{&mr_}), Eq(cetl::nullopt));
372+
});
373+
scheduler_.scheduleAt(2s, [&](const auto&) {
374+
//
375+
EXPECT_CALL(msg9_tx_session_mock, send(_, _)) //
376+
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
377+
//
378+
EXPECT_THAT(metadata.base.transfer_id, 90);
379+
return cetl::nullopt;
380+
}));
381+
382+
EXPECT_THAT(publisher9->publish(now() + 200ms, Message{&mr_}), Eq(cetl::nullopt));
383+
});
384+
scheduler_.scheduleAt(8s, [&](const auto&) {
385+
//
386+
EXPECT_CALL(transfer_id_map_mock, setIdFor(SessionSpec{tx9_params.subject_id, local_node_id}, 90 + 1)) //
387+
.WillOnce(Return());
388+
389+
publisher9.reset();
390+
testing::Mock::VerifyAndClearExpectations(&msg9_tx_session_mock);
391+
EXPECT_CALL(msg9_tx_session_mock, deinit()).Times(1);
392+
});
393+
scheduler_.scheduleAt(9s, [&](const auto&) {
394+
//
395+
EXPECT_CALL(transfer_id_map_mock, setIdFor(SessionSpec{tx7_params.subject_id, local_node_id}, 1)) //
396+
.WillOnce(Return());
397+
398+
publisher7.reset();
399+
testing::Mock::VerifyAndClearExpectations(&msg7_tx_session_mock);
400+
EXPECT_CALL(msg7_tx_session_mock, deinit()).Times(1);
401+
});
402+
scheduler_.spinFor(10s);
403+
}
404+
306405
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers)
307406

308407
} // namespace

test/unittest/presentation/test_publisher_custom_config.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ TEST_F(TestPublisherCustomConfig, publish_with_custom_buffer_size)
110110
EXPECT_CALL(msg_tx_session_mock, send(_, _)) //
111111
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
112112
//
113-
EXPECT_THAT(metadata.base.transfer_id, 1);
113+
EXPECT_THAT(metadata.base.transfer_id, 0);
114114
EXPECT_THAT(metadata.base.priority, Priority::Exceptional);
115115
EXPECT_THAT(metadata.deadline, now + 200ms);
116116
return cetl::nullopt;
@@ -123,7 +123,7 @@ TEST_F(TestPublisherCustomConfig, publish_with_custom_buffer_size)
123123
EXPECT_CALL(msg_tx_session_mock, send(_, _)) //
124124
.WillOnce(Invoke([now = now()](const auto& metadata, const auto) {
125125
//
126-
EXPECT_THAT(metadata.base.transfer_id, 2);
126+
EXPECT_THAT(metadata.base.transfer_id, 1);
127127
EXPECT_THAT(metadata.base.priority, Priority::Fast);
128128
EXPECT_THAT(metadata.deadline, now + 100ms);
129129
return cetl::nullopt;

0 commit comments

Comments
 (0)