Exercise offline and live edits over real Merkle and PUSH transport
This commit is contained in:
1 parent
ec8c6e9eb1
commit
d998b390f3
1 file changed
+42
@@ -64,6 +64,7 @@ static char temp_dir[] = "/tmp/utun_dbsync_XXXXXX";
|
||||
static char config_a[256], config_b[256], config_c[256];
|
||||
static uint32_t ca_target, cb_target, cc_target;
|
||||
static uint64_t delivery_timestamp;
|
||||
static uint64_t expected_revision;
|
||||
static int history_ready(struct DB_SYNC_INSTANCE* si);
|
||||
|
||||
/* Оба сообщения одного автора в одной ms получают отдельные реальные ACK. */
|
||||
@@ -259,6 +260,18 @@ static int same_roots(struct DB_SYNC_INSTANCE* a, struct DB_SYNC_INSTANCE* b, st
|
||||
return !c || (!db_sync_read_root(c, rc) && !memcmp(ra, rc, 32));
|
||||
}
|
||||
|
||||
static int cond_revision(void) {
|
||||
struct UTUN_INSTANCE* nodes[] = {inst_a, inst_b};
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
sqlite3_stmt* st = NULL;
|
||||
int rc = sqlite3_prepare_v2(nodes[i]->topo_sqlite_db, "SELECT max(ver) FROM push_t", -1, &st, NULL);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_step(st);
|
||||
int matches = rc == SQLITE_ROW && (uint64_t)sqlite3_column_int64(st, 0) == expected_revision;
|
||||
sqlite3_finalize(st); if (!matches) return 0;
|
||||
}
|
||||
return same_roots(si_a, si_b, NULL);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("=== test_db_sync ===\n");
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
@@ -417,6 +430,35 @@ int main(void) {
|
||||
!wait_for("two distinct delivery ACKs", cond_delivery, PHASE_TIMEOUT_TB)) { test_phase = 2; goto done; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS two same-timestamp PUSH records acknowledged separately");
|
||||
|
||||
/* Отключённый пир пропускает две правки: Merkle принимает сразу v3 при том же количестве строк. */
|
||||
{
|
||||
sqlite3_stmt* st = NULL; uint64_t ts; struct db_message_revision revision = {.ver = 1}; uint8_t signature[64];
|
||||
if (sqlite3_prepare_v2(inst_a->topo_sqlite_db, "SELECT timestamp,nonce FROM push_t ORDER BY timestamp LIMIT 1", -1, &st, NULL) != SQLITE_OK ||
|
||||
sqlite3_step(st) != SQLITE_ROW || sqlite3_column_bytes(st, 1) != 16) {
|
||||
sqlite3_finalize(st); test_phase = 2; goto done;
|
||||
}
|
||||
ts = (uint64_t)sqlite3_column_int64(st, 0); memcpy(revision.nonce, sqlite3_column_blob(st, 1), 16); sqlite3_finalize(st);
|
||||
db_sync_peer_set_paused(si_a, inst_b->node_id, 1); db_sync_peer_set_paused(si_b, inst_a->node_id, 1);
|
||||
for (uint64_t ver = 2; ver <= 3; ver++) {
|
||||
const char* text = ver == 2 ? "{\"ct\":\"text/plain\",\"d\":\"edit 2\"}" : "{\"ct\":\"text/plain\",\"d\":\"edit 3\"}";
|
||||
revision.ver = ver; revision.edited_at = db_sync_next_timestamp(si_a);
|
||||
if (db_sync_sign_message(40, ts, inst_a->node_id, &revision, text, strlen(text), inst_a->my_ed25519_privkey, signature) < 0 ||
|
||||
db_sync_insert_signed(si_a, text, strlen(text), signature, 64, ts, NULL, &revision) != 0) {
|
||||
test_phase = 2; goto done;
|
||||
}
|
||||
}
|
||||
expected_revision = 3; reset_done_flags();
|
||||
db_sync_reinitiate(si_a, inst_b->node_id); db_sync_reinitiate(si_b, inst_a->node_id);
|
||||
if (!wait_for("offline edits converge by Merkle", cond_revision, PHASE_TIMEOUT_TB) ||
|
||||
db_sync_count(si_a) != 6 || db_sync_count(si_b) != 6) { test_phase = 2; goto done; }
|
||||
const char* text = "{\"ct\":\"text/plain\",\"d\":\"live edit 4\"}";
|
||||
revision.ver = 4; revision.edited_at = db_sync_next_timestamp(si_a); expected_revision = 4;
|
||||
if (db_sync_sign_message(40, ts, inst_a->node_id, &revision, text, strlen(text), inst_a->my_ed25519_privkey, signature) < 0 ||
|
||||
db_sync_insert_signed(si_a, text, strlen(text), signature, 64, ts, NULL, &revision) != 0 ||
|
||||
!wait_for("live edit over PUSH", cond_revision, PHASE_TIMEOUT_TB)) { test_phase = 2; goto done; }
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS offline v1->v3 and live v4 converge with stable IDs and unchanged record count");
|
||||
}
|
||||
|
||||
/* Одинаковые count, отличие в первой записи длинной истории и разные локальные id. */
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "Phase 5d: long history with equal counts and divergent first record");
|
||||
remove_si(&si_a); remove_si(&si_b);
|
||||
|
||||
Reference in new issue
Block a user