mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-07 18:42:25 +00:00
* test(qa): cover CLI onboarding and plugin sources * test(qa): assert npm file plugin source * test(qa): redact onboarding password assertion * test(qa): retain onboarding evidence log
142 lines
4.2 KiB
JavaScript
142 lines
4.2 KiB
JavaScript
import { spawn } from "node:child_process";
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { buildScriptEvidenceSummary, QA_EVIDENCE_FILENAME } from "../../extensions/qa-lab/api.js";
|
|
import { createQaScriptEvidenceWriter } from "../../test/e2e/qa-lab/runtime/script-evidence.js";
|
|
|
|
const args = process.argv.slice(2);
|
|
const artifactBaseIndex = args.indexOf("--artifact-base");
|
|
const artifactBase = args[artifactBaseIndex + 1];
|
|
if (artifactBaseIndex === -1 || !artifactBase || artifactBase.startsWith("-")) {
|
|
throw new Error("--artifact-base is required");
|
|
}
|
|
|
|
const boundaries = [
|
|
{
|
|
id: "cli-gateway-auth-storage",
|
|
title: "CLI Gateway auth storage",
|
|
markers: [
|
|
"QA_ASSERT cli.gateway-auth-storage.token-ref pass",
|
|
"QA_ASSERT cli.gateway-auth-storage.password pass",
|
|
],
|
|
},
|
|
{
|
|
id: "cli-guided-onboarding",
|
|
title: "CLI guided onboarding",
|
|
marker: "QA_ASSERT cli.guided-onboarding pass",
|
|
},
|
|
{
|
|
id: "cli-remote-onboarding",
|
|
title: "CLI remote onboarding",
|
|
marker: "QA_ASSERT cli.remote-onboarding pass",
|
|
},
|
|
{
|
|
id: "cli-targeted-reconfiguration",
|
|
title: "CLI targeted reconfiguration",
|
|
markers: [
|
|
"QA_ASSERT cli.targeted-reconfiguration.reset pass",
|
|
"QA_ASSERT cli.targeted-reconfiguration.skills pass",
|
|
],
|
|
},
|
|
];
|
|
const writer = createQaScriptEvidenceWriter({
|
|
artifactBase,
|
|
logFileName: "cli-onboarding.log",
|
|
primaryModel: "openai/gpt-5.6-luna",
|
|
providerMode: "mock-openai",
|
|
repoRoot: process.cwd(),
|
|
target: {
|
|
id: "cli-onboarding",
|
|
title: "CLI onboarding boundaries",
|
|
sourcePath: "scripts/e2e/qa-cli-onboarding.mjs",
|
|
},
|
|
});
|
|
|
|
const seenMarkers = new Set();
|
|
let markerCarry = "";
|
|
const collectMarkers = (chunk) => {
|
|
const text = `${markerCarry}${chunk}`;
|
|
for (const boundary of boundaries) {
|
|
for (const marker of boundary.markers ?? [boundary.marker]) {
|
|
if (text.includes(marker)) {
|
|
seenMarkers.add(marker);
|
|
}
|
|
}
|
|
}
|
|
markerCarry = text.slice(-256);
|
|
};
|
|
|
|
const startedAt = Date.now();
|
|
const child = spawn("bash", ["scripts/e2e/onboard-docker.sh"], {
|
|
env: {
|
|
...process.env,
|
|
OPENCLAW_ONBOARD_E2E_CASES:
|
|
"guided-skip-ui,local-auth-refs,local-password,remote-non-interactive,reset,skills",
|
|
},
|
|
stdio: ["inherit", "pipe", "pipe"],
|
|
});
|
|
|
|
child.stdout.on("data", (chunk) => {
|
|
writer.appendLog(chunk);
|
|
collectMarkers(chunk);
|
|
process.stdout.write(chunk);
|
|
});
|
|
child.stderr.on("data", (chunk) => {
|
|
writer.appendLog(chunk);
|
|
collectMarkers(chunk);
|
|
process.stderr.write(chunk);
|
|
});
|
|
|
|
const { code, signal } = await new Promise((resolve, reject) => {
|
|
child.once("error", reject);
|
|
child.once("close", (closeCode, closeSignal) =>
|
|
resolve({ code: closeCode, signal: closeSignal }),
|
|
);
|
|
});
|
|
const durationMs = Date.now() - startedAt;
|
|
const results = boundaries.map((boundary) => {
|
|
const markers = boundary.markers ?? [boundary.marker];
|
|
const missingMarkers = markers.filter((marker) => !seenMarkers.has(marker));
|
|
return {
|
|
id: boundary.id,
|
|
status: missingMarkers.length === 0 ? "pass" : "fail",
|
|
durationMs,
|
|
...(missingMarkers.length > 0
|
|
? { failureMessage: `missing executable assertion marker(s): ${missingMarkers.join(", ")}` }
|
|
: {}),
|
|
};
|
|
});
|
|
const logArtifact = await writer.writeLog();
|
|
const evidence = buildScriptEvidenceSummary({
|
|
artifactPaths: [logArtifact],
|
|
env: process.env,
|
|
generatedAt: new Date().toISOString(),
|
|
primaryModel: "openai/gpt-5.6-luna",
|
|
providerMode: "mock-openai",
|
|
repoRoot: process.cwd(),
|
|
runner: "script",
|
|
targets: boundaries.map((boundary) => ({
|
|
id: boundary.id,
|
|
title: boundary.title,
|
|
sourcePath: "scripts/e2e/qa-cli-onboarding.mjs",
|
|
})),
|
|
results,
|
|
});
|
|
await fs.mkdir(artifactBase, { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(artifactBase, QA_EVIDENCE_FILENAME),
|
|
`${JSON.stringify(evidence, null, 2)}\n`,
|
|
"utf8",
|
|
);
|
|
await fs.writeFile(
|
|
path.join(artifactBase, "latest-run.json"),
|
|
`${JSON.stringify({ qaEvidence: QA_EVIDENCE_FILENAME }, null, 2)}\n`,
|
|
"utf8",
|
|
);
|
|
|
|
if (signal) {
|
|
process.kill(process.pid, signal);
|
|
}
|
|
const missingBoundary = results.some((result) => result.status !== "pass");
|
|
process.exit(code === 0 && !missingBoundary ? 0 : (code ?? 1));
|