mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 06:00:20 +00:00
test: dedupe plugin runtime utility suites
This commit is contained in:
@@ -34,17 +34,27 @@ afterEach(async () => {
|
||||
await tempHarness.cleanup();
|
||||
});
|
||||
|
||||
async function withBundleHomeEnv<T>(
|
||||
prefix: string,
|
||||
run: (params: { homeDir: string; workspaceDir: string }) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const env = captureEnv(["HOME", "USERPROFILE", "OPENCLAW_HOME", "OPENCLAW_STATE_DIR"]);
|
||||
try {
|
||||
const homeDir = await tempHarness.createTempDir(`${prefix}-home-`);
|
||||
const workspaceDir = await tempHarness.createTempDir(`${prefix}-workspace-`);
|
||||
process.env.HOME = homeDir;
|
||||
process.env.USERPROFILE = homeDir;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
return await run({ homeDir, workspaceDir });
|
||||
} finally {
|
||||
env.restore();
|
||||
}
|
||||
}
|
||||
|
||||
describe("loadEnabledBundleMcpConfig", () => {
|
||||
it("loads enabled Claude bundle MCP config and absolutizes relative args", async () => {
|
||||
const env = captureEnv(["HOME", "USERPROFILE", "OPENCLAW_HOME", "OPENCLAW_STATE_DIR"]);
|
||||
try {
|
||||
const homeDir = await tempHarness.createTempDir("openclaw-bundle-mcp-home-");
|
||||
const workspaceDir = await tempHarness.createTempDir("openclaw-bundle-mcp-workspace-");
|
||||
process.env.HOME = homeDir;
|
||||
process.env.USERPROFILE = homeDir;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
|
||||
await withBundleHomeEnv("openclaw-bundle-mcp", async ({ homeDir, workspaceDir }) => {
|
||||
const { pluginRoot, serverPath } = await createBundleProbePlugin(homeDir);
|
||||
|
||||
const config: OpenClawConfig = {
|
||||
@@ -76,21 +86,11 @@ describe("loadEnabledBundleMcpConfig", () => {
|
||||
normalizePathForAssertion(resolvedServerPath),
|
||||
);
|
||||
await expectResolvedPathEqual(loadedServer.cwd, resolvedPluginRoot);
|
||||
} finally {
|
||||
env.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("merges inline bundle MCP servers and skips disabled bundles", async () => {
|
||||
const env = captureEnv(["HOME", "USERPROFILE", "OPENCLAW_HOME", "OPENCLAW_STATE_DIR"]);
|
||||
try {
|
||||
const homeDir = await tempHarness.createTempDir("openclaw-bundle-inline-home-");
|
||||
const workspaceDir = await tempHarness.createTempDir("openclaw-bundle-inline-workspace-");
|
||||
process.env.HOME = homeDir;
|
||||
process.env.USERPROFILE = homeDir;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
|
||||
await withBundleHomeEnv("openclaw-bundle-inline", async ({ homeDir, workspaceDir }) => {
|
||||
const enabledRoot = path.join(homeDir, ".openclaw", "extensions", "inline-enabled");
|
||||
const disabledRoot = path.join(homeDir, ".openclaw", "extensions", "inline-disabled");
|
||||
await fs.mkdir(path.join(enabledRoot, ".claude-plugin"), { recursive: true });
|
||||
@@ -146,88 +146,77 @@ describe("loadEnabledBundleMcpConfig", () => {
|
||||
|
||||
expect(loaded.config.mcpServers.enabledProbe).toBeDefined();
|
||||
expect(loaded.config.mcpServers.disabledProbe).toBeUndefined();
|
||||
} finally {
|
||||
env.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves inline Claude MCP paths from the plugin root and expands CLAUDE_PLUGIN_ROOT", async () => {
|
||||
const env = captureEnv(["HOME", "USERPROFILE", "OPENCLAW_HOME", "OPENCLAW_STATE_DIR"]);
|
||||
try {
|
||||
const homeDir = await tempHarness.createTempDir("openclaw-bundle-inline-placeholder-home-");
|
||||
const workspaceDir = await tempHarness.createTempDir(
|
||||
"openclaw-bundle-inline-placeholder-workspace-",
|
||||
);
|
||||
process.env.HOME = homeDir;
|
||||
process.env.USERPROFILE = homeDir;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
|
||||
const pluginRoot = path.join(homeDir, ".openclaw", "extensions", "inline-claude");
|
||||
await fs.mkdir(path.join(pluginRoot, ".claude-plugin"), { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(pluginRoot, ".claude-plugin", "plugin.json"),
|
||||
`${JSON.stringify(
|
||||
{
|
||||
name: "inline-claude",
|
||||
mcpServers: {
|
||||
inlineProbe: {
|
||||
command: "${CLAUDE_PLUGIN_ROOT}/bin/server.sh",
|
||||
args: ["${CLAUDE_PLUGIN_ROOT}/servers/probe.mjs", "./local-probe.mjs"],
|
||||
cwd: "${CLAUDE_PLUGIN_ROOT}",
|
||||
env: {
|
||||
PLUGIN_ROOT: "${CLAUDE_PLUGIN_ROOT}",
|
||||
await withBundleHomeEnv(
|
||||
"openclaw-bundle-inline-placeholder",
|
||||
async ({ homeDir, workspaceDir }) => {
|
||||
const pluginRoot = path.join(homeDir, ".openclaw", "extensions", "inline-claude");
|
||||
await fs.mkdir(path.join(pluginRoot, ".claude-plugin"), { recursive: true });
|
||||
await fs.writeFile(
|
||||
path.join(pluginRoot, ".claude-plugin", "plugin.json"),
|
||||
`${JSON.stringify(
|
||||
{
|
||||
name: "inline-claude",
|
||||
mcpServers: {
|
||||
inlineProbe: {
|
||||
command: "${CLAUDE_PLUGIN_ROOT}/bin/server.sh",
|
||||
args: ["${CLAUDE_PLUGIN_ROOT}/servers/probe.mjs", "./local-probe.mjs"],
|
||||
cwd: "${CLAUDE_PLUGIN_ROOT}",
|
||||
env: {
|
||||
PLUGIN_ROOT: "${CLAUDE_PLUGIN_ROOT}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
null,
|
||||
2,
|
||||
)}\n`,
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const loaded = loadEnabledBundleMcpConfig({
|
||||
workspaceDir,
|
||||
cfg: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"inline-claude": { enabled: true },
|
||||
const loaded = loadEnabledBundleMcpConfig({
|
||||
workspaceDir,
|
||||
cfg: {
|
||||
plugins: {
|
||||
entries: {
|
||||
"inline-claude": { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const loadedServer = loaded.config.mcpServers.inlineProbe;
|
||||
const loadedArgs = getServerArgs(loadedServer);
|
||||
const loadedCommand = isRecord(loadedServer) ? loadedServer.command : undefined;
|
||||
const loadedCwd = isRecord(loadedServer) ? loadedServer.cwd : undefined;
|
||||
const loadedEnv =
|
||||
isRecord(loadedServer) && isRecord(loadedServer.env) ? loadedServer.env : {};
|
||||
});
|
||||
const loadedServer = loaded.config.mcpServers.inlineProbe;
|
||||
const loadedArgs = getServerArgs(loadedServer);
|
||||
const loadedCommand = isRecord(loadedServer) ? loadedServer.command : undefined;
|
||||
const loadedCwd = isRecord(loadedServer) ? loadedServer.cwd : undefined;
|
||||
const loadedEnv =
|
||||
isRecord(loadedServer) && isRecord(loadedServer.env) ? loadedServer.env : {};
|
||||
|
||||
expect(loaded.diagnostics).toEqual([]);
|
||||
await expectResolvedPathEqual(loadedCwd, pluginRoot);
|
||||
expect(typeof loadedCommand).toBe("string");
|
||||
expect(loadedArgs).toHaveLength(2);
|
||||
expect(typeof loadedEnv.PLUGIN_ROOT).toBe("string");
|
||||
if (typeof loadedCommand !== "string" || typeof loadedCwd !== "string") {
|
||||
throw new Error("expected inline bundled MCP server to expose command and cwd");
|
||||
}
|
||||
expect(normalizePathForAssertion(path.relative(loadedCwd, loadedCommand))).toBe(
|
||||
normalizePathForAssertion(path.join("bin", "server.sh")),
|
||||
);
|
||||
expect(
|
||||
loadedArgs?.map((entry) =>
|
||||
typeof entry === "string"
|
||||
? normalizePathForAssertion(path.relative(loadedCwd, entry))
|
||||
: entry,
|
||||
),
|
||||
).toEqual([
|
||||
normalizePathForAssertion(path.join("servers", "probe.mjs")),
|
||||
normalizePathForAssertion("local-probe.mjs"),
|
||||
]);
|
||||
await expectResolvedPathEqual(loadedEnv.PLUGIN_ROOT, pluginRoot);
|
||||
} finally {
|
||||
env.restore();
|
||||
}
|
||||
expect(loaded.diagnostics).toEqual([]);
|
||||
await expectResolvedPathEqual(loadedCwd, pluginRoot);
|
||||
expect(typeof loadedCommand).toBe("string");
|
||||
expect(loadedArgs).toHaveLength(2);
|
||||
expect(typeof loadedEnv.PLUGIN_ROOT).toBe("string");
|
||||
if (typeof loadedCommand !== "string" || typeof loadedCwd !== "string") {
|
||||
throw new Error("expected inline bundled MCP server to expose command and cwd");
|
||||
}
|
||||
expect(normalizePathForAssertion(path.relative(loadedCwd, loadedCommand))).toBe(
|
||||
normalizePathForAssertion(path.join("bin", "server.sh")),
|
||||
);
|
||||
expect(
|
||||
loadedArgs?.map((entry) =>
|
||||
typeof entry === "string"
|
||||
? normalizePathForAssertion(path.relative(loadedCwd, entry))
|
||||
: entry,
|
||||
),
|
||||
).toEqual([
|
||||
normalizePathForAssertion(path.join("servers", "probe.mjs")),
|
||||
normalizePathForAssertion("local-probe.mjs"),
|
||||
]);
|
||||
await expectResolvedPathEqual(loadedEnv.PLUGIN_ROOT, pluginRoot);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user