@@ -73,6 +73,62 @@ void shouldRunFullTurnWithDeltasAndHandshakeAuth() throws Exception {
7373 }
7474 }
7575
76+
77+ @ Test
78+ void shouldSerializeConcurrentTurnsForSameSessionKey () throws Exception {
79+ try (FakeCodexAppServer server = new FakeCodexAppServer ();
80+ CodexAppServerClient client = new CodexAppServerClient (configFor (server ))) {
81+ server .holdTurnCompletions ();
82+
83+ java .util .concurrent .CompletableFuture <AppServerTurnResult > first =
84+ client .runTurnAsync (AppServerTurnRequest .builder ()
85+ .prompt ("first" )
86+ .sessionKey ("chat-serial" )
87+ .build ());
88+ assertTrue (server .awaitTurnStarts (1 , 2_000 ), "first turn must reach server" );
89+
90+ java .util .concurrent .CompletableFuture <AppServerTurnResult > second =
91+ client .runTurnAsync (AppServerTurnRequest .builder ()
92+ .prompt ("second" )
93+ .sessionKey ("chat-serial" )
94+ .build ());
95+
96+ assertFalse (server .awaitTurnStarts (2 , 750 ),
97+ "second same-session turn must not start while first is active" );
98+
99+ server .releaseTurnCompletions ();
100+ first .get (5 , TimeUnit .SECONDS );
101+ second .get (5 , TimeUnit .SECONDS );
102+ assertEquals (2 , server .turnStartCount ());
103+ }
104+ }
105+
106+ @ Test
107+ void shouldAllowConcurrentTurnsForDifferentSessionKeys () throws Exception {
108+ try (FakeCodexAppServer server = new FakeCodexAppServer ();
109+ CodexAppServerClient client = new CodexAppServerClient (configFor (server ))) {
110+ server .holdTurnCompletions ();
111+
112+ java .util .concurrent .CompletableFuture <AppServerTurnResult > first =
113+ client .runTurnAsync (AppServerTurnRequest .builder ()
114+ .prompt ("first" )
115+ .sessionKey ("chat-a" )
116+ .build ());
117+ java .util .concurrent .CompletableFuture <AppServerTurnResult > second =
118+ client .runTurnAsync (AppServerTurnRequest .builder ()
119+ .prompt ("second" )
120+ .sessionKey ("chat-b" )
121+ .build ());
122+
123+ assertTrue (server .awaitTurnStarts (2 , 2_000 ),
124+ "different sessions must be able to run concurrently" );
125+
126+ server .releaseTurnCompletions ();
127+ first .get (5 , TimeUnit .SECONDS );
128+ second .get (5 , TimeUnit .SECONDS );
129+ }
130+ }
131+
76132 @ Test
77133 void shouldResumeSameThreadForRepeatedSessionKey () throws Exception {
78134 try (FakeCodexAppServer server = new FakeCodexAppServer ();
0 commit comments