mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 14:48:55 +02:00
test: clear synology chat channel broad matchers
This commit is contained in:
@@ -26,6 +26,14 @@ function makeSecurityAccount(
|
||||
return { ...securityAccountDefaults, ...overrides };
|
||||
}
|
||||
|
||||
function expectIncludesSubstring(values: readonly string[], expected: string): void {
|
||||
expect(values.some((value) => value.includes(expected))).toBe(true);
|
||||
}
|
||||
|
||||
function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] {
|
||||
return mock.mock.calls.map((call) => String(call[0] ?? ""));
|
||||
}
|
||||
|
||||
const clientModule = await import("./client.js");
|
||||
const gatewayRuntimeModule = await import("./gateway-runtime.js");
|
||||
const mockSendMessage = vi.spyOn(clientModule, "sendMessage").mockResolvedValue(true);
|
||||
@@ -112,16 +120,14 @@ describe("createSynologyChatPlugin", () => {
|
||||
};
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = plugin.config.resolveAccount(cfg, "office");
|
||||
expect(account).toMatchObject({
|
||||
accountId: "office",
|
||||
token: "office-token",
|
||||
incomingUrl: "https://nas/base",
|
||||
nasHost: "nas-base",
|
||||
allowedUserIds: ["base-user"],
|
||||
rateLimitPerMinute: 45,
|
||||
botName: "Base Bot",
|
||||
allowInsecureSsl: true,
|
||||
});
|
||||
expect(account.accountId).toBe("office");
|
||||
expect(account.token).toBe("office-token");
|
||||
expect(account.incomingUrl).toBe("https://nas/base");
|
||||
expect(account.nasHost).toBe("nas-base");
|
||||
expect(account.allowedUserIds).toEqual(["base-user"]);
|
||||
expect(account.rateLimitPerMinute).toBe(45);
|
||||
expect(account.botName).toBe("Base Bot");
|
||||
expect(account.allowInsecureSsl).toBe(true);
|
||||
});
|
||||
|
||||
it("defaultAccountId returns 'default'", () => {
|
||||
@@ -256,23 +262,21 @@ describe("createSynologyChatPlugin", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount({ token: "" });
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(expect.arrayContaining([expect.stringContaining("token")]));
|
||||
expectIncludesSubstring(warnings, "token");
|
||||
});
|
||||
|
||||
it("warns when allowInsecureSsl is true", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount({ allowInsecureSsl: true });
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(expect.arrayContaining([expect.stringContaining("SSL")]));
|
||||
expectIncludesSubstring(warnings, "SSL");
|
||||
});
|
||||
|
||||
it("warns when dangerous name matching is enabled", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount({ dangerouslyAllowNameMatching: true });
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining("dangerouslyAllowNameMatching")]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "dangerouslyAllowNameMatching");
|
||||
});
|
||||
|
||||
it("warns when inherited shared webhookPath is dangerously re-enabled", () => {
|
||||
@@ -283,36 +287,28 @@ describe("createSynologyChatPlugin", () => {
|
||||
dangerouslyAllowInheritedWebhookPath: true,
|
||||
});
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining("dangerouslyAllowInheritedWebhookPath=true"),
|
||||
]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "dangerouslyAllowInheritedWebhookPath=true");
|
||||
});
|
||||
|
||||
it("warns when dmPolicy is open", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount({ dmPolicy: "open", allowedUserIds: ["*"] });
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(expect.arrayContaining([expect.stringContaining("open")]));
|
||||
expectIncludesSubstring(warnings, "open");
|
||||
});
|
||||
|
||||
it("warns when dmPolicy is open and allowedUserIds is empty", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount({ dmPolicy: "open", allowedUserIds: [] });
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining("empty allowedUserIds")]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "empty allowedUserIds");
|
||||
});
|
||||
|
||||
it("warns when dmPolicy is allowlist and allowedUserIds is empty", () => {
|
||||
const plugin = createSynologyChatPlugin();
|
||||
const account = makeSecurityAccount();
|
||||
const warnings = plugin.security.collectWarnings({ cfg: {}, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining("empty allowedUserIds")]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "empty allowedUserIds");
|
||||
});
|
||||
|
||||
it("warns when named multi-account routes inherit a shared webhookPath", () => {
|
||||
@@ -320,9 +316,7 @@ describe("createSynologyChatPlugin", () => {
|
||||
const cfg = makeSharedWebhookConfig();
|
||||
const account = plugin.config.resolveAccount(cfg, "alerts");
|
||||
const warnings = plugin.security.collectWarnings({ cfg, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining("must set an explicit webhookPath")]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "must set an explicit webhookPath");
|
||||
});
|
||||
|
||||
it("warns when enabled accounts share the same exact webhookPath", () => {
|
||||
@@ -342,9 +336,7 @@ describe("createSynologyChatPlugin", () => {
|
||||
};
|
||||
const account = plugin.config.resolveAccount(cfg, "alerts");
|
||||
const warnings = plugin.security.collectWarnings({ cfg, account });
|
||||
expect(warnings).toEqual(
|
||||
expect.arrayContaining([expect.stringContaining("conflicts on webhookPath")]),
|
||||
);
|
||||
expectIncludesSubstring(warnings, "conflicts on webhookPath");
|
||||
});
|
||||
|
||||
it("returns no warnings for fully configured account", () => {
|
||||
@@ -410,42 +402,41 @@ describe("createSynologyChatPlugin", () => {
|
||||
},
|
||||
};
|
||||
|
||||
await expect(
|
||||
verifyChannelMessageAdapterCapabilityProofs({
|
||||
adapterName: "synology-chat",
|
||||
adapter: plugin.message,
|
||||
proofs: {
|
||||
text: async () => {
|
||||
const result = await plugin.message.send?.text?.({
|
||||
cfg,
|
||||
text: "hello",
|
||||
to: "user1",
|
||||
});
|
||||
expect(result?.receipt.parts[0]?.kind).toBe("text");
|
||||
expect(result?.receipt.platformMessageIds).toHaveLength(1);
|
||||
},
|
||||
media: async () => {
|
||||
const result = await plugin.message.send?.media?.({
|
||||
cfg,
|
||||
text: "image",
|
||||
mediaUrl: "https://example.com/img.png",
|
||||
to: "user1",
|
||||
});
|
||||
expect(result?.receipt.parts[0]?.kind).toBe("media");
|
||||
expect(result?.receipt.platformMessageIds).toHaveLength(1);
|
||||
},
|
||||
messageSendingHooks: () => {
|
||||
expect(plugin.message.durableFinal?.capabilities?.messageSendingHooks).toBe(true);
|
||||
},
|
||||
const results = await verifyChannelMessageAdapterCapabilityProofs({
|
||||
adapterName: "synology-chat",
|
||||
adapter: plugin.message,
|
||||
proofs: {
|
||||
text: async () => {
|
||||
const result = await plugin.message.send?.text?.({
|
||||
cfg,
|
||||
text: "hello",
|
||||
to: "user1",
|
||||
});
|
||||
expect(result?.receipt.parts[0]?.kind).toBe("text");
|
||||
expect(result?.receipt.platformMessageIds).toHaveLength(1);
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.arrayContaining([
|
||||
{ capability: "text", status: "verified" },
|
||||
{ capability: "media", status: "verified" },
|
||||
{ capability: "messageSendingHooks", status: "verified" },
|
||||
]),
|
||||
media: async () => {
|
||||
const result = await plugin.message.send?.media?.({
|
||||
cfg,
|
||||
text: "image",
|
||||
mediaUrl: "https://example.com/img.png",
|
||||
to: "user1",
|
||||
});
|
||||
expect(result?.receipt.parts[0]?.kind).toBe("media");
|
||||
expect(result?.receipt.platformMessageIds).toHaveLength(1);
|
||||
},
|
||||
messageSendingHooks: () => {
|
||||
expect(plugin.message.durableFinal?.capabilities?.messageSendingHooks).toBe(true);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const statusByCapability = new Map(
|
||||
results.map(({ capability, status }) => [capability, status]),
|
||||
);
|
||||
expect(statusByCapability.get("text")).toBe("verified");
|
||||
expect(statusByCapability.get("media")).toBe("verified");
|
||||
expect(statusByCapability.get("messageSendingHooks")).toBe("verified");
|
||||
});
|
||||
|
||||
it("sendText throws when no incomingUrl", async () => {
|
||||
@@ -479,10 +470,8 @@ describe("createSynologyChatPlugin", () => {
|
||||
text: "hello",
|
||||
to: "user1",
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
channel: "synology-chat",
|
||||
chatId: "user1",
|
||||
});
|
||||
expect(result.channel).toBe("synology-chat");
|
||||
expect(result.chatId).toBe("user1");
|
||||
expect(result.messageId).toMatch(/^sc-\d+$/);
|
||||
expect(result.receipt.primaryPlatformMessageId).toBe(result.messageId);
|
||||
expect(result.receipt.parts[0]?.kind).toBe("text");
|
||||
@@ -605,7 +594,7 @@ describe("createSynologyChatPlugin", () => {
|
||||
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
expect(ctx.log.warn).toHaveBeenCalledWith(expect.stringContaining("empty allowedUserIds"));
|
||||
expectIncludesSubstring(mockStringMessages(ctx.log.warn), "empty allowedUserIds");
|
||||
expect(registerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -623,8 +612,9 @@ describe("createSynologyChatPlugin", () => {
|
||||
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
expect(ctx.log.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("dmPolicy=open but empty allowedUserIds"),
|
||||
expectIncludesSubstring(
|
||||
mockStringMessages(ctx.log.warn),
|
||||
"dmPolicy=open but empty allowedUserIds",
|
||||
);
|
||||
expect(registerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -639,9 +629,7 @@ describe("createSynologyChatPlugin", () => {
|
||||
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
expect(ctx.log.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("must set an explicit webhookPath"),
|
||||
);
|
||||
expectIncludesSubstring(mockStringMessages(ctx.log.warn), "must set an explicit webhookPath");
|
||||
expect(registerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -656,9 +644,7 @@ describe("createSynologyChatPlugin", () => {
|
||||
|
||||
const result = plugin.gateway.startAccount(ctx);
|
||||
await expectPendingStartAccountPromise(result, abortController);
|
||||
expect(ctx.log.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("conflicts on webhookPath"),
|
||||
);
|
||||
expectIncludesSubstring(mockStringMessages(ctx.log.warn), "conflicts on webhookPath");
|
||||
expect(registerMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user