test(chat): cover startup admission, saved channel activation, and owner-close recovery
This commit is contained in:
1 parent
1c6d203754
commit
8151fc5a9c
1 file changed
+59
-4
@@ -152,6 +152,57 @@ static void sql_faults(struct UTUN_INSTANCE* inst, const char* path) {
|
||||
printf("PASS lifecycle:%u SQL faults/retries,commit veto,context/properties/routes allocation;exact DB,callbacks,and ready preserved\n", cases);
|
||||
}
|
||||
|
||||
static sqlite3_int64 number(sqlite3* db, const char* sql) {
|
||||
sqlite3_stmt* st = NULL; assert(sqlite3_prepare_v2(db, sql, -1, &st, NULL) == SQLITE_OK && sqlite3_step(st) == SQLITE_ROW);
|
||||
sqlite3_int64 result = sqlite3_column_int64(st, 0); assert(sqlite3_finalize(st) == SQLITE_OK); return result;
|
||||
}
|
||||
|
||||
static void validation(struct UTUN_INSTANCE* inst, const char* path) {
|
||||
uint8_t before[32], after[32]; snapshot(reader, before); ready = 0;
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, "BEGIN;CREATE TABLE lifecycle_outer(value);INSERT INTO lifecycle_outer VALUES(7)", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(chat_core_init(inst, path) < 0 && !inst->chat_core && !sqlite3_get_autocommit(inst->topo_sqlite_db));
|
||||
assert(number(inst->topo_sqlite_db, "SELECT value FROM lifecycle_outer") == 7);
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, "ROLLBACK", NULL, NULL, NULL) == SQLITE_OK);
|
||||
char long_path[513]; memset(long_path, 'x', sizeof(long_path)); long_path[512] = 0;
|
||||
assert(chat_core_init(inst, long_path) < 0 && chat_core_init(NULL, path) < 0 && chat_core_init(inst, NULL) < 0);
|
||||
chat_core_destroy(NULL); snapshot(reader, after); assert(!memcmp(before, after, 32) && !ready && !inst->chat_core);
|
||||
assert(number(reader, "SELECT count(*) FROM accounts") == 0);
|
||||
const char* modes[] = {"ABORT", "IGNORE"};
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
char sql[256]; snprintf(sql, sizeof(sql), "CREATE TRIGGER reject_identity BEFORE INSERT ON local_identity BEGIN SELECT RAISE(%s%s);END",
|
||||
modes[i], i ? "" : ",'injected identity rejection'");
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK); refused(inst, path);
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, "DROP TRIGGER reject_identity", NULL, NULL, NULL) == SQLITE_OK); retry(inst, path);
|
||||
}
|
||||
puts("PASS lifecycle:foreign transaction preserved,NULL/oversized path rejected,ABORT/IGNORE rollback,no demonstration contacts");
|
||||
}
|
||||
|
||||
static void activation(struct UTUN_INSTANCE* inst, const char* path) {
|
||||
ready = 0; assert(!chat_service_start(inst) && ready == 2);
|
||||
uint64_t groups[2] = {chat_core_create_channel_auto(inst, "first saved"), chat_core_create_channel_auto(inst, "second saved")};
|
||||
assert(groups[0] && groups[1]);
|
||||
struct chat_msg_submit request = {.inst = inst, .data = (uint8_t*)"startup retained", .data_len = 16};
|
||||
snprintf(request.channel_id, sizeof(request.channel_id), "%llu", (unsigned long long)groups[0]); strcpy(request.content_type, "text/plain");
|
||||
assert(!chat_core_submit_message(inst, &request)); chat_service_stop(inst);
|
||||
char sql[256]; snprintf(sql, sizeof(sql), "SELECT rowid FROM channels WHERE channel_id='%llu'", (unsigned long long)groups[0]);
|
||||
sqlite3_int64 row = number(reader, sql);
|
||||
const char* invalid[] = {"'01'", "CAST(X'313200' AS TEXT)", "'9223372036854775808'"};
|
||||
for (size_t i = 0; i < sizeof(invalid) / sizeof(invalid[0]); i++) {
|
||||
snprintf(sql, sizeof(sql), "UPDATE channels SET channel_id=%s WHERE rowid=%lld", invalid[i], (long long)row);
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK); refused(inst, path);
|
||||
snprintf(sql, sizeof(sql), "UPDATE channels SET channel_id='%llu' WHERE rowid=%lld", (unsigned long long)groups[0], (long long)row);
|
||||
assert(sqlite3_exec(inst->topo_sqlite_db, sql, NULL, NULL, NULL) == SQLITE_OK);
|
||||
}
|
||||
ready = 0; fail_sync = 2;
|
||||
assert(chat_service_start(inst) < 0 && !fail_sync && !ready && !inst->chat_core && !inst->chat_started && inst->core_started);
|
||||
assert(!topo_groups_find(inst->topo_groups, groups[0]) && !topo_groups_find(inst->topo_groups, groups[1]));
|
||||
assert(inst->nodeinfo_cbks == preserved_callback && number(reader, "SELECT count(*) FROM channels") == 2);
|
||||
snprintf(sql, sizeof(sql), "SELECT count(*) FROM msg_%llu", (unsigned long long)groups[0]); assert(number(reader, sql) == 1);
|
||||
assert(!chat_service_start(inst) && ready == 2 && chat_core_count(inst, request.channel_id) == 1);
|
||||
assert(topo_groups_find(inst->topo_groups, groups[0]) && topo_groups_find(inst->topo_groups, groups[1])); chat_service_stop(inst);
|
||||
puts("PASS lifecycle:corrupt catalog rejected;second channel activation failure cleans all runtime,keeps data,and retries without false ready");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); size_t baseline = u_get_allocated_count();
|
||||
utun_instance_set_tun_init_enabled(0); struct UASYNC* ua = uasync_create(); assert(ua);
|
||||
@@ -164,10 +215,14 @@ int main(void) {
|
||||
assert(!utun_add_nodeinfo_cbk(inst, preserved, inst)); preserved_callback = inst->nodeinfo_cbks;
|
||||
unsigned denied = 0; assert(sqlite3_set_authorizer(inst->topo_sqlite_db, deny_accounts, &denied) == SQLITE_OK);
|
||||
refused(inst, database); assert(denied == 1); assert(sqlite3_set_authorizer(inst->topo_sqlite_db, NULL, NULL) == SQLITE_OK);
|
||||
retry(inst, database); sql_faults(inst, database);
|
||||
ready = 0;
|
||||
assert(!chat_service_start(inst) && ready == 2); chat_service_stop(inst);
|
||||
retry(inst, database); sql_faults(inst, database); validation(inst, database); activation(inst, database);
|
||||
uint8_t before[32], after[32]; snapshot(reader, before); ready = 0;
|
||||
target = "COMMIT /* chat init */"; fault = F_EXEC; fail_rollback = 1; inst->running = 1;
|
||||
assert(chat_core_init(inst, database) < 0 && fault == F_NONE && !fail_rollback && !inst->running && !inst->chat_core);
|
||||
assert(!ready && !sqlite3_get_autocommit(inst->topo_sqlite_db) && inst->nodeinfo_cbks == preserved_callback);
|
||||
snapshot(reader, after); assert(!memcmp(before, after, 32)); utun_instance_destroy(inst);
|
||||
snapshot(reader, after); assert(!memcmp(before, after, 32));
|
||||
assert(sqlite3_close(reader) == SQLITE_OK);
|
||||
utun_instance_destroy(inst); uasync_poll(ua, 0); uasync_destroy(ua, 0); assert(u_get_allocated_count() == baseline);
|
||||
uasync_poll(ua, 0); uasync_destroy(ua, 0); assert(u_get_allocated_count() == baseline);
|
||||
puts("PASS lifecycle:subscription failure aborts startup without ready events;core survives and retry succeeds"); return 0;
|
||||
}
|
||||
Reference in new issue
Block a user