mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 00:28:26 +00:00
feat: Add Line plugin (#1630)
* feat: add LINE plugin (#1630) (thanks @plum-dawg) * feat: complete LINE plugin (#1630) (thanks @plum-dawg) * chore: drop line plugin node_modules (#1630) (thanks @plum-dawg) * test: mock /context report in commands test (#1630) (thanks @plum-dawg) * test: limit macOS CI workers to avoid OOM (#1630) (thanks @plum-dawg) * test: reduce macOS CI vitest workers (#1630) (thanks @plum-dawg) --------- Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
173
src/line/bot-handlers.test.ts
Normal file
173
src/line/bot-handlers.test.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { MessageEvent } from "@line/bot-sdk";
|
||||
|
||||
const { buildLineMessageContextMock, buildLinePostbackContextMock } = vi.hoisted(() => ({
|
||||
buildLineMessageContextMock: vi.fn(async () => ({
|
||||
ctxPayload: { From: "line:group:group-1" },
|
||||
replyToken: "reply-token",
|
||||
route: { agentId: "default" },
|
||||
isGroup: true,
|
||||
accountId: "default",
|
||||
})),
|
||||
buildLinePostbackContextMock: vi.fn(async () => null),
|
||||
}));
|
||||
|
||||
vi.mock("./bot-message-context.js", () => ({
|
||||
buildLineMessageContext: (...args: unknown[]) => buildLineMessageContextMock(...args),
|
||||
buildLinePostbackContext: (...args: unknown[]) => buildLinePostbackContextMock(...args),
|
||||
}));
|
||||
|
||||
const { readAllowFromStoreMock, upsertPairingRequestMock } = vi.hoisted(() => ({
|
||||
readAllowFromStoreMock: vi.fn(async () => [] as string[]),
|
||||
upsertPairingRequestMock: vi.fn(async () => ({ code: "CODE", created: true })),
|
||||
}));
|
||||
|
||||
let handleLineWebhookEvents: typeof import("./bot-handlers.js").handleLineWebhookEvents;
|
||||
|
||||
vi.mock("../pairing/pairing-store.js", () => ({
|
||||
readChannelAllowFromStore: (...args: unknown[]) => readAllowFromStoreMock(...args),
|
||||
upsertChannelPairingRequest: (...args: unknown[]) => upsertPairingRequestMock(...args),
|
||||
}));
|
||||
|
||||
describe("handleLineWebhookEvents", () => {
|
||||
beforeAll(async () => {
|
||||
({ handleLineWebhookEvents } = await import("./bot-handlers.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
buildLineMessageContextMock.mockClear();
|
||||
buildLinePostbackContextMock.mockClear();
|
||||
readAllowFromStoreMock.mockClear();
|
||||
upsertPairingRequestMock.mockClear();
|
||||
});
|
||||
|
||||
it("blocks group messages when groupPolicy is disabled", async () => {
|
||||
const processMessage = vi.fn();
|
||||
const event = {
|
||||
type: "message",
|
||||
message: { id: "m1", type: "text", text: "hi" },
|
||||
replyToken: "reply-token",
|
||||
timestamp: Date.now(),
|
||||
source: { type: "group", groupId: "group-1", userId: "user-1" },
|
||||
mode: "active",
|
||||
webhookEventId: "evt-1",
|
||||
deliveryContext: { isRedelivery: false },
|
||||
} as MessageEvent;
|
||||
|
||||
await handleLineWebhookEvents([event], {
|
||||
cfg: { channels: { line: { groupPolicy: "disabled" } } },
|
||||
account: {
|
||||
accountId: "default",
|
||||
enabled: true,
|
||||
channelAccessToken: "token",
|
||||
channelSecret: "secret",
|
||||
tokenSource: "config",
|
||||
config: { groupPolicy: "disabled" },
|
||||
},
|
||||
runtime: { error: vi.fn() },
|
||||
mediaMaxBytes: 1,
|
||||
processMessage,
|
||||
});
|
||||
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
expect(buildLineMessageContextMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("blocks group messages when allowlist is empty", async () => {
|
||||
const processMessage = vi.fn();
|
||||
const event = {
|
||||
type: "message",
|
||||
message: { id: "m2", type: "text", text: "hi" },
|
||||
replyToken: "reply-token",
|
||||
timestamp: Date.now(),
|
||||
source: { type: "group", groupId: "group-1", userId: "user-2" },
|
||||
mode: "active",
|
||||
webhookEventId: "evt-2",
|
||||
deliveryContext: { isRedelivery: false },
|
||||
} as MessageEvent;
|
||||
|
||||
await handleLineWebhookEvents([event], {
|
||||
cfg: { channels: { line: { groupPolicy: "allowlist" } } },
|
||||
account: {
|
||||
accountId: "default",
|
||||
enabled: true,
|
||||
channelAccessToken: "token",
|
||||
channelSecret: "secret",
|
||||
tokenSource: "config",
|
||||
config: { groupPolicy: "allowlist" },
|
||||
},
|
||||
runtime: { error: vi.fn() },
|
||||
mediaMaxBytes: 1,
|
||||
processMessage,
|
||||
});
|
||||
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
expect(buildLineMessageContextMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("allows group messages when sender is in groupAllowFrom", async () => {
|
||||
const processMessage = vi.fn();
|
||||
const event = {
|
||||
type: "message",
|
||||
message: { id: "m3", type: "text", text: "hi" },
|
||||
replyToken: "reply-token",
|
||||
timestamp: Date.now(),
|
||||
source: { type: "group", groupId: "group-1", userId: "user-3" },
|
||||
mode: "active",
|
||||
webhookEventId: "evt-3",
|
||||
deliveryContext: { isRedelivery: false },
|
||||
} as MessageEvent;
|
||||
|
||||
await handleLineWebhookEvents([event], {
|
||||
cfg: {
|
||||
channels: { line: { groupPolicy: "allowlist", groupAllowFrom: ["user-3"] } },
|
||||
},
|
||||
account: {
|
||||
accountId: "default",
|
||||
enabled: true,
|
||||
channelAccessToken: "token",
|
||||
channelSecret: "secret",
|
||||
tokenSource: "config",
|
||||
config: { groupPolicy: "allowlist", groupAllowFrom: ["user-3"] },
|
||||
},
|
||||
runtime: { error: vi.fn() },
|
||||
mediaMaxBytes: 1,
|
||||
processMessage,
|
||||
});
|
||||
|
||||
expect(buildLineMessageContextMock).toHaveBeenCalledTimes(1);
|
||||
expect(processMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("blocks group messages when wildcard group config disables groups", async () => {
|
||||
const processMessage = vi.fn();
|
||||
const event = {
|
||||
type: "message",
|
||||
message: { id: "m4", type: "text", text: "hi" },
|
||||
replyToken: "reply-token",
|
||||
timestamp: Date.now(),
|
||||
source: { type: "group", groupId: "group-2", userId: "user-4" },
|
||||
mode: "active",
|
||||
webhookEventId: "evt-4",
|
||||
deliveryContext: { isRedelivery: false },
|
||||
} as MessageEvent;
|
||||
|
||||
await handleLineWebhookEvents([event], {
|
||||
cfg: { channels: { line: { groupPolicy: "open" } } },
|
||||
account: {
|
||||
accountId: "default",
|
||||
enabled: true,
|
||||
channelAccessToken: "token",
|
||||
channelSecret: "secret",
|
||||
tokenSource: "config",
|
||||
config: { groupPolicy: "open", groups: { "*": { enabled: false } } },
|
||||
},
|
||||
runtime: { error: vi.fn() },
|
||||
mediaMaxBytes: 1,
|
||||
processMessage,
|
||||
});
|
||||
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
expect(buildLineMessageContextMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user