Add targeted SQL read fault injection for poll command tests

This commit is contained in:
evgeny committed 2026-10-27 03:44:02 +01:00
1 parent aef6aae432
commit 63e76d2cf5
2 files changed
+62

No files matched your search

+2
View File
@@ -1320,6 +1320,8 @@ test_tcp_io_flush_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_chat_poll_SOURCES = test_chat_poll.c
test_chat_poll_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/chat -I$(top_srcdir)/lib
test_chat_poll_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_chat_poll_LDFLAGS = -Wl,--wrap=sqlite3_prepare_v2 -Wl,--wrap=sqlite3_bind_blob -Wl,--wrap=sqlite3_bind_text \
-Wl,--wrap=sqlite3_step -Wl,--wrap=sqlite3_finalize
test_chat_poll_network_SOURCES = test_chat_poll_network.c
test_chat_poll_network_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/chat -I$(top_srcdir)/lib
+60
View File
@@ -5,6 +5,66 @@
#include "../src/config_parser.h"
#include <assert.h>
enum poll_fault { P_NONE, P_PREPARE, P_BIND, P_STEP, P_FINALIZE };
enum poll_query { P_VALID, P_FIELD, P_TARGET, P_SNAPSHOT, P_CHOICES, P_OPTIONS };
static enum poll_fault fault;
static enum poll_query query;
static unsigned query_number, matching_queries, fault_bind, changed_events;
static sqlite3_stmt* fault_statement;
static int query_matches(const char* sql) {
const char* prefix[] = {"SELECT json_valid(?1)", "SELECT json_type(?1,?2),json_extract(?1,?2)",
"SELECT CASE WHEN json_valid", "SELECT node_id,kind,ver,data FROM feedback_",
"SELECT type,value FROM json_each(?1,?2)", "SELECT type,value FROM json_each(?1,'$.options')"};
return !strncmp(sql, prefix[query], strlen(prefix[query]));
}
static int take_fault(enum poll_fault point, sqlite3_stmt* st, unsigned index) {
if (fault != point || st != fault_statement || (point == P_BIND && index != fault_bind)) return 0;
fault = P_NONE;
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "poll test: injected query=%d occurrence=%u stage=%d bind=%u", query, query_number, point, index);
return 1;
}
extern int __real_sqlite3_prepare_v2(sqlite3*, const char*, int, sqlite3_stmt**, const char**);
int __wrap_sqlite3_prepare_v2(sqlite3* db, const char* sql, int length, sqlite3_stmt** st, const char** tail) {
int target = fault != P_NONE && query_matches(sql) && ++matching_queries == query_number;
if (target && fault == P_PREPARE) {
fault = P_NONE; *st = NULL; DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "poll test: prepare query=%d occurrence=%u", query, query_number);
return SQLITE_NOMEM;
}
int rc = __real_sqlite3_prepare_v2(db, sql, length, st, tail);
if (target && rc == SQLITE_OK) fault_statement = *st;
return rc;
}
extern int __real_sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int, void (*)(void*));
int __wrap_sqlite3_bind_blob(sqlite3_stmt* st, int index, const void* bytes, int length, void (*destroy)(void*)) {
if (take_fault(P_BIND, st, index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_blob(st, index, bytes, length, destroy);
}
extern int __real_sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void (*)(void*));
int __wrap_sqlite3_bind_text(sqlite3_stmt* st, int index, const char* bytes, int length, void (*destroy)(void*)) {
if (take_fault(P_BIND, st, index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_text(st, index, bytes, length, destroy);
}
extern int __real_sqlite3_step(sqlite3_stmt*);
int __wrap_sqlite3_step(sqlite3_stmt* st) {
if (take_fault(P_STEP, st, 0)) return SQLITE_IOERR;
return __real_sqlite3_step(st);
}
extern int __real_sqlite3_finalize(sqlite3_stmt*);
int __wrap_sqlite3_finalize(sqlite3_stmt* st) {
int fail = st && take_fault(P_FINALIZE, st, 0);
int rc = __real_sqlite3_finalize(st); if (st == fault_statement) fault_statement = NULL;
return fail ? SQLITE_IOERR : rc;
}
static void poll_event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int len) {
(void)data; (void)len;
assert(sqlite3_get_autocommit(inst->topo_sqlite_db));
if (type == CHAT_EVT_FEEDBACK_CHANGED || type == CHAT_EVT_MSG_RECEIVED) changed_events++;
}
static sqlite3_int64 json_number(sqlite3* db, const char* json, const char* path) {
sqlite3_stmt* st = NULL;
assert(sqlite3_prepare_v2(db, "SELECT json_extract(?1,?2)", -1, &st, NULL) == SQLITE_OK);