Skip to content

Commit b2cc4ac

Browse files
committed
test(session): adapt regression checks to schema migration
Narrow SSEStallError assertions to satisfy Effect Schema unions and harden subagent-hang cleanup/polling to avoid leaked loop fibers under slower startup.
1 parent bbdc6e3 commit b2cc4ac

2 files changed

Lines changed: 18 additions & 9 deletions

File tree

packages/opencode/test/session/message-v2-sse-stall.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ describe("session.message-v2.fromError — SSEStallError", () => {
1414
const result = MessageV2.fromError(error, { providerID })
1515

1616
expect(result.name).toBe("SSEStallError")
17+
expect(MessageV2.SSEStallError.isInstance(result)).toBe(true)
18+
if (!MessageV2.SSEStallError.isInstance(result)) throw new Error("Expected SSEStallError")
1719
expect(result.data.message).toBe("SSE read timed out")
1820
})
1921

@@ -32,6 +34,8 @@ describe("session.message-v2.fromError — SSEStallError", () => {
3234
const result = MessageV2.fromError(error, { providerID })
3335

3436
expect(result.name).toBe("SSEStallError")
37+
expect(MessageV2.SSEStallError.isInstance(result)).toBe(true)
38+
if (!MessageV2.SSEStallError.isInstance(result)) throw new Error("Expected SSEStallError")
3539
expect(result.data.message).toBe("SSE chunk timeout after 120000ms")
3640
})
3741

packages/opencode/test/session/subagent-hang-regression.test.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const status = SessionStatus.layer.pipe(Layer.provideMerge(Bus.layer))
113113
const run = SessionRunState.layer.pipe(Layer.provide(status))
114114
const infra = Layer.mergeAll(NodeFileSystem.layer, CrossSpawnSpawner.defaultLayer)
115115

116-
// Copied verbatim from `prompt-effect.test.ts` — that file exports nothing,
116+
// Copied verbatim from `prompt.test.ts` — that file exports nothing,
117117
// so we can't import the helper. Keeping the composition identical guarantees
118118
// this regression gate exercises the same service wiring the rest of the
119119
// loop tests do (real Session/SessionPrompt/ToolRegistry/Question/Permission,
@@ -253,9 +253,9 @@ it.live(
253253
// transitions to retry, the hang regression is back. `pollUnsafe` is
254254
// the public synchronous-peek API — we use it to short-circuit if
255255
// the fiber dies early so the error cause surfaces, rather than
256-
// timing out blindly at 8s.
256+
// timing out blindly at 12s.
257257
const observed = yield* Effect.gen(function* () {
258-
const end = Date.now() + 8_000
258+
const end = Date.now() + 12_000
259259
while (Date.now() < end) {
260260
const exit = fiber.pollUnsafe()
261261
if (exit) return yield* Effect.fail(new Error(`loop exited before retry observed: ${JSON.stringify(exit)}`))
@@ -264,21 +264,26 @@ it.live(
264264
yield* Effect.sleep("25 millis")
265265
}
266266
const snap = yield* sessionStatus.get(chat.id)
267+
if (snap.type === "retry") return snap
267268
return yield* Effect.fail(
268-
new Error(`expected retry status within 8s; last status: ${JSON.stringify(snap)}`),
269+
new Error(`expected retry status within 12s; last status: ${JSON.stringify(snap)}`),
269270
)
270-
})
271+
}).pipe(
272+
Effect.ensuring(
273+
Effect.gen(function* () {
274+
yield* prompt.cancel(chat.id).pipe(Effect.timeout("1 second"), Effect.ignore)
275+
yield* Fiber.interrupt(fiber).pipe(Effect.timeout("3 seconds"), Effect.ignore)
276+
}),
277+
),
278+
)
271279

272280
expect(observed.type).toBe("retry")
273281
expect(observed.attempt).toBeGreaterThanOrEqual(1)
274282
// SessionRetry.transportMessage populates the retry message from
275283
// SSEStallError.data.message ("SSE read timed out after 1000ms").
276284
expect(observed.message).toMatch(/SSE|timed out/i)
277285

278-
// Stop the loop before the 2s exponential backoff fires a second
279-
// attempt (and another 1s stall) and blows the 15s test budget.
280-
yield* prompt.cancel(chat.id)
281-
yield* Fiber.await(fiber)
286+
// Cleanup runs via Effect.ensuring above so failures don't leak a live loop.
282287
}),
283288
{ git: true, config: (url) => providerCfg(url, 1_000) },
284289
),

0 commit comments

Comments
 (0)