mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix(qa): pass Mantis desktop runtime env
This commit is contained in:
@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Gateway/config: stop Gateway startup and hot reload from auto-restoring invalid config; invalid config now fails closed and `openclaw doctor --fix` owns last-known-good repair.
|
||||
- Gateway/performance: lazy-load early runtime discovery and shutdown-hook helpers, defer maintenance timers until after readiness, and trim duplicate plugin auto-enable work during Gateway startup.
|
||||
- QA/Mantis: add a `pnpm openclaw qa mantis discord-smoke` runner and manual GitHub workflow that verify the Mantis Discord bot can see the configured guild/channel, post a smoke message, add a reaction, and upload artifacts.
|
||||
- QA/Mantis: pass the runtime env through desktop-browser Crabbox and artifact-copy child commands, so embedded Mantis callers can provide Crabbox credentials without mutating the parent process. Thanks @vincentkoc.
|
||||
- QA/Slack: add a Slack live transport QA runner with canary and mention-gating coverage for the private bot-to-bot harness. Thanks @vincentkoc.
|
||||
- Gateway/performance: lazy-load the heavy cron runtime after the rest of Gateway startup, defer restart-sentinel refresh after readiness, and let the Gateway startup benchmark write per-run V8 CPU profiles with `--cpu-prof-dir`.
|
||||
- Gateway/performance: keep raw channel-config schema parsing from discovering bundled plugin runtime metadata, and add `pnpm gateway:watch --benchmark-no-force` for profiling startup without the default port cleanup.
|
||||
|
||||
@@ -18,43 +18,51 @@ describe("mantis desktop browser smoke runtime", () => {
|
||||
it("leases a desktop box, runs a visible browser, copies artifacts, and stops on pass", async () => {
|
||||
await fs.mkdir(path.join(repoRoot, "qa-artifacts"), { recursive: true });
|
||||
await fs.writeFile(path.join(repoRoot, "qa-artifacts", "timeline.html"), "<h1>Mantis</h1>");
|
||||
const commands: { args: readonly string[]; command: string }[] = [];
|
||||
const runner = vi.fn(async (command: string, args: readonly string[]) => {
|
||||
commands.push({ command, args });
|
||||
if (command === "/tmp/crabbox" && args[0] === "warmup") {
|
||||
return { stdout: "ready lease cbx_abc123\n", stderr: "" };
|
||||
}
|
||||
if (command === "/tmp/crabbox" && args[0] === "inspect") {
|
||||
return {
|
||||
stdout: `${JSON.stringify({
|
||||
host: "203.0.113.10",
|
||||
id: "cbx_abc123",
|
||||
provider: "hetzner",
|
||||
slug: "brisk-mantis",
|
||||
sshKey: "/tmp/key",
|
||||
sshPort: "2222",
|
||||
sshUser: "crabbox",
|
||||
state: "active",
|
||||
})}\n`,
|
||||
stderr: "",
|
||||
};
|
||||
}
|
||||
if (command === "rsync") {
|
||||
const outputDir = args.at(-1);
|
||||
expect(outputDir).toBeTypeOf("string");
|
||||
await fs.mkdir(outputDir as string, { recursive: true });
|
||||
await fs.writeFile(path.join(outputDir as string, "desktop-browser-smoke.png"), "png");
|
||||
await fs.writeFile(path.join(outputDir as string, "remote-metadata.json"), "{}\n");
|
||||
await fs.writeFile(path.join(outputDir as string, "chrome.log"), "chrome\n");
|
||||
const commands: { args: readonly string[]; command: string; env?: NodeJS.ProcessEnv }[] = [];
|
||||
const runtimeEnv = {
|
||||
PATH: process.env.PATH,
|
||||
CRABBOX_COORDINATOR_TOKEN: "runtime-token",
|
||||
OPENCLAW_MANTIS_CRABBOX_PROVIDER: "hetzner",
|
||||
};
|
||||
const runner = vi.fn(
|
||||
async (command: string, args: readonly string[], options: { env?: NodeJS.ProcessEnv }) => {
|
||||
commands.push({ command, args, env: options.env });
|
||||
if (command === "/tmp/crabbox" && args[0] === "warmup") {
|
||||
return { stdout: "ready lease cbx_abc123\n", stderr: "" };
|
||||
}
|
||||
if (command === "/tmp/crabbox" && args[0] === "inspect") {
|
||||
return {
|
||||
stdout: `${JSON.stringify({
|
||||
host: "203.0.113.10",
|
||||
id: "cbx_abc123",
|
||||
provider: "hetzner",
|
||||
slug: "brisk-mantis",
|
||||
sshKey: "/tmp/key",
|
||||
sshPort: "2222",
|
||||
sshUser: "crabbox",
|
||||
state: "active",
|
||||
})}\n`,
|
||||
stderr: "",
|
||||
};
|
||||
}
|
||||
if (command === "rsync") {
|
||||
const outputDir = args.at(-1);
|
||||
expect(outputDir).toBeTypeOf("string");
|
||||
await fs.mkdir(outputDir as string, { recursive: true });
|
||||
await fs.writeFile(path.join(outputDir as string, "desktop-browser-smoke.png"), "png");
|
||||
await fs.writeFile(path.join(outputDir as string, "remote-metadata.json"), "{}\n");
|
||||
await fs.writeFile(path.join(outputDir as string, "chrome.log"), "chrome\n");
|
||||
return { stdout: "", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
}
|
||||
return { stdout: "", stderr: "" };
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const result = await runMantisDesktopBrowserSmoke({
|
||||
browserUrl: "https://openclaw.ai/docs",
|
||||
commandRunner: runner,
|
||||
crabboxBin: "/tmp/crabbox",
|
||||
env: runtimeEnv,
|
||||
htmlFile: "qa-artifacts/timeline.html",
|
||||
now: () => new Date("2026-05-04T12:00:00.000Z"),
|
||||
outputDir: ".artifacts/qa-e2e/mantis/desktop-browser-test",
|
||||
@@ -69,6 +77,7 @@ describe("mantis desktop browser smoke runtime", () => {
|
||||
["rsync", "-az"],
|
||||
["/tmp/crabbox", "stop"],
|
||||
]);
|
||||
expect(commands.every((entry) => entry.env === runtimeEnv)).toBe(true);
|
||||
const rsyncArgs = commands.find((entry) => entry.command === "rsync")?.args ?? [];
|
||||
expect(rsyncArgs).not.toContain("--delete");
|
||||
expect(rsyncArgs).toEqual(
|
||||
|
||||
@@ -303,12 +303,13 @@ async function runCommand(params: {
|
||||
args: readonly string[];
|
||||
command: string;
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
runner: CommandRunner;
|
||||
stdio?: "inherit" | "pipe";
|
||||
}) {
|
||||
return params.runner(params.command, params.args, {
|
||||
cwd: params.cwd,
|
||||
env: process.env,
|
||||
env: params.env,
|
||||
stdio: params.stdio ?? "pipe",
|
||||
});
|
||||
}
|
||||
@@ -316,6 +317,7 @@ async function runCommand(params: {
|
||||
async function warmupCrabbox(params: {
|
||||
crabboxBin: string;
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
idleTimeout: string;
|
||||
machineClass: string;
|
||||
provider: string;
|
||||
@@ -338,6 +340,7 @@ async function warmupCrabbox(params: {
|
||||
params.ttl,
|
||||
],
|
||||
cwd: params.cwd,
|
||||
env: params.env,
|
||||
runner: params.runner,
|
||||
stdio: "inherit",
|
||||
});
|
||||
@@ -351,6 +354,7 @@ async function warmupCrabbox(params: {
|
||||
async function inspectCrabbox(params: {
|
||||
crabboxBin: string;
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
leaseId: string;
|
||||
provider: string;
|
||||
runner: CommandRunner;
|
||||
@@ -359,6 +363,7 @@ async function inspectCrabbox(params: {
|
||||
command: params.crabboxBin,
|
||||
args: ["inspect", "--provider", params.provider, "--id", params.leaseId, "--json"],
|
||||
cwd: params.cwd,
|
||||
env: params.env,
|
||||
runner: params.runner,
|
||||
});
|
||||
return JSON.parse(result.stdout) as CrabboxInspect;
|
||||
@@ -366,6 +371,7 @@ async function inspectCrabbox(params: {
|
||||
|
||||
async function copyRemoteArtifacts(params: {
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
inspect: CrabboxInspect;
|
||||
outputDir: string;
|
||||
remoteOutputDir: string;
|
||||
@@ -401,6 +407,7 @@ async function copyRemoteArtifacts(params: {
|
||||
`${params.outputDir}/`,
|
||||
],
|
||||
cwd: params.cwd,
|
||||
env: params.env,
|
||||
runner: params.runner,
|
||||
});
|
||||
}
|
||||
@@ -408,6 +415,7 @@ async function copyRemoteArtifacts(params: {
|
||||
async function stopCrabbox(params: {
|
||||
crabboxBin: string;
|
||||
cwd: string;
|
||||
env: NodeJS.ProcessEnv;
|
||||
leaseId: string;
|
||||
provider: string;
|
||||
runner: CommandRunner;
|
||||
@@ -416,6 +424,7 @@ async function stopCrabbox(params: {
|
||||
command: params.crabboxBin,
|
||||
args: ["stop", "--provider", params.provider, params.leaseId],
|
||||
cwd: params.cwd,
|
||||
env: params.env,
|
||||
runner: params.runner,
|
||||
stdio: "inherit",
|
||||
});
|
||||
@@ -471,6 +480,7 @@ export async function runMantisDesktopBrowserSmoke(
|
||||
(await warmupCrabbox({
|
||||
crabboxBin,
|
||||
cwd: repoRoot,
|
||||
env,
|
||||
idleTimeout,
|
||||
machineClass,
|
||||
provider,
|
||||
@@ -480,6 +490,7 @@ export async function runMantisDesktopBrowserSmoke(
|
||||
const inspected = await inspectCrabbox({
|
||||
crabboxBin,
|
||||
cwd: repoRoot,
|
||||
env,
|
||||
leaseId,
|
||||
provider,
|
||||
runner,
|
||||
@@ -500,11 +511,13 @@ export async function runMantisDesktopBrowserSmoke(
|
||||
renderRemoteScript({ browserUrl, htmlBase64, remoteOutputDir }),
|
||||
],
|
||||
cwd: repoRoot,
|
||||
env,
|
||||
runner,
|
||||
stdio: "inherit",
|
||||
});
|
||||
await copyRemoteArtifacts({
|
||||
cwd: repoRoot,
|
||||
env,
|
||||
inspect: inspected,
|
||||
outputDir,
|
||||
remoteOutputDir,
|
||||
@@ -582,7 +595,7 @@ export async function runMantisDesktopBrowserSmoke(
|
||||
await fs.writeFile(reportPath, renderReport(summary), "utf8");
|
||||
}
|
||||
if (summary?.status === "pass" && createdLease && leaseId && !keepLease) {
|
||||
await stopCrabbox({ crabboxBin, cwd: repoRoot, leaseId, provider, runner });
|
||||
await stopCrabbox({ crabboxBin, cwd: repoRoot, env, leaseId, provider, runner });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user