Skip to content

Commit eb1d592

Browse files
add test
1 parent 825f939 commit eb1d592

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

.idea/dictionaries/project.xml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/src/test_intrusive_rx.c

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ static udpard_fragment_t* fragment_at(udpard_tree_t* const root, uint32_t index)
2727
return NULL;
2828
}
2929

30+
static bool fragment_equals(udpard_fragment_t* const frag,
31+
const size_t offset,
32+
const size_t size,
33+
const void* const payload)
34+
{
35+
if ((frag == NULL) || (frag->offset != offset) || (frag->view.size != size)) {
36+
return false;
37+
}
38+
return (size == 0U) || (memcmp(frag->view.data, payload, size) == 0);
39+
}
40+
3041
/// Allocates the payload on the heap, emulating normal frame reception.
3142
static rx_frame_base_t make_frame_base(const udpard_mem_resource_t mem,
3243
const size_t offset,
@@ -434,6 +445,302 @@ static void test_rx_fragment_tree_update_a(void)
434445
}
435446
instrumented_allocator_reset(&alloc_frag);
436447
instrumented_allocator_reset(&alloc_payload);
448+
449+
// Multi-frame reassembly test with defragmentation: "abcdefghijklmnopqrst". Split with various MTU:
450+
//
451+
// MTU 4: abcd efgh ijkl mnop qrst
452+
// 0 4 8 12 16
453+
//
454+
// MTU 5: abcde fghij klmno pqrst
455+
// 0 5 10 15
456+
//
457+
// MTU 11: abcdefghijk lmnopqrst
458+
// 0 11
459+
//
460+
// Offset helper:
461+
// abcdefghijklmnopqrst
462+
// 01234567890123456789
463+
// 00000000001111111111
464+
{
465+
udpard_tree_t* root = NULL;
466+
size_t cov = 0;
467+
rx_fragment_tree_update_result_t res = rx_fragment_tree_not_done;
468+
469+
// Add fragment.
470+
res = rx_fragment_tree_update(&root, //
471+
mem_frag,
472+
del_payload,
473+
make_frame_base(mem_payload, 0, 5, "abcde"),
474+
21,
475+
21,
476+
&cov);
477+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
478+
TEST_ASSERT_EQUAL_size_t(5, cov);
479+
TEST_ASSERT_NOT_NULL(root);
480+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
481+
TEST_ASSERT_NULL(fragment_at(root, 1));
482+
483+
// Add fragment. Rejected because contained by existing.
484+
res = rx_fragment_tree_update(&root, //
485+
mem_frag,
486+
del_payload,
487+
make_frame_base(mem_payload, 0, 4, "abcd"),
488+
21,
489+
21,
490+
&cov);
491+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
492+
TEST_ASSERT_EQUAL_size_t(5, cov);
493+
TEST_ASSERT_NOT_NULL(root);
494+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
495+
TEST_ASSERT_NULL(fragment_at(root, 1));
496+
497+
// Add 2 fragments. They cover new ground with a gap but they are small, to be replaced later.
498+
// Resulting state:
499+
// 0 |abcde |
500+
// 1 | ijkl |
501+
// 2 | mnop |
502+
res = rx_fragment_tree_update(&root, //
503+
mem_frag,
504+
del_payload,
505+
make_frame_base(mem_payload, 8, 4, "ijkl"),
506+
21,
507+
21,
508+
&cov);
509+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
510+
res = rx_fragment_tree_update(&root, //
511+
mem_frag,
512+
del_payload,
513+
make_frame_base(mem_payload, 12, 4, "mnop"),
514+
21,
515+
21,
516+
&cov);
517+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
518+
TEST_ASSERT_EQUAL_size_t(5, cov); // not extended due to a gap
519+
TEST_ASSERT_NOT_NULL(root);
520+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
521+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 8, 4, "ijkl"));
522+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 12, 4, "mnop"));
523+
TEST_ASSERT_NULL(fragment_at(root, 3));
524+
TEST_ASSERT_EQUAL_size_t(3, alloc_frag.allocated_fragments);
525+
TEST_ASSERT_EQUAL_size_t(3, alloc_payload.allocated_fragments);
526+
527+
// Add another fragment that doesn't add any new information but is accepted anyway because it is larger.
528+
// This may enable defragmentation in the future.
529+
// Resulting state:
530+
// 0 |abcde |
531+
// 1 | ijkl |
532+
// 2 | klmno |
533+
// 3 | mnop |
534+
res = rx_fragment_tree_update(&root, //
535+
mem_frag,
536+
del_payload,
537+
make_frame_base(mem_payload, 10, 5, "klmno"),
538+
21,
539+
21,
540+
&cov);
541+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
542+
TEST_ASSERT_EQUAL_size_t(5, cov); // not extended due to a gap
543+
TEST_ASSERT_NOT_NULL(root);
544+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
545+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 8, 4, "ijkl"));
546+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 10, 5, "klmno"));
547+
TEST_ASSERT(fragment_equals(fragment_at(root, 3), 12, 4, "mnop"));
548+
TEST_ASSERT_NULL(fragment_at(root, 4));
549+
TEST_ASSERT_EQUAL_size_t(4, alloc_frag.allocated_fragments);
550+
TEST_ASSERT_EQUAL_size_t(4, alloc_payload.allocated_fragments);
551+
552+
// Add another fragment that bridges the gap and allows removing ijkl.
553+
// Resulting state:
554+
// 0 |abcde |
555+
// 1 | fghij | replaces the old 1
556+
// 2 | klmno |
557+
// 3 | mnop | kept because it has 'p'
558+
res = rx_fragment_tree_update(&root, //
559+
mem_frag,
560+
del_payload,
561+
make_frame_base(mem_payload, 5, 5, "fghij"),
562+
21,
563+
21,
564+
&cov);
565+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
566+
TEST_ASSERT_EQUAL_size_t(16, cov); // jumps to the end because the gap is covered
567+
TEST_ASSERT_NOT_NULL(root);
568+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
569+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 5, 5, "fghij"));
570+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 10, 5, "klmno"));
571+
TEST_ASSERT(fragment_equals(fragment_at(root, 3), 12, 4, "mnop"));
572+
TEST_ASSERT_NULL(fragment_at(root, 4));
573+
TEST_ASSERT_EQUAL_size_t(4, alloc_frag.allocated_fragments);
574+
TEST_ASSERT_EQUAL_size_t(4, alloc_payload.allocated_fragments);
575+
576+
// Add the last smallest fragment. The transfer is not detected as complete because it is set to 21 bytes.
577+
// Resulting state:
578+
// 0 |abcde |
579+
// 1 | fghij | replaces the old 1
580+
// 2 | klmno |
581+
// 3 | mnop | kept because it has 'p'
582+
// 4 | qrst|
583+
res = rx_fragment_tree_update(&root, //
584+
mem_frag,
585+
del_payload,
586+
make_frame_base(mem_payload, 16, 4, "qrst"),
587+
21,
588+
21,
589+
&cov);
590+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
591+
TEST_ASSERT_EQUAL_size_t(20, cov); // updated
592+
TEST_ASSERT_NOT_NULL(root);
593+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
594+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 5, 5, "fghij"));
595+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 10, 5, "klmno"));
596+
TEST_ASSERT(fragment_equals(fragment_at(root, 3), 12, 4, "mnop"));
597+
TEST_ASSERT(fragment_equals(fragment_at(root, 4), 16, 4, "qrst"));
598+
TEST_ASSERT_NULL(fragment_at(root, 5));
599+
TEST_ASSERT_EQUAL_size_t(5, alloc_frag.allocated_fragments);
600+
TEST_ASSERT_EQUAL_size_t(5, alloc_payload.allocated_fragments);
601+
602+
// Send redundant fragments. State unchanged.
603+
res = rx_fragment_tree_update(&root, //
604+
mem_frag,
605+
del_payload,
606+
make_frame_base(mem_payload, 4, 4, "efgh"),
607+
21,
608+
21,
609+
&cov);
610+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
611+
res = rx_fragment_tree_update(&root, //
612+
mem_frag,
613+
del_payload,
614+
make_frame_base(mem_payload, 5, 5, "fghij"),
615+
21,
616+
21,
617+
&cov);
618+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
619+
res = rx_fragment_tree_update(&root, //
620+
mem_frag,
621+
del_payload,
622+
make_frame_base(mem_payload, 0, 5, "abcde"),
623+
21,
624+
21,
625+
&cov);
626+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
627+
TEST_ASSERT_EQUAL_size_t(20, cov); // no change
628+
TEST_ASSERT_NOT_NULL(root);
629+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 5, "abcde"));
630+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 5, 5, "fghij"));
631+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 10, 5, "klmno"));
632+
TEST_ASSERT(fragment_equals(fragment_at(root, 3), 12, 4, "mnop"));
633+
TEST_ASSERT(fragment_equals(fragment_at(root, 4), 16, 4, "qrst"));
634+
TEST_ASSERT_NULL(fragment_at(root, 5));
635+
TEST_ASSERT_EQUAL_size_t(5, alloc_frag.allocated_fragments);
636+
TEST_ASSERT_EQUAL_size_t(5, alloc_payload.allocated_fragments);
637+
638+
// Add the first max-MTU fragment. Replaces the smaller initial fragments.
639+
// Resulting state:
640+
// 0 |abcdefghijk | replaces 0 and 1
641+
// 1 | klmno | kept because it has 'lmno'
642+
// 2 | mnop | kept because it has 'p'
643+
// 3 | qrst|
644+
res = rx_fragment_tree_update(&root, //
645+
mem_frag,
646+
del_payload,
647+
make_frame_base(mem_payload, 0, 11, "abcdefghijk"),
648+
21,
649+
21,
650+
&cov);
651+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
652+
TEST_ASSERT_EQUAL_size_t(20, cov);
653+
TEST_ASSERT_NOT_NULL(root);
654+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 11, "abcdefghijk"));
655+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 10, 5, "klmno"));
656+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 12, 4, "mnop"));
657+
TEST_ASSERT(fragment_equals(fragment_at(root, 3), 16, 4, "qrst"));
658+
TEST_ASSERT_NULL(fragment_at(root, 4));
659+
TEST_ASSERT_EQUAL_size_t(4, alloc_frag.allocated_fragments);
660+
TEST_ASSERT_EQUAL_size_t(4, alloc_payload.allocated_fragments);
661+
662+
// Add the last MTU 5 fragment. Replaces the last two MTU 4 fragments.
663+
// Resulting state:
664+
// 0 |abcdefghijk |
665+
// 1 | klmno | kept because it has 'lmno'
666+
// 2 | pqrst|
667+
res = rx_fragment_tree_update(&root, //
668+
mem_frag,
669+
del_payload,
670+
make_frame_base(mem_payload, 15, 5, "pqrst"),
671+
21,
672+
21,
673+
&cov);
674+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
675+
TEST_ASSERT_EQUAL_size_t(20, cov);
676+
TEST_ASSERT_NOT_NULL(root);
677+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 11, "abcdefghijk"));
678+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 10, 5, "klmno"));
679+
TEST_ASSERT(fragment_equals(fragment_at(root, 2), 15, 5, "pqrst"));
680+
TEST_ASSERT_NULL(fragment_at(root, 3));
681+
TEST_ASSERT_EQUAL_size_t(3, alloc_frag.allocated_fragments);
682+
TEST_ASSERT_EQUAL_size_t(3, alloc_payload.allocated_fragments);
683+
684+
// Add the last max-MTU fragment. Replaces the last two fragments.
685+
// Resulting state:
686+
// 0 |abcdefghijk |
687+
// 1 | lmnopqrst|
688+
res = rx_fragment_tree_update(&root, //
689+
mem_frag,
690+
del_payload,
691+
make_frame_base(mem_payload, 11, 9, "lmnopqrst"),
692+
21,
693+
21,
694+
&cov);
695+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
696+
TEST_ASSERT_EQUAL_size_t(20, cov);
697+
TEST_ASSERT_NOT_NULL(root);
698+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 11, "abcdefghijk"));
699+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 11, 9, "lmnopqrst"));
700+
TEST_ASSERT_NULL(fragment_at(root, 2));
701+
TEST_ASSERT_EQUAL_size_t(2, alloc_frag.allocated_fragments);
702+
TEST_ASSERT_EQUAL_size_t(2, alloc_payload.allocated_fragments);
703+
704+
// Replace everything with a single huge fragment.
705+
res = rx_fragment_tree_update(&root, //
706+
mem_frag,
707+
del_payload,
708+
make_frame_base(mem_payload, 0, 20, "abcdefghijklmnopqrst"),
709+
21,
710+
21,
711+
&cov);
712+
TEST_ASSERT_EQUAL(rx_fragment_tree_not_done, res);
713+
TEST_ASSERT_EQUAL_size_t(20, cov);
714+
TEST_ASSERT_NOT_NULL(root);
715+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 20, "abcdefghijklmnopqrst"));
716+
TEST_ASSERT_NULL(fragment_at(root, 1));
717+
TEST_ASSERT_EQUAL_size_t(1, alloc_frag.allocated_fragments);
718+
TEST_ASSERT_EQUAL_size_t(1, alloc_payload.allocated_fragments);
719+
720+
// One tiny boi will complete the transfer.
721+
res = rx_fragment_tree_update(&root, //
722+
mem_frag,
723+
del_payload,
724+
make_frame_base(mem_payload, 19, 2, "t-"),
725+
21,
726+
21,
727+
&cov);
728+
TEST_ASSERT_EQUAL(rx_fragment_tree_done, res);
729+
TEST_ASSERT_EQUAL_size_t(21, cov);
730+
TEST_ASSERT_NOT_NULL(root);
731+
TEST_ASSERT(fragment_equals(fragment_at(root, 0), 0, 20, "abcdefghijklmnopqrst"));
732+
TEST_ASSERT(fragment_equals(fragment_at(root, 1), 19, 2, "t-"));
733+
TEST_ASSERT_NULL(fragment_at(root, 2));
734+
TEST_ASSERT_EQUAL_size_t(2, alloc_frag.allocated_fragments);
735+
TEST_ASSERT_EQUAL_size_t(2, alloc_payload.allocated_fragments);
736+
737+
// Cleanup.
738+
udpard_fragment_free_all((udpard_fragment_t*)root, mem_frag);
739+
TEST_ASSERT_EQUAL_size_t(0, alloc_frag.allocated_fragments);
740+
TEST_ASSERT_EQUAL_size_t(0, alloc_payload.allocated_fragments);
741+
}
742+
instrumented_allocator_reset(&alloc_frag);
743+
instrumented_allocator_reset(&alloc_payload);
437744
}
438745

439746
static void test_rx_transfer_id_forward_distance(void)

0 commit comments

Comments
 (0)