test(hooks): repair stale retry harnesses
This commit is contained in:
@@ -7,6 +7,7 @@ import type { PluginInput } from "@opencode-ai/plugin"
|
|||||||
import { createAtlasHook } from "./atlas-hook"
|
import { createAtlasHook } from "./atlas-hook"
|
||||||
import { clearBoulderState, writeBoulderState } from "../../features/boulder-state"
|
import { clearBoulderState, writeBoulderState } from "../../features/boulder-state"
|
||||||
import { _resetForTesting, clearSessionAgent, registerAgentName, setSessionAgent } from "../../features/claude-code-session-state"
|
import { _resetForTesting, clearSessionAgent, registerAgentName, setSessionAgent } from "../../features/claude-code-session-state"
|
||||||
|
import { DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS } from "../../shared/prompt-async-gate"
|
||||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||||
|
|
||||||
// Force process isolation in CI runner (globalThis.setTimeout override conflicts with other atlas tests)
|
// Force process isolation in CI runner (globalThis.setTimeout override conflicts with other atlas tests)
|
||||||
@@ -24,6 +25,8 @@ describe("atlas background task retry", () => {
|
|||||||
let nextFakeTimerId = 1000
|
let nextFakeTimerId = 1000
|
||||||
const originalSetTimeout = globalThis.setTimeout
|
const originalSetTimeout = globalThis.setTimeout
|
||||||
const originalClearTimeout = globalThis.clearTimeout
|
const originalClearTimeout = globalThis.clearTimeout
|
||||||
|
const originalDateNow = Date.now
|
||||||
|
let fakeNow = 0
|
||||||
|
|
||||||
async function flushMicrotasks(): Promise<void> {
|
async function flushMicrotasks(): Promise<void> {
|
||||||
await Promise.resolve()
|
await Promise.resolve()
|
||||||
@@ -52,6 +55,7 @@ describe("atlas background task retry", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
capturedTimers.delete(id)
|
capturedTimers.delete(id)
|
||||||
|
fakeNow += 6000
|
||||||
await entry.callback()
|
await entry.callback()
|
||||||
}
|
}
|
||||||
await flushMicrotasks()
|
await flushMicrotasks()
|
||||||
@@ -67,6 +71,8 @@ describe("atlas background task retry", () => {
|
|||||||
|
|
||||||
capturedTimers.clear()
|
capturedTimers.clear()
|
||||||
nextFakeTimerId = 1000
|
nextFakeTimerId = 1000
|
||||||
|
fakeNow = 10_000
|
||||||
|
Date.now = () => fakeNow
|
||||||
|
|
||||||
globalThis.setTimeout = ((callback: Parameters<typeof setTimeout>[0], delay?: number, ...args: unknown[]) => {
|
globalThis.setTimeout = ((callback: Parameters<typeof setTimeout>[0], delay?: number, ...args: unknown[]) => {
|
||||||
const normalizedDelay = typeof delay === "number" ? delay : 0
|
const normalizedDelay = typeof delay === "number" ? delay : 0
|
||||||
@@ -74,7 +80,7 @@ describe("atlas background task retry", () => {
|
|||||||
return originalSetTimeout(callback, delay, ...args)
|
return originalSetTimeout(callback, delay, ...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedDelay >= 5000) {
|
if (normalizedDelay >= 5000 && normalizedDelay !== DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS) {
|
||||||
const id = nextFakeTimerId++
|
const id = nextFakeTimerId++
|
||||||
capturedTimers.set(id, {
|
capturedTimers.set(id, {
|
||||||
callback: () => (callback as LongTimerCallback)(...args),
|
callback: () => (callback as LongTimerCallback)(...args),
|
||||||
@@ -87,8 +93,9 @@ describe("atlas background task retry", () => {
|
|||||||
}) as typeof setTimeout
|
}) as typeof setTimeout
|
||||||
|
|
||||||
globalThis.clearTimeout = ((id?: number | ReturnType<typeof setTimeout>) => {
|
globalThis.clearTimeout = ((id?: number | ReturnType<typeof setTimeout>) => {
|
||||||
if (typeof id === "number" && capturedTimers.has(id)) {
|
const timerEntry = typeof id === "number" ? capturedTimers.get(id) : undefined
|
||||||
capturedTimers.get(id)!.cleared = true
|
if (timerEntry) {
|
||||||
|
timerEntry.cleared = true
|
||||||
capturedTimers.delete(id)
|
capturedTimers.delete(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -100,6 +107,7 @@ describe("atlas background task retry", () => {
|
|||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
globalThis.setTimeout = originalSetTimeout
|
globalThis.setTimeout = originalSetTimeout
|
||||||
globalThis.clearTimeout = originalClearTimeout
|
globalThis.clearTimeout = originalClearTimeout
|
||||||
|
Date.now = originalDateNow
|
||||||
_resetForTesting()
|
_resetForTesting()
|
||||||
clearBoulderState(testDir)
|
clearBoulderState(testDir)
|
||||||
if (existsSync(testDir)) {
|
if (existsSync(testDir)) {
|
||||||
@@ -423,7 +431,7 @@ describe("atlas background task retry", () => {
|
|||||||
agent: "atlas",
|
agent: "atlas",
|
||||||
})
|
})
|
||||||
|
|
||||||
const deferredPrompt = createDeferred<{}>()
|
const deferredPrompt = createDeferred<unknown>()
|
||||||
const promptAsyncMock = mock(() => deferredPrompt.promise)
|
const promptAsyncMock = mock(() => deferredPrompt.promise)
|
||||||
const hook = createAtlasHook(unsafeTestValue<PluginInput>({
|
const hook = createAtlasHook(unsafeTestValue<PluginInput>({
|
||||||
directory: testDir,
|
directory: testDir,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from "../../features/boulder-state"
|
} from "../../features/boulder-state"
|
||||||
import type { BoulderState } from "../../features/boulder-state"
|
import type { BoulderState } from "../../features/boulder-state"
|
||||||
import { _resetForTesting, registerAgentName, subagentSessions, updateSessionAgent } from "../../features/claude-code-session-state"
|
import { _resetForTesting, registerAgentName, subagentSessions, updateSessionAgent } from "../../features/claude-code-session-state"
|
||||||
|
import { DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS } from "../../shared/prompt-async-gate"
|
||||||
import type { AtlasHookOptions, PendingTaskRef } from "./types"
|
import type { AtlasHookOptions, PendingTaskRef } from "./types"
|
||||||
import { createAtlasHook } from "./index"
|
import { createAtlasHook } from "./index"
|
||||||
import { createToolExecuteAfterHandler } from "./tool-execute-after"
|
import { createToolExecuteAfterHandler } from "./tool-execute-after"
|
||||||
@@ -1702,7 +1703,7 @@ session_id: ses_untrusted_999
|
|||||||
|
|
||||||
// then - stale idle is consumed, not converted into another scheduled continuation
|
// then - stale idle is consumed, not converted into another scheduled continuation
|
||||||
expect(mockInput._promptMock).toHaveBeenCalledTimes(1)
|
expect(mockInput._promptMock).toHaveBeenCalledTimes(1)
|
||||||
expect(scheduledDelays.filter((delay) => delay >= 5_000)).toHaveLength(0)
|
expect(scheduledDelays.filter((delay) => delay >= 5_000 && delay !== DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS)).toHaveLength(0)
|
||||||
} finally {
|
} finally {
|
||||||
globalThis.setTimeout = originalSetTimeout
|
globalThis.setTimeout = originalSetTimeout
|
||||||
}
|
}
|
||||||
@@ -2498,7 +2499,7 @@ session_id: ses_untrusted_999
|
|||||||
|
|
||||||
globalThis.setTimeout = ((callback: Parameters<typeof setTimeout>[0], delay?: number, ...args: unknown[]) => {
|
globalThis.setTimeout = ((callback: Parameters<typeof setTimeout>[0], delay?: number, ...args: unknown[]) => {
|
||||||
const normalized = typeof delay === "number" ? delay : 0
|
const normalized = typeof delay === "number" ? delay : 0
|
||||||
if (normalized >= 5000) {
|
if (normalized >= 5000 && normalized !== DEFAULT_PROMPT_DISPATCH_TIMEOUT_MS) {
|
||||||
const timerID = originalSetTimeout(() => undefined, 0)
|
const timerID = originalSetTimeout(() => undefined, 0)
|
||||||
const capturedCallback = typeof callback === "function"
|
const capturedCallback = typeof callback === "function"
|
||||||
? () => callback(...args)
|
? () => callback(...args)
|
||||||
@@ -2512,8 +2513,9 @@ session_id: ses_untrusted_999
|
|||||||
}) as typeof setTimeout
|
}) as typeof setTimeout
|
||||||
|
|
||||||
globalThis.clearTimeout = ((id?: ReturnType<typeof setTimeout>) => {
|
globalThis.clearTimeout = ((id?: ReturnType<typeof setTimeout>) => {
|
||||||
if (id && capturedTimers.has(id)) {
|
const timerEntry = id ? capturedTimers.get(id) : undefined
|
||||||
capturedTimers.get(id)!.cleared = true
|
if (timerEntry) {
|
||||||
|
timerEntry.cleared = true
|
||||||
capturedTimers.delete(id)
|
capturedTimers.delete(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { readFileSync } from "node:fs"
|
|||||||
describe("experimental.session.compacting", () => {
|
describe("experimental.session.compacting", () => {
|
||||||
test("does not hardcode a model and uses output.context", () => {
|
test("does not hardcode a model and uses output.context", () => {
|
||||||
//#given
|
//#given
|
||||||
const indexUrl = new URL("./index.ts", import.meta.url)
|
const moduleUrl = new URL("./testing/create-plugin-module.ts", import.meta.url)
|
||||||
const compactionUrl = new URL("./plugin/session-compacting.ts", import.meta.url)
|
const compactionUrl = new URL("./plugin/session-compacting.ts", import.meta.url)
|
||||||
const content = readFileSync(indexUrl, "utf-8")
|
const content = readFileSync(moduleUrl, "utf-8")
|
||||||
const compactionContent = readFileSync(compactionUrl, "utf-8")
|
const compactionContent = readFileSync(compactionUrl, "utf-8")
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
@@ -22,9 +22,9 @@ describe("experimental.session.compacting", () => {
|
|||||||
|
|
||||||
test("registers autocontinue restores before OpenCode synthetic continue", () => {
|
test("registers autocontinue restores before OpenCode synthetic continue", () => {
|
||||||
//#given
|
//#given
|
||||||
const indexUrl = new URL("./index.ts", import.meta.url)
|
const moduleUrl = new URL("./testing/create-plugin-module.ts", import.meta.url)
|
||||||
const compactionUrl = new URL("./plugin/session-compacting.ts", import.meta.url)
|
const compactionUrl = new URL("./plugin/session-compacting.ts", import.meta.url)
|
||||||
const content = readFileSync(indexUrl, "utf-8")
|
const content = readFileSync(moduleUrl, "utf-8")
|
||||||
const compactionContent = readFileSync(compactionUrl, "utf-8")
|
const compactionContent = readFileSync(compactionUrl, "utf-8")
|
||||||
|
|
||||||
//#when
|
//#when
|
||||||
|
|||||||
Reference in New Issue
Block a user