feat: 完善用户确认节点选项与输出流转
- 重构确认节点单选多选配置及输出参数契约 - 统一管理端、用户中心、匿名分享和公共接口恢复流程 - 增加保存校验、错误契约及交互测试
This commit is contained in:
@@ -18,10 +18,12 @@ import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
|
||||
import tech.easyflow.ai.entity.Plugin;
|
||||
import tech.easyflow.ai.entity.PluginItem;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.enums.PluginType;
|
||||
import tech.easyflow.ai.plugin.workflow.snapshot.WorkflowPluginSnapshotResolver;
|
||||
import tech.easyflow.ai.service.PluginService;
|
||||
@@ -29,6 +31,7 @@ import tech.easyflow.ai.service.PluginItemService;
|
||||
import tech.easyflow.ai.service.AgentResourceReferenceService;
|
||||
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
@@ -91,11 +94,15 @@ public class PluginItemController extends BaseCurdController<PluginItemService,
|
||||
@Resource
|
||||
private WorkflowService workflowService;
|
||||
@Resource
|
||||
private WorkflowExecResultService workflowExecResultService;
|
||||
@Resource
|
||||
private ChainExecutor chainExecutor;
|
||||
@Resource
|
||||
private TinyFlowService tinyFlowService;
|
||||
@Resource
|
||||
private WorkflowCheckService workflowCheckService;
|
||||
@Resource
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
|
||||
@PostMapping("/tool/save")
|
||||
@SaCheckPermission("/api/v1/plugin/save")
|
||||
@@ -215,6 +222,7 @@ public class PluginItemController extends BaseCurdController<PluginItemService,
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<ChainInfo> pluginToolTestChainStatus(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||
assertPluginTestExecutionOwnership(executeId);
|
||||
return Result.ok(tinyFlowService.getChainStatus(executeId, nodes));
|
||||
}
|
||||
|
||||
@@ -229,10 +237,33 @@ public class PluginItemController extends BaseCurdController<PluginItemService,
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<Void> pluginToolTestResume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||
assertPluginTestExecutionOwnership(executeId);
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验插件试运行实例由当前登录用户发起。
|
||||
*
|
||||
* @param executeId 执行实例 ID
|
||||
*/
|
||||
private void assertPluginTestExecutionOwnership(String executeId) {
|
||||
if (StrUtil.isBlank(executeId)) {
|
||||
throw new BusinessException("执行ID不能为空");
|
||||
}
|
||||
WorkflowExecResult record = workflowExecResultService.getByExecKey(executeId);
|
||||
if (record == null) {
|
||||
throw new BusinessException(404, 404, "工作流执行记录不存在或已过期");
|
||||
}
|
||||
LoginAccount currentAccount = SaTokenUtil.getLoginAccount();
|
||||
if (currentAccount == null
|
||||
|| currentAccount.getId() == null
|
||||
|| record.getCreatedBy() == null
|
||||
|| !currentAccount.getId().toString().equals(record.getCreatedBy())) {
|
||||
throw new BusinessException(403, 403, "无权限访问当前插件试运行实例");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleArray(JSONArray array) {
|
||||
for (Object o : array) {
|
||||
JSONObject obj = (JSONObject) o;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import com.easyagents.flow.core.chain.ChainStatus;
|
||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -14,6 +13,7 @@ import tech.easyflow.admin.service.ai.WorkflowChatEventStream;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
@@ -64,6 +64,8 @@ public class WorkflowChatController {
|
||||
@Resource
|
||||
private ChainExecutor chainExecutor;
|
||||
@Resource
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
@Resource
|
||||
private WorkflowExecResultService execResultService;
|
||||
@Resource
|
||||
private WorkflowExecStepService execStepService;
|
||||
@@ -171,19 +173,8 @@ public class WorkflowChatController {
|
||||
@JsonBody("confirmParams")
|
||||
Map<String, Object> confirmParams
|
||||
) {
|
||||
WorkflowExecResult record = assertExecutionOwnership(executeId);
|
||||
if (record.getStatus() != null
|
||||
&& (record.getStatus() == ChainStatus.SUCCEEDED.getValue()
|
||||
|| record.getStatus() == ChainStatus.FAILED.getValue()
|
||||
|| record.getStatus() == ChainStatus.CANCELLED.getValue())) {
|
||||
throw new BusinessException("当前工作流执行已结束");
|
||||
}
|
||||
chainExecutor.resumeAsync(
|
||||
executeId,
|
||||
confirmParams == null
|
||||
? new LinkedHashMap<>()
|
||||
: new LinkedHashMap<>(confirmParams)
|
||||
);
|
||||
assertExecutionOwnership(executeId);
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowDatacenterContentService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.enums.PublishStatus;
|
||||
import tech.easyflow.ai.publish.WorkflowPublishAppService;
|
||||
@@ -94,6 +95,8 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
@Resource
|
||||
private WorkflowRunningParameterResolver workflowRunningParameterResolver;
|
||||
@Resource
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
@Resource
|
||||
private ResourceAccessService resourceAccessService;
|
||||
@Resource
|
||||
private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
|
||||
@@ -324,12 +327,7 @@ public class WorkflowController extends BaseCurdController<WorkflowService, Work
|
||||
)
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
if (!chainExecutor.resumeAsyncIfSuspended(executeId, confirmParams)) {
|
||||
throw new BusinessException(
|
||||
409,
|
||||
40901,
|
||||
"当前执行状态不可恢复,仅暂停中的工作流允许恢复");
|
||||
}
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.entity.WorkflowExecStep;
|
||||
@@ -46,6 +47,7 @@ public class WorkflowPublicChatService {
|
||||
private final WorkflowPublicChatAccessGuard accessGuard;
|
||||
private final WorkflowChatEventStream eventStream;
|
||||
private final ChainExecutor chainExecutor;
|
||||
private final WorkflowResumeService workflowResumeService;
|
||||
private final WorkflowExecResultService execResultService;
|
||||
private final WorkflowExecStepService execStepService;
|
||||
|
||||
@@ -57,6 +59,7 @@ public class WorkflowPublicChatService {
|
||||
WorkflowPublicChatAccessGuard accessGuard,
|
||||
WorkflowChatEventStream eventStream,
|
||||
ChainExecutor chainExecutor,
|
||||
WorkflowResumeService workflowResumeService,
|
||||
WorkflowExecResultService execResultService,
|
||||
WorkflowExecStepService execStepService
|
||||
) {
|
||||
@@ -67,6 +70,7 @@ public class WorkflowPublicChatService {
|
||||
this.accessGuard = accessGuard;
|
||||
this.eventStream = eventStream;
|
||||
this.chainExecutor = chainExecutor;
|
||||
this.workflowResumeService = workflowResumeService;
|
||||
this.execResultService = execResultService;
|
||||
this.execStepService = execStepService;
|
||||
}
|
||||
@@ -185,17 +189,8 @@ public class WorkflowPublicChatService {
|
||||
) {
|
||||
WorkflowPublicChatContext context = contextResolver.resolveActive(
|
||||
shareKey, visitorId);
|
||||
WorkflowExecResult record = assertExecutionOwnership(
|
||||
context, executeId);
|
||||
if (isTerminal(record.getStatus())) {
|
||||
throw new BusinessException("当前工作流执行已结束");
|
||||
}
|
||||
chainExecutor.resumeAsync(
|
||||
executeId,
|
||||
confirmParams == null
|
||||
? new LinkedHashMap<>()
|
||||
: new LinkedHashMap<>(confirmParams)
|
||||
);
|
||||
assertExecutionOwnership(context, executeId);
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,13 +248,6 @@ public class WorkflowPublicChatService {
|
||||
return record;
|
||||
}
|
||||
|
||||
private boolean isTerminal(Integer status) {
|
||||
return status != null
|
||||
&& (status == ChainStatus.SUCCEEDED.getValue()
|
||||
|| status == ChainStatus.FAILED.getValue()
|
||||
|| status == ChainStatus.CANCELLED.getValue());
|
||||
}
|
||||
|
||||
private Map<String, Object> buildExecutionDetail(
|
||||
WorkflowExecResult record,
|
||||
List<WorkflowExecStep> steps,
|
||||
|
||||
@@ -7,21 +7,27 @@ import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
import tech.easyflow.ai.entity.Plugin;
|
||||
import tech.easyflow.ai.entity.PluginItem;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.service.AgentResourceReferenceService;
|
||||
import tech.easyflow.ai.service.PluginItemService;
|
||||
import tech.easyflow.ai.service.PluginService;
|
||||
import tech.easyflow.ai.service.PluginVisibilityService;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
@@ -68,6 +74,61 @@ public class PluginItemControllerTest {
|
||||
verify(visibilityService).assertPluginVisible(1L, BigInteger.TEN, "无权限删除该插件工具");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证当前用户不能恢复其他用户发起的插件试运行实例。
|
||||
*/
|
||||
@Test
|
||||
public void testResumeShouldRejectAnotherUsersExecution() {
|
||||
PluginItemService pluginItemService = mock(PluginItemService.class);
|
||||
WorkflowExecResultService execResultService = mock(WorkflowExecResultService.class);
|
||||
WorkflowResumeService resumeService = mock(WorkflowResumeService.class);
|
||||
WorkflowExecResult record = new WorkflowExecResult();
|
||||
record.setCreatedBy(BigInteger.ONE.toString());
|
||||
when(execResultService.getByExecKey("execution-1")).thenReturn(record);
|
||||
|
||||
PluginItemController controller = new PluginItemController(pluginItemService);
|
||||
setField(controller, "workflowExecResultService", execResultService);
|
||||
setField(controller, "workflowResumeService", resumeService);
|
||||
LoginAccount currentAccount = new LoginAccount();
|
||||
currentAccount.setId(BigInteger.TWO);
|
||||
|
||||
try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
|
||||
login.when(SaTokenUtil::getLoginAccount).thenReturn(currentAccount);
|
||||
BusinessException error = Assert.expectThrows(
|
||||
BusinessException.class,
|
||||
() -> controller.pluginToolTestResume("execution-1", Map.of())
|
||||
);
|
||||
Assert.assertEquals(error.getHttpStatus(), 403);
|
||||
Assert.assertEquals(error.getErrorCode(), 403);
|
||||
}
|
||||
verifyNoInteractions(resumeService);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证当前用户可以恢复自己发起的插件试运行实例。
|
||||
*/
|
||||
@Test
|
||||
public void testResumeShouldAllowExecutionOwner() {
|
||||
PluginItemService pluginItemService = mock(PluginItemService.class);
|
||||
WorkflowExecResultService execResultService = mock(WorkflowExecResultService.class);
|
||||
WorkflowResumeService resumeService = mock(WorkflowResumeService.class);
|
||||
WorkflowExecResult record = new WorkflowExecResult();
|
||||
record.setCreatedBy(BigInteger.ONE.toString());
|
||||
when(execResultService.getByExecKey("execution-1")).thenReturn(record);
|
||||
|
||||
PluginItemController controller = new PluginItemController(pluginItemService);
|
||||
setField(controller, "workflowExecResultService", execResultService);
|
||||
setField(controller, "workflowResumeService", resumeService);
|
||||
LoginAccount currentAccount = new LoginAccount();
|
||||
currentAccount.setId(BigInteger.ONE);
|
||||
|
||||
try (MockedStatic<SaTokenUtil> login = mockStatic(SaTokenUtil.class)) {
|
||||
login.when(SaTokenUtil::getLoginAccount).thenReturn(currentAccount);
|
||||
controller.pluginToolTestResume("execution-1", Map.of("choice", "A"));
|
||||
}
|
||||
verify(resumeService).resume("execution-1", Map.of("choice", "A"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建插件工具。
|
||||
*
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
@@ -162,6 +163,8 @@ public class WorkflowPublicChatServiceTest {
|
||||
WorkflowChatEventStream eventStream = mock(
|
||||
WorkflowChatEventStream.class);
|
||||
ChainExecutor chainExecutor = mock(ChainExecutor.class);
|
||||
WorkflowResumeService workflowResumeService =
|
||||
mock(WorkflowResumeService.class);
|
||||
WorkflowExecResultService execResultService = mock(
|
||||
WorkflowExecResultService.class);
|
||||
WorkflowExecStepService execStepService = mock(
|
||||
@@ -196,6 +199,7 @@ public class WorkflowPublicChatServiceTest {
|
||||
accessGuard,
|
||||
eventStream,
|
||||
chainExecutor,
|
||||
workflowResumeService,
|
||||
execResultService,
|
||||
execStepService
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.easyagentsflow.support.PublishedWorkflowDefinitionIds;
|
||||
import tech.easyflow.ai.easyagentsflow.upload.WorkflowApiPreparedUpload;
|
||||
import tech.easyflow.ai.easyagentsflow.upload.WorkflowApiUploadLifecycleService;
|
||||
@@ -70,6 +71,8 @@ public class PublicWorkflowController {
|
||||
@Resource
|
||||
private WorkflowRunningParameterResolver workflowRunningParameterResolver;
|
||||
@Resource
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
@Resource
|
||||
private WorkflowApiPermissionService workflowApiPermissionService;
|
||||
@Resource
|
||||
private WorkflowExecResultService workflowExecResultService;
|
||||
@@ -250,14 +253,7 @@ public class PublicWorkflowController {
|
||||
SysApiKey apiKey = workflowApiPermissionService.assertWorkflowApi(request.getHeader("ApiKey"), request.getRequestURI());
|
||||
WorkflowExecResult execResult = assertApiKeyExecutionOwnership(apiKey, executeId);
|
||||
assertWorkflowExecutionResumable(execResult);
|
||||
if (!chainExecutor.resumeAsyncIfSuspended(
|
||||
executeId,
|
||||
confirmParams)) {
|
||||
throw new BusinessException(
|
||||
409,
|
||||
40901,
|
||||
"当前执行状态不可恢复,仅暂停中的工作流允许恢复");
|
||||
}
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -394,6 +394,7 @@ public final class WorkflowRunAsyncErrorProfile
|
||||
*/
|
||||
private boolean isStableBusinessCode(int code) {
|
||||
return (code >= 40011 && code <= 40017)
|
||||
|| code == 40031
|
||||
|| (code >= 40101 && code <= 40103)
|
||||
|| (code >= 40301 && code <= 40302)
|
||||
|| (code >= 40401 && code <= 40402)
|
||||
@@ -412,7 +413,8 @@ public final class WorkflowRunAsyncErrorProfile
|
||||
* @return 对外 HTTP 状态
|
||||
*/
|
||||
private int normalizeHttpStatus(int code, int fallback) {
|
||||
if (code >= 40011 && code <= 40017) {
|
||||
if ((code >= 40011 && code <= 40017)
|
||||
|| code == 40031) {
|
||||
return 400;
|
||||
}
|
||||
if (code >= 40101 && code <= 40103) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.enums.PublishStatus;
|
||||
@@ -44,6 +45,7 @@ public class PublicWorkflowControllerBehaviorTest {
|
||||
|
||||
private PublicWorkflowController controller;
|
||||
private ChainExecutor chainExecutor;
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
private TinyFlowService tinyFlowService;
|
||||
private HttpServletRequest request;
|
||||
|
||||
@@ -54,6 +56,7 @@ public class PublicWorkflowControllerBehaviorTest {
|
||||
public void setUp() {
|
||||
controller = new PublicWorkflowController();
|
||||
chainExecutor = Mockito.mock(ChainExecutor.class);
|
||||
workflowResumeService = Mockito.mock(WorkflowResumeService.class);
|
||||
tinyFlowService = Mockito.mock(TinyFlowService.class);
|
||||
WorkflowApiPermissionService permissionService =
|
||||
Mockito.mock(WorkflowApiPermissionService.class);
|
||||
@@ -79,6 +82,10 @@ public class PublicWorkflowControllerBehaviorTest {
|
||||
controller,
|
||||
"chainExecutor",
|
||||
chainExecutor);
|
||||
ReflectionTestUtils.setField(
|
||||
controller,
|
||||
"workflowResumeService",
|
||||
workflowResumeService);
|
||||
ReflectionTestUtils.setField(
|
||||
controller,
|
||||
"tinyFlowService",
|
||||
@@ -108,10 +115,12 @@ public class PublicWorkflowControllerBehaviorTest {
|
||||
public void resumeShouldRejectNonSuspendedExecution() {
|
||||
when(request.getRequestURI()).thenReturn(
|
||||
"/public-api/workflow/resume");
|
||||
when(chainExecutor.resumeAsyncIfSuspended(
|
||||
EXECUTE_ID,
|
||||
Map.of("approved", true)))
|
||||
.thenReturn(false);
|
||||
Mockito.doThrow(new BusinessException(
|
||||
409,
|
||||
40901,
|
||||
"当前执行状态不可恢复,仅暂停中的工作流允许恢复"))
|
||||
.when(workflowResumeService)
|
||||
.resume(EXECUTE_ID, Map.of("approved", true));
|
||||
|
||||
try {
|
||||
controller.resume(
|
||||
@@ -124,7 +133,7 @@ public class PublicWorkflowControllerBehaviorTest {
|
||||
Assert.assertEquals(40901, exception.getErrorCode());
|
||||
}
|
||||
|
||||
verify(chainExecutor).resumeAsyncIfSuspended(
|
||||
verify(workflowResumeService).resume(
|
||||
EXECUTE_ID,
|
||||
Map.of("approved", true));
|
||||
}
|
||||
|
||||
@@ -167,6 +167,28 @@ public class WorkflowRunAsyncErrorProfileTest {
|
||||
resolution.modelAndView.getModel().get("message"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证确认节点恢复校验保留专用错误码,不回退为运行参数错误。
|
||||
*/
|
||||
@Test
|
||||
public void shouldKeepResumeValidationCode() {
|
||||
Resolution resolution = resolve(
|
||||
"/public-api/workflow/resume",
|
||||
MediaType.APPLICATION_JSON_VALUE,
|
||||
new BusinessException(
|
||||
400,
|
||||
40031,
|
||||
"确认参数[模板类型]包含未配置选项"));
|
||||
|
||||
Assert.assertEquals(400, resolution.response.getStatus());
|
||||
Assert.assertEquals(
|
||||
40031,
|
||||
resolution.modelAndView.getModel().get("errorCode"));
|
||||
Assert.assertEquals(
|
||||
"确认参数[模板类型]包含未配置选项",
|
||||
resolution.modelAndView.getModel().get("message"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证 API Key 无效和两层权限错误保持可区分。
|
||||
*/
|
||||
|
||||
@@ -13,6 +13,7 @@ import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowCheckService;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowRunningParameterResolver;
|
||||
import tech.easyflow.ai.easyagentsflow.service.WorkflowResumeService;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
@@ -54,6 +55,8 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
||||
@Resource
|
||||
private WorkflowRunningParameterResolver workflowRunningParameterResolver;
|
||||
@Resource
|
||||
private WorkflowResumeService workflowResumeService;
|
||||
@Resource
|
||||
private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
|
||||
|
||||
public UcWorkflowController(WorkflowService service) {
|
||||
@@ -163,12 +166,7 @@ public class UcWorkflowController extends BaseCurdController<WorkflowService, Wo
|
||||
)
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
if (!chainExecutor.resumeAsyncIfSuspended(executeId, confirmParams)) {
|
||||
throw new BusinessException(
|
||||
409,
|
||||
40901,
|
||||
"当前执行状态不可恢复,仅暂停中的工作流允许恢复");
|
||||
}
|
||||
workflowResumeService.resume(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user