web: fix args-object React crash; e2e plugin-contract scenario
This commit is contained in:
+107
-90
@@ -19,14 +19,14 @@ import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { startFakeGitLab } from "./fake-gitlab.mjs";
|
||||
import {
|
||||
DAEMON_DIR,
|
||||
REPO_ROOT,
|
||||
Results,
|
||||
TEST_TOKEN,
|
||||
WEB_DIST,
|
||||
ensureWebDist,
|
||||
freePort,
|
||||
startDaemon,
|
||||
DAEMON_DIR,
|
||||
REPO_ROOT,
|
||||
Results,
|
||||
TEST_TOKEN,
|
||||
WEB_DIST,
|
||||
ensureWebDist,
|
||||
freePort,
|
||||
startDaemon,
|
||||
} from "./lib.mjs";
|
||||
|
||||
import { run as auth } from "./scenarios/auth.mjs";
|
||||
@@ -41,16 +41,16 @@ import { run as pluginContract } from "./scenarios/plugin-contract.mjs";
|
||||
import { run as resilience } from "./scenarios/resilience.mjs";
|
||||
|
||||
const SCENARIOS = [
|
||||
["auth", auth],
|
||||
["web-dist", webDist],
|
||||
["agent-lifecycle", agentLifecycle],
|
||||
["replay", replay],
|
||||
["prompt-routing", promptRouting],
|
||||
["session-list", sessionList],
|
||||
["gitlab", gitlab],
|
||||
["spawn-validation", spawnValidation],
|
||||
["plugin-contract", pluginContract],
|
||||
["resilience", resilience], // last: SIGKILLs and reboots the daemon
|
||||
["auth", auth],
|
||||
["web-dist", webDist],
|
||||
["agent-lifecycle", agentLifecycle],
|
||||
["replay", replay],
|
||||
["prompt-routing", promptRouting],
|
||||
["session-list", sessionList],
|
||||
["gitlab", gitlab],
|
||||
["spawn-validation", spawnValidation],
|
||||
["plugin-contract", pluginContract],
|
||||
["resilience", resilience], // last: SIGKILLs and reboots the daemon
|
||||
];
|
||||
|
||||
const r = new Results();
|
||||
@@ -60,92 +60,109 @@ let tmpDir = null;
|
||||
let cleanedUp = false;
|
||||
|
||||
async function cleanup() {
|
||||
if (cleanedUp) return;
|
||||
cleanedUp = true;
|
||||
if (daemon) await daemon.stop("SIGKILL");
|
||||
if (fakeGitLab) fakeGitLab.close();
|
||||
if (tmpDir && process.env.LVMH_E2E_KEEP !== "1") {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
} else if (tmpDir) {
|
||||
console.log(`(kept harness artifacts: ${tmpDir})`);
|
||||
}
|
||||
if (cleanedUp) return;
|
||||
cleanedUp = true;
|
||||
if (daemon) await daemon.stop("SIGKILL");
|
||||
if (fakeGitLab) fakeGitLab.close();
|
||||
if (tmpDir && process.env.LVMH_E2E_KEEP !== "1") {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
} else if (tmpDir) {
|
||||
console.log(`(kept harness artifacts: ${tmpDir})`);
|
||||
}
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => {
|
||||
void cleanup().finally(() => process.exit(130));
|
||||
void cleanup().finally(() => process.exit(130));
|
||||
});
|
||||
process.on("SIGTERM", () => {
|
||||
void cleanup().finally(() => process.exit(143));
|
||||
void cleanup().finally(() => process.exit(143));
|
||||
});
|
||||
|
||||
async function main() {
|
||||
console.log("=== lvmh e2e integration ===");
|
||||
const built = ensureWebDist();
|
||||
console.log(`web dist: ${built ? "built now" : "reused"} ${path.relative(REPO_ROOT, WEB_DIST)}`);
|
||||
console.log("=== lvmh e2e integration ===");
|
||||
const built = ensureWebDist();
|
||||
console.log(
|
||||
`web dist: ${built ? "built now" : "reused"} ${path.relative(REPO_ROOT, WEB_DIST)}`,
|
||||
);
|
||||
|
||||
fs.mkdirSync(path.join(REPO_ROOT, ".pi", "scratch"), { recursive: true });
|
||||
tmpDir = fs.mkdtempSync(path.join(REPO_ROOT, ".pi", "scratch", "e2e-"));
|
||||
const dbPath = path.join(tmpDir, "lvmh.db");
|
||||
const logPath = path.join(tmpDir, "daemon.log");
|
||||
fs.mkdirSync(path.join(REPO_ROOT, ".pi", "scratch"), { recursive: true });
|
||||
tmpDir = fs.mkdtempSync(path.join(REPO_ROOT, ".pi", "scratch", "e2e-"));
|
||||
const dbPath = path.join(tmpDir, "lvmh.db");
|
||||
const logPath = path.join(tmpDir, "daemon.log");
|
||||
|
||||
fakeGitLab = await startFakeGitLab();
|
||||
const port = await freePort();
|
||||
const addr = `127.0.0.1:${port}`;
|
||||
const daemonEnv = {
|
||||
LVMH_TOKEN: TEST_TOKEN,
|
||||
LVMH_DB: dbPath,
|
||||
GITLAB_BASE_URL: fakeGitLab.url,
|
||||
LVMH_REPO_DIR: path.join(tmpDir, "repos"),
|
||||
LVMH_CONTAINER_LVMH_URL: `ws://${addr}/agent/ws`,
|
||||
LVMH_WORKER_DOCKERFILE: path.join(tmpDir, "absent-worker.Dockerfile"),
|
||||
};
|
||||
const boot = () => startDaemon({ addr, dbPath, webdist: WEB_DIST, logPath, env: daemonEnv });
|
||||
daemon = await boot();
|
||||
fakeGitLab = await startFakeGitLab();
|
||||
const port = await freePort();
|
||||
const addr = `127.0.0.1:${port}`;
|
||||
const daemonEnv = {
|
||||
LVMH_TOKEN: TEST_TOKEN,
|
||||
LVMH_DB: dbPath,
|
||||
GITLAB_BASE_URL: fakeGitLab.url,
|
||||
LVMH_REPO_DIR: path.join(tmpDir, "repos"),
|
||||
LVMH_CONTAINER_LVMH_URL: `ws://${addr}/agent/ws`,
|
||||
LVMH_WORKER_DOCKERFILE: path.join(tmpDir, "absent-worker.Dockerfile"),
|
||||
};
|
||||
const boot = () =>
|
||||
startDaemon({ addr, dbPath, webdist: WEB_DIST, logPath, env: daemonEnv });
|
||||
daemon = await boot();
|
||||
|
||||
console.log(`daemon: ${daemon.baseUrl} (go run . in ${path.relative(REPO_ROOT, DAEMON_DIR)}, db ${dbPath})`);
|
||||
console.log(`fake gitlab: ${fakeGitLab.url}`);
|
||||
console.log(
|
||||
`daemon: ${daemon.baseUrl} (go run . in ${path.relative(REPO_ROOT, DAEMON_DIR)}, db ${dbPath})`,
|
||||
);
|
||||
console.log(`fake gitlab: ${fakeGitLab.url}`);
|
||||
|
||||
const ctx = {
|
||||
r,
|
||||
state: {},
|
||||
base: daemon.baseUrl,
|
||||
token: TEST_TOKEN,
|
||||
agentUrl: daemon.agentUrl,
|
||||
webUrl: daemon.webUrl,
|
||||
gitlab: fakeGitLab,
|
||||
restartDaemon: async () => {
|
||||
await daemon.stop("SIGKILL");
|
||||
daemon = await boot();
|
||||
},
|
||||
};
|
||||
const ctx = {
|
||||
r,
|
||||
state: {},
|
||||
base: daemon.baseUrl,
|
||||
token: TEST_TOKEN,
|
||||
agentUrl: daemon.agentUrl,
|
||||
webUrl: daemon.webUrl,
|
||||
gitlab: fakeGitLab,
|
||||
restartDaemon: async () => {
|
||||
await daemon.stop("SIGKILL");
|
||||
daemon = await boot();
|
||||
},
|
||||
};
|
||||
|
||||
for (const [name, scenario] of SCENARIOS) {
|
||||
r.group(name);
|
||||
try {
|
||||
await scenario(ctx);
|
||||
} catch (err) {
|
||||
r.check(`${name}: scenario crashed`, false, String(err?.stack ?? err));
|
||||
const log = fs.existsSync(logPath) ? fs.readFileSync(logPath, "utf8").split("\n").slice(-15).join("\n") : "";
|
||||
if (log) console.log(` daemon.log tail:\n${log.split("\n").map((l) => " " + l).join("\n")}`);
|
||||
}
|
||||
}
|
||||
for (const [name, scenario] of SCENARIOS) {
|
||||
r.group(name);
|
||||
try {
|
||||
await scenario(ctx);
|
||||
} catch (err) {
|
||||
r.check(`${name}: scenario crashed`, false, String(err?.stack ?? err));
|
||||
const log = fs.existsSync(logPath)
|
||||
? fs.readFileSync(logPath, "utf8").split("\n").slice(-15).join("\n")
|
||||
: "";
|
||||
if (log)
|
||||
console.log(
|
||||
` daemon.log tail:\n${log
|
||||
.split("\n")
|
||||
.map((l) => " " + l)
|
||||
.join("\n")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const { ok, fail, xfail, xpass, total } = r.summary();
|
||||
console.log("\n──────────────────────────────");
|
||||
console.log(`passed ${ok} / ${total} failed ${fail} xfail ${xfail} (known bugs) xpass ${xpass}`);
|
||||
if (fail > 0) {
|
||||
console.log("failed checks:");
|
||||
for (const e of r.entries.filter((e) => e.status === "fail")) {
|
||||
console.log(` [${e.scenario}] ${e.name}${e.detail ? " — " + e.detail : ""}`);
|
||||
}
|
||||
}
|
||||
console.log(`RESULT: ${fail === 0 ? "GREEN" : "RED"}`);
|
||||
process.exitCode = fail === 0 ? 0 : 1;
|
||||
const { ok, fail, xfail, xpass, total } = r.summary();
|
||||
console.log("\n──────────────────────────────");
|
||||
console.log(
|
||||
`passed ${ok} / ${total} failed ${fail} xfail ${xfail} (known bugs) xpass ${xpass}`,
|
||||
);
|
||||
if (fail > 0) {
|
||||
console.log("failed checks:");
|
||||
for (const e of r.entries.filter((e) => e.status === "fail")) {
|
||||
console.log(
|
||||
` [${e.scenario}] ${e.name}${e.detail ? " — " + e.detail : ""}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
console.log(`RESULT: ${fail === 0 ? "GREEN" : "RED"}`);
|
||||
process.exitCode = fail === 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((err) => {
|
||||
console.error("harness crashed:", err);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(() => cleanup());
|
||||
.catch((err) => {
|
||||
console.error("harness crashed:", err);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(() => cleanup());
|
||||
|
||||
Reference in New Issue
Block a user