Inject topology pool database registry and radio timer failures

This commit is contained in:
evgeny committed 2026-10-24 15:52:39 +02:00
1 parent d1562bdd0e
commit 56d513ed85
2 files changed
+68 -1

No files matched your search

+2 -1
View File
@@ -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
+66
View File
@@ -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);