#define PRETRANSCODE_TEST #include "../pretranscode.c" #include static void write_file(const char *path, const char *value) { char *parent = xstrdup(path), *slash = strrchr(parent, '/'); assert(slash); *slash = 0; assert(mkdirs(parent) == 0); free(parent); int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644); assert(fd >= 0); assert(write(fd, value, strlen(value)) == (ssize_t)strlen(value)); assert(close(fd) == 0); } static void remove_tree(const char *root) { char *roots[] = {(char *)root, NULL}; FTS *tree = fts_open(roots, FTS_PHYSICAL | FTS_NOCHDIR, NULL); assert(tree); FTSENT *entry; while ((entry = fts_read(tree))) { if (entry->fts_info == FTS_DP) assert(rmdir(entry->fts_path) == 0); else if (entry->fts_info != FTS_D) assert(unlink(entry->fts_path) == 0); } fts_close(tree); } static void test_hashes(void) { char a[33], b[33]; path_hash("tv/Test/one.mkv", a); path_hash("tv/Test/one.mkv", b); assert(strcmp(a, b) == 0); path_hash("tv/Test/two.mkv", b); assert(strcmp(a, b)); struct stat st = {.st_dev = 1, .st_ino = 2, .st_size = 3}; st.st_mtim.tv_sec = 4; st.st_mtim.tv_nsec = 5; generation_hash(&st, a); st.st_ino++; generation_hash(&st, b); assert(strcmp(a, b)); char path[] = "/tmp/pretranscode-hash-XXXXXX"; int fd = mkstemp(path); assert(fd >= 0); const char value[] = "immutable output"; assert(write(fd, value, sizeof(value) - 1) == (ssize_t)(sizeof(value) - 1)); close(fd); assert(file_hash(path, a) == 0); hash_bytes(value, sizeof(value) - 1, b); assert(strcmp(a, b) == 0); assert(unlink(path) == 0); } static void test_atomic_link_keeps_open_inode(void) { char root[] = "/tmp/pretranscode-link-XXXXXX"; assert(mkdtemp(root)); char *view = xprintf("%s/view/file.mkv", root); char *original = xprintf("%s/original", root), *cached = xprintf("%s/cached", root); write_file(original, "original"); write_file(cached, "cached"); assert(atomic_link(view, original) == 1); int old = open(view, O_RDONLY | O_CLOEXEC); assert(old >= 0); assert(atomic_link(view, cached) == 1); char data[16] = {0}; assert(read(old, data, sizeof(data)) == 8); assert(!strcmp(data, "original")); close(old); memset(data, 0, sizeof(data)); int current = open(view, O_RDONLY | O_CLOEXEC); assert(current >= 0); assert(read(current, data, sizeof(data)) == 6); assert(!strcmp(data, "cached")); close(current); free(view); free(original); free(cached); remove_tree(root); } static void test_cache_name(void) { const char *hash = "00112233445566778899aabbccddeeff"; char *name = xprintf("%s.%s.%s.%s.mkv", hash, hash, hash, hash); struct cache cache = {0}; assert(parse_cache_name(name, &cache)); cache.named = true; assert(!strcmp(cache.path_hash, hash)); assert(!strcmp(cache.extension, ".mkv")); struct item item = {.extension = ".mkv"}; memcpy(item.path_hash, hash, HASH_HEX + 1); memcpy(item.generation_hash, hash, HASH_HEX + 1); assert(cache_matches(&cache, &item)); name[2] = 'X'; assert(!parse_cache_name(name, &cache)); free(name); } static void test_lru_does_not_change_media_mtime(void) { char root[] = "/tmp/pretranscode-atime-XXXXXX"; assert(mkdtemp(root)); char *view_root = xprintf("%s/view", root), *media = xprintf("%s/media.mkv", root); char *view = xprintf("%s/movie.mkv", view_root); write_file(media, "cached"); assert(atomic_link(view, "/cache/files/media.mkv") == 1); struct timespec old[2] = {{.tv_sec = 100}, {.tv_sec = 100}}; assert(utimensat(AT_FDCWD, media, old, 0) == 0); struct manager manager = {.cfg.view_root = view_root}; struct cache cache = {.path = media, .target = "/cache/files/media.mkv"}; manager.caches.v = &cache; manager.caches.n = 1; touch_target(&manager, "movie.mkv"); struct stat st; assert(stat(media, &st) == 0); assert(st.st_mtim.tv_sec == 100); assert(st.st_atim.tv_sec > 100); manager.caches.v = NULL; manager.caches.n = 0; free(view_root); free(media); free(view); remove_tree(root); } static void test_old_profile_is_replacement_candidate(void) { const char *hash = "00112233445566778899aabbccddeeff"; struct cache old = {.named = true, .target = "/cache/files/old.mkv"}; memcpy(old.path_hash, hash, HASH_HEX + 1); memcpy(old.generation_hash, hash, HASH_HEX + 1); memcpy(old.extension, ".mkv", 5); memset(old.profile_hash, '1', HASH_HEX); old.profile_hash[HASH_HEX] = 0; struct item item = {.relative = "movie.mkv", .extension = ".mkv", .fallback = &old, .mtime = 1}; memcpy(item.path_hash, hash, HASH_HEX + 1); memcpy(item.generation_hash, hash, HASH_HEX + 1); struct manager manager = {0}; manager.items.v = &item; manager.items.n = 1; memset(manager.cfg.profile_hash, '2', HASH_HEX); manager.cfg.profile_hash[HASH_HEX] = 0; assert(valid_cache(&manager, &item) == NULL); assert(candidate(&manager) == &item); } static void test_single_writer_lock(void) { char root[] = "/tmp/pretranscode-lock-XXXXXX"; assert(mkdtemp(root)); int first = open(root, O_RDONLY | O_DIRECTORY | O_CLOEXEC); int second = open(root, O_RDONLY | O_DIRECTORY | O_CLOEXEC); assert(first >= 0 && second >= 0); assert(flock(first, LOCK_EX | LOCK_NB) == 0); assert(flock(second, LOCK_EX | LOCK_NB) < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)); close(second); close(first); assert(rmdir(root) == 0); } static void test_scheduling(void) { int pipes[2]; assert(pipe(pipes) == 0); pid_t pid = fork(); assert(pid >= 0); if (!pid) { close(pipes[0]); background_or_exit(); int values[2] = {sched_getscheduler(0), IOPRIO_PRIO_CLASS((int)syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, 0))}; if (write(pipes[1], values, sizeof(values)) != (ssize_t)sizeof(values)) _exit(1); _exit(0); } close(pipes[1]); int values[2]; assert(read(pipes[0], values, sizeof(values)) == (ssize_t)sizeof(values)); close(pipes[0]); assert(waitpid(pid, NULL, 0) == pid); assert(values[0] == SCHED_IDLE); assert(values[1] == IOPRIO_CLASS_IDLE); } static void test_output_validation(void) { struct media source = {.codec = "hevc", .depth = 10, .width = 1920, .height = 1080, .audio = 2, .subtitles = 3, .attachments = 1, .chapters = 12, .duration = 1200}; struct media output = {.codec = "h264", .depth = 8, .width = 1920, .height = 1080, .audio = 1, .audio_compatible = true, .duration = 1200}; assert(valid_output(&source, &output)); output.dolby_vision = true; assert(!valid_output(&source, &output)); output.dolby_vision = false; output.subtitles = 1; assert(!valid_output(&source, &output)); output.subtitles = 0; output.audio_compatible = false; assert(!valid_output(&source, &output)); } static void test_canonical_policy(void) { struct media media = {.codec = "h264", .depth = 8, .audio = 1, .audio_compatible = true}; assert(!incompatible(&media)); snprintf(media.codec, sizeof(media.codec), "av1"); assert(incompatible(&media)); snprintf(media.codec, sizeof(media.codec), "h264"); media.audio_compatible = false; assert(incompatible(&media)); media.audio_compatible = true; media.subtitles = 1; assert(incompatible(&media)); } int main(void) { test_hashes(); test_atomic_link_keeps_open_inode(); test_cache_name(); test_lru_does_not_change_media_mtime(); test_old_profile_is_replacement_candidate(); test_single_writer_lock(); test_scheduling(); test_output_validation(); test_canonical_policy(); puts("all core tests passed"); return 0; }