From 6bbd41f49feb011a3ee854d5e0f7022039ed55bd Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 27 Oct 2026 03:12:11 +0100 Subject: [PATCH] Exercise attachment recovery against uncommitted history deletion --- tests/test_chat_attachment.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_chat_attachment.c b/tests/test_chat_attachment.c index 016f34d0..c8b1b04d 100644 --- a/tests/test_chat_attachment.c +++ b/tests/test_chat_attachment.c @@ -770,6 +770,21 @@ static struct local_snapshot derived_snapshot(const struct local_snapshot* owner return result; } +/* Shutdown после SQL-отказа не должен принимать незавершённое удаление истории за отсутствие публикации. */ +static void test_recovery_transaction(void) { + struct fixture f; setup(&f); source(&f); publish(&f); + struct local_snapshot owner = local_read(&f); char query[160]; + assert(ma_file_size(owner.cipher) > 0 && ma_file_size(owner.plain) == sizeof(content) - 1); + snprintf(query, sizeof(query), "BEGIN IMMEDIATE; DELETE FROM msg_%s", f.channel); sql(f.inst->topo_sqlite_db, query); + chat_attachment_destroy(f.inst); + assert(!sqlite3_get_autocommit(f.inst->topo_sqlite_db)); local_equal(&f, &owner); + assert(ma_file_size(owner.cipher) > 0 && ma_file_size(owner.plain) == sizeof(content) - 1); + sql(f.inst->topo_sqlite_db, "ROLLBACK"); + chat_service_stop(f.inst); assert(!chat_service_start(f.inst)); local_equal(&f, &owner); + assert(ma_file_size(owner.cipher) > 0 && ma_file_size(owner.plain) == sizeof(content) - 1); cleanup(&f); + DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS recovery: uncommitted history deletion at shutdown preserves published files and foreign transaction; rollback/restart restores exact record"); +} + static void erase_index(struct fixture* f) { char query[160]; snprintf(query, sizeof(query), "DELETE FROM attachment_keys WHERE channel='%s'", f->channel); sql(f->inst->topo_sqlite_db, query); } @@ -1026,6 +1041,7 @@ int main(void) { test_worker_error_completion(); test_completion_limit(); test_channel_delete_rollback(); test_attachment_binding(); test_attachment_identity(); + test_recovery_transaction(); test_observation(); test_local_flags(); test_index_recovery(); test_backfill_capacity(); test_long_manual_manifest();