Files
UHD_Media_Tool/apps/server/test/organize-in-place-verify.test.ts
T

55 lines
2.4 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
// 不挂载 HTTP 路由;隔离 Deno 静态文件适配器,以便本单元测试在 Node 下执行。
vi.mock("hono/bun", () => ({ serveStatic: vi.fn() }));
import { verifyInPlace } from "../src/modules/acquisition-organize/services/organize.ts";
const path = "/media/unchanged.mkv";
const frozen = {
rootPath: "/media",
sentinel: ".uhd-root",
libraryRootId: "root",
entityId: "work",
sourceFacts: { [path]: { size: 100, mtimeMs: 200 } },
} as unknown as Parameters<typeof verifyInPlace>[2];
async function verify(observed: unknown, owner: string | null = null) {
const executeTakeFirst = vi.fn().mockResolvedValue(owner ? { media_entity_id: owner } : undefined);
const query = { innerJoin: () => query, select: () => query, where: () => query, executeTakeFirst };
const d = { ctx: { db: { selectFrom: () => query } } } as unknown as Parameters<typeof verifyInPlace>[0];
const statSafe = vi.fn().mockResolvedValue(observed);
// 仅提供 statSafe;若意外调用复制、移动、清理或写入,本测试立即失败。
const fsr = { proxy: { statSafe } } as unknown as Parameters<typeof verifyInPlace>[1];
return { result: await verifyInPlace(d, fsr, frozen, path, 100), statSafe, executeTakeFirst };
}
const observed = (extra = {}) => ({
kind: "ok",
facts: { isFile: true, isSymbolicLink: false, size: 100, mtimeMs: 200, ...extra },
});
describe("原地登记执行核验", () => {
it("只读核验,不复制或移动文件;同作品重复登记可继续", async () => {
const r = await verify(observed(), "work");
expect(r.result).toEqual({ status: "succeeded", bytes: 0 });
expect(r.statSafe).toHaveBeenCalledWith(path, { root: "/media", sentinel: ".uhd-root" });
});
it("文件消失、链接、变为目录或计划后的大小/时间变化均不登记", async () => {
for (const value of [
{ kind: "missing" },
observed({ isSymbolicLink: true }),
observed({ isFile: false }),
observed({ size: 101 }),
observed({ mtimeMs: 201 }),
]) {
const r = await verify(value);
expect(r.result.status).toBe("failed");
expect(r.executeTakeFirst).not.toHaveBeenCalled();
}
});
it("不会把已有视频悄悄登记为另一个作品", async () => {
expect((await verify(observed(), "other")).result).toMatchObject({
status: "failed",
error: { code: "ASSET_ENTITY_CONFLICT" },
});
});
});