feat(接口测试): 接口定义用例和场景的执行接口

This commit is contained in:
AgAngle 2024-03-04 16:52:56 +08:00 committed by jianxing
parent 13e34f8ee7
commit b42830cd76
28 changed files with 790 additions and 344 deletions

View File

@ -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;
/**

View File

@ -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;
/**

View File

@ -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"),

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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<BaseTreeNode> options(@PathVariable String projectId) {
return fileModuleService.getTree(projectId);
}
}

View File

@ -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<MsCommonElement> commonElements = new ArrayList<>();
/**
* 执行的资源ID列表
* 场景执行时为关联的所有用例和场景列表
*/
private Set<String> refResourceIds = HashSet.newHashSet(0);
/**
* 执行的资源所属项目的ID列表
* 场景执行时为引用的资源的项目ID列表
*/
private Set<String> refProjectIds = HashSet.newHashSet(0);
/**
* 环境相关信息
*/
private ApiScenarioParseEnvInfo scenarioParseEnvInfo;
}

View File

@ -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<String> linkFileIds;
/**
* 执行的资源ID列表
* 场景执行时为关联的所有用例和场景列表
*/
private Set<String> refResourceIds = HashSet.newHashSet(0);
/**
* 执行的资源所属项目的ID列表
* 场景执行时为引用的资源的项目ID列表
*/
private Set<String> refProjectIds = HashSet.newHashSet(0);
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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<ApiScenarioStepRequest> steps;
/**
* 步骤详情
* key 为步骤ID
* 为详情
*/
@Schema(description = "步骤详情")
private Map<String, Object> stepDetails;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank
private String projectId;
/**
* 新上传的文件ID
* 创建时先按ID创建目录再把文件放入目录
*/
@Schema(description = "新上传的文件ID")
private List<String> uploadFileIds;
/**
* 新关联的文件ID
*/
@Schema(description = "关联文件ID")
private List<String> linkFileIds;
@Schema(description = "是否是本地执行")
private Boolean frontendDebug = false;
}

View File

@ -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<String, Object> stepDetails;
}

View File

