diff --git a/common-agent-agent/src/test/java/com/bruce/agent/controller/AgentSessionControllerTests.java b/common-agent-agent/src/test/java/com/bruce/agent/controller/AgentSessionControllerTests.java new file mode 100644 index 0000000..a125770 --- /dev/null +++ b/common-agent-agent/src/test/java/com/bruce/agent/controller/AgentSessionControllerTests.java @@ -0,0 +1,69 @@ +package com.bruce.agent.controller; + +import com.bruce.agent.service.IAgentMessageService; +import com.bruce.agent.service.IAgentSessionService; +import com.bruce.agent.service.IAgentWorkspaceService; +import com.bruce.agent.vo.AgentWorkspaceVO; +import com.bruce.common.handler.GlobalExceptionHandler; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * 验证 Agent 工作台聚合接口的查询参数绑定和返回结构。 + */ +@ExtendWith(MockitoExtension.class) +class AgentSessionControllerTests { + + private MockMvc mockMvc; + + @Mock + private IAgentSessionService agentSessionService; + + @Mock + private IAgentMessageService agentMessageService; + + @Mock + private IAgentWorkspaceService agentWorkspaceService; + + @InjectMocks + private AgentSessionController agentSessionController; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(agentSessionController) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void workspaceShouldReturnStructuredAggregateView() throws Exception { + AgentWorkspaceVO workspace = new AgentWorkspaceVO(); + workspace.setAgentId(1001L); + workspace.setAgentCode("presale_agent"); + workspace.setAgentName("售前问答 Agent"); + workspace.setSessionId(2001L); + workspace.setSessionCode("session_001"); + workspace.setLatestRequestId("req-1001"); + workspace.setCitationCount(2); + + when(agentWorkspaceService.getWorkspace(1001L, null)).thenReturn(workspace); + + mockMvc.perform(get("/api/agent-sessions/workspace").param("agentId", "1001")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.resultcode").value("0")) + .andExpect(jsonPath("$.data.agentId").value(1001)) + .andExpect(jsonPath("$.data.agentName").value("售前问答 Agent")) + .andExpect(jsonPath("$.data.latestRequestId").value("req-1001")); + } +} diff --git a/common-agent-boot/src/test/java/com/bruce/dashboard/StudioDashboardControllerTests.java b/common-agent-boot/src/test/java/com/bruce/dashboard/StudioDashboardControllerTests.java new file mode 100644 index 0000000..99088f1 --- /dev/null +++ b/common-agent-boot/src/test/java/com/bruce/dashboard/StudioDashboardControllerTests.java @@ -0,0 +1,67 @@ +package com.bruce.dashboard; + +import com.bruce.common.handler.GlobalExceptionHandler; +import com.bruce.dashboard.controller.StudioDashboardController; +import com.bruce.dashboard.service.IStudioDashboardService; +import com.bruce.dashboard.vo.StudioDashboardMetricsVO; +import com.bruce.dashboard.vo.StudioDashboardVO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * 验证 Studio 首页聚合接口响应结构,确保前端首页可稳定消费。 + */ +@ExtendWith(MockitoExtension.class) +class StudioDashboardControllerTests { + + private MockMvc mockMvc; + + @Mock + private IStudioDashboardService studioDashboardService; + + @InjectMocks + private StudioDashboardController studioDashboardController; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(studioDashboardController) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void detailShouldReturnStructuredDashboardView() throws Exception { + StudioDashboardMetricsVO metrics = new StudioDashboardMetricsVO(); + metrics.setTodayRunCount(12); + metrics.setSuccessRate(98.5D); + metrics.setP50Latency("1.28s"); + metrics.setEstimatedCost("¥4.82"); + + StudioDashboardVO dashboard = new StudioDashboardVO(); + dashboard.setProjectName("Common Agent Studio"); + dashboard.setEnvironment("Dev"); + dashboard.setPublishStatus("DRAFT"); + dashboard.setMetrics(metrics); + dashboard.setWarningTitle("发布前仍需补齐模型路由"); + + when(studioDashboardService.getDashboard()).thenReturn(dashboard); + + mockMvc.perform(get("/api/studio/dashboard")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.resultcode").value("0")) + .andExpect(jsonPath("$.data.projectName").value("Common Agent Studio")) + .andExpect(jsonPath("$.data.environment").value("Dev")) + .andExpect(jsonPath("$.data.metrics.todayRunCount").value(12)); + } +} diff --git a/common-agent-common/src/main/java/com/bruce/common/handler/GlobalExceptionHandler.java b/common-agent-common/src/main/java/com/bruce/common/handler/GlobalExceptionHandler.java index a2bb67a..378815c 100644 --- a/common-agent-common/src/main/java/com/bruce/common/handler/GlobalExceptionHandler.java +++ b/common-agent-common/src/main/java/com/bruce/common/handler/GlobalExceptionHandler.java @@ -6,6 +6,8 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.bind.MissingServletRequestParameterException; @Slf4j @RestControllerAdvice @@ -17,6 +19,15 @@ public class GlobalExceptionHandler { return buildResponse(HttpStatus.BAD_REQUEST, exception.getMessage()); } + @ExceptionHandler({ + MissingServletRequestParameterException.class, + MethodArgumentTypeMismatchException.class + }) + public ResponseEntity> handleBadRequest(Exception exception) { + log.warn("GlobalExceptionHandler.handleBadRequest, message={}", exception.getMessage(), exception); + return buildResponse(HttpStatus.BAD_REQUEST, "请求参数不合法"); + } + @ExceptionHandler(Exception.class) public ResponseEntity> handleException(Exception exception) { log.error("GlobalExceptionHandler.handleException", exception); diff --git a/common-agent-common/src/test/java/com/bruce/common/controller/SysEnumControllerTests.java b/common-agent-common/src/test/java/com/bruce/common/controller/SysEnumControllerTests.java new file mode 100644 index 0000000..aeca28a --- /dev/null +++ b/common-agent-common/src/test/java/com/bruce/common/controller/SysEnumControllerTests.java @@ -0,0 +1,76 @@ +package com.bruce.common.controller; + +import com.bruce.common.dto.response.SysEnumResponse; +import com.bruce.common.handler.GlobalExceptionHandler; +import com.bruce.common.service.ISysEnumService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.http.MediaType; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * 验证系统枚举控制器的基础接口契约,确保前端依赖的 RequestResult 结构稳定。 + */ +@ExtendWith(MockitoExtension.class) +class SysEnumControllerTests { + + private MockMvc mockMvc; + + @Mock + private ISysEnumService sysEnumService; + + @BeforeEach + void setUp() { + SysEnumController controller = new SysEnumController(); + ReflectionTestUtils.setField(controller, "sysEnumService", sysEnumService); + mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void queryForManagementShouldReturnStructuredResult() throws Exception { + SysEnumResponse response = new SysEnumResponse(); + response.setId(1L); + response.setCatalog("common"); + response.setType("enable_status"); + response.setName("启用"); + response.setValue(1); + response.setStrvalue("ENABLED"); + + when(sysEnumService.listForManagement(any())).thenReturn(List.of(response)); + + mockMvc.perform(post("/api/sys-enum/queryForManagement") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "catalog": "common", + "type": "enable_status" + } + """)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.resultcode").value("0")) + .andExpect(jsonPath("$.data[0].catalog").value("common")) + .andExpect(jsonPath("$.data[0].strvalue").value("ENABLED")); + } + + @Test + void detailShouldReturnBadRequestWhenIdMissing() throws Exception { + mockMvc.perform(get("/api/sys-enum/detail")) + .andExpect(status().isBadRequest()); + } +} diff --git a/common-agent-rag/src/test/java/com/bruce/rag/controller/KnowledgeWorkspaceControllerTests.java b/common-agent-rag/src/test/java/com/bruce/rag/controller/KnowledgeWorkspaceControllerTests.java new file mode 100644 index 0000000..3b05f20 --- /dev/null +++ b/common-agent-rag/src/test/java/com/bruce/rag/controller/KnowledgeWorkspaceControllerTests.java @@ -0,0 +1,59 @@ +package com.bruce.rag.controller; + +import com.bruce.common.handler.GlobalExceptionHandler; +import com.bruce.rag.service.IKnowledgeWorkspaceService; +import com.bruce.rag.vo.KnowledgeWorkspaceVO; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * 验证知识工作台聚合接口的路径参数绑定和响应结构。 + */ +@ExtendWith(MockitoExtension.class) +class KnowledgeWorkspaceControllerTests { + + private MockMvc mockMvc; + + @Mock + private IKnowledgeWorkspaceService knowledgeWorkspaceService; + + @InjectMocks + private KnowledgeWorkspaceController knowledgeWorkspaceController; + + @BeforeEach + void setUp() { + mockMvc = MockMvcBuilders.standaloneSetup(knowledgeWorkspaceController) + .setControllerAdvice(new GlobalExceptionHandler()) + .build(); + } + + @Test + void getWorkspaceShouldReturnStructuredWorkspaceView() throws Exception { + KnowledgeWorkspaceVO workspace = new KnowledgeWorkspaceVO(); + workspace.setStoreId(1001L); + workspace.setStoreCode("PROD_DOC"); + workspace.setStoreName("产品制度库"); + workspace.setDocumentCount(9); + workspace.setHealthScore(88); + + when(knowledgeWorkspaceService.getWorkspace(1001L)).thenReturn(workspace); + + mockMvc.perform(get("/api/knowledge/workspaces/1001")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.resultcode").value("0")) + .andExpect(jsonPath("$.data.storeId").value("1001")) + .andExpect(jsonPath("$.data.storeName").value("产品制度库")) + .andExpect(jsonPath("$.data.healthScore").value(88)); + } +}