From de26483f74a2d2b9ffa4d17b15980e8a8c860378 Mon Sep 17 00:00:00 2001 From: guoyuqi Date: Fri, 25 Feb 2022 19:15:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=87=AA=E5=8A=A8=E5=8C=96=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=86=8D=E5=AF=BC=E5=85=A5=E4=BF=9D=E7=95=99?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E5=85=B3=E7=B3=BB=E6=94=AF=E6=8C=81=E8=B7=A8?= =?UTF-8?q?=E7=A9=BA=E9=97=B4=E8=A1=A5=E5=85=85=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --user=郭雨琦 接口自动化场景导出再导入保留引用关系 场景导入导出跨空间,增加数据 https://www.tapd.cn/55049933/prong/stories/view/1155049933001003780 --- .../parse/ApiScenarioImportUtil.java | 203 +++++++++++++++++- .../automation/parse/MsScenarioParser.java | 70 +----- .../dto/definition/ApiDefinitionRequest.java | 2 + .../api/service/ApiAutomationService.java | 97 ++++++++- .../api/service/ApiDefinitionService.java | 33 ++- .../api/service/ApiTestCaseService.java | 19 +- .../db/migration/V110__v1.19_release.sql | 5 +- .../automation/scenario/EditApiScenario.vue | 4 +- .../automation/scenario/api/ApiRelevance.vue | 9 + .../scenario/api/ScenarioRelevance.vue | 9 + .../component/ApiScenarioComponent.vue | 43 ++-- .../comonents/base/TestCaseRelevanceBase.vue | 38 +++- 12 files changed, 402 insertions(+), 130 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ApiScenarioImportUtil.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ApiScenarioImportUtil.java index 6c170041bb..e43c1060f4 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ApiScenarioImportUtil.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ApiScenarioImportUtil.java @@ -1,16 +1,28 @@ package io.metersphere.api.dto.automation.parse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.automation.ApiScenarioModuleDTO; +import io.metersphere.api.dto.definition.ApiDefinitionRequest; +import io.metersphere.api.dto.definition.ApiDefinitionResult; +import io.metersphere.api.dto.definition.SaveApiTestCaseRequest; import io.metersphere.api.dto.definition.parse.ms.NodeTree; +import io.metersphere.api.service.ApiDefinitionService; import io.metersphere.api.service.ApiScenarioModuleService; -import io.metersphere.base.domain.ApiScenarioModule; +import io.metersphere.api.service.ApiTestCaseService; +import io.metersphere.base.domain.*; +import io.metersphere.base.mapper.ApiDefinitionMapper; +import io.metersphere.base.mapper.ApiTestCaseMapper; +import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.service.ProjectService; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import java.util.Iterator; -import java.util.List; +import java.util.*; public class ApiScenarioImportUtil { @@ -106,4 +118,189 @@ public class ApiScenarioImportUtil { } } + public static boolean checkWorkSpace(String projectId, String currentProjectId) { + if(!Objects.equals(projectId, currentProjectId)){ + ProjectService projectService = CommonBeanFactory.getBean(ProjectService.class); + Project project = projectService.getProjectById(projectId); + return Objects.equals(project.getWorkspaceId(), SessionUtils.getCurrentWorkspaceId()); + } + return true; + } + + private static ApiDefinitionResult getApiDefinitionResult(JSONObject object, ApiDefinitionService apiDefinitionService) { + ApiDefinitionRequest apiDefinitionRequest = new ApiDefinitionRequest(); + apiDefinitionRequest.setPath(object.getString("path")); + apiDefinitionRequest.setMethod(object.getString("method")); + apiDefinitionRequest.setPath(object.getString("protocol")); + return apiDefinitionService.getApiDefinitionResult(apiDefinitionRequest); + } + + private static ApiTestCaseWithBLOBs getApiTestCase(JSONObject object, ApiTestCaseService testCaseService, ApiDefinitionResult apiDefinitionResult) { + SaveApiTestCaseRequest request = new SaveApiTestCaseRequest(); + request.setName(object.getString("name")); + request.setApiDefinitionId(apiDefinitionResult.getId()); + return testCaseService.getSameCaseWithBLOBs(request); + } + + public static void checkCase(JSONObject object, String versionId, String projectId, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) { + ApiTestCaseService testCaseService = CommonBeanFactory.getBean(ApiTestCaseService.class); + ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class); + ApiTestCaseWithBLOBs bloBs = testCaseService.get(object.getString("id")); + if (bloBs != null) { + boolean isSameWorkSpace = checkWorkSpace(bloBs.getProjectId(),projectId); + if(!isSameWorkSpace){ + ApiDefinitionResult apiDefinition = apiDefinitionService.getById(bloBs.getApiDefinitionId()); + String apiDefinitionId = checkDefinition(apiDefinitionService,apiDefinition, versionId,projectId,apiDefinitionMapper); + structureCaseData(bloBs,apiDefinitionId,versionId,projectId,apiTestCaseMapper); + object.put("projectId", projectId); + object.put("id", bloBs.getId()); + } + }else{ + ApiDefinitionResult apiDefinition = getApiDefinitionResult(object,apiDefinitionService); + ApiTestCaseWithBLOBs testCase; + if(apiDefinition!=null){ + testCase= getApiTestCase(object, testCaseService, apiDefinition); + if (testCase != null) { + boolean isSameWorkSpace = checkWorkSpace(testCase.getProjectId(),projectId); + if(!isSameWorkSpace){ + String apiDefinitionId = checkDefinition(apiDefinitionService, apiDefinition, versionId,projectId,apiDefinitionMapper); + structureCaseData(testCase,apiDefinitionId,versionId,projectId,apiTestCaseMapper); + } + }else{ + String apiDefinitionId = checkDefinition(apiDefinitionService, apiDefinition, versionId,projectId,apiDefinitionMapper); + testCase= structureCaseByJson(object, versionId, projectId, apiDefinitionId,apiTestCaseMapper); + } + }else{ + ApiDefinitionResult apiDefinitionResult = structureApiDefinitionByJson(apiDefinitionService, object, versionId, projectId, apiDefinitionMapper); + testCase = structureCaseByJson(object, versionId, projectId, apiDefinitionResult.getId(),apiTestCaseMapper); + } + object.put("projectId", projectId); + object.put("id", testCase.getId()); + } + } + + private static String checkDefinition(ApiDefinitionService apiDefinitionService, ApiDefinitionResult apiDefinition, String versionId, String projectId,ApiDefinitionMapper apiDefinitionMapper) { + boolean isSameWorkspace = checkWorkSpace(apiDefinition.getProjectId(),projectId); + if(!isSameWorkspace){ + String requestStr = apiDefinition.getRequest(); + JSONObject objectDefinition = JSONObject.parseObject(requestStr); + ApiDefinitionResult apiDefinitionResult1 = insertDefinitionByApiDefinition(apiDefinitionService,apiDefinition, objectDefinition, versionId, projectId,apiDefinitionMapper); + return apiDefinitionResult1.getId(); + }else{ + return apiDefinition.getId(); + } + } + + private static void structureCaseData(ApiTestCaseWithBLOBs testCase, String apiDefinitionId, String versionId, String projectId,ApiTestCaseMapper apiTestCaseMapper) { + String requestStr = testCase.getRequest(); + JSONObject objectCase = JSONObject.parseObject(requestStr); + testCase.setApiDefinitionId(apiDefinitionId); + insertCaseByApiTestCase(testCase,objectCase,versionId,projectId,apiTestCaseMapper); + } + + public static ApiDefinitionResult structureApiDefinitionByJson(ApiDefinitionService apiDefinitionService,JSONObject object, String versionId, String projectId,ApiDefinitionMapper apiDefinitionMapper) { + ApiDefinitionResult test = new ApiDefinitionResult(); + apiDefinitionService.checkQuota(); + String protocal = object.getString("protocal"); + if (StringUtils.equals(protocal, "DUBBO")) { + test.setMethod("dubbo://"); + }else{ + test.setMethod(protocal); + } + apiDefinitionService.initModulePathAndId(projectId, test); + String id = UUID.randomUUID().toString(); + test.setId(id); + test.setName(object.getString("name")); + test.setPath(object.getString("path")); + test.setCreateUser(SessionUtils.getUserId()); + test.setProjectId(projectId); + test.setCreateTime(System.currentTimeMillis()); + test.setUpdateTime(System.currentTimeMillis()); + test.setStatus(APITestStatus.Underway.name()); + test.setRefId(id); + test.setLatest(true); + test.setVersionId(versionId); + object.put("id", test.getId()); + object.put("resourceId", test.getId()); + object.put("projectId", projectId); + object.put("useEnvironment",""); + test.setRequest(object.toJSONString()); + test.setUserId(SessionUtils.getUserId()); + test.setLatest(true); + test.setOrder(apiDefinitionService.getImportNextOrder(projectId)); + apiDefinitionMapper.insert(test); + return test; + } + + public static ApiDefinitionResult insertDefinitionByApiDefinition(ApiDefinitionService apiDefinitionService, ApiDefinitionResult apiDefinitionResult, JSONObject objectDefinition, String versionId, String projectId,ApiDefinitionMapper apiDefinitionMapper){ + String id = UUID.randomUUID().toString(); + apiDefinitionResult.setId(id); + apiDefinitionResult.setProjectId(projectId); + apiDefinitionResult.setVersionId(versionId); + apiDefinitionResult.setRefId(id); + apiDefinitionResult.setLatest(true); + objectDefinition.put("id", id); + objectDefinition.put("resourceId", id); + objectDefinition.put("projectId", projectId); + objectDefinition.put("useEnvironment",""); + apiDefinitionService.initModulePathAndId(projectId, apiDefinitionResult); + apiDefinitionResult.setRequest(JSON.toJSONString(objectDefinition)); + apiDefinitionResult.setOrder(apiDefinitionService.getImportNextOrder(projectId)); + apiDefinitionMapper.insert(apiDefinitionResult); + return apiDefinitionResult; + } + + public static ApiTestCaseWithBLOBs structureCaseByJson(JSONObject object, String versionId, String projectId, String apiDefinitionId,ApiTestCaseMapper apiTestCaseMapper) { + ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class); + ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs(); + String id = UUID.randomUUID().toString(); + apiTestCase.setId(id); + apiTestCase.setName(object.getString("name")); + apiTestCase.setCaseStatus(APITestStatus.Underway.name()); + apiTestCase.setApiDefinitionId(apiDefinitionId); + apiTestCase.setCreateUserId(Objects.requireNonNull(SessionUtils.getUser()).getId()); + apiTestCase.setUpdateUserId(Objects.requireNonNull(SessionUtils.getUser()).getId()); + apiTestCase.setProjectId(projectId); + apiTestCase.setCreateTime(System.currentTimeMillis()); + apiTestCase.setUpdateTime(System.currentTimeMillis()); + apiTestCase.setVersionId(versionId); + object.put("id", apiTestCase.getId()); + object.put("resourceId", apiTestCase.getId()); + object.put("projectId", projectId); + object.put("useEnvironment",""); + apiTestCase.setRequest(object.toJSONString()); + apiTestCase.setOrder(apiDefinitionService.getImportNextCaseOrder(projectId)); + apiTestCaseMapper.insert(apiTestCase); + return apiTestCase; + } + + public static void insertCaseByApiTestCase(ApiTestCaseWithBLOBs bloBs, JSONObject objectCase, String versionId, String projectId,ApiTestCaseMapper apiTestCaseMapper){ + ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class); + String id = UUID.randomUUID().toString(); + bloBs.setId(id); + bloBs.setProjectId(projectId); + bloBs.setVersionId(versionId); + objectCase.put("id", id); + objectCase.put("resourceId", id); + objectCase.put("projectId", projectId); + objectCase.put("useEnvironment",""); + bloBs.setRequest(JSON.toJSONString(objectCase)); + bloBs.setOrder(apiDefinitionService.getImportNextCaseOrder(projectId)); + apiTestCaseMapper.insert(bloBs); + } + + public static void formatHashTree(JSONArray hashTree) { + if (CollectionUtils.isNotEmpty(hashTree)) { + for (int i = 0; i < hashTree.size(); i++) { + JSONObject object = (JSONObject) hashTree.get(i); + object.put("index", i + 1); + object.put("resourceId", UUID.randomUUID().toString()); + hashTree.set(i, object); + if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) { + formatHashTree(object.getJSONArray("hashTree")); + } + } + } + } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsScenarioParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsScenarioParser.java index 2c3345ceb6..f0ee0f0899 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsScenarioParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsScenarioParser.java @@ -1,21 +1,15 @@ package io.metersphere.api.dto.automation.parse; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.definition.parse.ms.NodeTree; import io.metersphere.api.dto.definition.request.MsScenario; +import io.metersphere.base.domain.*; import io.metersphere.plugin.core.MsTestElement; import io.metersphere.api.parse.MsAbstractParser; -import io.metersphere.api.service.ApiAutomationService; -import io.metersphere.api.service.ApiTestCaseService; -import io.metersphere.base.domain.ApiScenarioModule; -import io.metersphere.base.domain.ApiScenarioWithBLOBs; -import io.metersphere.base.domain.ApiTestCaseWithBLOBs; -import io.metersphere.commons.utils.CommonBeanFactory; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -66,20 +60,6 @@ public class MsScenarioParser extends MsAbstractParser { return scenarioWithBLOBs; } - private void formatHashTree(JSONArray hashTree) { - if (CollectionUtils.isNotEmpty(hashTree)) { - for (int i = 0; i < hashTree.size(); i++) { - JSONObject object = (JSONObject) hashTree.get(i); - object.put("index", i + 1); - object.put("resourceId", UUID.randomUUID().toString()); - hashTree.set(i, object); - if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) { - formatHashTree(object.getJSONArray("hashTree")); - } - } - } - } - private ScenarioImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) { ScenarioImport scenarioImport = JSON.parseObject(testStr, ScenarioImport.class); List data = scenarioImport.getData(); @@ -102,9 +82,6 @@ public class MsScenarioParser extends MsAbstractParser { if (StringUtils.isNotBlank(scenarioDefinitionStr)) { JSONObject scenarioDefinition = JSONObject.parseObject(scenarioDefinitionStr); if (scenarioDefinition != null) { - JSONArray hashTree = scenarioDefinition.getJSONArray("hashTree"); - formatHashTree(hashTree); - setCopy(hashTree); JSONObject environmentMap = scenarioDefinition.getJSONObject("environmentMap"); if (environmentMap != null) { scenarioDefinition.put("environmentMap", new HashMap<>()); @@ -127,61 +104,18 @@ public class MsScenarioParser extends MsAbstractParser { // 旧版本未导出模块 parseModule(item.getModulePath(), importRequest, item); } - -// item.setId(UUID.randomUUID().toString()); item.setProjectId(this.projectId); }); } return scenarioImport; } - private void setCopy(JSONArray hashTree) { - // 将引用转成复制 - if (CollectionUtils.isNotEmpty(hashTree)) { - for (int i = 0; i < hashTree.size(); i++) { - JSONObject object = (JSONObject) hashTree.get(i); - String referenced = object.getString("referenced"); - if (StringUtils.isNotBlank(referenced) && StringUtils.equals(referenced, "REF")) { - // 检测引用对象是否存在,若果不存在则改成复制对象 - String refType = object.getString("refType"); - boolean isCopy = true; - if (StringUtils.isNotEmpty(refType)) { - if (refType.equals("CASE")) { - ApiTestCaseService testCaseService = CommonBeanFactory.getBean(ApiTestCaseService.class); - ApiTestCaseWithBLOBs bloBs = testCaseService.get(object.getString("id")); - if (bloBs != null) { - isCopy = false; - } - } else { - ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class); - ApiScenarioWithBLOBs bloBs = apiAutomationService.getDto(object.getString("id")); - if (bloBs != null) { - isCopy = false; - } - } - } - if (isCopy) { - object.put("referenced", "Copy"); - } - } - object.put("projectId", ""); - JSONObject environmentMap = object.getJSONObject("environmentMap"); - if (environmentMap != null) { - object.put("environmentMap", new HashMap<>()); - } - if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) { - setCopy(object.getJSONArray("hashTree")); - } - } - } - } - protected void parseModule(String modulePath, ApiTestImportRequest importRequest, ApiScenarioWithBLOBs apiScenarioWithBLOBs) { if (StringUtils.isEmpty(modulePath)) { return; } if (modulePath.startsWith("/")) { - modulePath = modulePath.substring(1, modulePath.length()); + modulePath = modulePath.substring(1); } if (modulePath.endsWith("/")) { modulePath = modulePath.substring(0, modulePath.length() - 1); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java index cfd798f1bb..81c7d5b30b 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/ApiDefinitionRequest.java @@ -23,6 +23,8 @@ public class ApiDefinitionRequest extends BaseQueryRequest { private String reviewId; private String refId; private String versionId; + private String path; + private String method; // 测试计划是否允许重复 private boolean repeatCase; diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 08dc943a5c..21f25bc99d 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.*; import io.metersphere.api.dto.automation.*; +import io.metersphere.api.dto.automation.parse.ApiScenarioImportUtil; import io.metersphere.api.dto.automation.parse.ScenarioImport; import io.metersphere.api.dto.automation.parse.ScenarioImportParserFactory; import io.metersphere.api.dto.datacount.ApiDataCountResult; @@ -240,7 +241,14 @@ public class ApiAutomationService { request.setCustomNum(String.valueOf(nextNum)); } checkScenarioNum(request); - final ApiScenarioWithBLOBs scenario = buildSaveScenario(request); + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); + ApiDefinitionMapper apiDefinitionMapper = sqlSession.getMapper(ApiDefinitionMapper.class); + final ApiScenarioWithBLOBs scenario = buildSaveScenario(request,apiTestCaseMapper,apiDefinitionMapper); + sqlSession.flushStatements(); + if (sqlSession != null && sqlSessionFactory != null) { + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } scenario.setVersion(0); scenario.setCreateTime(System.currentTimeMillis()); @@ -346,7 +354,16 @@ public class ApiAutomationService { //如果场景有TCP步骤的话,也要做参数计算处理 tcpApiParamService.checkTestElement(request.getScenarioDefinition()); - final ApiScenarioWithBLOBs scenario = buildSaveScenario(request); + //检查是否要增加引用的步骤的CASE类型的数据 + SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); + ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); + ApiDefinitionMapper apiDefinitionMapper = sqlSession.getMapper(ApiDefinitionMapper.class); + final ApiScenarioWithBLOBs scenario = buildSaveScenario(request,apiTestCaseMapper,apiDefinitionMapper); + + sqlSession.flushStatements(); + if (sqlSession != null && sqlSessionFactory != null) { + SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); + } ApiScenarioWithBLOBs beforeScenario = apiScenarioMapper.selectByPrimaryKey(request.getId()); Integer version = beforeScenario.getVersion(); @@ -387,6 +404,8 @@ public class ApiAutomationService { extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name,同步到修改首页定时任务 uploadFiles(request, bodyFiles, scenarioFiles); + + // 存储依赖关系 ApiAutomationRelationshipEdgeService relationshipEdgeService = CommonBeanFactory.getBean(ApiAutomationRelationshipEdgeService.class); if (relationshipEdgeService != null) { @@ -396,6 +415,19 @@ public class ApiAutomationService { return scenario; } + private void checkReferenceCase(ApiScenarioWithBLOBs scenario,ApiTestCaseMapper apiTestCaseMapper,ApiDefinitionMapper apiDefinitionMapper) { + if (scenario == null || StringUtils.isEmpty(scenario.getScenarioDefinition())) { + return; + } + if (scenario.getScenarioDefinition().contains("\"referenced\":\"REF\"")) { + JSONObject element = JSON.parseObject(scenario.getScenarioDefinition()); + JSONArray hashTree = element.getJSONArray("hashTree"); + ApiScenarioImportUtil.formatHashTree(hashTree); + setReferenced(hashTree,scenario.getVersionId(),scenario.getProjectId(),apiTestCaseMapper,apiDefinitionMapper); + scenario.setScenarioDefinition(JSONObject.toJSONString(element)); + } + } + private void checkAndSetLatestVersion(String refId) { extApiScenarioMapper.clearLatestVersion(refId); extApiScenarioMapper.addLatestVersion(refId); @@ -424,7 +456,7 @@ public class ApiAutomationService { .map(MsHTTPSamplerProxy::getId).collect(Collectors.toSet()); } - public ApiScenarioWithBLOBs buildSaveScenario(SaveApiScenarioRequest request) { + public ApiScenarioWithBLOBs buildSaveScenario(SaveApiScenarioRequest request,ApiTestCaseMapper apiTestCaseMapper,ApiDefinitionMapper apiDefinitionMapper) { ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs(); scenario.setId(request.getId()); scenario.setName(request.getName()); @@ -473,6 +505,7 @@ public class ApiAutomationService { } else { scenario.setVersionId(request.getVersionId()); } + checkReferenceCase(scenario,apiTestCaseMapper,apiDefinitionMapper); return scenario; } @@ -1112,7 +1145,7 @@ public class ApiAutomationService { } private void _importCreate(List sameRequest, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, - ApiScenarioWithBLOBs scenarioWithBLOBs, ApiTestImportRequest apiTestImportRequest) { + ApiScenarioWithBLOBs scenarioWithBLOBs, ApiTestImportRequest apiTestImportRequest,ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) { if (CollectionUtils.isEmpty(sameRequest)) { scenarioWithBLOBs.setId(UUID.randomUUID().toString()); List useUrl = this.parseUrl(scenarioWithBLOBs); @@ -1126,6 +1159,7 @@ public class ApiAutomationService { scenarioWithBLOBs.setVersionId(apiTestImportRequest.getDefaultVersion()); } scenarioWithBLOBs.setLatest(true); + checkReferenceCase(scenarioWithBLOBs,apiTestCaseMapper,apiDefinitionMapper); batchMapper.insert(scenarioWithBLOBs); apiScenarioReferenceIdService.saveByApiScenario(scenarioWithBLOBs); } else { @@ -1156,6 +1190,7 @@ public class ApiAutomationService { scenarioWithBLOBs.setUseUrl(JSONArray.toJSONString(useUrl)); batchMapper.updateByPrimaryKeyWithBLOBs(scenarioWithBLOBs); } + checkReferenceCase(scenarioWithBLOBs,apiTestCaseMapper,apiDefinitionMapper); apiScenarioReferenceIdService.saveByApiScenario(scenarioWithBLOBs); extApiScenarioMapper.clearLatestVersion(scenarioWithBLOBs.getRefId()); extApiScenarioMapper.addLatestVersion(scenarioWithBLOBs.getRefId()); @@ -1163,7 +1198,7 @@ public class ApiAutomationService { } private ApiScenarioWithBLOBs importCreate(ApiScenarioWithBLOBs request, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, - ApiTestImportRequest apiTestImportRequest) { + ApiTestImportRequest apiTestImportRequest,ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) { final ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs(); BeanUtils.copyBean(scenarioWithBLOBs, request); scenarioWithBLOBs.setCreateTime(System.currentTimeMillis()); @@ -1212,7 +1247,7 @@ public class ApiAutomationService { } if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) { - _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest); + _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest,apiTestCaseMapper,apiDefinitionMapper); } else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) { if (CollectionUtils.isEmpty(sameRequest)) { List useUrl = this.parseUrl(scenarioWithBLOBs); @@ -1226,8 +1261,8 @@ public class ApiAutomationService { scenarioWithBLOBs.setVersionId(apiTestImportRequest.getDefaultVersion()); } scenarioWithBLOBs.setLatest(true); + checkReferenceCase(scenarioWithBLOBs,apiTestCaseMapper,apiDefinitionMapper); batchMapper.insert(scenarioWithBLOBs); - // 存储依赖关系 ApiAutomationRelationshipEdgeService relationshipEdgeService = CommonBeanFactory.getBean(ApiAutomationRelationshipEdgeService.class); if (relationshipEdgeService != null) { @@ -1237,7 +1272,7 @@ public class ApiAutomationService { } } else { - _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest); + _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest,apiTestCaseMapper,apiDefinitionMapper); } return scenarioWithBLOBs; } @@ -1246,6 +1281,8 @@ public class ApiAutomationService { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); ApiScenarioMapper batchMapper = sqlSession.getMapper(ApiScenarioMapper.class); ExtApiScenarioMapper extApiScenarioMapper = sqlSession.getMapper(ExtApiScenarioMapper.class); + ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); + ApiDefinitionMapper apiDefinitionMapper = sqlSession.getMapper(ApiDefinitionMapper.class); List data = apiImport.getData(); currentScenarioOrder.remove(); int num = 0; @@ -1283,7 +1320,7 @@ public class ApiAutomationService { item.setId(UUID.randomUUID().toString()); } // 导入之后刷新latest - importCreate(item, batchMapper, extApiScenarioMapper, request); + importCreate(item, batchMapper, extApiScenarioMapper, request,apiTestCaseMapper,apiDefinitionMapper); if (i % 300 == 0) { sqlSession.flushStatements(); } @@ -1571,7 +1608,6 @@ public class ApiAutomationService { return urlList; } - public ScenarioEnv getApiScenarioProjectId(String id) { ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(id); ScenarioEnv scenarioEnv = new ScenarioEnv(); @@ -1953,4 +1989,45 @@ public class ApiAutomationService { }); return strings; } + + private void setReferenced(JSONArray hashTree,String versionId,String projectId, ApiTestCaseMapper apiTestCaseMapper,ApiDefinitionMapper apiDefinitionMapper) { + // 将引用转成复制 + if (CollectionUtils.isNotEmpty(hashTree)) { + for (int i = 0; i < hashTree.size(); i++) { + JSONObject object = (JSONObject) hashTree.get(i); + String referenced = object.getString("referenced"); + if (StringUtils.isNotBlank(referenced) && StringUtils.equals(referenced, "REF")) { + // 检测引用对象是否存在,若果不存在则改成复制对象 + String refType = object.getString("refType"); + if (StringUtils.isNotEmpty(refType)) { + if (refType.equals("CASE")) { + ApiScenarioImportUtil.checkCase(object,versionId,projectId,apiTestCaseMapper,apiDefinitionMapper); + } else { + checkAutomation(object,projectId); + } + }else{ + object.put("referenced", "Copy"); + } + } + JSONObject environmentMap = object.getJSONObject("environmentMap"); + if (environmentMap != null) { + object.put("environmentMap", new HashMap<>()); + } + if (CollectionUtils.isNotEmpty(object.getJSONArray("hashTree"))) { + setReferenced(object.getJSONArray("hashTree"),versionId,projectId,apiTestCaseMapper,apiDefinitionMapper); + } + } + } + } + + public void checkAutomation(JSONObject object, String projectId) { + ApiScenarioWithBLOBs bloBs = getDto(object.getString("id")); + if (bloBs != null) { + boolean isSameWorkSpace = ApiScenarioImportUtil.checkWorkSpace(bloBs.getProjectId(),projectId); + if(!isSameWorkSpace){ + object.put("referenced", "Copy"); + } + } + } + } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index 0ec275a978..27b3bcdda1 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -325,7 +325,7 @@ public class ApiDefinitionService { return getBLOBs(returnModel.getId()); } - private void checkQuota() { + public void checkQuota() { QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class); if (quotaService != null) { quotaService.checkAPIDefinitionQuota(); @@ -688,13 +688,7 @@ public class ApiDefinitionService { test.setVersionId(request.getVersionId()); test.setLatest(true); // 新建一定是最新的 if (StringUtils.isEmpty(request.getModuleId()) || "default-module".equals(request.getModuleId())) { - ApiModuleExample example = new ApiModuleExample(); - example.createCriteria().andProjectIdEqualTo(test.getProjectId()).andProtocolEqualTo(test.getProtocol()).andNameEqualTo("未规划接口"); - List modules = apiModuleMapper.selectByExample(example); - if (CollectionUtils.isNotEmpty(modules)) { - test.setModuleId(modules.get(0).getId()); - test.setModulePath("/未规划接口"); - } + initModulePathAndId(test.getProjectId(), test); } test.setResponse(JSONObject.toJSONString(request.getResponse())); test.setEnvironmentId(request.getEnvironmentId()); @@ -791,7 +785,7 @@ public class ApiDefinitionService { return apiDefinition; } - private Long getImportNextOrder(String projectId) { + public Long getImportNextOrder(String projectId) { Long order = currentApiOrder.get(); if (order == null) { order = ServiceUtils.getNextOrder(projectId, extApiDefinitionMapper::getLastOrder); @@ -801,7 +795,7 @@ public class ApiDefinitionService { return order; } - private Long getImportNextCaseOrder(String projectId) { + public Long getImportNextCaseOrder(String projectId) { Long order = currentApiCaseOrder.get(); if (order == null) { order = ServiceUtils.getNextOrder(projectId, extApiTestCaseMapper::getLastOrder); @@ -2002,4 +1996,23 @@ public class ApiDefinitionService { SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); } } + + public ApiDefinitionResult getApiDefinitionResult(ApiDefinitionRequest request) { + List resList = extApiDefinitionMapper.list(request); + if(resList==null){ + return null; + } + return resList.get(0); + } + + public void initModulePathAndId(String projectId, ApiDefinitionWithBLOBs test) { + ApiModuleExample example = new ApiModuleExample(); + example.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(test.getProtocol()).andNameEqualTo("未规划接口"); + List modules = apiModuleMapper.selectByExample(example); + if (CollectionUtils.isNotEmpty(modules)) { + test.setModuleId(modules.get(0).getId()); + test.setModulePath("/未规划接口"); + } + } + } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java index bb1753d894..022a6b0a44 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java @@ -129,7 +129,6 @@ public class ApiTestCaseService { public List listSimple(ApiTestCaseRequest request) { request = this.initRequest(request, true, true); - List apiTestCases = extApiTestCaseMapper.listSimple(request); if (CollectionUtils.isEmpty(apiTestCases)) { return apiTestCases; @@ -1059,4 +1058,22 @@ public class ApiTestCaseService { List follows = apiTestCaseFollowMapper.selectByExample(example); return follows.stream().map(ApiTestCaseFollow::getFollowId).distinct().collect(Collectors.toList()); } + + public ApiTestCaseWithBLOBs getSameCaseWithBLOBs(SaveApiTestCaseRequest request) { + ApiTestCaseExample example = new ApiTestCaseExample(); + ApiTestCaseExample.Criteria criteria = example.createCriteria(); + criteria.andStatusNotEqualTo("Trash").andNameEqualTo(request.getName()).andApiDefinitionIdEqualTo(request.getApiDefinitionId()); + if (StringUtils.isNotBlank(request.getId())) { + criteria.andIdNotEqualTo(request.getId()); + } + if (StringUtils.isNotBlank(request.getVersionId())) { + criteria.andVersionIdEqualTo(request.getVersionId()); + } + List apiTestCaseWithBLOBs = apiTestCaseMapper.selectByExampleWithBLOBs(example); + if (CollectionUtils.isNotEmpty(apiTestCaseWithBLOBs)) { + return apiTestCaseWithBLOBs.get(0); + } + return null; + } + } diff --git a/backend/src/main/resources/db/migration/V110__v1.19_release.sql b/backend/src/main/resources/db/migration/V110__v1.19_release.sql index 179a7aabbe..ef2581a5ec 100644 --- a/backend/src/main/resources/db/migration/V110__v1.19_release.sql +++ b/backend/src/main/resources/db/migration/V110__v1.19_release.sql @@ -38,4 +38,7 @@ END DELIMITER ; CALL project_api_appl(); -DROP PROCEDURE IF EXISTS project_api_appl; \ No newline at end of file +DROP PROCEDURE IF EXISTS project_api_appl; + +ALTER TABLE `api_definition` ADD INDEX methodIndex ( `method` ); +ALTER TABLE `api_definition` ADD INDEX protocolIndex ( `protocol` ); \ No newline at end of file diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index 370bfac407..541b5b6c52 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -261,7 +261,7 @@ :scenario-definition="scenarioDefinition"/> - + - + diff --git a/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue b/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue index c9966242b7..41ad0ffad2 100644 --- a/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue +++ b/frontend/src/business/components/api/automation/scenario/api/ApiRelevance.vue @@ -1,5 +1,6 @@