Skip to content

Commit 708c30d

Browse files
test port
1 parent cae58b6 commit 708c30d

File tree

1 file changed

+346
-5
lines changed

1 file changed

+346
-5
lines changed

tests/src/test_intrusive_rx.c

Lines changed: 346 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2908,11 +2908,352 @@ static void test_port(void)
29082908
TEST_ASSERT_EQUAL(local_uid, rx.p2p_port.topic_hash);
29092909
TEST_ASSERT_EQUAL(UDPARD_REORDERING_WINDOW_UNORDERED, rx.p2p_port.reordering_window);
29102910

2911-
// TODO continue: init two ports, one ORDERED, one STATELESS. Feed frames from different remote nodes into each.
2912-
// Verify the callbacks: on message, on ack, on collision.
2913-
// Feed bad frames and verify they are rejected with no memory leaks.
2914-
(void)mem_payload; // TODO: Will be used when test is completed
2915-
(void)del_payload; // TODO: Will be used when test is completed
2911+
// Initialize two ports: one ORDERED, one STATELESS.
2912+
udpard_rx_port_t port_ordered;
2913+
const uint64_t topic_hash_ordered = 0x1234567890ABCDEFULL;
2914+
TEST_ASSERT(udpard_rx_port_new(&port_ordered, topic_hash_ordered, 1000, 10 * KILO, rx_mem));
2915+
2916+
udpard_rx_port_t port_stateless;
2917+
const uint64_t topic_hash_stateless = 0xFEDCBA0987654321ULL;
2918+
TEST_ASSERT(
2919+
udpard_rx_port_new(&port_stateless, topic_hash_stateless, 500, UDPARD_REORDERING_WINDOW_STATELESS, rx_mem));
2920+
2921+
udpard_us_t now = 0;
2922+
2923+
// Test 1: Send a valid single-frame transfer to the ORDERED port.
2924+
{
2925+
const uint64_t remote_uid = 0xAABBCCDDEEFF0011ULL;
2926+
const uint64_t transfer_id = 100;
2927+
const char* payload_str = "Hello World";
2928+
const size_t payload_len = strlen(payload_str) + 1; // include null terminator
2929+
meta_t meta = { .priority = udpard_prio_nominal,
2930+
.flag_ack = true,
2931+
.transfer_payload_size = (uint32_t)payload_len,
2932+
.transfer_id = transfer_id,
2933+
.sender_uid = remote_uid,
2934+
.topic_hash = topic_hash_ordered };
2935+
const rx_frame_t frame = make_frame(meta, mem_payload, payload_str, 0, payload_len);
2936+
2937+
// Serialize the frame into a datagram.
2938+
byte_t dgram[HEADER_SIZE_BYTES + payload_len];
2939+
header_serialize(dgram, meta, 0, 0, frame.base.crc);
2940+
memcpy(dgram + HEADER_SIZE_BYTES, payload_str, payload_len);
2941+
mem_free_payload(del_payload, frame.base.origin);
2942+
2943+
// Allocate payload for the push.
2944+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
2945+
memcpy(push_payload, dgram, sizeof(dgram));
2946+
2947+
now += 1000;
2948+
TEST_ASSERT(udpard_rx_port_push(&rx,
2949+
&port_ordered,
2950+
now,
2951+
(udpard_udpip_ep_t){ .ip = 0x0A000001, .port = 0x1234 },
2952+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
2953+
del_payload,
2954+
0));
2955+
2956+
// Verify the callback was invoked.
2957+
TEST_ASSERT_EQUAL(1, cb_result.message.count);
2958+
TEST_ASSERT_EQUAL(transfer_id, cb_result.message.history[0].transfer_id);
2959+
TEST_ASSERT_EQUAL(remote_uid, cb_result.message.history[0].remote.uid);
2960+
TEST_ASSERT_EQUAL(payload_len, cb_result.message.history[0].payload_size_stored);
2961+
TEST_ASSERT(transfer_payload_verify(&cb_result.message.history[0], payload_len, payload_str, payload_len));
2962+
2963+
// Verify ACK was mandated.
2964+
TEST_ASSERT_EQUAL(1, cb_result.ack_mandate.count);
2965+
TEST_ASSERT_EQUAL(transfer_id, cb_result.ack_mandate.am.transfer_id);
2966+
2967+
// Clean up.
2968+
udpard_fragment_free_all(cb_result.message.history[0].payload_head, mem_frag);
2969+
cb_result.message.count = 0;
2970+
cb_result.ack_mandate.count = 0;
2971+
}
2972+
2973+
// Test 2: Send a valid single-frame transfer to the STATELESS port.
2974+
{
2975+
const uint64_t remote_uid = 0x1122334455667788ULL;
2976+
const uint64_t transfer_id = 200;
2977+
const char* payload_str = "Stateless";
2978+
const size_t payload_len = strlen(payload_str) + 1;
2979+
meta_t meta = { .priority = udpard_prio_high,
2980+
.flag_ack = false,
2981+
.transfer_payload_size = (uint32_t)payload_len,
2982+
.transfer_id = transfer_id,
2983+
.sender_uid = remote_uid,
2984+
.topic_hash = topic_hash_stateless };
2985+
const rx_frame_t frame = make_frame(meta, mem_payload, payload_str, 0, payload_len);
2986+
2987+
byte_t dgram[HEADER_SIZE_BYTES + payload_len];
2988+
header_serialize(dgram, meta, 0, 0, frame.base.crc);
2989+
memcpy(dgram + HEADER_SIZE_BYTES, payload_str, payload_len);
2990+
mem_free_payload(del_payload, frame.base.origin);
2991+
2992+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
2993+
memcpy(push_payload, dgram, sizeof(dgram));
2994+
2995+
now += 1000;
2996+
TEST_ASSERT(udpard_rx_port_push(&rx,
2997+
&port_stateless,
2998+
now,
2999+
(udpard_udpip_ep_t){ .ip = 0x0B000001, .port = 0x5678 },
3000+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
3001+
del_payload,
3002+
1));
3003+
3004+
TEST_ASSERT_EQUAL(1, cb_result.message.count);
3005+
TEST_ASSERT_EQUAL(transfer_id, cb_result.message.history[0].transfer_id);
3006+
TEST_ASSERT_EQUAL(remote_uid, cb_result.message.history[0].remote.uid);
3007+
TEST_ASSERT_EQUAL(payload_len, cb_result.message.history[0].payload_size_stored);
3008+
TEST_ASSERT(transfer_payload_verify(&cb_result.message.history[0], payload_len, payload_str, payload_len));
3009+
3010+
// No ACK for stateless mode without flag_ack.
3011+
TEST_ASSERT_EQUAL(0, cb_result.ack_mandate.count);
3012+
3013+
udpard_fragment_free_all(cb_result.message.history[0].payload_head, mem_frag);
3014+
cb_result.message.count = 0;
3015+
}
3016+
3017+
// Test 3: Send a multi-frame transfer to the ORDERED port.
3018+
{
3019+
const uint64_t remote_uid = 0xAABBCCDDEEFF0011ULL;
3020+
const uint64_t transfer_id = 101;
3021+
const char* full_payload = "0123456789ABCDEFGHIJ";
3022+
const size_t payload_len = 20;
3023+
meta_t meta = { .priority = udpard_prio_nominal,
3024+
.flag_ack = true,
3025+
.transfer_payload_size = (uint32_t)payload_len,
3026+
.transfer_id = transfer_id,
3027+
.sender_uid = remote_uid,
3028+
.topic_hash = topic_hash_ordered };
3029+
3030+
// Frame 1: offset 0, 10 bytes.
3031+
{
3032+
const rx_frame_t frame = make_frame(meta, mem_payload, full_payload, 0, 10);
3033+
byte_t dgram[HEADER_SIZE_BYTES + 10];
3034+
header_serialize(dgram, meta, 0, 0, frame.base.crc);
3035+
memcpy(dgram + HEADER_SIZE_BYTES, full_payload, 10);
3036+
mem_free_payload(del_payload, frame.base.origin);
3037+
3038+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
3039+
memcpy(push_payload, dgram, sizeof(dgram));
3040+
3041+
now += 1000;
3042+
TEST_ASSERT(udpard_rx_port_push(&rx,
3043+
&port_ordered,
3044+
now,
3045+
(udpard_udpip_ep_t){ .ip = 0x0A000001, .port = 0x1234 },
3046+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
3047+
del_payload,
3048+
0));
3049+
}
3050+
3051+
// Frame 2: offset 10, 10 bytes.
3052+
{
3053+
const rx_frame_t frame = make_frame(meta, mem_payload, full_payload, 10, 10);
3054+
byte_t dgram[HEADER_SIZE_BYTES + 10];
3055+
header_serialize(dgram, meta, 1, 10, frame.base.crc);
3056+
memcpy(dgram + HEADER_SIZE_BYTES, full_payload + 10, 10);
3057+
mem_free_payload(del_payload, frame.base.origin);
3058+
3059+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
3060+
memcpy(push_payload, dgram, sizeof(dgram));
3061+
3062+
now += 1000;
3063+
TEST_ASSERT(udpard_rx_port_push(&rx,
3064+
&port_ordered,
3065+
now,
3066+
(udpard_udpip_ep_t){ .ip = 0x0A000001, .port = 0x1234 },
3067+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
3068+
del_payload,
3069+
0));
3070+
}
3071+
3072+
// Verify the transfer was received.
3073+
TEST_ASSERT_EQUAL(1, cb_result.message.count);
3074+
TEST_ASSERT_EQUAL(transfer_id, cb_result.message.history[0].transfer_id);
3075+
TEST_ASSERT_EQUAL(payload_len, cb_result.message.history[0].payload_size_stored);
3076+
TEST_ASSERT(transfer_payload_verify(&cb_result.message.history[0], payload_len, full_payload, payload_len));
3077+
3078+
TEST_ASSERT_EQUAL(1, cb_result.ack_mandate.count);
3079+
3080+
udpard_fragment_free_all(cb_result.message.history[0].payload_head, mem_frag);
3081+
cb_result.message.count = 0;
3082+
cb_result.ack_mandate.count = 0;
3083+
}
3084+
3085+
// Test 4: Send a frame with wrong topic hash (collision).
3086+
{
3087+
const uint64_t remote_uid = 0x9988776655443322ULL;
3088+
const uint64_t transfer_id = 300;
3089+
const char* payload_str = "Collision";
3090+
const size_t payload_len = strlen(payload_str) + 1;
3091+
const uint64_t wrong_hash = topic_hash_ordered + 1; // Different hash
3092+
meta_t meta = { .priority = udpard_prio_nominal,
3093+
.flag_ack = false,
3094+
.transfer_payload_size = (uint32_t)payload_len,
3095+
.transfer_id = transfer_id,
3096+
.sender_uid = remote_uid,
3097+
.topic_hash = wrong_hash };
3098+
const rx_frame_t frame = make_frame(meta, mem_payload, payload_str, 0, payload_len);
3099+
3100+
byte_t dgram[HEADER_SIZE_BYTES + payload_len];
3101+
header_serialize(dgram, meta, 0, 0, frame.base.crc);
3102+
memcpy(dgram + HEADER_SIZE_BYTES, payload_str, payload_len);
3103+
mem_free_payload(del_payload, frame.base.origin);
3104+
3105+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
3106+
memcpy(push_payload, dgram, sizeof(dgram));
3107+
3108+
now += 1000;
3109+
TEST_ASSERT(udpard_rx_port_push(&rx,
3110+
&port_ordered,
3111+
now,
3112+
(udpard_udpip_ep_t){ .ip = 0x0C000001, .port = 0x9999 },
3113+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
3114+
del_payload,
3115+
2));
3116+
3117+
// Verify collision callback was invoked.
3118+
TEST_ASSERT_EQUAL(1, cb_result.collision.count);
3119+
TEST_ASSERT_EQUAL(remote_uid, cb_result.collision.remote.uid);
3120+
3121+
// No message should have been received.
3122+
TEST_ASSERT_EQUAL(0, cb_result.message.count);
3123+
3124+
cb_result.collision.count = 0;
3125+
}
3126+
3127+
// Test 5: Send a malformed frame (bad CRC in header).
3128+
{
3129+
const uint64_t errors_before = rx.errors_frame_malformed;
3130+
byte_t bad_dgram[HEADER_SIZE_BYTES + 10];
3131+
memset(bad_dgram, 0xAA, sizeof(bad_dgram)); // Garbage data
3132+
3133+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(bad_dgram));
3134+
memcpy(push_payload, bad_dgram, sizeof(bad_dgram));
3135+
3136+
now += 1000;
3137+
TEST_ASSERT(udpard_rx_port_push(&rx,
3138+
&port_ordered,
3139+
now,
3140+
(udpard_udpip_ep_t){ .ip = 0x0D000001, .port = 0xAAAA },
3141+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(bad_dgram) },
3142+
del_payload,
3143+
0));
3144+
3145+
// Verify error counter was incremented.
3146+
TEST_ASSERT_EQUAL(errors_before + 1, rx.errors_frame_malformed);
3147+
3148+
// No callbacks should have been invoked.
3149+
TEST_ASSERT_EQUAL(0, cb_result.message.count);
3150+
TEST_ASSERT_EQUAL(0, cb_result.collision.count);
3151+
TEST_ASSERT_EQUAL(0, cb_result.ack_mandate.count);
3152+
}
3153+
3154+
// Test 6: Send a multi-frame transfer to STATELESS port (should be rejected).
3155+
{
3156+
const uint64_t errors_before = rx.errors_transfer_malformed;
3157+
const uint64_t remote_uid = 0x1122334455667788ULL;
3158+
const uint64_t transfer_id = 201;
3159+
const char* payload_str = "MultiFrameStateless";
3160+
const size_t payload_len = strlen(payload_str) + 1;
3161+
meta_t meta = { .priority = udpard_prio_high,
3162+
.flag_ack = false,
3163+
.transfer_payload_size = (uint32_t)payload_len,
3164+
.transfer_id = transfer_id,
3165+
.sender_uid = remote_uid,
3166+
.topic_hash = topic_hash_stateless };
3167+
3168+
// Send only the first frame (offset 0, partial payload).
3169+
const rx_frame_t frame = make_frame(meta, mem_payload, payload_str, 0, 10);
3170+
byte_t dgram[HEADER_SIZE_BYTES + 10];
3171+
header_serialize(dgram, meta, 0, 0, frame.base.crc);
3172+
memcpy(dgram + HEADER_SIZE_BYTES, payload_str, 10);
3173+
mem_free_payload(del_payload, frame.base.origin);
3174+
3175+
void* push_payload = mem_payload.alloc(mem_payload.user, sizeof(dgram));
3176+
memcpy(push_payload, dgram, sizeof(dgram));
3177+
3178+
now += 1000;
3179+
TEST_ASSERT(udpard_rx_port_push(&rx,
3180+
&port_stateless,
3181+
now,
3182+
(udpard_udpip_ep_t){ .ip = 0x0B000001, .port = 0x5678 },
3183+
(udpard_bytes_mut_t){ .data = push_payload, .size = sizeof(dgram) },
3184+
del_payload,
3185+
1));
3186+
3187+
// STATELESS mode rejects multi-frame transfers.
3188+
TEST_ASSERT_EQUAL(errors_before + 1, rx.errors_transfer_malformed);
3189+
TEST_ASSERT_EQUAL(0, cb_result.message.count);
3190+
}
3191+
3192+
// Test 7: Verify invalid API calls return false.
3193+
{
3194+
void* dummy_payload = mem_payload.alloc(mem_payload.user, 100);
3195+
memset(dummy_payload, 0, 100);
3196+
// Null rx pointer.
3197+
TEST_ASSERT_FALSE(udpard_rx_port_push(NULL,
3198+
&port_ordered,
3199+
now,
3200+
(udpard_udpip_ep_t){ .ip = 0x01020304, .port = 1234 },
3201+
(udpard_bytes_mut_t){ .data = dummy_payload, .size = 100 },
3202+
del_payload,
3203+
0));
3204+
// Null port pointer.
3205+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
3206+
NULL,
3207+
now,
3208+
(udpard_udpip_ep_t){ .ip = 0x01020304, .port = 1234 },
3209+
(udpard_bytes_mut_t){ .data = dummy_payload, .size = 100 },
3210+
del_payload,
3211+
0));
3212+
// Invalid endpoint (ip = 0).
3213+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
3214+
&port_ordered,
3215+
now,
3216+
(udpard_udpip_ep_t){ .ip = 0, .port = 1234 },
3217+
(udpard_bytes_mut_t){ .data = dummy_payload, .size = 100 },
3218+
del_payload,
3219+
0));
3220+
// Invalid endpoint (port = 0).
3221+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
3222+
&port_ordered,
3223+
now,
3224+
(udpard_udpip_ep_t){ .ip = 0x01020304, .port = 0 },
3225+
(udpard_bytes_mut_t){ .data = dummy_payload, .size = 100 },
3226+
del_payload,
3227+
0));
3228+
// Null datagram payload.
3229+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
3230+
&port_ordered,
3231+
now,
3232+
(udpard_udpip_ep_t){ .ip = 0x01020304, .port = 1234 },
3233+
(udpard_bytes_mut_t){ .data = NULL, .size = 100 },
3234+
del_payload,
3235+
0));
3236+
// Invalid interface index.
3237+
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
3238+
&port_ordered,
3239+
now,
3240+
(udpard_udpip_ep_t){ .ip = 0x01020304, .port = 1234 },
3241+
(udpard_bytes_mut_t){ .data = dummy_payload, .size = 100 },
3242+
del_payload,
3243+
UDPARD_NETWORK_INTERFACE_COUNT_MAX));
3244+
// Free the dummy payload since all calls failed.
3245+
mem_free(mem_payload, 100, dummy_payload);
3246+
}
3247+
3248+
// Cleanup.
3249+
udpard_rx_port_free(&rx, &port_ordered);
3250+
udpard_rx_port_free(&rx, &port_stateless);
3251+
udpard_rx_free(&rx);
3252+
3253+
// Verify no memory leaks.
3254+
TEST_ASSERT_EQUAL_size_t(0, alloc_frag.allocated_fragments);
3255+
TEST_ASSERT_EQUAL_size_t(0, alloc_session.allocated_fragments);
3256+
TEST_ASSERT_EQUAL_size_t(0, alloc_payload.allocated_fragments);
29163257
}
29173258

29183259
void setUp(void) {}

0 commit comments

Comments
 (0)