import test from "node:test"; import assert from "node:assert/strict"; import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import os from "node:os"; import path from "node:path"; // Run with: // pnpm -C editor exec tsx --test "app/api/ops/prepare-playable/route.test.ts" // // The body's shape and the refusals that come before any job, then one dry // run over a channel with no saved containers. Nothing is remuxed. const ROOT = await mkdtemp(path.join(os.tmpdir(), "prepare-playable-route-")); process.env.WORKER_TOKEN = "test-token"; process.env.TRANSCRIPTS_DIR = ROOT; process.env.SETTINGS_FILE = path.join(ROOT, "settings.json"); const { POST } = await import("./route"); const { getRegistry } = await import("yt-dlp-transcript-common/jobs/registry"); const { getPaths } = await import("yt-dlp-transcript-common/lib/paths"); test.after(() => rm(ROOT, { recursive: true, force: true })); await mkdir(path.join(ROOT, "channels", "tism", "data", "aaaaaaaaaaa"), { recursive: true }); await writeFile(path.join(ROOT, "channels", "tism", "config.json"), JSON.stringify({ handling: "youtube", name: "tism" })); async function post(body: Record) { const res = await POST( new Request("http://localhost/api/ops/prepare-playable", { method: "POST", headers: { authorization: "Bearer test-token", "content-type": "application/json" }, body: JSON.stringify(body), }), ); return { status: res.status, json: (await res.json()) as { ok?: boolean; error?: string; jobId?: string } }; } test("refusals before any job", async () => { const cases: [Record, RegExp][] = [ [{}, /"slug" is required/], [{ slug: "tism", force: 1 }, /unknown key\(s\): force/], [{ slug: "tism", ids: [] }, /non-empty array/], [{ slug: "tism", ids: ["../x"] }, /not a video id/], [{ slug: "tism", trackers: "wss://x" }, /must be an array/], [{ slug: "tism", trackers: ["file:///etc/passwd"] }, /not a tracker URL/], [{ slug: "tism", root: "relative" }, /must be an absolute path/], [{ slug: "nope" }, /Channel "nope" not found/], ]; for (const [body, re] of cases) { const r = await post(body); assert.equal(r.status, 400, JSON.stringify(body)); assert.match(r.json.error!, re, JSON.stringify(body)); } }); test("a dry run over a channel with no saved containers is a job that says so", async () => { const r = await post({ slug: "tism", dryRun: true, root: path.join(ROOT, "playable"), trackers: ["wss://tracker.example/announce"] }); assert.equal(r.status, 200, JSON.stringify(r.json)); for (let i = 0; i < 100; i++) { const s = getRegistry().get(r.json.jobId!)?.status; if (s === "done" || s === "failed") break; await new Promise((res) => setTimeout(res, 50)); } assert.equal(getRegistry().get(r.json.jobId!)?.status, "done"); const log = await readFile(path.join(getPaths().jobsDir, `${r.json.jobId}.log`), "utf8"); assert.match(log, /0 video\(s\) with a saved container/); assert.match(log, /summary: \{"dryRun":true/); });