ai-chatbot/scripts/qa/video-canvas-audio.cjs

127 lines
4.2 KiB
JavaScript

// Exercises the actual audio adapter with local provider/storage doubles; no paid calls.
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",
),
);
fs.mkdirSync(".qa/audio-expansion", { recursive: true });
const modules = {
"server-only": "",
"@/lib/db/queries":
"export async function getEnabledAiModelsWithProvider(){return globalThis.__audioModels}",
"@/lib/storage/service":
"export async function uploadFile(name,bytes){return globalThis.__audioUpload(name,bytes)}",
"./download-media":
"export async function downloadCanvasMedia(url,file){return globalThis.__audioDownload(url,file)}",
};
await esbuild.build({
entryPoints: ["lib/video-canvas/audio-generation.ts"],
outfile: ".qa/audio-expansion/adapter.cjs",
bundle: true,
platform: "node",
format: "cjs",
packages: "external",
alias: { "@": process.cwd() },
plugins: [
{
name: "qa",
setup(b) {
b.onResolve({ filter: /.*/ }, (args) =>
Object.hasOwn(modules, args.path) ? { path: args.path, namespace: "qa" } : undefined,
);
b.onLoad({ filter: /.*/, namespace: "qa" }, (args) => ({ contents: modules[args.path] }));
},
},
],
});
const { executeCanvasAudio } = require(path.resolve(".qa/audio-expansion/adapter.cjs"));
global.__audioModels = [
{
model: { id: "official", modelId: "qwen3-tts-instruct-flash" },
provider: {
type: "alibaba",
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
apiKey: "local-fixture",
},
},
];
let posts = 0,
downloads = 0,
uploads = 0,
checkpoint;
global.fetch = async (url, init) => {
posts++;
assert.equal(init.method, "POST");
assert.equal(JSON.parse(init.body).input.voice, "Cherry");
return Response.json({
request_id: "fixture",
output: {
audio: {
url: "https://example.com/test.wav",
expires_at: Math.floor(Date.now() / 1000) + 3600,
},
},
});
};
global.__audioDownload = async (url, file) => {
downloads++;
assert.ok(checkpoint);
fs.writeFileSync(file, Buffer.from("RIFF1234WAVEfixtureaudio"));
};
global.__audioUpload = async (name, bytes) => {
uploads++;
if (uploads === 1) throw Error("storage unavailable");
assert.ok(bytes.byteLength);
return { url: "https://storage.example.com/archived.wav" };
};
const input = { mode: "tts", modelRef: "official", text: "测试", voice: "Cherry" };
const lifecycle = {
assertActive: async () => {},
checkpoint: async (value) => {
checkpoint = value.upstreamAudio;
},
};
await assert.rejects(() => executeCanvasAudio(input, lifecycle), /转存暂未完成/);
assert.equal(posts, 1);
assert.ok(checkpoint);
const result = await executeCanvasAudio(input, { ...lifecycle, resume: checkpoint });
assert.equal(result.url, "https://storage.example.com/archived.wav");
assert.equal(posts, 1);
assert.equal(downloads, 2);
await assert.rejects(
() => executeCanvasAudio(input, { ...lifecycle, resume: { ...checkpoint, expiresAt: 1 } }),
/过期/,
);
assert.equal(posts, 1);
global.fetch = async () => {
posts++;
throw Error("connection lost");
};
await assert.rejects(() => executeCanvasAudio(input, lifecycle), /不会自动重发/);
assert.equal(posts, 2);
global.fetch = async () => Response.json({ code: "Forbidden" }, { status: 403 });
await assert.rejects(() => executeCanvasAudio(input, lifecycle), /403/);
await assert.rejects(
() =>
executeCanvasAudio(input, {
...lifecycle,
assertActive: async () => {
throw Error("lost lease");
},
}),
/lost lease/,
);
console.log(
"PASS: actual adapter body, checkpoint-before-download, archival recovery without POST, expiry, transport uncertainty, provider failure and lease fencing",
);
})().catch((e) => {
console.error(e);
process.exitCode = 1;
});