feat(compat): 补齐文档草案接口兼容入口
This commit is contained in:
@@ -8,6 +8,7 @@ import com.bruce.agent.dto.response.AgentDefinitionResponse;
|
||||
import com.bruce.agent.service.IAgentDefinitionService;
|
||||
import com.bruce.common.domain.model.RequestResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/agents")
|
||||
@RequiredArgsConstructor
|
||||
@@ -55,4 +57,15 @@ public class AgentDefinitionController {
|
||||
@RequestBody AgentChatRequest request) {
|
||||
return RequestResult.success(agentDefinitionService.chat(agentId, request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的运行入口路径。
|
||||
*/
|
||||
@PostMapping("/{agentId}/runs")
|
||||
public RequestResult<AgentChatResponse> run(@PathVariable("agentId") Long agentId,
|
||||
@RequestBody AgentChatRequest request) {
|
||||
log.info("Agent运行入口开始,agentId={}, messageCount={}",
|
||||
agentId, request.getMessages() == null ? 0 : request.getMessages().size());
|
||||
return RequestResult.success(agentDefinitionService.chat(agentId, request));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,24 @@ public class AgentSessionController {
|
||||
return RequestResult.success(agentSessionService.getDetailById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的资源化会话详情路径。
|
||||
*/
|
||||
@GetMapping("/{sessionId}")
|
||||
public RequestResult<AgentSessionDetailVO> detailByPath(@PathVariable("sessionId") Long sessionId) {
|
||||
log.info("Agent会话详情按路径查询开始,sessionId={}", sessionId);
|
||||
return RequestResult.success(agentSessionService.getDetailById(sessionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的 Agent 会话列表路径。
|
||||
*/
|
||||
@GetMapping("/agents/{agentId}/sessions")
|
||||
public RequestResult<List<AgentSessionDetailVO>> sessionsByAgent(@PathVariable("agentId") Long agentId) {
|
||||
log.info("Agent会话列表查询开始,agentId={}", agentId);
|
||||
return RequestResult.success(agentSessionService.listByAgentId(agentId));
|
||||
}
|
||||
|
||||
@GetMapping("/{sessionId}/messages")
|
||||
public RequestResult<List<AgentMessageVO>> messages(@PathVariable("sessionId") Long sessionId) {
|
||||
log.info("Agent消息列表查询开始,sessionId={}", sessionId);
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.bruce.agent.controller;
|
||||
|
||||
import com.bruce.agent.dto.response.AgentChatResponse;
|
||||
import com.bruce.agent.service.IAgentDefinitionService;
|
||||
import com.bruce.agent.service.IAgentMessageService;
|
||||
import com.bruce.agent.service.IAgentSessionService;
|
||||
import com.bruce.agent.service.IAgentWorkspaceService;
|
||||
import com.bruce.agent.vo.AgentSessionDetailVO;
|
||||
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.http.MediaType;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 验证 Agent 文档草案兼容路径。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AgentCompatControllerTests {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Mock
|
||||
private IAgentDefinitionService agentDefinitionService;
|
||||
|
||||
@Mock
|
||||
private IAgentSessionService agentSessionService;
|
||||
|
||||
@Mock
|
||||
private IAgentMessageService agentMessageService;
|
||||
|
||||
@Mock
|
||||
private IAgentWorkspaceService agentWorkspaceService;
|
||||
|
||||
@InjectMocks
|
||||
private AgentDefinitionController agentDefinitionController;
|
||||
|
||||
@InjectMocks
|
||||
private AgentSessionController agentSessionController;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockMvc = MockMvcBuilders.standaloneSetup(agentDefinitionController, agentSessionController)
|
||||
.setControllerAdvice(new GlobalExceptionHandler())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void agentRunCompatShouldReturnChatResponse() throws Exception {
|
||||
AgentChatResponse response = new AgentChatResponse();
|
||||
response.setAgentId(1001L);
|
||||
response.setAgentCode("presale_agent");
|
||||
response.setAnswer("这是兼容运行入口返回的答案");
|
||||
response.setModelRequestId("req-1001");
|
||||
|
||||
when(agentDefinitionService.chat(org.mockito.ArgumentMatchers.eq(1001L), any())).thenReturn(response);
|
||||
|
||||
mockMvc.perform(post("/api/agents/1001/runs")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "请总结合同重点"
|
||||
}
|
||||
],
|
||||
"ragEnabled": true
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data.agentCode").value("presale_agent"))
|
||||
.andExpect(jsonPath("$.data.modelRequestId").value("req-1001"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionsCompatShouldReturnStructuredSessionList() throws Exception {
|
||||
AgentSessionDetailVO session = new AgentSessionDetailVO();
|
||||
session.setId(2001L);
|
||||
session.setAgentId(1001L);
|
||||
session.setSessionCode("session_001");
|
||||
session.setStatus("ACTIVE");
|
||||
|
||||
when(agentSessionService.listByAgentId(1001L)).thenReturn(List.of(session));
|
||||
|
||||
mockMvc.perform(get("/api/agent-sessions/agents/1001/sessions"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data[0].sessionCode").value("session_001"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sessionDetailCompatShouldReturnStructuredDetail() throws Exception {
|
||||
AgentSessionDetailVO session = new AgentSessionDetailVO();
|
||||
session.setId(2001L);
|
||||
session.setSessionCode("session_001");
|
||||
session.setStatus("ACTIVE");
|
||||
|
||||
when(agentSessionService.getDetailById(2001L)).thenReturn(session);
|
||||
|
||||
mockMvc.perform(get("/api/agent-sessions/2001"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data.sessionCode").value("session_001"));
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import com.bruce.mcp.service.IMcpCapabilityService;
|
||||
import com.bruce.mcp.service.IMcpImportService;
|
||||
import com.bruce.mcp.service.IMcpServerService;
|
||||
import com.bruce.mcp.service.IMcpWorkspaceService;
|
||||
import com.bruce.mcp.vo.McpCapabilityVO;
|
||||
import com.bruce.mcp.vo.McpServerVO;
|
||||
import com.bruce.mcp.vo.McpCapabilityVO;
|
||||
import com.bruce.mcp.vo.McpWorkspaceVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -50,6 +50,15 @@ public class McpImportController {
|
||||
return RequestResult.success(mcpServerService.listServers());
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的 query 路径。
|
||||
*/
|
||||
@PostMapping("/servers/query")
|
||||
public RequestResult<List<McpServerVO>> queryServers() {
|
||||
log.info("MCP服务列表兼容查询开始");
|
||||
return RequestResult.success(mcpServerService.listServers());
|
||||
}
|
||||
|
||||
@GetMapping("/servers/{serverId}/capabilities")
|
||||
public RequestResult<List<McpCapabilityVO>> listCapabilities(@PathVariable("serverId") Long serverId) {
|
||||
log.info("MCP能力列表查询开始,serverId={}", serverId);
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.bruce.mcp.service.IMcpCapabilityService;
|
||||
import com.bruce.mcp.service.IMcpImportService;
|
||||
import com.bruce.mcp.service.IMcpServerService;
|
||||
import com.bruce.mcp.service.IMcpWorkspaceService;
|
||||
import com.bruce.mcp.vo.McpServerVO;
|
||||
import com.bruce.mcp.vo.McpWorkspaceVO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -17,6 +18,7 @@ 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.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -68,4 +70,19 @@ class McpImportControllerTests {
|
||||
.andExpect(jsonPath("$.data.serverCode").value("jira_server"))
|
||||
.andExpect(jsonPath("$.data.healthStatus").value("HEALTHY"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void queryServersCompatShouldReturnStructuredServerList() throws Exception {
|
||||
McpServerVO server = new McpServerVO();
|
||||
server.setId(301L);
|
||||
server.setServerCode("jira_server");
|
||||
server.setServerName("Jira 服务");
|
||||
|
||||
when(mcpServerService.listServers()).thenReturn(java.util.List.of(server));
|
||||
|
||||
mockMvc.perform(post("/api/mcp/servers/query"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data[0].serverCode").value("jira_server"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -41,6 +42,16 @@ public class SkillWorkspaceController {
|
||||
return RequestResult.success(skillVersionService.saveDraft(skillCode, request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的 PUT 草稿保存路径。
|
||||
*/
|
||||
@PutMapping("/{skillCode}/draft")
|
||||
public RequestResult<Boolean> saveDraftCompat(@PathVariable("skillCode") String skillCode,
|
||||
@RequestBody SkillVersionSaveDTO request) {
|
||||
log.info("Skill草稿兼容保存开始,skillCode={}, versionNo={}", skillCode, request.getVersionNo());
|
||||
return RequestResult.success(skillVersionService.saveDraft(skillCode, request));
|
||||
}
|
||||
|
||||
@PostMapping("/{skillCode}/test")
|
||||
public RequestResult<SkillVersionVO> test(@PathVariable("skillCode") String skillCode,
|
||||
@RequestBody SkillVersionSaveDTO request) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bruce.skill.controller;
|
||||
|
||||
import com.bruce.common.handler.GlobalExceptionHandler;
|
||||
import com.bruce.skill.dto.SkillVersionSaveDTO;
|
||||
import com.bruce.skill.service.ISkillVersionService;
|
||||
import com.bruce.skill.service.ISkillWorkspaceService;
|
||||
import com.bruce.skill.vo.SkillWorkspaceVO;
|
||||
@@ -15,6 +16,7 @@ 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.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -59,4 +61,22 @@ class SkillWorkspaceControllerTests {
|
||||
.andExpect(jsonPath("$.data.skillCode").value("resume_extract"))
|
||||
.andExpect(jsonPath("$.data.status").value("PUBLISHED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveDraftCompatShouldReturnSuccess() throws Exception {
|
||||
when(skillVersionService.saveDraft(org.mockito.ArgumentMatchers.eq("resume_extract"),
|
||||
org.mockito.ArgumentMatchers.any(SkillVersionSaveDTO.class))).thenReturn(true);
|
||||
|
||||
mockMvc.perform(put("/api/skills/resume_extract/draft")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"versionNo": 2,
|
||||
"promptText": "提取候选人经历"
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import com.bruce.workflow.dto.WorkflowDefinitionSaveDTO;
|
||||
import com.bruce.workflow.service.IWorkflowDefinitionService;
|
||||
import com.bruce.workflow.vo.WorkflowDefinitionVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/workflows")
|
||||
@RequiredArgsConstructor
|
||||
@@ -33,8 +36,26 @@ public class WorkflowDefinitionController {
|
||||
return RequestResult.success(workflowDefinitionService.getDefinition(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的 REST 详情路径。
|
||||
*/
|
||||
@GetMapping("/{workflowId}")
|
||||
public RequestResult<WorkflowDefinitionVO> detailByPath(@PathVariable("workflowId") Long workflowId) {
|
||||
log.info("Workflow定义详情查询开始,workflowId={}", workflowId);
|
||||
return RequestResult.success(workflowDefinitionService.getDefinition(workflowId));
|
||||
}
|
||||
|
||||
@PostMapping("/definition/save")
|
||||
public RequestResult<Boolean> save(@RequestBody WorkflowDefinitionSaveDTO request) {
|
||||
return RequestResult.success(workflowDefinitionService.saveDefinition(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的草稿保存路径。
|
||||
*/
|
||||
@PostMapping("/save-draft")
|
||||
public RequestResult<Boolean> saveDraft(@RequestBody WorkflowDefinitionSaveDTO request) {
|
||||
log.info("Workflow草稿保存开始,workflowId={}, workflowCode={}", request.getId(), request.getWorkflowCode());
|
||||
return RequestResult.success(workflowDefinitionService.saveDefinition(request));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.bruce.workflow.dto.WorkflowRunCreateDTO;
|
||||
import com.bruce.workflow.service.IWorkflowRunService;
|
||||
import com.bruce.workflow.vo.WorkflowRunVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/workflow-runs")
|
||||
@RequiredArgsConstructor
|
||||
@@ -30,4 +32,25 @@ public class WorkflowRunController {
|
||||
public RequestResult<List<WorkflowRunVO>> list(@PathVariable("workflowId") Long workflowId) {
|
||||
return RequestResult.success(workflowRunService.listRecentByWorkflowId(workflowId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的资源化运行创建路径。
|
||||
*/
|
||||
@PostMapping("/compat/workflows/{workflowId}/runs")
|
||||
public RequestResult<Boolean> createCompat(@PathVariable("workflowId") Long workflowId,
|
||||
@RequestBody WorkflowRunCreateDTO request) {
|
||||
request.setWorkflowId(workflowId);
|
||||
log.info("Workflow运行创建开始,workflowId={}, versionId={}, requestId={}",
|
||||
workflowId, request.getWorkflowVersionId(), request.getRequestId());
|
||||
return RequestResult.success(workflowRunService.createRun(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的按运行ID查询路径。
|
||||
*/
|
||||
@GetMapping("/compat/workflows/runs/{runId}")
|
||||
public RequestResult<WorkflowRunVO> detailCompat(@PathVariable("runId") Long runId) {
|
||||
log.info("Workflow运行详情查询开始,runId={}", runId);
|
||||
return RequestResult.success(workflowRunService.getRunById(runId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.bruce.workflow.dto.WorkflowVersionSaveDTO;
|
||||
import com.bruce.workflow.service.IWorkflowVersionService;
|
||||
import com.bruce.workflow.vo.WorkflowVersionVO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -14,6 +15,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/workflow-versions")
|
||||
@RequiredArgsConstructor
|
||||
@@ -30,4 +32,15 @@ public class WorkflowVersionController {
|
||||
public RequestResult<Boolean> publish(@RequestBody WorkflowVersionSaveDTO request) {
|
||||
return RequestResult.success(workflowVersionService.publishVersion(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容前端实现文档中的资源化发布路径。
|
||||
*/
|
||||
@PostMapping("/compat/workflows/{workflowId}/publish")
|
||||
public RequestResult<Boolean> publishCompat(@PathVariable("workflowId") Long workflowId,
|
||||
@RequestBody WorkflowVersionSaveDTO request) {
|
||||
request.setWorkflowId(workflowId);
|
||||
log.info("Workflow版本发布开始,workflowId={}, versionNo={}", workflowId, request.getVersionNo());
|
||||
return RequestResult.success(workflowVersionService.publishVersion(request));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,6 @@ public interface IWorkflowRunService extends IService<WorkflowRun> {
|
||||
boolean createRun(WorkflowRunCreateDTO request);
|
||||
|
||||
List<WorkflowRunVO> listRecentByWorkflowId(Long workflowId);
|
||||
|
||||
WorkflowRunVO getRunById(Long runId);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,18 @@ public class WorkflowRunServiceImpl extends ServiceImpl<WorkflowRunMapper, Workf
|
||||
return workflowRunFactory.toVOList(runs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowRunVO getRunById(Long runId) {
|
||||
if (runId == null) {
|
||||
throw new IllegalArgumentException("Workflow运行ID不能为空");
|
||||
}
|
||||
WorkflowRun run = getById(runId);
|
||||
if (run == null) {
|
||||
return null;
|
||||
}
|
||||
return workflowRunFactory.toVO(run);
|
||||
}
|
||||
|
||||
private void validateRequest(WorkflowRunCreateDTO request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("Workflow运行请求不能为空");
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.bruce.workflow.controller;
|
||||
|
||||
import com.bruce.common.handler.GlobalExceptionHandler;
|
||||
import com.bruce.workflow.service.IWorkflowDefinitionService;
|
||||
import com.bruce.workflow.service.IWorkflowRunService;
|
||||
import com.bruce.workflow.service.IWorkflowVersionService;
|
||||
import com.bruce.workflow.vo.WorkflowDefinitionVO;
|
||||
import com.bruce.workflow.vo.WorkflowRunVO;
|
||||
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.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 验证 Workflow 文档草案兼容路径的返回契约。
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class WorkflowCompatControllerTests {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Mock
|
||||
private IWorkflowDefinitionService workflowDefinitionService;
|
||||
|
||||
@Mock
|
||||
private IWorkflowVersionService workflowVersionService;
|
||||
|
||||
@Mock
|
||||
private IWorkflowRunService workflowRunService;
|
||||
|
||||
@InjectMocks
|
||||
private WorkflowDefinitionController workflowDefinitionController;
|
||||
|
||||
@InjectMocks
|
||||
private WorkflowVersionController workflowVersionController;
|
||||
|
||||
@InjectMocks
|
||||
private WorkflowRunController workflowRunController;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockMvc = MockMvcBuilders.standaloneSetup(
|
||||
workflowDefinitionController,
|
||||
workflowVersionController,
|
||||
workflowRunController
|
||||
)
|
||||
.setControllerAdvice(new GlobalExceptionHandler())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void workflowDetailCompatShouldReturnStructuredDefinition() throws Exception {
|
||||
WorkflowDefinitionVO detail = new WorkflowDefinitionVO();
|
||||
detail.setId(201L);
|
||||
detail.setWorkflowCode("workflow-support-rag");
|
||||
detail.setWorkflowName("合同知识召回");
|
||||
|
||||
when(workflowDefinitionService.getDefinition(201L)).thenReturn(detail);
|
||||
|
||||
mockMvc.perform(get("/api/workflows/201"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data.workflowCode").value("workflow-support-rag"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveDraftCompatShouldDelegateToDefinitionService() throws Exception {
|
||||
when(workflowDefinitionService.saveDefinition(any())).thenReturn(true);
|
||||
|
||||
mockMvc.perform(post("/api/workflows/save-draft")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"id": 201,
|
||||
"projectId": 101,
|
||||
"workflowCode": "workflow-support-rag",
|
||||
"workflowName": "合同知识召回"
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void publishCompatShouldDelegateToVersionService() throws Exception {
|
||||
when(workflowVersionService.publishVersion(any())).thenReturn(true);
|
||||
|
||||
mockMvc.perform(post("/api/workflow-versions/compat/workflows/201/publish")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"versionNo": 3,
|
||||
"snapshotName": "v3"
|
||||
}
|
||||
"""))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data").value(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runCompatShouldReturnStructuredRunDetail() throws Exception {
|
||||
WorkflowRunVO run = new WorkflowRunVO();
|
||||
run.setId(301L);
|
||||
run.setWorkflowId(201L);
|
||||
run.setRequestId("req-1001");
|
||||
run.setStatus("SUCCESS");
|
||||
|
||||
when(workflowRunService.getRunById(301L)).thenReturn(run);
|
||||
|
||||
mockMvc.perform(get("/api/workflow-runs/compat/workflows/runs/301"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.resultcode").value("0"))
|
||||
.andExpect(jsonPath("$.data.requestId").value("req-1001"))
|
||||
.andExpect(jsonPath("$.data.status").value("SUCCESS"));
|
||||
}
|
||||
}
|
||||
@@ -159,15 +159,18 @@
|
||||
- `WorkflowWorkspaceController`
|
||||
- 前端工作台聚合使用 `GET /api/workflow-workspace/detail`;
|
||||
旧管理接口继续承担定义、版本与运行管理能力。
|
||||
|
||||
说明:
|
||||
|
||||
- 前端实现文档中的 REST 草案与当前聚合接口命名不完全一致,但职责已由 `WorkflowWorkspaceController` 承接,且不影响旧接口兼容。
|
||||
- 文档草案兼容路径已补充:
|
||||
- `GET /api/workflows/{workflowId}`
|
||||
- `POST /api/workflows/save-draft`
|
||||
- `POST /api/workflow-versions/compat/workflows/{workflowId}/publish`
|
||||
- `POST /api/workflow-runs/compat/workflows/{workflowId}/runs`
|
||||
- `GET /api/workflow-runs/compat/workflows/runs/{runId}`
|
||||
|
||||
证据:
|
||||
|
||||
- 代码:`common-agent-workflow/src/main/java/com/bruce/workflow/**/*`
|
||||
- 测试:
|
||||
- `common-agent-workflow/src/test/java/com/bruce/workflow/controller/WorkflowCompatControllerTests.java`
|
||||
- `common-agent-workflow/src/test/java/com/bruce/workflow/controller/WorkflowWorkspaceControllerTests.java`
|
||||
- `common-agent-workflow/src/test/java/com/bruce/workflow/workspace/WorkflowWorkspaceServiceTests.java`
|
||||
- `common-agent-workflow/src/test/java/com/bruce/workflow/version/WorkflowVersionServiceTests.java`
|
||||
@@ -183,6 +186,7 @@
|
||||
- 接口已覆盖:
|
||||
- `POST /api/mcp/import`
|
||||
- `GET /api/mcp/servers`
|
||||
- `POST /api/mcp/servers/query`
|
||||
- `GET /api/mcp/servers/{serverId}/capabilities`
|
||||
- `GET /api/mcp/servers/code/{serverCode}/capabilities`
|
||||
- `POST /api/mcp/capabilities/save`
|
||||
@@ -206,6 +210,7 @@
|
||||
- 工作台接口已覆盖:
|
||||
- `GET /api/skills/{skillCode}`
|
||||
- `POST /api/skills/{skillCode}/draft`
|
||||
- `PUT /api/skills/{skillCode}/draft`
|
||||
- `POST /api/skills/{skillCode}/test`
|
||||
- `POST /api/skills/{skillCode}/publish`
|
||||
- `POST /api/skills/{skillCode}/archive`
|
||||
@@ -262,10 +267,29 @@
|
||||
- `frontend/src/pages/studio/__tests__/*`
|
||||
- `frontend/src/api/__tests__/*`
|
||||
|
||||
## 4.1 文档草案路径兼容收口
|
||||
|
||||
为减少“文档草案路径”和“现有聚合接口路径”之间的偏差,当前已额外补齐以下兼容入口:
|
||||
|
||||
- Workflow:
|
||||
- `GET /api/workflows/{workflowId}`
|
||||
- `POST /api/workflows/save-draft`
|
||||
- `POST /api/workflow-versions/compat/workflows/{workflowId}/publish`
|
||||
- `POST /api/workflow-runs/compat/workflows/{workflowId}/runs`
|
||||
- `GET /api/workflow-runs/compat/workflows/runs/{runId}`
|
||||
- Agent:
|
||||
- `POST /api/agents/{agentId}/runs`
|
||||
- `GET /api/agent-sessions/agents/{agentId}/sessions`
|
||||
- `GET /api/agent-sessions/{sessionId}`
|
||||
- MCP:
|
||||
- `POST /api/mcp/servers/query`
|
||||
- Skill:
|
||||
- `PUT /api/skills/{skillCode}/draft`
|
||||
|
||||
## 5. 当前仍需持续关注的风险
|
||||
|
||||
- 当前多数“mapper / repository 验证”仍以结构契约测试为主,真实数据库集成测试覆盖度有限。
|
||||
- 部分前端实现文档中的接口命名是草案,当前实现更多采用“旧管理接口 + Studio 聚合接口”的双轨方式;职责已覆盖,但验收时需要按“能力是否已落地”而非“路径字面一致”判断。
|
||||
- 当前实现仍保留“旧管理接口 + Studio 聚合接口 + 文档草案兼容路径”的三轨并行方式,能力已覆盖,但后续如进入正式 API 收敛阶段,仍建议选定长期主路径并逐步淘汰别名。
|
||||
- 现有运行链路以“主数据优先 + 最小可运行”实现为主,复杂分支调度、远程 MCP 实时执行编排、重型运行器能力仍适合后续继续增强。
|
||||
|
||||
## 6. 本次审计后的新增变更
|
||||
@@ -273,3 +297,4 @@
|
||||
- 新增 `POST /api/knowledge/ingestion-runs`,补齐前端实现文档中的摄取运行创建入口。
|
||||
- 补充 `IngestionRunControllerTests` 与前端 `ingestion.spec.ts` 创建接口测试。
|
||||
- 补充 `WorkflowWorkspaceController` 中文注释与标准化业务日志。
|
||||
- 补充 Workflow / Agent / MCP / Skill 的文档草案兼容路径与控制器测试。
|
||||
|
||||
Reference in New Issue
Block a user