mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-28 17:43:05 +00:00
perf(test): reduce hot-suite import and setup overhead
This commit is contained in:
@@ -2,23 +2,22 @@ import { randomUUID } from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { afterAll, describe, expect, it } from "vitest";
|
||||
import { resolvePluginTools } from "./tools.js";
|
||||
|
||||
type TempPlugin = { dir: string; file: string; id: string };
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
const fixtureRoot = path.join(os.tmpdir(), `openclaw-plugin-tools-${randomUUID()}`);
|
||||
const EMPTY_PLUGIN_SCHEMA = { type: "object", additionalProperties: false, properties: {} };
|
||||
|
||||
function makeTempDir() {
|
||||
const dir = path.join(os.tmpdir(), `openclaw-plugin-tools-${randomUUID()}`);
|
||||
function makeFixtureDir(id: string) {
|
||||
const dir = path.join(fixtureRoot, id);
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
tempDirs.push(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
function writePlugin(params: { id: string; body: string }): TempPlugin {
|
||||
const dir = makeTempDir();
|
||||
const dir = makeFixtureDir(params.id);
|
||||
const file = path.join(dir, `${params.id}.js`);
|
||||
fs.writeFileSync(file, params.body, "utf-8");
|
||||
fs.writeFileSync(
|
||||
@@ -36,18 +35,7 @@ function writePlugin(params: { id: string; body: string }): TempPlugin {
|
||||
return { dir, file, id: params.id };
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
try {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
} catch {
|
||||
// ignore cleanup failures
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
describe("resolvePluginTools optional tools", () => {
|
||||
const pluginBody = `
|
||||
const pluginBody = `
|
||||
export default { register(api) {
|
||||
api.registerTool(
|
||||
{
|
||||
@@ -63,92 +51,11 @@ export default { register(api) {
|
||||
} }
|
||||
`;
|
||||
|
||||
it("skips optional tools without explicit allowlist", () => {
|
||||
const plugin = writePlugin({ id: "optional-demo", body: pluginBody });
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
},
|
||||
});
|
||||
expect(tools).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("allows optional tools by name", () => {
|
||||
const plugin = writePlugin({ id: "optional-demo", body: pluginBody });
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
},
|
||||
toolAllowlist: ["optional_tool"],
|
||||
});
|
||||
expect(tools.map((tool) => tool.name)).toContain("optional_tool");
|
||||
});
|
||||
|
||||
it("allows optional tools via plugin groups", () => {
|
||||
const plugin = writePlugin({ id: "optional-demo", body: pluginBody });
|
||||
const toolsAll = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
},
|
||||
toolAllowlist: ["group:plugins"],
|
||||
});
|
||||
expect(toolsAll.map((tool) => tool.name)).toContain("optional_tool");
|
||||
|
||||
const toolsPlugin = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
},
|
||||
toolAllowlist: ["optional-demo"],
|
||||
});
|
||||
expect(toolsPlugin.map((tool) => tool.name)).toContain("optional_tool");
|
||||
});
|
||||
|
||||
it("rejects plugin id collisions with core tool names", () => {
|
||||
const plugin = writePlugin({ id: "message", body: pluginBody });
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
},
|
||||
existingToolNames: new Set(["message"]),
|
||||
toolAllowlist: ["message"],
|
||||
});
|
||||
expect(tools).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("skips conflicting tool names but keeps other tools", () => {
|
||||
const plugin = writePlugin({
|
||||
id: "multi",
|
||||
body: `
|
||||
const optionalDemoPlugin = writePlugin({ id: "optional-demo", body: pluginBody });
|
||||
const coreNameCollisionPlugin = writePlugin({ id: "message", body: pluginBody });
|
||||
const multiToolPlugin = writePlugin({
|
||||
id: "multi",
|
||||
body: `
|
||||
export default { register(api) {
|
||||
api.registerTool({
|
||||
name: "message",
|
||||
@@ -168,17 +75,105 @@ export default { register(api) {
|
||||
});
|
||||
} }
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
try {
|
||||
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
||||
} catch {
|
||||
// ignore cleanup failures
|
||||
}
|
||||
});
|
||||
|
||||
describe("resolvePluginTools optional tools", () => {
|
||||
it("skips optional tools without explicit allowlist", () => {
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [plugin.file] },
|
||||
allow: [plugin.id],
|
||||
load: { paths: [optionalDemoPlugin.file] },
|
||||
allow: [optionalDemoPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: plugin.dir,
|
||||
workspaceDir: optionalDemoPlugin.dir,
|
||||
},
|
||||
});
|
||||
expect(tools).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("allows optional tools by name", () => {
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [optionalDemoPlugin.file] },
|
||||
allow: [optionalDemoPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: optionalDemoPlugin.dir,
|
||||
},
|
||||
toolAllowlist: ["optional_tool"],
|
||||
});
|
||||
expect(tools.map((tool) => tool.name)).toContain("optional_tool");
|
||||
});
|
||||
|
||||
it("allows optional tools via plugin groups", () => {
|
||||
const toolsAll = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [optionalDemoPlugin.file] },
|
||||
allow: [optionalDemoPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: optionalDemoPlugin.dir,
|
||||
},
|
||||
toolAllowlist: ["group:plugins"],
|
||||
});
|
||||
expect(toolsAll.map((tool) => tool.name)).toContain("optional_tool");
|
||||
|
||||
const toolsPlugin = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [optionalDemoPlugin.file] },
|
||||
allow: [optionalDemoPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: optionalDemoPlugin.dir,
|
||||
},
|
||||
toolAllowlist: ["optional-demo"],
|
||||
});
|
||||
expect(toolsPlugin.map((tool) => tool.name)).toContain("optional_tool");
|
||||
});
|
||||
|
||||
it("rejects plugin id collisions with core tool names", () => {
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [coreNameCollisionPlugin.file] },
|
||||
allow: [coreNameCollisionPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: coreNameCollisionPlugin.dir,
|
||||
},
|
||||
existingToolNames: new Set(["message"]),
|
||||
toolAllowlist: ["message"],
|
||||
});
|
||||
expect(tools).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("skips conflicting tool names but keeps other tools", () => {
|
||||
const tools = resolvePluginTools({
|
||||
context: {
|
||||
config: {
|
||||
plugins: {
|
||||
load: { paths: [multiToolPlugin.file] },
|
||||
allow: [multiToolPlugin.id],
|
||||
},
|
||||
},
|
||||
workspaceDir: multiToolPlugin.dir,
|
||||
},
|
||||
existingToolNames: new Set(["message"]),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user