Skip to content

Commit c425dd1

Browse files
tests
1 parent 2110818 commit c425dd1

File tree

4 files changed

+324
-2
lines changed

4 files changed

+324
-2
lines changed

tests/src/test_fragment.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ void test_udpard_fragment_seek()
8686
instrumented_allocator_reset(&alloc_frag);
8787
instrumented_allocator_reset(&alloc_payload);
8888

89+
// Test 1b: Seek before the first fragment returns NULL.
90+
udpard_fragment_t* single_hi = make_test_fragment(mem_frag, mem_payload, del_payload, 5, 2, "hi");
91+
TEST_ASSERT_NOT_NULL(single_hi);
92+
single_hi->index_offset.up = nullptr;
93+
single_hi->index_offset.lr[0] = nullptr;
94+
single_hi->index_offset.lr[1] = nullptr;
95+
single_hi->index_offset.bf = 0;
96+
TEST_ASSERT_NULL(udpard_fragment_seek(single_hi, 1));
97+
mem_res_free(mem_payload, single_hi->origin.size, single_hi->origin.data);
98+
mem_res_free(mem_frag, sizeof(udpard_fragment_t), single_hi);
99+
instrumented_allocator_reset(&alloc_frag);
100+
instrumented_allocator_reset(&alloc_payload);
101+
89102
// Test 2: Tree with root and child - to test the root-finding loop.
90103
// Create a simple tree: root at offset 5, left child at offset 0, right child at offset 10
91104
udpard_fragment_t* root = make_test_fragment(mem_frag, mem_payload, del_payload, 5, 3, "mid");

tests/src/test_intrusive_guards.c

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ static void test_mem_endpoint_list_guards(void)
8787
udpard_listed_t tail = { 0 };
8888
enlist_head(&list, &tail);
8989
TEST_ASSERT_TRUE(is_listed(&list, &member));
90+
// is_listed returns true when next is populated.
91+
TEST_ASSERT_TRUE(is_listed(&list, &tail));
9092

