improve(qa): execute runtime scenarios through Docker (#99705)

* test(qa): run Docker runtime scenarios end to end

* test(qa): keep plugin lifecycle probe runtime-only
This commit is contained in:
Dallin Romney
2026-07-03 18:13:28 -07:00
committed by GitHub
parent bc802ceee1
commit ab9e233d02
8 changed files with 98 additions and 28 deletions
+26 -4
View File
@@ -242,16 +242,38 @@ describe("qa scenario catalog", () => {
expect(readQaScenarioById("openai-web-search-minimal").coverage?.secondary).toContain(
"runtime.reasoning-and-cache-controls",
);
expect(
readQaScenarioById("openai-web-search-native-assertions").coverage?.secondary,
).toEqual(
expect.arrayContaining(["web-search.openai-native-web-search", "plugins.web-search-and-fetch"]),
expect(readQaScenarioById("openai-web-search-native-assertions").coverage?.secondary).toEqual(
expect.arrayContaining([
"web-search.openai-native-web-search",
"plugins.web-search-and-fetch",
]),
);
expect(readQaScenarioById("openwebui-openai-compatible").coverage?.secondary).toEqual(
expect.arrayContaining(["gateway.openai-compatible-apis", "runtime.hosted-provider-turns"]),
);
});
it("routes Docker runtime scenarios through the shared lane adapter", () => {
const scenarioLanes = [
["openai-compatible-chat-tools", "openai-chat-tools"],
["openai-web-search-minimal", "openai-web-search-minimal"],
["openai-web-search-native-assertions", "openai-web-search-minimal"],
["openwebui-openai-compatible", "openwebui"],
["plugin-lifecycle-probe", "plugin-lifecycle-matrix"],
["packaged-bundled-plugin-install-uninstall", "bundled-plugin-install-uninstall"],
] as const;
for (const [scenarioId, lane] of scenarioLanes) {
const execution = readQaScenarioById(scenarioId).execution;
expect(execution.kind).toBe("script");
if (execution.kind !== "script") {
throw new Error(`expected script scenario, got ${execution.kind}`);
}
expect(execution.path).toBe("test/e2e/qa-lab/runtime/docker-e2e-lane.ts");
expect(execution.args).toStrictEqual(["--lane", lane]);
}
});
it("loads runtime parity tier metadata for first-hour and soak lanes", () => {
const firstHour = readQaScenarioById("runtime-first-hour-20-turn");
const soak = readQaScenarioById("runtime-soak-100-turn");
@@ -20,9 +20,17 @@ scenario:
- docs/cli/plugins.md
- docs/help/testing.md
codeRefs:
- scripts/e2e/bundled-plugin-install-uninstall-docker.sh
- scripts/e2e/lib/bundled-plugin-install-uninstall/sweep.sh
- scripts/e2e/lib/bundled-plugin-install-uninstall/probe.mjs
- scripts/e2e/lib/bundled-plugin-install-uninstall/runtime-smoke.mjs
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/scripts/bundled-plugin-install-uninstall-probe.test.ts
execution:
kind: vitest
path: test/scripts/bundled-plugin-install-uninstall-probe.test.ts
summary: Vitest coverage for packaged bundled plugin root discovery and install/uninstall record assertions.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the packaged bundled-plugin Docker sweep and asserts install, runtime load, and uninstall evidence for each selected plugin.
timeoutMs: 7200000
args:
- --lane
- bundled-plugin-install-uninstall
@@ -8,18 +8,26 @@ scenario:
- plugins.lifecycle
- cli.plugin-validation-repair
- plugins.setup-flows
objective: Exercise strict plugin load/uninstall proof parsing through QA Lab evidence.
objective: Exercise packaged plugin install, inspect, disable, enable, update, downgrade, and uninstall behavior in a clean Docker runtime.
successCriteria:
- Enabled loaded plugin inspect JSON is accepted as proof.
- Pending or missing inspect JSON is rejected instead of treated as loaded.
- Malformed config during uninstall proof fails with a bounded diagnostic.
- A clean container installs the candidate OpenClaw package and fixture plugin package.
- Runtime inspect reports the installed plugin as enabled and loaded.
- Disable and enable commands persist the expected plugin state.
- Update and downgrade commands replace the installed plugin version while preserving the npm project root.
- Forced uninstall succeeds after installed plugin code is removed and emits a bounded resource summary.
docsRefs:
- docs/plugins/manifest.md
- docs/cli/plugins.md
- docs/concepts/qa-e2e-automation.md
codeRefs:
- scripts/e2e/plugin-lifecycle-matrix-docker.sh
- test/e2e/qa-lab/plugins/plugin-lifecycle-probe-runtime.ts
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/e2e/qa-lab/plugins/plugin-lifecycle-probe.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/plugins/plugin-lifecycle-probe.e2e.test.ts
summary: Vitest coverage for plugin lifecycle proof parsing.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the packaged plugin lifecycle matrix in a clean Docker runtime and asserts each emitted lifecycle phase.
args:
- --lane
- plugin-lifecycle-matrix
@@ -21,8 +21,12 @@ scenario:
- scripts/e2e/lib/openai-chat-tools/client.mjs
- scripts/e2e/lib/openai-chat-tools/write-config.mjs
- scripts/e2e/openai-chat-tools-docker.sh
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts
summary: Vitest coverage for OpenAI-compatible chat-completions tool-call API behavior.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the OpenAI chat-tools Docker E2E lane against a real Gateway and the OpenAI-compatible chat-completions API.
args:
- --lane
- openai-chat-tools
@@ -21,8 +21,12 @@ scenario:
codeRefs:
- scripts/e2e/lib/openai-web-search-minimal/client.mjs
- scripts/e2e/openai-web-search-minimal-docker.sh
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts
summary: Vitest coverage for OpenAI web_search minimal-reasoning success and rejection validation.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the OpenAI web_search Docker E2E lane through a real Gateway with a container-local OpenAI Responses mock.
args:
- --lane
- openai-web-search-minimal
@@ -22,8 +22,13 @@ scenario:
codeRefs:
- scripts/e2e/lib/openai-web-search-minimal/assertions.mjs
- scripts/e2e/lib/openai-web-search-minimal/mock-server.mjs
- scripts/e2e/openai-web-search-minimal-docker.sh
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts
summary: Vitest coverage for native OpenAI web_search request-log assertions.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the OpenAI web_search Docker E2E lane and asserts the emitted native Responses request log.
args:
- --lane
- openai-web-search-minimal
@@ -20,8 +20,12 @@ scenario:
codeRefs:
- scripts/e2e/openwebui-probe.mjs
- scripts/e2e/openwebui-docker.sh
- test/e2e/qa-lab/runtime/docker-e2e-lane.ts
- test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts
summary: Vitest coverage for OpenWebUI model and chat-completions probe behavior.
kind: script
path: test/e2e/qa-lab/runtime/docker-e2e-lane.ts
summary: Runs the OpenWebUI Docker topology and probes its OpenAI-compatible model and chat APIs against OpenClaw.
args:
- --lane
- openwebui
@@ -6,9 +6,24 @@ import os from "node:os";
import path from "node:path";
import { readPluginInstallRecords } from "../../../../scripts/e2e/lib/plugin-index-sqlite.mjs";
import { resolveWindowsTaskkillPath } from "../../../../scripts/lib/windows-taskkill.mjs";
import { createTempDirTracker } from "../../../helpers/temp-dir.js";
const tempDirs = createTempDirTracker();
// The Docker entrypoint runs without Vitest installed, so keep cleanup local to this runtime probe.
const tempDirs = (() => {
const dirs = new Set<string>();
return {
make(prefix: string): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
dirs.add(dir);
return dir;
},
cleanup(): void {
for (const dir of dirs) {
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
}
dirs.clear();
},
};
})();
type ProbeEnv = Pick<NodeJS.ProcessEnv, "HOME" | "OPENCLAW_CONFIG_PATH" | "OPENCLAW_STATE_DIR">;