Skip to content

Commit 7463fd6

Browse files
more tests
1 parent 109371c commit 7463fd6

File tree

3 files changed

+127
-1
lines changed

3 files changed

+127
-1
lines changed

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ Keep the code and comments very brief. Be sure every significant code block is p
77
When building the code, don't hesitate to use multiple jobs to use all CPU cores.
88

99
Run all tests in debug build to ensure that all assertion checks are enabled.
10+
11+
It is best to use Clang-Format to format the code when done editing.

tests/src/test_integration_sockets.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ void test_multiple_publishers()
481481

482482
const udpard_bytes_scattered_t payload_view = make_scattered(payload.data(), payload.size());
483483
const udpard_us_t now =
484-
1000000LL + static_cast<udpard_us_t>(i) * 10000LL + static_cast<udpard_us_t>(tid) * 100LL;
484+
1000000LL + (static_cast<udpard_us_t>(i) * 10000LL) + (static_cast<udpard_us_t>(tid) * 100LL);
485485
const uint64_t transfer_id = (static_cast<uint64_t>(i) * 1000ULL) + static_cast<uint64_t>(tid);
486486

487487
TEST_ASSERT_GREATER_THAN_UINT32(0U,

tests/src/test_intrusive_tx.c

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ static void record_feedback(udpard_tx_t* const tx, const udpard_tx_feedback_t fb
5252
// Minimal endpoint helper.
5353
static udpard_udpip_ep_t make_ep(const uint32_t ip) { return (udpard_udpip_ep_t){ .ip = ip, .port = 1U }; }
5454

55+
// Small helpers for intrusive checks.
56+
static size_t frames_for(const size_t mtu, const size_t payload) { return larger(1, (payload + mtu - 1U) / mtu); }
57+
static tx_transfer_t* latest_transfer(udpard_tx_t* const tx)
58+
{
59+
return LIST_MEMBER(tx->agewise.head, tx_transfer_t, agewise);
60+
}
61+
5562
static void test_bytes_scattered_read(void)
5663
{
5764
// Skips empty fragments and spans boundaries.
@@ -444,6 +451,122 @@ static void test_tx_ack_and_scheduler(void)
444451
instrumented_allocator_reset(&alloc);
445452
}
446453

454+
static void test_tx_spool_deduplication(void)
455+
{
456+
instrumented_allocator_t alloc_a = { 0 };
457+
instrumented_allocator_t alloc_b = { 0 };
458+
instrumented_allocator_new(&alloc_a);
459+
instrumented_allocator_new(&alloc_b);
460+
udpard_tx_mem_resources_t mem = { .transfer = instrumented_allocator_make_resource(&alloc_a) };
461+
for (size_t i = 0; i < UDPARD_IFACE_COUNT_MAX; i++) {
462+
mem.payload[i] = instrumented_allocator_make_resource(&alloc_a);
463+
}
464+
465+
// Dedup when MTU and allocator match (multi-frame).
466+
udpard_tx_t tx = { 0 };
467+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 99U, 1U, 16U, mem, &(udpard_tx_vtable_t){ .eject = eject_with_flag }));
468+
tx.mtu[0] = 600;
469+
tx.mtu[1] = 600;
470+
const udpard_udpip_ep_t dest_same[] = { make_ep(1), make_ep(2), { 0 } };
471+
byte_t payload_big[1300] = { 0 };
472+
TEST_ASSERT_GREATER_THAN_UINT32(0U,
473+
udpard_tx_push(&tx,
474+
0,
475+
1000,
476+
udpard_prio_nominal,
477+
1,
478+
dest_same,
479+
1,
480+
make_scattered(payload_big, sizeof(payload_big)),
481+
NULL,
482+
NULL));
483+
tx_transfer_t* tr = latest_transfer(&tx);
484+
TEST_ASSERT_EQUAL_size_t(frames_for(tx.mtu[0], sizeof(payload_big)), tx.enqueued_frames_count);
485+
TEST_ASSERT_EQUAL_PTR(tr->head[0], tr->head[1]);
486+
for (tx_frame_t* f = tr->head[0]; f != NULL; f = f->next) {
487+
TEST_ASSERT_EQUAL_size_t(2, f->refcount);
488+
}
489+
udpard_tx_free(&tx);
490+
491+
// Dedup when payload fits both MTU despite mismatch.
492+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 99U, 1U, 8U, mem, &(udpard_tx_vtable_t){ .eject = eject_with_flag }));
493+
tx.mtu[0] = 500;
494+
tx.mtu[1] = 900;
495+
const udpard_udpip_ep_t dest_fit[] = { make_ep(3), make_ep(4), { 0 } };
496+
byte_t payload_small[300] = { 0 };
497+
TEST_ASSERT_GREATER_THAN_UINT32(0U,
498+
udpard_tx_push(&tx,
499+
0,
500+
1000,
501+
udpard_prio_nominal,
502+
2,
503+
dest_fit,
504+
2,
505+
make_scattered(payload_small, sizeof(payload_small)),
506+
NULL,
507+
NULL));
508+
tr = latest_transfer(&tx);
509+
TEST_ASSERT_EQUAL_size_t(1, tx.enqueued_frames_count);
510+
TEST_ASSERT_EQUAL_PTR(tr->head[0], tr->head[1]);
511+
TEST_ASSERT_EQUAL_size_t(2, tr->head[0]->refcount);
512+
udpard_tx_free(&tx);
513+
514+
// No dedup when MTU differs and payload exceeds the smaller MTU.
515+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 99U, 1U, 8U, mem, &(udpard_tx_vtable_t){ .eject = eject_with_flag }));
516+
tx.mtu[0] = 500;
517+
tx.mtu[1] = 900;
518+
const udpard_udpip_ep_t dest_split[] = { make_ep(5), make_ep(6), { 0 } };
519+
byte_t payload_split[800] = { 0 };
520+
TEST_ASSERT_GREATER_THAN_UINT32(0U,
521+
udpard_tx_push(&tx,
522+
0,
523+
1000,
524+
udpard_prio_nominal,
525+
3,
526+
dest_split,
527+
3,
528+
make_scattered(payload_split, sizeof(payload_split)),
529+
NULL,
530+
NULL));
531+
tr = latest_transfer(&tx);
532+
TEST_ASSERT_EQUAL_size_t(frames_for(tx.mtu[0], sizeof(payload_split)) +
533+
frames_for(tx.mtu[1], sizeof(payload_split)),
534+
tx.enqueued_frames_count);
535+
TEST_ASSERT_TRUE(tr->head[0] != tr->head[1]);
536+
TEST_ASSERT_EQUAL_size_t(1, tr->head[0]->refcount);
537+
TEST_ASSERT_EQUAL_size_t(1, tr->head[1]->refcount);
538+
udpard_tx_free(&tx);
539+
540+
// No dedup when allocators differ even with matching MTU and single frame.
541+
udpard_tx_mem_resources_t mem_split = { .transfer = instrumented_allocator_make_resource(&alloc_a) };
542+
mem_split.payload[0] = instrumented_allocator_make_resource(&alloc_a);
543+
mem_split.payload[1] = instrumented_allocator_make_resource(&alloc_b);
544+
mem_split.payload[2] = mem_split.payload[0];
545+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 99U, 1U, 8U, mem_split, &(udpard_tx_vtable_t){ .eject = eject_with_flag }));
546+
tx.mtu[0] = 600;
547+
tx.mtu[1] = 600;
548+
const udpard_udpip_ep_t dest_alloc[] = { make_ep(7), make_ep(8), { 0 } };
549+
byte_t payload_one[400] = { 0 };
550+
TEST_ASSERT_GREATER_THAN_UINT32(0U,
551+
udpard_tx_push(&tx,
552+
0,
553+
1000,
554+
udpard_prio_nominal,
555+
4,
556+
dest_alloc,
557+
4,
558+
make_scattered(payload_one, sizeof(payload_one)),
559+
NULL,
560+
NULL));
561+
tr = latest_transfer(&tx);
562+
TEST_ASSERT_EQUAL_size_t(2, tx.enqueued_frames_count);
563+
TEST_ASSERT_TRUE(tr->head[0] != tr->head[1]);
564+
udpard_tx_free(&tx);
565+
566+
TEST_ASSERT_EQUAL_size_t(0, alloc_a.allocated_fragments);
567+
TEST_ASSERT_EQUAL_size_t(0, alloc_b.allocated_fragments);
568+
}
569+
447570
void setUp(void) {}
448571

449572
void tearDown(void) {}
@@ -456,6 +579,7 @@ int main(void)
456579
RUN_TEST(test_tx_validation_and_free);
457580
RUN_TEST(test_tx_comparators_and_feedback);
458581
RUN_TEST(test_tx_spool_and_queue_errors);
582+
RUN_TEST(test_tx_spool_deduplication);
459583
RUN_TEST(test_tx_ack_and_scheduler);
460584
return UNITY_END();
461585
}

0 commit comments

Comments
 (0)