mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
test: trim more unit test startup overhead
This commit is contained in:
@@ -272,57 +272,57 @@ describe("installHooksFromPath", () => {
|
||||
expect(fs.existsSync(path.join(result.targetDir, "HOOK.md"))).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects hook pack entries that traverse outside package directory", async () => {
|
||||
const stateDir = makeTempDir();
|
||||
const workDir = makeTempDir();
|
||||
const pkgDir = path.join(workDir, "package");
|
||||
const outsideHookDir = path.join(workDir, "outside");
|
||||
fs.mkdirSync(pkgDir, { recursive: true });
|
||||
fs.mkdirSync(outsideHookDir, { recursive: true });
|
||||
writeHookPackManifest({
|
||||
pkgDir,
|
||||
hooks: ["../outside"],
|
||||
});
|
||||
fs.writeFileSync(path.join(outsideHookDir, "HOOK.md"), "---\nname: outside\n---\n", "utf-8");
|
||||
fs.writeFileSync(path.join(outsideHookDir, "handler.ts"), "export default async () => {};\n");
|
||||
it("rejects out-of-package hook entries", async () => {
|
||||
const cases = [
|
||||
{
|
||||
hooks: ["../outside"],
|
||||
setupLink: false,
|
||||
expected: "openclaw.hooks entry escapes package directory",
|
||||
},
|
||||
{
|
||||
hooks: ["./linked"],
|
||||
setupLink: true,
|
||||
expected: "openclaw.hooks entry resolves outside package directory",
|
||||
},
|
||||
] as const;
|
||||
|
||||
const result = await installHooksFromPath({
|
||||
path: pkgDir,
|
||||
hooksDir: path.join(stateDir, "hooks"),
|
||||
});
|
||||
for (const testCase of cases) {
|
||||
const stateDir = makeTempDir();
|
||||
const workDir = makeTempDir();
|
||||
const pkgDir = path.join(workDir, "package");
|
||||
const outsideHookDir = path.join(workDir, "outside");
|
||||
const linkedDir = path.join(pkgDir, "linked");
|
||||
fs.mkdirSync(pkgDir, { recursive: true });
|
||||
fs.mkdirSync(outsideHookDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(outsideHookDir, "HOOK.md"), "---\nname: outside\n---\n", "utf-8");
|
||||
fs.writeFileSync(
|
||||
path.join(outsideHookDir, "handler.ts"),
|
||||
"export default async () => {};\n",
|
||||
"utf-8",
|
||||
);
|
||||
if (testCase.setupLink) {
|
||||
try {
|
||||
fs.symlinkSync(
|
||||
outsideHookDir,
|
||||
linkedDir,
|
||||
process.platform === "win32" ? "junction" : "dir",
|
||||
);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
writeHookPackManifest({
|
||||
pkgDir,
|
||||
hooks: [...testCase.hooks],
|
||||
});
|
||||
|
||||
expectPathInstallFailureContains(result, "openclaw.hooks entry escapes package directory");
|
||||
});
|
||||
const result = await installHooksFromPath({
|
||||
path: pkgDir,
|
||||
hooksDir: path.join(stateDir, "hooks"),
|
||||
});
|
||||
|
||||
it("rejects hook pack entries that escape via symlink", async () => {
|
||||
const stateDir = makeTempDir();
|
||||
const workDir = makeTempDir();
|
||||
const pkgDir = path.join(workDir, "package");
|
||||
const outsideHookDir = path.join(workDir, "outside");
|
||||
const linkedDir = path.join(pkgDir, "linked");
|
||||
fs.mkdirSync(pkgDir, { recursive: true });
|
||||
fs.mkdirSync(outsideHookDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(outsideHookDir, "HOOK.md"), "---\nname: outside\n---\n", "utf-8");
|
||||
fs.writeFileSync(path.join(outsideHookDir, "handler.ts"), "export default async () => {};\n");
|
||||
try {
|
||||
fs.symlinkSync(outsideHookDir, linkedDir, process.platform === "win32" ? "junction" : "dir");
|
||||
} catch {
|
||||
return;
|
||||
expectPathInstallFailureContains(result, testCase.expected);
|
||||
}
|
||||
writeHookPackManifest({
|
||||
pkgDir,
|
||||
hooks: ["./linked"],
|
||||
});
|
||||
|
||||
const result = await installHooksFromPath({
|
||||
path: pkgDir,
|
||||
hooksDir: path.join(stateDir, "hooks"),
|
||||
});
|
||||
|
||||
expectPathInstallFailureContains(
|
||||
result,
|
||||
"openclaw.hooks entry resolves outside package directory",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -437,7 +437,7 @@ describe("fs-safe", () => {
|
||||
});
|
||||
|
||||
describe("tilde expansion in file tools", () => {
|
||||
it("expandHomePrefix respects process.env.HOME changes", async () => {
|
||||
it("keeps tilde expansion behavior aligned", async () => {
|
||||
const { expandHomePrefix } = await import("./home-dir.js");
|
||||
const originalHome = process.env.HOME;
|
||||
const fakeHome = path.resolve(path.sep, "tmp", "fake-home-test");
|
||||
@@ -448,11 +448,8 @@ describe("tilde expansion in file tools", () => {
|
||||
} finally {
|
||||
process.env.HOME = originalHome;
|
||||
}
|
||||
});
|
||||
|
||||
it("reads a file via ~/path after HOME override", async () => {
|
||||
const root = await tempDirs.make("openclaw-tilde-test-");
|
||||
const originalHome = process.env.HOME;
|
||||
process.env.HOME = root;
|
||||
try {
|
||||
await fs.writeFile(path.join(root, "hello.txt"), "tilde-works");
|
||||
@@ -464,16 +461,7 @@ describe("tilde expansion in file tools", () => {
|
||||
await result.handle.read(buf, 0, buf.length, 0);
|
||||
await result.handle.close();
|
||||
expect(buf.toString("utf8")).toBe("tilde-works");
|
||||
} finally {
|
||||
process.env.HOME = originalHome;
|
||||
}
|
||||
});
|
||||
|
||||
it("writes a file via ~/path after HOME override", async () => {
|
||||
const root = await tempDirs.make("openclaw-tilde-test-");
|
||||
const originalHome = process.env.HOME;
|
||||
process.env.HOME = root;
|
||||
try {
|
||||
await writeFileWithinRoot({
|
||||
rootDir: root,
|
||||
relativePath: "~/output.txt",
|
||||
@@ -484,14 +472,11 @@ describe("tilde expansion in file tools", () => {
|
||||
} finally {
|
||||
process.env.HOME = originalHome;
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects ~/path that resolves outside root", async () => {
|
||||
const root = await tempDirs.make("openclaw-tilde-outside-");
|
||||
// HOME points to real home, ~/file goes to /home/dev/file which is outside root
|
||||
const outsideRoot = await tempDirs.make("openclaw-tilde-outside-");
|
||||
await expect(
|
||||
openFileWithinRoot({
|
||||
rootDir: root,
|
||||
rootDir: outsideRoot,
|
||||
relativePath: "~/escape.txt",
|
||||
}),
|
||||
).rejects.toMatchObject({
|
||||
|
||||
@@ -52,7 +52,6 @@ const sourceCache = new Map<string, string>();
|
||||
const representativeRuntimeSmokeSubpaths = [
|
||||
"channel-runtime",
|
||||
"conversation-runtime",
|
||||
"discord",
|
||||
"provider-auth",
|
||||
"provider-setup",
|
||||
"setup",
|
||||
@@ -125,24 +124,28 @@ function expectSourceContract(
|
||||
|
||||
describe("plugin-sdk subpath exports", () => {
|
||||
it("keeps the curated public list free of internal implementation subpaths", () => {
|
||||
expect(pluginSdkSubpaths).not.toContain("acpx");
|
||||
expect(pluginSdkSubpaths).not.toContain("compat");
|
||||
expect(pluginSdkSubpaths).not.toContain("device-pair");
|
||||
expect(pluginSdkSubpaths).not.toContain("google");
|
||||
expect(pluginSdkSubpaths).not.toContain("lobster");
|
||||
expect(pluginSdkSubpaths).not.toContain("pairing-access");
|
||||
expect(pluginSdkSubpaths).not.toContain("qwen-portal-auth");
|
||||
expect(pluginSdkSubpaths).not.toContain("reply-prefix");
|
||||
expect(pluginSdkSubpaths).not.toContain("signal-core");
|
||||
expect(pluginSdkSubpaths).not.toContain("synology-chat");
|
||||
expect(pluginSdkSubpaths).not.toContain("typing");
|
||||
expect(pluginSdkSubpaths).not.toContain("whatsapp");
|
||||
expect(pluginSdkSubpaths).not.toContain("whatsapp-action-runtime");
|
||||
expect(pluginSdkSubpaths).not.toContain("whatsapp-login-qr");
|
||||
expect(pluginSdkSubpaths).not.toContain("secret-input-runtime");
|
||||
expect(pluginSdkSubpaths).not.toContain("secret-input-schema");
|
||||
expect(pluginSdkSubpaths).not.toContain("zai");
|
||||
expect(pluginSdkSubpaths).not.toContain("provider-model-definitions");
|
||||
for (const deniedSubpath of [
|
||||
"acpx",
|
||||
"compat",
|
||||
"device-pair",
|
||||
"google",
|
||||
"lobster",
|
||||
"pairing-access",
|
||||
"provider-model-definitions",
|
||||
"qwen-portal-auth",
|
||||
"reply-prefix",
|
||||
"secret-input-runtime",
|
||||
"secret-input-schema",
|
||||
"signal-core",
|
||||
"synology-chat",
|
||||
"typing",
|
||||
"whatsapp",
|
||||
"whatsapp-action-runtime",
|
||||
"whatsapp-login-qr",
|
||||
"zai",
|
||||
]) {
|
||||
expect(pluginSdkSubpaths).not.toContain(deniedSubpath);
|
||||
}
|
||||
});
|
||||
|
||||
it("keeps core focused on generic shared exports", () => {
|
||||
@@ -568,13 +571,10 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expectSourceMentions("testing", ["removeAckReactionAfterReply", "shouldAckReaction"]);
|
||||
});
|
||||
|
||||
it("exports shared core types used by bundled extensions", () => {
|
||||
it("keeps core shared types aligned", () => {
|
||||
expectTypeOf<CoreOpenClawPluginApi>().toMatchTypeOf<OpenClawPluginApi>();
|
||||
expectTypeOf<CorePluginRuntime>().toMatchTypeOf<PluginRuntime>();
|
||||
expectTypeOf<CoreChannelMessageActionContext>().toMatchTypeOf<ChannelMessageActionContext>();
|
||||
});
|
||||
|
||||
it("keeps core shared types aligned with the channel prelude", () => {
|
||||
expectTypeOf<CoreOpenClawPluginApi>().toMatchTypeOf<SharedOpenClawPluginApi>();
|
||||
expectTypeOf<CorePluginRuntime>().toMatchTypeOf<SharedPluginRuntime>();
|
||||
expectTypeOf<CoreChannelMessageActionContext>().toMatchTypeOf<SharedChannelMessageActionContext>();
|
||||
|
||||
@@ -57,33 +57,46 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("scripts/committer", () => {
|
||||
it("keeps plain argv paths working", () => {
|
||||
const repo = createRepo();
|
||||
writeRepoFile(repo, "alpha.txt", "alpha\n");
|
||||
writeRepoFile(repo, "nested/file with spaces.txt", "beta\n");
|
||||
it("accepts supported path argument shapes", () => {
|
||||
const cases = [
|
||||
{
|
||||
commitMessage: "test: plain argv",
|
||||
files: [
|
||||
["alpha.txt", "alpha\n"],
|
||||
["nested/file with spaces.txt", "beta\n"],
|
||||
] as const,
|
||||
args: ["alpha.txt", "nested/file with spaces.txt"],
|
||||
expected: ["alpha.txt", "nested/file with spaces.txt"],
|
||||
},
|
||||
{
|
||||
commitMessage: "test: space blob",
|
||||
files: [
|
||||
["alpha.txt", "alpha\n"],
|
||||
["beta.txt", "beta\n"],
|
||||
] as const,
|
||||
args: ["alpha.txt beta.txt"],
|
||||
expected: ["alpha.txt", "beta.txt"],
|
||||
},
|
||||
{
|
||||
commitMessage: "test: newline blob",
|
||||
files: [
|
||||
["alpha.txt", "alpha\n"],
|
||||
["nested/file with spaces.txt", "beta\n"],
|
||||
] as const,
|
||||
args: ["alpha.txt\nnested/file with spaces.txt"],
|
||||
expected: ["alpha.txt", "nested/file with spaces.txt"],
|
||||
},
|
||||
] as const;
|
||||
|
||||
commitWithHelper(repo, "test: plain argv", "alpha.txt", "nested/file with spaces.txt");
|
||||
for (const testCase of cases) {
|
||||
const repo = createRepo();
|
||||
for (const [file, contents] of testCase.files) {
|
||||
writeRepoFile(repo, file, contents);
|
||||
}
|
||||
|
||||
expect(committedPaths(repo)).toEqual(["alpha.txt", "nested/file with spaces.txt"]);
|
||||
});
|
||||
commitWithHelper(repo, testCase.commitMessage, ...testCase.args);
|
||||
|
||||
it("accepts a single space-delimited path blob", () => {
|
||||
const repo = createRepo();
|
||||
writeRepoFile(repo, "alpha.txt", "alpha\n");
|
||||
writeRepoFile(repo, "beta.txt", "beta\n");
|
||||
|
||||
commitWithHelper(repo, "test: space blob", "alpha.txt beta.txt");
|
||||
|
||||
expect(committedPaths(repo)).toEqual(["alpha.txt", "beta.txt"]);
|
||||
});
|
||||
|
||||
it("accepts a single newline-delimited path blob", () => {
|
||||
const repo = createRepo();
|
||||
writeRepoFile(repo, "alpha.txt", "alpha\n");
|
||||
writeRepoFile(repo, "nested/file with spaces.txt", "beta\n");
|
||||
|
||||
commitWithHelper(repo, "test: newline blob", "alpha.txt\nnested/file with spaces.txt");
|
||||
|
||||
expect(committedPaths(repo)).toEqual(["alpha.txt", "nested/file with spaces.txt"]);
|
||||
expect(committedPaths(repo)).toEqual(testCase.expected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user