test(ringcentral): add unit tests for targets, accounts, and monitor
- targets.test.ts: tests for target normalization and parsing - accounts.test.ts: tests for credential resolution and account management - monitor.test.ts: tests for sender allowlist matching Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
parent
0b1aebe80f
commit
ab952fd8cd
291
extensions/ringcentral/src/accounts.test.ts
Normal file
291
extensions/ringcentral/src/accounts.test.ts
Normal file
@ -0,0 +1,291 @@
|
||||
import { describe, expect, it, beforeEach, afterEach, vi } from "vitest";
|
||||
import type { ClawdbotConfig } from "clawdbot/plugin-sdk";
|
||||
import {
|
||||
listRingCentralAccountIds,
|
||||
resolveDefaultRingCentralAccountId,
|
||||
resolveRingCentralAccount,
|
||||
listEnabledRingCentralAccounts,
|
||||
} from "./accounts.js";
|
||||
|
||||
describe("listRingCentralAccountIds", () => {
|
||||
it("returns default account when no accounts configured", () => {
|
||||
const cfg = { channels: {} } as ClawdbotConfig;
|
||||
expect(listRingCentralAccountIds(cfg)).toEqual(["default"]);
|
||||
});
|
||||
|
||||
it("returns default account when ringcentral channel not configured", () => {
|
||||
const cfg = { channels: { telegram: { enabled: true } } } as ClawdbotConfig;
|
||||
expect(listRingCentralAccountIds(cfg)).toEqual(["default"]);
|
||||
});
|
||||
|
||||
it("returns configured account IDs sorted alphabetically", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
accounts: {
|
||||
work: { enabled: true },
|
||||
personal: { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
expect(listRingCentralAccountIds(cfg)).toEqual(["personal", "work"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveDefaultRingCentralAccountId", () => {
|
||||
it("returns explicitly set default account", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
defaultAccount: "work",
|
||||
accounts: {
|
||||
work: {},
|
||||
personal: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
expect(resolveDefaultRingCentralAccountId(cfg)).toBe("work");
|
||||
});
|
||||
|
||||
it("returns default if included in accounts", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
accounts: {
|
||||
default: {},
|
||||
other: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
expect(resolveDefaultRingCentralAccountId(cfg)).toBe("default");
|
||||
});
|
||||
|
||||
it("returns first account ID when no default specified", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
accounts: {
|
||||
zebra: {},
|
||||
alpha: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
expect(resolveDefaultRingCentralAccountId(cfg)).toBe("alpha");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveRingCentralAccount", () => {
|
||||
const originalEnv = process.env;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
process.env = { ...originalEnv };
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
});
|
||||
|
||||
it("resolves account from config credentials", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
clientId: "test-client-id",
|
||||
clientSecret: "test-client-secret",
|
||||
jwt: "test-jwt",
|
||||
server: "https://platform.devtest.ringcentral.com",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg });
|
||||
|
||||
expect(account.accountId).toBe("default");
|
||||
expect(account.enabled).toBe(true);
|
||||
expect(account.credentialSource).toBe("config");
|
||||
expect(account.clientId).toBe("test-client-id");
|
||||
expect(account.clientSecret).toBe("test-client-secret");
|
||||
expect(account.jwt).toBe("test-jwt");
|
||||
expect(account.server).toBe("https://platform.devtest.ringcentral.com");
|
||||
});
|
||||
|
||||
it("resolves account from environment variables", () => {
|
||||
process.env.RINGCENTRAL_CLIENT_ID = "env-client-id";
|
||||
process.env.RINGCENTRAL_CLIENT_SECRET = "env-client-secret";
|
||||
process.env.RINGCENTRAL_JWT = "env-jwt";
|
||||
process.env.RINGCENTRAL_SERVER = "https://platform.devtest.ringcentral.com";
|
||||
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg });
|
||||
|
||||
expect(account.credentialSource).toBe("env");
|
||||
expect(account.clientId).toBe("env-client-id");
|
||||
expect(account.clientSecret).toBe("env-client-secret");
|
||||
expect(account.jwt).toBe("env-jwt");
|
||||
expect(account.server).toBe("https://platform.devtest.ringcentral.com");
|
||||
});
|
||||
|
||||
it("returns none source when no credentials configured", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg });
|
||||
|
||||
expect(account.credentialSource).toBe("none");
|
||||
expect(account.clientId).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses default server when not specified", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
clientId: "test-client-id",
|
||||
clientSecret: "test-client-secret",
|
||||
jwt: "test-jwt",
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg });
|
||||
|
||||
expect(account.server).toBe("https://platform.ringcentral.com");
|
||||
});
|
||||
|
||||
it("resolves specific account from accounts map", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
accounts: {
|
||||
work: {
|
||||
clientId: "work-client-id",
|
||||
clientSecret: "work-client-secret",
|
||||
jwt: "work-jwt",
|
||||
name: "Work Account",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg, accountId: "work" });
|
||||
|
||||
expect(account.accountId).toBe("work");
|
||||
expect(account.name).toBe("Work Account");
|
||||
expect(account.clientId).toBe("work-client-id");
|
||||
});
|
||||
|
||||
it("merges base config with account config", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
server: "https://base.server.com",
|
||||
accounts: {
|
||||
work: {
|
||||
clientId: "work-client-id",
|
||||
clientSecret: "work-client-secret",
|
||||
jwt: "work-jwt",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg, accountId: "work" });
|
||||
|
||||
expect(account.server).toBe("https://base.server.com");
|
||||
});
|
||||
|
||||
it("account config overrides base config", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
server: "https://base.server.com",
|
||||
accounts: {
|
||||
work: {
|
||||
clientId: "work-client-id",
|
||||
clientSecret: "work-client-secret",
|
||||
jwt: "work-jwt",
|
||||
server: "https://work.server.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const account = resolveRingCentralAccount({ cfg, accountId: "work" });
|
||||
|
||||
expect(account.server).toBe("https://work.server.com");
|
||||
});
|
||||
});
|
||||
|
||||
describe("listEnabledRingCentralAccounts", () => {
|
||||
it("returns only enabled accounts", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: true,
|
||||
clientId: "base-id",
|
||||
clientSecret: "base-secret",
|
||||
jwt: "base-jwt",
|
||||
accounts: {
|
||||
enabled1: {
|
||||
enabled: true,
|
||||
clientId: "e1-id",
|
||||
clientSecret: "e1-secret",
|
||||
jwt: "e1-jwt",
|
||||
},
|
||||
disabled1: {
|
||||
enabled: false,
|
||||
clientId: "d1-id",
|
||||
clientSecret: "d1-secret",
|
||||
jwt: "d1-jwt",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const accounts = listEnabledRingCentralAccounts(cfg);
|
||||
|
||||
expect(accounts.map((a) => a.accountId)).toContain("enabled1");
|
||||
expect(accounts.map((a) => a.accountId)).not.toContain("disabled1");
|
||||
});
|
||||
|
||||
it("returns empty array when channel is disabled", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
ringcentral: {
|
||||
enabled: false,
|
||||
accounts: {
|
||||
work: { enabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
} as ClawdbotConfig;
|
||||
|
||||
const accounts = listEnabledRingCentralAccounts(cfg);
|
||||
|
||||
expect(accounts).toEqual([]);
|
||||
});
|
||||
});
|
||||
47
extensions/ringcentral/src/monitor.test.ts
Normal file
47
extensions/ringcentral/src/monitor.test.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isSenderAllowed } from "./monitor.js";
|
||||
|
||||
describe("isSenderAllowed", () => {
|
||||
it("returns true when allowFrom contains wildcard", () => {
|
||||
expect(isSenderAllowed("12345", ["*"])).toBe(true);
|
||||
expect(isSenderAllowed("any-user", ["*"])).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true when sender ID matches exactly", () => {
|
||||
expect(isSenderAllowed("12345", ["12345"])).toBe(true);
|
||||
expect(isSenderAllowed("12345", ["other", "12345"])).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true when sender ID matches with ringcentral: prefix", () => {
|
||||
expect(isSenderAllowed("12345", ["ringcentral:12345"])).toBe(true);
|
||||
expect(isSenderAllowed("12345", ["RINGCENTRAL:12345"])).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true when sender ID matches with rc: prefix", () => {
|
||||
expect(isSenderAllowed("12345", ["rc:12345"])).toBe(true);
|
||||
expect(isSenderAllowed("12345", ["RC:12345"])).toBe(true);
|
||||
});
|
||||
|
||||
it("returns true when sender ID matches with user: prefix", () => {
|
||||
expect(isSenderAllowed("12345", ["user:12345"])).toBe(true);
|
||||
expect(isSenderAllowed("12345", ["USER:12345"])).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when sender ID not in allowFrom", () => {
|
||||
expect(isSenderAllowed("12345", ["67890"])).toBe(false);
|
||||
expect(isSenderAllowed("12345", [])).toBe(false);
|
||||
});
|
||||
|
||||
it("handles case-insensitive matching", () => {
|
||||
expect(isSenderAllowed("ABC123", ["abc123"])).toBe(true);
|
||||
expect(isSenderAllowed("abc123", ["ABC123"])).toBe(true);
|
||||
});
|
||||
|
||||
it("handles whitespace in allowFrom entries", () => {
|
||||
expect(isSenderAllowed("12345", [" 12345 "])).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores empty entries in allowFrom", () => {
|
||||
expect(isSenderAllowed("12345", ["", "12345", " "])).toBe(true);
|
||||
});
|
||||
});
|
||||
118
extensions/ringcentral/src/targets.test.ts
Normal file
118
extensions/ringcentral/src/targets.test.ts
Normal file
@ -0,0 +1,118 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
normalizeRingCentralTarget,
|
||||
isRingCentralChatTarget,
|
||||
isRingCentralUserTarget,
|
||||
formatRingCentralChatTarget,
|
||||
formatRingCentralUserTarget,
|
||||
parseRingCentralTarget,
|
||||
} from "./targets.js";
|
||||
|
||||
describe("normalizeRingCentralTarget", () => {
|
||||
it("returns null for empty string", () => {
|
||||
expect(normalizeRingCentralTarget("")).toBeNull();
|
||||
expect(normalizeRingCentralTarget(" ")).toBeNull();
|
||||
});
|
||||
|
||||
it("removes ringcentral: prefix", () => {
|
||||
expect(normalizeRingCentralTarget("ringcentral:12345")).toBe("12345");
|
||||
expect(normalizeRingCentralTarget("RINGCENTRAL:12345")).toBe("12345");
|
||||
});
|
||||
|
||||
it("removes rc: prefix", () => {
|
||||
expect(normalizeRingCentralTarget("rc:12345")).toBe("12345");
|
||||
expect(normalizeRingCentralTarget("RC:12345")).toBe("12345");
|
||||
});
|
||||
|
||||
it("removes chat: prefix", () => {
|
||||
expect(normalizeRingCentralTarget("chat:12345")).toBe("12345");
|
||||
});
|
||||
|
||||
it("removes user: prefix", () => {
|
||||
expect(normalizeRingCentralTarget("user:12345")).toBe("12345");
|
||||
});
|
||||
|
||||
it("removes combined prefixes", () => {
|
||||
expect(normalizeRingCentralTarget("rc:chat:12345")).toBe("12345");
|
||||
expect(normalizeRingCentralTarget("ringcentral:user:12345")).toBe("12345");
|
||||
});
|
||||
|
||||
it("trims whitespace", () => {
|
||||
expect(normalizeRingCentralTarget(" 12345 ")).toBe("12345");
|
||||
});
|
||||
|
||||
it("returns plain ID as-is", () => {
|
||||
expect(normalizeRingCentralTarget("12345")).toBe("12345");
|
||||
});
|
||||
});
|
||||
|
||||
describe("isRingCentralChatTarget", () => {
|
||||
it("returns true for numeric IDs", () => {
|
||||
expect(isRingCentralChatTarget("12345")).toBe(true);
|
||||
expect(isRingCentralChatTarget("rc:12345")).toBe(true);
|
||||
expect(isRingCentralChatTarget("chat:12345")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for non-numeric IDs", () => {
|
||||
expect(isRingCentralChatTarget("abc")).toBe(false);
|
||||
expect(isRingCentralChatTarget("12345abc")).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false for empty string", () => {
|
||||
expect(isRingCentralChatTarget("")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isRingCentralUserTarget", () => {
|
||||
it("returns true for numeric IDs", () => {
|
||||
expect(isRingCentralUserTarget("12345")).toBe(true);
|
||||
expect(isRingCentralUserTarget("rc:12345")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for empty string", () => {
|
||||
expect(isRingCentralUserTarget("")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatRingCentralChatTarget", () => {
|
||||
it("formats chat ID with rc:chat: prefix", () => {
|
||||
expect(formatRingCentralChatTarget("12345")).toBe("rc:chat:12345");
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatRingCentralUserTarget", () => {
|
||||
it("formats user ID with rc:user: prefix", () => {
|
||||
expect(formatRingCentralUserTarget("12345")).toBe("rc:user:12345");
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseRingCentralTarget", () => {
|
||||
it("parses chat: prefix", () => {
|
||||
expect(parseRingCentralTarget("chat:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
expect(parseRingCentralTarget("rc:chat:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
expect(parseRingCentralTarget("ringcentral:chat:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
});
|
||||
|
||||
it("parses user: prefix", () => {
|
||||
expect(parseRingCentralTarget("user:12345")).toEqual({ type: "user", id: "12345" });
|
||||
expect(parseRingCentralTarget("rc:user:12345")).toEqual({ type: "user", id: "12345" });
|
||||
});
|
||||
|
||||
it("parses group: prefix as chat", () => {
|
||||
expect(parseRingCentralTarget("group:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
expect(parseRingCentralTarget("team:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
});
|
||||
|
||||
it("defaults numeric IDs to chat type", () => {
|
||||
expect(parseRingCentralTarget("12345")).toEqual({ type: "chat", id: "12345" });
|
||||
expect(parseRingCentralTarget("rc:12345")).toEqual({ type: "chat", id: "12345" });
|
||||
});
|
||||
|
||||
it("returns unknown for non-numeric IDs without type prefix", () => {
|
||||
expect(parseRingCentralTarget("abc")).toEqual({ type: "unknown", id: "abc" });
|
||||
});
|
||||
|
||||
it("trims whitespace", () => {
|
||||
expect(parseRingCentralTarget(" chat:12345 ")).toEqual({ type: "chat", id: "12345" });
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user