From 739ee0802fc71285abb2abfef82cde10f38d81f8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 27 Oct 2026 03:49:38 +0100 Subject: [PATCH] Verify poll commit acknowledgments survive snapshot faults and reserve memory before changes --- tests/Makefile.am | 2 +- tests/test_chat_poll.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 4392021a..4bb2970d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1321,7 +1321,7 @@ test_chat_poll_SOURCES = test_chat_poll.c test_chat_poll_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/chat -I$(top_srcdir)/lib test_chat_poll_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) test_chat_poll_LDFLAGS = -Wl,--wrap=sqlite3_prepare_v2 -Wl,--wrap=sqlite3_bind_blob -Wl,--wrap=sqlite3_bind_text \ - -Wl,--wrap=sqlite3_step -Wl,--wrap=sqlite3_finalize + -Wl,--wrap=sqlite3_step -Wl,--wrap=sqlite3_finalize -Wl,--wrap=u_malloc_impl test_chat_poll_network_SOURCES = test_chat_poll_network.c test_chat_poll_network_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/chat -I$(top_srcdir)/lib diff --git a/tests/test_chat_poll.c b/tests/test_chat_poll.c index 9c647e60..d77955de 100644 --- a/tests/test_chat_poll.c +++ b/tests/test_chat_poll.c @@ -11,6 +11,15 @@ static enum poll_fault fault; static enum poll_query query; static unsigned query_number, matching_queries, fault_bind, changed_events; static sqlite3_stmt* fault_statement; +static int fail_ack_allocation; + +extern void* __real_u_malloc_impl(uint32_t, const char*); +void* __wrap_u_malloc_impl(uint32_t size, const char* location) { + if (fail_ack_allocation && strstr(location, "chat_poll.c")) { + fail_ack_allocation = 0; DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "poll test: committed ack allocation failed bytes=%u", size); return NULL; + } + return __real_u_malloc_impl(size, location); +} static int query_matches(const char* sql) { const char* prefix[] = {"SELECT json_valid(?1)", "SELECT json_type(?1,?2),json_extract(?1,?2)", @@ -134,8 +143,29 @@ static void sql_faults(struct UTUN_INSTANCE* inst, const char* channel, const ch char* result = command(inst, react, -1); u_free(result); assert(chat_feedback_get(inst, channel, message, inst->node_id, CHAT_FEEDBACK_REACTION, &actual) == 1 && actual.ver == saved.ver); assert(actual.data_len == saved.data_len && !memcmp(actual.data, saved.data, saved.data_len)); + /* Snapshot после commit может отказать: ответ остаётся успехом, повторяем только чтение. */ + snprintf(react, sizeof(react), "{\"cmd\":\"react\",\"ch\":\"%s\",\"message_id\":\"%s\",\"emoji\":0}", channel, hex); + for (unsigned publish = 0; publish < 2; publish++) { + const char* request = publish ? create : react; + for (enum poll_fault point = P_PREPARE; point <= P_FINALIZE; point++) { + int messages = message_count(inst, channel); + query = P_SNAPSHOT; query_number = 1; matching_queries = 0; fault_statement = NULL; fault_bind = 1; fault = point; + result = command(inst, request, 0); assert(fault == P_NONE && !fault_statement); + assert(json_number(inst->topo_sqlite_db, result, "$.committed") == 1 && + json_number(inst->topo_sqlite_db, result, "$.snapshot_pending") == 1); + char acknowledged[65], read[256]; json_string(inst->topo_sqlite_db, result, "$.message_id", acknowledged, sizeof(acknowledged)); + u_free(result); + assert(message_count(inst, channel) == messages + (int)publish); + snprintf(read, sizeof(read), "{\"cmd\":\"feedback\",\"ch\":\"%s\",\"message_id\":\"%s\"}", channel, acknowledged); + result = command(inst, read, 0); u_free(result); + assert(message_count(inst, channel) == messages + (int)publish); + } + int messages = message_count(inst, channel); unsigned events = changed_events; + fail_ack_allocation = 1; result = command(inst, request, -1); u_free(result); + assert(!fail_ack_allocation && changed_events == events && message_count(inst, channel) == messages); + } chat_event_set_handler(inst, NULL); - printf("PASS: %u poll SQL faults preserve messages, reactions, Merkle root and events; retries succeed; emoji must be complete text\n", cases); + printf("PASS: %u poll SQL faults,8 post-commit read failures,2 pre-commit allocation failures; state/events preserved, read-only retry, complete emoji text\n", cases); } /* Проверяем границы, каноничность и невозможность интерпретации битого UTF-8. */