9193
// NULL endpoint list yields empty bitmap.
9294
TEST_ASSERT_EQUAL_UINT16(0U, valid_ep_bitmap(NULL));
@@ -158,12 +160,19 @@ static void test_tx_guards(void)
158160
// Push helpers reject invalid timing and null handles.
159161
const uint16_t iface_bitmap_1 = (1U << 0U);
160162
const udpard_bytes_scattered_t empty_payload = { .bytes = { .size = 0U, .data = NULL }, .next = NULL };
163+
const udpard_remote_t remote_ok = { .uid = 1, .endpoints = { { .ip = 1U, .port = UDP_PORT } } };
161164
TEST_ASSERT_FALSE(
162165
udpard_tx_push(&tx, 10, 5, iface_bitmap_1, udpard_prio_fast, 1U, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL));
163166
TEST_ASSERT_FALSE(
164167
udpard_tx_push(NULL, 0, 0, iface_bitmap_1, udpard_prio_fast, 1U, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL));
165-
TEST_ASSERT_FALSE(udpard_tx_push_p2p(
166-
NULL, 0, 0, udpard_prio_fast, (udpard_remote_t){ 0 }, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, NULL));
168+
TEST_ASSERT_FALSE(
169+
udpard_tx_push_p2p(NULL, 0, 0, udpard_prio_fast, remote_ok, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, NULL));
170+
// P2P pushes reject expired deadlines.
171+
TEST_ASSERT_FALSE(
172+
udpard_tx_push_p2p(&tx, 2, 1, udpard_prio_fast, remote_ok, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, NULL));
173+
// P2P pushes reject negative timestamps.
174+
TEST_ASSERT_FALSE(
175+
udpard_tx_push_p2p(&tx, -1, 0, udpard_prio_fast, remote_ok, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, NULL));
167176
// Reject invalid payload pointer and empty interface bitmap.
168177
const udpard_bytes_scattered_t bad_payload = { .bytes = { .size = 1U, .data = NULL }, .next = NULL };
169178
TEST_ASSERT_FALSE(
@@ -174,6 +183,34 @@ static void test_tx_guards(void)
174183
TEST_ASSERT_FALSE(
175184
udpard_tx_push_p2p(&tx, 0, 1, udpard_prio_fast, remote_bad, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, NULL));
176185

186+
// Reject invalid timestamps and priority.
187+
TEST_ASSERT_FALSE(
188+
udpard_tx_push(&tx, -1, 0, iface_bitmap_1, udpard_prio_fast, 1U, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL));
189+
// Use an out-of-range priority without a constant enum cast.
190+
udpard_prio_t bad_prio = udpard_prio_optional;
191+
const unsigned bad_prio_raw = UDPARD_PRIORITY_COUNT;
192+
memcpy(&bad_prio, &bad_prio_raw, sizeof(bad_prio));
193+
TEST_ASSERT_FALSE(
194+
udpard_tx_push(&tx, 0, 1, iface_bitmap_1, bad_prio, 1U, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL));
195+
196+
// Reject zero local UID.
197+
const uint64_t saved_uid = tx.local_uid;
198+
tx.local_uid = 0U;
199+
TEST_ASSERT_FALSE(
200+
udpard_tx_push(&tx, 0, 1, iface_bitmap_1, udpard_prio_fast, 1U, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL));
201+
tx.local_uid = saved_uid;
202+
203+
// P2P guard paths cover local UID, priority, and payload pointer.
204+
uint64_t out_tid = 0;
205+
tx.local_uid = 0U;
206+
TEST_ASSERT_FALSE(udpard_tx_push_p2p(
207+
&tx, 0, 1, udpard_prio_fast, remote_ok, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, &out_tid));
208+
tx.local_uid = saved_uid;
209+
TEST_ASSERT_FALSE(
210+
udpard_tx_push_p2p(&tx, 0, 1, bad_prio, remote_ok, empty_payload, NULL, UDPARD_USER_CONTEXT_NULL, &out_tid));
211+
TEST_ASSERT_FALSE(udpard_tx_push_p2p(
212+
&tx, 0, 1, udpard_prio_fast, remote_ok, bad_payload, NULL, UDPARD_USER_CONTEXT_NULL, &out_tid));
213+
177214
// Poll and refcount no-ops on null data.
178215
udpard_tx_poll(NULL, 0, 0);
179216
udpard_tx_poll(&tx, (udpard_us_t)-1, 0);
@@ -199,6 +236,20 @@ static void test_tx_predictor_sharing(void)
199236
make_mem(&shared_tag[1]),
200237
make_mem(&shared_tag[1]) };
201238
TEST_ASSERT_EQUAL_size_t(2U, tx_predict_frame_count(mtu, mem_arr_split, iface_bitmap_12, 16U));
239+
240+
// Shared spool when payload fits smaller MTU despite mismatch.
241+
const size_t mtu_mixed[UDPARD_IFACE_COUNT_MAX] = { 64U, 128U, 128U };
242+
const uint16_t iface_bitmap_01 = (1U << 0U) | (1U << 1U);
243+
TEST_ASSERT_EQUAL_size_t(1U, tx_predict_frame_count(mtu_mixed, mem_arr, iface_bitmap_01, 32U));
244+
245+
// Gapped bitmap exercises the unset-bit branch.
246+
static char gap_tag[3];
247+
const udpard_mem_t mem_gap[UDPARD_IFACE_COUNT_MAX] = { make_mem(&gap_tag[0]),
248+
make_mem(&gap_tag[1]),
249+
make_mem(&gap_tag[2]) };
250+
const size_t mtu_gap[UDPARD_IFACE_COUNT_MAX] = { 64U, 64U, 64U };
251+
const uint16_t iface_bitmap_02 = (1U << 0U) | (1U << 2U);
252+
TEST_ASSERT_EQUAL_size_t(2U, tx_predict_frame_count(mtu_gap, mem_gap, iface_bitmap_02, 16U));
202253
}
203254

