package com.vincent.rsf.server.ai.service.impl.chat; import com.vincent.rsf.server.ai.dto.AiChatTraceEventDto; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) class AiChatTraceEmitterTest { @Mock private AiSseEventPublisher aiSseEventPublisher; @Captor private ArgumentCaptor payloadCaptor; @Test void shouldReuseTraceIdentityForLogicalTraceCards() { AiChatTraceEmitter traceEmitter = new AiChatTraceEmitter( aiSseEventPublisher, new SseEmitter(1000L), "req-1", 11L, new AtomicLong(0) ); traceEmitter.startAnalyze(); traceEmitter.onToolStart("inventory.lookup", "builtin-stock", "tool-1", "{\"code\":\"A01\"}", 100L); traceEmitter.onToolResult("inventory.lookup", "builtin-stock", "tool-1", "{\"code\":\"A01\"}", "{\"stock\":12}", null, 64L, 164L, false); verify(aiSseEventPublisher, times(4)).emitSafely(any(), eq("trace"), payloadCaptor.capture()); List payloads = payloadCaptor.getAllValues(); assertThat(payloads).extracting(AiChatTraceEventDto::getSequence) .containsExactly(1L, 1L, 2L, 2L); assertThat(payloads).extracting(AiChatTraceEventDto::getTraceId) .containsExactly("req-1-thinking-ANALYZE", "req-1-thinking-ANALYZE", "tool-1", "tool-1"); assertThat(payloads).extracting(AiChatTraceEventDto::getTraceType) .containsExactly("thinking", "thinking", "tool", "tool"); assertThat(payloads.get(1).getStatus()).isEqualTo("COMPLETED"); assertThat(payloads.get(3).getStatus()).isEqualTo("COMPLETED"); assertThat(payloads.get(3).getToolCallId()).isEqualTo("tool-1"); assertThat(payloads.get(3).getInputSummary()).isEqualTo("{\"code\":\"A01\"}"); } }