Cover feedback page and hash SQL errors without empty success
This commit is contained in:
1 parent
96a3d05c74
commit
d89a86c9dd
1 file changed
+35
-3
@@ -6,12 +6,17 @@ static const uint8_t owner_private[32] = {9};
|
||||
static int events;
|
||||
|
||||
enum sql_fault { F_NONE, F_BEGIN, F_PREPARE, F_BIND, F_STEP, F_CHANGES, F_FINALIZE, F_COMMIT };
|
||||
enum sql_operation { F_GET, F_PUT };
|
||||
enum sql_operation { F_GET, F_PUT, F_PAGE, F_HASH };
|
||||
static enum sql_fault injected;
|
||||
static enum sql_operation injected_operation;
|
||||
static int injected_bind, failed_rollback, last_put;
|
||||
|
||||
static int fault_statement(const char* sql) {
|
||||
if (injected_operation == F_PAGE || injected_operation == F_HASH) {
|
||||
const char* prefix = "SELECT message_id,node_id,kind,ver,data,signature,record_key,bucket FROM feedback_1001 WHERE bucket=?";
|
||||
return sql && !strncmp(sql, prefix, strlen(prefix)) &&
|
||||
((strstr(sql, " AND (?=0 OR record_key>?)") != NULL) == (injected_operation == F_PAGE));
|
||||
}
|
||||
const char* prefix = injected_operation == F_GET ? "SELECT message_id,node_id,kind,ver,data,signature FROM feedback_1001 " :
|
||||
"INSERT INTO feedback_1001(record_key,bucket,message_id,node_id,kind,ver,data,signature)";
|
||||
return sql && !strncmp(sql, prefix, strlen(prefix));
|
||||
@@ -58,7 +63,8 @@ int __wrap_sqlite3_bind_int(sqlite3_stmt* st, int index, int value) {
|
||||
}
|
||||
extern int __real_sqlite3_step(sqlite3_stmt*);
|
||||
int __wrap_sqlite3_step(sqlite3_stmt* st) {
|
||||
const char* sql = sqlite3_sql(st); last_put = !strncmp(sql, "INSERT INTO feedback_1001(", 26);
|
||||
const char* sql = sqlite3_sql(st); const char* put = "INSERT INTO feedback_1001(";
|
||||
last_put = !strncmp(sql, put, strlen(put));
|
||||
if (take_fault(F_STEP, sql, 0)) return SQLITE_IOERR;
|
||||
return __real_sqlite3_step(st);
|
||||
}
|
||||
@@ -324,6 +330,18 @@ static void fault_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* dat
|
||||
assert(!merkle_tree_get(feedback_reader->topo_sqlite_db, "1:1001", 0, 0, reader) && !memcmp(reader, writer, 32)); events++;
|
||||
}
|
||||
|
||||
/* Те же операции, которыми Merkle получает лист и пересчитывает его хеш. */
|
||||
static int feedback_read(struct UTUN_INSTANCE* inst, const struct chat_feedback_record* record, enum sql_operation operation) {
|
||||
merkle_key_t key, after = {{0}}, next; assert(!fb_key(1001, record, &key));
|
||||
uint64_t prefix = merkle_sync_level_prefix(fb_read64(key.bytes), MT_MAX_LEVEL);
|
||||
if (operation == F_PAGE) {
|
||||
uint8_t bytes[FB_WIRE_MAX + 2]; size_t length = sizeof(bytes); int more;
|
||||
return fb_page(inst, "1001", prefix, 0, &after, bytes, &length, &next, &more);
|
||||
}
|
||||
EVP_MD_CTX* hash = EVP_MD_CTX_new(); assert(hash && EVP_DigestInit_ex(hash, EVP_sha256(), NULL) == 1);
|
||||
int rc = fb_hash(inst, "1001", MT_MAX_LEVEL, prefix, hash); EVP_MD_CTX_free(hash); return rc;
|
||||
}
|
||||
|
||||
static void sql_fault_regressions(struct UASYNC* ua) {
|
||||
char path[] = "/tmp/utun-feedback-fault-XXXXXX"; int fd = mkstemp(path); assert(fd >= 0); close(fd);
|
||||
struct UTUN_INSTANCE author, target, reader; memset(&reader, 0, sizeof(reader));
|
||||
@@ -361,6 +379,20 @@ static void sql_fault_regressions(struct UASYNC* ua) {
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned reads = 0;
|
||||
for (enum sql_operation operation = F_PAGE; operation <= F_HASH; operation++) {
|
||||
for (enum sql_fault point = F_PREPARE; point <= F_FINALIZE; point++) {
|
||||
if (point == F_CHANGES) continue;
|
||||
int bindings = point == F_BIND ? (operation == F_PAGE ? 3 : 1) : 1;
|
||||
for (int bind = 1; bind <= bindings; bind++) {
|
||||
root(&target, before); saved = events;
|
||||
injected_operation = operation; injected_bind = bind; injected = point;
|
||||
assert(feedback_read(&target, ¤t, operation) < 0 && injected == F_NONE && events == saved);
|
||||
assert_stored(&reader, ¤t); root(&target, after); assert(!memcmp(before, after, 32));
|
||||
assert(feedback_read(&target, ¤t, operation) >= 0); reads++;
|
||||
}
|
||||
}
|
||||
}
|
||||
const char* triggers[] = {
|
||||
"CREATE TEMP TRIGGER reject_feedback BEFORE INSERT ON feedback_1001 BEGIN SELECT RAISE(ABORT,'feedback'); END",
|
||||
"CREATE TEMP TRIGGER reject_feedback BEFORE INSERT ON feedback_1001 BEGIN SELECT RAISE(IGNORE); END"
|
||||
@@ -398,7 +430,7 @@ static void sql_fault_regressions(struct UASYNC* ua) {
|
||||
member_sync_destroy(&target); assert(sqlite3_close(target.topo_sqlite_db) == SQLITE_OK); assert_stored(&reader, ¤t);
|
||||
member_sync_destroy(&author); assert(sqlite3_close(author.topo_sqlite_db) == SQLITE_OK);
|
||||
assert(sqlite3_close(reader.topo_sqlite_db) == SQLITE_OK); assert(!remove(path)); feedback_reader = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS feedback:%u SQL faults/retries, stale-state lookup failure, ABORT/IGNORE/veto, foreign no-op/page, failed rollback stops owner; reader sees exact committed records/roots before events", cases);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS feedback:%u write/%u read faults and retries, stale lookup, ABORT/IGNORE/veto, foreign no-op/page, failed rollback; reader checks records/roots before events", cases, reads);
|
||||
}
|
||||
|
||||
/* Диагностика копии профиля: без изменения записей или доступа к приватным ключам. */
|
||||
|
||||
Reference in new issue
Block a user