From 56d513ed851894094bd87be46f0264aa6284347a Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 15:52:39 +0200 Subject: [PATCH] Inject topology pool database registry and radio timer failures --- tests/Makefile.am | 3 +- tests/test_topo_node_wire.c | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index a4cbffcc..04d49c84 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -732,7 +732,8 @@ test_node_snapshot_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) test_topo_node_wire_SOURCES = test_topo_node_wire.c test_topo_node_wire_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) if OS_LINUX -test_topo_node_wire_LDFLAGS = -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=memory_pool_alloc_impl +test_topo_node_wire_LDFLAGS = -Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=memory_pool_alloc_impl \ + -Wl,--wrap=memory_pool_init -Wl,--wrap=topo_node_sqlite_init -Wl,--wrap=queue_entry_new -Wl,--wrap=uasync_set_timeout endif test_ncd_config_SOURCES = test_ncd_config.c diff --git a/tests/test_topo_node_wire.c b/tests/test_topo_node_wire.c index f110e528..ef09180e 100644 --- a/tests/test_topo_node_wire.c +++ b/tests/test_topo_node_wire.c @@ -28,6 +28,33 @@ struct wire_fixture { static unsigned fail_at, attempts, inside_pool; static int track_allocations; static int lifecycle_faults; +static const char* fail_pool_name; +static int fail_schema, fail_registry_entry; +static const char* fail_timer_name; + +struct memory_pool* __real_memory_pool_init(size_t, const char*); +struct memory_pool* __wrap_memory_pool_init(size_t size, const char* name) { + if (fail_pool_name && !strcmp(fail_pool_name, name)) return NULL; + return __real_memory_pool_init(size, name); +} + +int __real_topo_node_sqlite_init(sqlite3*); +int __wrap_topo_node_sqlite_init(sqlite3* db) { + if (fail_schema) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "[fault] reject topology schema initialization"); return -1; } + return __real_topo_node_sqlite_init(db); +} + +struct ll_entry* __real_queue_entry_new(size_t); +struct ll_entry* __wrap_queue_entry_new(size_t size) { + if (fail_registry_entry && size == 8 + sizeof(void*)) { fail_registry_entry = 0; return NULL; } + return __real_queue_entry_new(size); +} + +void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*); +void* __wrap_uasync_set_timeout(struct UASYNC* ua, int delay, void* arg, timeout_callback_t cb, const char* name) { + if (fail_timer_name && !strcmp(fail_timer_name, name)) return NULL; + return __real_uasync_set_timeout(ua, delay, arg, cb, name); +} static int allocation_fails(const char *where) { if (!track_allocations || (!strstr(where, "topo_node.c:") && !strstr(where, "topo_node_sqlite.c:") && @@ -371,6 +398,9 @@ static void test_local_allocation_failures(struct wire_fixture *f) { assert(node->group_ref_count == before_refs && f->inst.rt->count == routes && live_allocations() == before); } lifecycle_faults = 0; fail_at = 0; + fail_timer_name = "radio_talker"; + assert(!topo_groups_create_group(&f->groups, 43, TOPO_GROUP_TYPE_UTUN, NULL)); + fail_timer_name = NULL; uasync_poll(f->inst.ua, 0); queue_free(f->groups.group_list); f->groups.group_list = NULL; DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] group creation: %u allocation failures roll back all resources; radio retry preserved", creation_allocations); @@ -381,6 +411,41 @@ static void test_local_allocation_failures(struct wire_fixture *f) { 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); } + +/* Контейнер не может возвращать успех с отсутствующим пулом, БД или локальной записью. */ +static void test_registry_initialization(struct wire_fixture* f) { + struct utun_config config = {0}; + struct UTUN_INSTANCE inst = {.config = &config, .node_id = f->inst.node_id}; + inst.my_keys = f->inst.my_keys; + memcpy(inst.my_ed25519_pubkey, f->inst.my_ed25519_pubkey, 32); + memcpy(inst.my_ed25519_privkey, f->inst.my_ed25519_privkey, 32); + inst.ua = uasync_create(); assert(inst.ua); + const char* pools[] = {"to_v4sock", "to_v4addr", "to_v6sock", "to_v6addr", "to_v4sub", "to_v6sub"}; + for (size_t i = 0; i < sizeof(pools) / sizeof(pools[0]); i++) { + size_t before = live_allocations(); + fail_pool_name = pools[i]; + assert(!topo_groups_init(&inst) && !inst.topo_groups && !inst.topo_sqlite_db); + fail_pool_name = NULL; + assert(live_allocations() == before); + } + size_t before = live_allocations(); + snprintf(config.global.db_path, sizeof(config.global.db_path), "/dev/null"); + assert(!topo_groups_init(&inst) && !inst.topo_groups && !inst.topo_sqlite_db); + assert(live_allocations() == before); config.global.db_path[0] = '\0'; + fail_schema = 1; + assert(!topo_groups_init(&inst) && !inst.topo_groups && !inst.topo_sqlite_db); + fail_schema = 0; assert(live_allocations() == before); + fail_registry_entry = 1; + assert(!topo_groups_init(&inst) && !fail_registry_entry && !inst.topo_groups && !inst.topo_sqlite_db); + assert(live_allocations() == before); + struct TOPO_GROUPS* registry = topo_groups_init(&inst); assert(registry); + sqlite3* db = inst.topo_sqlite_db; + assert(!topo_groups_init(&inst) && inst.topo_groups == registry && inst.topo_sqlite_db == db); + topo_groups_destroy(&inst); sqlite3_close(db); inst.topo_sqlite_db = NULL; + assert(live_allocations() == before); + uasync_poll(inst.ua, 0); uasync_destroy(inst.ua, 0); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] topology init: six pools, SQLite open/schema, registry OOM and duplicate initialization"); +} #endif int main(void) { @@ -396,6 +461,7 @@ int main(void) { test_allocation_failures(&fixture); test_bootstrap_allocation_failures(&fixture); test_local_allocation_failures(&fixture); + test_registry_initialization(&fixture); #endif fixture_destroy(&fixture); assert(u_get_allocated_count() == before);