Skip to content

Commit 4ceb246

Browse files
committed
test(acp): add observable lifecycle RED cases
1 parent 173d3f7 commit 4ceb246

1 file changed

Lines changed: 47 additions & 0 deletions

File tree

‎src/test/java/io/github/easy4j/kimi/acp/KimiAcpLifecycleHardeningTest.java‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import static org.junit.jupiter.api.Assertions.assertTrue;
1212

1313
import java.lang.reflect.Field;
14+
import java.lang.reflect.Method;
1415
import java.nio.file.Paths;
1516
import java.util.ArrayList;
1617
import java.util.List;
@@ -178,6 +179,52 @@ void shouldFailAndCleanPendingPromptWhenClientCloses() throws Exception {
178179
client.close();
179180
}
180181

182+
183+
@Test
184+
void shouldExposeLifecycleStateTransitions() throws Exception {
185+
KimiAcpClient client = new KimiAcpClient(config("normal"));
186+
assertEquals("NEW", lifecycleState(client));
187+
188+
client.connect();
189+
assertEquals("READY", lifecycleState(client));
190+
191+
client.close();
192+
assertEquals("CLOSED", lifecycleState(client));
193+
}
194+
195+
@Test
196+
void shouldMarkTransportFailedAndRejectNewRpcAfterMalformedFrame() throws Exception {
197+
try (KimiAcpClient client = new KimiAcpClient(config("malformed-prompt"))) {
198+
client.connect();
199+
String sessionId = client.newSession("/tmp");
200+
201+
CompletableFuture<KimiAcpTurnResult> future =
202+
client.promptAsync(sessionId, "bad-frame-state", null);
203+
assertThrows(ExecutionException.class, () -> future.get(2, TimeUnit.SECONDS));
204+
205+
assertEquals("FAILED", lifecycleState(client));
206+
assertThrows(KimiException.class, client::listSessions,
207+
"a failed transport must reject new RPCs before registration");
208+
assertEquals(0, privateMapSize(client, "pendingRpcs"));
209+
}
210+
}
211+
212+
@Test
213+
void shouldReturnToNewAfterRecoverableConnectFailure() throws Exception {
214+
KimiAcpConfig bad = config("normal");
215+
bad.setLocalExecutable("/nonexistent/kimi");
216+
try (KimiAcpClient client = new KimiAcpClient(bad)) {
217+
assertThrows(KimiException.class, client::connect);
218+
assertEquals("NEW", lifecycleState(client),
219+
"spawn/initialize failure remains retryable on the same client");
220+
}
221+
}
222+
223+
private static String lifecycleState(KimiAcpClient client) throws Exception {
224+
Method method = KimiAcpClient.class.getMethod("getState");
225+
return String.valueOf(method.invoke(client));
226+
}
227+
181228
@SuppressWarnings("unchecked")
182229
private static int privateMapSize(KimiAcpClient client, String fieldName) throws Exception {
183230
Field field = KimiAcpClient.class.getDeclaredField(fieldName);

0 commit comments

Comments
 (0)