// Isolated real HTTP + real FFmpeg + process restart. No paid model requests. const fs = require("node:fs"), path = require("node:path"), crypto = require("node:crypto"), assert = require("node:assert/strict"); const { spawn, execFileSync } = require("node:child_process"); const sha = (s) => crypto.createHash("sha256").update(s).digest("hex"); const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); (async () => { const dir = path.resolve(".qa/render-service"); fs.mkdirSync(dir, { recursive: true }); const data = fs.mkdtempSync(path.join(dir, "run-")), token = crypto.randomBytes(32).toString("hex"), base = "http://127.0.0.1:19340"; const tenant = sha("qa-user"), cache = path.join(data, "cache", sha(tenant).slice(0, 20)); fs.mkdirSync(cache, { recursive: true }); const plan = JSON.parse(fs.readFileSync(".qa/smart-edit/fixture-plan.json")); for (const [i, a] of plan.assets.entries()) { const file = path.resolve(".qa/smart-edit", i ? "with-audio.mp4" : "colors.mp4"), bytes = fs.readFileSync(file); a.hash = sha(bytes); fs.writeFileSync(path.join(cache, a.hash), bytes); fs.writeFileSync( path.join(cache, sha(a.url) + ".json"), JSON.stringify({ hash: a.hash, created: Date.now() }), ); } plan.transition = 0.5; plan.subtitles = true; plan.clips[1].gain = 2; plan.captions = [ { id: "font-http", start: 0, end: 2e6, text: "API 字体验证", style: { fontFamily: "noto-serif-sc", referenceHeight: 1080, fontSize: 56, color: "#ffffff", outlineColor: "#ffffff", outlineWidth: 0, opacity: 1, spacing: 0, }, }, ]; let child; const start = async () => { child = spawn(process.execPath, ["services/video-render/dist/server.cjs"], { env: { ...process.env, RENDER_PORT: "19340", RENDER_DATA_DIR: data, SMART_EDIT_CACHE_DIR: path.join(data, "cache"), RENDER_API_TOKEN: token, }, detached: true, stdio: ["ignore", "pipe", "pipe"], }); child.stdout.on("data", (b) => fs.appendFileSync(path.join(data, "log"), b)); child.stderr.on("data", (b) => fs.appendFileSync(path.join(data, "log"), b)); for (let i = 0; i < 60; i++) { try { if ( (await fetch(base + "/health", { headers: { authorization: "Bearer " + token } })).ok ) return; } catch {} await sleep(100); } throw Error("service did not start"); }; const stop = async (signal = "SIGTERM") => { if (child && child.exitCode === null) { process.kill(-child.pid, signal); await new Promise((r) => child.once("exit", r)); } child = null; }; const request = async (route, body) => { const r = await fetch(base + route, { method: body ? "POST" : "GET", headers: { authorization: "Bearer " + token, "content-type": "application/json" }, body: body && JSON.stringify(body), }); return { status: r.status, body: await r.json() }; }; try { await start(); assert.equal((await fetch(base + "/health")).status, 401); const id = sha("actual-render-restart"), input = { id, tenant, plan }; assert.equal((await request("/v1/renders", input)).status, 202); for (let i = 0; i < 100; i++) { if ( (await request("/v1/renders/" + id)).body.status === "running" && JSON.parse(fs.readFileSync(path.join(data, id + ".json"))).status === "running" ) break; await sleep(50); } await stop("SIGKILL"); await start(); assert.equal((await request("/v1/renders", input)).status, 200); assert.equal( (await request("/v1/renders", { ...input, plan: { ...plan, title: "changed" } })).status, 409, ); let state; for (let i = 0; i < 300; i++) { state = (await request("/v1/renders/" + id)).body; if (["succeeded", "failed"].includes(state.status)) break; await sleep(200); } assert.equal(state.status, "succeeded", JSON.stringify(state)); assert.equal(state.attempts, 2); assert.equal((await fetch(base + "/v1/renders/" + id + "/video")).status, 401); const result = await fetch(base + "/v1/renders/" + id + "/video", { headers: { authorization: "Bearer " + token }, }); const out = path.join(data, "download.mp4"); fs.writeFileSync(out, Buffer.from(await result.arrayBuffer())); const probe = JSON.parse( execFileSync("ffprobe", [ "-v", "error", "-show_format", "-show_streams", "-of", "json", out, ]), ); assert.ok(Math.abs(Number(probe.format.duration) - 3.5) < 0.15); assert.equal(probe.streams[0].width, 1280); assert.equal((await request("/v1/renders", input)).body.attempts, 2); await stop(); await start(); assert.equal((await request("/v1/renders/" + id)).body.status, "succeeded"); console.log( "PASS: authenticated API, real FFmpeg, persisted queue, kill/restart recovery, idempotency, conflicting request rejection, completed result survives restart", ); fs.writeFileSync(path.join(dir, "last-run.json"), JSON.stringify({ data, result: state })); } finally { await stop(); } })().catch((e) => { console.error(e); process.exitCode = 1; });