mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 23:04:32 +00:00
refactor(test): dedupe followup queue fixtures
This commit is contained in:
@@ -25,6 +25,13 @@ afterAll(() => {
|
|||||||
defaultRuntime.error = previousRuntimeError;
|
defaultRuntime.error = previousRuntimeError;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const COLLECT_SETTINGS: QueueSettings = {
|
||||||
|
mode: "collect",
|
||||||
|
debounceMs: 0,
|
||||||
|
cap: 50,
|
||||||
|
dropPolicy: "summarize",
|
||||||
|
};
|
||||||
|
|
||||||
function createRun(params: {
|
function createRun(params: {
|
||||||
prompt: string;
|
prompt: string;
|
||||||
messageId?: string;
|
messageId?: string;
|
||||||
@@ -56,24 +63,37 @@ function createRun(params: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createHarness(params: {
|
||||||
|
expectedCalls: number;
|
||||||
|
runFollowup?: (
|
||||||
|
run: FollowupRun,
|
||||||
|
ctx: {
|
||||||
|
calls: FollowupRun[];
|
||||||
|
done: ReturnType<typeof createDeferred<void>>;
|
||||||
|
expectedCalls: number;
|
||||||
|
},
|
||||||
|
) => Promise<void>;
|
||||||
|
}) {
|
||||||
|
const calls: FollowupRun[] = [];
|
||||||
|
const done = createDeferred<void>();
|
||||||
|
const expectedCalls = params.expectedCalls;
|
||||||
|
const runFollowup = async (run: FollowupRun) => {
|
||||||
|
if (params.runFollowup) {
|
||||||
|
await params.runFollowup(run, { calls, done, expectedCalls });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
calls.push(run);
|
||||||
|
if (calls.length >= expectedCalls) {
|
||||||
|
done.resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return { calls, done, runFollowup, expectedCalls };
|
||||||
|
}
|
||||||
|
|
||||||
describe("followup queue deduplication", () => {
|
describe("followup queue deduplication", () => {
|
||||||
it("deduplicates messages with same Discord message_id", async () => {
|
it("deduplicates messages with same Discord message_id", async () => {
|
||||||
const key = `test-dedup-message-id-${Date.now()}`;
|
const key = `test-dedup-message-id-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
const { calls, done, runFollowup } = createHarness({ expectedCalls: 1 });
|
||||||
const done = createDeferred<void>();
|
|
||||||
const expectedCalls = 1;
|
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
|
||||||
calls.push(run);
|
|
||||||
if (calls.length >= expectedCalls) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const settings: QueueSettings = {
|
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
// First enqueue should succeed
|
// First enqueue should succeed
|
||||||
const first = enqueueFollowupRun(
|
const first = enqueueFollowupRun(
|
||||||
@@ -84,7 +104,7 @@ describe("followup queue deduplication", () => {
|
|||||||
originatingChannel: "discord",
|
originatingChannel: "discord",
|
||||||
originatingTo: "channel:123",
|
originatingTo: "channel:123",
|
||||||
}),
|
}),
|
||||||
settings,
|
COLLECT_SETTINGS,
|
||||||
);
|
);
|
||||||
expect(first).toBe(true);
|
expect(first).toBe(true);
|
||||||
|
|
||||||
@@ -97,7 +117,7 @@ describe("followup queue deduplication", () => {
|
|||||||
originatingChannel: "discord",
|
originatingChannel: "discord",
|
||||||
originatingTo: "channel:123",
|
originatingTo: "channel:123",
|
||||||
}),
|
}),
|
||||||
settings,
|
COLLECT_SETTINGS,
|
||||||
);
|
);
|
||||||
expect(second).toBe(false);
|
expect(second).toBe(false);
|
||||||
|
|
||||||
@@ -110,7 +130,7 @@ describe("followup queue deduplication", () => {
|
|||||||
originatingChannel: "discord",
|
originatingChannel: "discord",
|
||||||
originatingTo: "channel:123",
|
originatingTo: "channel:123",
|
||||||
}),
|
}),
|
||||||
settings,
|
COLLECT_SETTINGS,
|
||||||
);
|
);
|
||||||
expect(third).toBe(true);
|
expect(third).toBe(true);
|
||||||
|
|
||||||
@@ -122,12 +142,7 @@ describe("followup queue deduplication", () => {
|
|||||||
|
|
||||||
it("deduplicates exact prompt when routing matches and no message id", async () => {
|
it("deduplicates exact prompt when routing matches and no message id", async () => {
|
||||||
const key = `test-dedup-whatsapp-${Date.now()}`;
|
const key = `test-dedup-whatsapp-${Date.now()}`;
|
||||||
const settings: QueueSettings = {
|
const settings = COLLECT_SETTINGS;
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
// First enqueue should succeed
|
// First enqueue should succeed
|
||||||
const first = enqueueFollowupRun(
|
const first = enqueueFollowupRun(
|
||||||
@@ -168,12 +183,7 @@ describe("followup queue deduplication", () => {
|
|||||||
|
|
||||||
it("does not deduplicate across different providers without message id", async () => {
|
it("does not deduplicate across different providers without message id", async () => {
|
||||||
const key = `test-dedup-cross-provider-${Date.now()}`;
|
const key = `test-dedup-cross-provider-${Date.now()}`;
|
||||||
const settings: QueueSettings = {
|
const settings = COLLECT_SETTINGS;
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
const first = enqueueFollowupRun(
|
const first = enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -200,12 +210,7 @@ describe("followup queue deduplication", () => {
|
|||||||
|
|
||||||
it("can opt-in to prompt-based dedupe when message id is absent", async () => {
|
it("can opt-in to prompt-based dedupe when message id is absent", async () => {
|
||||||
const key = `test-dedup-prompt-mode-${Date.now()}`;
|
const key = `test-dedup-prompt-mode-${Date.now()}`;
|
||||||
const settings: QueueSettings = {
|
const settings = COLLECT_SETTINGS;
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
const first = enqueueFollowupRun(
|
const first = enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -236,21 +241,8 @@ describe("followup queue deduplication", () => {
|
|||||||
describe("followup queue collect routing", () => {
|
describe("followup queue collect routing", () => {
|
||||||
it("does not collect when destinations differ", async () => {
|
it("does not collect when destinations differ", async () => {
|
||||||
const key = `test-collect-diff-to-${Date.now()}`;
|
const key = `test-collect-diff-to-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
const { calls, done, runFollowup } = createHarness({ expectedCalls: 2 });
|
||||||
const done = createDeferred<void>();
|
const settings = COLLECT_SETTINGS;
|
||||||
const expectedCalls = 2;
|
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
|
||||||
calls.push(run);
|
|
||||||
if (calls.length >= expectedCalls) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const settings: QueueSettings = {
|
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
enqueueFollowupRun(
|
enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -279,21 +271,8 @@ describe("followup queue collect routing", () => {
|
|||||||
|
|
||||||
it("collects when channel+destination match", async () => {
|
it("collects when channel+destination match", async () => {
|
||||||
const key = `test-collect-same-to-${Date.now()}`;
|
const key = `test-collect-same-to-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
const { calls, done, runFollowup } = createHarness({ expectedCalls: 1 });
|
||||||
const done = createDeferred<void>();
|
const settings = COLLECT_SETTINGS;
|
||||||
const expectedCalls = 1;
|
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
|
||||||
calls.push(run);
|
|
||||||
if (calls.length >= expectedCalls) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const settings: QueueSettings = {
|
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
enqueueFollowupRun(
|
enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -323,21 +302,8 @@ describe("followup queue collect routing", () => {
|
|||||||
|
|
||||||
it("collects Slack messages in same thread and preserves string thread id", async () => {
|
it("collects Slack messages in same thread and preserves string thread id", async () => {
|
||||||
const key = `test-collect-slack-thread-same-${Date.now()}`;
|
const key = `test-collect-slack-thread-same-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
const { calls, done, runFollowup } = createHarness({ expectedCalls: 1 });
|
||||||
const done = createDeferred<void>();
|
const settings = COLLECT_SETTINGS;
|
||||||
const expectedCalls = 1;
|
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
|
||||||
calls.push(run);
|
|
||||||
if (calls.length >= expectedCalls) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const settings: QueueSettings = {
|
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
enqueueFollowupRun(
|
enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -368,21 +334,8 @@ describe("followup queue collect routing", () => {
|
|||||||
|
|
||||||
it("does not collect Slack messages when thread ids differ", async () => {
|
it("does not collect Slack messages when thread ids differ", async () => {
|
||||||
const key = `test-collect-slack-thread-diff-${Date.now()}`;
|
const key = `test-collect-slack-thread-diff-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
const { calls, done, runFollowup } = createHarness({ expectedCalls: 2 });
|
||||||
const done = createDeferred<void>();
|
const settings = COLLECT_SETTINGS;
|
||||||
const expectedCalls = 2;
|
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
|
||||||
calls.push(run);
|
|
||||||
if (calls.length >= expectedCalls) {
|
|
||||||
done.resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const settings: QueueSettings = {
|
|
||||||
mode: "collect",
|
|
||||||
debounceMs: 0,
|
|
||||||
cap: 50,
|
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
enqueueFollowupRun(
|
enqueueFollowupRun(
|
||||||
key,
|
key,
|
||||||
@@ -415,26 +368,21 @@ describe("followup queue collect routing", () => {
|
|||||||
|
|
||||||
it("retries collect-mode batches without losing queued items", async () => {
|
it("retries collect-mode batches without losing queued items", async () => {
|
||||||
const key = `test-collect-retry-${Date.now()}`;
|
const key = `test-collect-retry-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
|
||||||
const done = createDeferred<void>();
|
|
||||||
const expectedCalls = 1;
|
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
const { calls, done, runFollowup } = createHarness({
|
||||||
attempt += 1;
|
expectedCalls: 1,
|
||||||
if (attempt === 1) {
|
runFollowup: async (run, ctx) => {
|
||||||
throw new Error("transient failure");
|
attempt += 1;
|
||||||
}
|
if (attempt === 1) {
|
||||||
calls.push(run);
|
throw new Error("transient failure");
|
||||||
if (calls.length >= expectedCalls) {
|
}
|
||||||
done.resolve();
|
ctx.calls.push(run);
|
||||||
}
|
if (ctx.calls.length >= ctx.expectedCalls) {
|
||||||
};
|
ctx.done.resolve();
|
||||||
const settings: QueueSettings = {
|
}
|
||||||
mode: "collect",
|
},
|
||||||
debounceMs: 0,
|
});
|
||||||
cap: 50,
|
const settings = COLLECT_SETTINGS;
|
||||||
dropPolicy: "summarize",
|
|
||||||
};
|
|
||||||
|
|
||||||
enqueueFollowupRun(key, createRun({ prompt: "one" }), settings);
|
enqueueFollowupRun(key, createRun({ prompt: "one" }), settings);
|
||||||
enqueueFollowupRun(key, createRun({ prompt: "two" }), settings);
|
enqueueFollowupRun(key, createRun({ prompt: "two" }), settings);
|
||||||
@@ -447,20 +395,20 @@ describe("followup queue collect routing", () => {
|
|||||||
|
|
||||||
it("retries overflow summary delivery without losing dropped previews", async () => {
|
it("retries overflow summary delivery without losing dropped previews", async () => {
|
||||||
const key = `test-overflow-summary-retry-${Date.now()}`;
|
const key = `test-overflow-summary-retry-${Date.now()}`;
|
||||||
const calls: FollowupRun[] = [];
|
|
||||||
const done = createDeferred<void>();
|
|
||||||
const expectedCalls = 1;
|
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
const runFollowup = async (run: FollowupRun) => {
|
const { calls, done, runFollowup } = createHarness({
|
||||||
attempt += 1;
|
expectedCalls: 1,
|
||||||
if (attempt === 1) {
|
runFollowup: async (run, ctx) => {
|
||||||
throw new Error("transient failure");
|
attempt += 1;
|
||||||
}
|
if (attempt === 1) {
|
||||||
calls.push(run);
|
throw new Error("transient failure");
|
||||||
if (calls.length >= expectedCalls) {
|
}
|
||||||
done.resolve();
|
ctx.calls.push(run);
|
||||||
}
|
if (ctx.calls.length >= ctx.expectedCalls) {
|
||||||
};
|
ctx.done.resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
const settings: QueueSettings = {
|
const settings: QueueSettings = {
|
||||||
mode: "followup",
|
mode: "followup",
|
||||||
debounceMs: 0,
|
debounceMs: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user