mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-23 02:24:44 +00:00
test(discord): cover durable chunk retry delivery (#82898)
* test(discord): cover durable chunk retry delivery * test(discord): use plugin sdk test runtime * fix(telegram): satisfy message cache strict checks * test(discord): include durable delivery in changed lane
This commit is contained in:
committed by
GitHub
parent
df23b0f86c
commit
6a8a6551fc
103
extensions/discord/src/durable-delivery.test.ts
Normal file
103
extensions/discord/src/durable-delivery.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-message";
|
||||
import {
|
||||
createEmptyPluginRegistry,
|
||||
createTestRegistry,
|
||||
resetPluginRuntimeStateForTest,
|
||||
setActivePluginRegistry,
|
||||
} from "openclaw/plugin-sdk/plugin-test-runtime";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
createDiscordOutboundHoisted,
|
||||
installDiscordOutboundModuleSpies,
|
||||
resetDiscordOutboundMocks,
|
||||
} from "./outbound-adapter.test-harness.js";
|
||||
|
||||
const hoisted = createDiscordOutboundHoisted();
|
||||
await installDiscordOutboundModuleSpies(hoisted);
|
||||
|
||||
let discordPlugin: typeof import("./channel.js").discordPlugin;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ discordPlugin } = await import("./channel.js"));
|
||||
});
|
||||
|
||||
describe("durable Discord delivery", () => {
|
||||
beforeEach(() => {
|
||||
resetDiscordOutboundMocks(hoisted);
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "discord",
|
||||
source: "test",
|
||||
plugin: discordPlugin,
|
||||
},
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetPluginRuntimeStateForTest();
|
||||
setActivePluginRegistry(createEmptyPluginRegistry());
|
||||
});
|
||||
|
||||
it("fans out planned text chunks and retries a transient failure on a later chunk", async () => {
|
||||
hoisted.sendMessageDiscordMock
|
||||
.mockResolvedValueOnce({
|
||||
messageId: "msg-chunk-1",
|
||||
channelId: "ch-1",
|
||||
})
|
||||
.mockRejectedValueOnce(Object.assign(new Error("discord 500"), { status: 500 }))
|
||||
.mockResolvedValueOnce({
|
||||
messageId: "msg-chunk-2",
|
||||
channelId: "ch-1",
|
||||
});
|
||||
|
||||
const result = await sendDurableMessageBatch({
|
||||
cfg: {
|
||||
channels: {
|
||||
discord: {
|
||||
token: "test-token",
|
||||
retry: { attempts: 2, minDelayMs: 0, maxDelayMs: 0, jitter: 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
channel: "discord",
|
||||
to: "channel:123456",
|
||||
payloads: [{ text: "first chunk\nsecond chunk" }],
|
||||
formatting: {
|
||||
chunkMode: "newline",
|
||||
maxLinesPerMessage: 1,
|
||||
textLimit: 2000,
|
||||
},
|
||||
skipQueue: true,
|
||||
});
|
||||
|
||||
expect(result.status).toBe("sent");
|
||||
if (result.status !== "sent") {
|
||||
throw new Error("expected durable Discord send to succeed");
|
||||
}
|
||||
expect(
|
||||
result.results.map((entry) => ({
|
||||
channel: entry.channel,
|
||||
messageId: entry.messageId,
|
||||
})),
|
||||
).toEqual([
|
||||
{ channel: "discord", messageId: "msg-chunk-1" },
|
||||
{ channel: "discord", messageId: "msg-chunk-2" },
|
||||
]);
|
||||
expect(result.receipt.platformMessageIds).toEqual(["msg-chunk-1", "msg-chunk-2"]);
|
||||
expect(result.payloadOutcomes).toEqual([
|
||||
{
|
||||
index: 0,
|
||||
status: "sent",
|
||||
results: result.results,
|
||||
},
|
||||
]);
|
||||
expect(hoisted.sendMessageDiscordMock).toHaveBeenCalledTimes(3);
|
||||
expect(hoisted.sendMessageDiscordMock.mock.calls.map((call) => call[1])).toEqual([
|
||||
"first chunk",
|
||||
"second chunk",
|
||||
"second chunk",
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -568,7 +568,7 @@ export function createTelegramMessageCache(params?: {
|
||||
}
|
||||
const key = telegramMessageCacheKey({ accountId, chatId, messageId });
|
||||
const cachedNode = upsertCachedMessageNode({ messages, key, node, mode });
|
||||
if (node.messageId === currentObservation.node.messageId) {
|
||||
if (messageId === currentObservation.node.messageId) {
|
||||
recordedEntry = cachedNode;
|
||||
}
|
||||
trimMessages(messages, maxMessages);
|
||||
@@ -697,11 +697,12 @@ function resolveSessionBoundaryNode(params: {
|
||||
if (!params.messageId) {
|
||||
return undefined;
|
||||
}
|
||||
const { messageId } = params;
|
||||
const candidates = params.cache
|
||||
.recentBefore({
|
||||
accountId: params.accountId,
|
||||
chatId: params.chatId,
|
||||
messageId: params.messageId,
|
||||
messageId,
|
||||
...(params.threadId !== undefined ? { threadId: params.threadId } : {}),
|
||||
limit: Number.MAX_SAFE_INTEGER,
|
||||
})
|
||||
@@ -709,7 +710,7 @@ function resolveSessionBoundaryNode(params: {
|
||||
const current = params.cache.get({
|
||||
accountId: params.accountId,
|
||||
chatId: params.chatId,
|
||||
messageId: params.messageId,
|
||||
messageId,
|
||||
});
|
||||
if (current && isSessionBoundaryCommandNode(current)) {
|
||||
candidates.push(current);
|
||||
|
||||
@@ -943,6 +943,7 @@ describe("test-projects args", () => {
|
||||
"extensions/discord/src/channel-actions.contract.test.ts",
|
||||
"extensions/discord/src/channel.message-adapter.test.ts",
|
||||
"extensions/discord/src/channel.test.ts",
|
||||
"extensions/discord/src/durable-delivery.test.ts",
|
||||
"extensions/discord/src/monitor/message-handler.bot-self-filter.test.ts",
|
||||
"extensions/discord/src/monitor/message-handler.queue.test.ts",
|
||||
"extensions/discord/src/monitor/provider.skill-dedupe.test.ts",
|
||||
|
||||
Reference in New Issue
Block a user