fix(接口测试): 复制的步骤,复制步骤中的文件
--task=1016924 --user=陈建星 复制步骤文件接口-场景未保存时操作-调试等 https://www.tapd.cn/55049933/s/1624392
This commit is contained in:
parent
aeede658ab
commit
e1c14e77c7
|
@ -21,6 +21,7 @@ import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||||
import io.metersphere.project.service.FileModuleService;
|
import io.metersphere.project.service.FileModuleService;
|
||||||
import io.metersphere.sdk.constants.PermissionConstants;
|
import io.metersphere.sdk.constants.PermissionConstants;
|
||||||
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
|
||||||
|
import io.metersphere.sdk.util.JSON;
|
||||||
import io.metersphere.system.dto.OperationHistoryDTO;
|
import io.metersphere.system.dto.OperationHistoryDTO;
|
||||||
import io.metersphere.system.dto.request.OperationHistoryRequest;
|
import io.metersphere.system.dto.request.OperationHistoryRequest;
|
||||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||||
|
@ -154,12 +155,20 @@ public class ApiScenarioController {
|
||||||
return apiScenarioService.getApiScenarioDetailDTO(scenarioId, SessionUtils.getUserId());
|
return apiScenarioService.getApiScenarioDetailDTO(scenarioId, SessionUtils.getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/step/get/un-save")
|
||||||
|
@Operation(summary = "接口测试-接口场景管理-获取未保存的场景步骤详情")
|
||||||
|
@RequiresPermissions(value = {PermissionConstants.PROJECT_API_SCENARIO_UPDATE, PermissionConstants.PROJECT_API_SCENARIO_ADD},
|
||||||
|
logical = Logical.OR)
|
||||||
|
public ApiScenarioUnsavedStepDetailDTO getUnsavedStepDetail(@Validated @RequestBody ApiScenarioStepDetailRequest request) {
|
||||||
|
return apiScenarioService.getUnsavedStepDetail(request);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/step/get/{stepId}")
|
@GetMapping("/step/get/{stepId}")
|
||||||
@Operation(summary = "接口测试-接口场景管理-获取场景步骤详情")
|
@Operation(summary = "接口测试-接口场景管理-获取场景步骤详情")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_SCENARIO_READ)
|
||||||
@CheckOwner(resourceId = "#stepId", resourceType = "api_scenario_step")
|
@CheckOwner(resourceId = "#stepId", resourceType = "api_scenario_step")
|
||||||
public Object getStepDetail(@PathVariable String stepId) {
|
public Object getStepDetail(@PathVariable String stepId) {
|
||||||
return apiScenarioService.getStepDetail(stepId);
|
return JSON.parseObject(JSON.toJSONString(apiScenarioService.getStepDetail(stepId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/step/resource-info/{resourceId}")
|
@GetMapping("/step/resource-info/{resourceId}")
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: jianxing
|
||||||
|
* @CreateTime: 2024-01-10 11:24
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ApiScenarioCopyStepMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* key 的 stepId,value 为 copyFrom 的步骤ID
|
||||||
|
*/
|
||||||
|
private Map<String, String> copyFromStepIdMap;
|
||||||
|
/**
|
||||||
|
* key 的 stepId,value 为 copyFrom 的接口ID
|
||||||
|
*/
|
||||||
|
private Map<String, String> isNewApiResourceMap;
|
||||||
|
/**
|
||||||
|
* key 的 stepId,value 为 copyFrom 的接口用例ID
|
||||||
|
*/
|
||||||
|
private Map<String, String> isNewApiCaseResourceMap;
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||||
|
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||||
|
import io.metersphere.sdk.valid.EnumValue;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ApiScenarioStepDetailRequest {
|
||||||
|
@Schema(description = "步骤id", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
@NotBlank
|
||||||
|
@Size(max = 50, message = "{api_scenario_step.id.length_range}")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录是从哪个步骤复制来的
|
||||||
|
* 如果没有传步骤详情
|
||||||
|
* 保存时需要根据这个字段查询原步骤详情保存
|
||||||
|
*/
|
||||||
|
@Schema(description = "复制的目标步骤ID")
|
||||||
|
@NotBlank
|
||||||
|
private String copyFromStepId;
|
||||||
|
|
||||||
|
@Schema(description = "资源id")
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ApiScenarioStepType}
|
||||||
|
*/
|
||||||
|
@Schema(description = "步骤类型/API/CASE等")
|
||||||
|
@NotBlank
|
||||||
|
@EnumValue(enumClass = ApiScenarioStepType.class)
|
||||||
|
private String stepType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 引用模式:默认完全引用
|
||||||
|
* - 完全引用:步骤状态不可调整
|
||||||
|
* - 部分引用:步骤状态可调整
|
||||||
|
*
|
||||||
|
* @see ApiScenarioStepRefType
|
||||||
|
*/
|
||||||
|
@Schema(description = "引用/复制/自定义")
|
||||||
|
@EnumValue(enumClass = ApiScenarioStepRefType.class)
|
||||||
|
@NotBlank
|
||||||
|
private String refType;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package io.metersphere.api.dto.scenario;
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -9,9 +10,11 @@ public class ApiScenarioStepRequest extends ApiScenarioStepCommonDTO<ApiScenario
|
||||||
* 如果没有传步骤详情
|
* 如果没有传步骤详情
|
||||||
* 保存时需要根据这个字段查询原步骤详情保存
|
* 保存时需要根据这个字段查询原步骤详情保存
|
||||||
*/
|
*/
|
||||||
|
@Schema(description = "复制的目标步骤ID")
|
||||||
private String copyFromStepId;
|
private String copyFromStepId;
|
||||||
/**
|
/**
|
||||||
* 记录当前步骤是否是新增的步骤
|
* 记录当前步骤是否是新增的步骤
|
||||||
*/
|
*/
|
||||||
|
@Schema(description = "当前步骤是否是新增的步骤")
|
||||||
private Boolean isNew;
|
private Boolean isNew;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package io.metersphere.api.dto.scenario;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ApiScenarioUnsavedStepDetailDTO {
|
||||||
|
|
||||||
|
@Schema(description = "步骤详情")
|
||||||
|
private Object detail;
|
||||||
|
|
||||||
|
@Schema(description = "复制的步骤中的本地文件ID集合")
|
||||||
|
private List<String> uploadIds;
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.domain.ApiTestCaseBlob;
|
import io.metersphere.api.domain.ApiTestCaseBlob;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.api.mapper.ApiTestCaseBlobMapper;
|
import io.metersphere.api.mapper.ApiTestCaseBlobMapper;
|
||||||
import io.metersphere.api.utils.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
@ -27,7 +27,7 @@ public class ApiCaseStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
if (isRef(step.getRefType())) {
|
if (isRef(step.getRefType())) {
|
||||||
ApiTestCaseBlobMapper apiTestCaseBlobMapper = CommonBeanFactory.getBean(ApiTestCaseBlobMapper.class);
|
ApiTestCaseBlobMapper apiTestCaseBlobMapper = CommonBeanFactory.getBean(ApiTestCaseBlobMapper.class);
|
||||||
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(step.getResourceId());
|
ApiTestCaseBlob apiTestCaseBlob = apiTestCaseBlobMapper.selectByPrimaryKey(step.getResourceId());
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioBlob;
|
import io.metersphere.api.domain.ApiScenarioBlob;
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.MsScenario;
|
import io.metersphere.api.dto.request.MsScenario;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
import io.metersphere.api.dto.scenario.ScenarioConfig;
|
||||||
import io.metersphere.api.mapper.ApiScenarioBlobMapper;
|
import io.metersphere.api.mapper.ApiScenarioBlobMapper;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
@ -38,7 +38,7 @@ public class ApiScenarioStepParser extends StepParser {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
if (isRef(step.getRefType())) {
|
if (isRef(step.getRefType())) {
|
||||||
ApiScenarioBlobMapper apiScenarioBlobMapper = CommonBeanFactory.getBean(ApiScenarioBlobMapper.class);
|
ApiScenarioBlobMapper apiScenarioBlobMapper = CommonBeanFactory.getBean(ApiScenarioBlobMapper.class);
|
||||||
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(step.getResourceId());
|
ApiScenarioBlob apiScenarioBlob = apiScenarioBlobMapper.selectByPrimaryKey(step.getResourceId());
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiDefinitionBlob;
|
import io.metersphere.api.domain.ApiDefinitionBlob;
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
import io.metersphere.api.dto.request.http.MsHTTPElement;
|
||||||
import io.metersphere.api.dto.request.http.body.Body;
|
import io.metersphere.api.dto.request.http.body.Body;
|
||||||
import io.metersphere.api.dto.request.http.body.FormDataKV;
|
import io.metersphere.api.dto.request.http.body.FormDataKV;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.api.mapper.ApiDefinitionBlobMapper;
|
import io.metersphere.api.mapper.ApiDefinitionBlobMapper;
|
||||||
import io.metersphere.api.utils.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
@ -52,7 +52,7 @@ public class ApiStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
if (isRef(step.getRefType())) {
|
if (isRef(step.getRefType())) {
|
||||||
ApiDefinitionBlobMapper apiDefinitionBlobMapper = CommonBeanFactory.getBean(ApiDefinitionBlobMapper.class);
|
ApiDefinitionBlobMapper apiDefinitionBlobMapper = CommonBeanFactory.getBean(ApiDefinitionBlobMapper.class);
|
||||||
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(step.getResourceId());
|
ApiDefinitionBlob apiDefinitionBlob = apiDefinitionBlobMapper.selectByPrimaryKey(step.getResourceId());
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.controller.MsConstantTimerController;
|
import io.metersphere.api.dto.request.controller.MsConstantTimerController;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
|
||||||
public class ConstantTimerStepParser extends StepParser {
|
public class ConstantTimerStepParser extends StepParser {
|
||||||
|
@ -12,7 +12,7 @@ public class ConstantTimerStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,7 +18,7 @@ public class DefaultStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return parse2MsTestElement(getStepBlobString(step.getId()));
|
return parse2MsTestElement(getStepBlobString(step.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.controller.MsIfController;
|
import io.metersphere.api.dto.request.controller.MsIfController;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
|
||||||
public class IfControllerStepParser extends StepParser {
|
public class IfControllerStepParser extends StepParser {
|
||||||
|
@ -12,7 +12,7 @@ public class IfControllerStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.MsJMeterComponent;
|
import io.metersphere.api.dto.request.MsJMeterComponent;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.api.utils.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ public class JMeterComponentStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.controller.MsLoopController;
|
import io.metersphere.api.dto.request.controller.MsLoopController;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
|
||||||
public class LoopControllerStepParser extends StepParser {
|
public class LoopControllerStepParser extends StepParser {
|
||||||
|
@ -13,7 +13,7 @@ public class LoopControllerStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.dto.request.controller.MsOnceOnlyController;
|
import io.metersphere.api.dto.request.controller.MsOnceOnlyController;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
import io.metersphere.sdk.util.BeanUtils;
|
import io.metersphere.sdk.util.BeanUtils;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ public class OnceOnlyControllerStepParser extends StepParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object parseDetail(ApiScenarioStep step) {
|
public Object parseDetail(ApiScenarioStepDetailRequest step) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package io.metersphere.api.parser.step;
|
package io.metersphere.api.parser.step;
|
||||||
|
|
||||||
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
import io.metersphere.api.constants.ApiScenarioStepRefType;
|
||||||
import io.metersphere.api.domain.ApiScenarioStep;
|
|
||||||
import io.metersphere.api.domain.ApiScenarioStepBlob;
|
import io.metersphere.api.domain.ApiScenarioStepBlob;
|
||||||
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
import io.metersphere.api.dto.scenario.ApiScenarioStepCommonDTO;
|
||||||
|
import io.metersphere.api.dto.scenario.ApiScenarioStepDetailRequest;
|
||||||
import io.metersphere.api.mapper.ApiScenarioStepBlobMapper;
|
import io.metersphere.api.mapper.ApiScenarioStepBlobMapper;
|
||||||
import io.metersphere.api.utils.ApiDataUtils;
|
import io.metersphere.api.utils.ApiDataUtils;
|
||||||
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
||||||
|
@ -37,7 +37,7 @@ public abstract class StepParser {
|
||||||
* @param step
|
* @param step
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public abstract Object parseDetail(ApiScenarioStep step);
|
public abstract Object parseDetail(ApiScenarioStepDetailRequest step);
|
||||||
|
|
||||||
|
|
||||||
protected boolean isRef(String refType) {
|
protected boolean isRef(String refType) {
|
||||||
|
|
|
@ -28,10 +28,7 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: jianxing
|
* @Author: jianxing
|
||||||
|
@ -400,4 +397,9 @@ public class ApiFileResourceService {
|
||||||
return fileId;
|
return fileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ApiFileResource> selectByResourceIds(Collection<String> copyFromStepIds) {
|
||||||
|
ApiFileResourceExample example = new ApiFileResourceExample();
|
||||||
|
example.createCriteria().andResourceIdIn(new ArrayList<>(copyFromStepIds));
|
||||||
|
return apiFileResourceMapper.selectByExample(example);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,7 +443,7 @@ public class ApiScenarioDataTransferService {
|
||||||
|
|
||||||
scenarioCsvSteps = apiScenarioService.filterNotExistCsv(request.getScenarioConfig(), scenarioCsvSteps);
|
scenarioCsvSteps = apiScenarioService.filterNotExistCsv(request.getScenarioConfig(), scenarioCsvSteps);
|
||||||
this.saveStepCsv(scenarioId, scenarioCsvSteps, csvStepBatchMapper);
|
this.saveStepCsv(scenarioId, scenarioCsvSteps, csvStepBatchMapper);
|
||||||
// apiScenarioService.
|
|
||||||
// 获取待更新的步骤详情
|
// 获取待更新的步骤详情
|
||||||
apiScenarioService.addSpecialStepDetails(steps, request.getStepDetails());
|
apiScenarioService.addSpecialStepDetails(steps, request.getStepDetails());
|
||||||
List<ApiScenarioStepBlob> updateStepBlobs = apiScenarioService.getUpdateStepBlobs(apiScenarioSteps, request.getStepDetails());
|
List<ApiScenarioStepBlob> updateStepBlobs = apiScenarioService.getUpdateStepBlobs(apiScenarioSteps, request.getStepDetails());
|
||||||
|
|
|
@ -125,7 +125,9 @@ public class ApiScenarioRunService {
|
||||||
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
|
apiScenarioService.handleRefUpgradeFile(csvVariables, dbCsv);
|
||||||
|
|
||||||
// 处理特殊的步骤详情
|
// 处理特殊的步骤详情
|
||||||
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
ApiScenarioCopyStepMap apiScenarioCopyStepMap = apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||||
|
// 处理copy的步骤文件
|
||||||
|
apiScenarioService.handleRunCopyStepFiles(request, apiScenarioCopyStepMap, request.getStepDetails());
|
||||||
|
|
||||||
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
ApiResourceRunRequest runRequest = new ApiResourceRunRequest();
|
||||||
runRequest = setFileParam(request, runRequest);
|
runRequest = setFileParam(request, runRequest);
|
||||||
|
@ -420,7 +422,9 @@ public class ApiScenarioRunService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理特殊的步骤详情
|
// 处理特殊的步骤详情
|
||||||
apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
ApiScenarioCopyStepMap apiScenarioCopyStepMap = apiScenarioService.addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||||
|
// 处理copy的步骤文件
|
||||||
|
apiScenarioService.handleRunCopyStepFiles(request, apiScenarioCopyStepMap, request.getStepDetails());
|
||||||
|
|
||||||
ApiScenarioParseTmpParam tmpParam = parse(msScenario, request.getSteps(), request);
|
ApiScenarioParseTmpParam tmpParam = parse(msScenario, request.getSteps(), request);
|
||||||
|
|
||||||
|
@ -983,7 +987,7 @@ public class ApiScenarioRunService {
|
||||||
|
|
||||||
// 记录引用的资源ID和项目ID,下载执行文件时需要使用
|
// 记录引用的资源ID和项目ID,下载执行文件时需要使用
|
||||||
parseParam.getRefProjectIds().add(step.getProjectId());
|
parseParam.getRefProjectIds().add(step.getProjectId());
|
||||||
if (apiScenarioService.isRefOrPartialRef(step.getRefType())) {
|
if (apiScenarioService.isRefOrPartialRef(step.getRefType()) && !apiScenarioService.isRefApi(step.getStepType(), step.getRefType())) {
|
||||||
// 引用的步骤记录引用的资源ID
|
// 引用的步骤记录引用的资源ID
|
||||||
parseParam.getFileResourceIds().add(step.getResourceId());
|
parseParam.getFileResourceIds().add(step.getResourceId());
|
||||||
} else if (msTestElement instanceof MsHTTPElement) {
|
} else if (msTestElement instanceof MsHTTPElement) {
|
||||||
|
|
|
@ -178,8 +178,6 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
public static final String SCHEDULE = "Schedule";
|
public static final String SCHEDULE = "Schedule";
|
||||||
private static final String SCENARIO_TABLE = "api_scenario";
|
private static final String SCENARIO_TABLE = "api_scenario";
|
||||||
private static final String SCENARIO = "SCENARIO";
|
private static final String SCENARIO = "SCENARIO";
|
||||||
@Resource
|
|
||||||
private ApiReportRelateTaskMapper apiReportRelateTaskMapper;
|
|
||||||
|
|
||||||
|
|
||||||
public List<ApiScenarioDTO> getScenarioPage(ApiScenarioPageRequest request, boolean isRepeat, String testPlanId) {
|
public List<ApiScenarioDTO> getScenarioPage(ApiScenarioPageRequest request, boolean isRepeat, String testPlanId) {
|
||||||
|
@ -468,7 +466,10 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
List<ApiScenarioStep> steps = getApiScenarioSteps(null, request.getSteps(), csvSteps);
|
List<ApiScenarioStep> steps = getApiScenarioSteps(null, request.getSteps(), csvSteps);
|
||||||
steps.forEach(step -> step.setScenarioId(scenario.getId()));
|
steps.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||||
// 处理特殊的步骤详情
|
// 处理特殊的步骤详情
|
||||||
addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
ApiScenarioCopyStepMap apiScenarioCopyStepMap = addSpecialStepDetails(request.getSteps(), request.getStepDetails());
|
||||||
|
// 处理copy的步骤文件
|
||||||
|
handleSaveCopyStepFiles(apiScenarioCopyStepMap, request.getStepDetails(), scenario);
|
||||||
|
|
||||||
List<ApiScenarioStepBlob> apiScenarioStepBlobs = getUpdateStepBlobs(steps, request.getStepDetails());
|
List<ApiScenarioStepBlob> apiScenarioStepBlobs = getUpdateStepBlobs(steps, request.getStepDetails());
|
||||||
apiScenarioStepBlobs.forEach(step -> step.setScenarioId(scenario.getId()));
|
apiScenarioStepBlobs.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||||
|
|
||||||
|
@ -844,8 +845,12 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
|
|
||||||
scenarioCsvSteps = filterNotExistCsv(request.getScenarioConfig(), scenarioCsvSteps);
|
scenarioCsvSteps = filterNotExistCsv(request.getScenarioConfig(), scenarioCsvSteps);
|
||||||
saveStepCsv(scenario.getId(), scenarioCsvSteps);
|
saveStepCsv(scenario.getId(), scenarioCsvSteps);
|
||||||
|
|
||||||
// 获取待更新的步骤详情
|
// 获取待更新的步骤详情
|
||||||
addSpecialStepDetails(steps, request.getStepDetails());
|
ApiScenarioCopyStepMap apiScenarioCopyStepMap = addSpecialStepDetails(steps, request.getStepDetails());
|
||||||
|
// 处理copy的步骤文件
|
||||||
|
handleSaveCopyStepFiles(apiScenarioCopyStepMap, request.getStepDetails(), scenario);
|
||||||
|
|
||||||
List<ApiScenarioStepBlob> updateStepBlobs = getUpdateStepBlobs(apiScenarioSteps, request.getStepDetails());
|
List<ApiScenarioStepBlob> updateStepBlobs = getUpdateStepBlobs(apiScenarioSteps, request.getStepDetails());
|
||||||
updateStepBlobs.forEach(step -> step.setScenarioId(scenario.getId()));
|
updateStepBlobs.forEach(step -> step.setScenarioId(scenario.getId()));
|
||||||
|
|
||||||
|
@ -1041,9 +1046,9 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
* copyFromStepId 的 detail
|
* copyFromStepId 的 detail
|
||||||
* isNew 的资源的 detail
|
* isNew 的资源的 detail
|
||||||
*/
|
*/
|
||||||
public void addSpecialStepDetails(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetails) {
|
public ApiScenarioCopyStepMap addSpecialStepDetails(List<ApiScenarioStepRequest> steps, Map<String, Object> stepDetails) {
|
||||||
if (CollectionUtils.isEmpty(steps)) {
|
if (CollectionUtils.isEmpty(steps)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// key 的 stepId,value 为 copyFrom 的步骤ID
|
// key 的 stepId,value 为 copyFrom 的步骤ID
|
||||||
|
@ -1107,6 +1112,287 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
apiScenarioStepBlobMapper.selectByExampleWithBLOBs(example)
|
apiScenarioStepBlobMapper.selectByExampleWithBLOBs(example)
|
||||||
.forEach(scenarioStepBlob -> copyFromBlobMap.put(scenarioStepBlob.getId(), scenarioStepBlob.getContent()));
|
.forEach(scenarioStepBlob -> copyFromBlobMap.put(scenarioStepBlob.getId(), scenarioStepBlob.getContent()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ApiScenarioCopyStepMap apiScenarioCopyStepMap = new ApiScenarioCopyStepMap();
|
||||||
|
apiScenarioCopyStepMap.setCopyFromStepIdMap(copyFromStepIdMap);
|
||||||
|
apiScenarioCopyStepMap.setIsNewApiResourceMap(isNewApiResourceMap);
|
||||||
|
apiScenarioCopyStepMap.setIsNewApiCaseResourceMap(isNewApiCaseResourceMap);
|
||||||
|
return apiScenarioCopyStepMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理保存时,copy的步骤中文件
|
||||||
|
* @param apiScenarioCopyStepMap
|
||||||
|
* @param stepDetails
|
||||||
|
*/
|
||||||
|
public void handleSaveCopyStepFiles(ApiScenarioCopyStepMap apiScenarioCopyStepMap, Map<String, Object> stepDetails, ApiScenario scenario) {
|
||||||
|
try {
|
||||||
|
List<ApiFileResource> apiFileResources = new ArrayList<>();
|
||||||
|
apiFileResources.addAll(handleCopyFromStepFiles(stepDetails, apiScenarioCopyStepMap.getCopyFromStepIdMap(), scenario));
|
||||||
|
apiFileResources.addAll(handleCopyApiFiles(stepDetails, apiScenarioCopyStepMap.getIsNewApiResourceMap(), scenario));
|
||||||
|
apiFileResources.addAll(handleCopyApiCaseFiles(stepDetails, apiScenarioCopyStepMap.getIsNewApiCaseResourceMap(), scenario));
|
||||||
|
if (CollectionUtils.isNotEmpty(apiFileResources)) {
|
||||||
|
// 插入步骤和文件的关联关系
|
||||||
|
apiFileResources.forEach(apiFileResource -> apiFileResource.setProjectId(scenario.getProjectId()));
|
||||||
|
apiFileResourceMapper.batchInsert(apiFileResources);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理调试执行时,copy的步骤中文件
|
||||||
|
* @param debugRequest
|
||||||
|
* @param apiScenarioCopyStepMap
|
||||||
|
* @param stepDetails
|
||||||
|
*/
|
||||||
|
public void handleRunCopyStepFiles(ApiScenarioDebugRequest debugRequest, ApiScenarioCopyStepMap apiScenarioCopyStepMap, Map<String, Object> stepDetails) {
|
||||||
|
try {
|
||||||
|
List<ApiFileResource> apiFileResources = new ArrayList<>();
|
||||||
|
apiFileResources.addAll(handleCopyFromStepFiles(stepDetails, apiScenarioCopyStepMap.getCopyFromStepIdMap(), null));
|
||||||
|
apiFileResources.addAll(handleCopyApiFiles(stepDetails, apiScenarioCopyStepMap.getIsNewApiResourceMap(), null));
|
||||||
|
apiFileResources.addAll(handleCopyApiCaseFiles(stepDetails, apiScenarioCopyStepMap.getIsNewApiCaseResourceMap(), null));
|
||||||
|
|
||||||
|
if (debugRequest.getStepFileParam() == null) {
|
||||||
|
debugRequest.setStepFileParam(new HashMap<>());
|
||||||
|
}
|
||||||
|
// 将copy的步骤中的文件设置为新上传的临时文件,执行时从临时目录获取
|
||||||
|
Map<String, ResourceAddFileParam> stepFileParam = debugRequest.getStepFileParam();
|
||||||
|
for (ApiFileResource apiFileResource : apiFileResources) {
|
||||||
|
stepFileParam.putIfAbsent(apiFileResource.getResourceId(), new ResourceAddFileParam());
|
||||||
|
ResourceAddFileParam resourceAddFileParam = stepFileParam.get(apiFileResource.getResourceId());
|
||||||
|
if (resourceAddFileParam.getUploadFileIds() == null) {
|
||||||
|
resourceAddFileParam.setUploadFileIds(new ArrayList<>());
|
||||||
|
}
|
||||||
|
resourceAddFileParam.getUploadFileIds().add(apiFileResource.getFileId());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 copy 的步骤中的文件
|
||||||
|
* 复制文件
|
||||||
|
* 创建关联关系
|
||||||
|
* 替换文件ID
|
||||||
|
* @param stepDetails
|
||||||
|
* @param copyFromStepIdMap
|
||||||
|
*/
|
||||||
|
private List<ApiFileResource> handleCopyFromStepFiles(Map<String, Object> stepDetails, Map<String, String> copyFromStepIdMap, ApiScenario scenario) {
|
||||||
|
if (copyFromStepIdMap.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
// 查询 copyFrom 的步骤所关联的文件
|
||||||
|
Collection<String> copyFromStepIds = copyFromStepIdMap.values();
|
||||||
|
List<ApiFileResource> apiFileResources = apiFileResourceService.selectByResourceIds(copyFromStepIds);
|
||||||
|
if (apiFileResources.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
Map<String, List<ApiFileResource>> stepFileMap = apiFileResources.stream().collect(Collectors.groupingBy(ApiFileResource::getResourceId));
|
||||||
|
|
||||||
|
// 查询 copyFrom 步骤的场景ID Map
|
||||||
|
List<String> hasFileCopyFromStepIds = stepFileMap.keySet().stream().toList();
|
||||||
|
Map<String, String> copyFromStepScenarioMap = getApiScenarioStepByIds(hasFileCopyFromStepIds).stream()
|
||||||
|
.collect(Collectors.toMap(ApiScenarioStep::getId, ApiScenarioStep::getScenarioId));
|
||||||
|
|
||||||
|
Map<String, String> fileIdMap = new HashMap<>();
|
||||||
|
List<ApiFileResource> newApiFileResources = new ArrayList<>();
|
||||||
|
for (String stepId : copyFromStepIdMap.keySet()) {
|
||||||
|
List<ApiFileResource> originApiFileResources = stepFileMap.get(copyFromStepIdMap.get(stepId));
|
||||||
|
if (CollectionUtils.isEmpty(originApiFileResources)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isSave = scenario != null;
|
||||||
|
|
||||||
|
String newFileId = IDGenerator.nextStr();
|
||||||
|
for (ApiFileResource originApiFileResource : originApiFileResources) {
|
||||||
|
String sourceDir = DefaultRepositoryDir.getApiScenarioStepDir(originApiFileResource.getProjectId(),
|
||||||
|
copyFromStepScenarioMap.get(originApiFileResource.getResourceId()), originApiFileResource.getResourceId());
|
||||||
|
|
||||||
|
// 如果是保存,则copy到正式目录,如果是执行,则copy到临时目录
|
||||||
|
String targetDir = isSave ? DefaultRepositoryDir.getApiScenarioStepDir(scenario.getProjectId(), scenario.getId(), stepId)
|
||||||
|
: DefaultRepositoryDir.getSystemTempDir();
|
||||||
|
|
||||||
|
// 复制文件
|
||||||
|
apiFileResourceService.copyFile(sourceDir + "/" + originApiFileResource.getFileId(),
|
||||||
|
targetDir + "/" + newFileId,
|
||||||
|
originApiFileResource.getFileName());
|
||||||
|
|
||||||
|
// 记录步骤和文件信息
|
||||||
|
ApiFileResource newApiFileResource = getStepApiFileResource(stepId, newFileId, originApiFileResource.getFileName());
|
||||||
|
newApiFileResources.add(newApiFileResource);
|
||||||
|
|
||||||
|
// 记录文件ID映射
|
||||||
|
fileIdMap.put(originApiFileResource.getFileId(), newFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换详情中的文件ID
|
||||||
|
replaceCopyStepFileId(stepDetails, fileIdMap, stepId);
|
||||||
|
}
|
||||||
|
return newApiFileResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理复制的接口定义步骤中的文件
|
||||||
|
* 复制文件
|
||||||
|
* 创建关联关系
|
||||||
|
* 替换文件ID
|
||||||
|
* @param stepDetails
|
||||||
|
*/
|
||||||
|
private List<ApiFileResource> handleCopyApiFiles(Map<String, Object> stepDetails, Map<String, String> copyApiIdMap, ApiScenario scenario) {
|
||||||
|
if (copyApiIdMap.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
// 查询 copy 的接口定义所关联的文件
|
||||||
|
Collection<String> copyApiIds = copyApiIdMap.values();
|
||||||
|
List<ApiFileResource> apiFileResources = apiFileResourceService.selectByResourceIds(copyApiIds);
|
||||||
|
if (apiFileResources.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
Map<String, List<ApiFileResource>> stepFileMap = apiFileResources.stream().collect(Collectors.groupingBy(ApiFileResource::getResourceId));
|
||||||
|
|
||||||
|
Map<String, String> fileIdMap = new HashMap<>();
|
||||||
|
List<ApiFileResource> newApiFileResources = new ArrayList<>();
|
||||||
|
for (String stepId : copyApiIdMap.keySet()) {
|
||||||
|
List<ApiFileResource> originApiFileResources = stepFileMap.get(copyApiIdMap.get(stepId));
|
||||||
|
if (CollectionUtils.isEmpty(originApiFileResources)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String newFileId = IDGenerator.nextStr();
|
||||||
|
for (ApiFileResource originApiFileResource : originApiFileResources) {
|
||||||
|
String sourceDir = DefaultRepositoryDir.getApiDefinitionDir(originApiFileResource.getProjectId(), originApiFileResource.getResourceId());
|
||||||
|
|
||||||
|
boolean isSave = scenario != null;
|
||||||
|
|
||||||
|
// 如果是保存,则copy到正式目录,如果是执行,则copy到临时目录
|
||||||
|
String targetDir = isSave ? DefaultRepositoryDir.getApiScenarioStepDir(scenario.getProjectId(), scenario.getId(), stepId)
|
||||||
|
: DefaultRepositoryDir.getSystemTempDir();
|
||||||
|
|
||||||
|
// 复制文件
|
||||||
|
apiFileResourceService.copyFile(sourceDir + "/" + originApiFileResource.getFileId(),
|
||||||
|
targetDir + "/" + newFileId,
|
||||||
|
originApiFileResource.getFileName());
|
||||||
|
|
||||||
|
// 记录步骤和文件信息
|
||||||
|
ApiFileResource newApiFileResource = getStepApiFileResource(stepId, newFileId, originApiFileResource.getFileName());
|
||||||
|
newApiFileResources.add(newApiFileResource);
|
||||||
|
|
||||||
|
// 记录文件ID映射
|
||||||
|
fileIdMap.put(originApiFileResource.getFileId(), newFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换详情中的文件ID
|
||||||
|
replaceCopyStepFileId(stepDetails, fileIdMap, stepId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newApiFileResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理复制的接口用例步骤中的文件
|
||||||
|
* 复制文件
|
||||||
|
* 创建关联关系
|
||||||
|
* 替换文件ID
|
||||||
|
* @param stepDetails
|
||||||
|
*/
|
||||||
|
private List<ApiFileResource> handleCopyApiCaseFiles(Map<String, Object> stepDetails, Map<String, String> copyApiCaseIdMap, ApiScenario scenario) {
|
||||||
|
if (copyApiCaseIdMap.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
// 查询 copy 的接口定义所关联的文件
|
||||||
|
Collection<String> copyApiIds = copyApiCaseIdMap.values();
|
||||||
|
List<ApiFileResource> apiFileResources = apiFileResourceService.selectByResourceIds(copyApiIds);
|
||||||
|
if (apiFileResources.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
Map<String, List<ApiFileResource>> stepFileMap = apiFileResources.stream().collect(Collectors.groupingBy(ApiFileResource::getResourceId));
|
||||||
|
|
||||||
|
boolean isSave = scenario != null;
|
||||||
|
Map<String, String> fileIdMap = new HashMap<>();
|
||||||
|
List<ApiFileResource> newApiFileResources = new ArrayList<>();
|
||||||
|
for (String stepId : copyApiCaseIdMap.keySet()) {
|
||||||
|
List<ApiFileResource> originApiFileResources = stepFileMap.get(copyApiCaseIdMap.get(stepId));
|
||||||
|
if (CollectionUtils.isEmpty(originApiFileResources)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String newFileId = IDGenerator.nextStr();
|
||||||
|
for (ApiFileResource originApiFileResource : originApiFileResources) {
|
||||||
|
String sourceDir = DefaultRepositoryDir.getApiCaseDir(originApiFileResource.getProjectId(), originApiFileResource.getResourceId());
|
||||||
|
|
||||||
|
// 如果是保存,则copy到正式目录,如果是执行,则copy到临时目录
|
||||||
|
String targetDir = isSave ? DefaultRepositoryDir.getApiScenarioStepDir(scenario.getProjectId(), scenario.getId(), stepId)
|
||||||
|
: DefaultRepositoryDir.getSystemTempDir();
|
||||||
|
|
||||||
|
// 复制文件
|
||||||
|
apiFileResourceService.copyFile(sourceDir + "/" + originApiFileResource.getFileId(),
|
||||||
|
targetDir + "/" + newFileId,
|
||||||
|
originApiFileResource.getFileName());
|
||||||
|
|
||||||
|
// 记录步骤和文件信息
|
||||||
|
ApiFileResource newApiFileResource = getStepApiFileResource(stepId, newFileId, originApiFileResource.getFileName());
|
||||||
|
newApiFileResources.add(newApiFileResource);
|
||||||
|
|
||||||
|
// 记录文件ID映射
|
||||||
|
fileIdMap.put(originApiFileResource.getFileId(), newFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换详情中的文件ID
|
||||||
|
replaceCopyStepFileId(stepDetails, fileIdMap, stepId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newApiFileResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换复制的步骤中详情的文件ID
|
||||||
|
* @param stepDetails
|
||||||
|
* @param fileIdMap
|
||||||
|
* @param stepId
|
||||||
|
*/
|
||||||
|
private void replaceCopyStepFileId(Map<String, Object> stepDetails, Map<String, String> fileIdMap, String stepId) {
|
||||||
|
Object stepDetail = stepDetails.get(stepId);
|
||||||
|
if (stepDetail != null) {
|
||||||
|
// 替换详情中的文件ID
|
||||||
|
if (stepDetail instanceof byte[] detailBytes) {
|
||||||
|
AbstractMsTestElement msTestElement = getAbstractMsTestElement(detailBytes);
|
||||||
|
for (ApiFile apiFile : apiCommonService.getApiFiles(msTestElement)) {
|
||||||
|
if (fileIdMap.get(apiFile.getFileId()) != null) {
|
||||||
|
apiFile.setFileId(fileIdMap.get(apiFile.getFileId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stepDetails.put(stepId, msTestElement);
|
||||||
|
} else if (stepDetail instanceof AbstractMsTestElement msTestElement) {
|
||||||
|
for (ApiFile apiFile : apiCommonService.getApiFiles(msTestElement)) {
|
||||||
|
if (fileIdMap.get(apiFile.getFileId()) != null) {
|
||||||
|
apiFile.setFileId(fileIdMap.get(apiFile.getFileId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiFileResource getStepApiFileResource(String stepId, String fileId, String fileName) {
|
||||||
|
ApiFileResource apiFileResource = new ApiFileResource();
|
||||||
|
apiFileResource.setFileId(fileId);
|
||||||
|
apiFileResource.setResourceId(stepId);
|
||||||
|
apiFileResource.setResourceType(ApiFileResourceType.API_SCENARIO_STEP.name());
|
||||||
|
apiFileResource.setCreateTime(System.currentTimeMillis());
|
||||||
|
apiFileResource.setFileName(fileName);
|
||||||
|
return apiFileResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ApiScenarioStep> getApiScenarioStepByIds(List<String> stepIds) {
|
||||||
|
if (CollectionUtils.isEmpty(stepIds)) {
|
||||||
|
List.of();
|
||||||
|
}
|
||||||
|
ApiScenarioStepExample example = new ApiScenarioStepExample();
|
||||||
|
example.createCriteria().andIdIn(stepIds);
|
||||||
|
return apiScenarioStepMapper.selectByExample(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1698,7 +1984,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
* 判断步骤是否是引用的接口定义
|
* 判断步骤是否是引用的接口定义
|
||||||
* 引用的接口定义允许修改参数值,需要特殊处理
|
* 引用的接口定义允许修改参数值,需要特殊处理
|
||||||
*/
|
*/
|
||||||
private boolean isRefApi(String stepType, String refType) {
|
public boolean isRefApi(String stepType, String refType) {
|
||||||
return isApi(stepType) && StringUtils.equals(refType, ApiScenarioStepRefType.REF.name());
|
return isApi(stepType) && StringUtils.equals(refType, ApiScenarioStepRefType.REF.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1881,6 +2167,10 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
|
|
||||||
public Object getStepDetail(String stepId) {
|
public Object getStepDetail(String stepId) {
|
||||||
ApiScenarioStep step = apiScenarioStepMapper.selectByPrimaryKey(stepId);
|
ApiScenarioStep step = apiScenarioStepMapper.selectByPrimaryKey(stepId);
|
||||||
|
return getStepDetail(BeanUtils.copyBean(new ApiScenarioStepDetailRequest(), step));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getStepDetail(ApiScenarioStepDetailRequest step) {
|
||||||
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
|
StepParser stepParser = StepParserFactory.getStepParser(step.getStepType());
|
||||||
Object stepDetail = stepParser.parseDetail(step);
|
Object stepDetail = stepParser.parseDetail(step);
|
||||||
if (stepDetail instanceof MsScriptElement msScriptElement) {
|
if (stepDetail instanceof MsScriptElement msScriptElement) {
|
||||||
|
@ -1900,7 +2190,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
apiCommonService.setLinkFileInfo(step.getId(), msTestElement);
|
apiCommonService.setLinkFileInfo(step.getId(), msTestElement);
|
||||||
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
|
apiCommonService.setEnableCommonScriptProcessorInfo(msTestElement);
|
||||||
}
|
}
|
||||||
return JSON.parseObject(JSON.toJSONString(stepDetail));
|
return stepDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkTargetModule(String targetModuleId, String projectId) {
|
private void checkTargetModule(String targetModuleId, String projectId) {
|
||||||
|
@ -2387,13 +2677,7 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractMsTestElement msTestElement = null;
|
AbstractMsTestElement msTestElement = getAbstractMsTestElement(apiScenarioStepBlob.getContent());
|
||||||
try {
|
|
||||||
msTestElement = ApiDataUtils.parseObject(new String(apiScenarioStepBlob.getContent()), AbstractMsTestElement.class);
|
|
||||||
// 如果插件删除,会转换异常
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtils.error(e);
|
|
||||||
}
|
|
||||||
if (msTestElement != null && msTestElement instanceof MsHTTPElement msHTTPElement) {
|
if (msTestElement != null && msTestElement instanceof MsHTTPElement msHTTPElement) {
|
||||||
List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msHTTPElement);
|
List<ApiFile> updateFiles = apiCommonService.getApiFilesByFileId(originFileAssociation.getFileId(), msHTTPElement);
|
||||||
// 替换文件的Id和name
|
// 替换文件的Id和name
|
||||||
|
@ -2406,6 +2690,20 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AbstractMsTestElement getAbstractMsTestElement(byte[] msTestElementByte) {
|
||||||
|
return getAbstractMsTestElement(new String(msTestElementByte));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbstractMsTestElement getAbstractMsTestElement(String msTestElementStr) {
|
||||||
|
try {
|
||||||
|
return ApiDataUtils.parseObject(msTestElementStr, AbstractMsTestElement.class);
|
||||||
|
// 如果插件删除,会转换异常
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.error(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public void handleScenarioFileAssociationUpgrade(FileAssociation originFileAssociation, FileMetadata newFileMetadata) {
|
public void handleScenarioFileAssociationUpgrade(FileAssociation originFileAssociation, FileMetadata newFileMetadata) {
|
||||||
String scenarioId = originFileAssociation.getSourceId();
|
String scenarioId = originFileAssociation.getSourceId();
|
||||||
// 查询步骤详情
|
// 查询步骤详情
|
||||||
|
@ -2680,4 +2978,78 @@ public class ApiScenarioService extends MoveNodeService {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未保存过的步骤的详情
|
||||||
|
* @param request
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ApiScenarioUnsavedStepDetailDTO getUnsavedStepDetail(ApiScenarioStepDetailRequest request) {
|
||||||
|
ApiScenarioStep step = apiScenarioStepMapper.selectByPrimaryKey(request.getId());
|
||||||
|
if (step == null) {
|
||||||
|
ApiScenarioUnsavedStepDetailDTO result = new ApiScenarioUnsavedStepDetailDTO();
|
||||||
|
ApiScenarioStepDetailRequest getDetailRequest = BeanUtils.copyBean(new ApiScenarioStepDetailRequest(), request);
|
||||||
|
if (StringUtils.isNotBlank(request.getCopyFromStepId())) {
|
||||||
|
// 从已有步骤复制,则获取复制步骤的详情
|
||||||
|
ApiScenarioStep copyFromStep = apiScenarioStepMapper.selectByPrimaryKey(request.getCopyFromStepId());
|
||||||
|
getDetailRequest = BeanUtils.copyBean(new ApiScenarioStepDetailRequest(), copyFromStep);
|
||||||
|
}
|
||||||
|
Object stepDetail = getStepDetail(getDetailRequest);
|
||||||
|
List<String> uploadFileIds = uploadCopyStepLocalFiles(request, stepDetail);
|
||||||
|
result.setDetail(JSON.parseObject(JSON.toJSONString(stepDetail)));
|
||||||
|
result.setUploadIds(uploadFileIds);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
throw new MSException("步骤已存在,请调用 /api/scenario/step/get/{stepId} 接口获取详情");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制的步骤,将步骤中的文件上传
|
||||||
|
* 并替换文件ID
|
||||||
|
* @param request
|
||||||
|
* @param stepDetail
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<String> uploadCopyStepLocalFiles(ApiScenarioStepDetailRequest request, Object stepDetail) {
|
||||||
|
if (stepDetail instanceof AbstractMsTestElement stepMsTestElement) {
|
||||||
|
List<ApiFile> localFiles = apiCommonService.getApiFiles(stepMsTestElement)
|
||||||
|
.stream()
|
||||||
|
.filter(file -> BooleanUtils.isTrue(file.getLocal()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isNotEmpty(localFiles)) {
|
||||||
|
List<String> uploadFileIds = new ArrayList<>();
|
||||||
|
String sourceDir = null;
|
||||||
|
String stepType = request.getStepType();
|
||||||
|
String resourceId = request.getResourceId();
|
||||||
|
if (StringUtils.isNotBlank(request.getCopyFromStepId())) {
|
||||||
|
// 从已有步骤复制,则获取复制步骤的文件
|
||||||
|
ApiScenarioStep copyFromStep = apiScenarioStepMapper.selectByPrimaryKey(request.getCopyFromStepId());
|
||||||
|
sourceDir = DefaultRepositoryDir.getApiScenarioStepDir(copyFromStep.getProjectId(),
|
||||||
|
copyFromStep.getScenarioId(), copyFromStep.getId());
|
||||||
|
} else if (StringUtils.equals(stepType, ApiScenarioStepType.API.name())) {
|
||||||
|
// 获取接口定义相关的文件
|
||||||
|
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(resourceId);
|
||||||
|
sourceDir = DefaultRepositoryDir.getApiDefinitionDir(apiDefinition.getProjectId(),
|
||||||
|
apiDefinition.getId());
|
||||||
|
} else if (StringUtils.equals(stepType, ApiScenarioStepType.API_CASE.name())) {
|
||||||
|
// 获取接口用例相关的文件
|
||||||
|
ApiTestCase apiTestCase = apiTestCaseMapper.selectByPrimaryKey(resourceId);
|
||||||
|
sourceDir = DefaultRepositoryDir.getApiCaseDir(apiTestCase.getProjectId(),
|
||||||
|
apiTestCase.getId());
|
||||||
|
}
|
||||||
|
// 复制的步骤将文件复制到临时目录,并且保存新的文件ID
|
||||||
|
for (ApiFile localFile : localFiles) {
|
||||||
|
String newFileId = IDGenerator.nextStr();
|
||||||
|
String targetDir = DefaultRepositoryDir.getSystemTempDir();
|
||||||
|
// 复制文件到临时目录
|
||||||
|
apiFileResourceService.copyFile(sourceDir + "/" + localFile.getFileId(),
|
||||||
|
targetDir + "/" + newFileId,
|
||||||
|
localFile.getFileName());
|
||||||
|
localFile.setFileId(newFileId);
|
||||||
|
uploadFileIds.add(newFileId);
|
||||||
|
}
|
||||||
|
return uploadFileIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue