mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
test(whatsapp): simplify inbound-drain harness internals (#131158)
Replace the drain waiter array + release loop with one lazily created shared idle deferred (same semantics: concurrent waiters share it, it resolves on the first all-trackers-zero publish), and fold the tracker update into publishInboundPendingWork. Collapse expectInboxPairingReplyText into expectPairingPromptSent: the mocked pairing upsert always issues PAIRCODE, so the regex code extraction and code-override parameter were dead generality. Net -20 lines of test-support code, no behavior change.
This commit is contained in:
committed by
GitHub
parent
d95a1dbcf6
commit
97f66133c5
@@ -257,25 +257,6 @@ export type InboxMonitorOptions = Parameters<MonitorWebInbox>[0];
|
||||
let monitorWebInbox: MonitorWebInbox;
|
||||
let resetWebInboundDedupe: ResetWebInboundDedupe;
|
||||
|
||||
function expectInboxPairingReplyText(
|
||||
text: string,
|
||||
params: {
|
||||
channel: string;
|
||||
idLine: string;
|
||||
code?: string;
|
||||
},
|
||||
): string {
|
||||
const code = text.match(/Pairing code:\s*```[\r\n]+([A-Z2-9]{6,})/)?.[1];
|
||||
expect(code).toBeDefined();
|
||||
const resolvedCode = params.code ?? code ?? "";
|
||||
expect(text).toContain("OpenClaw: access not configured.");
|
||||
expect(text).toContain(params.idLine);
|
||||
expect(text).toContain("Pairing code:");
|
||||
expect(text).toContain(`\n\`\`\`\n${resolvedCode}\n\`\`\`\n`);
|
||||
expect(text).toContain(`pairing approve ${params.channel} ${resolvedCode}`);
|
||||
return resolvedCode;
|
||||
}
|
||||
|
||||
// Yields two macrotask ticks so already-scheduled inbound continuations run.
|
||||
// This deliberately does NOT wait for pending inbound work to finish — tests
|
||||
// observing intermediate states (held handlers, parked debounce batches) rely
|
||||
@@ -291,23 +272,7 @@ export async function settleInboundWork() {
|
||||
|
||||
type InboundWorkTracker = { pending: number };
|
||||
const inboundWorkTrackers = new Set<InboundWorkTracker>();
|
||||
let inboundDrainWaiters: Array<() => void> = [];
|
||||
|
||||
function releaseInboundDrainWaitersIfIdle() {
|
||||
if (inboundDrainWaiters.length === 0) {
|
||||
return;
|
||||
}
|
||||
for (const tracker of inboundWorkTrackers) {
|
||||
if (tracker.pending > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const waiters = inboundDrainWaiters;
|
||||
inboundDrainWaiters = [];
|
||||
for (const release of waiters) {
|
||||
release();
|
||||
}
|
||||
}
|
||||
let inboundIdle: { promise: Promise<void>; release: () => void } | undefined;
|
||||
|
||||
function hasPendingInboundWork(): boolean {
|
||||
for (const tracker of inboundWorkTrackers) {
|
||||
@@ -318,6 +283,14 @@ function hasPendingInboundWork(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function publishInboundPendingWork(tracker: InboundWorkTracker, pending: number) {
|
||||
tracker.pending = pending;
|
||||
if (inboundIdle && !hasPendingInboundWork()) {
|
||||
inboundIdle.release();
|
||||
inboundIdle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Event-driven drain: resolves when every harness-started listener reports zero
|
||||
// pending inbound work. Unlike a vi.waitFor deadline, this cannot fail spuriously
|
||||
// when a saturated no-isolate worker stalls mid-flow (sync module fetches against
|
||||
@@ -329,9 +302,14 @@ export async function waitForInboundWorkDrained() {
|
||||
throw new Error("waitForInboundWorkDrained requires a listener started via startInboxMonitor");
|
||||
}
|
||||
if (hasPendingInboundWork()) {
|
||||
await new Promise<void>((resolve) => {
|
||||
inboundDrainWaiters.push(resolve);
|
||||
});
|
||||
if (!inboundIdle) {
|
||||
let release!: () => void;
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
release = resolve;
|
||||
});
|
||||
inboundIdle = { promise, release };
|
||||
}
|
||||
await inboundIdle.promise;
|
||||
}
|
||||
// One extra tick lets drained-callback continuations (delivery bookkeeping) run.
|
||||
await new Promise((resolve) => {
|
||||
@@ -377,8 +355,7 @@ export async function startInboxMonitor(
|
||||
const listener = await monitorWebInbox({
|
||||
...merged,
|
||||
onPendingWorkChanged: (pendingWorkCount: number, at?: number) => {
|
||||
tracker.pending = pendingWorkCount;
|
||||
releaseInboundDrainWaitersIfIdle();
|
||||
publishInboundPendingWork(tracker, pendingWorkCount);
|
||||
callerOnPendingWorkChanged?.(pendingWorkCount, at);
|
||||
},
|
||||
});
|
||||
@@ -411,15 +388,18 @@ export function buildNotifyMessageUpsert(params: {
|
||||
};
|
||||
}
|
||||
|
||||
// The mocked pairing upsert always issues PAIRCODE, so the reply text can be
|
||||
// asserted directly instead of re-extracting the code from the message.
|
||||
function expectPairingPromptSent(sock: MockSock, jid: string, senderE164: string) {
|
||||
expect(sock.sendMessage).toHaveBeenCalledTimes(1);
|
||||
const sendCall = sock.sendMessage.mock.calls.at(0);
|
||||
expect(sendCall?.[0]).toBe(jid);
|
||||
expectInboxPairingReplyText((sendCall?.[1] as { text?: string } | undefined)?.text ?? "", {
|
||||
channel: "whatsapp",
|
||||
idLine: `Your WhatsApp phone number: ${senderE164}`,
|
||||
code: "PAIRCODE",
|
||||
});
|
||||
const text = (sendCall?.[1] as { text?: string } | undefined)?.text ?? "";
|
||||
expect(text).toContain("OpenClaw: access not configured.");
|
||||
expect(text).toContain(`Your WhatsApp phone number: ${senderE164}`);
|
||||
expect(text).toContain("Pairing code:");
|
||||
expect(text).toContain("\n```\nPAIRCODE\n```\n");
|
||||
expect(text).toContain("pairing approve whatsapp PAIRCODE");
|
||||
}
|
||||
|
||||
// The pairing reply is sent before the inbound handler completes, so a full
|
||||
@@ -446,7 +426,7 @@ export function installWebMonitorInboxUnitTestHooks(opts?: { authDir?: boolean }
|
||||
vi.useRealTimers();
|
||||
vi.clearAllMocks();
|
||||
inboundWorkTrackers.clear();
|
||||
inboundDrainWaiters = [];
|
||||
inboundIdle = undefined;
|
||||
channelActivityMocks.recordChannelActivity.mockClear();
|
||||
pluginRuntimeMocks.reset();
|
||||
setWhatsAppRuntime({
|
||||
|
||||
Reference in New Issue
Block a user