feat(接口测试): 场景MS格式导入-全量数据导入 (#33723)
* feat(接口测试): 场景MS格式导入-全量数据导入 * feat(接口测试): 场景MS格式导入-全量数据导入 --------- Co-authored-by: Jianguo-Genius <herman.song.yang@gmail.com>
This commit is contained in:
parent
176801e843
commit
fdbdb44364
|
@ -22,7 +22,6 @@ public class ApiScenarioImportParseResult {
|
|||
@Schema(description = "有关联关系的场景")
|
||||
List<ApiScenarioImportDetail> relatedScenarioList = new ArrayList<>();
|
||||
|
||||
|
||||
@Schema(description = "场景CSV相关的数据")
|
||||
private List<ApiScenarioCsv> apiScenarioCsvList = new ArrayList<>();
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.metersphere.api.dto.converter;
|
||||
|
||||
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioImportDetail;
|
||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
@ -12,7 +13,7 @@ import java.util.List;
|
|||
public class ApiScenarioPreImportAnalysisResult {
|
||||
|
||||
@Schema(description = "需要创建的模块数据")
|
||||
List<BaseTreeNode> insertModuleList = new ArrayList<>();
|
||||
List<BaseTreeNode> insertScenarioModuleList = new ArrayList<>();
|
||||
|
||||
@Schema(description = "需要新增的场景")
|
||||
List<ApiScenarioImportDetail> insertApiScenarioData = new ArrayList<>();
|
||||
|
@ -20,4 +21,24 @@ public class ApiScenarioPreImportAnalysisResult {
|
|||
@Schema(description = "需要更新的场景")
|
||||
List<ApiScenarioImportDetail> updateApiScenarioData = new ArrayList<>();
|
||||
|
||||
@Schema(description = "需要新增的接口定义, ID已经生成好")
|
||||
private List<ApiDefinitionDetail> insertApiDefinitions = new ArrayList<>();
|
||||
|
||||
@Schema(description = "需要新增的接口定义模块")
|
||||
private List<BaseTreeNode> insertApiModuleList = new ArrayList<>();
|
||||
|
||||
@Schema(description = "需要新增的接口用例, ID已经生成好")
|
||||
private List<ApiTestCaseDTO> insertApiTestCaseList = new ArrayList<>();
|
||||
|
||||
public void setApiDefinition(ApiDefinitionDetail insertApi) {
|
||||
this.insertApiDefinitions.add(insertApi);
|
||||
}
|
||||
|
||||
public void setApiTestCase(ApiTestCaseDTO insertCase) {
|
||||
this.insertApiTestCaseList.add(insertCase);
|
||||
}
|
||||
|
||||
public void setApiScenario(ApiScenarioImportDetail insertScenario) {
|
||||
this.insertApiScenarioData.add(insertScenario);
|
||||
}
|
||||
}
|
|
@ -30,9 +30,30 @@ public class ApiTestCaseWithBlob extends ApiTestCaseBlob {
|
|||
@Size(min = 1, max = 20, message = "{api_test_case.status.length_range}", groups = {Created.class, Updated.class})
|
||||
private String status;
|
||||
|
||||
@Schema(description = "api的协议")
|
||||
private String protocol;
|
||||
@Schema(description = "api的路径")
|
||||
private String path;
|
||||
@Schema(description = "api的方法")
|
||||
private String method;
|
||||
@Schema(description = "模块ID")
|
||||
private String moduleId;
|
||||
|
||||
@Schema(description = "最新执行结果状态")
|
||||
private String lastReportStatus;
|
||||
|
||||
@Schema(description = "接口定义ID")
|
||||
private String apiDefinitionId;
|
||||
|
||||
@Schema(description = "接口定义名称")
|
||||
private String apiDefinitionName;
|
||||
|
||||
@Schema(description = "接口用例编号id")
|
||||
private Long num;
|
||||
|
||||
@Schema(description = "项目fk", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{api_test_case.project_id.not_blank}", groups = {Created.class})
|
||||
@Size(min = 1, max = 50, message = "{api_test_case.project_id.length_range}", groups = {Created.class, Updated.class})
|
||||
private String projectId;
|
||||
|
||||
}
|
||||
|
|
|
@ -103,4 +103,6 @@ public interface ExtApiDefinitionMapper {
|
|||
List<ApiDefinition> getListBySelectIds(@Param("projectId") String projectId, @Param("ids") List<String> ids, @Param("protocols") List<String> protocols);
|
||||
|
||||
List<String> getIdsByShareParam(@Param("projectId") String projectId, @Param("condition") String condition);
|
||||
|
||||
long countByProjectAndId(@Param("projectId") String projectId, @Param("id") String id);
|
||||
}
|
||||
|
|
|
@ -159,7 +159,8 @@
|
|||
</select>
|
||||
<select id="importList" resultType="io.metersphere.api.dto.converter.ApiDefinitionDetail">
|
||||
select
|
||||
api_definition.id, api_definition.`name`, api_definition.protocol, api_definition.`method`,
|
||||
api_definition.id, api_definition.`name`, api_definition.protocol,
|
||||
api_definition.`method`,api_definition.project_id,
|
||||
api_definition.`path`, api_definition.version_id,
|
||||
api_definition.ref_id, api_definition.module_id
|
||||
from api_definition
|
||||
|
@ -758,4 +759,11 @@
|
|||
and ${condition}
|
||||
</if>
|
||||
</select>
|
||||
<select id="countByProjectAndId" resultType="java.lang.Long">
|
||||
SELECT count(id)
|
||||
FROM api_definition
|
||||
WHERE project_id = #{projectId}
|
||||
AND id = #{id}
|
||||
AND deleted = false
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
@ -129,4 +129,6 @@ public interface ExtApiTestCaseMapper {
|
|||
List<ApiTestCaseWithBlob> selectAllDetailByApiIds(@Param("apiIds") List<String> apiIds);
|
||||
|
||||
List<ApiTestCaseWithBlob> selectAllDetailByIds(@Param("ids") List<String> apiIds);
|
||||
|
||||
List<ApiTestCaseDTO> selectBaseInfoByProjectIdAndApiId(@Param("projectId") String projectId, @Param("apiId") String apiId);
|
||||
}
|
|
@ -978,6 +978,7 @@
|
|||
and api_scenario.deleted = 0;
|
||||
</select>
|
||||
<resultMap id="ApiTestCaseDetailMap" type="io.metersphere.api.dto.definition.ApiTestCaseWithBlob">
|
||||
<result column="module_id" jdbcType="VARCHAR" property="moduleId"/>
|
||||
<result column="request" jdbcType="LONGVARBINARY" property="request"/>
|
||||
<result column="tags" jdbcType="VARCHAR" property="tags" typeHandler="io.metersphere.handler.ListTypeHandler"/>
|
||||
</resultMap>
|
||||
|
@ -992,9 +993,11 @@
|
|||
</select>
|
||||
|
||||
<select id="selectAllDetailByIds" resultMap="ApiTestCaseDetailMap">
|
||||
SELECT apiTestCase.*,apiTestCaseBlob.request
|
||||
SELECT apiTestCase.*,ad.protocol,ad.path,ad.method,ad.module_id,ad.name AS apiDefinitionName,
|
||||
apiTestCaseBlob.request
|
||||
FROM api_test_case apiTestCase
|
||||
INNER JOIN api_test_case_blob apiTestCaseBlob ON apiTestCase.id = apiTestCaseBlob.id
|
||||
INNER JOIN api_definition ad ON apiTestCase.api_definition_id = ad.id
|
||||
WHERE apiTestCase.id IN
|
||||
<foreach collection="ids" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
|
@ -1009,4 +1012,12 @@
|
|||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
<select id="selectBaseInfoByProjectIdAndApiId"
|
||||
resultType="io.metersphere.api.dto.definition.ApiTestCaseDTO">
|
||||
SELECT id, num, name, project_id, api_definition_id
|
||||
FROM api_test_case
|
||||
WHERE project_id = #{projectId}
|
||||
AND api_definition_id = #{apiId}
|
||||
AND deleted = false
|
||||
</select>
|
||||
</mapper>
|
|
@ -12,6 +12,7 @@ import io.metersphere.sdk.exception.MSException;
|
|||
import io.metersphere.sdk.util.BeanUtils;
|
||||
import io.metersphere.sdk.util.LogUtils;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
@ -85,9 +86,21 @@ public class MetersphereParserApiScenario implements ApiScenarioImportParser {
|
|||
ApiScenarioStepParseResult apiScenarioStepParseResult = new ApiScenarioStepParseResult();
|
||||
|
||||
List<ApiScenarioStepDTO> stepList = apiScenarioStepMap.getOrDefault(scenarioId, new ArrayList<>());
|
||||
for (ApiScenarioStepDTO stepDTO : stepList) {
|
||||
if (stepList.isEmpty()) {
|
||||
return apiScenarioStepParseResult;
|
||||
}
|
||||
List<ApiScenarioStepDTO> firstStepList = stepList.stream().filter(step -> StringUtils.isEmpty(step.getParentId())).toList();
|
||||
if (CollectionUtils.isEmpty(firstStepList)) {
|
||||
// 需要补充的场景数据中,它的步骤很可能存在于要导入的场景数据里,所以他们的parentId不一定为null。这时候要去parentId
|
||||
// 去parentId方案: 将sort为1的步骤作为基点,它的parentId不起效果,所有以此为parentId的数据是第一层数据
|
||||
List<ApiScenarioStepDTO> sort1ScenarioList = stepList.stream().filter(step -> step.getSort() == 1).toList();
|
||||
if (CollectionUtils.isNotEmpty(sort1ScenarioList)) {
|
||||
ApiScenarioStepDTO firstScenario = sort1ScenarioList.getFirst();
|
||||
firstStepList = stepList.stream().filter(step -> StringUtils.equals(step.getParentId(), firstScenario.getParentId())).toList();
|
||||
}
|
||||
}
|
||||
for (ApiScenarioStepDTO stepDTO : firstStepList) {
|
||||
String oldStepId = stepDTO.getId();
|
||||
|
||||
ApiScenarioStepRequest stepRequest = new ApiScenarioStepRequest();
|
||||
BeanUtils.copyBean(stepRequest, stepDTO);
|
||||
// 赋值新ID防止和库内已有数据重复
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package io.metersphere.api.service;
|
||||
|
||||
import io.metersphere.api.constants.ApiDefinitionStatus;
|
||||
import io.metersphere.api.constants.ApiScenarioExportType;
|
||||
import io.metersphere.api.constants.ApiScenarioStepType;
|
||||
import io.metersphere.api.domain.*;
|
||||
import io.metersphere.api.dto.ApiFile;
|
||||
import io.metersphere.api.dto.converter.ApiDefinitionDetail;
|
||||
import io.metersphere.api.dto.converter.ApiDefinitionExportDetail;
|
||||
import io.metersphere.api.dto.converter.ApiScenarioImportParseResult;
|
||||
import io.metersphere.api.dto.converter.ApiScenarioPreImportAnalysisResult;
|
||||
|
@ -15,6 +17,9 @@ import io.metersphere.api.mapper.*;
|
|||
import io.metersphere.api.parser.ApiScenarioImportParser;
|
||||
import io.metersphere.api.parser.ImportParserFactory;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionExportService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionImportService;
|
||||
import io.metersphere.api.service.definition.ApiDefinitionModuleService;
|
||||
import io.metersphere.api.service.definition.ApiTestCaseService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioLogService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioModuleService;
|
||||
import io.metersphere.api.service.scenario.ApiScenarioService;
|
||||
|
@ -26,6 +31,7 @@ import io.metersphere.plugin.api.spi.AbstractMsTestElement;
|
|||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
|
||||
import io.metersphere.project.mapper.ProjectMapper;
|
||||
import io.metersphere.project.service.PermissionCheckService;
|
||||
import io.metersphere.project.utils.FileDownloadUtils;
|
||||
import io.metersphere.sdk.constants.*;
|
||||
import io.metersphere.sdk.dto.ExportMsgDTO;
|
||||
|
@ -47,9 +53,12 @@ import io.metersphere.system.service.FileService;
|
|||
import io.metersphere.system.service.NoticeSendService;
|
||||
import io.metersphere.system.socket.ExportWebSocketHandler;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.system.uid.NumGenerator;
|
||||
import io.metersphere.system.utils.TreeNodeParseUtils;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
|
@ -65,6 +74,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -77,7 +87,13 @@ public class ApiScenarioDataTransferService {
|
|||
|
||||
private final ThreadLocal<Long> currentApiScenarioOrder = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<Long> currentModuleOrder = new ThreadLocal<>();
|
||||
private final ThreadLocal<Long> currentScenarioModuleOrder = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<Long> currentApiModuleOrder = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<Long> currentApiOrder = new ThreadLocal<>();
|
||||
|
||||
private final ThreadLocal<Long> currentApiTestCaseOrder = new ThreadLocal<>();
|
||||
|
||||
private static final String EXPORT_CASE_TMP_DIR = "apiScenario";
|
||||
|
||||
|
@ -116,6 +132,14 @@ public class ApiScenarioDataTransferService {
|
|||
private ApiScenarioLogService apiScenarioLogService;
|
||||
@Resource
|
||||
private ApiDefinitionExportService apiDefinitionExportService;
|
||||
@Resource
|
||||
private PermissionCheckService permissionCheckService;
|
||||
@Resource
|
||||
private ApiDefinitionImportService apiDefinitionImportService;
|
||||
@Resource
|
||||
private ApiDefinitionModuleService apiDefinitionModuleService;
|
||||
@Resource
|
||||
private ApiTestCaseService apiTestCaseService;
|
||||
|
||||
public String exportScenario(ApiScenarioBatchExportRequest request, String type, String userId) {
|
||||
String returnId;
|
||||
|
@ -155,25 +179,114 @@ public class ApiScenarioDataTransferService {
|
|||
}
|
||||
//解析
|
||||
ApiScenarioPreImportAnalysisResult preImportAnalysisResult = this.importAnalysis(
|
||||
parseResult, request.getProjectId(), request.getModuleId(), apiScenarioModuleService.getTree(request.getProjectId()));
|
||||
|
||||
parseResult, request.getOperator(), request.getProjectId(), request.getModuleId(), apiScenarioModuleService.getTree(request.getProjectId()));
|
||||
//存储
|
||||
this.save(preImportAnalysisResult, request.getProjectId(), request.getOperator(), request.isCoverData());
|
||||
}
|
||||
|
||||
private void save(ApiScenarioPreImportAnalysisResult preImportAnalysisResult, String projectId, String operator, boolean isCoverData) {
|
||||
List<LogDTO> operationLogs = new ArrayList<>();
|
||||
currentModuleOrder.remove();
|
||||
currentApiScenarioOrder.remove();
|
||||
// 更新、修改数据
|
||||
{
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
this.insertModule(projectId, operator, preImportAnalysisResult.getInsertModuleList(), sqlSession);
|
||||
// 接口定义模块
|
||||
if (CollectionUtils.isNotEmpty(preImportAnalysisResult.getInsertApiModuleList())) {
|
||||
Map<String, List<BaseTreeNode>> projectMap = preImportAnalysisResult.getInsertApiModuleList().stream().collect(Collectors.groupingBy(BaseTreeNode::getProjectId));
|
||||
ApiDefinitionModuleMapper batchApiModuleMapper = sqlSession.getMapper(ApiDefinitionModuleMapper.class);
|
||||
projectMap.forEach((targetProjectId, nodeList) -> {
|
||||
currentApiModuleOrder.remove();
|
||||
nodeList.forEach(t -> {
|
||||
ApiDefinitionModule module = new ApiDefinitionModule();
|
||||
module.setId(t.getId());
|
||||
module.setName(t.getName());
|
||||
module.setParentId(t.getParentId());
|
||||
module.setProjectId(t.getProjectId());
|
||||
module.setCreateUser(operator);
|
||||
module.setPos(getImportNextOrder(apiDefinitionModuleService::getNextOrder, currentApiModuleOrder, targetProjectId));
|
||||
module.setCreateTime(System.currentTimeMillis());
|
||||
module.setUpdateUser(operator);
|
||||
module.setUpdateTime(System.currentTimeMillis());
|
||||
batchApiModuleMapper.insertSelective(module);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
});
|
||||
}
|
||||
// 接口定义
|
||||
if (CollectionUtils.isNotEmpty(preImportAnalysisResult.getInsertApiDefinitions())) {
|
||||
Map<String, List<ApiDefinitionDetail>> projectMap = preImportAnalysisResult.getInsertApiDefinitions().stream().collect(Collectors.groupingBy(ApiDefinitionDetail::getProjectId));
|
||||
ApiDefinitionMapper batchApiMapper = sqlSession.getMapper(ApiDefinitionMapper.class);
|
||||
ApiDefinitionBlobMapper batchApiBlobMapper = sqlSession.getMapper(ApiDefinitionBlobMapper.class);
|
||||
projectMap.forEach((targetProjectId, apiList) -> {
|
||||
currentApiOrder.remove();
|
||||
String versionId = extBaseProjectVersionMapper.getDefaultVersion(targetProjectId);
|
||||
for (ApiDefinitionDetail t : apiList) {
|
||||
ApiDefinition apiDefinition = new ApiDefinition();
|
||||
BeanUtils.copyBean(apiDefinition, t);
|
||||
apiDefinition.setPos(getImportNextOrder(apiDefinitionImportService::getNextOrder, currentApiOrder, targetProjectId));
|
||||
apiDefinition.setLatest(true);
|
||||
apiDefinition.setStatus(ApiDefinitionStatus.PROCESSING.name());
|
||||
apiDefinition.setRefId(apiDefinition.getId());
|
||||
apiDefinition.setVersionId(versionId);
|
||||
apiDefinition.setCreateUser(operator);
|
||||
apiDefinition.setCreateTime(System.currentTimeMillis());
|
||||
apiDefinition.setUpdateUser(operator);
|
||||
apiDefinition.setUpdateTime(System.currentTimeMillis());
|
||||
batchApiMapper.insertSelective(apiDefinition);
|
||||
//插入blob数据
|
||||
ApiDefinitionBlob apiDefinitionBlob = new ApiDefinitionBlob();
|
||||
apiDefinitionBlob.setId(apiDefinition.getId());
|
||||
apiDefinitionBlob.setRequest(ApiDataUtils.toJSONString(t.getRequest()).getBytes(StandardCharsets.UTF_8));
|
||||
apiDefinitionBlob.setResponse(ApiDataUtils.toJSONString(t.getResponse()).getBytes(StandardCharsets.UTF_8));
|
||||
batchApiBlobMapper.insertSelective(apiDefinitionBlob);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
// 接口用例
|
||||
if (CollectionUtils.isNotEmpty(preImportAnalysisResult.getInsertApiTestCaseList())) {
|
||||
Map<String, List<ApiTestCaseDTO>> projectMap = preImportAnalysisResult.getInsertApiTestCaseList().stream().collect(Collectors.groupingBy(ApiTestCaseDTO::getProjectId));
|
||||
|
||||
ApiTestCaseMapper batchApiCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
|
||||
ApiTestCaseBlobMapper batchApiBlobCaseMapper = sqlSession.getMapper(ApiTestCaseBlobMapper.class);
|
||||
|
||||
projectMap.forEach((targetProjectId, testCaseList) -> {
|
||||
currentApiTestCaseOrder.remove();
|
||||
String versionId = extBaseProjectVersionMapper.getDefaultVersion(targetProjectId);
|
||||
testCaseList.forEach(t -> {
|
||||
ApiTestCase apiTestCase = new ApiTestCase();
|
||||
BeanUtils.copyBean(apiTestCase, t);
|
||||
apiTestCase.setProjectId(targetProjectId);
|
||||
apiTestCase.setPos(getImportNextOrder(apiTestCaseService::getNextOrder, currentApiTestCaseOrder, targetProjectId));
|
||||
apiTestCase.setNum(NumGenerator.nextNum(targetProjectId, ApplicationNumScope.API_DEFINITION));
|
||||
apiTestCase.setStatus(ApiDefinitionStatus.PROCESSING.name());
|
||||
apiTestCase.setVersionId(versionId);
|
||||
apiTestCase.setCreateUser(operator);
|
||||
apiTestCase.setCreateTime(System.currentTimeMillis());
|
||||
apiTestCase.setUpdateUser(operator);
|
||||
apiTestCase.setUpdateTime(System.currentTimeMillis());
|
||||
batchApiCaseMapper.insertSelective(apiTestCase);
|
||||
//插入blob数据
|
||||
ApiTestCaseBlob apiTestCaseBlob = new ApiTestCaseBlob();
|
||||
apiTestCaseBlob.setId(apiTestCase.getId());
|
||||
|
||||
apiTestCaseBlob.setRequest(apiDefinitionImportService.getMsTestElementStr(t.getRequest()).getBytes());
|
||||
batchApiBlobCaseMapper.insertSelective(apiTestCaseBlob);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
});
|
||||
}
|
||||
|
||||
//场景模块
|
||||
this.insertModule(operator, preImportAnalysisResult.getInsertScenarioModuleList(), sqlSession);
|
||||
if (isCoverData) {
|
||||
this.updateScenarios(projectId, operator, preImportAnalysisResult.getUpdateApiScenarioData(), sqlSession);
|
||||
}
|
||||
String versionId = extBaseProjectVersionMapper.getDefaultVersion(projectId);
|
||||
this.insertScenarios(projectId, operator, versionId, preImportAnalysisResult.getInsertApiScenarioData(), sqlSession);
|
||||
//场景
|
||||
this.insertScenarios(operator, versionId, preImportAnalysisResult.getInsertApiScenarioData(), sqlSession);
|
||||
|
||||
sqlSession.flushStatements();
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
}
|
||||
|
@ -183,7 +296,7 @@ public class ApiScenarioDataTransferService {
|
|||
List<ApiScenarioImportDetail> noticeCreateLists = new ArrayList<>();
|
||||
List<ApiScenarioImportDetail> noticeUpdateLists = new ArrayList<>();
|
||||
|
||||
preImportAnalysisResult.getInsertModuleList().forEach(t ->
|
||||
preImportAnalysisResult.getInsertScenarioModuleList().forEach(t ->
|
||||
operationLogs.add(ApiDefinitionImportUtils.genImportLog(project, t.getId(), t.getName(), t, OperationLogModule.API_SCENARIO_MANAGEMENT_MODULE, operator, OperationLogType.ADD.name()))
|
||||
);
|
||||
|
||||
|
@ -339,20 +452,23 @@ public class ApiScenarioDataTransferService {
|
|||
}
|
||||
}
|
||||
|
||||
private void insertModule(String projectId, String operator, List<BaseTreeNode> insertModuleList, SqlSession sqlSession) {
|
||||
private void insertModule(String operator, List<BaseTreeNode> insertModuleList, SqlSession sqlSession) {
|
||||
if (CollectionUtils.isEmpty(insertModuleList)) {
|
||||
return;
|
||||
}
|
||||
ApiScenarioModuleMapper batchApiDefinitionMapper = sqlSession.getMapper(ApiScenarioModuleMapper.class);
|
||||
SubListUtils.dealForSubList(insertModuleList, 100, list -> {
|
||||
|
||||
Map<String, List<BaseTreeNode>> projectMap = insertModuleList.stream().collect(Collectors.groupingBy(BaseTreeNode::getProjectId));
|
||||
|
||||
projectMap.forEach((targetProjectId, list) -> {
|
||||
list.forEach(t -> {
|
||||
ApiScenarioModule module = new ApiScenarioModule();
|
||||
module.setId(t.getId());
|
||||
module.setName(t.getName());
|
||||
module.setParentId(t.getParentId());
|
||||
module.setProjectId(projectId);
|
||||
module.setProjectId(t.getProjectId());
|
||||
module.setCreateUser(operator);
|
||||
module.setPos(getImportNextOrder(apiScenarioModuleService::getNextOrder, currentModuleOrder, projectId));
|
||||
module.setPos(getImportNextOrder(apiScenarioModuleService::getNextOrder, currentScenarioModuleOrder, targetProjectId));
|
||||
module.setCreateTime(System.currentTimeMillis());
|
||||
module.setUpdateUser(operator);
|
||||
module.setUpdateTime(module.getCreateTime());
|
||||
|
@ -362,7 +478,7 @@ public class ApiScenarioDataTransferService {
|
|||
});
|
||||
}
|
||||
|
||||
private void insertScenarios(String projectId, String operator, String versionId, List<ApiScenarioImportDetail> insertScenarioList, SqlSession sqlSession) {
|
||||
private void insertScenarios(String operator, String versionId, List<ApiScenarioImportDetail> insertScenarioList, SqlSession sqlSession) {
|
||||
// 创建场景
|
||||
if (CollectionUtils.isEmpty(insertScenarioList)) {
|
||||
return;
|
||||
|
@ -375,13 +491,16 @@ public class ApiScenarioDataTransferService {
|
|||
ApiScenarioStepMapper stepBatchMapper = sqlSession.getMapper(ApiScenarioStepMapper.class);
|
||||
ApiScenarioStepBlobMapper stepBlobBatchMapper = sqlSession.getMapper(ApiScenarioStepBlobMapper.class);
|
||||
|
||||
SubListUtils.dealForSubList(insertScenarioList, 100, list -> {
|
||||
Map<String, List<ApiScenarioImportDetail>> projectMap = insertScenarioList.stream().collect(Collectors.groupingBy(ApiScenarioImportDetail::getProjectId));
|
||||
|
||||
projectMap.forEach((targetProjectId, targetList) -> {
|
||||
currentApiScenarioOrder.remove();
|
||||
SubListUtils.dealForSubList(targetList, 100, list -> {
|
||||
list.forEach(t -> {
|
||||
t.setId(IDGenerator.nextStr());
|
||||
ApiScenario scenario = new ApiScenario();
|
||||
BeanUtils.copyBean(scenario, t);
|
||||
scenario.setNum(apiScenarioService.getNextNum(projectId));
|
||||
scenario.setPos(getImportNextOrder(apiScenarioService::getNextOrder, currentApiScenarioOrder, projectId));
|
||||
scenario.setNum(apiScenarioService.getNextNum(targetProjectId));
|
||||
scenario.setPos(getImportNextOrder(apiScenarioService::getNextOrder, currentApiScenarioOrder, targetProjectId));
|
||||
scenario.setLatest(true);
|
||||
scenario.setCreateUser(operator);
|
||||
scenario.setUpdateUser(operator);
|
||||
|
@ -411,6 +530,9 @@ public class ApiScenarioDataTransferService {
|
|||
});
|
||||
sqlSession.flushStatements();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void handleStepAdd(ApiScenarioImportDetail t, ApiScenario scenario,
|
||||
|
@ -518,14 +640,17 @@ public class ApiScenarioDataTransferService {
|
|||
return order;
|
||||
}
|
||||
|
||||
private ApiScenarioPreImportAnalysisResult importAnalysis(ApiScenarioImportParseResult parseResult, String projectId, String moduleId, List<BaseTreeNode> apiScenarioModules) {
|
||||
private ApiScenarioPreImportAnalysisResult importAnalysis(ApiScenarioImportParseResult parseResult, String operator, String projectId, String moduleId, List<BaseTreeNode> apiScenarioModules) {
|
||||
ApiScenarioPreImportAnalysisResult analysisResult = new ApiScenarioPreImportAnalysisResult();
|
||||
|
||||
Map<String, String> moduleIdPathMap = apiScenarioModules.stream().collect(Collectors.toMap(BaseTreeNode::getId, BaseTreeNode::getPath));
|
||||
Map<String, BaseTreeNode> modulePathMap = apiScenarioModules.stream().collect(Collectors.toMap(BaseTreeNode::getPath, k -> k, (k1, k2) -> k1));
|
||||
|
||||
ReplaceScenarioResource replaceScenarioResource = this.parseRelatedDataToAnalysisResult(operator, projectId, parseResult, analysisResult);
|
||||
|
||||
List<ApiScenarioImportDetail> importScenarios = parseResult.getImportScenarioList();
|
||||
for (ApiScenarioImportDetail importScenario : importScenarios) {
|
||||
//处理模块
|
||||
if (StringUtils.isBlank(moduleId) || StringUtils.equalsIgnoreCase(moduleId, ModuleConstants.DEFAULT_NODE_ID) || !moduleIdPathMap.containsKey(moduleId)) {
|
||||
importScenario.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
importScenario.setModulePath(moduleIdPathMap.get(ModuleConstants.DEFAULT_NODE_ID));
|
||||
|
@ -555,23 +680,329 @@ public class ApiScenarioDataTransferService {
|
|||
scenario.setId(existenceNameIdMap.get(scenario.getName()));
|
||||
analysisResult.getUpdateApiScenarioData().add(scenario);
|
||||
} else {
|
||||
scenario.setId(IDGenerator.nextStr());
|
||||
scenario.setModuleId(modulePathMap.get(finalModulePath).getId());
|
||||
analysisResult.getInsertApiScenarioData().add(scenario);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//模块不存在的必定是新建
|
||||
analysisResult.getInsertModuleList().addAll(TreeNodeParseUtils.getInsertNodeByPath(modulePathMap, modulePath));
|
||||
List<BaseTreeNode> insertModuleList = TreeNodeParseUtils.getInsertNodeByPath(modulePathMap, modulePath);
|
||||
insertModuleList.forEach(item -> item.setProjectId(projectId));
|
||||
analysisResult.getInsertScenarioModuleList().addAll(insertModuleList);
|
||||
String finalModulePath = modulePath;
|
||||
scenarios.forEach(scenario ->
|
||||
scenario.setModuleId(modulePathMap.get(finalModulePath).getId())
|
||||
);
|
||||
scenarios.forEach(scenario -> {
|
||||
scenario.setId(IDGenerator.nextStr());
|
||||
scenario.setModuleId(modulePathMap.get(finalModulePath).getId());
|
||||
});
|
||||
analysisResult.getInsertApiScenarioData().addAll(scenarios);
|
||||
}
|
||||
});
|
||||
//将要补的场景数据导入进来
|
||||
analysisResult.getInsertApiScenarioData().addAll(replaceScenarioResource.getInsertRelatedApiScenarioData());
|
||||
|
||||
for (ApiScenarioImportDetail importScenario : analysisResult.getInsertApiScenarioData()) {
|
||||
// 处理步骤里的关联资源文件
|
||||
importScenario.getSteps().forEach(item -> {
|
||||
if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API.name())) {
|
||||
ApiDefinitionDetail apiDetail = replaceScenarioResource.getApi(item.getResourceId());
|
||||
if (apiDetail != null) {
|
||||
item.setResourceId(apiDetail.getId());
|
||||
item.setProjectId(importScenario.getProjectId());
|
||||
item.setOriginProjectId(apiDetail.getProjectId());
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API_CASE.name())) {
|
||||
ApiTestCaseDTO newData = replaceScenarioResource.getApiCase(item.getResourceId());
|
||||
if (newData != null) {
|
||||
item.setResourceId(newData.getId());
|
||||
item.setProjectId(importScenario.getProjectId());
|
||||
item.setOriginProjectId(newData.getProjectId());
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API_SCENARIO.name())) {
|
||||
ApiScenarioImportDetail newData = replaceScenarioResource.getApiScenario(item.getResourceId());
|
||||
if (newData != null) {
|
||||
item.setResourceId(newData.getId());
|
||||
item.setProjectId(importScenario.getProjectId());
|
||||
item.setOriginProjectId(newData.getProjectId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
for (ApiScenarioImportDetail updateScenario : analysisResult.getUpdateApiScenarioData()) {
|
||||
// 处理步骤里的关联资源文件
|
||||
updateScenario.getSteps().forEach(item -> {
|
||||
if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API.name())) {
|
||||
ApiDefinitionDetail apiDetail = replaceScenarioResource.getApi(item.getResourceId());
|
||||
if (apiDetail != null) {
|
||||
item.setResourceId(apiDetail.getId());
|
||||
item.setProjectId(updateScenario.getProjectId());
|
||||
item.setOriginProjectId(apiDetail.getProjectId());
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API_CASE.name())) {
|
||||
ApiTestCaseDTO newData = replaceScenarioResource.getApiCase(item.getResourceId());
|
||||
if (newData != null) {
|
||||
item.setResourceId(newData.getId());
|
||||
item.setProjectId(updateScenario.getProjectId());
|
||||
item.setOriginProjectId(newData.getProjectId());
|
||||
}
|
||||
} else if (StringUtils.equalsIgnoreCase(item.getStepType(), ApiScenarioStepType.API_SCENARIO.name())) {
|
||||
ApiScenarioImportDetail newData = replaceScenarioResource.getApiScenario(item.getResourceId());
|
||||
if (newData != null) {
|
||||
item.setResourceId(newData.getId());
|
||||
item.setProjectId(updateScenario.getProjectId());
|
||||
item.setOriginProjectId(newData.getProjectId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return analysisResult;
|
||||
}
|
||||
|
||||
private ReplaceScenarioResource parseRelatedDataToAnalysisResult(String operator, String projectId, ApiScenarioImportParseResult parseResult, ApiScenarioPreImportAnalysisResult analysisResult) {
|
||||
/*
|
||||
1.判断接口定义中要创建的部分,然后进行新旧ID映射
|
||||
2.判断用例中的接口定义是否在上一步中创建,如果没有则进行筛选判断符合条件的接口定义(若没有则新建)并关联到其下面。
|
||||
*/
|
||||
Map<String, List<ApiDefinitionDetail>> projectApiMap = new HashMap<>();
|
||||
Map<String, List<ApiTestCaseDTO>> projectApiCaseMap = new HashMap<>();
|
||||
Map<String, List<ApiScenarioImportDetail>> projectScenarioMap = new HashMap<>();
|
||||
// 对导入文件中的数据进行分组
|
||||
{
|
||||
for (Map.Entry<String, List<ApiDefinitionDetail>> entry : parseResult.getRelatedApiDefinitions().stream().collect(Collectors.groupingBy(ApiDefinitionDetail::getProjectId)).entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<ApiDefinitionDetail> apiDefinitionDetails = entry.getValue();
|
||||
// 如果没有权限,需要在当前项目进行校验
|
||||
if (projectMapper.selectByPrimaryKey(targetProjectId) == null) {
|
||||
targetProjectId = projectId;
|
||||
} else if (!permissionCheckService.userHasProjectPermission(operator, targetProjectId, PermissionConstants.PROJECT_API_DEFINITION_ADD)) {
|
||||
targetProjectId = projectId;
|
||||
}
|
||||
if (projectApiMap.containsKey(targetProjectId)) {
|
||||
projectApiMap.get(targetProjectId).addAll(apiDefinitionDetails);
|
||||
} else {
|
||||
projectApiMap.put(targetProjectId, apiDefinitionDetails);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, List<ApiTestCaseDTO>> entry : parseResult.getRelatedApiTestCaseList().stream().collect(Collectors.groupingBy(ApiTestCaseDTO::getProjectId)).entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<ApiTestCaseDTO> apiTestCaseList = entry.getValue();
|
||||
// 如果没有权限,需要在当前项目进行校验
|
||||
if (projectMapper.selectByPrimaryKey(targetProjectId) == null) {
|
||||
targetProjectId = projectId;
|
||||
} else if (!permissionCheckService.userHasProjectPermission(operator, targetProjectId, PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD)) {
|
||||
targetProjectId = projectId;
|
||||
}
|
||||
if (projectApiCaseMap.containsKey(targetProjectId)) {
|
||||
projectApiCaseMap.get(targetProjectId).addAll(apiTestCaseList);
|
||||
} else {
|
||||
projectApiCaseMap.put(targetProjectId, apiTestCaseList);
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, List<ApiScenarioImportDetail>> entry : parseResult.getRelatedScenarioList().stream().collect(Collectors.groupingBy(ApiScenarioImportDetail::getProjectId)).entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<ApiScenarioImportDetail> scenarioList = entry.getValue();
|
||||
// 如果没有权限,需要在当前项目进行校验
|
||||
if (projectMapper.selectByPrimaryKey(targetProjectId) == null) {
|
||||
targetProjectId = projectId;
|
||||
} else if (!permissionCheckService.userHasProjectPermission(operator, targetProjectId, PermissionConstants.PROJECT_API_DEFINITION_CASE_ADD)) {
|
||||
targetProjectId = projectId;
|
||||
}
|
||||
if (projectScenarioMap.containsKey(targetProjectId)) {
|
||||
projectScenarioMap.get(targetProjectId).addAll(scenarioList);
|
||||
} else {
|
||||
projectScenarioMap.put(targetProjectId, scenarioList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReplaceScenarioResource returnResource = new ReplaceScenarioResource();
|
||||
// 1.处理接口定义
|
||||
{
|
||||
for (Map.Entry<String, List<ApiDefinitionDetail>> entry : projectApiMap.entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<ApiDefinitionDetail> apiDefinitionDetails = entry.getValue();
|
||||
|
||||
Map<String, List<ApiDefinitionDetail>> protocolImportMap = apiDefinitionDetails.stream().collect(Collectors.groupingBy(ApiDefinitionDetail::getProtocol));
|
||||
|
||||
ApiDefinitionPageRequest pageRequest = new ApiDefinitionPageRequest();
|
||||
pageRequest.setProjectId(targetProjectId);
|
||||
pageRequest.setProtocols(new ArrayList<>(protocolImportMap.keySet()));
|
||||
List<ApiDefinitionDetail> existenceApiDefinitionList = extApiDefinitionMapper.importList(pageRequest);
|
||||
|
||||
Map<String, List<ApiDefinitionDetail>> existenceProtocolMap = existenceApiDefinitionList.stream().collect(Collectors.groupingBy(ApiDefinitionDetail::getProtocol));
|
||||
|
||||
for (Map.Entry<String, List<ApiDefinitionDetail>> protocolEntry : protocolImportMap.entrySet()) {
|
||||
returnResource.getApiDefinitionIdMap().putAll(ApiScenarioImportUtils.getApiIdInTargetList(
|
||||
protocolEntry.getValue(), existenceProtocolMap.get(protocolEntry.getKey()), protocolEntry.getKey(), projectId, analysisResult));
|
||||
}
|
||||
|
||||
// 解析接口定义的模块
|
||||
List<BaseTreeNode> apiModules = apiDefinitionImportService.buildTreeData(targetProjectId, null);
|
||||
Map<String, BaseTreeNode> modulePathMap = apiModules.stream().collect(Collectors.toMap(BaseTreeNode::getPath, k -> k, (k1, k2) -> k1));
|
||||
for (ApiDefinitionDetail apiDefinitionDetail : analysisResult.getInsertApiDefinitions()) {
|
||||
List<BaseTreeNode> insertModuleList = TreeNodeParseUtils.getInsertNodeByPath(modulePathMap, apiDefinitionDetail.getModulePath());
|
||||
insertModuleList.forEach(item -> item.setProjectId(targetProjectId));
|
||||
analysisResult.getInsertApiModuleList().addAll(insertModuleList);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2.处理接口用例
|
||||
{
|
||||
for (Map.Entry<String, List<ApiTestCaseDTO>> entry : projectApiCaseMap.entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<ApiTestCaseDTO> apiTestCaseDTOS = entry.getValue();
|
||||
Map<String, List<ApiTestCaseDTO>> protocolMap = apiTestCaseDTOS.stream().collect(Collectors.groupingBy(ApiTestCaseDTO::getProtocol));
|
||||
//将项目下的用例,通过协议、关键词进行分组处理。
|
||||
|
||||
ApiDefinitionPageRequest pageRequest = new ApiDefinitionPageRequest();
|
||||
pageRequest.setProjectId(targetProjectId);
|
||||
pageRequest.setProtocols(new ArrayList<>(protocolMap.keySet()));
|
||||
List<ApiDefinitionDetail> existenceApiDefinitionList = extApiDefinitionMapper.importList(pageRequest);
|
||||
|
||||
for (Map.Entry<String, List<ApiTestCaseDTO>> protocolEntry : protocolMap.entrySet()) {
|
||||
String protocol = protocolEntry.getKey();
|
||||
List<ApiTestCaseDTO> protocolList = protocolEntry.getValue();
|
||||
|
||||
Map<String, List<ApiTestCaseDTO>> apiIdMap = protocolList.stream().collect(Collectors.groupingBy(ApiTestCaseDTO::getApiDefinitionId));
|
||||
for (Map.Entry<String, List<ApiTestCaseDTO>> apiIdEntry : apiIdMap.entrySet()) {
|
||||
String replaceApiDefinitionId = returnResource.getApi(apiIdEntry.getKey()) == null ? StringUtils.EMPTY : returnResource.getApi(apiIdEntry.getKey()).getId();
|
||||
|
||||
List<ApiTestCaseDTO> testCaseList = apiIdEntry.getValue();
|
||||
|
||||
if (StringUtils.isBlank(replaceApiDefinitionId)) {
|
||||
// 用例对应的接口在上述步骤中未处理
|
||||
boolean apiExistence = ApiScenarioImportUtils.isApiExistence(
|
||||
protocol, testCaseList.getFirst().getMethod(), testCaseList.getFirst().getPath(),
|
||||
testCaseList.getFirst().getModulePath(), testCaseList.getFirst().getApiDefinitionName(), existenceApiDefinitionList);
|
||||
|
||||
if (apiExistence) {
|
||||
Map<Long, ApiTestCaseDTO> existenceApiCaseNumMap = extApiTestCaseMapper.selectBaseInfoByProjectIdAndApiId(targetProjectId, apiIdEntry.getKey())
|
||||
.stream().collect(Collectors.toMap(ApiTestCaseDTO::getNum, Function.identity(), (k1, k2) -> k1));
|
||||
for (ApiTestCaseDTO apiTestCaseDTO : apiIdEntry.getValue()) {
|
||||
if (existenceApiCaseNumMap.containsKey(apiTestCaseDTO.getNum())) {
|
||||
returnResource.putApiTestCase(apiTestCaseDTO.getId(), existenceApiCaseNumMap.get(apiTestCaseDTO.getNum()));
|
||||
} else {
|
||||
apiTestCaseDTO.setId(IDGenerator.nextStr());
|
||||
apiTestCaseDTO.setProjectId(targetProjectId);
|
||||
returnResource.putApiTestCase(apiTestCaseDTO.getId(), apiTestCaseDTO);
|
||||
analysisResult.setApiTestCase(apiTestCaseDTO);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 同步创建API
|
||||
ApiDefinitionDetail apiDefinitionDetail = new ApiDefinitionDetail();
|
||||
apiDefinitionDetail.setProjectId(targetProjectId);
|
||||
apiDefinitionDetail.setModulePath(testCaseList.getFirst().getModulePath());
|
||||
apiDefinitionDetail.setId(IDGenerator.nextStr());
|
||||
apiDefinitionDetail.setName(testCaseList.getFirst().getApiDefinitionName());
|
||||
apiDefinitionDetail.setRequest(testCaseList.getFirst().getRequest());
|
||||
apiDefinitionDetail.setProtocol(testCaseList.getFirst().getProtocol());
|
||||
apiDefinitionDetail.setPath(testCaseList.getFirst().getPath());
|
||||
apiDefinitionDetail.setMethod(testCaseList.getFirst().getMethod());
|
||||
apiDefinitionDetail.setResponse(new ArrayList<>());
|
||||
returnResource.putApiDefinitionId(apiIdEntry.getKey(), apiDefinitionDetail);
|
||||
analysisResult.setApiDefinition(apiDefinitionDetail);
|
||||
|
||||
for (ApiTestCaseDTO apiTestCaseDTO : testCaseList) {
|
||||
apiTestCaseDTO.setId(IDGenerator.nextStr());
|
||||
apiTestCaseDTO.setProjectId(targetProjectId);
|
||||
apiTestCaseDTO.setApiDefinitionId(apiDefinitionDetail.getId());
|
||||
returnResource.putApiTestCase(apiTestCaseDTO.getId(), apiTestCaseDTO);
|
||||
analysisResult.setApiTestCase(apiTestCaseDTO);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Map<Long, ApiTestCaseDTO> existenceApiCaseNumMap = extApiTestCaseMapper.selectBaseInfoByProjectIdAndApiId(targetProjectId, replaceApiDefinitionId)
|
||||
.stream().collect(Collectors.toMap(ApiTestCaseDTO::getNum, Function.identity(), (k1, k2) -> k1));
|
||||
for (ApiTestCaseDTO apiTestCaseDTO : testCaseList) {
|
||||
apiTestCaseDTO.setApiDefinitionId(replaceApiDefinitionId);
|
||||
if (existenceApiCaseNumMap.containsKey(apiTestCaseDTO.getNum())) {
|
||||
returnResource.putApiTestCase(apiTestCaseDTO.getId(), existenceApiCaseNumMap.get(apiTestCaseDTO.getNum()));
|
||||
} else {
|
||||
apiTestCaseDTO.setProjectId(targetProjectId);
|
||||
returnResource.putApiTestCase(apiTestCaseDTO.getId(), apiTestCaseDTO);
|
||||
apiTestCaseDTO.setId(IDGenerator.nextStr());
|
||||
analysisResult.setApiTestCase(apiTestCaseDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. 处理场景
|
||||
{
|
||||
for (Map.Entry<String, List<ApiScenarioImportDetail>> entry : projectScenarioMap.entrySet()) {
|
||||
String targetProjectId = entry.getKey();
|
||||
List<BaseTreeNode> apiScenarioModules = apiScenarioModuleService.getTree(targetProjectId);
|
||||
|
||||
Map<String, String> moduleIdPathMap = apiScenarioModules.stream().collect(Collectors.toMap(BaseTreeNode::getId, BaseTreeNode::getPath));
|
||||
Map<String, BaseTreeNode> modulePathMap = apiScenarioModules.stream().collect(Collectors.toMap(BaseTreeNode::getPath, k -> k, (k1, k2) -> k1));
|
||||
|
||||
List<ApiScenarioImportDetail> importScenarios = parseResult.getRelatedScenarioList();
|
||||
|
||||
for (ApiScenarioImportDetail importScenario : importScenarios) {
|
||||
importScenario.setProjectId(targetProjectId);
|
||||
if (StringUtils.isBlank(importScenario.getModulePath()) || StringUtils.equals(importScenario.getModulePath().trim(), "/")) {
|
||||
importScenario.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
importScenario.setModulePath(moduleIdPathMap.get(ModuleConstants.DEFAULT_NODE_ID));
|
||||
} else {
|
||||
if (!StringUtils.startsWith(importScenario.getModulePath(), "/")) {
|
||||
importScenario.setModulePath("/" + importScenario.getModulePath());
|
||||
}
|
||||
if (StringUtils.endsWith(importScenario.getModulePath(), "/")) {
|
||||
importScenario.setModulePath(importScenario.getModulePath().substring(0, importScenario.getModulePath().length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, List<ApiScenarioImportDetail>> modulePathScenario = importScenarios.stream().collect(Collectors.groupingBy(ApiScenarioImportDetail::getModulePath));
|
||||
for (Map.Entry<String, List<ApiScenarioImportDetail>> modulePathEntry : modulePathScenario.entrySet()) {
|
||||
String modulePath = modulePathEntry.getKey();
|
||||
|
||||
Map<String, ApiScenario> apiScenarioNameMap = new HashMap<>();
|
||||
String moduleId = null;
|
||||
// 设置moduleId
|
||||
if (!modulePathMap.containsKey(modulePath)) {
|
||||
List<BaseTreeNode> insertModuleList = TreeNodeParseUtils.getInsertNodeByPath(modulePathMap, modulePath);
|
||||
insertModuleList.forEach(item -> item.setProjectId(targetProjectId));
|
||||
analysisResult.getInsertScenarioModuleList().addAll(insertModuleList);
|
||||
moduleId = modulePathMap.get(modulePath).getId();
|
||||
} else {
|
||||
moduleId = modulePathMap.get(modulePath).getId();
|
||||
apiScenarioNameMap = extApiScenarioMapper.selectBaseInfoByModuleIdAndProjectId(moduleId, targetProjectId)
|
||||
.stream().collect(Collectors.toMap(ApiScenario::getName, Function.identity(), (k1, k2) -> k1));
|
||||
}
|
||||
|
||||
Map<String, ApiScenarioImportDetail> createdNameOldIds = new HashMap<>();
|
||||
|
||||
for (ApiScenarioImportDetail scenario : modulePathEntry.getValue()) {
|
||||
scenario.setModuleId(moduleId);
|
||||
if (createdNameOldIds.containsKey(scenario.getName())) {
|
||||
returnResource.putApiScenarioId(scenario.getId(), createdNameOldIds.get(scenario.getName()));
|
||||
} else {
|
||||
if (apiScenarioNameMap.containsKey(scenario.getName())) {
|
||||
ApiScenarioImportDetail oldData = new ApiScenarioImportDetail();
|
||||
BeanUtils.copyBean(oldData, apiScenarioNameMap.get(scenario.getName()));
|
||||
returnResource.putApiScenarioId(scenario.getId(), oldData);
|
||||
createdNameOldIds.put(scenario.getName(), oldData);
|
||||
} else {
|
||||
String oldId = scenario.getId();
|
||||
scenario.setId(IDGenerator.nextStr());
|
||||
scenario.setProjectId(targetProjectId);
|
||||
returnResource.getInsertRelatedApiScenarioData().add(scenario);
|
||||
returnResource.putApiScenarioId(oldId, scenario);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return returnResource;
|
||||
}
|
||||
|
||||
private String exportApiScenarioZip(ApiScenarioBatchExportRequest request, String exportType, String userId) throws Exception {
|
||||
File tmpDir = new File(LocalRepositoryDir.getSystemTempDir() + File.separatorChar + EXPORT_CASE_TMP_DIR + "_" + IDGenerator.nextStr());
|
||||
if (!tmpDir.mkdirs()) {
|
||||
|
@ -659,29 +1090,21 @@ public class ApiScenarioDataTransferService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Map<String, Map<String, String>> projectApiModuleIdMap = new HashMap<>();
|
||||
if (CollectionUtils.isNotEmpty(apiDefinitionIdList)) {
|
||||
List<ApiDefinitionWithBlob> apiList = extApiDefinitionMapper.selectApiDefinitionWithBlob(apiDefinitionIdList);
|
||||
List<String> projectIdList = apiList.stream().map(ApiDefinitionWithBlob::getProjectId).distinct().toList();
|
||||
projectIdList.forEach(projectId -> projectApiModuleIdMap.put(projectId, apiDefinitionExportService.buildModuleIdPathMap(request.getProjectId())));
|
||||
|
||||
for (ApiDefinitionWithBlob blob : apiList) {
|
||||
ApiDefinitionExportDetail detail = new ApiDefinitionExportDetail();
|
||||
BeanUtils.copyBean(detail, blob);
|
||||
if (blob.getRequest() != null) {
|
||||
detail.setRequest(ApiDataUtils.parseObject(new String(blob.getRequest()), AbstractMsTestElement.class));
|
||||
}
|
||||
if (blob.getResponse() != null) {
|
||||
detail.setResponse(ApiDataUtils.parseArray(new String(blob.getResponse()), HttpResponse.class));
|
||||
}
|
||||
detail.setName(blob.getName());
|
||||
detail.setProtocol(blob.getProtocol());
|
||||
detail.setMethod(blob.getMethod());
|
||||
detail.setPath(blob.getPath());
|
||||
detail.setStatus(blob.getStatus());
|
||||
detail.setTags(blob.getTags());
|
||||
detail.setPos(blob.getPos());
|
||||
detail.setDescription(blob.getDescription());
|
||||
|
||||
String moduleName;
|
||||
if (StringUtils.equals(blob.getModuleId(), ModuleConstants.DEFAULT_NODE_ID)) {
|
||||
moduleName = Translator.get("api_unplanned_request");
|
||||
|
@ -698,12 +1121,27 @@ public class ApiScenarioDataTransferService {
|
|||
}
|
||||
if (CollectionUtils.isNotEmpty(apiTestCaseWithBlobs)) {
|
||||
for (ApiTestCaseWithBlob apiTestCaseWithBlob : apiTestCaseWithBlobs) {
|
||||
String projectId = apiTestCaseWithBlob.getProjectId();
|
||||
if (!projectApiModuleIdMap.containsKey(projectId)) {
|
||||
projectApiModuleIdMap.put(projectId, apiDefinitionExportService.buildModuleIdPathMap(projectId));
|
||||
}
|
||||
String moduleId = apiTestCaseWithBlob.getModuleId();
|
||||
|
||||
ApiTestCaseDTO dto = new ApiTestCaseDTO();
|
||||
dto.setName(apiTestCaseWithBlob.getName());
|
||||
dto.setPriority(apiTestCaseWithBlob.getPriority());
|
||||
dto.setStatus(apiTestCaseWithBlob.getStatus());
|
||||
BeanUtils.copyBean(dto, apiTestCaseWithBlob);
|
||||
dto.setTags(apiTestCaseWithBlob.getTags());
|
||||
dto.setRequest(ApiDataUtils.parseObject(new String(apiTestCaseWithBlob.getRequest()), AbstractMsTestElement.class));
|
||||
|
||||
String moduleName;
|
||||
if (StringUtils.equals(moduleId, ModuleConstants.DEFAULT_NODE_ID)) {
|
||||
moduleName = Translator.get("api_unplanned_request");
|
||||
} else if (projectApiModuleIdMap.containsKey(projectId) && projectApiModuleIdMap.get(projectId).containsKey(moduleId)) {
|
||||
moduleName = projectApiModuleIdMap.get(projectId).get(moduleId);
|
||||
} else {
|
||||
dto.setModuleId(ModuleConstants.DEFAULT_NODE_ID);
|
||||
moduleName = Translator.get("api_unplanned_request");
|
||||
}
|
||||
dto.setModulePath(moduleName);
|
||||
response.addExportApiCase(dto);
|
||||
}
|
||||
}
|
||||
|
@ -740,3 +1178,38 @@ public class ApiScenarioDataTransferService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class ReplaceScenarioResource {
|
||||
private Map<String, ApiDefinitionDetail> apiDefinitionIdMap = new HashMap<>();
|
||||
private Map<String, ApiTestCaseDTO> apiTestCaseIdMap = new HashMap<>();
|
||||
private Map<String, ApiScenarioImportDetail> apiScenarioIdMap = new HashMap<>();
|
||||
|
||||
@Schema(description = "要新增的关联场景")
|
||||
List<ApiScenarioImportDetail> insertRelatedApiScenarioData = new ArrayList<>();
|
||||
|
||||
public ApiDefinitionDetail getApi(String apiOldId) {
|
||||
return apiDefinitionIdMap.get(apiOldId);
|
||||
}
|
||||
|
||||
public ApiTestCaseDTO getApiCase(String oldId) {
|
||||
return apiTestCaseIdMap.get(oldId);
|
||||
}
|
||||
|
||||
public ApiScenarioImportDetail getApiScenario(String oldId) {
|
||||
return apiScenarioIdMap.get(oldId);
|
||||
}
|
||||
|
||||
|
||||
public void putApiDefinitionId(String oldId, ApiDefinitionDetail newData) {
|
||||
apiDefinitionIdMap.put(oldId, newData);
|
||||
}
|
||||
|
||||
public void putApiTestCase(String oldId, ApiTestCaseDTO newData) {
|
||||
apiTestCaseIdMap.put(oldId, newData);
|
||||
}
|
||||
|
||||
public void putApiScenarioId(String oldId, ApiScenarioImportDetail newData) {
|
||||
apiScenarioIdMap.put(oldId, newData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,7 +405,7 @@ public class ApiDefinitionImportService {
|
|||
sqlSession.flushStatements();
|
||||
}
|
||||
|
||||
private String getMsTestElementStr(Object request) {
|
||||
public String getMsTestElementStr(Object request) {
|
||||
String requestStr = JSON.toJSONString(request);
|
||||
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(requestStr, AbstractMsTestElement.class);
|
||||
// 手动校验参数
|
||||
|
|
|
@ -1823,7 +1823,7 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
steps.forEach(dto -> {
|
||||
ApiScenarioStepDTO returnDTO = new ApiScenarioStepDTO();
|
||||
BeanUtils.copyBean(returnDTO, dto);
|
||||
if (!StringUtils.equalsIgnoreCase(parentId, dto.getId())) {
|
||||
if (StringUtils.isNotBlank(parentId) && !StringUtils.equalsIgnoreCase(parentId, dto.getId())) {
|
||||
returnDTO.setParentId(parentId);
|
||||
}
|
||||
if (returnDTO.getConfig() != null && StringUtils.isNotBlank(returnDTO.getConfig().toString())) {
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
package io.metersphere.api.utils;
|
||||
|
||||
import io.metersphere.api.constants.ApiConstants;
|
||||
import io.metersphere.api.dto.converter.ApiDefinitionDetail;
|
||||
import io.metersphere.api.dto.converter.ApiScenarioPreImportAnalysisResult;
|
||||
import io.metersphere.project.domain.Project;
|
||||
import io.metersphere.sdk.constants.HttpMethodConstants;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.system.log.dto.LogDTO;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class ApiScenarioImportUtils {
|
||||
public static LogDTO genImportLog(Project project, String dataId, String dataName, Object importData, String module, String operator, String operationType) {
|
||||
public static LogDTO genImportLog(Project project, String dataId, String dataName, Object targetList, String module, String operator, String operationType) {
|
||||
LogDTO dto = new LogDTO(
|
||||
project.getId(),
|
||||
project.getOrganizationId(),
|
||||
|
@ -19,7 +31,59 @@ public class ApiScenarioImportUtils {
|
|||
dto.setHistory(true);
|
||||
dto.setPath("/api/scenario/import");
|
||||
dto.setMethod(HttpMethodConstants.POST.name());
|
||||
dto.setOriginalValue(JSON.toJSONBytes(importData));
|
||||
dto.setOriginalValue(JSON.toJSONBytes(targetList));
|
||||
return dto;
|
||||
}
|
||||
|
||||
public static Map<String, ApiDefinitionDetail> getApiIdInTargetList(List<ApiDefinitionDetail> compareList, List<ApiDefinitionDetail> targetList, String protocol, String projectId, ApiScenarioPreImportAnalysisResult analysisResult) {
|
||||
if (CollectionUtils.isEmpty(compareList)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
if (targetList == null) {
|
||||
targetList = new ArrayList<>();
|
||||
}
|
||||
|
||||
// API类型,通过 Method & Path 组合判断,接口是否存在
|
||||
Map<String, ApiDefinitionDetail> targetApiIdMap = null;
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(protocol, ApiConstants.HTTP_PROTOCOL)) {
|
||||
targetApiIdMap = targetList.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), t -> t, (oldValue, newValue) -> newValue));
|
||||
} else {
|
||||
targetApiIdMap = targetList.stream().collect(Collectors.toMap(t -> t.getModulePath() + t.getName(), t -> t, (oldValue, newValue) -> newValue));
|
||||
}
|
||||
Map<String, ApiDefinitionDetail> prepareInsertApi = new HashMap<>();
|
||||
Map<String, ApiDefinitionDetail> apiIdDic = new HashMap<>();
|
||||
for (ApiDefinitionDetail compareApi : compareList) {
|
||||
String compareKey = StringUtils.equalsIgnoreCase(protocol, ApiConstants.HTTP_PROTOCOL) ?
|
||||
compareApi.getMethod() + compareApi.getPath() : compareApi.getModulePath() + compareApi.getName();
|
||||
// 去除文件中相同类型的接口
|
||||
|
||||
if (targetApiIdMap.containsKey(compareKey)) {
|
||||
apiIdDic.put(compareApi.getId(), targetApiIdMap.get(compareKey));
|
||||
} else {
|
||||
if (prepareInsertApi.containsKey(compareKey)) {
|
||||
apiIdDic.put(compareApi.getId(), prepareInsertApi.get(compareKey));
|
||||
} else {
|
||||
String oldId = compareApi.getId();
|
||||
compareApi.setProjectId(projectId);
|
||||
compareApi.setId(IDGenerator.nextStr());
|
||||
analysisResult.setApiDefinition(compareApi);
|
||||
apiIdDic.put(oldId, compareApi);
|
||||
prepareInsertApi.put(compareKey, compareApi);
|
||||
}
|
||||
}
|
||||
}
|
||||
return apiIdDic;
|
||||
}
|
||||
|
||||
public static boolean isApiExistence(String protocol, String method, String path, String modulePath, String apiDefinitionName, List<ApiDefinitionDetail> existenceApiDefinitionList) {
|
||||
Map<String, ApiDefinitionDetail> existenceMap = null;
|
||||
if (StringUtils.equalsIgnoreCase(protocol, ApiConstants.HTTP_PROTOCOL)) {
|
||||
existenceMap = existenceApiDefinitionList.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), t -> t, (oldValue, newValue) -> newValue));
|
||||
return existenceMap.containsKey(method + path);
|
||||
} else {
|
||||
existenceMap = existenceApiDefinitionList.stream().collect(Collectors.toMap(t -> t.getModulePath() + t.getName(), t -> t, (oldValue, newValue) -> newValue));
|
||||
return existenceMap.containsKey(modulePath + apiDefinitionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,14 +76,21 @@ public class ApiScenarioControllerImportAndExportTests extends BaseTest {
|
|||
ApiScenarioImportRequest request = new ApiScenarioImportRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType("jmeter");
|
||||
String importType = "jmeter";
|
||||
String fileSuffix = "jmx";
|
||||
FileInputStream inputStream = new FileInputStream(new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/import-scenario/" + importType + "/simple." + fileSuffix)).getPath()));
|
||||
MockMultipartFile file = new MockMultipartFile("file", "simple." + fileSuffix, MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
|
||||
FileInputStream inputStream = new FileInputStream(new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/import-scenario/jmeter/simple.jmx")).getPath()));
|
||||
MockMultipartFile file = new MockMultipartFile("file", "simple.jmx", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
|
||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||
paramMap.add("request", JSON.toJSONString(request));
|
||||
paramMap.add("file", file);
|
||||
this.requestMultipartWithOkAndReturn(URL_POST_IMPORT, paramMap);
|
||||
|
||||
|
||||
request.setType("metersphere");
|
||||
inputStream = new FileInputStream(new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/import-scenario/metersphere/simple.ms")).getPath()));
|
||||
file = new MockMultipartFile("file", "simple.ms", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
|
||||
paramMap = new LinkedMultiValueMap<>();
|
||||
paramMap.add("request", JSON.toJSONString(request));
|
||||
paramMap.add("file", file);
|
||||
this.requestMultipartWithOkAndReturn(URL_POST_IMPORT, paramMap);
|
||||
}
|
||||
|
||||
@Resource
|
||||
|
@ -132,26 +139,11 @@ public class ApiScenarioControllerImportAndExportTests extends BaseTest {
|
|||
|
||||
MetersphereApiScenarioExportResponse exportResponse = ApiDataUtils.parseObject(fileContent, MetersphereApiScenarioExportResponse.class);
|
||||
|
||||
Assertions.assertEquals(exportResponse.getExportScenarioList().size(), 3);
|
||||
Assertions.assertEquals(exportResponse.getExportScenarioList().size(), 8);
|
||||
|
||||
MsFileUtils.deleteDir("/tmp/api-scenario-export/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testImportMs() throws Exception {
|
||||
ApiScenarioImportRequest request = new ApiScenarioImportRequest();
|
||||
request.setProjectId(project.getId());
|
||||
request.setType("metersphere");
|
||||
String importType = "metersphere";
|
||||
FileInputStream inputStream = new FileInputStream(new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("file/import-scenario/" + importType + "/all.ms")).getPath()));
|
||||
MockMultipartFile file = new MockMultipartFile("file", "all.ms", MediaType.APPLICATION_OCTET_STREAM_VALUE, inputStream);
|
||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
||||
paramMap.add("request", JSON.toJSONString(request));
|
||||
paramMap.add("file", file);
|
||||
this.requestMultipartWithOkAndReturn(URL_POST_IMPORT, paramMap);
|
||||
}
|
||||
|
||||
private MvcResult download(String projectId, String fileId) throws Exception {
|
||||
return mockMvc.perform(MockMvcRequestBuilders.get("/api/scenario/download/file/" + projectId + "/" + fileId)
|
||||
.header(SessionConstants.HEADER_TOKEN, sessionId)
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -25,6 +25,9 @@ public class BaseTreeNode {
|
|||
@Schema(description = "父节点ID")
|
||||
private String parentId;
|
||||
|
||||
@Schema(description = "项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Schema(description = "子节点")
|
||||
private List<BaseTreeNode> children = new ArrayList<>();
|
||||
|
||||
|
|
Loading…
Reference in New Issue