From b1bfb94f1f070ef5ed8f079e31ddda049b1b73f8 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 3 Nov 2026 22:40:37 +0100 Subject: [PATCH] test: identify custody replies and force storage-mediated file delivery --- tests/test_dm_group_routes.c | 5 ++++- tests/test_dm_media_cleanup.c | 35 +++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/tests/test_dm_group_routes.c b/tests/test_dm_group_routes.c index 20603d5c6..a877d1591 100644 --- a/tests/test_dm_group_routes.c +++ b/tests/test_dm_group_routes.c @@ -166,6 +166,8 @@ static int run(void) { REQUIRE(!member(A, 0, A, "admitted", 1)); /* Отдельная A/B-группа нужна только для начала беседы, затем прямого маршрута нет. */ REQUIRE(!member(A, 6, B, "admitted", 0) && !member(B, 6, A, "admitted", 0)); + /* Синхронизация подписанного состава не должна восстановить прямой путь в этом сценарии. */ + f.group[A][6]->stopping = f.group[B][6]->stopping = 1; topo_group_revalidate_members(f.group[A][6]); topo_group_revalidate_members(f.group[B][6]); REQUIRE(!dm_send(f.node[A], f.conv, "text", (const uint8_t*)"pairwise mailbox", 16)); uint8_t packet[2048] = {1}; @@ -214,7 +216,8 @@ static int file_delivery(void) { REQUIRE(sqlite3_finalize(st) == SQLITE_OK); REQUIRE(!dm_mailbox_store_file(f.node[A], f.node[B]->node_id, body, bytes)); uint64_t end = get_time_tb() + 250000; - while (value(B, "SELECT count(*) FROM dm_files WHERE ready=1") != 1 && get_time_tb() < end) uasync_poll(f.ua, 1); + while ((value(B, "SELECT count(*) FROM dm_files WHERE ready=1") != 1 || + value(M, "SELECT count(*) FROM dm_custody WHERE ready=1") != 1) && get_time_tb() < end) uasync_poll(f.ua, 1); REQUIRE(value(B, "SELECT count(*) FROM dm_files WHERE ready=1") == 1); REQUIRE(sqlite3_prepare_v2(f.node[B]->topo_sqlite_db, "SELECT local_path FROM dm_files WHERE ready=1", -1, &st, NULL) == SQLITE_OK); REQUIRE(sqlite3_step(st) == SQLITE_ROW); snprintf(path, sizeof(path), "%s", sqlite3_column_text(st, 0)); diff --git a/tests/test_dm_media_cleanup.c b/tests/test_dm_media_cleanup.c index dd88efba9..83ae7a053 100644 --- a/tests/test_dm_media_cleanup.c +++ b/tests/test_dm_media_cleanup.c @@ -21,7 +21,7 @@ static const uint8_t id[16] = {1}; static uint8_t receipt[DM_MEDIA_RECEIPT_SIZE]; static int inject(enum operation op, const char* sql) { - const char* prefixes[] = { "SELECT node_id FROM dm_media_holders", "UPDATE dm_media_holders SET released=1", + const char* prefixes[] = { "SELECT node_id,assignment_id FROM dm_media_holders", "UPDATE dm_media_holders SET released=1", "UPDATE dm_media_jobs SET body=NULL" }; if (fault != op || !sql || strncmp(sql, prefixes[target], strlen(prefixes[target]))) return 0; fault = NO_FAULT; hits++; @@ -55,9 +55,8 @@ int __wrap_sqlite3_finalize(sqlite3_stmt* st) { int __wrap_dm_media_send(struct UTUN_INSTANCE* inst, uint64_t group, uint64_t peer, uint8_t cmd, const uint8_t* body, size_t len) { (void)inst; (void)group; - assert(len == sizeof(receipt) && !memcmp(body, receipt, len)); - if (cmd == DM_MEDIA_RECEIPT) { assert(peer == 11); return -1; } - assert(cmd == DM_MEDIA_DELETE); + if (cmd == DM_MEDIA_RECEIPT) { assert(peer == 11 && len == sizeof(receipt) && !memcmp(body, receipt, len)); return -1; } + assert(cmd == DM_MEDIA_DELETE && len == 16 + sizeof(receipt) && body[0] == (uint8_t)peer && !memcmp(body + 16, receipt, sizeof(receipt))); deletes++; last_peer = peer; return 0; } int __wrap_dm_route_group(struct UTUN_INSTANCE* inst, uint64_t peer, uint64_t preferred, uint64_t* group) { @@ -75,18 +74,26 @@ static void fixture(sqlite3* db, int pending) { exec_sql(db, "DELETE FROM dm_media_holders; DELETE FROM dm_media_jobs; DELETE FROM dm_file_targets"); sqlite3_stmt* st = NULL; assert(sqlite3_prepare_v2(db, "INSERT INTO dm_media_jobs(id,author,recipient,seq,body,body_hash,holder,stored,receipt)" - " VALUES(?,11,12,1,x'01020304',zeroblob(32),102,1,?)", -1, &st, NULL) == SQLITE_OK); + " VALUES(?,11,12,1,x'01020304',zeroblob(32),101,1,?)", -1, &st, NULL) == SQLITE_OK); assert(sqlite3_bind_blob(st, 1, id, sizeof(id), SQLITE_STATIC) == SQLITE_OK); assert(sqlite3_bind_blob(st, 2, receipt, sizeof(receipt), SQLITE_STATIC) == SQLITE_OK); assert(sqlite3_step(st) == SQLITE_DONE && sqlite3_finalize(st) == SQLITE_OK); exec_sql(db, "INSERT INTO dm_file_targets SELECT id,12,1,receipt,NULL FROM dm_media_jobs"); - assert(sqlite3_prepare_v2(db, "INSERT INTO dm_media_holders(id,node_id,released) VALUES(?,101,?)", + assert(sqlite3_prepare_v2(db, "INSERT INTO dm_media_holders(id,node_id,assignment_id,released)" + " VALUES(?,101,x'65000000000000000000000000000000',?)", -1, &st, NULL) == SQLITE_OK); assert(sqlite3_bind_blob(st, 1, id, sizeof(id), SQLITE_STATIC) == SQLITE_OK); assert(sqlite3_bind_int(st, 2, !pending) == SQLITE_OK); assert(sqlite3_step(st) == SQLITE_DONE && sqlite3_finalize(st) == SQLITE_OK); } +/* Ответы привязаны к сохранённому назначению; номер группы не входит в его идентичность. */ +static void reply(struct dm_mb_media* media, uint64_t group, uint64_t peer, uint8_t cmd, const uint8_t* body, size_t len) { + uint8_t packet[41] = {0}; packet[0] = (uint8_t)peer; + assert(len + 16 <= sizeof(packet)); memcpy(packet + 16, body, len); + dm_mailbox_media_recv(media, group, peer, cmd, packet, len + 16); +} + static void check_receipt(sqlite3* db) { sqlite3_stmt* st = NULL; assert(sqlite3_prepare_v2(db, "SELECT receipt FROM dm_media_jobs", -1, &st, NULL) == SQLITE_OK); @@ -120,12 +127,12 @@ static void write_failures(struct UTUN_INSTANCE* inst, struct dm_mb_media* media if (target == BODY && op == BIND_INT) continue; fixture(inst->topo_sqlite_db, target == ACK); fault = op; hits = 0; - if (target == ACK) dm_mailbox_media_recv(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + if (target == ACK) reply(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); else test_clock_next_timer(inst->ua); assert(hits == 1); if (target == ACK) { assert(scalar(inst->topo_sqlite_db, "SELECT released FROM dm_media_holders") == (op == FINALIZE)); - dm_mailbox_media_recv(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + reply(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); } else { assert(scalar(inst->topo_sqlite_db, "SELECT body IS NULL FROM dm_media_jobs") == (op == FINALIZE)); } @@ -158,19 +165,19 @@ int main(void) { test_clock_next_timer(inst.ua); assert(deletes == sent + 1); assert(scalar(inst.topo_sqlite_db, "SELECT body IS NOT NULL FROM dm_media_jobs") == 1); check_receipt(inst.topo_sqlite_db); - dm_mailbox_media_recv(media, 77, 999, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + reply(media, 77, 999, DM_MEDIA_DELETE_ACK, id, sizeof(id)); assert(scalar(inst.topo_sqlite_db, "SELECT released FROM dm_media_holders") == 0); - exec_sql(inst.topo_sqlite_db, "INSERT INTO dm_media_holders SELECT id,102,0 FROM dm_media_jobs"); - dm_mailbox_media_recv(media, 78, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + exec_sql(inst.topo_sqlite_db, "INSERT INTO dm_media_holders SELECT id,102,x'66000000000000000000000000000000',0 FROM dm_media_jobs"); + reply(media, 78, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); assert(scalar(inst.topo_sqlite_db, "SELECT released FROM dm_media_holders WHERE node_id=101") == 1); - dm_mailbox_media_recv(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + reply(media, 77, 101, DM_MEDIA_DELETE_ACK, id, sizeof(id)); exec_sql(inst.topo_sqlite_db, "UPDATE dm_media_jobs SET retry_at=0"); test_clock_next_timer(inst.ua); assert(last_peer == 102 && scalar(inst.topo_sqlite_db, "SELECT body IS NOT NULL FROM dm_media_jobs") == 1); - dm_mailbox_media_recv(media, 77, 102, DM_MEDIA_DELETE_ACK, id, sizeof(id)); + reply(media, 77, 102, DM_MEDIA_DELETE_ACK, id, sizeof(id)); exec_sql(inst.topo_sqlite_db, "UPDATE dm_media_jobs SET retry_at=0"); test_clock_next_timer(inst.ua); assert(scalar(inst.topo_sqlite_db, "SELECT body IS NULL FROM dm_media_jobs") == 1); uint8_t stored[25] = {1}; - dm_mailbox_media_recv(media, 77, 101, DM_MEDIA_STORED, stored, sizeof(stored)); + reply(media, 77, 101, DM_MEDIA_STORED, stored, sizeof(stored)); assert(last_peer == 101 && scalar(inst.topo_sqlite_db, "SELECT count(*) FROM dm_media_holders WHERE released=0") == 0); check_receipt(inst.topo_sqlite_db); dm_mailbox_media_destroy(media); assert(sqlite3_close(inst.topo_sqlite_db) == SQLITE_OK);