From 74b63cc31520156f28938318b473263abd18b97c Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 00:01:02 +0200 Subject: [PATCH] Verify ETCP registry identity and failure ownership invariants --- tests/test_etcp_lifecycle.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_etcp_lifecycle.c b/tests/test_etcp_lifecycle.c index 52887dbc..b33ea3f0 100644 --- a/tests/test_etcp_lifecycle.c +++ b/tests/test_etcp_lifecycle.c @@ -307,6 +307,33 @@ static void neighbor_close_case(struct UTUN_INSTANCE *inst) { puts("PASS nested close: current and neighbor links, no cached next pointer"); } +static void registry_index_cases(struct UTUN_INSTANCE *inst) { + struct ETCP_CONN *first = etcp_connection_create(inst, "first indexed"); CHECK(first); + struct ETCP_CONN *second = etcp_connection_create(inst, "second indexed"); CHECK(second); + struct ll_entry *entry = first->conn_queue_entry, *other = second->conn_queue_entry; + first->peer_node_id = second->peer_node_id = 1; + size_t allocated = u_get_allocated_count(); + CHECK(etcp_conn_index_peer(first) == 0 && first->conn_queue_entry == entry); + CHECK(first->state == 0 && instance_find_conn(inst, 1) == first && inst->connections->count == 2); + CHECK(etcp_conn_index_peer(first) == 0 && u_get_allocated_count() == allocated); + CHECK(etcp_conn_index_peer(second) < 0 && second->conn_queue_entry == other); + CHECK(((struct conn_queue_entry*)other->data)->peer_node_id == 0 && instance_find_conn(inst, 1) == first); + etcp_conn_queue_set_ready(first); etcp_conn_queue_set_ready(first); + CHECK(first->state == 1 && first->conn_queue_entry == entry && u_get_allocated_count() == allocated); + second->peer_node_id = 2; + CHECK(etcp_conn_index_peer(second) == 0 && second->conn_queue_entry == other && instance_find_conn(inst, 2) == second); + /* Отказ put освобождает entry: close не должен повторно трогать эту память. */ + queue_set_size_limit(inst->connections, 1); + second->peer_node_id = 3; + CHECK(etcp_conn_index_peer(second) < 0 && !second->conn_queue_entry && inst->connections->count == 1); + CHECK(!instance_find_conn(inst, 2) && !instance_find_conn(inst, 3) && instance_find_conn(inst, 1) == first); + queue_set_size_limit(inst->connections, -1); + etcp_connection_close(second); etcp_connection_close(first); + uasync_drain_immediate(inst->ua); uasync_poll(inst->ua, 0); + CHECK(!inst->connections->count); + puts("PASS peer registry: stable entry, idempotent ready, duplicate rejection, failed put cleanup"); +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); const char* log = getenv("LIFECYCLE_TEST_LOG"); @@ -340,6 +367,7 @@ int main(void) { } ncd_cases(&inst); ncd_late_up_case(&inst); recovery_cases(&inst); neighbor_close_case(&inst); constructor_close_cases(&inst); link_constructor_close_cases(&inst); subscription_cases(&inst); + registry_index_cases(&inst); queue_free(inst.connections); uasync_poll(inst.ua,0); CHECK(inst.ua->timer_alloc_count == inst.ua->timer_free_count); uasync_destroy(inst.ua,0); CHECK(u_get_allocated_count() == baseline);