diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/ApiRunModeConfigDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/ApiRunModeConfigDTO.java index 5dfcf4ea8a..0c68f2a9bb 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/ApiRunModeConfigDTO.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/ApiRunModeConfigDTO.java @@ -1,6 +1,7 @@ package io.metersphere.sdk.dto.api.task; import io.metersphere.sdk.constants.ApiExecuteRunMode; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serial; @@ -12,9 +13,10 @@ public class ApiRunModeConfigDTO implements Serializable { private static final long serialVersionUID = 1L; /** - * 运行模式 串行/并行 + * 运行模式 * {@link ApiExecuteRunMode} */ + @NotBlank private String runMode; /** diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java index 4a1fd6ebb8..530e635a81 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java @@ -1,6 +1,8 @@ package io.metersphere.sdk.dto.api.task; import io.metersphere.sdk.dto.api.result.MsRegexDTO; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import java.io.Serial; @@ -15,6 +17,7 @@ public class TaskRequestDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; + @NotBlank private String reportId; private String msUrl; private String kafkaConfig; @@ -32,22 +35,20 @@ public class TaskRequestDTO implements Serializable { /** * 执行的资源ID */ + @NotBlank private String resourceId; - /** * 触发方式 * 手动执行,批量执行,API执行,定时任务 * {@link io.metersphere.sdk.constants.TaskTriggerMode} */ private String triggerMode; - /** * 资源类型 * * @see io.metersphere.sdk.constants.ApiExecuteResourceType */ private String resourceType; - /** * 点击调试时,尚未保存的本地上传的文件列表 */ @@ -80,11 +81,13 @@ public class TaskRequestDTO implements Serializable { /** * 项目id */ + @NotBlank private String projectId; /** * 运行配置 */ + @Valid private ApiRunModeConfigDTO runModeConfig; /** diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/constants/ApiDefinitionStatus.java b/backend/services/api-test/src/main/java/io/metersphere/api/constants/ApiDefinitionStatus.java index 43f96bd8fd..af9f68ea9d 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/constants/ApiDefinitionStatus.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/constants/ApiDefinitionStatus.java @@ -1,5 +1,6 @@ package io.metersphere.api.constants; +import io.metersphere.sdk.constants.ValueEnum; import lombok.Getter; /** @@ -8,7 +9,7 @@ import lombok.Getter; * @version: 1.0 */ @Getter -public enum ApiDefinitionStatus { +public enum ApiDefinitionStatus implements ValueEnum { PREPARE("Prepare"), UNDERWAY("Underway"), DEBUGGING("Debugging"), diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java index 2adf17048a..3d14a0cd1c 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java @@ -7,6 +7,7 @@ import io.metersphere.jmeter.mock.Mock; import io.metersphere.plugin.api.dto.ApiPluginSelectOption; import io.metersphere.project.dto.customfunction.request.CustomFunctionRunRequest; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.system.dto.ProtocolDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -47,7 +48,7 @@ public class ApiTestController { @PostMapping("/custom/func/run") @Operation(summary = "项目管理-公共脚本-脚本测试") @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_EXECUTE) - public String run(@Validated @RequestBody CustomFunctionRunRequest runRequest) { + public TaskRequestDTO run(@Validated @RequestBody CustomFunctionRunRequest runRequest) { return apiExecuteService.runScript(runRequest); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionController.java index 777e48a616..c4910c2bee 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiDefinitionController.java @@ -14,6 +14,7 @@ import io.metersphere.api.service.definition.ApiDefinitionService; import io.metersphere.api.utils.JsonSchemaBuilder; import io.metersphere.project.service.FileModuleService; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.system.dto.OperationHistoryDTO; import io.metersphere.system.dto.request.OperationHistoryRequest; import io.metersphere.system.dto.request.OperationHistoryVersionRequest; @@ -274,4 +275,11 @@ public class ApiDefinitionController { public String preview(@RequestBody TextNode jsonSchema) { return JsonSchemaBuilder.preview(jsonSchema.asText()); } + + @PostMapping("/debug") + @Operation(summary = "接口调试") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_EXECUTE) + public TaskRequestDTO debug(@Validated @RequestBody ApiRunRequest request) { + return apiDefinitionService.debug(request); + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java index 90188783d2..c904903a0b 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/definition/ApiTestCaseController.java @@ -11,6 +11,7 @@ import io.metersphere.api.service.definition.ApiTestCaseRecoverService; import io.metersphere.api.service.definition.ApiTestCaseService; import io.metersphere.project.service.FileModuleService; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.system.dto.OperationHistoryDTO; import io.metersphere.system.dto.request.OperationHistoryRequest; import io.metersphere.system.dto.sdk.BaseTreeNode; @@ -243,5 +244,17 @@ public class ApiTestCaseController { return fileModuleService.getTree(projectId); } + @GetMapping("/run/{id}/{reportId}") + @Operation(summary = "用例执行,获取获取执行结果") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE) + public TaskRequestDTO run(@PathVariable String id, @PathVariable String reportId) { + return apiTestCaseService.run(id, reportId); + } + @PostMapping("/debug") + @Operation(summary = "用例调试") + @RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE) + public TaskRequestDTO debug(@Validated @RequestBody ApiRunRequest request) { + return apiTestCaseService.debug(request); + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java index 27113661f1..ef29bfe070 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/scenario/ApiScenarioController.java @@ -14,6 +14,7 @@ import io.metersphere.api.service.scenario.ApiScenarioNoticeService; import io.metersphere.api.service.scenario.ApiScenarioService; import io.metersphere.project.service.FileModuleService; import io.metersphere.sdk.constants.PermissionConstants; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.system.dto.OperationHistoryDTO; import io.metersphere.system.dto.request.OperationHistoryRequest; import io.metersphere.system.dto.sdk.BaseTreeNode; @@ -153,10 +154,17 @@ public class ApiScenarioController { @PostMapping("/debug") @Operation(summary = "接口测试-接口场景管理-场景调试") @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE) - public String debug(@Validated @RequestBody ApiScenarioDebugRequest request) { + public TaskRequestDTO debug(@Validated @RequestBody ApiScenarioDebugRequest request) { return apiScenarioService.debug(request); } + @GetMapping("/run/{id}/{reportId}") + @Operation(summary = "接口测试-接口场景管理-场景执行") + @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE) + public TaskRequestDTO run(@PathVariable String id, @PathVariable String reportId) { + return apiScenarioService.run(id, reportId); + } + @GetMapping(value = "/update-status/{id}/{status}") @Operation(summary = "接口测试-接口场景管理-更新状态") @RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_UPDATE) @@ -252,5 +260,4 @@ public class ApiScenarioController { public List options(@PathVariable String projectId) { return fileModuleService.getTree(projectId); } - } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseParam.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseTmpParam.java similarity index 63% rename from backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseParam.java rename to backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseTmpParam.java index fa42af8cbd..d4fd15daf7 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseParam.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/ApiScenarioParseTmpParam.java @@ -4,10 +4,7 @@ import io.metersphere.api.dto.request.MsCommonElement; import io.metersphere.api.dto.request.http.MsHTTPElement; import lombok.Data; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * 执行场景解析参数时的临时参数 @@ -16,7 +13,7 @@ import java.util.Map; * @CreateTime: 2024-02-22 11:27 */ @Data -public class ApiScenarioParseParam { +public class ApiScenarioParseTmpParam { /** * 步骤详情 Map * key 为步骤ID @@ -39,4 +36,18 @@ public class ApiScenarioParseParam { * 场景中所有的 MsCommonElement 列表 */ private List commonElements = new ArrayList<>(); + /** + * 执行的资源ID列表 + * 场景执行时,为关联的所有用例和场景列表 + */ + private Set refResourceIds = HashSet.newHashSet(0); + /** + * 执行的资源所属项目的ID列表 + * 场景执行时,为引用的资源的项目ID列表 + */ + private Set refProjectIds = HashSet.newHashSet(0); + /** + * 环境相关信息 + */ + private ApiScenarioParseEnvInfo scenarioParseEnvInfo; } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/debug/ApiResourceRunRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/debug/ApiResourceRunRequest.java index 135a065124..f0509e8087 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/debug/ApiResourceRunRequest.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/debug/ApiResourceRunRequest.java @@ -4,44 +4,16 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.util.HashSet; import java.util.List; +import java.util.Set; @Data public class ApiResourceRunRequest { - private String id; - /** - * 项目ID - */ - private String projectId; - /** - * 资源ID - */ - private String testId; - /** - * 测试报告ID - */ - private String reportId; - /** - * 是否为环境组 - */ - private Boolean grouped = false; - /** - * 环境或者环境组ID - */ - private String environmentId; - /** - * 资源类型 - * @see io.metersphere.api.constants.ApiResourceType - */ - private String resourceType; /** * 执行组件 */ private AbstractMsTestElement testElement; - /** - * 是否是本地执行 - */ - private Boolean frontendDebug = false; /** * 新上传的文件ID * 创建时先按ID创建目录,再把文件放入目录 @@ -53,4 +25,14 @@ public class ApiResourceRunRequest { */ @Schema(description = "关联文件ID") private List linkFileIds; + /** + * 执行的资源ID列表 + * 场景执行时,为关联的所有用例和场景列表 + */ + private Set refResourceIds = HashSet.newHashSet(0); + /** + * 执行的资源所属项目的ID列表 + * 场景执行时,为引用的资源的项目ID列表 + */ + private Set refProjectIds = HashSet.newHashSet(0); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionAddRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionAddRequest.java index 62ed2db60e..396f259b7a 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionAddRequest.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionAddRequest.java @@ -1,7 +1,9 @@ package io.metersphere.api.dto.definition; +import io.metersphere.api.constants.ApiDefinitionStatus; import io.metersphere.api.domain.ApiDefinitionCustomField; import io.metersphere.sdk.constants.ModuleConstants; +import io.metersphere.system.valid.EnumValue; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -50,6 +52,7 @@ public class ApiDefinitionAddRequest implements Serializable { @Schema(description = "接口状态/进行中/已完成", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{api_definition.status.not_blank}") @Size(min = 1, max = 50, message = "{api_definition.status.length_range}") + @EnumValue(enumClass = ApiDefinitionStatus.class) private String status; @Schema(description = "模块fk", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiRunRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiRunRequest.java new file mode 100644 index 0000000000..13169945f6 --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/definition/ApiRunRequest.java @@ -0,0 +1,12 @@ +package io.metersphere.api.dto.definition; + +import io.metersphere.api.dto.debug.ApiDebugRunRequest; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + + +@Data +public class ApiRunRequest extends ApiDebugRunRequest { + @Schema(description = "环境ID") + private String environmentId; +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioDebugRequest.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioDebugRequest.java index 9ce58ef80e..d3fef6f19d 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioDebugRequest.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioDebugRequest.java @@ -14,7 +14,7 @@ import java.util.Map; * @CreateTime: 2024-01-10 11:24 */ @Data -public class ApiScenarioDebugRequest { +public class ApiScenarioDebugRequest extends ApiScenarioParseParam { @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "{api_scenario.id.not_blank}") @Size(max = 50, message = "{api_scenario.id.length_range}") @@ -25,41 +25,27 @@ public class ApiScenarioDebugRequest { @Size(max = 50) private String reportId; - @Schema(description = "是否为环境组") - private Boolean grouped = false; - - @Schema(description = "环境或者环境组ID", requiredMode = Schema.RequiredMode.REQUIRED) - @NotBlank - @Size(max = 50, message = "{api_scenario.environment_id.length_range}") - private String environmentId; - - @Schema(description = "场景的通用配置") - private ScenarioConfig scenarioConfig; - @Valid @Schema(description = "步骤集合") private List steps; - /** - * 步骤详情 - * key 为步骤ID - * 值 为详情 - */ - @Schema(description = "步骤详情") - private Map stepDetails; - @Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank private String projectId; + /** * 新上传的文件ID * 创建时先按ID创建目录,再把文件放入目录 */ @Schema(description = "新上传的文件ID") private List uploadFileIds; + /** * 新关联的文件ID */ @Schema(description = "关联文件ID") private List linkFileIds; + + @Schema(description = "是否是本地执行") + private Boolean frontendDebug = false; } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioParseParam.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioParseParam.java new file mode 100644 index 0000000000..23c9db8efe --- /dev/null +++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/scenario/ApiScenarioParseParam.java @@ -0,0 +1,36 @@ +package io.metersphere.api.dto.scenario; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +/** + * @Author: jianxing + * @CreateTime: 2024-03-01 20:33 + */ +@Data +public class ApiScenarioParseParam { + @Schema(description = "是否为环境组") + private Boolean grouped = false; + + @Schema(description = "环境或者环境组ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank + @Size(max = 50, message = "{api_scenario.environment_id.length_range}") + private String environmentId; + + @Schema(description = "场景的通用配置") + private ScenarioConfig scenarioConfig; + + /** + * 步骤详情 + * key 为步骤ID + * 值 为详情 + */ + @Schema(description = "步骤详情") + private Map stepDetails; +} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsScenarioConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsScenarioConverter.java index f1bfd0e600..19d8e9a06e 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsScenarioConverter.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsScenarioConverter.java @@ -121,8 +121,7 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter scenarioPreProcessors = processorConfig.getProcessors(); - if (CollectionUtils.isEmpty(scenarioPreProcessors)) { + + if (processorConfig == null || CollectionUtils.isEmpty(processorConfig.getProcessors())) { return; } + List scenarioPreProcessors = processorConfig.getProcessors(); Function, MsProcessorConverter> getConverterFunc = isPre ? MsProcessorConverterFactory::getPreConverter : MsProcessorConverterFactory::getPostConverter; diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiExecuteService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiExecuteService.java index a0bd12ba0d..4d3ec77aca 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiExecuteService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiExecuteService.java @@ -4,10 +4,12 @@ import io.metersphere.api.config.JmeterProperties; import io.metersphere.api.config.KafkaConfig; import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.dto.ApiParamConfig; +import io.metersphere.api.dto.debug.ApiDebugRunRequest; import io.metersphere.api.dto.debug.ApiResourceRunRequest; import io.metersphere.api.dto.request.controller.MsCommentScriptElement; import io.metersphere.api.parser.TestElementParser; import io.metersphere.api.parser.TestElementParserFactory; +import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.project.domain.FileMetadata; @@ -93,6 +95,8 @@ public class ApiExecuteService { private ApiPluginService apiPluginService; @Resource private GlobalParamsService globalParamsService; + @Resource + private ApiCommonService apiCommonService; @PostConstruct private void init() { @@ -120,31 +124,53 @@ public class ApiExecuteService { return reportId + "_" + testId; } - public TaskRequestDTO debug(ApiResourceRunRequest request, ApiParamConfig parameterConfig) { - TaskRequestDTO taskRequest = new TaskRequestDTO(); - BeanUtils.copyBean(taskRequest, request); - taskRequest.setRealTime(true); - taskRequest.setSaveResult(false); - taskRequest.setResourceId(request.getTestId()); + public TaskRequestDTO execute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig parameterConfig) { + // 置minio kafka ms 等信息 setServerInfoParam(taskRequest); // 设置执行文件参数 - setTaskFileParam(request, taskRequest); + setTaskFileParam(runRequest, taskRequest); // 误报处理 - if (StringUtils.isNotBlank(request.getProjectId())) { - taskRequest.setMsRegexList(projectApplicationService.get(Collections.singletonList(request.getProjectId()))); + taskRequest.setMsRegexList(projectApplicationService.get(Collections.singletonList(taskRequest.getProjectId()))); + + if (!StringUtils.equals(taskRequest.getResourceType(), ApiExecuteResourceType.API_DEBUG.name())) { + // 设置全局参数,接口调试不使用全局参数 + parameterConfig.setGlobalParams(getGlobalParam(taskRequest.getProjectId())); } - parameterConfig.setGlobalParams(getGlobalParam(request)); + // 解析执行脚本 + String executeScript = parseExecuteScript(runRequest.getTestElement(), parameterConfig); - String executeScript = parseExecuteScript(request.getTestElement(), parameterConfig); + // 设置插件文件信息 + taskRequest.setPluginFiles(apiPluginService.getFileInfoByProjectId(taskRequest.getProjectId())); - return doDebug(request, taskRequest, executeScript); + // 将测试脚本缓存到 redis + String scriptRedisKey = getScriptRedisKey(taskRequest.getReportId(), taskRequest.getResourceId()); + stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript); + + if (StringUtils.equals(taskRequest.getRunModeConfig().getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name())) { + // 前端调试返回执行参数,由前端调用本地资源池执行 + return taskRequest; + } + + try { + return doExecute(taskRequest); + } catch (MSException e) { + LogUtils.error(e); + // 调用失败清理脚本 + stringRedisTemplate.delete(scriptRedisKey); + throw e; + } catch (Exception e) { + LogUtils.error(e); + // 调用失败清理脚本 + stringRedisTemplate.delete(scriptRedisKey); + throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage()); + } } - private GlobalParams getGlobalParam(ApiResourceRunRequest request) { - GlobalParamsDTO globalParamsDTO = globalParamsService.get(request.getProjectId()); + private GlobalParams getGlobalParam(String projectId) { + GlobalParamsDTO globalParamsDTO = globalParamsService.get(projectId); if (globalParamsDTO != null) { return globalParamsDTO.getGlobalParams(); } @@ -154,35 +180,11 @@ public class ApiExecuteService { /** * 发送执行任务 * - * @param taskRequest 执行参数 - * @param executeScript 执行脚本 + * @param taskRequest 执行参数 */ - private TaskRequestDTO doDebug(ApiResourceRunRequest request, - TaskRequestDTO taskRequest, - String executeScript) { - String reportId = request.getReportId(); - String testId = request.getTestId(); - String projectId = request.getProjectId(); - - // 设置插件文件信息 - taskRequest.setPluginFiles(apiPluginService.getFileInfoByProjectId(projectId)); - ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO(); - runModeConfig.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name()); - if (request.getFrontendDebug()) { - runModeConfig.setRunMode(ApiExecuteRunMode.FRONTEND_DEBUG.name()); - } - taskRequest.setRunModeConfig(runModeConfig); - - // 将测试脚本缓存到 redis - String scriptRedisKey = getScriptRedisKey(reportId, testId); - stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript); - - if (request.getFrontendDebug()) { - // 前端调试返回执行参数,由前端调用本地资源池执行 - return taskRequest; - } - - TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(projectId); + private TaskRequestDTO doExecute(TaskRequestDTO taskRequest) throws Exception { + // 获取资源池 + TestResourcePoolReturnDTO testResourcePoolDTO = getGetResourcePoolNodeDTO(taskRequest.getProjectId()); TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(testResourcePoolDTO); if (StringUtils.isNotBlank(testResourcePoolDTO.getServerUrl())) { // 如果资源池配置了当前站点,则使用资源池的 @@ -190,20 +192,20 @@ public class ApiExecuteService { } taskRequest.setPoolSize(testResourceNodeDTO.getConcurrentNumber()); - try { - String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort()); - LogUtils.info(String.format("开始发送请求【 %s 】到 %s 节点执行", testId, endpoint), reportId); + String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort()); + LogUtils.info("开始发送请求【 {}_{} 】到 {} 节点执行", taskRequest.getReportId(), taskRequest.getResourceId(), endpoint); + if (StringUtils.equalsAny(taskRequest.getRunModeConfig().getRunMode(), ApiExecuteRunMode.FRONTEND_DEBUG.name(), ApiExecuteRunMode.BACKEND_DEBUG.name())) { TaskRunnerClient.debugApi(endpoint, taskRequest); - // 清空mino和kafka配置信息,避免前端获取 - taskRequest.setMinioConfig(null); - taskRequest.setKafkaConfig(null); - return taskRequest; - } catch (Exception e) { - LogUtils.error(e); - // 调用失败清理脚本 - stringRedisTemplate.delete(scriptRedisKey); - throw new MSException(RESOURCE_POOL_EXECUTE_ERROR, e.getMessage()); + } else { + TaskRunnerClient.runApi(endpoint, taskRequest); } + + // 清空mino和kafka配置信息,避免前端获取 + taskRequest.setMinioConfig(null); + taskRequest.setKafkaConfig(null); + + return taskRequest; + } private TestResourceNodeDTO getProjectExecuteNode(TestResourcePoolReturnDTO resourcePoolDTO) { @@ -238,52 +240,121 @@ public class ApiExecuteService { * @param runRequest 执行参数 * @return 报告ID */ - public String runScript(CustomFunctionRunRequest runRequest) { + public TaskRequestDTO runScript(CustomFunctionRunRequest runRequest) { String reportId = runRequest.getReportId(); String testId = runRequest.getProjectId(); + // 生成执行脚本 MsCommentScriptElement msCommentScriptElement = BeanUtils.copyBean(new MsCommentScriptElement(), runRequest); msCommentScriptElement.setScriptLanguage(runRequest.getType()); - String executeScript = parseExecuteScript(msCommentScriptElement, new ApiParamConfig()); + + ApiResourceRunRequest apiRunRequest = new ApiResourceRunRequest(); + apiRunRequest.setTestElement(msCommentScriptElement); + // 设置执行参数 - TaskRequestDTO taskRequest = new TaskRequestDTO(); + TaskRequestDTO taskRequest = getTaskRequest(reportId, testId, runRequest.getProjectId()); setServerInfoParam(taskRequest); taskRequest.setRealTime(true); taskRequest.setSaveResult(false); - taskRequest.setReportId(reportId); - taskRequest.setResourceId(testId); - taskRequest.setResourceType(ApiExecuteResourceType.API_DEBUG.name()); - ApiResourceRunRequest apiRunRequest = new ApiResourceRunRequest(); - apiRunRequest.setTestId(testId); - apiRunRequest.setReportId(reportId); - apiRunRequest.setProjectId(runRequest.getProjectId()); - apiRunRequest.setFrontendDebug(false); - doDebug(apiRunRequest, taskRequest, executeScript); - return reportId; + taskRequest.setResourceType(ApiExecuteResourceType.API_DEBUG.name()); + ApiRunModeConfigDTO runModeConfig = new ApiRunModeConfigDTO(); + runModeConfig.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name()); + taskRequest.setRunModeConfig(runModeConfig); + + return execute(apiRunRequest, taskRequest, new ApiParamConfig()); } /** * 给 taskRequest 设置文件相关参数 * - * @param request 请求参数 + * @param runRequest 请求参数 * @param taskRequest 执行参数 */ - private void setTaskFileParam(ApiResourceRunRequest request, TaskRequestDTO taskRequest) { + private void setTaskFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) { + setTaskRefFileParam(runRequest, taskRequest); + setTaskTmpFileParam(runRequest, taskRequest); + setTaskFuncJarParam(runRequest, taskRequest); + } + + /** + * 处理脚本执行所需要的jar包 + * + * @param runRequest + * @param taskRequest + */ + private void setTaskFuncJarParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) { + Set projectIdsSet = runRequest.getRefProjectIds(); + projectIdsSet.add(taskRequest.getProjectId()); + List projectIds = projectIdsSet.stream().collect(Collectors.toList()); + + // 获取函数jar包 + List fileMetadataList = fileManagementService.findJarByProjectId(projectIds); + taskRequest.setFuncJars(getApiExecuteFileInfo(fileMetadataList)); + + // TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在 + // 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载 + if (CollectionUtils.isEmpty(taskRequest.getFuncJars())) { + ApiExecuteFileInfo tempFileInfo = new ApiExecuteFileInfo(); + tempFileInfo.setProjectId(taskRequest.getProjectId()); + taskRequest.setFuncJars(List.of(tempFileInfo)); + } + } + + /** + * 处理没有保存的临时文件 + * + * @param runRequest + * @param taskRequest + */ + private void setTaskTmpFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) { + // 没有保存的本地临时文件 + List uploadFileIds = runRequest.getUploadFileIds(); + if (CollectionUtils.isNotEmpty(uploadFileIds)) { + List localTempFiles = uploadFileIds.stream() + .map(tempFileId -> { + String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId); + return getApiExecuteFileInfo(tempFileId, fileName, taskRequest.getProjectId()); + }) + .collect(Collectors.toList()); + taskRequest.setLocalTempFiles(localTempFiles); + } + + List linkFileIds = runRequest.getLinkFileIds(); + // 没有保存的文件管理临时文件 + if (CollectionUtils.isNotEmpty(linkFileIds)) { + List fileMetadataList = fileMetadataService.getByFileIds(linkFileIds); + // 添加临时的文件管理的文件 + taskRequest.getRefFiles().addAll(getApiExecuteFileInfo(fileMetadataList)); + } + } + + /** + * 处理运行的资源所关联的文件信息 + * + * @param runRequest + * @param taskRequest + */ + private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) { + // 查询包括引用的资源所需的文件 + Set resourceIdsSet = runRequest.getRefResourceIds(); + resourceIdsSet.add(taskRequest.getResourceId()); + List resourceIds = resourceIdsSet.stream().collect(Collectors.toList()); + // 查询通过本地上传的文件 - List localFiles = apiFileResourceService.getByResourceId(request.getId()). + List localFiles = apiFileResourceService.getByResourceIds(resourceIds). stream() .map(file -> { ApiExecuteFileInfo apiExecuteFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getFileName(), file.getProjectId()); // 本地上传的文件需要 resourceId 查询对应的目录 - apiExecuteFileInfo.setResourceId(request.getId()); + apiExecuteFileInfo.setResourceId(file.getResourceId()); return apiExecuteFileInfo; }) .collect(Collectors.toList()); taskRequest.setLocalFiles(localFiles); // 查询关联的文件管理的文件 - List refFiles = fileAssociationService.getFiles(request.getId()). + List refFiles = fileAssociationService.getFiles(resourceIds). stream() .map(file -> { ApiExecuteFileInfo refFileInfo = getApiExecuteFileInfo(file.getFileId(), file.getOriginalName(), @@ -295,39 +366,7 @@ public class ApiExecuteService { } return refFileInfo; }).collect(Collectors.toList()); - - // 没有保存的本地临时文件 - List uploadFileIds = request.getUploadFileIds(); - if (CollectionUtils.isNotEmpty(uploadFileIds)) { - List localTempFiles = uploadFileIds.stream() - .map(tempFileId -> { - String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId); - return getApiExecuteFileInfo(tempFileId, fileName, request.getProjectId()); - }) - .collect(Collectors.toList()); - taskRequest.setLocalTempFiles(localTempFiles); - } - - List linkFileIds = request.getLinkFileIds(); - // 没有保存的文件管理临时文件 - if (CollectionUtils.isNotEmpty(linkFileIds)) { - List fileMetadataList = fileMetadataService.getByFileIds(linkFileIds); - // 添加临时的文件管理的文件 - refFiles.addAll(getApiExecuteFileInfo(fileMetadataList)); - } - taskRequest.setRefFiles(refFiles); - // 获取函数jar包 - List fileMetadataList = fileManagementService.findJarByProjectId(List.of(taskRequest.getProjectId())); - taskRequest.setFuncJars(getApiExecuteFileInfo(fileMetadataList)); - - // TODO 当前项目没有包分两种情况,1 之前存在被删除,2 一直不存在 - // 为了兼容1 这种情况需要初始化一条空的数据,由执行机去做卸载 - if (CollectionUtils.isEmpty(taskRequest.getFuncJars())) { - ApiExecuteFileInfo tempFileInfo = new ApiExecuteFileInfo(); - tempFileInfo.setProjectId(request.getProjectId()); - taskRequest.setFuncJars(List.of(tempFileInfo)); - } } private List getApiExecuteFileInfo(List fileMetadataList) { @@ -364,7 +403,7 @@ public class ApiExecuteService { * @param config 参数配置 * @return 执行脚本 */ - private static String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) { + private String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) { // 解析生成脚本 TestElementParser defaultParser = TestElementParserFactory.getDefaultParser(); return defaultParser.parse(msTestElement, config); @@ -442,4 +481,44 @@ public class ApiExecuteService { } } } + + /** + * 单接口执行 + * + * @param runRequest + * @return + */ + public TaskRequestDTO apiExecute(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest, ApiParamConfig apiParamConfig) { + // 设置使用脚本前后置的公共脚本信息 + apiCommonService.setEnableCommonScriptProcessorInfo(runRequest.getTestElement()); + return execute(runRequest, taskRequest, apiParamConfig); + } + + public ApiParamConfig getApiParamConfig(String reportId) { + ApiParamConfig paramConfig = new ApiParamConfig(); + paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); + paramConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap()); + paramConfig.setReportId(reportId); + return paramConfig; + } + + public TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId) { + TaskRequestDTO taskRequest = new TaskRequestDTO(); + taskRequest.setReportId(reportId); + taskRequest.setResourceId(resourceId); + taskRequest.setProjectId(projectId); + return taskRequest; + } + + public String getDebugRunModule(boolean isFrontendDebug) { + return isFrontendDebug ? ApiExecuteRunMode.FRONTEND_DEBUG.name() : ApiExecuteRunMode.BACKEND_DEBUG.name(); + } + + public ApiResourceRunRequest getApiResourceRunRequest(ApiDebugRunRequest request) { + ApiResourceRunRequest runRequest = new ApiResourceRunRequest(); + runRequest.setLinkFileIds(request.getLinkFileIds()); + runRequest.setUploadFileIds(request.getUploadFileIds()); + runRequest.setTestElement(ApiDataUtils.parseObject(JSON.toJSONString(request.getRequest()), AbstractMsTestElement.class)); + return runRequest; + } } \ No newline at end of file diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java index 15837688d5..25a55b9031 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/ApiFileResourceService.java @@ -233,6 +233,13 @@ public class ApiFileResourceService { return apiFileResourceMapper.selectByExample(example); } + public List getByResourceIds(List resourceIds) { + ApiFileResourceExample example = new ApiFileResourceExample(); + example.createCriteria() + .andResourceIdIn(resourceIds); + return apiFileResourceMapper.selectByExample(example); + } + /** * 上传临时文件 * system/temp/{fileId}/{fileName} diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/debug/ApiDebugService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/debug/ApiDebugService.java index 77fa589456..0df13d15c2 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/debug/ApiDebugService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/debug/ApiDebugService.java @@ -23,13 +23,13 @@ import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.FileMetadata; import io.metersphere.project.service.ProjectService; import io.metersphere.sdk.constants.DefaultRepositoryDir; +import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO; import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.FileAssociationSourceUtil; import io.metersphere.sdk.util.JSON; import io.metersphere.system.log.constants.OperationLogModule; -import io.metersphere.system.service.ApiPluginService; import io.metersphere.system.uid.IDGenerator; import io.metersphere.system.utils.ServiceUtils; import jakarta.annotation.Resource; @@ -61,8 +61,6 @@ public class ApiDebugService { @Resource private ApiExecuteService apiExecuteService; @Resource - private ApiPluginService apiPluginService; - @Resource private ApiDebugModuleMapper apiDebugModuleMapper; @Resource private ApiCommonService apiCommonService; @@ -207,24 +205,18 @@ public class ApiDebugService { } public TaskRequestDTO debug(ApiDebugRunRequest request) { - String id = request.getId(); - String reportId = request.getReportId(); + ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request); + ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId()); - ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request); - runRequest.setProjectId(request.getProjectId()); - runRequest.setTestId(id); - runRequest.setReportId(reportId); - runRequest.setResourceType(ApiResourceType.API_DEBUG.name()); - runRequest.setTestElement(ApiDataUtils.parseObject(JSON.toJSONString(request.getRequest()), AbstractMsTestElement.class)); + TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId()); + taskRequest.setSaveResult(false); + taskRequest.setRealTime(true); + taskRequest.setResourceType(ApiResourceType.API_DEBUG.name()); + ApiRunModeConfigDTO apiRunModeConfig = new ApiRunModeConfigDTO(); + apiRunModeConfig.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug())); + taskRequest.setRunModeConfig(apiRunModeConfig); - ApiParamConfig paramConfig = new ApiParamConfig(); - paramConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); - paramConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap()); - paramConfig.setReportId(reportId); - - // 设置使用脚本前后置的公共脚本信息 - apiCommonService.setEnableCommonScriptProcessorInfo(runRequest.getTestElement()); - return apiExecuteService.debug(runRequest, paramConfig); + return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig); } public void checkModuleExist(String moduleId) { diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java index 237914eeab..2229bc0157 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiDefinitionService.java @@ -5,9 +5,11 @@ import io.metersphere.api.constants.ApiResourceType; import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.domain.*; import io.metersphere.api.dto.ApiFile; +import io.metersphere.api.dto.ApiParamConfig; import io.metersphere.api.dto.ApiResourceModuleInfo; import io.metersphere.api.dto.converter.ApiDefinitionImport; import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest; +import io.metersphere.api.dto.debug.ApiResourceRunRequest; import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.request.ApiEditPosRequest; import io.metersphere.api.dto.request.ApiTransferRequest; @@ -16,18 +18,23 @@ import io.metersphere.api.mapper.*; import io.metersphere.api.parser.ImportParser; import io.metersphere.api.parser.ImportParserFactory; import io.metersphere.api.service.ApiCommonService; +import io.metersphere.api.service.ApiExecuteService; import io.metersphere.api.service.ApiFileResourceService; import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.FileMetadata; +import io.metersphere.project.dto.environment.EnvironmentInfoDTO; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; +import io.metersphere.project.service.EnvironmentService; import io.metersphere.project.service.ProjectService; import io.metersphere.sdk.constants.ApiReportStatus; import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.DefaultRepositoryDir; import io.metersphere.sdk.constants.ModuleConstants; import io.metersphere.sdk.domain.OperationLogBlob; +import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.mapper.OperationLogBlobMapper; import io.metersphere.sdk.util.*; @@ -85,6 +92,8 @@ public class ApiDefinitionService { @Resource private ApiDefinitionBlobMapper apiDefinitionBlobMapper; + @Resource + private EnvironmentService environmentService; @Resource private ApiCommonService apiCommonService; @@ -124,6 +133,8 @@ public class ApiDefinitionService { @Resource private OperationLogBlobMapper operationLogBlobMapper; + @Resource + private ApiExecuteService apiExecuteService; public List getApiDefinitionPage(ApiDefinitionPageRequest request, String userId) { CustomFieldUtils.setBaseQueryRequestCustomMultipleFields(request, userId); @@ -1122,4 +1133,21 @@ public class ApiDefinitionService { return apiFileResourceService.transfer(request, userId, ApiResourceType.API.name()); } + public TaskRequestDTO debug(ApiRunRequest request) { + ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request); + EnvironmentInfoDTO environmentInfoDTO = environmentService.get(request.getEnvironmentId()); + ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId()); + + TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(request.getReportId(), request.getId(), request.getProjectId()); + taskRequest.setSaveResult(false); + taskRequest.setRealTime(true); + taskRequest.setResourceType(ApiResourceType.API.name()); + ApiRunModeConfigDTO apiRunModeConfig = new ApiRunModeConfigDTO(); + apiRunModeConfig.setRunMode(apiExecuteService.getDebugRunModule(request.getFrontendDebug())); + taskRequest.setRunModeConfig(apiRunModeConfig); + + // 设置环境 + apiParamConfig.setEnvConfig(environmentInfoDTO); + return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig); + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java index b90151ce9d..0e4ee60695 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/definition/ApiTestCaseService.java @@ -3,13 +3,16 @@ package io.metersphere.api.service.definition; import io.metersphere.api.constants.ApiResourceType; import io.metersphere.api.domain.*; import io.metersphere.api.dto.ApiFile; +import io.metersphere.api.dto.ApiParamConfig; import io.metersphere.api.dto.ApiResourceModuleInfo; import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest; +import io.metersphere.api.dto.debug.ApiResourceRunRequest; import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.request.ApiTransferRequest; import io.metersphere.api.dto.request.http.MsHTTPElement; import io.metersphere.api.mapper.*; import io.metersphere.api.service.ApiCommonService; +import io.metersphere.api.service.ApiExecuteService; import io.metersphere.api.service.ApiFileResourceService; import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.plugin.api.spi.AbstractMsTestElement; @@ -17,10 +20,14 @@ import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.domain.FileMetadata; import io.metersphere.project.domain.Project; import io.metersphere.project.mapper.ProjectMapper; +import io.metersphere.project.service.EnvironmentService; +import io.metersphere.sdk.constants.ApiExecuteRunMode; import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.DefaultRepositoryDir; import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.EnvironmentExample; +import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.mapper.EnvironmentMapper; import io.metersphere.sdk.util.*; @@ -91,6 +98,10 @@ public class ApiTestCaseService { private ExtApiDefinitionMapper extApiDefinitionMapper; @Resource private ApiCommonService apiCommonService; + @Resource + private ApiExecuteService apiExecuteService; + @Resource + private EnvironmentService environmentService; private static final String CASE_TABLE = "api_test_case"; @@ -628,7 +639,50 @@ public class ApiTestCaseService { } } + public String transfer(ApiTransferRequest request, String userId) { return apiFileResourceService.transfer(request, userId, ApiResourceType.API_CASE.name()); } + + public TaskRequestDTO run(String id, String reportId) { + ApiTestCase apiTestCase = checkResourceExist(id); + ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(id); + + ApiResourceRunRequest runRequest = new ApiResourceRunRequest(); + runRequest.setTestElement(ApiDataUtils.parseObject(new String(apiTestCaseBlob.getRequest()), AbstractMsTestElement.class)); + + TaskRequestDTO taskRequest = getTaskRequest(reportId, apiTestCase.getId(), apiTestCase.getProjectId(), ApiExecuteRunMode.RUN.name()); + taskRequest.setSaveResult(true); + taskRequest.setRealTime(true); + + ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(reportId); + // 设置环境 + apiParamConfig.setEnvConfig(environmentService.get(apiTestCase.getEnvironmentId())); + + return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig); + } + + public TaskRequestDTO debug(ApiRunRequest request) { + ApiResourceRunRequest runRequest = apiExecuteService.getApiResourceRunRequest(request); + + TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(), + request.getProjectId(), apiExecuteService.getDebugRunModule(request.getFrontendDebug())); + taskRequest.setSaveResult(true); + taskRequest.setRealTime(true); + + ApiParamConfig apiParamConfig = apiExecuteService.getApiParamConfig(request.getReportId()); + // 设置环境 + apiParamConfig.setEnvConfig(environmentService.get(request.getEnvironmentId())); + + return apiExecuteService.apiExecute(runRequest, taskRequest, apiParamConfig); + } + + private TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) { + TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(reportId, resourceId, projectId); + taskRequest.setResourceType(ApiResourceType.API_CASE.name()); + ApiRunModeConfigDTO apiRunModeConfig = new ApiRunModeConfigDTO(); + apiRunModeConfig.setRunMode(runModule); + taskRequest.setRunModeConfig(apiRunModeConfig); + return taskRequest; + } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java index c38904f93e..5e389ff012 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/service/scenario/ApiScenarioService.java @@ -38,14 +38,13 @@ import io.metersphere.project.dto.environment.http.SelectModule; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ProjectMapper; import io.metersphere.project.service.*; -import io.metersphere.sdk.constants.ApplicationNumScope; -import io.metersphere.sdk.constants.DefaultRepositoryDir; -import io.metersphere.sdk.constants.ModuleConstants; -import io.metersphere.sdk.constants.ScheduleResourceType; +import io.metersphere.sdk.constants.*; import io.metersphere.sdk.domain.Environment; import io.metersphere.sdk.domain.EnvironmentExample; import io.metersphere.sdk.domain.EnvironmentGroup; import io.metersphere.sdk.domain.EnvironmentGroupExample; +import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO; +import io.metersphere.sdk.dto.api.task.TaskRequestDTO; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.file.FileCenter; import io.metersphere.sdk.file.FileCopyRequest; @@ -83,6 +82,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; +import org.jetbrains.annotations.NotNull; import org.mybatis.spring.SqlSessionUtils; import org.quartz.CronExpression; import org.quartz.CronScheduleBuilder; @@ -1038,69 +1038,129 @@ public class ApiScenarioService { } } - private void checkResourceExist(String id) { - ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name"); + private ApiScenario checkResourceExist(String id) { + return ServiceUtils.checkResourceExist(apiScenarioMapper.selectByPrimaryKey(id), "permission.system_api_scenario.name"); } public String uploadTempFile(MultipartFile file) { return apiFileResourceService.uploadTempFile(file); } - public String debug(ApiScenarioDebugRequest request) { + public TaskRequestDTO debug(ApiScenarioDebugRequest request) { ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId()); boolean hasSave = apiScenario != null; - List steps = request.getSteps(); - - // 记录引用的资源ID - Map> refResourceMap = new HashMap<>(); - buildRefResourceIdMap(steps, refResourceMap); - - ApiScenarioParseParam parseParam = new ApiScenarioParseParam(); - // 查询引用的资源详情 - parseParam.setResourceDetailMap(getResourceDetailMap(refResourceMap)); - // 查询复制的步骤详情 - parseParam.setStepDetailMap(getStepDetailMap(steps, request.getStepDetails())); - // 解析生成待执行的场景树 MsScenario msScenario = new MsScenario(); msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name()); msScenario.setScenarioConfig(getScenarioConfig(request, hasSave)); msScenario.setProjectId(request.getProjectId()); - // 获取场景环境相关配置 - ApiScenarioParseEnvInfo scenarioParseEnvInfo = getScenarioParseEnvInfo(refResourceMap, request.getEnvironmentId(), request.getGrouped()); - parseStep2MsElement(msScenario, steps, parseParam, scenarioParseEnvInfo); - // 设置 HttpElement 的模块信息 - setHttpElementModuleId(parseParam.getStepTypeHttpElementMap()); - // 设置使用脚本前后置的公共脚本信息 - apiCommonService.setEnableCommonScriptProcessorInfo(parseParam.getCommonElements()); + ApiScenarioParseTmpParam tmpParam = parse(msScenario, request.getSteps(), request); - ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request); - runRequest.setProjectId(request.getProjectId()); - runRequest.setTestId(request.getId()); - runRequest.setReportId(request.getReportId()); - runRequest.setResourceType(ApiResourceType.API_SCENARIO.name()); - runRequest.setUploadFileIds(request.getUploadFileIds()); - runRequest.setGrouped(request.getGrouped()); - runRequest.setEnvironmentId(request.getEnvironmentId()); + ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam); + runRequest.setRefResourceIds(tmpParam.getRefResourceIds()); + runRequest.setRefProjectIds(tmpParam.getRefProjectIds()); runRequest.setTestElement(msScenario); + TaskRequestDTO taskRequest = getTaskRequest(request.getReportId(), request.getId(), request.getProjectId(), + apiExecuteService.getDebugRunModule(request.getFrontendDebug())); + taskRequest.setSaveResult(false); + taskRequest.setRealTime(true); + + ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(request, tmpParam); + parseConfig.setReportId(request.getReportId()); + + return apiExecuteService.execute(runRequest, taskRequest, parseConfig); + } + + public TaskRequestDTO run(String id, String reportId) { + ApiScenarioDetail apiScenarioDetail = get(id); + + // 解析生成待执行的场景树 + MsScenario msScenario = new MsScenario(); + msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name()); + msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig()); + msScenario.setProjectId(apiScenarioDetail.getProjectId()); + + ApiScenarioParseParam parseParam = new ApiScenarioParseParam(); + parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig()); + parseParam.setStepDetails(Map.of()); + parseParam.setEnvironmentId(apiScenarioDetail.getEnvironmentId()); + parseParam.setGrouped(apiScenarioDetail.getGrouped()); + + ApiScenarioParseTmpParam tmpParam = parse(msScenario, apiScenarioDetail.getSteps(), parseParam); + + ApiResourceRunRequest runRequest = getApiResourceRunRequest(msScenario, tmpParam); + + TaskRequestDTO taskRequest = getTaskRequest(reportId, id, apiScenarioDetail.getProjectId(), ApiExecuteRunMode.RUN.name()); + taskRequest.setSaveResult(true); + taskRequest.setRealTime(true); + + ApiScenarioParamConfig parseConfig = getApiScenarioParamConfig(parseParam, tmpParam); + parseConfig.setReportId(reportId); + + return apiExecuteService.execute(runRequest, taskRequest, parseConfig); + } + + private ApiScenarioParamConfig getApiScenarioParamConfig(ApiScenarioParseParam request, ApiScenarioParseTmpParam tmpParam) { ApiScenarioParamConfig parseConfig = new ApiScenarioParamConfig(); parseConfig.setTestElementClassPluginIdMap(apiPluginService.getTestElementPluginMap()); parseConfig.setTestElementClassProtocalMap(apiPluginService.getTestElementProtocolMap()); parseConfig.setGrouped(request.getGrouped()); - parseConfig.setReportId(request.getReportId()); if (BooleanUtils.isTrue(request.getGrouped())) { // 设置环境组 map - parseConfig.setProjectEnvMap(getProjectEnvMap(scenarioParseEnvInfo, request.getEnvironmentId())); + parseConfig.setProjectEnvMap(getProjectEnvMap(tmpParam.getScenarioParseEnvInfo(), request.getEnvironmentId())); } else { // 设置环境 - parseConfig.setEnvConfig(scenarioParseEnvInfo.getEnvMap().get(request.getEnvironmentId())); + parseConfig.setEnvConfig(tmpParam.getScenarioParseEnvInfo().getEnvMap().get(request.getEnvironmentId())); } + return parseConfig; + } - apiExecuteService.debug(runRequest, parseConfig); - return request.getReportId(); + private ApiResourceRunRequest getApiResourceRunRequest(MsScenario msScenario, ApiScenarioParseTmpParam tmpParam) { + ApiResourceRunRequest runRequest = new ApiResourceRunRequest(); + runRequest.setRefResourceIds(tmpParam.getRefResourceIds()); + runRequest.setRefProjectIds(tmpParam.getRefProjectIds()); + runRequest.setTestElement(msScenario); + return runRequest; + } + + public ApiScenarioParseTmpParam parse(MsScenario msScenario, + List steps, + ApiScenarioParseParam parseParam) { + // 记录引用的资源ID + Map> refResourceMap = new HashMap<>(); + buildRefResourceIdMap(steps, refResourceMap); + + ApiScenarioParseTmpParam tmpParam = new ApiScenarioParseTmpParam(); + + // 查询引用的资源详情 + tmpParam.setResourceDetailMap(getResourceDetailMap(refResourceMap)); + + // 查询复制的步骤详情 + tmpParam.setStepDetailMap(getStepDetailMap(steps, parseParam.getStepDetails())); + + // 获取场景环境相关配置 + tmpParam.setScenarioParseEnvInfo(getScenarioParseEnvInfo(refResourceMap, parseParam.getEnvironmentId(), parseParam.getGrouped())); + parseStep2MsElement(msScenario, steps, tmpParam); + + // 设置 HttpElement 的模块信息 + setHttpElementModuleId(tmpParam.getStepTypeHttpElementMap()); + + // 设置使用脚本前后置的公共脚本信息 + apiCommonService.setEnableCommonScriptProcessorInfo(tmpParam.getCommonElements()); + + return tmpParam; + } + + private TaskRequestDTO getTaskRequest(String reportId, String resourceId, String projectId, String runModule) { + TaskRequestDTO taskRequest = apiExecuteService.getTaskRequest(reportId, resourceId, projectId); + taskRequest.setResourceType(ApiResourceType.API_SCENARIO.name()); + ApiRunModeConfigDTO apiRunModeConfig = new ApiRunModeConfigDTO(); + apiRunModeConfig.setRunMode(runModule); + taskRequest.setRunModeConfig(apiRunModeConfig); + return taskRequest; } /** @@ -1233,8 +1293,7 @@ public class ApiScenarioService { */ private void parseStep2MsElement(AbstractMsTestElement parentElement, List steps, - ApiScenarioParseParam parseParam, - ApiScenarioParseEnvInfo scenarioParseEnvInfo) { + ApiScenarioParseTmpParam parseParam) { if (CollectionUtils.isNotEmpty(steps)) { parentElement.setChildren(new LinkedList<>()); } @@ -1259,18 +1318,33 @@ public class ApiScenarioService { } msTestElement.setProjectId(step.getProjectId()); msTestElement.setResourceId(step.getResourceId()); - setMsScenarioParam(scenarioParseEnvInfo, step, msTestElement); + + // 记录引用的资源ID和项目ID,下载执行文件时需要使用 + parseParam.getRefProjectIds().add(step.getProjectId()); + parseParam.getRefResourceIds().add(step.getResourceId()); + + // 设置环境等,运行时场景参数 + setMsScenarioParam(parseParam.getScenarioParseEnvInfo(), step, msTestElement); + // 记录 msCommonElement Optional.ofNullable(apiCommonService.getMsCommonElement(msTestElement)) .ifPresent(msCommonElement -> parseParam.getCommonElements().add(msCommonElement)); + // 组装树结构 parentElement.getChildren().add(msTestElement); } if (CollectionUtils.isNotEmpty(step.getChildren())) { - parseStep2MsElement(msTestElement, step.getChildren(), parseParam, scenarioParseEnvInfo); + parseStep2MsElement(msTestElement, step.getChildren(), parseParam); } } } + /** + * 设置运行时场景参数 + * + * @param scenarioParseEnvInfo + * @param step + * @param msTestElement + */ private void setMsScenarioParam(ApiScenarioParseEnvInfo scenarioParseEnvInfo, ApiScenarioStepCommonDTO step, AbstractMsTestElement msTestElement) { @@ -1363,9 +1437,9 @@ public class ApiScenarioService { StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.PARTIAL_REF.name()); } - private Map getStepDetailMap(List steps, Map stepDetailsParam) { + private Map getStepDetailMap(List steps, Map stepDetailsParam) { List needBlobStepIds = new ArrayList<>(); - for (ApiScenarioStepRequest step : steps) { + for (ApiScenarioStepCommonDTO step : steps) { if (BooleanUtils.isFalse(step.getEnable())) { continue; } @@ -1474,8 +1548,7 @@ public class ApiScenarioService { } public ApiScenarioDetail get(String scenarioId) { - checkResourceExist(scenarioId); - ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(scenarioId); + ApiScenario apiScenario = checkResourceExist(scenarioId); ApiScenarioDetail apiScenarioDetail = BeanUtils.copyBean(new ApiScenarioDetail(), apiScenario); ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(scenarioId); if (apiScenarioBlob != null) { diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionControllerTests.java index 4acd2cd641..bcf2eb3afa 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiDefinitionControllerTests.java @@ -16,6 +16,7 @@ import io.metersphere.api.model.CheckLogModel; import io.metersphere.api.service.ApiCommonService; import io.metersphere.api.service.ApiFileResourceService; import io.metersphere.api.service.BaseFileManagementTestService; +import io.metersphere.api.service.definition.ApiTestCaseService; import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.project.dto.filemanagement.FileInfo; @@ -62,6 +63,7 @@ import org.springframework.util.MultiValueMap; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -75,30 +77,32 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. public class ApiDefinitionControllerTests extends BaseTest { private static final String BASE_PATH = "/api/definition/"; - private final static String ADD = BASE_PATH + "add"; - private final static String UPDATE = BASE_PATH + "update"; - private final static String BATCH_UPDATE = BASE_PATH + "batch-update"; - private final static String DELETE = BASE_PATH + "delete"; - private final static String BATCH_DELETE = BASE_PATH + "batch-del"; - private final static String COPY = BASE_PATH + "copy"; - private final static String BATCH_MOVE = BASE_PATH + "batch-move"; + private final static String ADD = "add"; + private final static String UPDATE = "update"; + private final static String BATCH_UPDATE = "batch-update"; + private final static String DELETE = "delete"; + private final static String BATCH_DELETE = "batch-del"; + private final static String COPY = "copy"; + private final static String BATCH_MOVE = "batch-move"; - private final static String RESTORE = BASE_PATH + "recover"; - private final static String BATCH_RESTORE = BASE_PATH + "batch-recover"; + private final static String RESTORE = "recover"; + private final static String BATCH_RESTORE = "batch-recover"; - private final static String TRASH_DEL = BASE_PATH + "trash-del"; - private final static String BATCH_TRASH_DEL = BASE_PATH + "batch-trash-del"; + private final static String TRASH_DEL = "trash-del"; + private final static String BATCH_TRASH_DEL = "batch-trash-del"; - private final static String PAGE = BASE_PATH + "page"; - private final static String PAGE_DOC = BASE_PATH + "page-doc"; - private final static String DOC = BASE_PATH + "doc"; - private static final String GET = BASE_PATH + "get-detail/"; - private static final String FOLLOW = BASE_PATH + "follow/"; - private static final String VERSION = BASE_PATH + "version/"; - private static final String OPERATION_HISTORY = BASE_PATH + "operation-history"; - private static final String OPERATION_HISTORY_RECOVER = BASE_PATH + "operation-history/recover"; - private static final String OPERATION_HISTORY_SAVE = BASE_PATH + "operation-history/save"; - private static final String UPLOAD_TEMP_FILE = BASE_PATH + "/upload/temp/file"; + private final static String PAGE = "page"; + private final static String PAGE_DOC = "page-doc"; + private final static String DOC = "doc"; + private static final String GET = "get-detail/"; + private static final String FOLLOW = "follow/"; + private static final String VERSION = "version/"; + private static final String OPERATION_HISTORY = "operation-history"; + private static final String OPERATION_HISTORY_RECOVER = "operation-history/recover"; + private static final String OPERATION_HISTORY_SAVE = "operation-history/save"; + private static final String UPLOAD_TEMP_FILE = "upload/temp/file"; + private static final String DEBUG = "debug"; + private static final String IMPORT = "import"; private static final String DEFAULT_MODULE_ID = "10001"; @@ -144,12 +148,19 @@ public class ApiDefinitionControllerTests extends BaseTest { private ApiCommonService apiCommonService; @Resource private ApiFileResourceMapper apiFileResourceMapper; + @Resource + private ApiTestCaseService apiTestCaseService; private static String fileMetadataId; private static String uploadFileId; private static final List checkLogModelList = new ArrayList<>(); + @Override + public String getBasePath() { + return BASE_PATH; + } + @Test @Order(0) public void uploadTempFile() throws Exception { @@ -210,7 +221,7 @@ public class ApiDefinitionControllerTests extends BaseTest { assertUploadFile(apiDefinition.getId(), List.of(uploadFileId)); assertLinkFile(apiDefinition.getId()); - this.requestGetWithOk("/api/definition/transfer/options/" + "/" + DEFAULT_PROJECT_ID); + this.requestGetWithOk("transfer/options/" + DEFAULT_PROJECT_ID); ApiTransferRequest apiTransferRequest = new ApiTransferRequest(); apiTransferRequest.setSourceId(apiDefinition.getId()); apiTransferRequest.setProjectId(DEFAULT_PROJECT_ID); @@ -219,10 +230,10 @@ public class ApiDefinitionControllerTests extends BaseTest { String uploadFileId = doUploadTempFile(getMockMultipartFile("api-file_upload.JPG")); apiTransferRequest.setFileId(uploadFileId); apiTransferRequest.setFileName("api-file_upload.JPG"); - this.requestPost("/api/definition/transfer", apiTransferRequest).andExpect(status().isOk()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk()); //文件不存在 apiTransferRequest.setFileId("111"); - this.requestPost("/api/definition/transfer", apiTransferRequest).andExpect(status().is5xxServerError()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().is5xxServerError()); //文件已经上传 ApiFileResourceExample apiFileResourceExample = new ApiFileResourceExample(); apiFileResourceExample.createCriteria().andResourceIdEqualTo(apiDefinition.getId()); @@ -230,7 +241,7 @@ public class ApiDefinitionControllerTests extends BaseTest { Assertions.assertFalse(apiFileResources.isEmpty()); apiTransferRequest.setFileId(apiFileResources.get(0).getFileId()); apiTransferRequest.setFileName("test-file_upload.JPG"); - this.requestPost("/api/definition/transfer", apiTransferRequest).andExpect(status().isOk()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk()); // 再插入一条数据,便于修改时重名校验 request.setMethod("GET"); @@ -525,7 +536,7 @@ public class ApiDefinitionControllerTests extends BaseTest { testCaseAddRequest.setStatus(ApiDefinitionStatus.PREPARE.getValue()); testCaseAddRequest.setTags(new LinkedHashSet<>(List.of("tag1", "tag2"))); testCaseAddRequest.setRequest(getMsElementParam(msHttpElement)); - this.requestPostWithOkAndReturn("/api/case/add", testCaseAddRequest); + apiTestCaseService.addCase(testCaseAddRequest, "admin"); } updateRequest.setPath("/api/test/path/method/case"); this.requestPostWithOk(UPDATE, updateRequest); @@ -552,6 +563,26 @@ public class ApiDefinitionControllerTests extends BaseTest { requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_UPDATE, UPDATE, request); } + @Test + @Order(4) + public void debug() throws Exception { + ApiRunRequest request = new ApiRunRequest(); + request.setId(apiDefinition.getId()); + MsHTTPElement msHTTPElement = new MsHTTPElement(); + msHTTPElement.setPath("/test"); + msHTTPElement.setMethod("GET"); + request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement))); + request.setReportId(IDGenerator.nextStr()); + request.setProjectId(DEFAULT_PROJECT_ID); + MvcResult mvcResult = this.requestPostAndReturn(DEBUG, request); + ResultHolder resultHolder = JSON.parseObject(mvcResult.getResponse().getContentAsString(Charset.defaultCharset()), ResultHolder.class); + Assertions.assertTrue(resultHolder.getCode() == ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR.getCode() || + resultHolder.getCode() == MsHttpResultCode.SUCCESS.getCode()); + + // @@校验权限 + requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_EXECUTE, DEBUG, request); + } + private List updateCustomFields() { List list = new ArrayList<>(); ApiDefinitionCustomField customField = new ApiDefinitionCustomField(); @@ -1129,14 +1160,14 @@ public class ApiDefinitionControllerTests extends BaseTest { request.setMoveId(apiDefinition.getId()); request.setModuleId("root"); request.setMoveMode("AFTER"); - this.requestPostWithOkAndReturn(BASE_PATH + "edit/pos", request); + this.requestPostWithOkAndReturn("edit/pos", request); request.setMoveId(apiDefinition1.getId()); - this.requestPostWithOkAndReturn(BASE_PATH + "edit/pos", request); + this.requestPostWithOkAndReturn("edit/pos", request); request.setMoveMode("BEFORE"); - this.requestPostWithOkAndReturn(BASE_PATH + "edit/pos", request); + this.requestPostWithOkAndReturn("edit/pos", request); request.setModuleId("module-st-6"); - requestPost(BASE_PATH + "edit/pos", request).andExpect(status().is5xxServerError()); + requestPost("edit/pos", request).andExpect(status().is5xxServerError()); } @@ -1468,7 +1499,7 @@ public class ApiDefinitionControllerTests extends BaseTest { if (StringUtils.isEmpty(checkLogModel.getUrl())) { this.checkLog(checkLogModel.getResourceId(), checkLogModel.getOperationType()); } else { - this.checkLog(checkLogModel.getResourceId(), checkLogModel.getOperationType(), checkLogModel.getUrl()); + this.checkLog(checkLogModel.getResourceId(), checkLogModel.getOperationType(), BASE_PATH + checkLogModel.getUrl()); } } } @@ -1503,10 +1534,10 @@ public class ApiDefinitionControllerTests extends BaseTest { MockMultipartFile file = new MockMultipartFile("file", "openapi.json", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream); paramMap.add("file", file); - this.requestMultipartWithOkAndReturn("/api/definition/import", paramMap); + this.requestMultipartWithOkAndReturn(IMPORT, paramMap); request.setCoverModule(false); request.setCoverData(false); - this.requestMultipartWithOkAndReturn("/api/definition/import", paramMap); + this.requestMultipartWithOkAndReturn(IMPORT, paramMap); paramMap.clear(); inputStream = new FileInputStream(new File( this.getClass().getClassLoader().getResource("file/openapi1.json") @@ -1516,7 +1547,7 @@ public class ApiDefinitionControllerTests extends BaseTest { request.setCoverModule(true); request.setCoverData(true); paramMap.add("request", JSON.toJSONString(request)); - this.requestMultipartWithOkAndReturn("/api/definition/import", paramMap); + this.requestMultipartWithOkAndReturn(IMPORT, paramMap); paramMap.clear(); inputStream = new FileInputStream(new File( this.getClass().getClassLoader().getResource("file/openapi2.json") @@ -1526,7 +1557,7 @@ public class ApiDefinitionControllerTests extends BaseTest { request.setCoverModule(false); request.setCoverData(false); paramMap.add("request", JSON.toJSONString(request)); - this.requestMultipart("/api/definition/import", paramMap, status().is5xxServerError()); + this.requestMultipart(IMPORT, paramMap, status().is5xxServerError()); paramMap.clear(); inputStream = new FileInputStream(new File( @@ -1537,7 +1568,7 @@ public class ApiDefinitionControllerTests extends BaseTest { request.setCoverModule(false); request.setCoverData(false); paramMap.add("request", JSON.toJSONString(request)); - this.requestMultipartWithOkAndReturn("/api/definition/import", paramMap); + this.requestMultipartWithOkAndReturn(IMPORT, paramMap); paramMap.clear(); paramMap.add("file", file); @@ -1545,7 +1576,7 @@ public class ApiDefinitionControllerTests extends BaseTest { request.setCoverData(false); request.setSwaggerUrl("http://localhost:8080/v2/api-docs"); paramMap.add("request", JSON.toJSONString(request)); - this.requestMultipart("/api/definition/import", paramMap, status().is5xxServerError()); + this.requestMultipart(IMPORT, paramMap, status().is5xxServerError()); } @@ -2017,7 +2048,7 @@ public class ApiDefinitionControllerTests extends BaseTest { } """; //正常数据; - requestPost("/api/definition/preview", jsonString).andExpect(status().isOk()); + requestPost("preview", jsonString).andExpect(status().isOk()); //非正常json数据 会走try catch String abnormalString = """ { @@ -2037,7 +2068,7 @@ public class ApiDefinitionControllerTests extends BaseTest { "testfalse" : false } """; - requestPost("/api/definition/preview", abnormalString).andExpect(status().isOk()); + requestPost("preview", abnormalString).andExpect(status().isOk()); //正常array数据 String jsonArray = """ { @@ -2129,7 +2160,7 @@ public class ApiDefinitionControllerTests extends BaseTest { "extensions": null } """; - requestPost("/api/definition/preview", jsonArray).andExpect(status().isOk()); + requestPost("preview", jsonArray).andExpect(status().isOk()); } } diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiScenarioControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiScenarioControllerTests.java index fb069f220e..d5a4aaf8b9 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiScenarioControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiScenarioControllerTests.java @@ -113,6 +113,7 @@ public class ApiScenarioControllerTests extends BaseTest { protected static final String DELETE_TO_GC = "delete-to-gc/{0}"; protected static final String STEP_GET = "step/get"; protected static final String DEBUG = "debug"; + protected static final String RUN = "run/{0}/{1}"; private static final String UPDATE_STATUS = "update-status"; private static final String UPDATE_PRIORITY = "update-priority"; @@ -996,6 +997,15 @@ public class ApiScenarioControllerTests extends BaseTest { return msLoopController; } + @Order(6) + public void run() throws Exception { + mockPost("/api/run", ""); + this.requestGetWithOk(RUN, addApiScenario.getId(), "11111"); + + // @@校验权限 + requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, RUN, addApiScenario.getId(), "11111"); + } + public Plugin addEnvTestPlugin() throws Exception { PluginUpdateRequest request = new PluginUpdateRequest(); File jarFile = new File( diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java index 5be71317e7..7030b2d083 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/ApiTestCaseControllerTests.java @@ -2,6 +2,7 @@ package io.metersphere.api.controller; import io.metersphere.api.constants.ApiConstants; import io.metersphere.api.controller.param.ApiTestCaseAddRequestDefinition; +import io.metersphere.api.controller.result.ApiResultCode; import io.metersphere.api.domain.*; import io.metersphere.api.dto.ApiFile; import io.metersphere.api.dto.definition.*; @@ -30,6 +31,7 @@ import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.JSON; import io.metersphere.system.base.BaseTest; import io.metersphere.system.controller.handler.ResultHolder; +import io.metersphere.system.controller.handler.result.MsHttpResultCode; import io.metersphere.system.dto.OperationHistoryDTO; import io.metersphere.system.dto.request.OperationHistoryRequest; import io.metersphere.system.dto.sdk.request.PosRequest; @@ -56,40 +58,42 @@ import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class ApiTestCaseControllerTests extends BaseTest { private static final String BASE_PATH = "/api/case/"; - private static final String ADD = BASE_PATH + "add"; - private static final String GET = BASE_PATH + "get-detail/"; - private static final String MOVE_TO_GC = BASE_PATH + "move-gc/"; - private static final String RECOVER = BASE_PATH + "recover/"; - private static final String FOLLOW = BASE_PATH + "follow/"; - private static final String UNFOLLOW = BASE_PATH + "unfollow/"; - private static final String DELETE = BASE_PATH + "delete/"; - private static final String UPDATE = BASE_PATH + "update"; - private static final String PAGE = BASE_PATH + "page"; - private static final String TRASH_PAGE = BASE_PATH + "trash/page"; - private static final String UPDATE_STATUS = BASE_PATH + "update-status"; - private static final String UPDATE_PRIORITY = BASE_PATH + "update-priority"; - private static final String BATCH_EDIT = BASE_PATH + "batch/edit"; - private static final String BATCH_DELETE = BASE_PATH + "batch/delete"; - private static final String BATCH_MOVE_GC = BASE_PATH + "batch/move-gc"; - private static final String BATCH_RECOVER = BASE_PATH + "batch/recover"; - private static final String POS_URL = BASE_PATH + "/edit/pos"; - private static final String UPLOAD_TEMP_FILE = BASE_PATH + "/upload/temp/file"; - private static final String EXECUTE = BASE_PATH + "/execute/page"; - private static final String HISTORY = BASE_PATH + "/operation-history/page"; + private static final String ADD = "add"; + private static final String GET = "get-detail/"; + private static final String MOVE_TO_GC = "move-gc/"; + private static final String RECOVER = "recover/"; + private static final String FOLLOW = "follow/"; + private static final String UNFOLLOW = "unfollow/"; + private static final String DELETE = "delete/"; + private static final String UPDATE = "update"; + private static final String PAGE = "page"; + private static final String TRASH_PAGE = "trash/page"; + private static final String UPDATE_STATUS = "update-status"; + private static final String UPDATE_PRIORITY = "update-priority"; + private static final String BATCH_EDIT = "batch/edit"; + private static final String BATCH_DELETE = "batch/delete"; + private static final String BATCH_MOVE_GC = "batch/move-gc"; + private static final String BATCH_RECOVER = "batch/recover"; + private static final String POS_URL = "edit/pos"; + private static final String UPLOAD_TEMP_FILE = "upload/temp/file"; + private static final String EXECUTE = "execute/page"; + private static final String HISTORY = "operation-history/page"; + private static final String DEBUG = "debug"; + private static final String RUN = "run/{0}/{1}"; private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError(); private static ApiTestCase apiTestCase; @@ -126,6 +130,11 @@ public class ApiTestCaseControllerTests extends BaseTest { @Resource private ApiFileResourceMapper apiFileResourceMapper; + @Override + public String getBasePath() { + return BASE_PATH; + } + public static T parseObjectFromMvcResult(MvcResult mvcResult, Class parseClass) { try { String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); @@ -138,16 +147,6 @@ public class ApiTestCaseControllerTests extends BaseTest { return null; } - private MvcResult responsePost(String url, Object param) throws Exception { - return mockMvc.perform(MockMvcRequestBuilders.post(url) - .header(SessionConstants.HEADER_TOKEN, sessionId) - .header(SessionConstants.CSRF_TOKEN, csrfToken) - .content(JSON.toJSONString(param)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn(); - } - public void initApiData() { ApiDefinition apiDefinition = new ApiDefinition(); apiDefinition.setId("apiDefinitionId"); @@ -396,6 +395,34 @@ public class ApiTestCaseControllerTests extends BaseTest { return JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement)); } + @Test + @Order(3) + public void debug() throws Exception { + ApiRunRequest request = new ApiRunRequest(); + request.setId(apiTestCase.getId()); + MsHTTPElement msHTTPElement = new MsHTTPElement(); + msHTTPElement.setPath("/test"); + msHTTPElement.setMethod("GET"); + request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement))); + request.setReportId(IDGenerator.nextStr()); + request.setProjectId(DEFAULT_PROJECT_ID); + MvcResult mvcResult = this.requestPostAndReturn(DEBUG, request); + ResultHolder resultHolder = JSON.parseObject(mvcResult.getResponse().getContentAsString(Charset.defaultCharset()), ResultHolder.class); + Assertions.assertTrue(resultHolder.getCode() == ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR.getCode() || + resultHolder.getCode() == MsHttpResultCode.SUCCESS.getCode()); + + // @@校验权限 + requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE, DEBUG, request); + } + + @Test + @Order(3) + public void run() throws Exception { + assertErrorCode(this.requestGet(RUN, apiTestCase.getId(), "111"), ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR); + + // @@校验权限 + requestGetPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_EXECUTE, RUN, apiTestCase.getId(), "11111"); + } @Test @Order(3) @@ -453,7 +480,7 @@ public class ApiTestCaseControllerTests extends BaseTest { @Order(5) public void recover() throws Exception { // @@请求成功 - MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(RECOVER + apiTestCase.getId()); + MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get(BASE_PATH + RECOVER + apiTestCase.getId()); requestBuilder .header(SessionConstants.HEADER_TOKEN, sessionId) .header(SessionConstants.CSRF_TOKEN, csrfToken) @@ -528,7 +555,7 @@ public class ApiTestCaseControllerTests extends BaseTest { assertLinkFile(apiTestCase.getId(), List.of()); // 校验请求成功数据 request.setTags(new ArrayList<>()); - MvcResult mvcResult = this.responsePost(UPDATE, request); + MvcResult mvcResult = this.requestPostWithOkAndReturn(UPDATE, request); ApiTestCase resultData = getResultData(mvcResult, ApiTestCase.class); assertUpdateApiDebug(request, msHttpElement, resultData.getId()); @@ -583,7 +610,7 @@ public class ApiTestCaseControllerTests extends BaseTest { @Test @Order(9) public void testTransfer() throws Exception { - this.requestGetWithOk("/api/case/transfer/options/" + "/" + DEFAULT_PROJECT_ID); + this.requestGetWithOk("transfer/options/" + DEFAULT_PROJECT_ID); ApiTransferRequest apiTransferRequest = new ApiTransferRequest(); apiTransferRequest.setSourceId(apiTestCase.getId()); apiTransferRequest.setProjectId(DEFAULT_PROJECT_ID); @@ -592,10 +619,10 @@ public class ApiTestCaseControllerTests extends BaseTest { String uploadFileId = doUploadTempFile(getMockMultipartFile()); apiTransferRequest.setFileId(uploadFileId); apiTransferRequest.setFileName("test-api-test-case.txt"); - this.requestPost("/api/case/transfer", apiTransferRequest).andExpect(status().isOk()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk()); //文件不存在 apiTransferRequest.setFileId("111"); - this.requestPost("/api/case/transfer", apiTransferRequest).andExpect(status().is5xxServerError()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().is5xxServerError()); //文件已经上传 ApiFileResourceExample apiFileResourceExample = new ApiFileResourceExample(); apiFileResourceExample.createCriteria().andResourceIdEqualTo(apiTestCase.getId()); @@ -603,7 +630,7 @@ public class ApiTestCaseControllerTests extends BaseTest { Assertions.assertFalse(apiFileResources.isEmpty()); apiTransferRequest.setFileId(apiFileResources.get(0).getFileId()); apiTransferRequest.setFileName("test-api-test-case-1.txt"); - this.requestPost("/api/case/transfer", apiTransferRequest).andExpect(status().isOk()); + this.requestPost("transfer", apiTransferRequest).andExpect(status().isOk()); } @@ -658,14 +685,14 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setId(first.getId()); request.setPageSize(10); request.setCurrent(1); - MvcResult mvcResult = responsePost(EXECUTE, request); + MvcResult mvcResult = requestPostWithOkAndReturn(EXECUTE, request); Pager returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); request.setFilter(new HashMap<>() {{ put("status", List.of(ApiReportStatus.SUCCESS.name())); }}); - mvcResult = responsePost(EXECUTE, request); + mvcResult = requestPostWithOkAndReturn(EXECUTE, request); returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -694,7 +721,7 @@ public class ApiTestCaseControllerTests extends BaseTest { pageRequest.setProjectId(DEFAULT_PROJECT_ID); pageRequest.setPageSize(10); pageRequest.setCurrent(1); - MvcResult mvcResult = responsePost(PAGE, pageRequest); + MvcResult mvcResult = requestPostWithOkAndReturn(PAGE, pageRequest); Pager returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -705,7 +732,7 @@ public class ApiTestCaseControllerTests extends BaseTest { //查询apiDefinitionId1的数据 pageRequest.setApiDefinitionId("apiDefinitionId1"); - mvcResult = responsePost(PAGE, pageRequest); + mvcResult = requestPostWithOkAndReturn(PAGE, pageRequest); returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -718,7 +745,7 @@ public class ApiTestCaseControllerTests extends BaseTest { //查询模块为moduleId1的数据 pageRequest.setApiDefinitionId(null); pageRequest.setModuleIds(List.of("moduleId1")); - mvcResult = responsePost(PAGE, pageRequest); + mvcResult = requestPostWithOkAndReturn(PAGE, pageRequest); returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -731,7 +758,7 @@ public class ApiTestCaseControllerTests extends BaseTest { pageRequest.setSort(new HashMap<>() {{ put("createTime", "asc"); }}); - responsePost(PAGE, pageRequest); + requestPostWithOkAndReturn(PAGE, pageRequest); //校验权限 requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, PAGE, pageRequest); } @@ -774,7 +801,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setAppendTag(true); request.setSelectAll(true); request.setTags(new LinkedHashSet<>(List.of("tag1", "tag3", "tag4"))); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); ApiTestCaseExample example = new ApiTestCaseExample(); List ids = extApiTestCaseMapper.getIds(request, false); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andDeletedEqualTo(false).andIdIn(ids); @@ -786,7 +813,7 @@ public class ApiTestCaseControllerTests extends BaseTest { //覆盖标签 request.setTags(new LinkedHashSet<>(List.of("tag1"))); request.setAppendTag(false); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); apiTestCaseMapper.selectByExample(example).forEach(apiTestCase -> { Assertions.assertEquals(apiTestCase.getTags(), List.of("tag1")); }); @@ -801,7 +828,7 @@ public class ApiTestCaseControllerTests extends BaseTest { List apiIdList = caseList1.stream().map(ApiTestCase::getId).toList(); request.setSelectIds(apiIdList); request.setExcludeIds(apiIdList); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); initCaseData(); //优先级 @@ -811,7 +838,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setModuleIds(List.of("case-moduleId")); request.setPriority("P3"); request.setExcludeIds(new ArrayList<>()); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); //判断数据的优先级是不是P3 example.clear(); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId").andDeletedEqualTo(false); @@ -826,14 +853,14 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(false); request.setSelectIds(List.of(apiTestCase.getId())); request.setExcludeIds(List.of(apiTestCase.getId())); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); //状态 request.setPriority(null); request.setType("Status"); request.setStatus("Completed"); request.setSelectAll(true); request.setExcludeIds(new ArrayList<>()); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); //判断数据的状态是不是Completed caseList = apiTestCaseMapper.selectByExample(example); caseList.forEach(apiTestCase -> Assertions.assertEquals(apiTestCase.getStatus(), "Completed")); @@ -847,7 +874,7 @@ public class ApiTestCaseControllerTests extends BaseTest { environmentExample.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andMockEqualTo(true); List environments = environmentMapper.selectByExample(environmentExample); request.setEnvId(environments.get(0).getId()); - responsePost(BATCH_EDIT, request); + requestPostWithOkAndReturn(BATCH_EDIT, request); //判断数据的环境是不是environments.get(0).getId() caseList = apiTestCaseMapper.selectByExample(example); caseList.forEach(apiTestCase -> Assertions.assertEquals(apiTestCase.getEnvironmentId(), environments.get(0).getId())); @@ -887,7 +914,7 @@ public class ApiTestCaseControllerTests extends BaseTest { version.setCreateUser("admin"); projectVersionMapper.insertSelective(version); - MvcResult mvcResult = responsePost(HISTORY, request); + MvcResult mvcResult = requestPostWithOkAndReturn(HISTORY, request); Pager returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -902,7 +929,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSourceId("111"); request.setPageSize(10); request.setCurrent(1); - responsePost(HISTORY, request); + requestPostWithOkAndReturn(HISTORY, request); } @Test @@ -914,13 +941,13 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(false); request.setSelectIds(List.of(apiTestCase.getId())); request.setExcludeIds(List.of(apiTestCase.getId())); - responsePost(BATCH_MOVE_GC, request); + requestPostWithOkAndReturn(BATCH_MOVE_GC, request); request.setSelectAll(true); request.setExcludeIds(new ArrayList<>()); request.setApiDefinitionId("apiDefinitionId"); request.setModuleIds(List.of("case-moduleId")); - responsePost(BATCH_MOVE_GC, request); + requestPostWithOkAndReturn(BATCH_MOVE_GC, request); ApiTestCaseExample example = new ApiTestCaseExample(); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId").andDeletedEqualTo(true); List caseList = apiTestCaseMapper.selectByExample(example); @@ -929,7 +956,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(true); request.setExcludeIds(new ArrayList<>()); request.setModuleIds(List.of("case-moduleId")); - responsePost(BATCH_MOVE_GC, request); + requestPostWithOkAndReturn(BATCH_MOVE_GC, request); //校验日志 checkLog(apiTestCase.getId(), OperationLogType.DELETE); //校验权限 @@ -944,7 +971,7 @@ public class ApiTestCaseControllerTests extends BaseTest { pageRequest.setProjectId(DEFAULT_PROJECT_ID); pageRequest.setPageSize(10); pageRequest.setCurrent(1); - MvcResult mvcResult = responsePost(TRASH_PAGE, pageRequest); + MvcResult mvcResult = requestPostWithOkAndReturn(TRASH_PAGE, pageRequest); Pager returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -955,7 +982,7 @@ public class ApiTestCaseControllerTests extends BaseTest { //查询apiDefinitionId1的数据 pageRequest.setApiDefinitionId("apiDefinitionId1"); - mvcResult = responsePost(TRASH_PAGE, pageRequest); + mvcResult = requestPostWithOkAndReturn(TRASH_PAGE, pageRequest); returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -968,7 +995,7 @@ public class ApiTestCaseControllerTests extends BaseTest { //查询模块为moduleId1的数据 pageRequest.setApiDefinitionId(null); pageRequest.setModuleIds(List.of("moduleId1")); - mvcResult = responsePost(TRASH_PAGE, pageRequest); + mvcResult = requestPostWithOkAndReturn(TRASH_PAGE, pageRequest); returnPager = parseObjectFromMvcResult(mvcResult, Pager.class); //返回值不为空 Assertions.assertNotNull(returnPager); @@ -981,7 +1008,7 @@ public class ApiTestCaseControllerTests extends BaseTest { pageRequest.setSort(new HashMap<>() {{ put("createTime", "asc"); }}); - responsePost(TRASH_PAGE, pageRequest); + requestPostWithOkAndReturn(TRASH_PAGE, pageRequest); //校验权限 requestPostPermissionTest(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, TRASH_PAGE, pageRequest); } @@ -995,7 +1022,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(false); request.setSelectIds(List.of(apiTestCase.getId())); request.setExcludeIds(List.of(apiTestCase.getId())); - responsePost(BATCH_RECOVER, request); + requestPostWithOkAndReturn(BATCH_RECOVER, request); ApiDefinition apiDefinition = new ApiDefinition(); apiDefinition.setId("apiDefinitionId"); @@ -1006,7 +1033,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setExcludeIds(List.of(apiTestCase.getId())); request.setApiDefinitionId("apiDefinitionId"); request.setModuleIds(List.of("case-moduleId")); - responsePost(BATCH_RECOVER, request); + requestPostWithOkAndReturn(BATCH_RECOVER, request); ApiTestCaseExample example = new ApiTestCaseExample(); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId").andDeletedEqualTo(false); List caseList = apiTestCaseMapper.selectByExample(example); @@ -1015,7 +1042,7 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(true); request.setExcludeIds(new ArrayList<>()); request.setModuleIds(List.of("case-moduleId")); - responsePost(BATCH_RECOVER, request); + requestPostWithOkAndReturn(BATCH_RECOVER, request); //校验日志 checkLog(apiTestCase.getId(), OperationLogType.DELETE); //校验权限 @@ -1025,7 +1052,7 @@ public class ApiTestCaseControllerTests extends BaseTest { gcRequest.setSelectAll(true); gcRequest.setExcludeIds(new ArrayList<>()); gcRequest.setApiDefinitionId("apiDefinitionId"); - responsePost(BATCH_MOVE_GC, gcRequest); + requestPostWithOkAndReturn(BATCH_MOVE_GC, gcRequest); ApiTestCaseExample example1 = new ApiTestCaseExample(); example1.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId").andDeletedEqualTo(true); List caseList1 = apiTestCaseMapper.selectByExample(example1); @@ -1069,11 +1096,11 @@ public class ApiTestCaseControllerTests extends BaseTest { request.setSelectAll(false); request.setSelectIds(List.of(apiTestCase.getId())); request.setExcludeIds(List.of(apiTestCase.getId())); - responsePost(BATCH_DELETE, request); + requestPostWithOkAndReturn(BATCH_DELETE, request); request.setProjectId(DEFAULT_PROJECT_ID); request.setSelectAll(true); request.setApiDefinitionId("apiDefinitionId"); - responsePost(BATCH_DELETE, request); + requestPostWithOkAndReturn(BATCH_DELETE, request); ApiTestCaseExample example = new ApiTestCaseExample(); example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID).andApiDefinitionIdEqualTo("apiDefinitionId"); //数据为空 diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.java b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.java index b10df9326c..23bdc05096 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.java @@ -17,5 +17,7 @@ public interface ExtFileAssociationMapper { List selectAssociationFileInfo(@Param("sourceId") String sourceId); + List selectFileInfoBySourceIds(@Param("sourceIds") List sourceIds); + List selectFileIdsBySourceId(@Param("sourceIds")List sourceIds, @Param("sourceType")String sourceType); } diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.xml b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.xml index dfd23bba4e..063e663ea3 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.xml +++ b/backend/services/project-management/src/main/java/io/metersphere/project/mapper/ExtFileAssociationMapper.xml @@ -38,6 +38,32 @@ file_association.source_id = #{sourceId} + +