diff --git a/tests/Makefile.am b/tests/Makefile.am index 514a8497..78608f68 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -847,7 +847,8 @@ if OS_LINUX test_db_sync_integrity_SOURCES = test_db_sync_integrity.c test_db_sync_integrity_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib test_db_sync_integrity_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS) -test_db_sync_integrity_LDFLAGS = -Wl,--wrap=EVP_DigestVerifyInit -Wl,--wrap=sqlite3_exec -Wl,--wrap=uasync_set_timeout +test_db_sync_integrity_LDFLAGS = -Wl,--wrap=EVP_DigestVerifyInit -Wl,--wrap=sqlite3_exec -Wl,--wrap=uasync_set_timeout \ + -Wl,--wrap=sqlite3_column_blob -Wl,--wrap=sqlite3_errcode endif test_merkle_sync_SOURCES = test_merkle_sync.c $(test_clock_sources) diff --git a/tests/test_db_sync_integrity.c b/tests/test_db_sync_integrity.c index 27d27556..d142368b 100644 --- a/tests/test_db_sync_integrity.c +++ b/tests/test_db_sync_integrity.c @@ -3,7 +3,7 @@ #include "../src/chat/db_sync.c" #include -static int fail_verify, fail_commit, fail_timer; +static int fail_verify, fail_commit, fail_timer, fail_blob, blob_nomem; static unsigned fault_hits; extern int __real_EVP_DigestVerifyInit(EVP_MD_CTX*, EVP_PKEY_CTX**, const EVP_MD*, ENGINE*, EVP_PKEY*); int __wrap_EVP_DigestVerifyInit(EVP_MD_CTX* ctx, EVP_PKEY_CTX** pctx, const EVP_MD* md, ENGINE* engine, EVP_PKEY* key) { @@ -17,6 +17,17 @@ int __wrap_sqlite3_exec(sqlite3* db, const char* sql, int (*cb)(void*, int, char return __real_sqlite3_exec(db, sql, cb, arg, err); } +extern const void* __real_sqlite3_column_blob(sqlite3_stmt*, int); +const void* __wrap_sqlite3_column_blob(sqlite3_stmt* stmt, int col) { + if (fail_blob) { fail_blob = 0; blob_nomem = 1; fault_hits++; return NULL; } + return __real_sqlite3_column_blob(stmt, col); +} +extern int __real_sqlite3_errcode(sqlite3*); +int __wrap_sqlite3_errcode(sqlite3* db) { + if (blob_nomem) { blob_nomem = 0; return SQLITE_NOMEM; } + return __real_sqlite3_errcode(db); +} + extern void* __real_uasync_set_timeout(struct UASYNC*, uint64_t, void*, void (*)(void*), const char*); void* __wrap_uasync_set_timeout(struct UASYNC* ua, uint64_t delay, void* arg, void (*cb)(void*), const char* name) { if (fail_timer && !strcmp(name, "db_recalc")) { fail_timer = 0; fault_hits++; return NULL; } @@ -84,10 +95,16 @@ static void test_preservation(void) { assert(insert(&f, 100, "original", sig) == 0 && insert(&f, 100, "original", sig) == 1); fail_verify = 1; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original"); fail_verify = 2; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original"); + fail_blob = 1; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original"); + fail_blob = 1; + assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original"); assert(insert(&f, 100, "modified", sig) == -2); intact(&f, "original"); sql(&f, "UPDATE history SET node_id=99"); assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original"); assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original"); + f.inst.topo_sqlite_db = f.db.db; /* Отказ SQL lookup, в отличие от ещё неизвестного ключа. */ + assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original"); + f.inst.topo_sqlite_db = NULL; sql(&f, "UPDATE history SET node_id=1"); fail_verify = 1; assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original"); @@ -134,6 +151,8 @@ static void test_recalc(void) { struct fixture f; init(&f); uint8_t sig[64]; for (uint64_t ts = 1; ts <= 55; ts++) { sign(&f, ts, "record", sig); assert(insert(&f, ts, "record", sig) == 0); } uint64_t next = f.si.next_id, hash = 0; + fail_blob = 1; + assert(db_sync_last_chain_hash8(&f.si, &hash) == -1 && db_sync_count(&f.si) == 55 && f.si.recalc.pending); fail_commit = 1; assert(db_sync_last_chain_hash8(&f.si, &hash) == -1 && f.si.recalc.pending && f.si.recalc.pos == 0); assert(sqlite3_get_autocommit(f.db.db)); @@ -172,7 +191,7 @@ int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG); size_t baseline = u_get_allocated_count(); test_preservation(); test_deletion(); test_recalc(); test_delivery(); + assert(fault_hits == 10 && u_get_allocated_count() == baseline); DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS history integrity; injected failures=%u; tracked allocations restored", fault_hits); - assert(fault_hits == 7 && u_get_allocated_count() == baseline); return 0; }