mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 22:40:26 +00:00
328 lines
9.8 KiB
TypeScript
328 lines
9.8 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import type { ChannelPlugin } from "../channels/plugins/types.js";
|
|
|
|
vi.mock("../channels/plugins/index.js", () => ({
|
|
listChannelPlugins: vi.fn(),
|
|
}));
|
|
|
|
const { buildChannelSummary } = await import("./channel-summary.js");
|
|
const { listChannelPlugins } = await import("../channels/plugins/index.js");
|
|
|
|
function makeSlackHttpSummaryPlugin(): ChannelPlugin {
|
|
return {
|
|
id: "slack",
|
|
meta: {
|
|
id: "slack",
|
|
label: "Slack",
|
|
selectionLabel: "Slack",
|
|
docsPath: "/channels/slack",
|
|
blurb: "test",
|
|
},
|
|
capabilities: { chatTypes: ["direct"] },
|
|
config: {
|
|
listAccountIds: () => ["primary"],
|
|
defaultAccountId: () => "primary",
|
|
inspectAccount: (cfg) =>
|
|
(cfg as { marker?: string }).marker === "source"
|
|
? {
|
|
accountId: "primary",
|
|
name: "Primary",
|
|
enabled: true,
|
|
configured: true,
|
|
mode: "http",
|
|
botToken: "xoxb-http",
|
|
signingSecret: "",
|
|
botTokenSource: "config",
|
|
signingSecretSource: "config", // pragma: allowlist secret
|
|
botTokenStatus: "available",
|
|
signingSecretStatus: "configured_unavailable", // pragma: allowlist secret
|
|
}
|
|
: {
|
|
accountId: "primary",
|
|
name: "Primary",
|
|
enabled: true,
|
|
configured: false,
|
|
mode: "http",
|
|
botToken: "xoxb-http",
|
|
botTokenSource: "config",
|
|
botTokenStatus: "available",
|
|
},
|
|
resolveAccount: () => ({
|
|
accountId: "primary",
|
|
name: "Primary",
|
|
enabled: true,
|
|
configured: false,
|
|
mode: "http",
|
|
botToken: "xoxb-http",
|
|
botTokenSource: "config",
|
|
botTokenStatus: "available",
|
|
}),
|
|
isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
|
|
isEnabled: () => true,
|
|
},
|
|
actions: {
|
|
listActions: () => ["send"],
|
|
},
|
|
};
|
|
}
|
|
|
|
function makeTelegramSummaryPlugin(params: {
|
|
enabled: boolean;
|
|
configured: boolean;
|
|
linked?: boolean;
|
|
authAgeMs?: number;
|
|
allowFrom?: string[];
|
|
}): ChannelPlugin {
|
|
return {
|
|
id: "telegram",
|
|
meta: {
|
|
id: "telegram",
|
|
label: "Telegram",
|
|
selectionLabel: "Telegram",
|
|
docsPath: "/channels/telegram",
|
|
blurb: "test",
|
|
},
|
|
capabilities: { chatTypes: ["direct"] },
|
|
config: {
|
|
listAccountIds: () => ["primary"],
|
|
defaultAccountId: () => "primary",
|
|
inspectAccount: () => ({
|
|
accountId: "primary",
|
|
name: "Main Bot",
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
linked: params.linked,
|
|
allowFrom: params.allowFrom ?? [],
|
|
dmPolicy: "mutuals",
|
|
tokenSource: "env",
|
|
}),
|
|
resolveAccount: () => ({
|
|
accountId: "primary",
|
|
name: "Main Bot",
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
linked: params.linked,
|
|
allowFrom: params.allowFrom ?? [],
|
|
dmPolicy: "mutuals",
|
|
tokenSource: "env",
|
|
}),
|
|
isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
|
|
isEnabled: (account) => Boolean((account as { enabled?: boolean }).enabled),
|
|
formatAllowFrom: () => ["alice", "bob", "carol"],
|
|
},
|
|
status: {
|
|
buildChannelSummary: async () => ({
|
|
linked: params.linked,
|
|
configured: params.configured,
|
|
authAgeMs: params.authAgeMs,
|
|
self: { e164: "+15551234567" },
|
|
}),
|
|
},
|
|
actions: {
|
|
listActions: () => ["send"],
|
|
},
|
|
};
|
|
}
|
|
|
|
function makeSignalSummaryPlugin(params: { enabled: boolean; configured: boolean }): ChannelPlugin {
|
|
return {
|
|
id: "signal",
|
|
meta: {
|
|
id: "signal",
|
|
label: "Signal",
|
|
selectionLabel: "Signal",
|
|
docsPath: "/channels/signal",
|
|
blurb: "test",
|
|
},
|
|
capabilities: { chatTypes: ["direct"] },
|
|
config: {
|
|
listAccountIds: () => ["desktop"],
|
|
defaultAccountId: () => "desktop",
|
|
inspectAccount: () => ({
|
|
accountId: "desktop",
|
|
name: "Desktop",
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
appTokenSource: "env",
|
|
baseUrl: "https://signal.example.test",
|
|
port: 31337,
|
|
cliPath: "/usr/local/bin/signal-cli",
|
|
dbPath: "/tmp/signal.db",
|
|
}),
|
|
resolveAccount: () => ({
|
|
accountId: "desktop",
|
|
name: "Desktop",
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
appTokenSource: "env",
|
|
baseUrl: "https://signal.example.test",
|
|
port: 31337,
|
|
cliPath: "/usr/local/bin/signal-cli",
|
|
dbPath: "/tmp/signal.db",
|
|
}),
|
|
isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
|
|
isEnabled: (account) => Boolean((account as { enabled?: boolean }).enabled),
|
|
},
|
|
actions: {
|
|
listActions: () => ["send"],
|
|
},
|
|
};
|
|
}
|
|
|
|
function makeFallbackSummaryPlugin(params: {
|
|
configured: boolean;
|
|
enabled: boolean;
|
|
accountIds?: string[];
|
|
defaultAccountId?: string;
|
|
}): ChannelPlugin {
|
|
return {
|
|
id: "fallback-plugin",
|
|
meta: {
|
|
id: "fallback-plugin",
|
|
label: "Fallback",
|
|
selectionLabel: "Fallback",
|
|
docsPath: "/channels/fallback",
|
|
blurb: "test",
|
|
},
|
|
capabilities: { chatTypes: ["direct"] },
|
|
config: {
|
|
listAccountIds: () => params.accountIds ?? [],
|
|
defaultAccountId: () => params.defaultAccountId ?? "default",
|
|
inspectAccount: (_cfg, accountId) => ({
|
|
accountId,
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
}),
|
|
resolveAccount: (_cfg, accountId) => ({
|
|
accountId,
|
|
enabled: params.enabled,
|
|
configured: params.configured,
|
|
}),
|
|
isConfigured: (account) => Boolean((account as { configured?: boolean }).configured),
|
|
isEnabled: (account) => Boolean((account as { enabled?: boolean }).enabled),
|
|
},
|
|
actions: {
|
|
listActions: () => ["send"],
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("buildChannelSummary", () => {
|
|
it("preserves Slack HTTP signing-secret unavailable state from source config", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([makeSlackHttpSummaryPlugin()]);
|
|
|
|
const lines = await buildChannelSummary({ marker: "resolved", channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: false,
|
|
sourceConfig: { marker: "source", channels: {} } as never,
|
|
});
|
|
|
|
expect(lines).toContain("Slack: configured");
|
|
expect(lines).toContain(
|
|
" - primary (Primary) (bot:config, signing:config, secret unavailable in this command path)",
|
|
);
|
|
});
|
|
|
|
it("shows disabled status without configured account detail lines", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeTelegramSummaryPlugin({ enabled: false, configured: false }),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: true,
|
|
});
|
|
|
|
expect(lines).toEqual(["Telegram: disabled +15551234567"]);
|
|
});
|
|
|
|
it("includes linked summary metadata and truncates allow-from details", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeTelegramSummaryPlugin({
|
|
enabled: true,
|
|
configured: true,
|
|
linked: true,
|
|
authAgeMs: 300_000,
|
|
allowFrom: ["alice", "bob", "carol"],
|
|
}),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: true,
|
|
});
|
|
|
|
expect(lines).toContain("Telegram: linked +15551234567 auth 5m ago");
|
|
expect(lines).toContain(" - primary (Main Bot) (dm:mutuals, token:env, allow:alice,bob)");
|
|
});
|
|
|
|
it("shows not-linked status when linked metadata is explicitly false", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeTelegramSummaryPlugin({
|
|
enabled: true,
|
|
configured: true,
|
|
linked: false,
|
|
}),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: false,
|
|
});
|
|
|
|
expect(lines).toContain("Telegram: not linked +15551234567");
|
|
expect(lines).toContain(" - primary (Main Bot) (dm:mutuals, token:env)");
|
|
});
|
|
|
|
it("renders non-slack account detail fields for configured accounts", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeSignalSummaryPlugin({ enabled: false, configured: true }),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: false,
|
|
});
|
|
|
|
expect(lines).toEqual([
|
|
"Signal: disabled",
|
|
" - desktop (Desktop) (disabled, app:env, https://signal.example.test, port:31337, cli:/usr/local/bin/signal-cli, db:/tmp/signal.db)",
|
|
]);
|
|
});
|
|
|
|
it("uses the channel label and default account id when no accounts exist", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeFallbackSummaryPlugin({
|
|
enabled: true,
|
|
configured: true,
|
|
accountIds: [],
|
|
defaultAccountId: "fallback-account",
|
|
}),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: false,
|
|
});
|
|
|
|
expect(lines).toEqual(["Fallback: configured", " - fallback-account"]);
|
|
});
|
|
|
|
it("shows not-configured status when enabled accounts exist without configured ones", async () => {
|
|
vi.mocked(listChannelPlugins).mockReturnValue([
|
|
makeFallbackSummaryPlugin({
|
|
enabled: true,
|
|
configured: false,
|
|
accountIds: ["fallback-account"],
|
|
}),
|
|
]);
|
|
|
|
const lines = await buildChannelSummary({ channels: {} } as never, {
|
|
colorize: false,
|
|
includeAllowFrom: false,
|
|
});
|
|
|
|
expect(lines).toEqual(["Fallback: not configured"]);
|
|
});
|
|
});
|