204255
static void test_rx_guards(void)
@@ -229,7 +280,11 @@ static void test_rx_guards(void)
229280
TEST_ASSERT_FALSE(rx_validate_mem_resources(bad_fragment));
230281
bad_fragment.fragment.vtable = &vtable_no_alloc;
231282
TEST_ASSERT_FALSE(rx_validate_mem_resources(bad_fragment));
283+
bad_fragment.fragment.vtable = NULL;
284+
TEST_ASSERT_FALSE(rx_validate_mem_resources(bad_fragment));
232285
TEST_ASSERT_TRUE(udpard_rx_port_new_stateless(&port, 8U, rx_mem, &rx_vtb));
286+
TEST_ASSERT_FALSE(udpard_rx_port_new_stateless(&port, 8U, bad_fragment, &rx_vtb));
287+
TEST_ASSERT_FALSE(udpard_rx_port_new_p2p(&port, 8U, bad_fragment, &rx_vtb));
233288

234289
// Invalid datagram inputs are rejected without processing.
235290
udpard_rx_t rx;
@@ -250,6 +305,59 @@ static void test_rx_guards(void)
250305
small_payload,
251306
(udpard_deleter_t){ .vtable = &(udpard_deleter_vtable_t){ .free = NULL }, .context = NULL },
252307
0));
308+
// Cover each guard term with a valid baseline payload.
309+
const udpard_deleter_t deleter_ok = { .vtable = &deleter_vtable, .context = NULL };
310+
byte_t dgram[HEADER_SIZE_BYTES];
311+
const meta_t meta = { .priority = udpard_prio_nominal,
312+
.kind = frame_msg_best,
313+
.transfer_payload_size = 0,
314+
.transfer_id = 1,
315+
.sender_uid = 2 };
316+
header_serialize(dgram, meta, 0, 0, crc_full(0, NULL));
317+
const udpard_bytes_mut_t dgram_view = { .size = sizeof(dgram), .data = dgram };
318+
const udpard_udpip_ep_t ep_ok = { .ip = 1U, .port = UDP_PORT };
319+
TEST_ASSERT_FALSE(udpard_rx_port_push(NULL, &port, 0, ep_ok, dgram_view, deleter_ok, 0));
320+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx, NULL, 0, ep_ok, dgram_view, deleter_ok, 0));
321+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx, &port, -1, ep_ok, dgram_view, deleter_ok, 0));
322+
TEST_ASSERT_FALSE(
323+
udpard_rx_port_push(&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 0U, .port = UDP_PORT }, dgram_view, deleter_ok, 0));
324+
TEST_ASSERT_FALSE(
325+
udpard_rx_port_push(&rx, &port, 0, ep_ok, (udpard_bytes_mut_t){ .size = 1U, .data = NULL }, deleter_ok, 0));
326+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx, &port, 0, ep_ok, dgram_view, deleter_ok, UDPARD_IFACE_COUNT_MAX));
327+
TEST_ASSERT_FALSE(
328+
udpard_rx_port_push(&rx, &port, 0, ep_ok, dgram_view, (udpard_deleter_t){ .vtable = NULL, .context = NULL }, 0));
329+
TEST_ASSERT_FALSE(
330+
udpard_rx_port_push(&rx,
331+
&port,
332+
0,
333+
ep_ok,
334+
dgram_view,
335+
(udpard_deleter_t){ .vtable = &(udpard_deleter_vtable_t){ .free = NULL }, .context = NULL },
336+
0));
337+
338+
// ACK frames are accepted on P2P ports.
339+
udpard_rx_port_t port_p2p;
340+
TEST_ASSERT_TRUE(udpard_rx_port_new_p2p(&port_p2p, 8U, rx_mem, &rx_vtb));
341+
const meta_t ack_meta = { .priority = udpard_prio_nominal,
342+
.kind = frame_ack,
343+
.transfer_payload_size = 0,
344+
.transfer_id = 2,
345+
.sender_uid = 3 };
346+
header_serialize(dgram, ack_meta, 0, 0, crc_full(0, NULL));
347+
TEST_ASSERT_TRUE(udpard_rx_port_push(&rx, &port_p2p, 0, ep_ok, dgram_view, deleter_ok, 0));
348+
349+
// ACK frames are rejected on non-P2P ports.
350+
const uint64_t errors_before_ack = rx.errors_frame_malformed;
351+
header_serialize(dgram, ack_meta, 0, 0, crc_full(0, NULL));
352+
TEST_ASSERT_TRUE(udpard_rx_port_push(&rx, &port, 0, ep_ok, dgram_view, deleter_ok, 0));
353+
TEST_ASSERT_EQUAL_UINT64(errors_before_ack + 1U, rx.errors_frame_malformed);
354+
355+
// Malformed frames are rejected after parsing.
356+
const uint64_t errors_before_bad = rx.errors_frame_malformed;
357+
header_serialize(dgram, meta, 0, 0, crc_full(0, NULL));
358+
dgram[HEADER_SIZE_BYTES - 1] ^= 0xFFU;
359+
TEST_ASSERT_TRUE(udpard_rx_port_push(&rx, &port, 0, ep_ok, dgram_view, deleter_ok, 0));
360+
TEST_ASSERT_EQUAL_UINT64(errors_before_bad + 1U, rx.errors_frame_malformed);
253361

