mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 18:40:21 +00:00
test: strengthen regression coverage and trim low-value checks
This commit is contained in:
@@ -97,7 +97,6 @@ async function expectActiveInProcessLockIsNotReclaimed(params?: {
|
||||
describe("acquireSessionWriteLock", () => {
|
||||
it("reuses locks across symlinked session paths", async () => {
|
||||
if (process.platform === "win32") {
|
||||
expect(true).toBe(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,12 +109,24 @@ describe("acquireSessionWriteLock", () => {
|
||||
|
||||
const sessionReal = path.join(realDir, "sessions.json");
|
||||
const sessionLink = path.join(linkDir, "sessions.json");
|
||||
const realLockPath = `${sessionReal}.lock`;
|
||||
const linkLockPath = `${sessionLink}.lock`;
|
||||
|
||||
const lockA = await acquireSessionWriteLock({ sessionFile: sessionReal, timeoutMs: 500 });
|
||||
const lockB = await acquireSessionWriteLock({ sessionFile: sessionLink, timeoutMs: 500 });
|
||||
|
||||
await lockB.release();
|
||||
await lockA.release();
|
||||
await expect(fs.access(realLockPath)).resolves.toBeUndefined();
|
||||
await expect(fs.access(linkLockPath)).resolves.toBeUndefined();
|
||||
const [realCanonicalLockPath, linkCanonicalLockPath] = await Promise.all([
|
||||
fs.realpath(realLockPath),
|
||||
fs.realpath(linkLockPath),
|
||||
]);
|
||||
expect(linkCanonicalLockPath).toBe(realCanonicalLockPath);
|
||||
await expectLockRemovedOnlyAfterFinalRelease({
|
||||
lockPath: realLockPath,
|
||||
firstLock: lockA,
|
||||
secondLock: lockB,
|
||||
});
|
||||
} finally {
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import * as channelWeb from "../channel-web.js";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { normalizeChatType } from "./chat-type.js";
|
||||
import * as webEntry from "./web/index.js";
|
||||
|
||||
describe("channel-web barrel", () => {
|
||||
it("exports the expected web helpers", () => {
|
||||
expect(channelWeb.createWaSocket).toBeTypeOf("function");
|
||||
expect(channelWeb.loginWeb).toBeTypeOf("function");
|
||||
expect(channelWeb.monitorWebChannel).toBeTypeOf("function");
|
||||
expect(channelWeb.sendMessageWhatsApp).toBeTypeOf("function");
|
||||
expect(channelWeb.monitorWebInbox).toBeTypeOf("function");
|
||||
expect(channelWeb.pickWebChannel).toBeTypeOf("function");
|
||||
expect(channelWeb.WA_WEB_AUTH_DIR).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("normalizeChatType", () => {
|
||||
const cases: Array<{ name: string; value: string | undefined; expected: string | undefined }> = [
|
||||
@@ -42,17 +28,43 @@ describe("normalizeChatType", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("channels/web entrypoint", () => {
|
||||
it("re-exports web channel helpers", () => {
|
||||
expect(webEntry.createWaSocket).toBe(channelWeb.createWaSocket);
|
||||
expect(webEntry.loginWeb).toBe(channelWeb.loginWeb);
|
||||
expect(webEntry.logWebSelfId).toBe(channelWeb.logWebSelfId);
|
||||
expect(webEntry.monitorWebInbox).toBe(channelWeb.monitorWebInbox);
|
||||
expect(webEntry.monitorWebChannel).toBe(channelWeb.monitorWebChannel);
|
||||
expect(webEntry.pickWebChannel).toBe(channelWeb.pickWebChannel);
|
||||
expect(webEntry.sendMessageWhatsApp).toBe(channelWeb.sendMessageWhatsApp);
|
||||
expect(webEntry.WA_WEB_AUTH_DIR).toBe(channelWeb.WA_WEB_AUTH_DIR);
|
||||
expect(webEntry.waitForWaConnection).toBe(channelWeb.waitForWaConnection);
|
||||
expect(webEntry.webAuthExists).toBe(channelWeb.webAuthExists);
|
||||
describe("WA_WEB_AUTH_DIR", () => {
|
||||
afterEach(() => {
|
||||
vi.doUnmock("../plugins/runtime/runtime-whatsapp-boundary.js");
|
||||
vi.resetModules();
|
||||
});
|
||||
|
||||
it("resolves lazily and caches across the legacy and channels/web entrypoints", async () => {
|
||||
const resolveWaWebAuthDir = vi.fn(() => "/tmp/openclaw-whatsapp-auth");
|
||||
|
||||
vi.resetModules();
|
||||
vi.doMock("../plugins/runtime/runtime-whatsapp-boundary.js", () => ({
|
||||
createWaSocket: vi.fn(),
|
||||
extractMediaPlaceholder: vi.fn(),
|
||||
extractText: vi.fn(),
|
||||
formatError: vi.fn(),
|
||||
getStatusCode: vi.fn(),
|
||||
logWebSelfId: vi.fn(),
|
||||
loginWeb: vi.fn(),
|
||||
logoutWeb: vi.fn(),
|
||||
monitorWebChannel: vi.fn(),
|
||||
monitorWebInbox: vi.fn(),
|
||||
pickWebChannel: vi.fn(),
|
||||
resolveHeartbeatRecipients: vi.fn(),
|
||||
resolveWaWebAuthDir,
|
||||
runWebHeartbeatOnce: vi.fn(),
|
||||
sendMessageWhatsApp: vi.fn(),
|
||||
sendReactionWhatsApp: vi.fn(),
|
||||
waitForWaConnection: vi.fn(),
|
||||
webAuthExists: vi.fn(),
|
||||
}));
|
||||
|
||||
const channelWeb = await import("../channel-web.js");
|
||||
const webEntry = await import("./web/index.js");
|
||||
|
||||
expect(resolveWaWebAuthDir).not.toHaveBeenCalled();
|
||||
expect(String(channelWeb.WA_WEB_AUTH_DIR)).toBe("/tmp/openclaw-whatsapp-auth");
|
||||
expect(String(webEntry.WA_WEB_AUTH_DIR)).toBe("/tmp/openclaw-whatsapp-auth");
|
||||
expect(resolveWaWebAuthDir).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,9 @@ describe("pairing adapters", () => {
|
||||
const lower = createPairingPrefixStripper(/^nextcloud:/i, (entry) => entry.toLowerCase());
|
||||
expect(strip("telegram:123")).toBe("123");
|
||||
expect(strip("tg:123")).toBe("123");
|
||||
expect(strip(" telegram:123 ")).toBe("123");
|
||||
expect(lower("nextcloud:USER")).toBe("user");
|
||||
expect(lower(" nextcloud:USER ")).toBe("user");
|
||||
});
|
||||
|
||||
it("builds text pairing adapters", async () => {
|
||||
|
||||
@@ -6,7 +6,7 @@ export function createPairingPrefixStripper(
|
||||
prefixRe: RegExp,
|
||||
map: (entry: string) => string = (entry) => entry,
|
||||
): NonNullable<ChannelPairingAdapter["normalizeAllowEntry"]> {
|
||||
return (entry) => map(entry.replace(prefixRe, ""));
|
||||
return (entry) => map(entry.trim().replace(prefixRe, "").trim());
|
||||
}
|
||||
|
||||
export function createLoggedPairingApprovalNotifier(
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildGatewayAuthConfig } from "./configure.js";
|
||||
|
||||
function expectGeneratedTokenFromInput(token: string | undefined, literalToAvoid = "undefined") {
|
||||
function expectGeneratedTokenFromInput(
|
||||
token: string | undefined,
|
||||
forbiddenValues: string[] = ["undefined"],
|
||||
) {
|
||||
const result = buildGatewayAuthConfig({
|
||||
mode: "token",
|
||||
token,
|
||||
});
|
||||
expect(result?.mode).toBe("token");
|
||||
expect(result?.token).toBeDefined();
|
||||
expect(result?.token).not.toBe(literalToAvoid);
|
||||
expect(typeof result?.token).toBe("string");
|
||||
if (typeof result?.token !== "string") {
|
||||
throw new Error("Expected generated token to be a string.");
|
||||
}
|
||||
for (const forbiddenValue of forbiddenValues) {
|
||||
expect(result.token).not.toBe(forbiddenValue);
|
||||
}
|
||||
expect(result.token.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
@@ -70,10 +74,37 @@ describe("buildGatewayAuthConfig", () => {
|
||||
|
||||
it("generates random token for missing, empty, and coerced-literal token inputs", () => {
|
||||
expectGeneratedTokenFromInput(undefined);
|
||||
expectGeneratedTokenFromInput("");
|
||||
expectGeneratedTokenFromInput(" ");
|
||||
expectGeneratedTokenFromInput("undefined");
|
||||
expectGeneratedTokenFromInput("null", "null");
|
||||
expectGeneratedTokenFromInput("", [""]);
|
||||
expectGeneratedTokenFromInput(" ", [""]);
|
||||
expectGeneratedTokenFromInput("undefined", ["undefined"]);
|
||||
expectGeneratedTokenFromInput("null", ["null"]);
|
||||
});
|
||||
|
||||
it("trims and preserves explicit token values", () => {
|
||||
const result = buildGatewayAuthConfig({
|
||||
mode: "token",
|
||||
token: " abc123 ",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ mode: "token", token: "abc123" });
|
||||
});
|
||||
|
||||
it("trims password values before storing them", () => {
|
||||
const result = buildGatewayAuthConfig({
|
||||
mode: "password",
|
||||
password: " secret ", // pragma: allowlist secret
|
||||
});
|
||||
|
||||
expect(result).toEqual({ mode: "password", password: "secret" }); // pragma: allowlist secret
|
||||
});
|
||||
|
||||
it("keeps password mode valid even when the trimmed password becomes empty", () => {
|
||||
const result = buildGatewayAuthConfig({
|
||||
mode: "password",
|
||||
password: " ",
|
||||
});
|
||||
|
||||
expect(result).toEqual({ mode: "password" });
|
||||
});
|
||||
|
||||
it("preserves SecretRef tokens when token mode is selected", () => {
|
||||
|
||||
@@ -14,13 +14,20 @@ function mockProcReads(entries: Record<string, string>) {
|
||||
}
|
||||
|
||||
async function withLinuxProcessPlatform<T>(run: () => Promise<T>): Promise<T> {
|
||||
return withProcessPlatform("linux", run);
|
||||
}
|
||||
|
||||
async function withProcessPlatform<T>(
|
||||
platform: NodeJS.Platform,
|
||||
run: () => Promise<T>,
|
||||
): Promise<T> {
|
||||
const originalPlatformDescriptor = Object.getOwnPropertyDescriptor(process, "platform");
|
||||
if (!originalPlatformDescriptor) {
|
||||
throw new Error("missing process.platform descriptor");
|
||||
}
|
||||
Object.defineProperty(process, "platform", {
|
||||
...originalPlatformDescriptor,
|
||||
value: "linux",
|
||||
value: platform,
|
||||
});
|
||||
try {
|
||||
vi.resetModules();
|
||||
@@ -102,12 +109,10 @@ describe("getProcessStartTime", () => {
|
||||
});
|
||||
|
||||
it("returns null on non-Linux platforms", () => {
|
||||
if (process.platform === "linux") {
|
||||
// On actual Linux, this test is trivially satisfied by the other tests.
|
||||
expect(true).toBe(true);
|
||||
return;
|
||||
}
|
||||
expect(getProcessStartTime(process.pid)).toBeNull();
|
||||
return withProcessPlatform("darwin", async () => {
|
||||
const { getProcessStartTime: fresh } = await import("./pid-alive.js");
|
||||
expect(fresh(process.pid)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("returns null for invalid PIDs", () => {
|
||||
|
||||
Reference in New Issue
Block a user