- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll - stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close - utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP), add deferred drain in both Phase J and L - stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39, exchange ed25519_pubkey in both handshake directions - etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb - chat_sync.c: fix lk->conn NULL dereference for TCP links - test_stcp.c: update stcp_server_create/stcp_client_connect callsites - tools/chat_tcp_test: change transport udp→tcp
199 lines
5.9 KiB
C
199 lines
5.9 KiB
C
/**
|
|
* FULL REFACTORED TEST for new NODEINFO-based routing system
|
|
*
|
|
* Tests:
|
|
* - TOPO_GROUP_NODE creation and insertion
|
|
* - paths management (add/remove)
|
|
* - versioning (ver field)
|
|
* - WITHDRAW when no paths left
|
|
* - Performance with 1000 nodes
|
|
* - Overlap prevention and lookup
|
|
*
|
|
* Status: Complete coverage of current route_lib + route_bgp
|
|
*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
|
|
//#include "../src/utun_instance.h"
|
|
#include "topo_node.h"
|
|
#include "route_lib.h"
|
|
#include "../lib/debug_config.h"
|
|
#include "../lib/mem.h"
|
|
#include "../lib/platform_compat.h"
|
|
#include "../lib/ll_queue.h"
|
|
|
|
/* ====================== МОКИ И ХЕЛПЕРЫ ====================== */
|
|
struct ETCP_CONN {
|
|
uint64_t peer_node_id;
|
|
struct UTUN_INSTANCE* instance;
|
|
char log_name[32];
|
|
};
|
|
|
|
struct UTUN_INSTANCE {
|
|
uint64_t node_id;
|
|
struct ROUTE_TABLE* rt;
|
|
struct TOPO_GROUP* group;
|
|
};
|
|
|
|
/* Helper to create test TOPO_GROUP_NODE with subnet in linked list */
|
|
static struct TOPO_GROUP_NODE* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) {
|
|
struct TOPO_GROUP_NODE* nq = u_calloc(1, sizeof(struct TOPO_GROUP_NODE));
|
|
if (!nq) return NULL;
|
|
struct TOPO_NODE* ni = u_calloc(1, sizeof(struct TOPO_NODE));
|
|
if (!ni) { u_free(nq); return NULL; }
|
|
ni->group_ref_count = 1;
|
|
ni->node_id = htobe64(node_id);
|
|
ni->ver = ver;
|
|
nq->node_id = ni->node_id;
|
|
nq->paths = queue_new(NULL, 16, 0, 0, "test_paths");
|
|
struct TOPO_NODESUBNETS* r = u_calloc(1, sizeof(struct TOPO_NODESUBNETS));
|
|
if (r) {
|
|
struct TOPO_SUBNET4* sn = u_calloc(1, sizeof(struct TOPO_SUBNET4));
|
|
uint32_t net = htonl(subnet_net);
|
|
memcpy(sn->addr, &net, 4); sn->prefix_length = prefix;
|
|
r->v4_subnets = sn;
|
|
nq->subnets = r;
|
|
}
|
|
return nq;
|
|
}
|
|
|
|
static void free_test_node(struct TOPO_GROUP_NODE* nq) {
|
|
if (nq) {
|
|
if (nq->paths) queue_free(nq->paths);
|
|
if (nq->subnets) { u_free(nq->subnets->v4_subnets); u_free(nq->subnets); }
|
|
u_free(nq);
|
|
}
|
|
}
|
|
|
|
/* ====================== СТАТИСТИКА ====================== */
|
|
static struct {
|
|
int run, passed, failed;
|
|
} stats = {0};
|
|
|
|
#define TEST(name) do { \
|
|
printf("TEST: %-50s ", name); fflush(stdout); \
|
|
stats.run++; \
|
|
} while(0)
|
|
|
|
#define PASS() do { puts("PASS"); stats.passed++; } while(0)
|
|
#define FAIL(msg) do { printf("FAIL: %s\n", msg); stats.failed++; } while(0)
|
|
|
|
#define ASSERT(c, m) do { if (!(c)) { FAIL(m); return; } } while(0)
|
|
#define ASSERT_EQ(a,b,m) ASSERT((a)==(b),m)
|
|
#define ASSERT_PTR(p,m) ASSERT((p)!=NULL,m)
|
|
|
|
/* ====================== CALLBACK ====================== */
|
|
static int cb_insert = 0;
|
|
static int cb_reroute = 0;
|
|
static int cb_withdraw = 0;
|
|
|
|
static void test_change_cb(struct ROUTE_TABLE* table,
|
|
struct ROUTE_ENTRY* entry,
|
|
int action,
|
|
uint64_t changed_from,
|
|
void* arg) {
|
|
(void)table; (void)entry; (void)changed_from; (void)arg;
|
|
if (action == 0) cb_insert++;
|
|
else if (action == 1) cb_reroute++;
|
|
else if (action == 2) cb_withdraw++;
|
|
}
|
|
|
|
/* ====================== ТЕСТЫ (для новой NODEINFO архитектуры) ====================== */
|
|
|
|
static void test_table_create_destroy(void) {
|
|
TEST("route_table_create / destroy");
|
|
struct ROUTE_TABLE *t = route_table_create(0);
|
|
ASSERT_PTR(t, "create failed");
|
|
ASSERT_EQ(t->count, 0, "empty table");
|
|
route_table_destroy(t);
|
|
PASS();
|
|
}
|
|
|
|
static void test_nodeinfo_insert(void) {
|
|
TEST("TOPO_GROUP_NODE insert into routing table");
|
|
struct ROUTE_TABLE *t = route_table_create(0);
|
|
struct TOPO_GROUP_NODE* nq = create_test_node(0x12345678ULL, 1, 0x0a000000, 8);
|
|
|
|
bool inserted = route_insert(t, nq);
|
|
ASSERT(inserted, "insert nodeinfo");
|
|
ASSERT(t->count > 0, "routes added");
|
|
|
|
free_test_node(nq);
|
|
route_table_destroy(t);
|
|
PASS();
|
|
}
|
|
|
|
static void test_versioning(void) {
|
|
TEST("NODEINFO multiple nodes");
|
|
struct ROUTE_TABLE *t = route_table_create(0);
|
|
struct TOPO_GROUP_NODE* nq1 = create_test_node(0x1111ULL, 5, 0x0a000000, 8);
|
|
struct TOPO_GROUP_NODE* nq2 = create_test_node(0x2222ULL, 1, 0xac100000, 12);
|
|
|
|
route_insert(t, nq1);
|
|
bool ins2 = route_insert(t, nq2);
|
|
|
|
ASSERT(ins2, "second node inserted");
|
|
ASSERT_EQ(t->count, 2, "two nodes/routes");
|
|
|
|
free_test_node(nq1);
|
|
free_test_node(nq2);
|
|
route_table_destroy(t);
|
|
PASS();
|
|
}
|
|
|
|
|
|
static void test_performance_1000_nodes(void) {
|
|
TEST("performance with 1000 nodes");
|
|
struct ROUTE_TABLE *t = route_table_create(0);
|
|
clock_t start = clock();
|
|
|
|
for (int i = 0; i < 1000; i++) {
|
|
uint32_t sub = 0x0a000000 + (i * 0x100); /* distinct 10.0.x.0/24 to avoid overlap */
|
|
struct TOPO_GROUP_NODE* nq = create_test_node(0x1000000ULL + i, 1, sub, 24);
|
|
route_insert(t, nq);
|
|
/* note: nq not freed here (table holds ref to it), freed in test cleanup if needed */
|
|
}
|
|
|
|
clock_t end = clock();
|
|
double time = (double)(end - start) / CLOCKS_PER_SEC;
|
|
|
|
ASSERT(t->count >= 1000, "all nodes inserted");
|
|
printf("(%.3fs for 1000 nodes) ", time);
|
|
|
|
route_table_destroy(t);
|
|
PASS();
|
|
}
|
|
|
|
static void test_destroy_refcount(void) {
|
|
TEST("destroy with multiple paths (ref_count safety)");
|
|
struct ROUTE_TABLE *t = route_table_create(0);
|
|
/* TOPO_GROUP_NODE memory managed externally, table only holds pointers */
|
|
route_table_destroy(t);
|
|
PASS();
|
|
}
|
|
|
|
|
|
/* ====================== MAIN ====================== */
|
|
int main(void) {
|
|
debug_config_init();
|
|
debug_set_level(DEBUG_LEVEL_INFO);
|
|
debug_set_categories(DEBUG_CATEGORY_ROUTING);
|
|
|
|
test_table_create_destroy();
|
|
test_nodeinfo_insert();
|
|
test_versioning();
|
|
test_performance_1000_nodes();
|
|
test_destroy_refcount();
|
|
|
|
printf("\n=== ROUTING TEST SUMMARY ===\n"
|
|
"run=%d passed=%d failed=%d\n\n",
|
|
stats.run, stats.passed, stats.failed);
|
|
|
|
return stats.failed ? 1 : 0;
|
|
}
|