From 919546f23b10651e21d9b7c589c744e413204958 Mon Sep 17 00:00:00 2001 From: kami Date: Mon, 25 May 2026 11:44:24 +0400 Subject: [PATCH] test(tui-03): add gap detection test for SnapshotPhaseReducer --- .../tui/reducer/SnapshotPhaseReducerTest.kt | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/apps/tui/src/test/kotlin/com/correx/apps/tui/reducer/SnapshotPhaseReducerTest.kt b/apps/tui/src/test/kotlin/com/correx/apps/tui/reducer/SnapshotPhaseReducerTest.kt index 8ed49ef7..4dce6204 100644 --- a/apps/tui/src/test/kotlin/com/correx/apps/tui/reducer/SnapshotPhaseReducerTest.kt +++ b/apps/tui/src/test/kotlin/com/correx/apps/tui/reducer/SnapshotPhaseReducerTest.kt @@ -33,6 +33,60 @@ class SnapshotPhaseReducerTest { assertTrue(state.sessions.sessions.isEmpty()) } + @Test + fun `live event with sessionSequence at or below cursor is dropped`() { + val state = TuiState(snapshotPhase = false, cursors = mapOf("s1" to 5L)) + val action = Action.ServerEventReceived( + ServerMessage.SessionStarted( + sessionId = SessionId("s1"), + workflowId = "wf", + sequence = 5L, + sessionSequence = 5L, + ) + ) + + val result = SnapshotPhaseReducer.process(state, action) + + assertTrue(result.actionsToDispatch.isEmpty()) + assertEquals(5L, result.state.cursors["s1"]) + } + + @Test + fun `live event with sessionSequence one above cursor is applied and cursor advances`() { + val state = TuiState(snapshotPhase = false, cursors = mapOf("s1" to 5L)) + val action = Action.ServerEventReceived( + ServerMessage.SessionStarted( + sessionId = SessionId("s1"), + workflowId = "wf", + sequence = 6L, + sessionSequence = 6L, + ) + ) + + val result = SnapshotPhaseReducer.process(state, action) + + assertEquals(listOf(action), result.actionsToDispatch) + assertEquals(6L, result.state.cursors["s1"]) + } + + @Test + fun `gap event is applied and cursor advances to incoming sequence`() { + val state = TuiState(snapshotPhase = false, cursors = mapOf("s1" to 5L)) + val action = Action.ServerEventReceived( + ServerMessage.SessionStarted( + sessionId = SessionId("s1"), + workflowId = "wf", + sequence = 8L, + sessionSequence = 8L, + ) + ) + + val result = SnapshotPhaseReducer.process(state, action) + + assertEquals(listOf(action), result.actionsToDispatch) + assertEquals(8L, result.state.cursors["s1"]) + } + @Test fun `during snapshotPhase SessionSnapshot installs cursor and is forwarded to sub-reducers`() { val state = TuiState(snapshotPhase = true)