From af99c2b134f540b66efa69f7e80fb96a6404768a Mon Sep 17 00:00:00 2001 From: kirillk Date: Fri, 10 Jul 2026 13:50:14 -0400 Subject: [PATCH] test(jetbrains): dispose ignores late SSE callbacks without reconnecting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../backend/app/KiloConnectionServiceTest.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/app/KiloConnectionServiceTest.kt b/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/app/KiloConnectionServiceTest.kt index 34cef9fecd2..bd9e454a892 100644 --- a/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/app/KiloConnectionServiceTest.kt +++ b/packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/app/KiloConnectionServiceTest.kt @@ -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