diff --git a/tests/test_topo_node_wire.c b/tests/test_topo_node_wire.c index ba0707a0..e49f9e08 100644 --- a/tests/test_topo_node_wire.c +++ b/tests/test_topo_node_wire.c @@ -5,10 +5,13 @@ #include "utun_instance.h" #include "routing_layer/topo_group.h" #include "routing_layer/topo_node_sqlite.h" +#include "routing_layer/route_lib.h" +#include "config_parser.h" #include "transport_layer/etcp.h" #include "../lib/debug_config.h" #include "../lib/mem.h" #include "../lib/memory_pool.h" +#include "../lib/u_async.h" struct wire_fixture { struct UTUN_INSTANCE inst; @@ -296,6 +299,50 @@ static void test_bootstrap_allocation_failures(struct wire_fixture *f) { topo_node_destroy(&f->groups, node); sqlite3_close(db); DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] SQL bootstrap: %u allocation failures and SQL failure leave no live objects/statements", total); } + +/* Уже опубликованный local_node и его маршруты переживают любой отказ подготовки новой группы. */ +static void test_local_allocation_failures(struct wire_fixture *f) { + struct CFG_ROUTE_ENTRY v6 = {.ip.family = AF_INET6, .netmask = 64}; + memcpy(&v6.ip.addr.v6, (uint8_t[]){0x20, 1, 0xdb, 8}, 4); + struct CFG_ROUTE_ENTRY v4 = {.next = &v6, .ip.family = AF_INET, .netmask = 24}; + v4.ip.addr.v4.s_addr = htonl(0x0a010000); + struct utun_config config = {.my_subnets = &v4}; f->inst.config = &config; + f->inst.ua = uasync_create(); assert(f->inst.ua); + f->groups.node_registry = queue_new(f->inst.ua, 16, 0, 8, "local_wire_test"); assert(f->groups.node_registry); + assert(sc_generate_keypair(&f->inst.my_keys) == SC_OK); + memcpy(f->inst.my_ed25519_privkey, f->inst.my_keys.private_key, 32); + sc_derive_ed25519_pubkey(f->inst.my_keys.private_key, f->inst.my_ed25519_pubkey); + f->inst.node_id = sc_derive_node_id_from_pubkey(f->inst.my_keys.public_key); + f->inst.rt = route_table_create(f->inst.node_id); assert(f->inst.rt); + assert(!topo_node_init_self(&f->inst)); + f->group.group_type = TOPO_GROUP_TYPE_UTUN; + assert(topo_group_update_my_nodeinfo(&f->inst, &f->group) == 1); + v4.ip.addr.v4.s_addr = htonl(0x0a020000); + attempts = 0; fail_at = 0; track_allocations = 1; + int rc = topo_group_update_my_nodeinfo(&f->inst, &f->group); + track_allocations = 0; + assert(rc == 1 && attempts >= 4); unsigned total = attempts; + struct TOPO_GROUP_NODE* old = f->group.local_node; + struct TOPO_NODE* node = topo_node_registry_find(&f->groups, f->inst.node_id); + uint64_t timestamp = node->timestamp; uint32_t refs = node->group_ref_count; + v4.ip.addr.v4.s_addr = htonl(0x0a030000); + for (unsigned nth = 1; nth <= total; nth++) { + size_t before = live_allocations(); + attempts = 0; fail_at = nth; track_allocations = 1; + rc = topo_group_update_my_nodeinfo(&f->inst, &f->group); + track_allocations = 0; + assert(rc < 0 && attempts == nth && f->group.local_node == old && live_allocations() == before); + assert(node->timestamp == timestamp && node->group_ref_count == refs && !topo_node_verify(node)); + assert(route_lookup(f->inst.rt, 0x0a020001)->v_node_info == old && !route_lookup(f->inst.rt, 0x0a030001)); + } + fail_at = 0; + topo_nodeq_free_group_fields(&f->groups, old); u_free(old); f->group.local_node = NULL; + topo_node_registry_unref(&f->groups, f->inst.node_id); + assert(!f->groups.node_registry->head); queue_free(f->groups.node_registry); f->groups.node_registry = NULL; + route_table_destroy(f->inst.rt); f->inst.rt = NULL; + uasync_destroy(f->inst.ua, 0); f->inst.ua = NULL; f->inst.config = NULL; + DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] local group: %u allocation failures preserve identity, routes and ownership", total); +} #endif int main(void) { @@ -310,6 +357,7 @@ int main(void) { #ifdef __linux__ test_allocation_failures(&fixture); test_bootstrap_allocation_failures(&fixture); + test_local_allocation_failures(&fixture); #endif fixture_destroy(&fixture); assert(u_get_allocated_count() == before);