@@ -96,6 +96,11 @@ import {
9696let tempDir : string ;
9797let codexAppServerClientFactoryForTest : CodexAppServerClientFactory | undefined ;
9898const fastWait = { interval : 1 , timeout : 5_000 } as const ;
99+ const appServerHarnessWait = { interval : 1 , timeout : 120_000 } as const ;
100+ const activeAppServerAttemptsForTest = new Set < {
101+ abortController ?: AbortController ;
102+ promise : Promise < unknown > ;
103+ } > ( ) ;
99104
100105type RunCodexAppServerAttemptOptions = NonNullable <
101106 Parameters < typeof runCodexAppServerAttemptImpl > [ 1 ]
@@ -150,10 +155,38 @@ function runCodexAppServerAttempt(
150155 options : RunCodexAppServerAttemptOptions = { } ,
151156) {
152157 const clientFactory = options . clientFactory ?? codexAppServerClientFactoryForTest ;
153- return runCodexAppServerAttemptImpl (
154- params ,
158+ const abortController = params . abortSignal ? undefined : new AbortController ( ) ;
159+ const trackedParams = abortController
160+ ? ( { ...params , abortSignal : abortController . signal } as EmbeddedRunAttemptParams )
161+ : params ;
162+ const entry = {
163+ abortController,
164+ promise : undefined as unknown as Promise < unknown > ,
165+ } ;
166+ const promise = runCodexAppServerAttemptImpl (
167+ trackedParams ,
155168 clientFactory ? { ...options , clientFactory } : options ,
156- ) ;
169+ ) . finally ( ( ) => {
170+ activeAppServerAttemptsForTest . delete ( entry ) ;
171+ } ) ;
172+ entry . promise = promise ;
173+ activeAppServerAttemptsForTest . add ( entry ) ;
174+ promise . catch ( ( ) => undefined ) ;
175+ return promise ;
176+ }
177+
178+ async function drainActiveAppServerAttemptsForTest ( ) : Promise < void > {
179+ const attempts = [ ...activeAppServerAttemptsForTest ] ;
180+ if ( attempts . length === 0 ) {
181+ return ;
182+ }
183+ for ( const attempt of attempts ) {
184+ attempt . abortController ?. abort ( "test_cleanup" ) ;
185+ }
186+ await Promise . race ( [
187+ Promise . allSettled ( attempts . map ( ( attempt ) => attempt . promise ) ) ,
188+ new Promise < void > ( ( resolve ) => setTimeout ( resolve , 5_000 ) ) ,
189+ ] ) ;
157190}
158191
159192function createParams ( sessionFile : string , workspaceDir : string ) : EmbeddedRunAttemptParams {
@@ -367,15 +400,15 @@ function createAppServerHarness(
367400 const waitForServerRequestHandler = async ( ) => {
368401 await vi . waitFor ( ( ) => expect ( handleServerRequest ) . toBeTypeOf ( "function" ) , {
369402 interval : 1 ,
370- timeout : 30_000 ,
403+ timeout : appServerHarnessWait . timeout ,
371404 } ) ;
372405 return handleServerRequest ! ;
373406 } ;
374407
375408 return {
376409 request,
377410 requests,
378- async waitForMethod ( method : string , timeoutMs = 30_000 ) {
411+ async waitForMethod ( method : string , timeoutMs = appServerHarnessWait . timeout ) {
379412 await vi . waitFor (
380413 ( ) => {
381414 if ( ! requests . some ( ( entry ) => entry . method === method ) ) {
@@ -837,6 +870,8 @@ describe("runCodexAppServerAttempt", () => {
837870 } ) ;
838871
839872 afterEach ( async ( ) => {
873+ await drainActiveAppServerAttemptsForTest ( ) ;
874+ await closeCodexSandboxExecServersForTests ( ) ;
840875 resetCodexAppServerClientFactoryForTest ( ) ;
841876 testing . resetOpenClawCodingToolsFactoryForTests ( ) ;
842877 resetCodexRateLimitCacheForTests ( ) ;
0 commit comments