mirror of https://github.com/openclaw/openclaw.git
test: add direct infra helper coverage
This commit is contained in:
parent
3e77263b4c
commit
a423b1d936
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { isGatewayArgv, parseProcCmdline } from "./gateway-process-argv.js";
|
||||||
|
|
||||||
|
describe("parseProcCmdline", () => {
|
||||||
|
it("splits null-delimited argv and trims empty entries", () => {
|
||||||
|
expect(parseProcCmdline(" node \0 gateway \0\0 --port \0 18789 \0")).toEqual([
|
||||||
|
"node",
|
||||||
|
"gateway",
|
||||||
|
"--port",
|
||||||
|
"18789",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isGatewayArgv", () => {
|
||||||
|
it("requires a gateway token", () => {
|
||||||
|
expect(isGatewayArgv(["node", "dist/index.js", "--port", "18789"])).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches known entrypoints across slash and case variants", () => {
|
||||||
|
expect(isGatewayArgv(["NODE", "C:\\OpenClaw\\DIST\\ENTRY.JS", "gateway"])).toBe(true);
|
||||||
|
expect(isGatewayArgv(["bun", "/srv/openclaw/scripts/run-node.mjs", "gateway"])).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches the openclaw executable but gates the gateway binary behind the opt-in flag", () => {
|
||||||
|
expect(isGatewayArgv(["C:\\bin\\openclaw.cmd", "gateway"])).toBe(true);
|
||||||
|
expect(isGatewayArgv(["/usr/local/bin/openclaw-gateway", "gateway"])).toBe(false);
|
||||||
|
expect(
|
||||||
|
isGatewayArgv(["/usr/local/bin/openclaw-gateway", "gateway"], {
|
||||||
|
allowGatewayBinary: true,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import fs from "node:fs/promises";
|
||||||
|
import path from "node:path";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { withTempDir } from "../test-helpers/temp-dir.js";
|
||||||
|
import { readPackageName, readPackageVersion } from "./package-json.js";
|
||||||
|
|
||||||
|
describe("package-json helpers", () => {
|
||||||
|
it("reads package version and trims package name", async () => {
|
||||||
|
await withTempDir({ prefix: "openclaw-package-json-" }, async (root) => {
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(root, "package.json"),
|
||||||
|
JSON.stringify({ version: "1.2.3", name: " @openclaw/demo " }),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(readPackageVersion(root)).resolves.toBe("1.2.3");
|
||||||
|
await expect(readPackageName(root)).resolves.toBe("@openclaw/demo");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns null for missing or invalid package.json data", async () => {
|
||||||
|
await withTempDir({ prefix: "openclaw-package-json-" }, async (root) => {
|
||||||
|
await expect(readPackageVersion(root)).resolves.toBeNull();
|
||||||
|
await expect(readPackageName(root)).resolves.toBeNull();
|
||||||
|
|
||||||
|
await fs.writeFile(path.join(root, "package.json"), "{", "utf8");
|
||||||
|
await expect(readPackageVersion(root)).resolves.toBeNull();
|
||||||
|
await expect(readPackageName(root)).resolves.toBeNull();
|
||||||
|
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(root, "package.json"),
|
||||||
|
JSON.stringify({ version: 123, name: " " }),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
await expect(readPackageVersion(root)).resolves.toBeNull();
|
||||||
|
await expect(readPackageName(root)).resolves.toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
hasNodeErrorCode,
|
||||||
|
isNodeError,
|
||||||
|
isNotFoundPathError,
|
||||||
|
isPathInside,
|
||||||
|
isSymlinkOpenError,
|
||||||
|
normalizeWindowsPathForComparison,
|
||||||
|
} from "./path-guards.js";
|
||||||
|
|
||||||
|
describe("normalizeWindowsPathForComparison", () => {
|
||||||
|
it("normalizes extended-length and UNC windows paths", () => {
|
||||||
|
expect(normalizeWindowsPathForComparison("\\\\?\\C:\\Users\\Peter/Repo")).toBe(
|
||||||
|
"c:\\users\\peter\\repo",
|
||||||
|
);
|
||||||
|
expect(normalizeWindowsPathForComparison("\\\\?\\UNC\\Server\\Share\\Folder")).toBe(
|
||||||
|
"\\\\server\\share\\folder",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("node path error helpers", () => {
|
||||||
|
it("recognizes node-style error objects and exact codes", () => {
|
||||||
|
const enoent = { code: "ENOENT" };
|
||||||
|
|
||||||
|
expect(isNodeError(enoent)).toBe(true);
|
||||||
|
expect(isNodeError({ message: "nope" })).toBe(false);
|
||||||
|
expect(hasNodeErrorCode(enoent, "ENOENT")).toBe(true);
|
||||||
|
expect(hasNodeErrorCode(enoent, "EACCES")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("classifies not-found and symlink-open error codes", () => {
|
||||||
|
expect(isNotFoundPathError({ code: "ENOENT" })).toBe(true);
|
||||||
|
expect(isNotFoundPathError({ code: "ENOTDIR" })).toBe(true);
|
||||||
|
expect(isNotFoundPathError({ code: "EACCES" })).toBe(false);
|
||||||
|
|
||||||
|
expect(isSymlinkOpenError({ code: "ELOOP" })).toBe(true);
|
||||||
|
expect(isSymlinkOpenError({ code: "EINVAL" })).toBe(true);
|
||||||
|
expect(isSymlinkOpenError({ code: "ENOTSUP" })).toBe(true);
|
||||||
|
expect(isSymlinkOpenError({ code: "ENOENT" })).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("isPathInside", () => {
|
||||||
|
it("accepts identical and nested paths but rejects escapes", () => {
|
||||||
|
expect(isPathInside("/workspace/root", "/workspace/root")).toBe(true);
|
||||||
|
expect(isPathInside("/workspace/root", "/workspace/root/nested/file.txt")).toBe(true);
|
||||||
|
expect(isPathInside("/workspace/root", "/workspace/root/../escape.txt")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { isBlockedObjectKey } from "./prototype-keys.js";
|
||||||
|
|
||||||
|
describe("isBlockedObjectKey", () => {
|
||||||
|
it("blocks prototype-pollution keys and allows ordinary keys", () => {
|
||||||
|
for (const key of ["__proto__", "prototype", "constructor"]) {
|
||||||
|
expect(isBlockedObjectKey(key)).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of ["toString", "value", "constructorName"]) {
|
||||||
|
expect(isBlockedObjectKey(key)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue