diff --git a/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test-support.ts b/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test-support.ts index e394a0040..bb04412bd 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test-support.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test-support.ts @@ -75,6 +75,7 @@ export function createMockContext(): PluginInput { export function setupDelayedTimeoutMocks(): { createUntrackedTimeout: () => ReturnType + runScheduledTimeout: (index: number) => void restore: () => void getClearTimeoutCalls: () => Array> getScheduledTimeouts: () => Array> @@ -83,6 +84,7 @@ export function setupDelayedTimeoutMocks(): { const originalClearTimeout = globalThis.clearTimeout const clearTimeoutCalls: Array> = [] const scheduledTimeouts: Array> = [] + const scheduledCallbacks: Array<() => void> = [] function createTimeoutHandle(): ReturnType { const timeoutID = originalSetTimeout(() => {}, 60_000) @@ -90,9 +92,10 @@ export function setupDelayedTimeoutMocks(): { return timeoutID } - globalThis.setTimeout = ((_: () => void, _delay?: number) => { + globalThis.setTimeout = ((callback: () => void, _delay?: number) => { const timeoutID = createTimeoutHandle() scheduledTimeouts.push(timeoutID) + scheduledCallbacks.push(callback) return timeoutID }) as typeof setTimeout @@ -103,6 +106,9 @@ export function setupDelayedTimeoutMocks(): { return { createUntrackedTimeout: createTimeoutHandle, + runScheduledTimeout: (index: number) => { + scheduledCallbacks[index]?.() + }, restore: () => { globalThis.setTimeout = originalSetTimeout globalThis.clearTimeout = originalClearTimeout diff --git a/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts b/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts index 4291bb754..6300ab55e 100644 --- a/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts +++ b/src/hooks/anthropic-context-window-limit-recovery/recovery-hook.test.ts @@ -94,4 +94,45 @@ describe("createAnthropicContextWindowLimitRecoveryHook", () => { } }) + test("#given active pending and retry timers #when dispose is called #then it clears both timer maps", async () => { + //#given + const { createUntrackedTimeout, getClearTimeoutCalls, getScheduledTimeouts, restore, runScheduledTimeout } = + setupDelayedTimeoutMocks() + executeCompactMock.mockImplementationOnce(async (...args: Parameters) => { + const sessionID = args[0] + const autoCompactState = args[2] + + autoCompactState.retryTimerBySession.set(sessionID, createUntrackedTimeout()) + }) + const hook = createRecoveryHook() + + try { + await hook.event({ + event: { + type: "session.error", + properties: { sessionID: "session-retry", error: "prompt is too long" }, + }, + }) + + await hook.event({ + event: { + type: "session.error", + properties: { sessionID: "session-pending", error: "prompt is too long" }, + }, + }) + + runScheduledTimeout(0) + + const [retryTimer, pendingTimer] = getScheduledTimeouts() + + //#when + hook.dispose() + + //#then + expect(getClearTimeoutCalls()).toEqual(expect.arrayContaining([retryTimer, pendingTimer])) + } finally { + restore() + } + }) + })