test(anthropic-recovery): cover recovery hook timer disposal
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -75,6 +75,7 @@ export function createMockContext(): PluginInput {
|
|||||||
|
|
||||||
export function setupDelayedTimeoutMocks(): {
|
export function setupDelayedTimeoutMocks(): {
|
||||||
createUntrackedTimeout: () => ReturnType<typeof setTimeout>
|
createUntrackedTimeout: () => ReturnType<typeof setTimeout>
|
||||||
|
runScheduledTimeout: (index: number) => void
|
||||||
restore: () => void
|
restore: () => void
|
||||||
getClearTimeoutCalls: () => Array<ReturnType<typeof setTimeout>>
|
getClearTimeoutCalls: () => Array<ReturnType<typeof setTimeout>>
|
||||||
getScheduledTimeouts: () => Array<ReturnType<typeof setTimeout>>
|
getScheduledTimeouts: () => Array<ReturnType<typeof setTimeout>>
|
||||||
@@ -83,6 +84,7 @@ export function setupDelayedTimeoutMocks(): {
|
|||||||
const originalClearTimeout = globalThis.clearTimeout
|
const originalClearTimeout = globalThis.clearTimeout
|
||||||
const clearTimeoutCalls: Array<ReturnType<typeof setTimeout>> = []
|
const clearTimeoutCalls: Array<ReturnType<typeof setTimeout>> = []
|
||||||
const scheduledTimeouts: Array<ReturnType<typeof setTimeout>> = []
|
const scheduledTimeouts: Array<ReturnType<typeof setTimeout>> = []
|
||||||
|
const scheduledCallbacks: Array<() => void> = []
|
||||||
|
|
||||||
function createTimeoutHandle(): ReturnType<typeof setTimeout> {
|
function createTimeoutHandle(): ReturnType<typeof setTimeout> {
|
||||||
const timeoutID = originalSetTimeout(() => {}, 60_000)
|
const timeoutID = originalSetTimeout(() => {}, 60_000)
|
||||||
@@ -90,9 +92,10 @@ export function setupDelayedTimeoutMocks(): {
|
|||||||
return timeoutID
|
return timeoutID
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.setTimeout = ((_: () => void, _delay?: number) => {
|
globalThis.setTimeout = ((callback: () => void, _delay?: number) => {
|
||||||
const timeoutID = createTimeoutHandle()
|
const timeoutID = createTimeoutHandle()
|
||||||
scheduledTimeouts.push(timeoutID)
|
scheduledTimeouts.push(timeoutID)
|
||||||
|
scheduledCallbacks.push(callback)
|
||||||
return timeoutID
|
return timeoutID
|
||||||
}) as typeof setTimeout
|
}) as typeof setTimeout
|
||||||
|
|
||||||
@@ -103,6 +106,9 @@ export function setupDelayedTimeoutMocks(): {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
createUntrackedTimeout: createTimeoutHandle,
|
createUntrackedTimeout: createTimeoutHandle,
|
||||||
|
runScheduledTimeout: (index: number) => {
|
||||||
|
scheduledCallbacks[index]?.()
|
||||||
|
},
|
||||||
restore: () => {
|
restore: () => {
|
||||||
globalThis.setTimeout = originalSetTimeout
|
globalThis.setTimeout = originalSetTimeout
|
||||||
globalThis.clearTimeout = originalClearTimeout
|
globalThis.clearTimeout = originalClearTimeout
|
||||||
|
|||||||
@@ -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<typeof executeCompactMock>) => {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user