import test from "node:test"; import assert from "node:assert/strict"; import { callPost, setupOpsCorpus } from "../_testCorpus"; // Run with: // pnpm -C editor exec tsx --test "app/api/ops/persist-videos/route.test.ts" // // persist-videos' dry run, its body's shape and its disk floor — all answered // before any job. Moved from e2e/ops-api.spec.ts (release 19, A2b). const corpus = await setupOpsCorpus("one-youtube-channel-with-data"); const { POST } = await import("./route"); test.after(() => corpus.cleanup()); const slug = "test-youtube"; const video = "20240101_test1234567"; const items = [ { slug, id: video }, { slug, id: "missing12345" }, { slug: "no-such-channel", id: "abc123" }, ]; type Bucket = { count: number; items: { slug: string; id: string }[] }; type Plan = Record<"saved" | "wrongHeight" | "toFetch" | "noUrl" | "unknown", Bucket> & { willFetch: number; }; test("persist-videos buckets a list in a dry run, and refuses a bad body and a low disk — before any job", async () => { const dry = await callPost(POST, { items, format: "video_720", dryRun: true }); assert.equal(dry.status, 200, JSON.stringify(dry.body)); assert.equal(dry.body.dryRun, true); const plan = dry.body.plan as Plan; assert.deepEqual(plan.toFetch.items, [{ slug, id: video }]); assert.equal(plan.unknown.count, 2); assert.equal(plan.saved.count, 0); assert.equal(plan.willFetch, 1); // Nothing to fetch is an answer, not a job. const none = await callPost(POST, { items: [{ slug: "no-such-channel", id: "abc123" }] }); assert.equal(none.status, 200, JSON.stringify(none.body)); assert.deepEqual(none.body.jobIds, []); // The body's shape. const cases: [Record, RegExp][] = [ [{}, /"items" is required/], [{ items: [] }, /"items" is required/], [{ items: [{ slug, id: video, height: 720 }] }, /unknown key\(s\): height/], [{ items: [{ slug, id: "../escape" }] }, /is not a video id/], [{ items, format: "1080p" }, /"format" must be one of original, video_720/], [{ items, replace: "always" }, /"replace" must be one of never, above-height/], [{ items, gapMs: -1 }, /"gapMs" must be a whole number, zero or above/], [{ items, minFreeMemMb: "4096" }, /"minFreeMemMb" must be a whole number/], [{ items, dryRun: "yes" }, /"dryRun" must be a boolean/], [{ items, ids: ["x"] }, /unknown key\(s\): ids/], ]; for (const [data, error] of cases) { const res = await callPost(POST, data); assert.equal(res.status, 400, JSON.stringify(data)); assert.match(String(res.body.error), error, JSON.stringify(data)); } // A real run asks the disk floor before it queues anything. await corpus.writeSettings({ minFreeDiskGB: 1_000_000 }); try { const low = await callPost(POST, { items }); assert.equal(low.status, 400, JSON.stringify(low.body)); assert.match(String(low.body.error), /^Low disk space/); } finally { await corpus.writeSettings({ minFreeDiskGB: 0 }); } assert.deepEqual(await corpus.listJobIds(), []); });