You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
5.9 KiB
199 lines
5.9 KiB
/** |
|
* FULL REFACTORED TEST for new NODEINFO-based routing system |
|
* |
|
* Tests: |
|
* - NODEINFO_Q 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 "route_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 ROUTE_BGP* bgp; |
|
}; |
|
|
|
/* Helper to create test NODEINFO_Q with subnet in dynamic section */ |
|
static struct NODEINFO_Q* create_test_node(uint64_t node_id, uint8_t ver, uint32_t subnet_net, uint8_t prefix) { |
|
/* Allocate fixed + dynamic for 1 subnet (no name, no sockets) */ |
|
size_t dyn_size = sizeof(struct NODEINFO_IPV4_SUBNET); |
|
struct NODEINFO_Q* nq = u_calloc(1, sizeof(struct NODEINFO_Q) + dyn_size); |
|
if (!nq) return NULL; |
|
nq->node.node_id = htobe64(node_id); |
|
nq->node.ver = ver; |
|
nq->node.node_name_len = 0; |
|
nq->node.local_v4_sockets = 0; |
|
nq->node.local_v6_sockets = 0; |
|
nq->node.local_v4_subnets = 1; |
|
nq->node.local_v6_subnets = 0; |
|
nq->node.tranzit_nodes = 0; |
|
nq->node.hop_count = 0; |
|
nq->paths = queue_new(NULL, 16, "test_paths"); |
|
/* Fill subnet after fixed header (after name_len=0, sockets=0) */ |
|
uint8_t *dyn = (uint8_t *)&nq->node + sizeof(struct NODEINFO); |
|
struct NODEINFO_IPV4_SUBNET *sn = (struct NODEINFO_IPV4_SUBNET *)dyn; |
|
uint32_t net = htonl(subnet_net); |
|
memcpy(sn->addr, &net, 4); |
|
sn->prefix_length = prefix; |
|
return nq; |
|
} |
|
|
|
static void free_test_node(struct NODEINFO_Q* nq) { |
|
if (nq) { |
|
if (nq->paths) queue_free(nq->paths); |
|
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(); |
|
ASSERT_PTR(t, "create failed"); |
|
ASSERT_EQ(t->count, 0, "empty table"); |
|
route_table_destroy(t); |
|
PASS(); |
|
} |
|
|
|
static void test_nodeinfo_insert(void) { |
|
TEST("NODEINFO_Q insert into routing table"); |
|
struct ROUTE_TABLE *t = route_table_create(); |
|
struct NODEINFO_Q* 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(); |
|
struct NODEINFO_Q* nq1 = create_test_node(0x1111ULL, 5, 0x0a000000, 8); |
|
struct NODEINFO_Q* 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(); |
|
clock_t start = clock(); |
|
|
|
for (int i = 0; i < 1000; i++) { |
|
uint32_t sub = 0x0a000000 + (i * 0x01000000); /* different /8 to avoid overlap */ |
|
struct NODEINFO_Q* nq = create_test_node(0x1000000ULL + i, 1, sub, 8); |
|
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(); |
|
/* NODEINFO_Q 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; |
|
}
|
|
|