@@ -15,30 +15,58 @@ namespace {
1515
1616void on_message (udpard_rx_t * rx, udpard_rx_port_t * port, udpard_rx_transfer_t transfer);
1717void on_collision (udpard_rx_t * rx, udpard_rx_port_t * port, udpard_remote_t remote);
18- constexpr udpard_rx_port_vtable_t callbacks{ &on_message, &on_collision };
18+ constexpr udpard_rx_port_vtable_t callbacks{ .on_message = &on_message, .on_collision = &on_collision };
19+
20+ struct CapturedFrame
21+ {
22+ udpard_bytes_mut_t datagram;
23+ uint_fast8_t iface_index;
24+ };
25+
26+ void tx_refcount_free (void * const user, const size_t size, void * const payload)
27+ {
28+ (void )user;
29+ udpard_tx_refcount_dec (udpard_bytes_t { .size = size, .data = payload });
30+ }
31+
32+ bool capture_tx_frame (udpard_tx_t * const tx, const udpard_tx_ejection_t ejection)
33+ {
34+ auto * frames = static_cast <std::vector<CapturedFrame>*>(tx->user );
35+ if (frames == nullptr ) {
36+ return false ;
37+ }
38+ udpard_tx_refcount_inc (ejection.datagram );
39+ void * const data = const_cast <void *>(ejection.datagram .data ); // NOLINT(cppcoreguidelines-pro-type-const-cast)
40+ frames->push_back (CapturedFrame{ .datagram = { .size = ejection.datagram .size , .data = data },
41+ .iface_index = ejection.iface_index });
42+ return true ;
43+ }
44+
45+ constexpr udpard_tx_vtable_t tx_vtable{ .eject = &capture_tx_frame };
1946
2047struct Context
2148{
2249 std::vector<uint64_t > ids;
2350 size_t collisions = 0 ;
2451 uint64_t expected_uid = 0 ;
25- udpard_udpip_ep_t source = {};
52+ udpard_udpip_ep_t source{};
2653};
2754
2855struct Fixture
2956{
30- instrumented_allocator_t tx_alloc_frag{};
31- instrumented_allocator_t tx_alloc_payload{};
32- instrumented_allocator_t rx_alloc_frag{};
33- instrumented_allocator_t rx_alloc_session{};
34- udpard_tx_t tx{};
35- udpard_rx_t rx{};
36- udpard_rx_port_t port{};
37- udpard_mem_deleter_t tx_payload_deleter{};
38- Context ctx{};
39- udpard_udpip_ep_t dest{};
40- udpard_udpip_ep_t source{};
41- uint64_t topic_hash{ 0x90AB12CD34EF5678ULL };
57+ instrumented_allocator_t tx_alloc_transfer{};
58+ instrumented_allocator_t tx_alloc_payload{};
59+ instrumented_allocator_t rx_alloc_frag{};
60+ instrumented_allocator_t rx_alloc_session{};
61+ udpard_tx_t tx{};
62+ udpard_rx_t rx{};
63+ udpard_rx_port_t port{};
64+ udpard_mem_deleter_t tx_payload_deleter{};
65+ std::vector<CapturedFrame> frames;
66+ Context ctx{};
67+ udpard_udpip_ep_t dest{};
68+ udpard_udpip_ep_t source{};
69+ uint64_t topic_hash{ 0x90AB12CD34EF5678ULL };
4270
4371 Fixture (const Fixture&) = delete ;
4472 Fixture& operator =(const Fixture&) = delete ;
@@ -47,21 +75,24 @@ struct Fixture
4775
4876 explicit Fixture (const udpard_us_t reordering_window)
4977 {
50- instrumented_allocator_new (&tx_alloc_frag );
78+ instrumented_allocator_new (&tx_alloc_transfer );
5179 instrumented_allocator_new (&tx_alloc_payload);
5280 instrumented_allocator_new (&rx_alloc_frag);
5381 instrumented_allocator_new (&rx_alloc_session);
54- const udpard_tx_mem_resources_t tx_mem{ .fragment = instrumented_allocator_make_resource (&tx_alloc_frag),
55- .payload = instrumented_allocator_make_resource (&tx_alloc_payload) };
82+ udpard_tx_mem_resources_t tx_mem{};
83+ tx_mem.transfer = instrumented_allocator_make_resource (&tx_alloc_transfer);
84+ for (auto & res : tx_mem.payload ) {
85+ res = instrumented_allocator_make_resource (&tx_alloc_payload);
86+ }
5687 const udpard_rx_mem_resources_t rx_mem{ .session = instrumented_allocator_make_resource (&rx_alloc_session),
5788 .fragment = instrumented_allocator_make_resource (&rx_alloc_frag) };
58- tx_payload_deleter = instrumented_allocator_make_deleter (&tx_alloc_payload) ;
89+ tx_payload_deleter = udpard_mem_deleter_t { . user = nullptr , . free = &tx_refcount_free } ;
5990 source = { .ip = 0x0A000001U , .port = 7501U };
6091 dest = udpard_make_subject_endpoint (222U );
6192
62- TEST_ASSERT_TRUE (udpard_tx_new (&tx, 0x0A0B0C0D0E0F1011ULL , 16 , tx_mem));
63- std::array< udpard_tx_t *, UDPARD_NETWORK_INTERFACE_COUNT_MAX> rx_tx{} ;
64- udpard_rx_new (&rx, rx_tx. data (), 0 );
93+ TEST_ASSERT_TRUE (udpard_tx_new (&tx, 0x0A0B0C0D0E0F1011ULL , 42U , 16 , tx_mem, &tx_vtable ));
94+ tx. user = &frames ;
95+ udpard_rx_new (&rx, nullptr );
6596 ctx.expected_uid = tx.local_uid ;
6697 ctx.source = source;
6798 rx.user = &ctx;
@@ -71,36 +102,48 @@ struct Fixture
71102 ~Fixture ()
72103 {
73104 udpard_rx_port_free (&rx, &port);
105+ udpard_tx_free (&tx);
74106 TEST_ASSERT_EQUAL_size_t (0 , rx_alloc_frag.allocated_fragments );
75107 TEST_ASSERT_EQUAL_size_t (0 , rx_alloc_session.allocated_fragments );
76- TEST_ASSERT_EQUAL_size_t (0 , tx_alloc_frag .allocated_fragments );
108+ TEST_ASSERT_EQUAL_size_t (0 , tx_alloc_transfer .allocated_fragments );
77109 TEST_ASSERT_EQUAL_size_t (0 , tx_alloc_payload.allocated_fragments );
78110 instrumented_allocator_reset (&rx_alloc_frag);
79111 instrumented_allocator_reset (&rx_alloc_session);
80- instrumented_allocator_reset (&tx_alloc_frag );
112+ instrumented_allocator_reset (&tx_alloc_transfer );
81113 instrumented_allocator_reset (&tx_alloc_payload);
82114 }
83115
84116 void push_single (const udpard_us_t ts, const uint64_t transfer_id)
85117 {
118+ frames.clear ();
86119 std::array<uint8_t , 8 > payload_buf{};
87120 for (size_t i = 0 ; i < payload_buf.size (); i++) {
88121 payload_buf[i] = static_cast <uint8_t >(transfer_id >> (i * 8U ));
89122 }
90123 const udpard_bytes_t payload{ .size = payload_buf.size (), .data = payload_buf.data () };
91- const udpard_us_t deadline = ts + 1000000 ;
92- const uint_fast8_t iface_index = 0 ;
93- TEST_ASSERT_GREATER_THAN_UINT32 (
94- 0U ,
95- udpard_tx_push (&tx, ts, deadline, udpard_prio_slow, topic_hash, dest, transfer_id, payload, false , nullptr ));
96- udpard_tx_item_t * const item = udpard_tx_peek (&tx, ts);
97- TEST_ASSERT_NOT_NULL (item);
98- udpard_tx_pop (&tx, item);
99- TEST_ASSERT_TRUE (
100- udpard_rx_port_push (&rx, &port, ts, source, item->datagram_payload , tx_payload_deleter, iface_index));
101- item->datagram_payload .data = nullptr ;
102- item->datagram_payload .size = 0 ;
103- udpard_tx_free (tx.memory , item);
124+ const udpard_us_t deadline = ts + 1000000 ;
125+ for (auto & mtu_value : tx.mtu ) {
126+ mtu_value = UDPARD_MTU_DEFAULT;
127+ }
128+ std::array<udpard_udpip_ep_t , UDPARD_IFACE_COUNT_MAX> dest_per_iface{};
129+ dest_per_iface.fill (udpard_udpip_ep_t {});
130+ dest_per_iface[0 ] = dest;
131+ TEST_ASSERT_GREATER_THAN_UINT32 (0U ,
132+ udpard_tx_push (&tx,
133+ ts,
134+ deadline,
135+ udpard_prio_slow,
136+ topic_hash,
137+ dest_per_iface.data (),
138+ transfer_id,
139+ payload,
140+ nullptr ,
141+ nullptr ));
142+ udpard_tx_poll (&tx, ts, UDPARD_IFACE_MASK_ALL);
143+ TEST_ASSERT_GREATER_THAN_UINT32 (0U , static_cast <uint32_t >(frames.size ()));
144+ for (const auto & [datagram, iface_index] : frames) {
145+ TEST_ASSERT_TRUE (udpard_rx_port_push (&rx, &port, ts, source, datagram, tx_payload_deleter, iface_index));
146+ }
104147 }
105148};
106149
@@ -127,15 +170,15 @@ void test_udpard_rx_unordered_duplicates()
127170 Fixture fix{ UDPARD_RX_REORDERING_WINDOW_UNORDERED };
128171 udpard_us_t now = 0 ;
129172
130- const std::array<uint64_t , 6 > ids{ 100 , 20000 , 10100 , 5000 , 20000 , 100 };
173+ constexpr std::array<uint64_t , 6 > ids{ 100 , 20000 , 10100 , 5000 , 20000 , 100 };
131174 for (const auto id : ids) {
132175 fix.push_single (now, id);
133176 udpard_rx_poll (&fix.rx , now);
134177 now++;
135178 }
136179 udpard_rx_poll (&fix.rx , now + 100 );
137180
138- const std::array<uint64_t , 4 > expected{ 100 , 20000 , 10100 , 5000 };
181+ constexpr std::array<uint64_t , 4 > expected{ 100 , 20000 , 10100 , 5000 };
139182 TEST_ASSERT_EQUAL_size_t (expected.size (), fix.ctx .ids .size ());
140183 for (size_t i = 0 ; i < expected.size (); i++) {
141184 TEST_ASSERT_EQUAL_UINT64 (expected[i], fix.ctx .ids [i]);
@@ -176,7 +219,7 @@ void test_udpard_rx_ordered_out_of_order()
176219 // Allow the window to expire so the remaining interned transfers eject.
177220 udpard_rx_poll (&fix.rx , now + 70 );
178221
179- const std::array<uint64_t , 5 > expected{ 100 , 200 , 300 , 10100 , 10200 };
222+ constexpr std::array<uint64_t , 5 > expected{ 100 , 200 , 300 , 10100 , 10200 };
180223 TEST_ASSERT_EQUAL_size_t (expected.size (), fix.ctx .ids .size ());
181224 for (size_t i = 0 ; i < expected.size (); i++) {
182225 TEST_ASSERT_EQUAL_UINT64 (expected[i], fix.ctx .ids [i]);
@@ -211,7 +254,7 @@ void test_udpard_rx_ordered_head_advanced_late()
211254 fix.push_single (++now, 310 );
212255 udpard_rx_poll (&fix.rx , now);
213256
214- const std::array<uint64_t , 5 > expected{ 100 , 200 , 300 , 420 , 450 };
257+ constexpr std::array<uint64_t , 5 > expected{ 100 , 200 , 300 , 420 , 450 };
215258 TEST_ASSERT_EQUAL_size_t (expected.size (), fix.ctx .ids .size ());
216259 for (size_t i = 0 ; i < expected.size (); i++) {
217260 TEST_ASSERT_EQUAL_UINT64 (expected[i], fix.ctx .ids [i]);
0 commit comments