1616import java .util .Optional ;
1717
1818import static org .assertj .core .api .Assertions .assertThat ;
19- import static org .mockito .Mockito .mock ;
20- import static org .mockito .Mockito .verify ;
21- import static org .mockito .Mockito .when ;
19+ import static org .mockito .Mockito .*;
2220
2321class ResultQueueConsumerTest {
2422
2523 private final TaskStatusRepository taskStatusRepository = mock (TaskStatusRepository .class );
26- private final TaskStatusHistoryRepository pgRepository = mock (TaskStatusHistoryRepository .class );
24+ private final TaskStatusHistoryRepository historyRepository = mock (TaskStatusHistoryRepository .class );
2725 private final PipelineMetrics pipelineMetrics = new PipelineMetrics (new SimpleMeterRegistry ());
2826 private final ObjectMapper objectMapper = new ObjectMapper ()
2927 .configure (DeserializationFeature .FAIL_ON_UNKNOWN_PROPERTIES , false );
3028 private final ResultQueueConsumer consumer = new ResultQueueConsumer (
3129 mock (org .springframework .data .redis .core .RedisTemplate .class ),
32- taskStatusRepository , pgRepository , pipelineMetrics , objectMapper );
30+ taskStatusRepository , historyRepository , pipelineMetrics , objectMapper );
3331
3432 private TaskStatus queued (String taskId ) {
3533 return new TaskStatus (taskId , AgentStep .JUDGING , false , 0 , null ,
@@ -54,7 +52,7 @@ void successMessageMapsToPassed() {
5452 assertThat (saved .executable ()).isTrue ();
5553 assertThat (saved .errorMessage ()).isNull ();
5654 assertThat (saved .aiReports ()).containsKey ("judge_report" );
57- verify (pgRepository ).upsert (saved );
55+ verify (historyRepository ).upsert (saved );
5856 }
5957
6058 @ Test
@@ -94,4 +92,55 @@ void infraErrorMapsToErrorNotFailed() {
9492 assertThat (saved .currentAgent ()).isEqualTo (AgentStep .ERROR );
9593 assertThat (saved .errorMessage ()).contains ("판정 불가" );
9694 }
95+ @ Test
96+ void progressEventUpdatesStepAndRound () {
97+ when (taskStatusRepository .findById ("t4" )).thenReturn (Optional .of (queued ("t4" )));
98+
99+ consumer .process (Map .of (
100+ "type" , "progress" ,
101+ "request_id" , "t4" ,
102+ "step" , "REFINING" ,
103+ "round" , 2 ,
104+ "max_rounds" , 3
105+ ));
106+
107+ ArgumentCaptor <TaskStatus > captor = ArgumentCaptor .forClass (TaskStatus .class );
108+ verify (taskStatusRepository ).save (captor .capture ());
109+ TaskStatus saved = captor .getValue ();
110+
111+ assertThat (saved .currentAgent ()).isEqualTo (AgentStep .REFINING );
112+ assertThat (saved .iterationCount ()).isEqualTo (2 );
113+ assertThat (saved .errorMessage ()).isNull ();
114+ verify (historyRepository ).upsert (saved );
115+ }
116+
117+ @ Test
118+ void progressAfterTerminalIsIgnored () {
119+ TaskStatus done = new TaskStatus ("t5" , AgentStep .PASSED , true , 1 , null ,
120+ LocalDateTime .of (2026 , 8 , 3 , 12 , 0 ), "https://github.com/phdcoco/QuickByte_Demo" , "main" , "d1c5c5e" , null );
121+ when (taskStatusRepository .findById ("t5" )).thenReturn (Optional .of (done ));
122+
123+ consumer .process (Map .of ("type" , "progress" , "request_id" , "t5" , "step" , "BASELINE" ));
124+
125+ // 확정된 결과는 늦게 온 progress로 되돌아가지 않는다
126+ verify (taskStatusRepository , never ()).save (any ());
127+ verify (historyRepository , never ()).upsert (any ());
128+ }
129+
130+ @ Test
131+ void unknownMessageTypeIsIgnored () {
132+ consumer .process (Map .of ("type" , "heartbeat" , "request_id" , "t6" ));
133+
134+ verify (taskStatusRepository , never ()).save (any ());
135+ verify (historyRepository , never ()).upsert (any ());
136+ }
137+
138+ @ Test
139+ void unknownStepProgressIsIgnored () {
140+ when (taskStatusRepository .findById ("t7" )).thenReturn (Optional .of (queued ("t7" )));
141+
142+ consumer .process (Map .of ("type" , "progress" , "request_id" , "t7" , "step" , "DEPLOYING" ));
143+
144+ verify (taskStatusRepository , never ()).save (any ());
145+ }
97146}
0 commit comments