From 302ba0ca0b27eb6f74560a8e305470339690f7e5 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 14 May 2026 19:24:09 -0400 Subject: [PATCH] test(session): de-flake shell-cancel tests by waiting for busy state (#27622) --- packages/opencode/test/session/prompt.test.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index 59fd2b48a4..b50d6e994f 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -336,6 +336,21 @@ const pollWithTimeout = ( }), ) +// Wait for a session's runner to enter a busy state. SessionStatus is flipped to +// "busy" inside Runner.startShell's modifyEffect at the same moment the runner +// is registered, so this is a deterministic readiness signal — cancel can't +// no-op once we observe it. +const waitForBusy = (sessionID: SessionID, duration: Duration.Input = "2 seconds") => + pollWithTimeout( + Effect.gen(function* () { + const status = yield* SessionStatus.Service + const s = yield* status.get(sessionID) + return s.type === "busy" ? (true as const) : undefined + }), + `session ${sessionID} never became busy`, + duration, + ) + const hasBash = Effect.sync(() => Bun.which("bash") !== null) const deferredAsPromise = (deferred: Deferred.Deferred): PromiseLike => ({ @@ -1493,7 +1508,7 @@ it.instance( const sh = yield* prompt .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) .pipe(Effect.forkChild) - yield* Effect.sleep(50) + yield* waitForBusy(chat.id) const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) yield* Effect.sleep(50) @@ -1530,7 +1545,7 @@ it.instance( const sh = yield* prompt .shell({ sessionID: chat.id, agent: "build", command: "sleep 0.2" }) .pipe(Effect.forkChild) - yield* Effect.sleep(50) + yield* waitForBusy(chat.id) const a = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) const b = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) @@ -1597,7 +1612,7 @@ unix( const sh = yield* prompt .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) .pipe(Effect.forkChild) - yield* Effect.sleep(50) + yield* waitForBusy(chat.id) yield* prompt.cancel(chat.id) @@ -1721,7 +1736,7 @@ unix( const { prompt, chat } = yield* boot() const sh = yield* prompt.shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }).pipe(Effect.forkChild) - yield* Effect.sleep(50) + yield* waitForBusy(chat.id) const loop = yield* prompt.loop({ sessionID: chat.id }).pipe(Effect.forkChild) yield* Effect.sleep(50) @@ -1751,7 +1766,7 @@ unix( const a = yield* prompt .shell({ sessionID: chat.id, agent: "build", command: "sleep 30" }) .pipe(Effect.forkChild) - yield* Effect.sleep(50) + yield* waitForBusy(chat.id) const exit = yield* prompt.shell({ sessionID: chat.id, agent: "build", command: "echo hi" }).pipe(Effect.exit) expect(Exit.isFailure(exit)).toBe(true)