mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(qa): run plugin MCP probes from repo root
This commit is contained in:
@@ -71,6 +71,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Security/config parsing: reject unsafe OAuth/token lifetimes, retry-after delays, inbound timestamps, response body sizes, command timeout config, sandbox observer token TTLs, and gateway WebSocket calls after close.
|
||||
- Providers/media: cap local service, model, usage, queue, generated media, TTS, music, workflow polling, and provider OAuth request timers across hosted and local providers.
|
||||
- Release/CI/E2E: bound release candidate reads, beta smoke REST calls, changelog restore, kitchen-sink and bundled plugin readiness probes, secret-provider probes, Vitest routing, and mainline test flakes. (#88127, #88137, #88155, #88160)
|
||||
- Release/CI/E2E: keep Kitchen Sink live plugin MCP probes resolving source-checkout workspace packages and align the live gauntlet with current Kitchen Sink diagnostics.
|
||||
- Release/CI/E2E: run the secret-provider integration proof through the repo pnpm runner so native macOS and Windows validation use the hydrated package-manager shim.
|
||||
- Release/CI/E2E: run the Telegram desktop proof gateway through the repo pnpm runner so native macOS proof uses the hydrated package-manager shim.
|
||||
- Docs/CI: run Mintlify anchor checks through the repo pnpm runner so docs link validation works when pnpm is only available through the hydrated package-manager shim.
|
||||
|
||||
@@ -405,6 +405,15 @@ describe("qa scenario catalog", () => {
|
||||
expect(config?.expectedAdversarialDiagnostics).toContain(
|
||||
"control UI descriptor registration requires id, surface, label, and valid optional fields",
|
||||
);
|
||||
expect(config?.expectedAdversarialDiagnostics).toContain(
|
||||
"hosted media resolver registration missing resolver",
|
||||
);
|
||||
expect(config?.expectedAdversarialDiagnostics).toContain(
|
||||
"plugin must declare contracts.embeddingProviders for adapter: kitchen-sink-embedding-provider",
|
||||
);
|
||||
expect(config?.expectedAdversarialDiagnostics).toContain(
|
||||
"model catalog provider registration missing provider",
|
||||
);
|
||||
expect(
|
||||
config?.expectedAdversarialDiagnostics?.every((entry) => typeof entry === "string"),
|
||||
).toBe(true);
|
||||
|
||||
@@ -143,7 +143,7 @@ describe("qa suite runtime agent tools helpers", () => {
|
||||
path.join(repoRoot, "src", "mcp", "plugin-tools-serve.ts"),
|
||||
],
|
||||
stderr: "pipe",
|
||||
cwd: gatewayTempRoot,
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
PATH: "/usr/bin",
|
||||
OPENCLAW_KEY: "1",
|
||||
@@ -225,4 +225,37 @@ describe("qa suite runtime agent tools helpers", () => {
|
||||
expect(message).not.toContain("old stderr");
|
||||
expect(closeMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps plugin-tools MCP stderr on startup failures", async () => {
|
||||
connectMock.mockImplementationOnce(async () => {
|
||||
const stderrListener = stderrOnMock.mock.calls[0]?.[1] as
|
||||
| ((chunk: unknown) => void)
|
||||
| undefined;
|
||||
stderrListener?.(
|
||||
Buffer.from("Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@openclaw/example'\n"),
|
||||
);
|
||||
throw new Error("MCP error -32000: Connection closed");
|
||||
});
|
||||
|
||||
const error = await callPluginToolsMcp({
|
||||
env: {
|
||||
gateway: {
|
||||
tempRoot: gatewayTempRoot,
|
||||
runtimeEnv: {
|
||||
PATH: "/usr/bin",
|
||||
},
|
||||
},
|
||||
repoRoot,
|
||||
} as never,
|
||||
toolName: "plugin.echo",
|
||||
args: { text: "hello" },
|
||||
}).catch((value: unknown) => value);
|
||||
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
expect(message).toContain("MCP error -32000: Connection closed");
|
||||
expect(message).toContain("MCP stderr tail:");
|
||||
expect(message).toContain("Cannot find package '@openclaw/example'");
|
||||
expect(closeMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@ async function callPluginToolsMcp(params: {
|
||||
path.join(params.env.repoRoot, "src/mcp/plugin-tools-serve.ts"),
|
||||
],
|
||||
stderr: "pipe",
|
||||
cwd: params.env.gateway.tempRoot,
|
||||
cwd: params.env.repoRoot,
|
||||
env: transportEnv,
|
||||
});
|
||||
const stderrTail = createQaChildOutputTail(MCP_STDERR_TAIL_LIMIT);
|
||||
@@ -80,22 +80,20 @@ async function callPluginToolsMcp(params: {
|
||||
`MCP tool missing: ${params.toolName}; available tools: ${availableTools.join(", ") || "<none>"}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
return await client.callTool(
|
||||
{
|
||||
name: params.toolName,
|
||||
arguments: params.args,
|
||||
},
|
||||
undefined,
|
||||
{ timeout: MCP_REQUEST_TIMEOUT_MS },
|
||||
);
|
||||
} catch (error) {
|
||||
const tail = formatQaChildOutputTail(stderrTail, "MCP stderr").trim();
|
||||
if (!tail || !(error instanceof Error)) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`${error.message}\nMCP stderr tail:\n${tail}`, { cause: error });
|
||||
return await client.callTool(
|
||||
{
|
||||
name: params.toolName,
|
||||
arguments: params.args,
|
||||
},
|
||||
undefined,
|
||||
{ timeout: MCP_REQUEST_TIMEOUT_MS },
|
||||
);
|
||||
} catch (error) {
|
||||
const tail = formatQaChildOutputTail(stderrTail, "MCP stderr").trim();
|
||||
if (!tail || !(error instanceof Error)) {
|
||||
throw error;
|
||||
}
|
||||
throw new Error(`${error.message}\nMCP stderr tail:\n${tail}`, { cause: error });
|
||||
} finally {
|
||||
await client.close().catch(() => {});
|
||||
}
|
||||
|
||||
@@ -95,9 +95,12 @@ execution:
|
||||
- compaction provider "kitchen-sink-compaction-provider" registration missing summarize
|
||||
- context engine registration missing id
|
||||
- control UI descriptor registration requires id, surface, label, and valid optional fields
|
||||
- hosted media resolver registration missing resolver
|
||||
- "http route registration missing or invalid auth: /kitchen-sink/http-route"
|
||||
- "plugin must declare contracts.embeddingProviders for adapter: kitchen-sink-embedding-provider"
|
||||
- "plugin must own memory slot or declare contracts.memoryEmbeddingProviders for adapter: kitchen-sink-memory-embedding-provider"
|
||||
- memory prompt supplement registration missing builder
|
||||
- model catalog provider registration missing provider
|
||||
- node invoke policy registration missing commands
|
||||
- session extension registration requires namespace and description
|
||||
- session scheduler job registration requires unique id, sessionKey, and kind
|
||||
|
||||
Reference in New Issue
Block a user