test: avoid cold source SDK loading in MCP coverage (#143415)

This commit is contained in:
Peter Steinberger 2026-09-09 15:01:53 -07:00 • committed by GitHub
parent 9601bb22f3
commit 7e3a90bf5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 73 additions and 19 deletions

View file

@ -20,7 +20,10 @@ import {
triageMaintenanceRuntimeEntrypoints,
} from "../../src/infra/triage-runtime.test-support.ts";
import { nodeHostConfigRuntimeEntrypoint } from "../../src/node-host/config-runtime.test-support.ts";
import { publishedSdkBridgeEntrypoints } from "../../src/plugins/loader-sdk-bridge-artifacts.test-support.ts";
import {
mcpProviderCatalogEntrypoint,
publishedSdkBridgeEntrypoints,
} from "../../src/plugins/loader-sdk-bridge-artifacts.test-support.ts";
import { persistenceRuntimeEntrypoint } from "../../src/skills/library/persistence-runtime.test-support.ts";
import {
agentDatabaseHeldRuntimeEntrypoint,
@ -41,6 +44,7 @@ export const vitestWorkerBuildEntries = {
codeModeDescriptionRetentionEntrypoint,
...cliCompactionBackendEntrypoints,
...publishedSdkBridgeEntrypoints,
mcpProviderCatalogEntrypoint,
...Object.values(cliRecoveryEntrypoints),
...Object.values(gatewayDirectStopEntrypoints),
stateDirGatewayFixtureEntrypoint,

View file

@ -3,14 +3,18 @@ import path from "node:path";
import type { DatabaseSync } from "node:sqlite";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createTempDirTracker } from "../../test/helpers/temp-dir.js";
import { createCompiledSdkHost } from "../plugins/compiled-sdk-host.test-support.js";
import { LegacyPluginSdkResourceHost } from "../plugins/legacy-sdk-resource-host.js";
import { mcpProviderCatalogEntrypoint } from "../plugins/loader-sdk-bridge-artifacts.test-support.js";
import {
cleanupPluginLoaderFixturesForTest,
resetPluginLoaderTestStateForTest,
useNoBundledPlugins,
writePlugin,
} from "../plugins/loader.test-fixtures.js";
import { getPluginModuleLoaderStats } from "../plugins/plugin-module-loader-cache.js";
import { markPluginRegistryActive } from "../plugins/registry-lifecycle.js";
import { withPluginRuntimeRegistryScope } from "../plugins/runtime/gateway-request-scope.js";
import { acquireStandalonePluginToolRegistry } from "../plugins/tools.js";
@ -19,6 +23,20 @@ import { createCodexSupervisionToolsMcpServer } from "./codex-supervision-tools-
import { createToolsMcpServer, serveRegisteredToolsMcpServer } from "./tools-stdio-server.js";
let sequence = 0;
const sdkHostDirs = createTempDirTracker();
let sdkHost: string | undefined;
let beforeLoad: ReturnType<typeof getPluginModuleLoaderStats>;
beforeAll(() => {
sdkHost = createCompiledSdkHost(mcpProviderCatalogEntrypoint, (prefix) =>
sdkHostDirs.make(prefix),
);
});
beforeEach(() => {
if (sdkHost) {
vi.stubEnv("OPENCLAW_DEV_SOURCE_ROOT", sdkHost);
}
beforeLoad = getPluginModuleLoaderStats();
});
function nativePlugin(options: { failDisposal?: boolean; abortSdk?: boolean } = {}) {
useNoBundledPlugins();
const key = `__mcp_registration_native_${sequence++}`;
@ -117,10 +135,21 @@ module.exports = { id: "mcp-native", register(api) {
}
afterEach(() => {
vi.restoreAllMocks();
resetPluginLoaderTestStateForTest();
try {
if (sdkHost) {
const afterLoad = getPluginModuleLoaderStats();
expect(afterLoad.nativeHits).toBeGreaterThan(beforeLoad.nativeHits);
expect(afterLoad.sourceTransformForced).toBe(beforeLoad.sourceTransformForced);
expect(afterLoad.sourceTransformFallbacks).toBe(beforeLoad.sourceTransformFallbacks);
}
} finally {
vi.restoreAllMocks();
resetPluginLoaderTestStateForTest();
vi.unstubAllEnvs();
}
});
afterAll(cleanupPluginLoaderFixturesForTest);
afterAll(sdkHostDirs.cleanup);
function causes(error: unknown): unknown[] {
if (error instanceof AggregateError) {

View file

@ -0,0 +1,28 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { resolveRuntimeWorkerUrl } from "../infra/runtime-worker-url.js";
/** Keep native SDK consumers on the invocation's verified, current-source graph. */
export function createCompiledSdkHost(
entrypoint: Parameters<typeof resolveRuntimeWorkerUrl>[0],
makeTempDir: (prefix: string) => string,
): string | undefined {
const artifact = fileURLToPath(resolveRuntimeWorkerUrl(entrypoint));
// Standalone and watch-mode Vitest deliberately retain source declarations.
if (path.extname(artifact) !== ".js") {
return undefined;
}
const hostRoot = makeTempDir("openclaw-sdk-host-");
fs.cpSync(path.dirname(path.dirname(artifact)), path.join(hostRoot, "dist"), {
recursive: true,
});
fs.copyFileSync(
path.resolve(import.meta.dirname, "../../package.json"),
path.join(hostRoot, "package.json"),
);
fs.mkdirSync(path.join(hostRoot, "src"));
fs.mkdirSync(path.join(hostRoot, "extensions"));
fs.symlinkSync(path.resolve("node_modules"), path.join(hostRoot, "node_modules"), "junction");
return hostRoot;
}

View file

@ -1,5 +1,10 @@
// Published plugin compatibility uses the same compiled SDK graph as native execution.
const currentModuleUrl = import.meta.url;
export const mcpProviderCatalogEntrypoint = {
currentModuleUrl,
sourceWorkerName: "../plugin-sdk/provider-catalog-runtime",
distWorkerPath: "plugin-sdk/provider-catalog-runtime.js",
} as const;
export const publishedSdkBridgeEntrypoints = [
{
currentModuleUrl,

View file

@ -1,10 +1,9 @@
/** Verifies plugin loader behavior for native module loading and resolver hooks. */
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createTempDirTracker } from "../../test/helpers/temp-dir.js";
import { resolveRuntimeWorkerUrl } from "../infra/runtime-worker-url.js";
import { createCompiledSdkHost } from "./compiled-sdk-host.test-support.js";
import { publishedSdkBridgeEntrypoints } from "./loader-sdk-bridge-artifacts.test-support.js";
import { loadOpenClawPlugins } from "./loader.js";
import { resetPluginCache } from "./plugin-cache.js";
@ -199,20 +198,9 @@ describe("createPluginModuleLoader", () => {
it("loads published pre-split SDK bridge imports (doctor repair, WhatsApp ack, Slack render)", () => {
const pluginRoot = writePreSplitSdkBridgeConsumerFixture();
const [entrypoint] = publishedSdkBridgeEntrypoints;
const artifact = fileURLToPath(resolveRuntimeWorkerUrl(entrypoint));
const hasCompiledSdk = path.extname(artifact) === ".js";
const hostRoot = createCompiledSdkHost(entrypoint, (prefix) => tempDirs.make(prefix));
const hasCompiledSdk = hostRoot !== undefined;
if (hasCompiledSdk) {
const hostRoot = tempDirs.make("openclaw-sdk-bridge-host-");
fs.cpSync(path.dirname(path.dirname(artifact)), path.join(hostRoot, "dist"), {
recursive: true,
});
fs.copyFileSync(
path.resolve(import.meta.dirname, "../../package.json"),
path.join(hostRoot, "package.json"),
);
fs.mkdirSync(path.join(hostRoot, "src"));
fs.mkdirSync(path.join(hostRoot, "extensions"));
fs.symlinkSync(path.resolve("node_modules"), path.join(hostRoot, "node_modules"), "junction");
vi.stubEnv("OPENCLAW_DEV_SOURCE_ROOT", hostRoot);
vi.stubEnv("OPENCLAW_BUNDLED_PLUGINS_DIR", path.join(hostRoot, "extensions"));
} else {