test(jetbrains): dispose ignores late SSE callbacks without reconnecting

Locks in the disposal terminal-state guarantee (R5): after dispose(), a late SSE onClosed/onFailure with a stale source must not resurrect the connection or schedule a reconnect. Deterministic — drives the listener directly, no sleeps.
This commit is contained in:
kirillk
2026-07-10 13:50:14 -04:00
parent e0bfed308c
commit af99c2b134
@@ -277,6 +277,35 @@ class KiloConnectionServiceTest {
assertEquals(ConnectionState.Disconnected, svc.state.value)
}
@Test
fun `dispose prevents reconnect on late SSE callbacks`() = runBlocking {
val reconnects = AtomicInteger(0)
val svc = KiloConnectionService(scope, fake, { reconnects.incrementAndGet() }, log)
svc.connect()
mock.awaitSseConnection()
withTimeout(5_000) {
svc.state.first { it is ConnectionState.Connected }
}
svc.dispose()
// Simulate a late SSE close/failure arriving after teardown. The stale source must be
// ignored so shutdown neither resurrects the connection nor schedules a reconnect.
val field = KiloConnectionService::class.java.getDeclaredField("listener")
field.isAccessible = true
val listener = field.get(svc) as EventSourceListener
val stale = object : EventSource {
override fun request(): Request = Request.Builder().url("http://127.0.0.1/global/event").build()
override fun cancel() {}
}
listener.onFailure(stale, RuntimeException("late failure"), null)
listener.onClosed(stale)
assertEquals(ConnectionState.Disconnected, svc.state.value)
assertEquals(0, reconnects.get())
}
// ------ Reconnect & health ------
@Test