@ -121,8 +121,7 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
MsProcessorConfig scenarioProcessorConfig = isPre ? scenarioConfig.getPreProcessorConfig() : scenarioConfig.getPostProcessorConfig();
Boolean enableGlobal = scenarioProcessorConfig.getEnableGlobal();
if (BooleanUtils.isFalse(enableGlobal) || envInfo == null) {
if (scenarioProcessorConfig == null || BooleanUtils.isFalse(scenarioProcessorConfig.getEnableGlobal()) || envInfo == null) {
// 如果场景配置没有开启全局前置不添加环境的前后置
return;
}
@ -156,11 +155,12 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
// 获取场景前后置
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
MsProcessorConfig processorConfig = isPre ? scenarioConfig.getPreProcessorConfig() : scenarioConfig.getPostProcessorConfig();
List<MsProcessor> scenarioPreProcessors = processorConfig.getProcessors();
if (CollectionUtils.isEmpty(scenarioPreProcessors)) {
if (processorConfig == null || CollectionUtils.isEmpty(processorConfig.getProcessors())) {
return;
}
List<MsProcessor> scenarioPreProcessors = processorConfig.getProcessors();
Function<Class<?>, MsProcessorConverter<MsProcessor>> getConverterFunc =
isPre ? MsProcessorConverterFactory::getPreConverter : MsProcessorConverterFactory::getPostConverter;

View File

@ -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<String> projectIdsSet = runRequest.getRefProjectIds();
projectIdsSet.add(taskRequest.getProjectId());
List<String> projectIds = projectIdsSet.stream().collect(Collectors.toList());
// 获取函数jar包
List<FileMetadata> 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<String> uploadFileIds = runRequest.getUploadFileIds();
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
.map(tempFileId -> {
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
return getApiExecuteFileInfo(tempFileId, fileName, taskRequest.getProjectId());
})
.collect(Collectors.toList());
taskRequest.setLocalTempFiles(localTempFiles);
}
List<String> linkFileIds = runRequest.getLinkFileIds();
// 没有保存的文件管理临时文件
if (CollectionUtils.isNotEmpty(linkFileIds)) {
List<FileMetadata> fileMetadataList = fileMetadataService.getByFileIds(linkFileIds);
// 添加临时的文件管理的文件
taskRequest.getRefFiles().addAll(getApiExecuteFileInfo(fileMetadataList));
}
}
/**
* 处理运行的资源所关联的文件信息
*
* @param runRequest
* @param taskRequest
*/
private void setTaskRefFileParam(ApiResourceRunRequest runRequest, TaskRequestDTO taskRequest) {
// 查询包括引用的资源所需的文件
Set<String> resourceIdsSet = runRequest.getRefResourceIds();
resourceIdsSet.add(taskRequest.getResourceId());
List<String> resourceIds = resourceIdsSet.stream().collect(Collectors.toList());
// 查询通过本地上传的文件
List<ApiExecuteFileInfo> localFiles = apiFileResourceService.getByResourceId(request.getId()).
List<ApiExecuteFileInfo> 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<ApiExecuteFileInfo> refFiles = fileAssociationService.getFiles(request.getId()).
List<ApiExecuteFileInfo> 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<String> uploadFileIds = request.getUploadFileIds();
if (CollectionUtils.isNotEmpty(uploadFileIds)) {
List<ApiExecuteFileInfo> localTempFiles = uploadFileIds.stream()
.map(tempFileId -> {
String fileName = apiFileResourceService.getTempFileNameByFileId(tempFileId);
return getApiExecuteFileInfo(tempFileId, fileName, request.getProjectId());
})
.collect(Collectors.toList());
taskRequest.setLocalTempFiles(localTempFiles);
}
List<String> linkFileIds = request.getLinkFileIds();
// 没有保存的文件管理临时文件
if (CollectionUtils.isNotEmpty(linkFileIds)) {
List<FileMetadata> fileMetadataList = fileMetadataService.getByFileIds(linkFileIds);
// 添加临时的文件管理的文件
refFiles.addAll(getApiExecuteFileInfo(fileMetadataList));
}
taskRequest.setRefFiles(refFiles);
// 获取函数jar包
List<FileMetadata> 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<ApiExecuteFileInfo> getApiExecuteFileInfo(List<FileMetadata> 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;
}
}

View File

