Tighten result regression snapshots and expose SQL transition diagnostics
This commit is contained in:
1 parent
935bd704ae
commit
03d1afbd13
2 files changed
+27
-11
No files matched your search
@@ -426,6 +426,8 @@ static int ak_apply_result(struct UTUN_INSTANCE* inst, const char* channel, uint
|
||||
int incoming = sqlite3_column_int(st, 0), state = sqlite3_column_int(st, 1), queued = sqlite3_column_int(st, 2);
|
||||
stage = "read finalize"; rc = sqlite3_finalize(st); st = NULL;
|
||||
if (rc != SQLITE_OK) goto fail;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "attachment keys: result before transaction writes channel=%s peer=%llu command=%u incoming=%d state=%d queued=%d",
|
||||
channel, (unsigned long long)peer, cmd, incoming, state, queued);
|
||||
if ((incoming != 0 && incoming != 1) || state < 0 || state > 4 ||
|
||||
(cmd == AK_RESULT_ACK ? !incoming || (state != 2 && state != 3 && state != 4) : incoming || state > 3) ||
|
||||
((cmd == AK_GRANT || cmd == AK_DENY) && ((state == 2 && cmd != AK_GRANT) || (state == 3 && cmd != AK_DENY)))) {
|
||||
@@ -454,7 +456,10 @@ static int ak_apply_result(struct UTUN_INSTANCE* inst, const char* channel, uint
|
||||
changed = sqlite3_changes(db);
|
||||
stage = "key finalize"; rc = sqlite3_finalize(st); st = NULL;
|
||||
if (rc != SQLITE_OK) goto fail;
|
||||
if (changed != 1) { stage = "key row count"; rc = SQLITE_CONSTRAINT; goto fail; }
|
||||
if (changed != 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: result key rows=%d expected=1 channel=%s", changed, channel);
|
||||
stage = "key row count"; rc = SQLITE_CONSTRAINT; goto fail;
|
||||
}
|
||||
}
|
||||
int next = cmd == AK_REQUEST_ACK ? (state == 0 ? 1 : state) : cmd == AK_RESULT_ACK ? (state == 3 ? 3 : 4) : cmd == AK_GRANT ? 2 : 3;
|
||||
stage = "state prepare";
|
||||
@@ -473,7 +478,10 @@ static int ak_apply_result(struct UTUN_INSTANCE* inst, const char* channel, uint
|
||||
changed = sqlite3_changes(db);
|
||||
stage = "state finalize"; rc = sqlite3_finalize(st); st = NULL;
|
||||
if (rc != SQLITE_OK) goto fail;
|
||||
if (changed != 1) { stage = "state row count"; rc = SQLITE_CONSTRAINT; goto fail; }
|
||||
if (changed != 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: result state rows=%d expected=1 channel=%s", changed, channel);
|
||||
stage = "state row count"; rc = SQLITE_CONSTRAINT; goto fail;
|
||||
}
|
||||
int command = cmd == AK_RESULT_ACK ? (state == 3 ? AK_DENY : AK_GRANT) : AK_REQUEST;
|
||||
stage = "outbox prepare";
|
||||
rc = sqlite3_prepare_v2(db, "DELETE FROM attachment_key_outbox WHERE channel=? AND message_id=? AND peer=? AND command=?", -1, &st, NULL);
|
||||
@@ -492,7 +500,11 @@ static int ak_apply_result(struct UTUN_INSTANCE* inst, const char* channel, uint
|
||||
stage = "outbox finalize"; rc = sqlite3_finalize(st); st = NULL;
|
||||
if (rc != SQLITE_OK) goto fail;
|
||||
/* REQUEST_ACK мог удалить REQUEST раньше GRANT; дубликат результата также не требует строки outbox. */
|
||||
if (changed != (queued == command)) { stage = "outbox row count"; rc = SQLITE_CONSTRAINT; goto fail; }
|
||||
if (changed != (queued == command)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "attachment keys: result outbox rows=%d expected=%d channel=%s command=%d",
|
||||
changed, queued == command, channel, command);
|
||||
stage = "outbox row count"; rc = SQLITE_CONSTRAINT; goto fail;
|
||||
}
|
||||
stage = "commit"; rc = sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
|
||||
if (rc != SQLITE_OK) goto fail;
|
||||
*next_out = next;
|
||||
|
||||
@@ -41,10 +41,10 @@ static struct fixture* active;
|
||||
|
||||
static enum operation operation(const char* sql) {
|
||||
if (!sql) return NO_OPERATION;
|
||||
if (!strncmp(sql, "SELECT r.incoming,r.state,o.command", 34)) return READ;
|
||||
if (!strncmp(sql, "UPDATE attachment_keys SET key=?,error=0 WHERE", 45)) return KEY;
|
||||
if (!strncmp(sql, "UPDATE attachment_key_requests SET state=? WHERE", 47)) return STATE;
|
||||
if (!strncmp(sql, "DELETE FROM attachment_key_outbox WHERE", 38)) return OUTBOX;
|
||||
static const char* prefixes[] = {NULL, "SELECT r.incoming,r.state,o.command", "UPDATE attachment_keys SET key=?,error=0 WHERE",
|
||||
"UPDATE attachment_key_requests SET state=? WHERE", "DELETE FROM attachment_key_outbox WHERE"};
|
||||
for (enum operation op = READ; op <= OUTBOX; op++)
|
||||
if (!strncmp(sql, prefixes[op], strlen(prefixes[op]))) return op;
|
||||
return NO_OPERATION;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ static int take(enum failure point, enum operation op, int index) {
|
||||
|
||||
extern int __real_sqlite3_exec(sqlite3*, const char*, int (*)(void*, int, char**, char**), void*, char**);
|
||||
int __wrap_sqlite3_exec(sqlite3* db, const char* sql, int (*cb)(void*, int, char**, char**), void* arg, char** error) {
|
||||
if (active && db == active->inst->topo_sqlite_db) {
|
||||
if (active && active->inst && db == active->inst->topo_sqlite_db) {
|
||||
if (!strcmp(sql, "BEGIN IMMEDIATE") && take(BEGIN, NO_OPERATION, 0)) return SQLITE_BUSY;
|
||||
if (!strcmp(sql, "COMMIT") && take(COMMIT, NO_OPERATION, 0)) return SQLITE_BUSY;
|
||||
if (!strcmp(sql, "ROLLBACK") && fail_rollback) {
|
||||
@@ -147,7 +147,10 @@ static struct snapshot snapshot(struct fixture* f) {
|
||||
|
||||
/* Reader проверяет обе целевые строки и не затронутую соседнюю запись без чтения секретов в лог. */
|
||||
static void equal(struct fixture* f, struct snapshot expected) {
|
||||
struct snapshot current = snapshot(f); assert(!memcmp(¤t, &expected, sizeof(current)));
|
||||
struct snapshot current = snapshot(f);
|
||||
assert(current.key_bytes == expected.key_bytes && current.error == expected.error && current.incoming == expected.incoming);
|
||||
assert(current.state == expected.state && current.queued == expected.queued);
|
||||
assert(!current.key_bytes || !memcmp(current.key, expected.key, 32));
|
||||
sqlite3_stmt* st = NULL;
|
||||
assert(sqlite3_prepare_v2(f->reader, "SELECT key,error FROM attachment_keys WHERE channel='900'", -1, &st, NULL) == SQLITE_OK);
|
||||
assert(sqlite3_step(st) == SQLITE_ROW && sqlite3_column_bytes(st, 0) == 32 && sqlite3_column_int(st, 1) == 7);
|
||||
@@ -213,9 +216,10 @@ static void reset(struct fixture* f, int command) {
|
||||
f->room = 1; memset(f->key, 0, sizeof(f->key)); f->key[0] = 55;
|
||||
int author = command == RESULT_ACK, state = author ? 2 : command == REQUEST_ACK ? 0 : 1;
|
||||
sqlite3_stmt* st = NULL;
|
||||
assert(sqlite3_prepare_v2(f->inst->topo_sqlite_db, "UPDATE attachment_keys SET key=?,error=1 WHERE channel=?", -1, &st, NULL) == SQLITE_OK);
|
||||
assert(sqlite3_prepare_v2(f->inst->topo_sqlite_db, "UPDATE attachment_keys SET key=?,error=1,author=? WHERE channel=?", -1, &st, NULL) == SQLITE_OK);
|
||||
assert((author ? sqlite3_bind_blob(st, 1, f->key, 32, SQLITE_STATIC) : sqlite3_bind_null(st, 1)) == SQLITE_OK);
|
||||
assert(sqlite3_bind_text(st, 2, f->channel, -1, SQLITE_STATIC) == SQLITE_OK && sqlite3_step(st) == SQLITE_DONE);
|
||||
assert(sqlite3_bind_int64(st, 2, (sqlite3_int64)(author ? f->inst->node_id : 123)) == SQLITE_OK);
|
||||
assert(sqlite3_bind_text(st, 3, f->channel, -1, SQLITE_STATIC) == SQLITE_OK && sqlite3_step(st) == SQLITE_DONE);
|
||||
assert(sqlite3_finalize(st) == SQLITE_OK);
|
||||
char query[512];
|
||||
snprintf(query, sizeof(query), "UPDATE attachment_key_requests SET incoming=%d,state=%d WHERE channel='%s';"
|
||||
|
||||
Reference in new issue
Block a user