// test_tcp_proxy.c — TCP proxy smoke test: create/destroy without leaks #include #include #include #include #include #include "test_utils.h" #include "../src/tcp_proxy.h" #include "../src/config_parser.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" #include "../lib/mem.h" static int g_ok = 1; static void check_no_leaks(const char* label) { size_t leaks = u_get_allocated_count(); if (leaks != 0) { printf("[FAIL] %s: memory leak count=%zu\n", label, leaks); g_ok = 0; } } int main(void) { debug_config_init(); int fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { perror("socketpair"); return 1; } // Test 1: create proxy with mapping, raw-fd mode { struct UASYNC* ua = uasync_create(); if (!ua) { printf("[FAIL] uasync_create\n"); close(fds[0]); close(fds[1]); return 1; } struct tcp_proxy_mapping_config m = {.local_port = 9090, .remote_ip = "127.0.0.1", .remote_port = 9999}; struct tcp_proxy* p = tcp_proxy_create(NULL, ua, NULL, NULL, 0, 0, &m, 1, 0, fds[0], 0); if (!p) { printf("[FAIL] tcp_proxy_create with mapping\n"); uasync_destroy(ua, 0); close(fds[0]); close(fds[1]); return 1; } tcp_proxy_destroy(p); uasync_destroy(ua, 0); check_no_leaks("create/destroy with mapping"); } // Test 2: create proxy without mapping { int fds2[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds2) < 0) { perror("socketpair2"); close(fds[1]); return 1; } struct UASYNC* ua = uasync_create(); if (!ua) { printf("[FAIL] uasync_create\n"); close(fds2[0]); close(fds2[1]); close(fds[1]); return 1; } struct tcp_proxy* p = tcp_proxy_create(NULL, ua, NULL, NULL, 0, 0, NULL, 0, 0, fds2[0], 0); if (!p) { printf("[FAIL] tcp_proxy_create without mapping\n"); uasync_destroy(ua, 0); close(fds2[0]); close(fds2[1]); close(fds[1]); return 1; } tcp_proxy_destroy(p); uasync_destroy(ua, 0); close(fds2[1]); check_no_leaks("create/destroy without mapping"); } close(fds[1]); if (g_ok) printf("[PASS] test_tcp_proxy — create/destroy\n"); return g_ok ? 0 : 1; }