Test reentrant media events and cleanup after hash failure

This commit is contained in:
evgeny committed 2026-10-22 14:58:15 +02:00
1 parent d4efdba44e
commit c08c24140c
2 files changed
+55 -1

No files matched your search

+3
View File
@@ -877,6 +877,9 @@ test_media_index_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
check_PROGRAMS += test_media_index_regressions
test_media_index_regressions_SOURCES = test_media_index_regressions.c
test_media_index_regressions_LDADD = $(LIBUTUN) $(COMMON_LIBS)
if OS_LINUX
test_media_index_regressions_LDFLAGS = -Wl,--wrap=ma_sha256_file
endif
test_media_delivery_sql_SOURCES = test_media_delivery_sql.c
test_media_delivery_sql_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/media_delivery -I$(top_srcdir)/lib
+52 -1
View File
@@ -18,6 +18,16 @@ static uint8_t key[32] = {1}, ids[32] = {1};
static struct media_index_result result = { .media_id = {2}, .content_hash = {3},
.file_size = 14, .block_size = 7, .num_blocks = 2, .block_ids = ids };
#ifdef __linux__
int __real_ma_sha256_file(const char*, uint8_t[32]);
int __wrap_ma_sha256_file(const char* path, uint8_t hash[32]) {
if (strstr(path, "/hash-failure")) {
memset(hash, 0, 32); DEBUG_ERROR(DEBUG_CATEGORY_DEBUG, "injected hash failure after file copy path=%s", path); return -1;
}
return __real_ma_sha256_file(path, hash);
}
#endif
static void sql(sqlite3* db, const char* query) { assert(sqlite3_exec(db, query, NULL, NULL, NULL) == SQLITE_OK); }
static int scalar(sqlite3* db, const char* query) {
sqlite3_stmt* st = NULL; assert(sqlite3_prepare_v2(db, query, -1, &st, NULL) == SQLITE_OK);
@@ -159,12 +169,17 @@ static void long_path(void) {
}
static int deleted_events, failed_submissions, successful_submissions;
static char delete_from_event[64];
static void event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int length) {
(void)inst;
if (type == CHAT_EVT_CHANNEL_DELETED) deleted_events++;
if (type == CHAT_EVT_MSG_SUBMITTED) {
assert(length == 9);
if (data[8]) successful_submissions++; else failed_submissions++;
if (delete_from_event[0]) {
int before = deleted_events;
assert(CC(inst)->media_submissions); chat_core_delete_channel(inst, delete_from_event);
assert(deleted_events == before); delete_from_event[0] = 0;
}
}
}
@@ -201,13 +216,49 @@ static void pending_deletion(void) {
assert(ma_file_size(source) == 14 && ma_file_size(destinations[0]) == -1 && ma_file_size(destinations[1]) == -1);
chat_core_ensure_channel_ready(inst, channel); uasync_poll(ua, 0);
assert(!scalar(db, "SELECT count(*) FROM media_files"));
/* Обработчик MSG_SUBMITTED синхронный: удаление должно увидеть ещё живую задачу. */
chat_core_create_channel_auto(inst, "reentrant");
assert(!sqlite3_prepare_v2(db, "SELECT channel_id FROM channels WHERE name='reentrant'", -1, &st, NULL));
assert(sqlite3_step(st) == SQLITE_ROW);
snprintf(req.channel_id, sizeof(req.channel_id), "%s", sqlite3_column_text(st, 0)); sqlite3_finalize(st);
snprintf(delete_from_event, sizeof(delete_from_event), "%s", req.channel_id);
req.request_id = 4; chat_core_submit_media_message(inst, &req);
for (int i = 0; i < 2000 && deleted_events < 2; i++) uasync_poll(ua, 100);
assert(deleted_events == 2 && successful_submissions == 1 && failed_submissions == 3 && !CC(inst)->media_submissions);
assert(!scalar(db, "SELECT count(*) FROM channels WHERE name='reentrant'"));
assert(ma_file_size(destinations[1]) == -1 && ma_file_size(source) == 14);
utun_instance_destroy(inst); uasync_destroy(ua, 0);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "media regression pending deletion/two completions/recreation PASS");
}
#ifdef __linux__
static void preparation_failed(void* arg, int error, const struct media_index_result* value) {
int* completed = arg; assert(error && !value); (*completed)++;
}
static void failed_preparation(void) {
char source[MEDIA_PATH_MAX], destination[MEDIA_PATH_MAX];
assert(!media_index_path(root, "copy-source", source) && !media_index_path(root, "hash-failure", destination));
write_file(source); sqlite3* db = database();
struct UASYNC* ua = uasync_create(); assert(ua);
struct media_async* ma = media_async_create(); assert(ma); int completed = 0;
media_index_register_async(ma, ua, db, 1, key, "failed", source, destination, 1, root, preparation_failed, &completed);
for (int i = 0; i < 2000 && !completed; i++) uasync_poll(ua, 100);
assert(completed == 1 && ma_file_size(destination) == 14 && !scalar(db, "SELECT count(*) FROM media_files"));
assert(scalar(db, "SELECT count(*) FROM media_preparations") == 1);
assert(!media_index_delete_channel(db, "failed", root));
assert(ma_file_size(destination) == -1 && ma_file_size(source) == 14);
media_async_destroy(ma); uasync_destroy(ua, 0); sqlite3_close(db);
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "media regression failed preparation cleanup PASS");
}
#endif
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO);
assert(!test_mkdtemp(root)); ids[16] = 2;
paths(); transactions(); deletion(); long_path(); pending_deletion();
#ifdef __linux__
failed_preparation();
#endif
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "test_media_index_regressions PASS"); return 0;
}