diff --git a/tests/test_etcp_ping.c b/tests/test_etcp_ping.c new file mode 100644 index 00000000..7c4e563a --- /dev/null +++ b/tests/test_etcp_ping.c @@ -0,0 +1,107 @@ +// test_etcp_ping.c - unit test for etcp_send_ping with callback on PONG/timeout +#include +#include +#include +#include +#include "../src/etcp_connections.h" +#include "../src/utun_instance.h" +#include "../lib/u_async.h" +#include "../lib/debug_config.h" +#include "../lib/mem.h" +#include "../src/secure_channel.h" + +#define TEST_TIMEOUT_MS 500 +static int test_completed = 0; +static int cb_called = 0; +static int cb_success = -1; +static uint64_t test_nonce = 0; + +static void ping_test_callback(int success, void* arg, uint64_t nonce) { + (void)arg; + cb_called++; + cb_success = success; + test_nonce = nonce; + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "ping_test_callback: success=%d nonce=%016llx", success, (unsigned long long)nonce); + test_completed = 1; +} + +int main(void) { + debug_config_init(); + debug_set_level(DEBUG_LEVEL_TRACE); + debug_set_categories(DEBUG_CATEGORY_ALL); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "=== ETCP Ping Test ==="); + + struct UASYNC* ua = uasync_create(); + if (!ua) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "uasync_create failed"); + return 1; + } + + struct UTUN_INSTANCE* instance = u_calloc(1, sizeof(struct UTUN_INSTANCE)); + if (!instance) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "instance alloc failed"); + uasync_destroy(ua, 0); + return 1; + } + instance->ua = ua; + instance->node_id = 0x1234567890ABCDEFULL; + // dummy keys for test (full init in production) + for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { + instance->my_keys.private_key[i] = i; + instance->my_keys.public_key[i] = i + 64; + } + + struct ETCP_SOCKET* dummy_sock = u_calloc(1, sizeof(struct ETCP_SOCKET)); + if (!dummy_sock) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "dummy sock alloc failed"); + utun_instance_destroy(instance); + uasync_destroy(ua, 0); + return 1; + } + dummy_sock->instance = instance; + dummy_sock->fd = socket(AF_INET, SOCK_DGRAM, 0); + dummy_sock->local_addr.ss_family = AF_INET; + instance->etcp_sockets = dummy_sock; + + // dummy pubkey + uint8_t dummy_pubkey[SC_PUBKEY_SIZE]; + for (int i = 0; i < SC_PUBKEY_SIZE; i++) dummy_pubkey[i] = i; + + struct sockaddr_storage test_addr; + memset(&test_addr, 0, sizeof(test_addr)); + struct sockaddr_in* sin = (struct sockaddr_in*)&test_addr; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); + sin->sin_port = htons(12345); + + // test timeout path (no receiver, expect success=0) + int ret = etcp_send_ping(instance, dummy_pubkey, &test_addr, 100, ping_test_callback, NULL); + if (ret != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "etcp_send_ping failed ret=%d", ret); + utun_instance_destroy(instance); + uasync_destroy(ua, 0); + return 1; + } + + // run uasync to trigger timeout cb + for (int i = 0; i < 20 && !test_completed; i++) { + uasync_poll(ua, 50); + } + + if (cb_called != 1 || cb_success != 0) { + DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "callback not triggered correctly: called=%d success=%d", cb_called, cb_success); + utun_instance_destroy(instance); + uasync_destroy(ua, 0); + return 1; + } + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Ping timeout test PASSED (cb called with success=0)"); + + // cleanup + utun_instance_destroy(instance); + uasync_destroy(ua, 0); + + DEBUG_INFO(DEBUG_CATEGORY_ETCP, "ETCP ping unit test PASSED"); + return 0; +}