254362
// Port freeing should tolerate null rx.
255363
udpard_rx_port_free(NULL, &port);

tests/src/test_intrusive_rx.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,60 @@ static void test_rx_fragment_tree_update_a(void)
202202
instrumented_allocator_reset(&alloc_frag);
203203
instrumented_allocator_reset(&alloc_payload);
204204

205+
// Redundant fragment removal when a larger fragment bridges neighbors.
206+
{
207+
udpard_tree_t* root = NULL;
208+
size_t cov = 0;
209+
rx_fragment_tree_update_result_t res = rx_fragment_tree_rejected;
210+
const char payload[] = "abcdefghij";
211+
212+
res = rx_fragment_tree_update(&root, //
213+
mem_frag,
214+
del_payload,
215+
make_frame_base(mem_payload, 0, 2, payload),
216+
10,
217+
10,
218+
&cov);
219+
TEST_ASSERT_EQUAL(rx_fragment_tree_accepted, res);
220+
res = rx_fragment_tree_update(&root, //
221+
mem_frag,
222+
del_payload,
223+
make_frame_base(mem_payload, 2, 2, payload + 2),
224+
10,
225+
10,
226+
&cov);
227+
TEST_ASSERT_EQUAL(rx_fragment_tree_accepted, res);
228+
res = rx_fragment_tree_update(&root, //
229+
mem_frag,
230+
del_payload,
231+
make_frame_base(mem_payload, 6, 2, payload + 6),
232+
10,
233+
10,
234+
&cov);
235+
TEST_ASSERT_EQUAL(rx_fragment_tree_accepted, res);
236+
TEST_ASSERT_EQUAL_size_t(3, tree_count(root));
237+
238+
res = rx_fragment_tree_update(&root, //
239+
mem_frag,
240+
del_payload,
241+
make_frame_base(mem_payload, 1, 6, payload + 1),
242+
10,
243+
10,
244+
&cov);
245+
TEST_ASSERT_EQUAL(rx_fragment_tree_accepted, res);
246+
TEST_ASSERT_EQUAL_size_t(3, tree_count(root));
247+
TEST_ASSERT_EQUAL_size_t(0, fragment_at(root, 0)->offset);
248+
TEST_ASSERT_EQUAL_size_t(1, fragment_at(root, 1)->offset);
249+
TEST_ASSERT_EQUAL_size_t(6, fragment_at(root, 2)->offset);
250+
251+
// Cleanup.
252+
udpard_fragment_free_all((udpard_fragment_t*)root, udpard_make_deleter(mem_frag));
253+
TEST_ASSERT_EQUAL_size_t(0, alloc_frag.allocated_fragments);
254+
TEST_ASSERT_EQUAL_size_t(0, alloc_payload.allocated_fragments);
255+
}
256+
instrumented_allocator_reset(&alloc_frag);
257+
instrumented_allocator_reset(&alloc_payload);
258+
205259
// Non-empty payload test with zero extent.
206260
{
207261
udpard_tree_t* root = NULL;

0 commit comments

Comments
 (0)