// Exercises actual provider adapters and selection with synthetic credentials and an in-process fetch stub. // No real network request or paid model execution is permitted. const fs = require("node:fs"), path = require("node:path"), assert = require("node:assert/strict"); (async () => { const esbuild = require( path.resolve( "node_modules/.pnpm", fs.readdirSync("node_modules/.pnpm").find((n) => n.startsWith("esbuild@0.25.")), "node_modules/esbuild", ), ); const out = path.resolve(".qa/video-provider-recovery"); fs.mkdirSync(out, { recursive: true }); const stubs = { "server-only": "", "@/lib/db/queries": `export const getEnabledAiModelsWithProvider=async()=>globalThis.qaModels;export const getSubModelsByParentModelId=async()=>[];export const getSystemSetting=async()=>null;export const getDefaultStorageConfig=async()=>{throw Error('unexpected storage');};`, "@/lib/ai/dynamic-provider": `export const getLanguageModelById=async()=>{throw Error('durable video must use task adapter');};`, "@/lib/storage/service": `export const uploadFile=async()=>{throw Error('unexpected upload');};export const buildS3PublicUrl=()=>'';export const createS3Client=()=>{throw Error('unexpected S3');};export const toDbS3UploadConfig=x=>x;`, "@/lib/storage/image-archive": `export const createDeferredUploadedImage=async()=>null;`, }; await esbuild.build({ entryPoints: ["lib/ai/tools/generate-video.ts"], outfile: path.join(out, "video.cjs"), bundle: true, platform: "node", format: "cjs", packages: "external", alias: { "@": process.cwd() }, plugins: [ { name: "qa-only", setup(build) { build.onResolve({ filter: /.*/ }, (a) => stubs[a.path] !== undefined ? { path: a.path, namespace: "qa" } : undefined, ); build.onLoad({ filter: /.*/, namespace: "qa" }, (a) => ({ contents: stubs[a.path], loader: "js", })); }, }, ], }); const { executeDirectVideoGeneration } = require(path.join(out, "video.cjs")); const originalFetch = globalThis.fetch, originalTimeout = globalThis.setTimeout; // Only provider sleep timers are shortened. AbortSignal's native timeout is unchanged. globalThis.setTimeout = (fn, ms, ...args) => originalTimeout(fn, Math.min(ms, 1), ...args); try { for (const [kind, type, modelId] of [ ["aliyun", "qianwen-video", "wan2.6-i2v-flash"], ["vip98k", "vip98k", "veo-qa"], ["volcano", "volcano-video", "doubao-seedance-1-0-pro-250528"], ["atlascloud", "atlascloud", "qa-video"], ["agnes", "custom", "agnes-video-qa"], ]) { const capabilities = { kind: "video", mediaType: "video", provider: kind === "agnes" ? "agnes-ai" : kind, supportedModes: ["text-to-video", "first-frame"], supportedResolutions: ["720p"], supportedRatios: ["16:9"], durationRange: { min: 2, max: 15 }, durationOptions: [5], maxReferenceImages: 4, }; const fixture = { model: { id: "model-" + kind, modelId, displayName: kind, isEnabled: true, capabilities, imageGenConfig: kind === "atlascloud" ? { atlasCloud: { submitEndpoint: "/api/v1/model/generateVideo", pollEndpoint: "/api/v1/model/prediction/{id}", propertyNames: ["model", "prompt", "duration", "aspect_ratio", "resolution"], requiredFields: ["model", "prompt"], maxReferenceImages: 0, defaultValues: {}, }, } : {}, }, provider: { id: "provider-" + kind, type, apiKey: "synthetic-qa-key", baseUrl: "https://provider.invalid", }, }; globalThis.qaModels = [fixture]; let checkpoint = null, calls = [], failQuery = true; globalThis.fetch = async (url, init = {}) => { assert.equal( new URL(String(url)).hostname, "provider.invalid", "unexpected network destination", ); const method = init.method || "GET"; calls.push(method); if (method === "POST") { assert.equal(calls.filter((m) => m === "POST").length, 1, "duplicate submit"); if (kind === "aliyun") return Response.json({ output: { task_id: "qa-original" } }); if (kind === "vip98k") return Response.json({ task_id: "qa-original" }); if (kind === "agnes") return Response.json({ video_id: "qa-original", task_id: "qa-original" }); return Response.json({ id: "qa-original" }); } assert(checkpoint, "provider GET happened before durable checkpoint"); assert(String(url).includes("qa-original"), "query must use saved task"); if (failQuery) throw Error("QA simulated connection lost"); if (kind === "aliyun") return Response.json({ output: { task_status: "SUCCEEDED", video_url: "https://output.invalid/video.mp4" }, }); if (kind === "volcano") return Response.json({ status: "succeeded", content: { video_url: "https://output.invalid/video.mp4" }, }); if (kind === "agnes") return Response.json({ status: "completed", url: "https://output.invalid/video.mp4" }); return Response.json({ status: "completed", outputs: ["https://output.invalid/video.mp4"], }); }; const params = { prompt: "QA only", mode: kind === "aliyun" ? "first-frame" : "text-to-video", images: kind === "aliyun" ? ["https://input.invalid/ref.png"] : [], duration: 5, resolution: "720p", ratio: "16:9", preferredModelRef: fixture.model.id, }; await assert.rejects( executeDirectVideoGeneration({ ...params, taskLifecycle: { save: async (cp) => { checkpoint = cp; }, assertActive: async () => {}, }, }), ); assert(checkpoint, kind + " did not save accepted task"); assert.equal(checkpoint.provider, kind); assert.equal(checkpoint.modelRef, fixture.model.id); failQuery = false; calls = []; const result = await executeDirectVideoGeneration({ ...params, taskLifecycle: { resume: checkpoint, save: async () => { throw Error("resume must not save new task"); }, assertActive: async () => {}, }, }); assert.equal(result.videoUrl, "https://output.invalid/video.mp4"); assert(calls.length > 0); assert( calls.every((method) => method === "GET"), kind + " resumed with a POST", ); calls = []; globalThis.fetch = async (url, init = {}) => { assert.equal(new URL(String(url)).hostname, "provider.invalid"); calls.push(init.method || "GET"); return Response.json( kind === "aliyun" ? { output: { task_status: "FAILED", code: "QA_FAILURE" } } : { status: "failed", error: { message: "QA terminal network failure" } }, ); }; await assert.rejects( executeDirectVideoGeneration({ ...params, taskLifecycle: { resume: checkpoint, save: async () => {}, assertActive: async () => {} }, }), (error) => error.constructor.name === "ProviderTaskFailedError", ); assert.deepEqual(calls, ["GET"], kind + " retried a terminal failure"); fixture.provider.baseUrl = "https://changed.invalid"; calls = []; await assert.rejects( executeDirectVideoGeneration({ ...params, taskLifecycle: { resume: checkpoint, save: async () => {}, assertActive: async () => {} }, }), /线路已变更/, ); assert.equal(calls.length, 0); fixture.provider.baseUrl = "https://provider.invalid"; calls = []; globalThis.fetch = async (url, init = {}) => { calls.push(init.method || "GET"); throw Error("fetch failed: connection reset during submit"); }; await assert.rejects( executeDirectVideoGeneration({ ...params, taskLifecycle: { save: async () => { throw Error("no accepted ID"); }, assertActive: async () => {}, }, }), /不会自动重新提交/, ); assert.equal( calls.filter((m) => m === "POST").length, 1, kind + " retried an uncertain POST", ); console.log( `PASS ${kind}: checkpoint before GET, interrupted query, GET-only resume, original provider identity enforced`, ); } } finally { globalThis.fetch = originalFetch; globalThis.setTimeout = originalTimeout; } })().then( () => process.exit(0), (error) => { console.error(error); process.exit(1); }, );