test: identify custody replies and force storage-mediated file delivery

This commit is contained in:
evgeny committed 2026-11-03 22:40:37 +01:00
1 parent 13d838988e
commit b1bfb94f1f
2 files changed
+25 -15

No files matched your search

+4 -1
View File
@@ -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));
+21 -14
View File
@@ -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);