Skip to content

Commit 76762f6

Browse files
tests
1 parent cc72ece commit 76762f6

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

tests/src/test_intrusive_tx.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ typedef struct
1919
udpard_tx_feedback_t last;
2020
} feedback_state_t;
2121

22+
typedef struct
23+
{
24+
size_t count;
25+
udpard_us_t when[8];
26+
} eject_log_t;
27+
2228
static void noop_free(void* const user, const size_t size, void* const pointer)
2329
{
2430
(void)user;
@@ -38,6 +44,16 @@ static bool eject_with_flag(udpard_tx_t* const tx, const udpard_tx_ejection_t ej
3844
return true;
3945
}
4046

47+
// Records ejection timestamps for later inspection.
48+
static bool eject_with_log(udpard_tx_t* const tx, const udpard_tx_ejection_t ejection)
49+
{
50+
eject_log_t* const st = (eject_log_t*)tx->user;
51+
if ((st != NULL) && (st->count < (sizeof(st->when) / sizeof(st->when[0])))) {
52+
st->when[st->count++] = ejection.now;
53+
}
54+
return true;
55+
}
56+
4157
// Records feedback into the provided state via user_transfer_reference.
4258
static void record_feedback(udpard_tx_t* const tx, const udpard_tx_feedback_t fb)
4359
{
@@ -451,6 +467,107 @@ static void test_tx_ack_and_scheduler(void)
451467
instrumented_allocator_reset(&alloc);
452468
}
453469

470+
static void test_tx_stage_if(void)
471+
{
472+
// Exercises retransmission gating near deadline.
473+
udpard_tx_t tx = { 0 };
474+
tx.ack_baseline_timeout = 10;
475+
476+
tx_transfer_t tr;
477+
mem_zero(sizeof(tr), &tr);
478+
tr.priority = udpard_prio_nominal;
479+
tr.deadline = 1000;
480+
tr.staged_until = 100;
481+
482+
udpard_us_t expected = tr.staged_until;
483+
484+
tx_stage_if(&tx, &tr);
485+
expected += tx_ack_timeout(tx.ack_baseline_timeout, tr.priority, 0);
486+
TEST_ASSERT_EQUAL_UINT8(1, tr.epoch);
487+
TEST_ASSERT_EQUAL(expected, tr.staged_until);
488+
TEST_ASSERT_NOT_NULL(tx.index_staged);
489+
cavl2_remove(&tx.index_staged, &tr.index_staged);
490+
491+
tx_stage_if(&tx, &tr);
492+
expected += tx_ack_timeout(tx.ack_baseline_timeout, tr.priority, 1);
493+
TEST_ASSERT_EQUAL_UINT8(2, tr.epoch);
494+
TEST_ASSERT_EQUAL(expected, tr.staged_until);
495+
TEST_ASSERT_NOT_NULL(tx.index_staged);
496+
cavl2_remove(&tx.index_staged, &tr.index_staged);
497+
498+
tx_stage_if(&tx, &tr);
499+
expected += tx_ack_timeout(tx.ack_baseline_timeout, tr.priority, 2);
500+
TEST_ASSERT_EQUAL_UINT8(3, tr.epoch);
501+
TEST_ASSERT_EQUAL(expected, tr.staged_until);
502+
TEST_ASSERT_NULL(tx.index_staged);
503+
}
504+
505+
static void test_tx_stage_if_via_tx_push(void)
506+
{
507+
// Tracks retransmission times via the scheduler.
508+
instrumented_allocator_t alloc = { 0 };
509+
instrumented_allocator_new(&alloc);
510+
udpard_tx_mem_resources_t mem = { .transfer = instrumented_allocator_make_resource(&alloc) };
511+
for (size_t i = 0; i < UDPARD_IFACE_COUNT_MAX; i++) {
512+
mem.payload[i] = instrumented_allocator_make_resource(&alloc);
513+
}
514+
515+
udpard_tx_t tx = { 0 };
516+
eject_log_t log = { 0 };
517+
feedback_state_t fb = { 0 };
518+
udpard_tx_vtable_t vt = { .eject = eject_with_log };
519+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 30U, 1U, 4U, mem, &vt));
520+
tx.user = &log;
521+
tx.ack_baseline_timeout = 10;
522+
udpard_udpip_ep_t dest[UDPARD_IFACE_COUNT_MAX] = { make_ep(1), { 0 } };
523+
524+
TEST_ASSERT_GREATER_THAN_UINT32(
525+
0, udpard_tx_push(&tx, 0, 500, udpard_prio_nominal, 77, dest, 1, make_scattered(NULL, 0), record_feedback, &fb));
526+
527+
udpard_tx_poll(&tx, 0, UDPARD_IFACE_MASK_ALL);
528+
udpard_tx_poll(&tx, 160, UDPARD_IFACE_MASK_ALL);
529+
udpard_tx_poll(&tx, 400, UDPARD_IFACE_MASK_ALL);
530+
531+
TEST_ASSERT_EQUAL_size_t(2, log.count);
532+
TEST_ASSERT_EQUAL(0, log.when[0]);
533+
TEST_ASSERT_EQUAL(160, log.when[1]);
534+
TEST_ASSERT_NULL(tx.index_staged);
535+
udpard_tx_free(&tx);
536+
instrumented_allocator_reset(&alloc);
537+
}
538+
539+
static void test_tx_stage_if_short_deadline(void)
540+
{
541+
// Ensures retransmission is skipped when deadline is too close.
542+
instrumented_allocator_t alloc = { 0 };
543+
instrumented_allocator_new(&alloc);
544+
udpard_tx_mem_resources_t mem = { .transfer = instrumented_allocator_make_resource(&alloc) };
545+
for (size_t i = 0; i < UDPARD_IFACE_COUNT_MAX; i++) {
546+
mem.payload[i] = instrumented_allocator_make_resource(&alloc);
547+
}
548+
549+
udpard_tx_t tx = { 0 };
550+
eject_log_t log = { 0 };
551+
feedback_state_t fb = { 0 };
552+
udpard_tx_vtable_t vt = { .eject = eject_with_log };
553+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 31U, 1U, 4U, mem, &vt));
554+
tx.user = &log;
555+
tx.ack_baseline_timeout = 10;
556+
udpard_udpip_ep_t dest[UDPARD_IFACE_COUNT_MAX] = { make_ep(1), { 0 } };
557+
558+
TEST_ASSERT_GREATER_THAN_UINT32(
559+
0, udpard_tx_push(&tx, 0, 50, udpard_prio_nominal, 78, dest, 1, make_scattered(NULL, 0), record_feedback, &fb));
560+
561+
udpard_tx_poll(&tx, 0, UDPARD_IFACE_MASK_ALL);
562+
udpard_tx_poll(&tx, 30, UDPARD_IFACE_MASK_ALL);
563+
udpard_tx_poll(&tx, 60, UDPARD_IFACE_MASK_ALL);
564+
565+
TEST_ASSERT_EQUAL_size_t(1, log.count);
566+
TEST_ASSERT_EQUAL(0, log.when[0]);
567+
udpard_tx_free(&tx);
568+
instrumented_allocator_reset(&alloc);
569+
}
570+
454571
// Cancels transfers and reports outcome.
455572
static void test_tx_cancel(void)
456573
{
@@ -618,6 +735,9 @@ int main(void)
618735
RUN_TEST(test_tx_validation_and_free);
619736
RUN_TEST(test_tx_comparators_and_feedback);
620737
RUN_TEST(test_tx_spool_and_queue_errors);
738+
RUN_TEST(test_tx_stage_if);
739+
RUN_TEST(test_tx_stage_if_via_tx_push);
740+
RUN_TEST(test_tx_stage_if_short_deadline);
621741
RUN_TEST(test_tx_cancel);
622742
RUN_TEST(test_tx_spool_deduplication);
623743
RUN_TEST(test_tx_ack_and_scheduler);

0 commit comments

Comments
 (0)