Files
tyx_AI_xhs/tests/package/postv1-runtime.test.mjs
T
suyx 79b01ebc81
Dada P0-A isolated Windows CI / validate-and-package (push) Waiting to run
test(POSTV1-01): 增加最终便携包启动链路验收
2026-08-05 11:38:32 +08:00

83 lines
3.9 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import { join, resolve } from "node:path";
import { tmpdir } from "node:os";
import { spawn } from "node:child_process";
const packageRoot = resolve(process.env.DADA_POSTV1_PACKAGE_ROOT ?? ".build/portable-release/Dada-P0A-0.0.0-win-x64");
const port = 43121;
async function waitForHealth(child) {
const deadline = Date.now() + 15_000;
while (Date.now() < deadline) {
if (child.exitCode !== null) throw new Error(`packaged api exited: ${child.exitCode}: ${child.errorOutput ?? ""}`);
try {
const response = await fetch(`http://127.0.0.1:${port}/healthz`, { headers: { host: `127.0.0.1:${port}` } });
if (response.ok) return;
} catch {}
await new Promise((resolveDelay) => setTimeout(resolveDelay, 100));
}
throw new Error("packaged api health timeout");
}
function startApi(configPath, dataRoot) {
const child = spawn(join(packageRoot, "runtime", "node.exe"), [join(packageRoot, "server", "api.mjs"), "--dada-credential-stdin"], {
cwd: packageRoot,
env: { ...process.env, DADA_INSTANCE_CONFIG_PATH: configPath, DADA_SUPPORT_GATE_ROOT: join(packageRoot, "web", "support-gate"), DADA_WEB_ROOT: join(packageRoot, "web") },
stdio: ["pipe", "ignore", "pipe"],
windowsHide: true,
});
child.errorOutput = "";
child.stderr.setEncoding("utf8");
child.stderr.on("data", (chunk) => { child.errorOutput += chunk; });
child.stdin.end(JSON.stringify({ "Dada/P0A/api/amap": "", "Dada/P0A/api/resend": "", "Dada/P0A/admin/pepper": "portable-test-pepper-00000000000000000000000000000000" }));
return child;
}
async function stop(child) {
if (child.exitCode === null) {
child.kill();
await new Promise((resolveExit) => child.once("exit", resolveExit));
}
}
test("portable package serves the product and keeps SQLite data across API restart", async () => {
assert.ok(existsSync(join(packageRoot, "Dada.exe")));
assert.ok(existsSync(join(packageRoot, "web", "index.html")));
assert.match(await readFile(join(packageRoot, "server", "worker", "dist", "worker.js"), "utf8"), /GenerationProcessor/);
const root = await mkdtemp(join(tmpdir(), "dada-postv1-"));
const dataRoot = join(root, "data");
await mkdir(join(dataRoot, "db"), { recursive: true });
const configPath = join(root, "instance.json");
await writeFile(configPath, JSON.stringify({ data_root: dataRoot, initialized: true, instance_id: "portable-test", schema_version: 1, secure_config_revision: 1, admin_allowlist_hashes: [], admin_recovery_hashes: [] }));
let api = startApi(configPath, dataRoot);
try {
await waitForHealth(api);
const support = await fetch(`http://127.0.0.1:${port}/api/v1/support/check`, {
method: "POST",
headers: { host: `127.0.0.1:${port}`, origin: `http://127.0.0.1:${port}`, "content-type": "application/json", "sec-ch-ua": '"Google Chrome";v="150"', "sec-ch-ua-full-version-list": '"Google Chrome";v="150.0.0.0"', "sec-ch-ua-platform": '"Windows"' },
body: JSON.stringify({ brands: [{ brand: "Google Chrome", version: "150" }], full_version_list: [{ brand: "Google Chrome", version: "150.0.0.0" }], platform: "Windows" }),
});
assert.ok([200, 426].includes(support.status));
if (support.status === 200) {
const cookie = support.headers.get("set-cookie")?.split(";", 1)[0];
const page = await fetch(`http://127.0.0.1:${port}/app`, { headers: { host: `127.0.0.1:${port}`, cookie } });
assert.equal(page.status, 200);
assert.match(await page.text(), /<div id="root"><\/div>/);
}
assert.ok(existsSync(join(dataRoot, "db", "dada.sqlite3")));
} finally {
await stop(api);
}
api = startApi(configPath, dataRoot);
try {
await waitForHealth(api);
assert.ok(existsSync(join(dataRoot, "db", "dada.sqlite3")));
} finally {
await stop(api);
await rm(root, { recursive: true, force: true });
}
});