feat(接口测试): 场景执行接口
This commit is contained in:
parent
31562ac774
commit
26f9f6726e
|
@ -283,7 +283,7 @@ CREATE TABLE IF NOT EXISTS api_scenario_step(
|
|||
`project_id` VARCHAR(50) COMMENT '项目fk' ,
|
||||
`parent_id` VARCHAR(50) DEFAULT 'NONE' COMMENT '父级fk' ,
|
||||
`version_id` VARCHAR(50) COMMENT '版本号' ,
|
||||
`ref_type` VARCHAR(10) COMMENT '引用/复制/自定义' ,
|
||||
`ref_type` VARCHAR(20) COMMENT '引用/复制/自定义' ,
|
||||
`config` VARCHAR(500) COMMENT '循环等组件基础数据' ,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE = InnoDB
|
||||
|
|
|
@ -11,13 +11,13 @@ public enum ApiScenarioStepRefType {
|
|||
*/
|
||||
DIRECT,
|
||||
/**
|
||||
* 引用
|
||||
* 完全引用
|
||||
*/
|
||||
REF,
|
||||
/**
|
||||
* 步骤引用
|
||||
* 部分引用
|
||||
*/
|
||||
STEP_REF,
|
||||
PARTIAL_REF,
|
||||
/**
|
||||
* 复制
|
||||
*/
|
||||
|
|
|
@ -70,7 +70,7 @@ public class ApiScenarioController {
|
|||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@Operation(summary = "创建场景")
|
||||
@Operation(summary = "接口测试-接口场景管理-创建场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_ADD)
|
||||
@Log(type = OperationLogType.ADD, expression = "#msClass.addLog(#request)", msClass = ApiScenarioLogService.class)
|
||||
public ApiScenario add(@Validated @RequestBody ApiScenarioAddRequest request) {
|
||||
|
@ -78,14 +78,14 @@ public class ApiScenarioController {
|
|||
}
|
||||
|
||||
@PostMapping("/upload/temp/file")
|
||||
@Operation(summary = "上传场景所需的文件资源,并返回文件ID")
|
||||
@Operation(summary = "接口测试-接口场景管理-上传场景所需的文件资源,并返回文件ID")
|
||||
@RequiresPermissions(logical = Logical.OR, value = {PermissionConstants.PROJECT_API_SCENARIO_ADD, PermissionConstants.PROJECT_API_SCENARIO_UPDATE})
|
||||
public String uploadTempFile(@RequestParam("file") MultipartFile file) {
|
||||
return apiScenarioService.uploadTempFile(file);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@Operation(summary = "更新场景")
|
||||
@Operation(summary = "接口测试-接口场景管理-更新场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_UPDATE)
|
||||
@Log(type = OperationLogType.UPDATE, expression = "#msClass.updateLog(#request)", msClass = ApiScenarioLogService.class)
|
||||
public ApiScenario update(@Validated @RequestBody ApiScenarioUpdateRequest request) {
|
||||
|
@ -93,7 +93,7 @@ public class ApiScenarioController {
|
|||
}
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
@Operation(summary = "删除场景")
|
||||
@Operation(summary = "接口测试-接口场景管理-删除场景")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_DELETE)
|
||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ApiScenarioLogService.class)
|
||||
public void delete(@PathVariable String id) {
|
||||
|
@ -101,10 +101,17 @@ public class ApiScenarioController {
|
|||
}
|
||||
|
||||
@GetMapping("/delete-to-gc/{id}")
|
||||
@Operation(summary = "删除场景到回收站")
|
||||
@Operation(summary = "接口测试-接口场景管理-删除场景到回收站")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_DELETE)
|
||||
@Log(type = OperationLogType.DELETE, expression = "#msClass.deleteLog(#id)", msClass = ApiScenarioLogService.class)
|
||||
public void deleteToGc(@PathVariable String id) {
|
||||
apiScenarioService.deleteToGc(id);
|
||||
}
|
||||
|
||||
@PostMapping("/debug")
|
||||
@Operation(summary = "接口测试-接口场景管理-场景调试")
|
||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE)
|
||||
public String debug(@RequestBody ApiScenarioDebugRequest request) {
|
||||
return apiScenarioService.debug(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,5 +18,5 @@ public class ApiDebugRunRequest {
|
|||
private List<String> tempFileIds;
|
||||
@NotNull
|
||||
@Schema(description = "请求内容")
|
||||
private String request;
|
||||
private Object request;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto.debug;
|
||||
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -20,7 +21,11 @@ public class ApiResourceRunRequest {
|
|||
*/
|
||||
private String reportId;
|
||||
/**
|
||||
* 环境ID
|
||||
* 是否为环境组
|
||||
*/
|
||||
private Boolean grouped = false;
|
||||
/**
|
||||
* 环境或者环境组ID
|
||||
*/
|
||||
private String environmentId;
|
||||
/**
|
||||
|
@ -33,9 +38,9 @@ public class ApiResourceRunRequest {
|
|||
*/
|
||||
private String resourceType;
|
||||
/**
|
||||
* 请求内容
|
||||
* 执行组件
|
||||
*/
|
||||
private String request;
|
||||
private AbstractMsTestElement testElement;
|
||||
/**
|
||||
* 点击调试时尚未保存的文件列表
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto.request;
|
||||
|
||||
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
@ -7,4 +8,5 @@ import lombok.EqualsAndHashCode;
|
|||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MsScenario extends AbstractMsTestElement {
|
||||
private ScenarioConfig scenarioConfig;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
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-01-10 11:24
|
||||
*/
|
||||
@Data
|
||||
public class ApiScenarioDebugRequest {
|
||||
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_scenario.id.not_blank}")
|
||||
@Size(max = 50, message = "{api_scenario.id.length_range}")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "是否为环境组")
|
||||
private Boolean grouped = false;
|
||||
|
||||
@Schema(description = "环境或者环境组ID", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank
|
||||
private String environmentId;
|
||||
|
||||
@Schema(description = "场景的通用配置")
|
||||
private ScenarioConfig scenarioConfig;
|
||||
|
||||
@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;
|
||||
@Schema(description = "点击调试时尚未保存的文件ID列表")
|
||||
private List<String> tempFileIds;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import io.metersphere.api.domain.ApiScenario;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ApiScenarioDetail extends ApiScenario {
|
||||
@Schema(description = "场景的通用配置")
|
||||
private ScenarioConfig scenarioConfig;
|
||||
}
|
|
@ -50,7 +50,8 @@ public class ApiScenarioStepRequest {
|
|||
/**
|
||||
* 引用模式:默认完全引用
|
||||
* - 完全引用:步骤状态不可调整
|
||||
* - 步骤引用:步骤状态可调整
|
||||
* - 部分引用:步骤状态可调整
|
||||
* @see io.metersphere.api.constants.ApiScenarioStepRefType
|
||||
*/
|
||||
@Schema(description = "引用/复制/自定义")
|
||||
private String refType;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package io.metersphere.api.dto.scenario;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-22 15:17
|
||||
*/
|
||||
@Data
|
||||
public class PartialRefStepDetail {
|
||||
/**
|
||||
* 记录子步骤中启用的步骤ID
|
||||
* 不包含,部分引用的子步骤
|
||||
* 部分引用的子步骤也会自行保存子步骤的启用状态
|
||||
*/
|
||||
private Set<String> enableStepIds;
|
||||
// 预留保存其他信息
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package io.metersphere.api.parser.step;
|
||||
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-20 15:43
|
||||
*/
|
||||
public class ApiCaseStepParser extends StepParser {
|
||||
@Override
|
||||
public AbstractMsTestElement parse(ApiScenarioStepRequest step, String resourceBlob, String stepDetail) {
|
||||
if (isRef(step.getRefType())) {
|
||||
return StringUtils.isBlank(resourceBlob) ? null : parse2MsTestElement(resourceBlob);
|
||||
} else {
|
||||
if (StringUtils.isBlank(stepDetail)) {
|
||||
return null;
|
||||
}
|
||||
return StringUtils.isBlank(stepDetail) ? null : ApiDataUtils.parseObject(stepDetail, AbstractMsTestElement.class);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package io.metersphere.api.parser.step;
|
||||
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
|
||||
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-20 15:43
|
||||
*/
|
||||
public class ApiScenarioStepParser extends StepParser {
|
||||
@Override
|
||||
public AbstractMsTestElement parse(ApiScenarioStepRequest step, String resourceBlob, String stepDetail) {
|
||||
MsScenario msScenario = new MsScenario();
|
||||
if (isRef(step.getRefType())) {
|
||||
if (StringUtils.isNotBlank(resourceBlob)) {
|
||||
msScenario.setScenarioConfig(JSON.parseObject(resourceBlob, ScenarioConfig.class));
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isNotBlank(stepDetail)) {
|
||||
msScenario.setScenarioConfig(JSON.parseObject(stepDetail, ScenarioConfig.class));
|
||||
}
|
||||
}
|
||||
return msScenario;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package io.metersphere.api.parser.step;
|
||||
|
||||
import io.metersphere.api.dto.request.http.KeyValueParam;
|
||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.request.http.body.Body;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-20 15:43
|
||||
*/
|
||||
public class ApiStepParser extends StepParser {
|
||||
@Override
|
||||
public AbstractMsTestElement parse(ApiScenarioStepRequest step, String resourceBlob, String stepDetail) {
|
||||
if (isRef(step.getRefType())) {
|
||||
if (StringUtils.isBlank(resourceBlob)) {
|
||||
return null;
|
||||
}
|
||||
AbstractMsTestElement refResourceElement = parse2MsTestElement(resourceBlob);
|
||||
if (refResourceElement instanceof MsHTTPElement && StringUtils.isNotBlank(stepDetail)) {
|
||||
// 如果是 http 并且有修改请求参数,则替换请求参数
|
||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(stepDetail, AbstractMsTestElement.class);
|
||||
return replaceParams((MsHTTPElement) msTestElement, (MsHTTPElement) refResourceElement);
|
||||
} else {
|
||||
return refResourceElement;
|
||||
}
|
||||
} else {
|
||||
return StringUtils.isBlank(stepDetail) ? null : ApiDataUtils.parseObject(stepDetail, AbstractMsTestElement.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private AbstractMsTestElement replaceParams(MsHTTPElement msTestElement, MsHTTPElement refResourceElement) {
|
||||
replaceKvParam(msTestElement.getHeaders(), refResourceElement.getHeaders());
|
||||
replaceKvParam(msTestElement.getQuery(), refResourceElement.getQuery());
|
||||
replaceKvParam(msTestElement.getRest(), refResourceElement.getRest());
|
||||
replaceBodyParams(msTestElement.getBody(), refResourceElement.getBody());
|
||||
return refResourceElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换请求体中的参数
|
||||
*
|
||||
* @param valueBody
|
||||
* @param refBody
|
||||
*/
|
||||
private void replaceBodyParams(Body valueBody, Body refBody) {
|
||||
if (refBody == null || valueBody == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.equals(refBody.getBodyType(), Body.BodyType.FORM_DATA.name()) &&
|
||||
valueBody.getFormDataBody() != null && refBody.getFormDataBody() != null) {
|
||||
replaceKvParam(valueBody.getFormDataBody().getFromValues(), valueBody.getFormDataBody().getFromValues());
|
||||
}
|
||||
if (StringUtils.equals(refBody.getBodyType(), Body.BodyType.WWW_FORM.name()) &&
|
||||
valueBody.getWwwFormBody() != null && refBody.getWwwFormBody() != null) {
|
||||
replaceKvParam(valueBody.getWwwFormBody().getFromValues(), valueBody.getWwwFormBody().getFromValues());
|
||||
}
|
||||
// todo JsonSchema body
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换参数
|
||||
*
|
||||
* @param valueList
|
||||
* @param refList
|
||||
*/
|
||||
private void replaceKvParam(List valueList, List refList) {
|
||||
if (CollectionUtils.isEmpty(refList) || CollectionUtils.isEmpty(valueList)) {
|
||||
return;
|
||||
}
|
||||
refList.forEach(item -> {
|
||||
KeyValueParam keyValueParam = (KeyValueParam) item;
|
||||
for (Object valueItem : valueList) {
|
||||
KeyValueParam valueParam = (KeyValueParam) valueItem;
|
||||
if (StringUtils.equals(keyValueParam.getKey(), valueParam.getKey())) {
|
||||
keyValueParam.setValue(valueParam.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package io.metersphere.api.parser.step;
|
||||
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepRequest;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-20 15:43
|
||||
*/
|
||||
public abstract class StepParser {
|
||||
|
||||
public abstract AbstractMsTestElement parse(ApiScenarioStepRequest step, String resourceBlob, String stepDetail);
|
||||
|
||||
protected boolean isRef(String refType) {
|
||||
return StringUtils.equalsAny(refType, ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
}
|
||||
|
||||
protected static AbstractMsTestElement parse2MsTestElement(String blobContent) {
|
||||
return ApiDataUtils.parseObject(blobContent, AbstractMsTestElement.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.api.parser.step;
|
||||
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: jianxing
|
||||
* @CreateTime: 2024-01-20 15:43
|
||||
*/
|
||||
public abstract class StepParserFactory {
|
||||
|
||||
private static Map<String, StepParser> stepParserMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
stepParserMap.put(ApiScenarioStepType.API.name(), new ApiStepParser());
|
||||
stepParserMap.put(ApiScenarioStepType.API_CASE.name(), new ApiCaseStepParser());
|
||||
stepParserMap.put(ApiScenarioStepType.API_SCENARIO.name(), new ApiScenarioStepParser());
|
||||
}
|
||||
|
||||
public static StepParser getStepParser(String stepType) {
|
||||
return stepParserMap.get(stepType);
|
||||
}
|
||||
}
|
|
@ -131,7 +131,7 @@ public class ApiExecuteService {
|
|||
// todo 接口用例 method 获取定义中的数据库字段
|
||||
ParameterConfig parameterConfig = new ParameterConfig();
|
||||
parameterConfig.setReportId(reportId);
|
||||
String executeScript = parseExecuteScript(request.getRequest(), parameterConfig);
|
||||
String executeScript = parseExecuteScript(request.getTestElement(), parameterConfig);
|
||||
|
||||
TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(request.getProjectId());
|
||||
|
||||
|
@ -306,15 +306,10 @@ public class ApiExecuteService {
|
|||
/**
|
||||
* 生成执行脚本
|
||||
*
|
||||
* @param testElementStr
|
||||
* @param msTestElement
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
private static String parseExecuteScript(String testElementStr, ParameterConfig config) {
|
||||
// 解析生成脚本
|
||||
return parseExecuteScript(ApiDataUtils.parseObject(testElementStr, AbstractMsTestElement.class), config);
|
||||
}
|
||||
|
||||
private static String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
|
||||
// 解析生成脚本
|
||||
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
|
||||
|
|
|
@ -18,6 +18,7 @@ import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
|||
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.uid.IDGenerator;
|
||||
import io.metersphere.system.utils.ServiceUtils;
|
||||
|
@ -187,6 +188,8 @@ public class ApiDebugService {
|
|||
runRequest.setReportId(id);
|
||||
runRequest.setResourceType(ApiResourceType.API_DEBUG.name());
|
||||
runRequest.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
||||
runRequest.setEnvironmentId(request.getEnvironmentId());
|
||||
runRequest.setTestElement(ApiDataUtils.parseObject(JSON.toJSONString(request.getRequest()), AbstractMsTestElement.class));
|
||||
|
||||
apiExecuteService.debug(runRequest);
|
||||
|
||||
|
|
|
@ -1011,4 +1011,13 @@ public class ApiDefinitionService {
|
|||
// 记录操作日志
|
||||
return apiDefinitionLogService.recoverOperationHistoryLog(apiDefinitionDTO, apiDefinition.getCreateUser(), apiDefinition.getProjectId());
|
||||
}
|
||||
|
||||
public List<ApiDefinitionBlob> getBlobByIds(List<String> apiIds) {
|
||||
if (CollectionUtils.isEmpty(apiIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiDefinitionBlobExample apiDefinitionBlobExample = new ApiDefinitionBlobExample();
|
||||
apiDefinitionBlobExample.createCriteria().andIdIn(apiIds);
|
||||
return apiDefinitionBlobMapper.selectByExampleWithBLOBs(apiDefinitionBlobExample);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
@ -529,4 +530,13 @@ public class ApiTestCaseService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ApiTestCaseBlob> getBlobByIds(List<String> apiCaseIds) {
|
||||
if (CollectionUtils.isEmpty(apiCaseIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiTestCaseBlobExample example = new ApiTestCaseBlobExample();
|
||||
example.createCriteria().andIdIn(apiCaseIds);
|
||||
return apiTestCaseBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,20 @@ import io.metersphere.api.constants.ApiScenarioStepRefType;
|
|||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.debug.ApiFileResourceUpdateRequest;
|
||||
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
|
||||
import io.metersphere.api.dto.request.MsScenario;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.parser.step.StepParser;
|
||||
import io.metersphere.api.parser.step.StepParserFactory;
|
||||
import io.metersphere.api.service.ApiExecuteService;
|
||||
import io.metersphere.api.service.ApiFileResourceService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.project.service.ProjectService;
|
||||
import io.metersphere.sdk.constants.ApiExecuteRunMode;
|
||||
import io.metersphere.sdk.constants.ApplicationNumScope;
|
||||
import io.metersphere.sdk.constants.DefaultRepositoryDir;
|
||||
import io.metersphere.sdk.domain.Environment;
|
||||
|
@ -45,6 +54,7 @@ import java.util.stream.Collectors;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import static io.metersphere.api.controller.result.ApiResultCode.API_SCENARIO_EXIST;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiScenarioService {
|
||||
|
@ -84,6 +94,12 @@ public class ApiScenarioService {
|
|||
private ApiScenarioStepBlobMapper apiScenarioStepBlobMapper;
|
||||
@Resource
|
||||
private ApiScenarioBlobMapper apiScenarioBlobMapper;
|
||||
@Resource
|
||||
private ApiExecuteService apiExecuteService;
|
||||
@Resource
|
||||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
public static final String PRIORITY = "Priority";
|
||||
public static final String STATUS = "Status";
|
||||
public static final String TAGS = "Tags";
|
||||
|
@ -284,13 +300,16 @@ public class ApiScenarioService {
|
|||
|
||||
// 插入步骤
|
||||
if (CollectionUtils.isNotEmpty(request.getSteps())) {
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
List<ApiScenarioStep> apiScenarioSteps = getUpdateApiScenarioSteps(null, request.getSteps(), apiScenarioStepsDetails);
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
|
||||
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
// 获取待添加的步骤
|
||||
List<ApiScenarioStep> steps = getApiScenarioSteps(null, request.getSteps());
|
||||
steps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
// 获取待添加的步骤详情
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = getPartialRefStepDetails(request.getSteps());
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(steps, request.getStepDetails()));
|
||||
apiScenarioStepsDetails.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioSteps)) {
|
||||
apiScenarioStepMapper.batchInsert(apiScenarioSteps);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(steps)) {
|
||||
apiScenarioStepMapper.batchInsert(steps);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(apiScenarioStepsDetails)) {
|
||||
apiScenarioStepBlobMapper.batchInsert(apiScenarioStepsDetails);
|
||||
|
@ -359,6 +378,7 @@ public class ApiScenarioService {
|
|||
|
||||
/**
|
||||
* 更新场景步骤
|
||||
*
|
||||
* @param request
|
||||
* @param scenario
|
||||
*/
|
||||
|
@ -372,10 +392,13 @@ public class ApiScenarioService {
|
|||
return;
|
||||
}
|
||||
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
List<ApiScenarioStep> apiScenarioSteps = getUpdateApiScenarioSteps(null, request.getSteps(), apiScenarioStepsDetails);
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
|
||||
// 获取待更新的步骤
|
||||
List<ApiScenarioStep> apiScenarioSteps = getApiScenarioSteps(null, request.getSteps());
|
||||
apiScenarioSteps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
|
||||
// 获取待更新的步骤详情
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = getPartialRefStepDetails(request.getSteps());
|
||||
apiScenarioStepsDetails.addAll(getUpdateStepDetails(apiScenarioSteps, request.getStepDetails()));
|
||||
apiScenarioStepsDetails.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||
|
||||
List<String> stepIds = apiScenarioSteps.stream().map(ApiScenarioStep::getId).collect(Collectors.toList());
|
||||
|
@ -439,6 +462,7 @@ public class ApiScenarioService {
|
|||
|
||||
/**
|
||||
* 获取待更新的 ApiScenarioStepBlob 列表
|
||||
*
|
||||
* @param apiScenarioSteps
|
||||
* @param stepDetails
|
||||
* @return
|
||||
|
@ -457,8 +481,7 @@ public class ApiScenarioService {
|
|||
if (step == null) {
|
||||
return;
|
||||
}
|
||||
boolean isRef = StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.STEP_REF.name());
|
||||
if (!isRef || StringUtils.equals(step.getRefType(), ApiScenarioStepType.API.name())) {
|
||||
if (!isRef(step.getRefType()) || StringUtils.equals(step.getRefType(), ApiScenarioStepType.API.name())) {
|
||||
// 非引用的步骤,如果有编辑内容,保存到blob表
|
||||
// 如果引用的是接口定义,也保存详情,因为应用接口定义允许修改参数值
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
|
@ -470,17 +493,20 @@ public class ApiScenarioService {
|
|||
return apiScenarioStepsDetails;
|
||||
}
|
||||
|
||||
private boolean isRef(String refType) {
|
||||
return StringUtils.equalsAny(refType, ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析步骤树结构
|
||||
* 获取待更新的 ApiScenarioStep 列表
|
||||
*
|
||||
* @param parent
|
||||
* @param steps
|
||||
* @param apiScenarioStepsDetails
|
||||
* @return
|
||||
*/
|
||||
private List<ApiScenarioStep> getUpdateApiScenarioSteps(ApiScenarioStepRequest parent,
|
||||
List<ApiScenarioStepRequest> steps,
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails) {
|
||||
private List<ApiScenarioStep> getApiScenarioSteps(ApiScenarioStepRequest parent,
|
||||
List<ApiScenarioStepRequest> steps) {
|
||||
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return Collections.emptyList();
|
||||
|
@ -499,25 +525,49 @@ public class ApiScenarioService {
|
|||
}
|
||||
apiScenarioSteps.add(apiScenarioStep);
|
||||
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.STEP_REF.name())) {
|
||||
// 如果是步骤引用,blob表保存启用的子步骤ID
|
||||
Set<String> enableStepSet = getEnableStepSet(step.getChildren());
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
apiScenarioStepBlob.setId(apiScenarioStep.getId());
|
||||
apiScenarioStepBlob.setContent(JSON.toJSONString(enableStepSet).getBytes());
|
||||
apiScenarioStepsDetails.add(apiScenarioStepBlob);
|
||||
}
|
||||
|
||||
if (StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.STEP_REF.name())) {
|
||||
if (StringUtils.equalsAny(step.getRefType(), ApiScenarioStepRefType.REF.name(), ApiScenarioStepRefType.PARTIAL_REF.name())) {
|
||||
// 引用的步骤不解析子步骤
|
||||
continue;
|
||||
}
|
||||
// 解析子步骤
|
||||
apiScenarioSteps.addAll(getUpdateApiScenarioSteps(step, step.getChildren(), apiScenarioStepsDetails));
|
||||
apiScenarioSteps.addAll(getApiScenarioSteps(step, step.getChildren()));
|
||||
}
|
||||
return apiScenarioSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析步骤树结构
|
||||
* 获取待更新的 ApiScenarioStep 列表
|
||||
*
|
||||
* @param steps
|
||||
* @return
|
||||
*/
|
||||
private List<ApiScenarioStepBlob> getPartialRefStepDetails(List<ApiScenarioStepRequest> steps) {
|
||||
if (CollectionUtils.isEmpty(steps)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<ApiScenarioStepBlob> apiScenarioStepsDetails = new ArrayList<>();
|
||||
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.REF.name())) {
|
||||
// 引用的步骤不解析子步骤
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.PARTIAL_REF.name())) {
|
||||
// 如果是部分引用,blob表保存启用的子步骤ID
|
||||
Set<String> enableStepSet = getEnableStepSet(step.getChildren());
|
||||
PartialRefStepDetail stepDetail = new PartialRefStepDetail();
|
||||
stepDetail.setEnableStepIds(enableStepSet);
|
||||
ApiScenarioStepBlob apiScenarioStepBlob = new ApiScenarioStepBlob();
|
||||
apiScenarioStepBlob.setId(step.getId());
|
||||
apiScenarioStepBlob.setContent(JSON.toJSONString(stepDetail).getBytes());
|
||||
apiScenarioStepsDetails.add(apiScenarioStepBlob);
|
||||
}
|
||||
apiScenarioStepsDetails.addAll(getPartialRefStepDetails(step.getChildren()));
|
||||
}
|
||||
return apiScenarioStepsDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取步骤及子步骤中 enable 的步骤ID
|
||||
*
|
||||
|
@ -533,8 +583,11 @@ public class ApiScenarioService {
|
|||
if (BooleanUtils.isTrue(step.getEnable())) {
|
||||
enableSteps.add(step.getId());
|
||||
}
|
||||
// 获取子步骤中 enable = true 的步骤
|
||||
enableSteps.addAll(getEnableStepSet(step.getChildren()));
|
||||
// 完全引用和部分引用不解析子步骤
|
||||
if (!isRef(step.getRefType())) {
|
||||
// 获取子步骤中 enable 的步骤
|
||||
enableSteps.addAll(getEnableStepSet(step.getChildren()));
|
||||
}
|
||||
}
|
||||
return enableSteps;
|
||||
}
|
||||
|
@ -609,4 +662,210 @@ public class ApiScenarioService {
|
|||
public String uploadTempFile(MultipartFile file) {
|
||||
return apiFileResourceService.uploadTempFile(file);
|
||||
}
|
||||
|
||||
public String debug(ApiScenarioDebugRequest request) {
|
||||
ApiScenario apiScenario = apiScenarioMapper.selectByPrimaryKey(request.getId());
|
||||
boolean hasSave = apiScenario != null;
|
||||
String reportId = IDGenerator.nextStr();
|
||||
|
||||
List<ApiScenarioStepRequest> steps = request.getSteps();
|
||||
|
||||
// 记录引用的资源ID
|
||||
Map<String, List<String>> refResourceMap = new HashMap<>();
|
||||
buildRefResourceIdMap(steps, refResourceMap);
|
||||
|
||||
// 查询引用的资源详情
|
||||
Map<String, String> resourceBlobMap = getResourceBlobMap(refResourceMap);
|
||||
|
||||
// 查询复制的步骤详情
|
||||
Map<String, String> detailMap = getStepDetailMap(steps, request.getStepDetails());
|
||||
|
||||
// 解析生成待执行的场景树
|
||||
MsScenario msScenario = new MsScenario();
|
||||
msScenario.setScenarioConfig(getScenarioConfig(request, hasSave));
|
||||
parseStep2MsElement(msScenario, steps, resourceBlobMap, detailMap);
|
||||
|
||||
ApiResourceRunRequest runRequest = BeanUtils.copyBean(new ApiResourceRunRequest(), request);
|
||||
runRequest.setProjectId(request.getProjectId());
|
||||
runRequest.setTestId(request.getId());
|
||||
runRequest.setReportId(reportId);
|
||||
runRequest.setResourceType(ApiResourceType.API_SCENARIO.name());
|
||||
runRequest.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
|
||||
runRequest.setTempFileIds(request.getTempFileIds());
|
||||
runRequest.setGrouped(request.getGrouped());
|
||||
runRequest.setEnvironmentId(request.getEnvironmentId());
|
||||
runRequest.setTestElement(msScenario);
|
||||
|
||||
apiExecuteService.debug(runRequest);
|
||||
|
||||
return reportId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将步骤解析成 MsTestElement 树结构
|
||||
*
|
||||
* @param parentElement
|
||||
* @param steps
|
||||
* @param resourceBlobMap
|
||||
* @param stepDetailMap
|
||||
*/
|
||||
private void parseStep2MsElement(AbstractMsTestElement parentElement,
|
||||
List<ApiScenarioStepRequest> steps,
|
||||
Map<String, String> resourceBlobMap,
|
||||
Map<String, String> stepDetailMap) {
|
||||
if (CollectionUtils.isNotEmpty(steps)) {
|
||||
parentElement.setChildren(new LinkedList<>());
|
||||
}
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
|
||||
if (stepParser == null || BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.equals(step.getStepType(), ApiScenarioStepRefType.PARTIAL_REF.name())) {
|
||||
setPartialRefStepEnable(step, stepDetailMap);
|
||||
}
|
||||
// 将步骤详情解析生成对应的MsTestElement
|
||||
AbstractMsTestElement msTestElement = stepParser.parse(step, resourceBlobMap.get(step.getResourceId()), stepDetailMap.get(step.getId()));
|
||||
if (msTestElement != null) {
|
||||
parentElement.getChildren().add(msTestElement);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
parseStep2MsElement(msTestElement, step.getChildren(), resourceBlobMap, stepDetailMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置部分引用的步骤的启用状态
|
||||
* @param step
|
||||
* @param stepDetailMap
|
||||
*/
|
||||
private void setPartialRefStepEnable(ApiScenarioStepRequest step, Map<String, String> stepDetailMap) {
|
||||
String stepDetail = stepDetailMap.get(step.getId());
|
||||
if (StringUtils.isBlank(stepDetail)) {
|
||||
return;
|
||||
}
|
||||
PartialRefStepDetail partialRefStepDetail = JSON.parseObject(stepDetail, PartialRefStepDetail.class);
|
||||
setChildPartialRefEnable(step.getChildren(), partialRefStepDetail.getEnableStepIds(), stepDetailMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置部分引用的步骤的启用状态
|
||||
* @param steps
|
||||
* @param enableStepIds
|
||||
* @param stepDetailMap
|
||||
*/
|
||||
private void setChildPartialRefEnable(List<ApiScenarioStepRequest> steps, Set<String> enableStepIds, Map<String, String> stepDetailMap) {
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.REF.name())) {
|
||||
// 引用的启用不修改
|
||||
continue;
|
||||
}
|
||||
// 非完全引用的步骤,使用当前场景配置的启用状态
|
||||
step.setEnable(enableStepIds.contains(step.getId()));
|
||||
if (StringUtils.equals(step.getRefType(), ApiScenarioStepRefType.PARTIAL_REF.name())) {
|
||||
// 如果是部分引用的场景,重新获取详情再解析
|
||||
setPartialRefStepEnable(step, stepDetailMap);
|
||||
continue;
|
||||
}
|
||||
// 非完全引用和部分引用的步骤,递归设置子步骤
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
setChildPartialRefEnable(step.getChildren(), enableStepIds, stepDetailMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> getStepDetailMap(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetailsParam) {
|
||||
List<String> needBlobStepIds = new ArrayList<>();
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
if (BooleanUtils.isFalse(step.getEnable())) {
|
||||
continue;
|
||||
}
|
||||
if (StringUtils.equalsAny(step.getStepType(), ApiScenarioStepRefType.REF.name())
|
||||
&& !StringUtils.equals(step.getRefType(), ApiScenarioStepType.API.name())) {
|
||||
// 非完全引用的步骤和接口定义的步骤,才需要查blob
|
||||
continue;
|
||||
}
|
||||
if (stepDetailsParam != null && stepDetailsParam.keySet().contains(step.getId())) {
|
||||
// 前端传了blob,不需要再查
|
||||
continue;
|
||||
}
|
||||
needBlobStepIds.add(step.getId());
|
||||
}
|
||||
|
||||
Map<String, String> stepDetails = getStepBlobByIds(needBlobStepIds).stream()
|
||||
.collect(Collectors.toMap(ApiScenarioStepBlob::getId, blob -> new String(blob.getContent())));
|
||||
// 前端有传,就用前端传的
|
||||
if (stepDetailsParam != null) {
|
||||
stepDetailsParam.forEach((stepId, detail) -> stepDetails.put(stepId, JSON.toJSONString(detail)));
|
||||
}
|
||||
return stepDetails;
|
||||
}
|
||||
|
||||
private Map<String, String> getResourceBlobMap(Map<String, List<String>> refResourceMap) {
|
||||
Map<String, String> resourceBlobMap = new HashMap<>();
|
||||
List<String> apiIds = refResourceMap.get(ApiScenarioStepType.API.name());
|
||||
List<ApiDefinitionBlob> apiDefinitionBlobs = apiDefinitionService.getBlobByIds(apiIds);
|
||||
apiDefinitionBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiCaseIds = refResourceMap.get(ApiScenarioStepType.API_CASE.name());
|
||||
List<ApiTestCaseBlob> apiTestCaseBlobs = apiTestCaseService.getBlobByIds(apiCaseIds);
|
||||
apiTestCaseBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getRequest())));
|
||||
|
||||
List<String> apiScenarioIds = refResourceMap.get(ApiScenarioStepType.API_SCENARIO.name());
|
||||
List<ApiScenarioBlob> apiScenarioBlobs = getBlobByIds(apiScenarioIds);
|
||||
apiScenarioBlobs.forEach(blob -> resourceBlobMap.put(blob.getId(), new String(blob.getConfig())));
|
||||
return resourceBlobMap;
|
||||
}
|
||||
|
||||
private List<ApiScenarioStepBlob> getStepBlobByIds(List<String> stepIds) {
|
||||
if (CollectionUtils.isEmpty(stepIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiScenarioStepBlobExample example = new ApiScenarioStepBlobExample();
|
||||
example.createCriteria().andIdIn(stepIds);
|
||||
return apiScenarioStepBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
private List<ApiScenarioBlob> getBlobByIds(List<String> apiScenarioIds) {
|
||||
if (CollectionUtils.isEmpty(apiScenarioIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ApiScenarioBlobExample example = new ApiScenarioBlobExample();
|
||||
example.createCriteria().andIdIn(apiScenarioIds);
|
||||
return apiScenarioBlobMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
private void buildRefResourceIdMap(List<ApiScenarioStepRequest> steps, Map<String, List<String>> refResourceIdMap) {
|
||||
for (ApiScenarioStepRequest step : steps) {
|
||||
if (isRef(step.getRefType()) && BooleanUtils.isTrue(step.getEnable())) {
|
||||
// 记录引用的步骤ID
|
||||
List<String> resourceIds = refResourceIdMap.get(step.getStepType());
|
||||
if (resourceIds == null) {
|
||||
resourceIds = new ArrayList<>();
|
||||
refResourceIdMap.put(step.getStepType(), resourceIds);
|
||||
}
|
||||
resourceIds.add(step.getResourceId());
|
||||
}
|
||||
|
||||
if (CollectionUtils.isNotEmpty(step.getChildren())) {
|
||||
buildRefResourceIdMap(step.getChildren(), refResourceIdMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScenarioConfig getScenarioConfig(ApiScenarioDebugRequest request, boolean hasSave) {
|
||||
ScenarioConfig scenarioConfig = null;
|
||||
if (request.getScenarioConfig() != null) {
|
||||
// 优先使用前端传的配置
|
||||
scenarioConfig = request.getScenarioConfig();
|
||||
} else if (hasSave) {
|
||||
// 没传并且保存过,则从数据库获取
|
||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(request.getId());
|
||||
if (apiScenarioBlob != null) {
|
||||
scenarioConfig = JSON.parseObject(new String(apiScenarioBlob.getConfig()), ScenarioConfig.class);
|
||||
}
|
||||
}
|
||||
return scenarioConfig;
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package io.metersphere.api.utils;
|
|||
import io.metersphere.api.parser.jmeter.MsCommentScriptElementConverter;
|
||||
import io.metersphere.api.parser.jmeter.MsCommonElementConverter;
|
||||
import io.metersphere.api.parser.jmeter.MsHTTPElementConverter;
|
||||
import io.metersphere.api.parser.jmeter.MsScenarioConverter;
|
||||
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
|
||||
import io.metersphere.plugin.api.spi.MsTestElement;
|
||||
import io.metersphere.plugin.sdk.util.PluginLogUtils;
|
||||
|
@ -30,6 +31,7 @@ public class JmeterElementConverterRegister {
|
|||
register(MsHTTPElementConverter.class);
|
||||
register(MsCommonElementConverter.class);
|
||||
register(MsCommentScriptElementConverter.class);
|
||||
register(MsScenarioConverter.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -363,7 +363,7 @@ public class ApiDebugControllerTests extends BaseTest {
|
|||
MsHTTPElement msHTTPElement = new MsHTTPElement();
|
||||
msHTTPElement.setPath("/test");
|
||||
msHTTPElement.setMethod("GET");
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement)));
|
||||
|
||||
// @校验组织没有资源池权限异常
|
||||
assertErrorCode(this.requestPost(DEBUG, request), ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
|
||||
|
@ -392,7 +392,7 @@ public class ApiDebugControllerTests extends BaseTest {
|
|||
msHTTPElement = MsHTTPElementTest.getMsHttpElement();
|
||||
msHTTPElement.setChildren(linkedList);
|
||||
msHTTPElement.setEnable(true);
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试请求体
|
||||
|
@ -407,10 +407,10 @@ public class ApiDebugControllerTests extends BaseTest {
|
|||
|
||||
// 增加覆盖率
|
||||
msHTTPElement.setMethod("GET");
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
msHTTPElement.setEnable(false);
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 增加覆盖率
|
||||
|
@ -426,35 +426,39 @@ public class ApiDebugControllerTests extends BaseTest {
|
|||
private void testBodyParse(ApiDebugRunRequest request, MsHTTPElement msHTTPElement, Body generalBody) throws Exception {
|
||||
// 测试 FORM_DATA
|
||||
generalBody.setBodyType(Body.BodyType.FORM_DATA.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试 WWW_FORM
|
||||
generalBody.setBodyType(Body.BodyType.WWW_FORM.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试 BINARY
|
||||
generalBody.setBodyType(Body.BodyType.BINARY.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试 JSON
|
||||
generalBody.setBodyType(Body.BodyType.JSON.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试 XML
|
||||
generalBody.setBodyType(Body.BodyType.XML.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// 测试 RAW
|
||||
generalBody.setBodyType(Body.BodyType.RAW.name());
|
||||
request.setRequest(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
request.setRequest(getMsElementParam(msHTTPElement));
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
}
|
||||
|
||||
private Object getMsElementParam(MsHTTPElement msHTTPElement) {
|
||||
return JSON.parseObject(ApiDataUtils.toJSONString(msHTTPElement));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
public void delete() throws Exception {
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.api.controller;
|
|||
import io.metersphere.api.constants.ApiDefinitionStatus;
|
||||
import io.metersphere.api.constants.ApiScenarioStatus;
|
||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.definition.ApiDefinitionAddRequest;
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseAddRequest;
|
||||
|
@ -11,6 +12,7 @@ import io.metersphere.api.dto.request.assertion.MsScriptAssertion;
|
|||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||
import io.metersphere.api.dto.scenario.*;
|
||||
import io.metersphere.api.mapper.*;
|
||||
import io.metersphere.api.service.BaseResourcePoolTestService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.api.utils.ApiDataUtils;
|
||||
|
@ -60,6 +62,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
private static final String FOLLOW = "follow/";
|
||||
protected static final String UPLOAD_TEMP_FILE = "upload/temp/file";
|
||||
protected static final String DELETE_TO_GC = "delete-to-gc/{0}";
|
||||
protected static final String DEBUG = "debug";
|
||||
|
||||
private static final ResultMatcher ERROR_REQUEST_MATCHER = status().is5xxServerError();
|
||||
@Resource
|
||||
|
@ -86,6 +89,8 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
private ApiDefinitionService apiDefinitionService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
@Resource
|
||||
private BaseResourcePoolTestService baseResourcePoolTestService;
|
||||
private static ApiScenario addApiScenario;
|
||||
private static ApiScenario anOtherAddApiScenario;
|
||||
private static ApiDefinition apiDefinition;
|
||||
|
@ -227,7 +232,7 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
stepRequest2.setId(IDGenerator.nextStr());
|
||||
stepRequest2.setName(addApiScenario.getName());
|
||||
stepRequest2.setResourceId(addApiScenario.getId());
|
||||
stepRequest2.setRefType(ApiScenarioStepRefType.STEP_REF.name());
|
||||
stepRequest2.setRefType(ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
stepRequest2.setChildren(List.of(stepRequest));
|
||||
steps = List.of(stepRequest, stepRequest2);
|
||||
request.setSteps(steps);
|
||||
|
@ -326,8 +331,11 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
stepRequest3.setResourceId(apiDefinition.getId());
|
||||
stepRequest.setName(apiDefinition.getName() + "3");
|
||||
stepRequest3.setRefType(ApiScenarioStepRefType.REF.name());
|
||||
|
||||
return List.of(stepRequest, stepRequest2);
|
||||
return new ArrayList<>() {{
|
||||
add(stepRequest);
|
||||
add(stepRequest2);
|
||||
add(stepRequest3);
|
||||
}};
|
||||
}
|
||||
|
||||
private void initTestData() {
|
||||
|
@ -409,30 +417,6 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_UPDATE, DEFAULT_UPDATE, request);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void deleteToGc() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DELETE_TO_GC, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DELETE_TO_GC, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void delete() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DEFAULT_DELETE, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DEFAULT_DELETE, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
public void uploadTempFile() throws Exception {
|
||||
|
@ -450,6 +434,45 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
requestUploadPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_UPDATE, UPLOAD_TEMP_FILE, file);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
public void debug() throws Exception {
|
||||
mockPost("/api/debug", "");
|
||||
baseResourcePoolTestService.initProjectResourcePool();
|
||||
// @@请求成功
|
||||
ApiScenarioDebugRequest request = new ApiScenarioDebugRequest();
|
||||
request.setProjectId(DEFAULT_PROJECT_ID);
|
||||
request.setScenarioConfig(new ScenarioConfig());
|
||||
request.setEnvironmentId("environmentId");
|
||||
|
||||
List<ApiScenarioStepRequest> steps = getApiScenarioStepRequests();
|
||||
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
|
||||
stepRequest.setName("test step");
|
||||
stepRequest.setId(IDGenerator.nextStr());
|
||||
stepRequest.setRefType(ApiScenarioStepRefType.REF.name());
|
||||
stepRequest.setResourceId(addApiScenario.getId());
|
||||
stepRequest.setResourceNum(addApiScenario.getNum().toString());
|
||||
stepRequest.setName(addApiScenario.getName());
|
||||
stepRequest.setStepType(ApiScenarioStepType.API_SCENARIO.name());
|
||||
stepRequest.setChildren(getApiScenarioStepRequests());
|
||||
steps.add(stepRequest);
|
||||
ApiScenarioStepRequest copyScenarioStep = BeanUtils.copyBean(new ApiScenarioStepRequest(), stepRequest);
|
||||
copyScenarioStep.setRefType(ApiScenarioStepRefType.COPY.name());
|
||||
copyScenarioStep.setChildren(getApiScenarioStepRequests());
|
||||
steps.add(stepRequest);
|
||||
ApiScenarioStepRequest partialScenarioStep = BeanUtils.copyBean(new ApiScenarioStepRequest(), stepRequest);
|
||||
partialScenarioStep.setRefType(ApiScenarioStepRefType.PARTIAL_REF.name());
|
||||
partialScenarioStep.setChildren(getApiScenarioStepRequests());
|
||||
steps.add(partialScenarioStep);
|
||||
request.setId(addApiScenario.getId());
|
||||
request.setSteps(steps);
|
||||
request.setStepDetails(new HashMap<>());
|
||||
this.requestPostWithOk(DEBUG, request);
|
||||
|
||||
// @@校验权限
|
||||
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, DEBUG, request);
|
||||
}
|
||||
|
||||
private String doUploadTempFile(MockMultipartFile file) throws Exception {
|
||||
return JSON.parseObject(requestUploadFileWithOkAndReturn(UPLOAD_TEMP_FILE, file)
|
||||
.getResponse()
|
||||
|
@ -467,6 +490,30 @@ public class ApiScenarioControllerTests extends BaseTest {
|
|||
return file;
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
public void deleteToGc() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DELETE_TO_GC, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DELETE_TO_GC, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
public void delete() throws Exception {
|
||||
// @@请求成功
|
||||
this.requestGetWithOk(DEFAULT_DELETE, addApiScenario.getId());
|
||||
// todo 校验请求成功数据
|
||||
// @@校验日志
|
||||
checkLog(addApiScenario.getId(), OperationLogType.DELETE);
|
||||
// @@校验权限
|
||||
requestGetPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_DELETE, DEFAULT_DELETE, addApiScenario.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11)
|
||||
public void page() throws Exception {
|
||||
|
|
Loading…
Reference in New Issue