@ -233,6 +233,13 @@ public class ApiFileResourceService {
return apiFileResourceMapper.selectByExample(example);
}
public List<ApiFileResource> getByResourceIds(List<String> resourceIds) {
ApiFileResourceExample example = new ApiFileResourceExample();
example.createCriteria()
.andResourceIdIn(resourceIds);
return apiFileResourceMapper.selectByExample(example);
}
/**
* 上传临时文件
* system/temp/{fileId}/{fileName}

View File

@ -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) {

View File

@ -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<ApiDefinitionDTO> 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);
}
}

View File

@ -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;
}
}

View File

@ -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<ApiScenarioStepRequest> steps = request.getSteps();
// 记录引用的资源ID
Map<String, List<String>> 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<? extends ApiScenarioStepCommonDTO> steps,
ApiScenarioParseParam parseParam) {
// 记录引用的资源ID
Map<String, List<String>> 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<? extends ApiScenarioStepCommonDTO> 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<String, String> getStepDetailMap(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetailsParam) {
private Map<String, String> getStepDetailMap(List<? extends ApiScenarioStepCommonDTO> steps, Map<String, Object> stepDetailsParam) {
List<String> 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) {

View File

@ -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<CheckLogModel> 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<ApiDefinitionCustomField> updateCustomFields() {
List<ApiDefinitionCustomField> 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());
}
}

View File

@ -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(

View File

@ -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> T parseObjectFromMvcResult(MvcResult mvcResult, Class<T> 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<String> 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<String> 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<Environment> 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<ApiTestCase> 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<ApiTestCase> 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<ApiTestCase> 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");
//数据为空

View File

@ -17,5 +17,7 @@ public interface ExtFileAssociationMapper {
List<FileInfo> selectAssociationFileInfo(@Param("sourceId") String sourceId);
List<FileInfo> selectFileInfoBySourceIds(@Param("sourceIds") List<String> sourceIds);
List<FileAssociation> selectFileIdsBySourceId(@Param("sourceIds")List<String> sourceIds, @Param("sourceType")String sourceType);
}

View File

@ -38,6 +38,32 @@
file_association.source_id = #{sourceId}
</select>
<select id="selectFileInfoBySourceIds" resultType="io.metersphere.project.dto.filemanagement.FileInfo">
SELECT
file_association.id AS id,
file_association.file_id AS fileId,
CONCAT( file_metadata.`name`, IF(LENGTH(file_metadata.type) = 0, '', '.'), file_metadata.type ) AS fileName,
file_metadata.original_name,
file_metadata.size AS size,
file_metadata.storage,
file_metadata.project_id,
file_metadata.module_id,
file_metadata.id as metadataId,
'false' AS local,
file_association.create_user AS createUser,
file_association.create_time AS createTime,
file_association.deleted deleted,
file_association.deleted_file_name AS deletedFileName
FROM
file_association
JOIN file_metadata ON file_association.file_id = file_metadata.id
WHERE
file_association.source_id in
<foreach collection="sourceIds" item="sourceId" open="(" separator="," close=")">
#{sourceId}
</foreach>
</select>
<select id="selectFileIdsBySourceId" resultType="io.metersphere.project.domain.FileAssociation">
select source_id, file_id from file_association where source_type = #{sourceType} and source_id in
<foreach collection="sourceIds" item="sourceId" open="(" separator="," close=")">

View File

@ -347,6 +347,16 @@ public class FileAssociationService {
return extFileAssociationMapper.selectAssociationFileInfo(sourceId);
}
/**
* 获取文件列表接口
*
* @param sourceIds
* @return
*/
public List<FileInfo> getFiles(List<String> sourceIds) {
return extFileAssociationMapper.selectFileInfoBySourceIds(sourceIds);
}
public List<FileAssociation> getFileAssociations(List<String> sourceIds, String sourceType) {
return extFileAssociationMapper.selectFileIdsBySourceId(sourceIds, sourceType);
}

View File

@ -22,6 +22,7 @@ public class TaskRunnerClient {
private static TOTPGenerator totpGenerator;
private static final String API_DEBUG = "/api/debug";
private static final String API_RUN = "/api/run";
private static final String HTTP_BATH = "http://%s:%s";
private static final String API_STOP = "/api/stop";
@ -39,6 +40,10 @@ public class TaskRunnerClient {
post(endpoint + API_DEBUG, taskRequest);
}
public static void runApi(String endpoint, TaskRequestDTO taskRequest) throws Exception {
post(endpoint + API_RUN, taskRequest);
}
public static void stopApi(String endpoint, List<String> reportIds) throws Exception {
post(endpoint + API_STOP, reportIds);
}

View File

@ -0,0 +1,37 @@
package io.metersphere.system.service;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.utils.TaskRunnerClient;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TaskRunnerClientTest extends BaseTest {
@Value("${embedded.mockserver.host}")
private String mockServerHost;
@Value("${embedded.mockserver.port}")
private Integer mockServerHostPort;
@Test
public void debugApi() throws Exception {
mockPost("/api/debug", "");
String endpoint = TaskRunnerClient.getEndpoint(mockServerHost, mockServerHostPort.toString());
TaskRunnerClient.debugApi(endpoint, new TaskRequestDTO());
}
@Test
public void runApi() throws Exception {
mockPost("/api/run", "");
String endpoint = TaskRunnerClient.getEndpoint(mockServerHost, mockServerHostPort.toString());
TaskRunnerClient.runApi(endpoint, new TaskRequestDTO());
}
}