From 23d76b335d125505563a25d2be51ec98c5d7aeb6 Mon Sep 17 00:00:00 2001 From: guoyuqi <xiaomeinvG@126.com> Date: Tue, 21 Jun 2022 17:23:45 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E5=9C=BA=E6=99=AF=E6=8E=A5=E5=8F=A3=E6=A8=A1=E5=9D=97=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E9=80=BB=E8=BE=91=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --user=郭雨琦 --- .../api/controller/ApiModuleController.java | 6 - .../dto/automation/ApiScenarioModuleDTO.java | 4 +- .../automation/UpdateScenarioModuleDTO.java | 16 + .../parse/ApiScenarioImportUtil.java | 6 + .../dto/automation/parse/EsbDataParser.java | 5 +- .../automation/parse/HarScenarioParser.java | 93 +-- .../dto/automation/parse/MsJmeterParser.java | 26 +- .../automation/parse/MsScenarioParser.java | 73 +- .../parse/PostmanScenarioParser.java | 20 +- .../api/dto/definition/ApiModuleDTO.java | 2 + .../dto/definition/UpdateApiModuleDTO.java | 17 + .../api/dto/definition/parse/ESBParser.java | 95 +-- .../api/dto/definition/parse/HarParser.java | 22 - .../parse/JmeterDefinitionParser.java | 31 +- .../definition/parse/MsDefinitionParser.java | 79 +- .../parse/PostmanDefinitionParser.java | 40 +- .../dto/definition/parse/Swagger2Parser.java | 35 +- .../dto/definition/parse/Swagger3Parser.java | 57 +- .../api/parse/ApiImportAbstractParser.java | 1 + .../api/service/ApiAutomationService.java | 81 ++- .../api/service/ApiDefinitionService.java | 257 ++++--- .../api/service/ApiModuleService.java | 686 +++++++++++++++++- .../api/service/ApiScenarioModuleService.java | 446 +++++++++++- .../mapper/ext/ExtApiDefinitionMapper.java | 12 +- .../mapper/ext/ExtApiDefinitionMapper.xml | 236 ++++-- .../base/mapper/ext/ExtApiScenarioMapper.java | 6 + .../base/mapper/ext/ExtApiScenarioMapper.xml | 42 ++ .../base/mapper/ext/ExtLoadTestMapper.xml | 102 +-- .../ext/ExtSwaggerUrlScheduleMapper.xml | 2 +- .../components/import/ApiImport.vue | 6 - 30 files changed, 1792 insertions(+), 712 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java create mode 100644 backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiModuleController.java b/backend/src/main/java/io/metersphere/api/controller/ApiModuleController.java index 36585ceedc..d42b24d650 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiModuleController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiModuleController.java @@ -46,12 +46,6 @@ public class ApiModuleController { return apiModuleService.countTrashApiData(projectId, protocol); } - @GetMapping("/getModuleByName/{projectId}/{protocol}") - public ApiModule getModuleByName(@PathVariable String projectId, @PathVariable String protocol) { -// checkPermissionService.checkProjectOwner(projectId); - return apiModuleService.getModuleByName(projectId, protocol); - } - @GetMapping("/getUserDefaultApiType") public String getUserDefaultApiType() { String returnStr = ApiDefinitionDefaultApiTypeUtil.HTTP; diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioModuleDTO.java index c4e9200298..154aaccfd4 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioModuleDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioModuleDTO.java @@ -1,13 +1,11 @@ package io.metersphere.api.dto.automation; -import io.metersphere.base.domain.ApiScenarioModule; import io.metersphere.track.dto.TreeNodeDTO; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public class ApiScenarioModuleDTO extends TreeNodeDTO<ApiScenarioModuleDTO> { + private String path; } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java new file mode 100644 index 0000000000..534d963ba8 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/automation/UpdateScenarioModuleDTO.java @@ -0,0 +1,16 @@ +package io.metersphere.api.dto.automation; + +import io.metersphere.base.domain.ApiScenarioModule; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class UpdateScenarioModuleDTO { + private List<ApiScenarioModule> moduleList; + private List<ApiScenarioWithBLOBs> needUpdateList; + private List<ApiScenarioWithBLOBs> apiScenarioWithBLOBsList; +} 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 584173a95a..2fe45151ce 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 @@ -247,6 +247,9 @@ public class ApiScenarioImportUtil { test.setUserId(SessionUtils.getUserId()); test.setLatest(true); test.setOrder(apiDefinitionService.getImportNextOrder(projectId)); + if (test.getName().length() > 255) { + test.setName(test.getName().substring(0, 255)); + } apiDefinitionMapper.insert(test); definitionMap.put(object.getString("path") + object.getString("method") + object.getString("protocol"), test); return test; @@ -279,6 +282,9 @@ public class ApiScenarioImportUtil { objectNew.remove("referenced"); apiTestCase.setRequest(objectNew.toJSONString()); apiTestCase.setOrder(apiDefinitionService.getImportNextCaseOrder(projectId)); + if (apiTestCase.getName().length() > 255) { + apiTestCase.setName(apiTestCase.getName().substring(0, 255)); + } apiTestCaseMapper.insert(apiTestCase); } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/EsbDataParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/EsbDataParser.java index 577aea787e..f270bdb47f 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/EsbDataParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/EsbDataParser.java @@ -1,6 +1,5 @@ package io.metersphere.api.dto.automation.parse; -import com.alibaba.fastjson.JSONArray; import io.metersphere.api.dto.automation.EsbDataStruct; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.XMLUtils; @@ -89,11 +88,11 @@ public class EsbDataParser { } else { returnData = dataStuct.copy(true); } - }else if(index == 0){ + } else if (index == 0) { //如果是第一个节点不符合,则遍历子节点是否有符合的。 int newIndex = index; EsbDataStruct itemData = selectEsbDataStructByNameStruct(dataStuct.getChildren(), paramArr, newIndex); - if(itemData != null ){ + if (itemData != null) { returnData = itemData; } } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java index da2543a827..20fd2959ff 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/HarScenarioParser.java @@ -8,7 +8,6 @@ import io.metersphere.api.dto.definition.request.MsScenario; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.parse.HarScenarioAbstractParser; -import io.metersphere.base.domain.ApiScenarioModule; import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.LogUtil; @@ -16,7 +15,6 @@ import io.metersphere.dto.RequestResult; import io.metersphere.dto.ResponseResult; import io.metersphere.plugin.core.MsTestElement; import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.lang3.StringUtils; import java.io.InputStream; import java.util.ArrayList; @@ -49,33 +47,20 @@ public class HarScenarioParser extends HarScenarioAbstractParser<ScenarioImport> MsScenario msScenario = new MsScenario(); msScenario.setName(harName); this.projectId = request.getProjectId(); - if (!ObjectUtils.isEmpty(har.log)&&!ObjectUtils.isEmpty(har.log.entries)) { + if (!ObjectUtils.isEmpty(har.log) && !ObjectUtils.isEmpty(har.log.entries)) { parseItem(har.log.entries, msScenario, apiScenarioWithBLOBs); } // 生成场景对象 List<ApiScenarioWithBLOBs> scenarioWithBLOBs = new LinkedList<>(); - parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario, request); + parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario); scenarioImport.setData(scenarioWithBLOBs); return scenarioImport; } - private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) { - ApiScenarioModule selectModule = null; - if (StringUtils.isNotBlank(request.getModuleId())) { - selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId()); - } - ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId); + private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario) { ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario); - if (module != null) { - scenarioWithBLOBs.setApiScenarioModuleId(module.getId()); - if (selectModule != null) { - String selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName()); - } else { - scenarioWithBLOBs.setModulePath("/" + module.getName()); - } - } + scenarioWithBLOBs.setModulePath("/" + msScenario.getName()); scenarioWithBLOBsList.add(scenarioWithBLOBs); } @@ -89,47 +74,47 @@ public class HarScenarioParser extends HarScenarioAbstractParser<ScenarioImport> scenario.setHashTree(results); } -private RequestResult getRequestResult(MsHTTPSamplerProxy samplerProxy, HarEntry harEntry) { - HarRequest request = harEntry.request; - HarResponse response = harEntry.response; + private RequestResult getRequestResult(MsHTTPSamplerProxy samplerProxy, HarEntry harEntry) { + HarRequest request = harEntry.request; + HarResponse response = harEntry.response; - RequestResult requestResult = new RequestResult(); - requestResult.setName("Response"); - requestResult.setUrl(request.url); - requestResult.setMethod(request.method); - if(samplerProxy.getBody()!= null){ - List<KeyValue> keyValueList = new ArrayList<>(); - if(!ObjectUtils.isEmpty(request.queryString)){ - for (HarQueryParm model : request.queryString) { - KeyValue keyValue = new KeyValue(model.name,model.value); - keyValueList.add(keyValue); + RequestResult requestResult = new RequestResult(); + requestResult.setName("Response"); + requestResult.setUrl(request.url); + requestResult.setMethod(request.method); + if (samplerProxy.getBody() != null) { + List<KeyValue> keyValueList = new ArrayList<>(); + if (!ObjectUtils.isEmpty(request.queryString)) { + for (HarQueryParm model : request.queryString) { + KeyValue keyValue = new KeyValue(model.name, model.value); + keyValueList.add(keyValue); + } } - } - if(!ObjectUtils.isEmpty(request.postData)&&!ObjectUtils.isEmpty(request.postData.params)){ - for (HarPostParam model : request.postData.params) { - KeyValue keyValue = new KeyValue(model.name,model.value); - keyValueList.add(keyValue); + if (!ObjectUtils.isEmpty(request.postData) && !ObjectUtils.isEmpty(request.postData.params)) { + for (HarPostParam model : request.postData.params) { + KeyValue keyValue = new KeyValue(model.name, model.value); + keyValueList.add(keyValue); + } } + + requestResult.setBody(JSONArray.toJSONString(keyValueList)); } - requestResult.setBody(JSONArray.toJSONString(keyValueList)); - } + requestResult.setHeaders(JSONArray.toJSONString(request.headers)); + requestResult.setRequestSize(request.bodySize); + if (!ObjectUtils.isEmpty(request.cookies)) { + requestResult.setCookies(JSONArray.toJSONString(request.cookies)); + } - requestResult.setHeaders(JSONArray.toJSONString(request.headers)); - requestResult.setRequestSize(request.bodySize); - if(!ObjectUtils.isEmpty(request.cookies)){ - requestResult.setCookies(JSONArray.toJSONString(request.cookies)); - } + ResponseResult responseResult = requestResult.getResponseResult(); + responseResult.setHeaders(JSONArray.toJSONString(response.headers)); + responseResult.setResponseCode(String.valueOf(response.status)); + responseResult.setResponseSize(response.bodySize); + if (response.content != null && response.content.text != null) { + responseResult.setBody(response.content.text); + responseResult.setResponseMessage(response.content.text); + } - ResponseResult responseResult = requestResult.getResponseResult(); - responseResult.setHeaders(JSONArray.toJSONString(response.headers)); - responseResult.setResponseCode(String.valueOf(response.status)); - responseResult.setResponseSize(response.bodySize); - if(response.content != null && response.content.text != null){ - responseResult.setBody(response.content.text); - responseResult.setResponseMessage(response.content.text); + return requestResult; } - - return requestResult; -} } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java index c3cae551de..526a3ff12a 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/MsJmeterParser.java @@ -8,7 +8,6 @@ import io.github.ningyu.jmeter.plugin.util.Constants; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.automation.ImportPoolsDTO; import io.metersphere.api.dto.definition.request.MsScenario; -import io.metersphere.plugin.core.MsTestElement; import io.metersphere.api.dto.definition.request.assertions.*; import io.metersphere.api.dto.definition.request.controller.MsLoopController; import io.metersphere.api.dto.definition.request.controller.MsTransactionController; @@ -39,7 +38,6 @@ import io.metersphere.api.dto.scenario.request.BodyFile; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.parse.ApiImportAbstractParser; import io.metersphere.api.service.ApiTestEnvironmentService; -import io.metersphere.base.domain.ApiScenarioModule; import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.ApiTestEnvironmentExample; import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; @@ -48,6 +46,7 @@ import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.LogUtil; +import io.metersphere.plugin.core.MsTestElement; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.assertions.*; @@ -115,27 +114,11 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> { private List<ApiScenarioWithBLOBs> parseObj(MsScenario msScenario, ApiTestImportRequest request) { List<ApiScenarioWithBLOBs> scenarioWithBLOBsList = new ArrayList<>(); ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs(); - ApiScenarioModule selectModule = null; - String selectModulePath = null; - if (StringUtils.isNotBlank(request.getModuleId())) { - selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId()); - if (selectModule != null) { - selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - } - } - ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId); scenarioWithBLOBs.setName(request.getFileName()); scenarioWithBLOBs.setProjectId(request.getProjectId()); if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) { scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size()); - } - if (module != null) { - scenarioWithBLOBs.setApiScenarioModuleId(module.getId()); - if (StringUtils.isNotBlank(selectModulePath)) { - scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName()); - } else { - scenarioWithBLOBs.setModulePath("/" + module.getName()); - } + scenarioWithBLOBs.setModulePath("/" + msScenario.getName()); } scenarioWithBLOBs.setId(UUID.randomUUID().toString()); scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario)); @@ -780,11 +763,6 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> { elementNode.setType("ConstantTimer"); } // IF条件控制器,这里平台方式和jmeter 不同,暂时不处理 -// else if (key instanceof IfController) { -// elementNode = new MsIfController(); -// BeanUtils.copyBean(elementNode, key); -// elementNode.setType("IfController"); -// } // 次数循环控制器 else if (key instanceof LoopController) { elementNode = new MsLoopController(); 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 792d124af9..b836033407 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 @@ -5,37 +5,27 @@ 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.base.domain.ApiScenarioWithBLOBs; +import io.metersphere.plugin.core.MsTestElement; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import java.io.InputStream; -import java.util.*; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; public class MsScenarioParser extends MsAbstractParser<ScenarioImport> { - private ApiScenarioModule selectModule; - - private String selectModulePath; - @Override public ScenarioImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); this.projectId = request.getProjectId(); JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); - if (StringUtils.isNotBlank(request.getModuleId())) { - this.selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId()); - if (this.selectModule != null) { - this.selectModulePath = ApiScenarioImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId()); - } - } - if (testObject.get("projectName") != null || testObject.get("projectId") != null) { return parseMsFormat(testStr, request); } else { @@ -64,19 +54,7 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> { ScenarioImport scenarioImport = JSON.parseObject(testStr, ScenarioImport.class, Feature.DisableSpecialKeyDetect); List<ApiScenarioWithBLOBs> data = scenarioImport.getData(); - Set<String> moduleIdSet = scenarioImport.getData().stream() - .map(ApiScenarioWithBLOBs::getApiScenarioModuleId).collect(Collectors.toSet()); - - Map<String, NodeTree> nodeMap = null; - List<NodeTree> nodeTree = scenarioImport.getNodeTree(); - if (CollectionUtils.isNotEmpty(nodeTree)) { - cutDownTree(nodeTree, moduleIdSet); - ApiScenarioImportUtil.createNodeTree(nodeTree, projectId, importRequest.getModuleId()); - nodeMap = getNodeMap(nodeTree); - } - if (CollectionUtils.isNotEmpty(data)) { - Map<String, NodeTree> finalNodeMap = nodeMap; data.forEach(item -> { String scenarioDefinitionStr = item.getScenarioDefinition(); if (StringUtils.isNotBlank(scenarioDefinitionStr)) { @@ -94,48 +72,9 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> { } } - if (finalNodeMap != null && finalNodeMap.get(item.getApiScenarioModuleId()) != null) { - NodeTree node = finalNodeMap.get(item.getApiScenarioModuleId()); - item.setApiScenarioModuleId(node.getNewId()); - item.setModulePath(node.getPath()); - } else { - if (StringUtils.isBlank(item.getModulePath())) { - item.setApiScenarioModuleId(null); - } - // 旧版本未导出模块 - parseModule(item.getModulePath(), importRequest, item); - } item.setProjectId(this.projectId); }); } return scenarioImport; } - - protected void parseModule(String modulePath, ApiTestImportRequest importRequest, ApiScenarioWithBLOBs apiScenarioWithBLOBs) { - if (StringUtils.isEmpty(modulePath)) { - return; - } - if (modulePath.startsWith("/")) { - modulePath = modulePath.substring(1); - } - if (modulePath.endsWith("/")) { - modulePath = modulePath.substring(0, modulePath.length() - 1); - } - List<String> modules = Arrays.asList(modulePath.split("/")); - ApiScenarioModule parent = this.selectModule; - Iterator<String> iterator = modules.iterator(); - while (iterator.hasNext()) { - String item = iterator.next(); - parent = ApiScenarioImportUtil.buildModule(parent, item, this.projectId); - if (!iterator.hasNext()) { - apiScenarioWithBLOBs.setApiScenarioModuleId(parent.getId()); - String path = apiScenarioWithBLOBs.getModulePath() == null ? "" : apiScenarioWithBLOBs.getModulePath(); - if (StringUtils.isNotBlank(this.selectModulePath)) { - apiScenarioWithBLOBs.setModulePath(this.selectModulePath + path); - } else if (StringUtils.isBlank(importRequest.getModuleId())) { - apiScenarioWithBLOBs.setModulePath("/未规划场景" + path); - } - } - } - } } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/PostmanScenarioParser.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/PostmanScenarioParser.java index 2b14cb5ff6..f1e620c6c0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/PostmanScenarioParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/PostmanScenarioParser.java @@ -3,7 +3,6 @@ package io.metersphere.api.dto.automation.parse; import com.alibaba.fastjson.JSON; import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.definition.request.MsScenario; -import io.metersphere.plugin.core.MsTestElement; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; import io.metersphere.api.dto.parse.postman.PostmanCollection; @@ -11,9 +10,9 @@ import io.metersphere.api.dto.parse.postman.PostmanCollectionInfo; import io.metersphere.api.dto.parse.postman.PostmanItem; import io.metersphere.api.dto.parse.postman.PostmanKeyValue; import io.metersphere.api.parse.PostmanAbstractParserParser; -import io.metersphere.base.domain.ApiScenarioModule; import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.commons.constants.VariableTypeConstants; +import io.metersphere.plugin.core.MsTestElement; import java.io.InputStream; import java.util.ArrayList; @@ -40,25 +39,14 @@ public class PostmanScenarioParser extends PostmanAbstractParserParser<ScenarioI parseItem(postmanCollection.getItem(), variables, msScenario, apiScenarioWithBLOBs); // 生成场景对象 List<ApiScenarioWithBLOBs> scenarioWithBLOBs = new LinkedList<>(); - parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario, request); + parseScenarioWithBLOBs(scenarioWithBLOBs, msScenario); scenarioImport.setData(scenarioWithBLOBs); return scenarioImport; } - private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario, ApiTestImportRequest request) { - ApiScenarioModule selectModule = ApiScenarioImportUtil.getSelectModule(request.getModuleId()); - - ApiScenarioModule module = ApiScenarioImportUtil.buildModule(selectModule, msScenario.getName(), this.projectId); + private void parseScenarioWithBLOBs(List<ApiScenarioWithBLOBs> scenarioWithBLOBsList, MsScenario msScenario) { ApiScenarioWithBLOBs scenarioWithBLOBs = parseScenario(msScenario); - if (module != null) { - scenarioWithBLOBs.setApiScenarioModuleId(module.getId()); - if (selectModule != null) { - String selectModulePath = ApiScenarioImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - scenarioWithBLOBs.setModulePath(selectModulePath + "/" + module.getName()); - } else { - scenarioWithBLOBs.setModulePath("/" + module.getName()); - } - } + scenarioWithBLOBs.setModulePath("/" + msScenario.getName()); scenarioWithBLOBsList.add(scenarioWithBLOBs); } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/ApiModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/definition/ApiModuleDTO.java index d76ac995fc..30eb8f8f3e 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/ApiModuleDTO.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/ApiModuleDTO.java @@ -8,4 +8,6 @@ import lombok.Setter; @Setter public class ApiModuleDTO extends TreeNodeDTO<ApiModuleDTO> { private String protocol; + + private String path; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java b/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java new file mode 100644 index 0000000000..de4b644e26 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/UpdateApiModuleDTO.java @@ -0,0 +1,17 @@ +package io.metersphere.api.dto.definition; + +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class UpdateApiModuleDTO { + private List<ApiModule> moduleList; + private List<ApiDefinitionWithBLOBs> needUpdateList; + private List<ApiDefinitionWithBLOBs> definitionWithBLOBs; + +} diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java index 2df437ff73..4bc959b9b9 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ESBParser.java @@ -13,7 +13,6 @@ import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.service.EsbApiParamService; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.base.domain.EsbApiParamsWithBLOBs; import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.LogUtil; @@ -165,17 +164,6 @@ public class ESBParser extends EsbAbstractParser { setCellValue("", row1.createCell(8), font, cellStyleMap.get("default")); setCellValue("", row1.createCell(9), font, cellStyleMap.get("default")); -// } else { -// setCellValue("", row1.createCell(4), font, cellStyleMap.get("default")); -// setCellValue("", row1.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("服务名称", row1.createCell(6), font, cellStyleMap.get("default")); -// setCellValue("服务场景", row1.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row1.createCell(8), font, cellStyleMap.get("default")); -// setCellValue("", row1.createCell(9), font, cellStyleMap.get("default")); -// setCellValue("", row1.createCell(10), font, cellStyleMap.get("default")); -// } - - XSSFRow row2 = sheet.createRow(1); setCellValue("请输入交易码(必填)", row2.createCell(0), font, cellStyleMap.get("default")); setCellValue("请输入交易名称(必填)", row2.createCell(1), font, cellStyleMap.get("default")); @@ -188,15 +176,6 @@ public class ESBParser extends EsbAbstractParser { setCellValue("", row2.createCell(7), font, cellStyleMap.get("default")); setCellValue("", row2.createCell(8), font, cellStyleMap.get("default")); setCellValue("", row2.createCell(9), font, cellStyleMap.get("default")); -// } else { -// setCellValue("", row2.createCell(4), font, cellStyleMap.get("default")); -// setCellValue("", row2.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("请输入服务名称(如果不填,则以交易名称为主)", row2.createCell(6), font, null); -// setCellValue("请输入服务场景(选填)", row2.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row2.createCell(8), font, cellStyleMap.get("default")); -// setCellValue("", row2.createCell(9), font, cellStyleMap.get("default")); -// setCellValue("", row2.createCell(10), font, cellStyleMap.get("default")); -// } XSSFRow row3 = sheet.createRow(2); setCellValue("", row3.createCell(0), font, cellStyleMap.get("yellow")); @@ -214,19 +193,6 @@ public class ESBParser extends EsbAbstractParser { sheet.addMergedRegion(region1); CellRangeAddress region2 = new CellRangeAddress(2, 2, 5, 9); sheet.addMergedRegion(region2); -// } else { -// setCellValue("", row3.createCell(4), font, cellStyleMap.get("yellow")); -// setCellValue("", row3.createCell(5), font, cellStyleMap.get("yellow")); -// setCellValue("请输入系统名称", row3.createCell(6), font, cellStyleMap.get("yellow")); -// setCellValue("", row3.createCell(7), font, cellStyleMap.get("yellow")); -// setCellValue("", row3.createCell(8), font, cellStyleMap.get("yellow")); -// setCellValue("", row3.createCell(9), font, cellStyleMap.get("yellow")); -// setCellValue("", row3.createCell(10), font, cellStyleMap.get("yellow")); -// CellRangeAddress region1 = new CellRangeAddress(2, 2, 0, 4); -// sheet.addMergedRegion(region1); -// CellRangeAddress region2 = new CellRangeAddress(2, 2, 6, 10); -// sheet.addMergedRegion(region2); -// } XSSFRow row4 = sheet.createRow(3); setCellValue("英文名称", row4.createCell(0), font, cellStyleMap.get("yellow")); @@ -240,16 +206,6 @@ public class ESBParser extends EsbAbstractParser { setCellValue("中文名称", row4.createCell(7), font, cellStyleMap.get("yellow")); setCellValue("备注", row4.createCell(8), font, cellStyleMap.get("yellow")); setCellValue("所在报文位置", row4.createCell(9), font, cellStyleMap.get("yellow")); -// } else { -// setCellValue("是否必输", row4.createCell(3), font, cellStyleMap.get("yellow")); -// setCellValue("备注", row4.createCell(4), font, cellStyleMap.get("yellow")); -// setCellValue("", row4.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("英文名称", row4.createCell(6), font, cellStyleMap.get("yellow")); -// setCellValue("数据类型/长度", row4.createCell(7), font, cellStyleMap.get("yellow")); -// setCellValue("中文名称", row4.createCell(8), font, cellStyleMap.get("yellow")); -// setCellValue("备注", row4.createCell(9), font, cellStyleMap.get("yellow")); -// setCellValue("所在报文位置", row4.createCell(10), font, cellStyleMap.get("yellow")); -// } XSSFRow row5 = sheet.createRow(4); setCellValue("输入", row5.createCell(0), font, cellStyleMap.get("green")); @@ -262,54 +218,31 @@ public class ESBParser extends EsbAbstractParser { setCellValue("", row5.createCell(7), font, cellStyleMap.get("green")); setCellValue("", row5.createCell(8), font, cellStyleMap.get("green")); setCellValue("", row5.createCell(9), font, cellStyleMap.get("green")); -// if (!isHead) { -// setCellValue("", row5.createCell(10), font, cellStyleMap.get("green")); -// } XSSFRow row6 = sheet.createRow(5); setCellValue("", row6.createCell(0), font, cellStyleMap.get("default")); setCellValue("", row6.createCell(1), font, cellStyleMap.get("default")); setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(2), font, cellStyleMap.get("default")); setCellValue("", row6.createCell(3), font, cellStyleMap.get("default")); -// if (isHead) { + setCellValue("", row6.createCell(4), font, cellStyleMap.get("pop")); setCellValue("", row6.createCell(5), font, cellStyleMap.get("default")); setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(6), font, cellStyleMap.get("default")); setCellValue("", row6.createCell(7), font, cellStyleMap.get("default")); setCellValue("", row6.createCell(8), font, cellStyleMap.get("default")); setCellValue("", row6.createCell(9), font, cellStyleMap.get("default")); -// } else { -// setCellValue("", row6.createCell(4), font, cellStyleMap.get("default")); -// setCellValue("", row6.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("", row6.createCell(6), font, cellStyleMap.get("default")); -// setCellValue("请输入STRING(具体长度) 或 ARRAY", row6.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row6.createCell(8), font, cellStyleMap.get("default")); -// setCellValue("", row6.createCell(9), font, cellStyleMap.get("default")); -// setCellValue("", row6.createCell(10), font, cellStyleMap.get("default")); -// } - XSSFRow row7 = sheet.createRow(6); setCellValue("", row7.createCell(1), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(2), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(3), font, cellStyleMap.get("default")); -// if (isHead) { + setCellValue("", row7.createCell(4), font, cellStyleMap.get("pop")); setCellValue("", row7.createCell(5), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(6), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(7), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(8), font, cellStyleMap.get("default")); setCellValue("", row7.createCell(9), font, cellStyleMap.get("default")); -// } else { -// setCellValue("", row7.createCell(4), font, cellStyleMap.get("default")); -// setCellValue("", row7.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("", row7.createCell(6), font, cellStyleMap.get("default")); -// setCellValue("", row7.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row7.createCell(8), font, cellStyleMap.get("default")); -// setCellValue("", row7.createCell(9), font, cellStyleMap.get("default")); -// setCellValue("", row7.createCell(10), font, cellStyleMap.get("default")); -// } - XSSFRow row8 = sheet.createRow(7); setCellValue("输出", row8.createCell(0), font, cellStyleMap.get("green")); @@ -322,33 +255,19 @@ public class ESBParser extends EsbAbstractParser { setCellValue("", row8.createCell(7), font, cellStyleMap.get("green")); setCellValue("", row8.createCell(8), font, cellStyleMap.get("green")); setCellValue("", row8.createCell(9), font, cellStyleMap.get("green")); -// if (!isHead) { -// setCellValue("", row8.createCell(10), font, cellStyleMap.get("green")); -// } - XSSFRow row9 = sheet.createRow(8); setCellValue("", row9.createCell(0), font, cellStyleMap.get("default")); setCellValue("", row9.createCell(1), font, cellStyleMap.get("default")); setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(2), font, cellStyleMap.get("default")); setCellValue("", row9.createCell(3), font, cellStyleMap.get("default")); -// if (isHead) { + setCellValue("", row9.createCell(4), font, cellStyleMap.get("pop")); setCellValue("", row9.createCell(5), font, cellStyleMap.get("default")); setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(6), font, cellStyleMap.get("default")); setCellValue("", row9.createCell(7), font, cellStyleMap.get("default")); setCellValue("", row9.createCell(8), font, cellStyleMap.get("default")); setCellValue("", row9.createCell(9), font, cellStyleMap.get("default")); -// } else { -// setCellValue("", row9.createCell(4), font, cellStyleMap.get("default")); -// setCellValue("", row9.createCell(5), font, cellStyleMap.get("pop")); -// setCellValue("", row9.createCell(6), font, cellStyleMap.get("default")); -// setCellValue("请输入STRING(具体长度) 或 ARRAY", row9.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row9.createCell(7), font, cellStyleMap.get("default")); -// setCellValue("", row9.createCell(8), font, cellStyleMap.get("default")); -// setCellValue("", row9.createCell(9), font, cellStyleMap.get("default")); -// setCellValue("", row9.createCell(10), font, cellStyleMap.get("default")); -// } } @@ -580,7 +499,9 @@ public class ESBParser extends EsbAbstractParser { ApiDefinitionImport resultModel = new ApiDefinitionImport(); List<ApiDefinitionWithBLOBs> apiDataList = new ArrayList<>(); +/* ApiModule parentNode = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); +*/ EsbSheetDataStruct headSheetData = esbExcelDataStruct.getHeadData(); List<EsbSheetDataStruct> interfaceDataList = esbExcelDataStruct.getInterfaceList(); List<String> savedNames = new ArrayList<>(); @@ -603,8 +524,8 @@ public class ESBParser extends EsbAbstractParser { apiDefinition.setMethod("ESB"); apiDefinition.setId(apiId); apiDefinition.setProjectId(this.projectId); - apiDefinition.setModuleId(importRequest.getModuleId()); - apiDefinition.setModulePath(importRequest.getModulePath()); + /* apiDefinition.setModuleId(importRequest.getModuleId()); + apiDefinition.setModulePath(importRequest.getModulePath());*/ apiDefinition.setRequest(genTCPSampler(esbSendRequest, reqDataStructStr)); if (StringUtils.equalsIgnoreCase("schedule", importRequest.getType())) { apiDefinition.setUserId(importRequest.getUserId()); @@ -612,7 +533,7 @@ public class ESBParser extends EsbAbstractParser { apiDefinition.setUserId(SessionUtils.getUserId()); } apiDefinition.setProtocol(RequestType.TCP); - buildModule(parentNode, apiDefinition, null); + /* buildModule(parentNode, apiDefinition, null);*/ apiDataList.add(apiDefinition); EsbApiParamsWithBLOBs apiParams = new EsbApiParamsWithBLOBs(); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java index 74893208bd..d91768c26e 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/HarParser.java @@ -11,7 +11,6 @@ import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.XMLUtils; @@ -60,16 +59,6 @@ public class HarParser extends HarAbstractParser { private List<ApiDefinitionWithBLOBs> parseRequests(Har har, ApiTestImportRequest importRequest) { List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); - ApiModule selectModule = null; - String selectModulePath = null; - if (StringUtils.isNotBlank(importRequest.getModuleId())) { - selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); - if (selectModule != null) { - selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - } - } - - List<HarEntry> harEntryList = new ArrayList<>(); if (har.log != null && har.log.entries != null) { harEntryList = har.log.entries; @@ -113,17 +102,6 @@ public class HarParser extends HarAbstractParser { addBodyHeader(request); apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setResponse(JSON.toJSONString(parseResponse(entry.response))); - if (selectModule == null) { - apiDefinition.setModuleId("default-module"); - - } else { - apiDefinition.setModuleId(selectModule.getId()); - } - if (StringUtils.isNotBlank(selectModulePath)) { - apiDefinition.setModulePath(selectModulePath); - } else { - apiDefinition.setModulePath("/未规划接口"); - } results.add(apiDefinition); } } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/JmeterDefinitionParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/JmeterDefinitionParser.java index 0e95b07fd0..e3c9eba31a 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/JmeterDefinitionParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/JmeterDefinitionParser.java @@ -16,8 +16,6 @@ import io.metersphere.api.dto.definition.request.extract.MsExtractRegex; import io.metersphere.api.dto.definition.request.extract.MsExtractXPath; import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor; import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor; -import io.metersphere.commons.utils.LogUtil; -import io.metersphere.plugin.core.MsTestElement; import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler; @@ -35,11 +33,16 @@ import io.metersphere.api.dto.scenario.request.BodyFile; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.parse.ApiImportAbstractParser; import io.metersphere.api.service.ApiTestEnvironmentService; -import io.metersphere.base.domain.*; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiTestCaseWithBLOBs; +import io.metersphere.base.domain.ApiTestEnvironmentExample; +import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.SessionUtils; +import io.metersphere.plugin.core.MsTestElement; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.assertions.*; @@ -72,9 +75,7 @@ public class JmeterDefinitionParser extends ApiImportAbstractParser<ApiDefinitio private ImportPoolsDTO dataPools; private final String ENV_NAME = "导入数据环境"; - private ApiModule selectModule; - private ApiModule apiModule; - private String selectModulePath; + private String planName = "default"; private static final Integer GROUP_GLOBAL = 1; @@ -93,12 +94,6 @@ public class JmeterDefinitionParser extends ApiImportAbstractParser<ApiDefinitio jmeterHashTree(testPlan, scenario); - this.selectModule = ApiDefinitionImportUtil.getSelectModule(request.getModuleId()); - if (this.selectModule != null) { - this.selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId()); - } - this.apiModule = ApiDefinitionImportUtil.buildModule(this.selectModule, this.planName, this.projectId); - LinkedList<MsTestElement> elements = scenario.getHashTree(); LinkedList<MsTestElement> results = new LinkedList<>(); getAllApiCase(elements, results); @@ -279,14 +274,8 @@ public class JmeterDefinitionParser extends ApiImportAbstractParser<ApiDefinitio apiDefinition.setName(element.getName()); apiDefinition.setProjectId(this.projectId); apiDefinition.setRequest(JSON.toJSONString(element)); - if (this.apiModule != null) { - apiDefinition.setModuleId(this.apiModule.getId()); - if (StringUtils.isNotBlank(this.selectModulePath)) { - apiDefinition.setModulePath(this.selectModulePath + "/" + this.apiModule.getName()); - } else { - apiDefinition.setModulePath("/" + this.apiModule.getName()); - } - } + + apiDefinition.setModulePath("/" + this.planName); // todo 除HTTP协议外,其它协议设置默认模块 apiDefinition.setStatus("Prepare"); apiDefinition.setProtocol(protocol); @@ -638,7 +627,7 @@ public class JmeterDefinitionParser extends ApiImportAbstractParser<ApiDefinitio }); } elementNode.setAttachmentArgs(attachmentArgs); - if(StringUtils.isEmpty(elementNode.getMethod())){ + if (StringUtils.isEmpty(elementNode.getMethod())) { elementNode.setMethod(elementNode.getProtocol()); } } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/MsDefinitionParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/MsDefinitionParser.java index a7130c4a15..3896f9bb35 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/MsDefinitionParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/MsDefinitionParser.java @@ -4,13 +4,11 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; import io.metersphere.api.dto.ApiTestImportRequest; -import io.metersphere.api.dto.definition.parse.ms.NodeTree; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.parse.ApiImportAbstractParser; import io.metersphere.api.parse.MsAbstractParser; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.commons.constants.ApiImportPlatform; import io.metersphere.commons.utils.CommonBeanFactory; @@ -21,26 +19,19 @@ import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> { - private ApiModule selectModule; - - private String selectModulePath; - @Override public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); JSONObject testObject = JSONObject.parseObject(testStr, Feature.DisableSpecialKeyDetect); this.projectId = request.getProjectId(); - if (StringUtils.isNotBlank(request.getModuleId())) { - this.selectModule = ApiDefinitionImportUtil.getSelectModule(request.getModuleId()); - if (this.selectModule != null) { - this.selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId()); - } - } if (testObject.get("projectName") != null || testObject.get("projectId") != null) {// metersphere 格式导入 return parseMsFormat(testStr, request); @@ -56,14 +47,10 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> { protected List<ApiDefinitionWithBLOBs> parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest, Boolean isCreateModule) { List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); testObject.keySet().forEach(tag -> { - String moduleId = null; - if (isCreateModule) { - moduleId = ApiDefinitionImportUtil.buildModule(this.selectModule, tag, this.projectId).getId(); - } + List<MsHTTPSamplerProxy> msHTTPSamplerProxies = parseMsHTTPSamplerProxy(testObject, tag, false); for (MsHTTPSamplerProxy msHTTPSamplerProxy : msHTTPSamplerProxies) { ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(msHTTPSamplerProxy.getId(), msHTTPSamplerProxy.getName(), msHTTPSamplerProxy.getPath(), msHTTPSamplerProxy.getMethod(), importRequest); - apiDefinition.setModuleId(moduleId); apiDefinition.setProjectId(this.projectId); apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy)); apiDefinition.setName(apiDefinition.getPath() + " [" + apiDefinition.getMethod() + "]"); @@ -90,20 +77,8 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> { }); } - Set<String> moduleIdSet = apiDefinitionImport.getData().stream() - .map(ApiDefinitionWithBLOBs::getModuleId).collect(Collectors.toSet()); - - Map<String, NodeTree> nodeMap = null; - List<NodeTree> nodeTree = apiDefinitionImport.getNodeTree(); - if (CollectionUtils.isNotEmpty(nodeTree)) { - cutDownTree(nodeTree, moduleIdSet); - ApiDefinitionImportUtil.createNodeTree(nodeTree, projectId, importRequest.getModuleId()); - nodeMap = getNodeMap(nodeTree); - } - - Map<String, NodeTree> finalNodeMap = nodeMap; apiDefinitionImport.getData().forEach(apiDefinition -> { - parseApiDefinition(apiDefinition, importRequest, caseMap, finalNodeMap); + parseApiDefinition(apiDefinition, importRequest, caseMap); }); if (MapUtils.isNotEmpty(caseMap)) { List<ApiTestCaseWithBLOBs> list = new ArrayList<>(); @@ -116,19 +91,8 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> { } private void parseApiDefinition(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest, - Map<String, List<ApiTestCaseWithBLOBs>> caseMap, Map<String, NodeTree> nodeMap) { + Map<String, List<ApiTestCaseWithBLOBs>> caseMap) { String originId = apiDefinition.getId(); - if (nodeMap != null && nodeMap.get(apiDefinition.getModuleId()) != null) { - NodeTree nodeTree = nodeMap.get(apiDefinition.getModuleId()); - apiDefinition.setModuleId(nodeTree.getNewId()); - apiDefinition.setModulePath(nodeTree.getPath()); - } else { - if (StringUtils.isBlank(apiDefinition.getModulePath())) { - apiDefinition.setModuleId(null); - } - // 旧版本未导出模块 - parseModule(apiDefinition.getModulePath(), importRequest, apiDefinition); - } apiDefinition.setProjectId(this.projectId); JSONObject requestObj = this.parseObject(apiDefinition.getRequest(), apiDefinition.getProjectId()); @@ -190,32 +154,5 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> { return null; } } - - private void parseModule(String modulePath, ApiTestImportRequest importRequest, ApiDefinitionWithBLOBs apiDefinition) { - if (StringUtils.isEmpty(modulePath)) { - return; - } - if (modulePath.startsWith("/")) { - modulePath = modulePath.substring(1, modulePath.length()); - } - if (modulePath.endsWith("/")) { - modulePath = modulePath.substring(0, modulePath.length() - 1); - } - List<String> modules = Arrays.asList(modulePath.split("/")); - ApiModule parent = this.selectModule; - Iterator<String> iterator = modules.iterator(); - while (iterator.hasNext()) { - String item = iterator.next(); - parent = ApiDefinitionImportUtil.buildModule(parent, item, this.projectId, importRequest.getUserId()); - if (!iterator.hasNext()) { - apiDefinition.setModuleId(parent.getId()); - String path = apiDefinition.getModulePath() == null ? "" : apiDefinition.getModulePath(); - if (StringUtils.isNotBlank(this.selectModulePath)) { - apiDefinition.setModulePath(this.selectModulePath + path); - } else if (StringUtils.isBlank(importRequest.getModuleId())) { - apiDefinition.setModulePath("/未规划接口" + path); - } - } - } - } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/PostmanDefinitionParser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/PostmanDefinitionParser.java index 7ed3c8ec2e..e617b05360 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/PostmanDefinitionParser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/PostmanDefinitionParser.java @@ -10,7 +10,6 @@ import io.metersphere.api.dto.parse.postman.PostmanItem; import io.metersphere.api.dto.parse.postman.PostmanKeyValue; import io.metersphere.api.parse.PostmanAbstractParserParser; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.Project; import io.metersphere.base.mapper.ProjectMapper; @@ -26,10 +25,6 @@ import java.util.*; public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefinitionImport> { - private ApiModule selectModule; - - private String selectModulePath; - @Override public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { String testStr = getApiTestStr(source); @@ -38,12 +33,11 @@ public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefi List<PostmanKeyValue> variables = postmanCollection.getVariable(); ApiDefinitionImport apiImport = new ApiDefinitionImport(); List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); - this.selectModule = ApiDefinitionImportUtil.getSelectModule(request.getModuleId()); - if (this.selectModule != null) { - this.selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(this.selectModule.getName(), this.selectModule.getParentId()); - } - ApiModule apiModule = ApiDefinitionImportUtil.buildModule(this.selectModule, postmanCollection.getInfo().getName(), this.projectId); + String modulePath = null; + if (StringUtils.isNotBlank(postmanCollection.getInfo().getName())) { + modulePath = "/" + postmanCollection.getInfo().getName(); + } List<ApiTestCaseWithBLOBs> cases = new ArrayList<>(); Map<String, String> repeatMap = new HashMap(); ProjectMapper projectMapper = CommonBeanFactory.getBean(ProjectMapper.class); @@ -51,8 +45,8 @@ public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefi ProjectApplicationService projectApplicationService = CommonBeanFactory.getBean(ProjectApplicationService.class); ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.URL_REPEATABLE.name()); boolean urlRepeat = config.getUrlRepeatable(); - parseItem(postmanCollection.getItem(), variables, results, - apiModule, apiModule.getName(), cases, repeatMap, urlRepeat); + parseItem(postmanCollection.getItem(), modulePath, variables, results, + cases, repeatMap, urlRepeat); Collections.reverse(results); // 调整顺序 Collections.reverse(cases); apiImport.setData(results); @@ -60,14 +54,16 @@ public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefi return apiImport; } - protected void parseItem(List<PostmanItem> items, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results, - ApiModule parentModule, String path, List<ApiTestCaseWithBLOBs> cases, Map<String, String> repeatMap, Boolean repeatable) { + protected void parseItem(List<PostmanItem> items, String modulePath, List<PostmanKeyValue> variables, List<ApiDefinitionWithBLOBs> results, + List<ApiTestCaseWithBLOBs> cases, Map<String, String> repeatMap, Boolean repeatable) { for (PostmanItem item : items) { List<PostmanItem> childItems = item.getItem(); if (childItems != null) { - ApiModule module = null; - module = ApiDefinitionImportUtil.buildModule(parentModule, item.getName(), this.projectId); - parseItem(childItems, variables, results, module, path + "/" + module.getName(), cases, repeatMap, repeatable); + + if (StringUtils.isNotBlank(modulePath) && StringUtils.isNotBlank(item.getName())) { + modulePath = modulePath + "/" + item.getName(); + } + parseItem(childItems, modulePath, variables, results, cases, repeatMap, repeatable); } else { MsHTTPSamplerProxy msHTTPSamplerProxy = parsePostman(item); HttpResponse response = parsePostmanResponse(item); @@ -76,13 +72,9 @@ public class PostmanDefinitionParser extends PostmanAbstractParserParser<ApiDefi request.setPath(msHTTPSamplerProxy.getPath()); request.setRequest(JSON.toJSONString(msHTTPSamplerProxy)); request.setResponse(JSON.toJSONString(response)); - if (parentModule != null) { - request.setModuleId(parentModule.getId()); - if (StringUtils.isNotBlank(this.selectModulePath)) { - request.setModulePath(this.selectModulePath + "/" + path); - } else { - request.setModulePath("/" + path); - } + + if (StringUtils.isNotBlank(modulePath)) { + request.setModulePath(modulePath); } if (request != null) { if (repeatMap.keySet().contains(request.getMethod() + request.getPath()) diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger2Parser.java index 442ebd97be..af08d272f0 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger2Parser.java @@ -11,7 +11,6 @@ import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.constants.SwaggerParameterType; import io.metersphere.commons.exception.MSException; import io.metersphere.utils.LoggerUtil; @@ -115,15 +114,6 @@ public class Swagger2Parser extends SwaggerAbstractParser { List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); - ApiModule selectModule = null; - String selectModulePath = null; - if (StringUtils.isNotBlank(importRequest.getModuleId())) { - selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); - if (selectModule != null) { - selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - } - } - String basePath = swagger.getBasePath(); for (String pathName : pathNames) { Path path = paths.get(pathName); @@ -142,7 +132,8 @@ public class Swagger2Parser extends SwaggerAbstractParser { } apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses()))); - buildModule(selectModule, apiDefinition, operation.getTags(), selectModulePath); + + buildModulePath(apiDefinition, operation.getTags()); if (operation.isDeprecated() != null && operation.isDeprecated()) { apiDefinition.setTags("[\"Deleted\"]"); } @@ -154,6 +145,28 @@ public class Swagger2Parser extends SwaggerAbstractParser { return results; } + private void buildModulePath(ApiDefinitionWithBLOBs apiDefinition, List<String> tags) { + StringBuilder modulePathBuilder = new StringBuilder(); + String modulePath = getModulePath(tags, modulePathBuilder); + apiDefinition.setModulePath(modulePath); + } + + private String getModulePath(List<String> tagTree, StringBuilder modulePath) { + for (String s : tagTree) { + if (s.contains("/")) { + String[] split = s.split("/"); + if (split.length > 0) { + getModulePath(List.of(split), modulePath); + } + } else { + if (StringUtils.isNotBlank(s)) { + modulePath.append("/").append(s); + } + } + } + return modulePath.toString(); + } + private ApiDefinitionWithBLOBs buildApiDefinition(String id, Operation operation, String path, String method, ApiTestImportRequest importRequest) { String name = ""; if (StringUtils.isNotBlank(operation.getSummary())) { diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger3Parser.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger3Parser.java index f015ad47e8..3fb887a057 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger3Parser.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/Swagger3Parser.java @@ -5,7 +5,6 @@ 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.definition.ApiModuleDTO; import io.metersphere.api.dto.definition.SwaggerApiExportResult; import io.metersphere.api.dto.definition.parse.swagger.SwaggerApiInfo; import io.metersphere.api.dto.definition.parse.swagger.SwaggerInfo; @@ -16,11 +15,8 @@ import io.metersphere.api.dto.definition.response.HttpResponse; import io.metersphere.api.dto.scenario.Body; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.request.RequestType; -import io.metersphere.api.service.ApiModuleService; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; -import io.metersphere.base.domain.ApiModule; import io.metersphere.commons.exception.MSException; -import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.XMLUtils; import io.swagger.parser.OpenAPIParser; @@ -131,15 +127,6 @@ public class Swagger3Parser extends SwaggerAbstractParser { List<ApiDefinitionWithBLOBs> results = new ArrayList<>(); - ApiModule selectModule = null; - String selectModulePath = null; - if (StringUtils.isNotBlank(importRequest.getModuleId())) { - selectModule = ApiDefinitionImportUtil.getSelectModule(importRequest.getModuleId()); - if (selectModule != null) { - selectModulePath = ApiDefinitionImportUtil.getSelectModulePath(selectModule.getName(), selectModule.getParentId()); - } - } - for (String pathName : pathNames) { PathItem pathItem = paths.get(pathName); @@ -167,7 +154,7 @@ public class Swagger3Parser extends SwaggerAbstractParser { } // 有数据的话,去掉 Kvs 里初始化的第一个全 null 的数据,否则有空行 apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation.getResponses()))); - buildModule(selectModule, apiDefinition, operation.getTags(), selectModulePath); + buildModulePath(apiDefinition, operation.getTags()); if (operation.getDeprecated() != null && operation.getDeprecated()) { apiDefinition.setTags("[\"Deleted\"]"); } @@ -179,6 +166,12 @@ public class Swagger3Parser extends SwaggerAbstractParser { return results; } + private void buildModulePath(ApiDefinitionWithBLOBs apiDefinition, List<String> tags) { + StringBuilder modulePathBuilder = new StringBuilder(); + String modulePath = getModulePath(tags, modulePathBuilder); + apiDefinition.setModulePath(modulePath); + } + private ApiDefinitionWithBLOBs buildApiDefinition(String id, Operation operation, String path, String method, ApiTestImportRequest importRequest) { String name; if (StringUtils.isNotBlank(operation.getSummary())) { @@ -588,15 +581,20 @@ public class Swagger3Parser extends SwaggerAbstractParser { SwaggerApiInfo swaggerApiInfo = new SwaggerApiInfo(); // {tags:, summary:, description:, parameters:} swaggerApiInfo.setSummary(apiDefinition.getName()); // 设置导入后的模块名 (根据 api 的 moduleID 查库获得所属模块,作为导出的模块名) - ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); - String moduleName = ""; - if (apiDefinition.getModuleId() != null) { // module_id 可能为空 - ApiModuleDTO node = apiModuleService.getNode(apiDefinition.getModuleId()); - if (node != null) { - moduleName = node.getName(); + //直接导出完整路径 + if (apiDefinition.getModulePath() != null) { + String[] split = new String[0]; + String modulePath = apiDefinition.getModulePath(); + String substring = modulePath.substring(0, 1); + if (substring.equals("/")) { + modulePath = modulePath.substring(1); } + if (modulePath.contains("/")) { + split = modulePath.split("/"); + } + swaggerApiInfo.setTags(Arrays.asList(split)); } - swaggerApiInfo.setTags(Arrays.asList(moduleName)); + // 设置请求体 JSONObject requestObject = JSON.parseObject(apiDefinition.getRequest(), Feature.DisableSpecialKeyDetect); // 将api的request属性转换成JSON对象以便获得参数 JSONObject requestBody = buildRequestBody(requestObject); @@ -990,4 +988,21 @@ public class Swagger3Parser extends SwaggerAbstractParser { } return content; } + + private String getModulePath(List<String> tagTree, StringBuilder modulePath) { + for (String s : tagTree) { + if (s.contains("/")) { + String[] split = s.split("/"); + if (split.length > 0) { + getModulePath(List.of(split), modulePath); + } + } else { + if (StringUtils.isNotBlank(s)) { + modulePath.append("/").append(s); + } + } + } + return modulePath.toString(); + } + } diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java index 3ac7f6cf4f..957303a401 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java @@ -161,6 +161,7 @@ public abstract class ApiImportAbstractParser<T> implements ApiImportParser<T> { request.setHeaders(new ArrayList<>()); request.setArguments(new ArrayList<>()); request.setRest(new ArrayList<>()); + request.setFollowRedirects(true); Body body = new Body(); body.initKvs(); body.initBinary(); 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 c6e33cb2e1..7557e01167 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import io.metersphere.api.dto.*; import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.automation.parse.ApiScenarioImportUtil; @@ -75,6 +77,8 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; + @Service @Transactional(rollbackFor = Exception.class) public class ApiAutomationService { @@ -1216,7 +1220,7 @@ public class ApiAutomationService { } private ApiScenarioWithBLOBs importCreate(ApiScenarioWithBLOBs request, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, - ApiTestImportRequest apiTestImportRequest, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) { + ApiTestImportRequest apiTestImportRequest, List<ApiScenarioWithBLOBs> sameList, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) { final ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs(); BeanUtils.copyBean(scenarioWithBLOBs, request); scenarioWithBLOBs.setCreateTime(System.currentTimeMillis()); @@ -1235,14 +1239,12 @@ public class ApiAutomationService { } scenarioWithBLOBs.setDescription(request.getDescription()); - List<ApiScenarioWithBLOBs> sameRequest = getSameScenario(scenarioWithBLOBs); - Boolean openCustomNum = apiTestImportRequest.getOpenCustomNum(); List<ApiScenario> list = new ArrayList<>(); if (BooleanUtils.isTrue(openCustomNum)) { ApiScenarioExample example = new ApiScenarioExample(); ApiScenarioExample.Criteria criteria = example.createCriteria(); - if (CollectionUtils.isEmpty(sameRequest)) { + if (CollectionUtils.isEmpty(sameList)) { criteria.andCustomNumEqualTo(scenarioWithBLOBs.getCustomNum()) .andProjectIdEqualTo(scenarioWithBLOBs.getProjectId()); } else { @@ -1250,7 +1252,7 @@ public class ApiAutomationService { criteria.andNameEqualTo(scenarioWithBLOBs.getName()) .andCustomNumEqualTo(scenarioWithBLOBs.getCustomNum()) .andProjectIdEqualTo(scenarioWithBLOBs.getProjectId()) - .andIdNotEqualTo(sameRequest.get(0).getId()); + .andIdNotEqualTo(sameList.get(0).getId()); } } @@ -1265,9 +1267,9 @@ public class ApiAutomationService { } if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) { - _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper); + _importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper); } else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) { - if (CollectionUtils.isEmpty(sameRequest)) { + if (CollectionUtils.isEmpty(sameList)) { scenarioWithBLOBs.setOrder(getImportNextOrder(request.getProjectId())); scenarioWithBLOBs.setId(UUID.randomUUID().toString()); scenarioWithBLOBs.setRefId(scenarioWithBLOBs.getId()); @@ -1288,21 +1290,36 @@ public class ApiAutomationService { } } else { - _importCreate(sameRequest, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper); + _importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper); } return scenarioWithBLOBs; } private void editScenario(ApiTestImportRequest request, ScenarioImport apiImport) { + ApiScenarioModuleService apiScenarioModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class); + 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<ApiScenarioWithBLOBs> data = apiImport.getData(); + ApiScenarioModuleMapper apiScenarioModuleMapper = sqlSession.getMapper(ApiScenarioModuleMapper.class); + + List<ApiScenarioWithBLOBs> initData = apiImport.getData(); currentScenarioOrder.remove(); + + UpdateScenarioModuleDTO updateScenarioModuleDTO = apiScenarioModuleService.checkScenarioModule(request, initData, StringUtils.equals("fullCoverage", request.getModeId()), request.getCoverModule()); + List<ApiScenarioModule> moduleList = updateScenarioModuleDTO.getModuleList(); + List<ApiScenarioWithBLOBs> data = updateScenarioModuleDTO.getApiScenarioWithBLOBsList(); + List<ApiScenarioWithBLOBs> needUpdateList = updateScenarioModuleDTO.getNeedUpdateList(); + + if (moduleList != null) { + for (ApiScenarioModule apiScenarioModule : moduleList) { + apiScenarioModuleMapper.insert(apiScenarioModule); + } + } int num = 0; - Project project = new Project(); + Project project; if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) { project = projectMapper.selectByPrimaryKey(data.get(0).getProjectId()); ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.SCENARIO_CUSTOM_NUM.name()); @@ -1312,11 +1329,9 @@ public class ApiAutomationService { String defaultVersion = extProjectVersionMapper.getDefaultVersion(request.getProjectId()); request.setDefaultVersion(defaultVersion); for (int i = 0; i < data.size(); i++) { - ApiScenarioWithBLOBs item = data.get(i); - if (StringUtils.isBlank(item.getApiScenarioModuleId()) || "default-module".equals(item.getApiScenarioModuleId())) { - replenishScenarioModuleIdPath(request.getProjectId(), apiScenarioModuleMapper, item); - } + ApiScenarioWithBLOBs item = data.get(i); + List<ApiScenarioWithBLOBs> sameList = needUpdateList.stream().filter(t -> t.getId().equals(item.getId())).collect(toList()); if (StringUtils.isBlank(item.getCreateUser())) { item.setCreateUser(SessionUtils.getUserId()); } @@ -1340,11 +1355,12 @@ public class ApiAutomationService { item.setUserId(SessionUtils.getUserId()); item.setPrincipal(SessionUtils.getUserId()); // 导入之后刷新latest - importCreate(item, batchMapper, extApiScenarioMapper, request, apiTestCaseMapper, apiDefinitionMapper); + importCreate(item, batchMapper, extApiScenarioMapper, request, sameList, apiTestCaseMapper, apiDefinitionMapper); if (i % 300 == 0) { sqlSession.flushStatements(); } } + sqlSession.flushStatements(); if (sqlSession != null && sqlSessionFactory != null) { SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); @@ -2111,4 +2127,39 @@ public class ApiAutomationService { } return returnMap; } + + public Boolean checkIsSynchronize(ApiScenarioWithBLOBs existApiScenario, ApiScenarioWithBLOBs apiScenario) { + + ApiScenario exScenario; + ApiScenario scenario; + exScenario = existApiScenario; + scenario = apiScenario; + ObjectMapper objectMapper = new ObjectMapper(); + String exScenarioString = null; + String scenarioString = null; + try { + exScenarioString = objectMapper.writeValueAsString(exScenario); + scenarioString = objectMapper.writeValueAsString(scenario); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + //Compare the basic information of the APIScenario. + + if (!StringUtils.equals(exScenario.getName(), scenario.getName())) { + return true; + } + if (!StringUtils.equals(exScenarioString, scenarioString)) { + return true; + } + if (!StringUtils.equals(existApiScenario.getEnvironmentJson(), apiScenario.getEnvironmentJson())) { + return true; + } + + if (!StringUtils.equals(existApiScenario.getDescription(), apiScenario.getDescription())) { + return true; + } + + return !StringUtils.equals(existApiScenario.getScenarioDefinition(), apiScenario.getScenarioDefinition()); + } } 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 558f75965e..ea306a2261 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -3,6 +3,9 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.parser.Feature; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import io.metersphere.api.dto.APIReportResult; @@ -544,51 +547,6 @@ public class ApiDefinitionService { } } - private List<ApiDefinition> getSameRequest(SaveApiDefinitionRequest request) { - ApiDefinitionExample example = new ApiDefinitionExample(); - if (request.getProtocol().equals(RequestType.HTTP)) { - example.createCriteria().andMethodEqualTo(request.getMethod()).andStatusNotEqualTo("Trash") - .andPathEqualTo(request.getPath()) - .andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId()); - return apiDefinitionMapper.selectByExample(example); - } else { - example.createCriteria().andProtocolEqualTo(request.getProtocol()).andStatusNotEqualTo("Trash") - .andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()) - .andIdNotEqualTo(request.getId()); - return apiDefinitionMapper.selectByExample(example); - } - } - - private List<ApiDefinition> getSameRequestById(String id, String projectId) { - ApiDefinitionExample example = new ApiDefinitionExample(); - example.createCriteria().andStatusNotEqualTo("Trash") - .andProjectIdEqualTo(projectId) - .andIdEqualTo(id); - return apiDefinitionMapper.selectByExample(example); - } - - private List<ApiDefinition> getSameRequestWithName(SaveApiDefinitionRequest request) { - ApiDefinitionExample example = new ApiDefinitionExample(); - if (request.getProtocol().equals(RequestType.HTTP)) { - example.createCriteria() - .andMethodEqualTo(request.getMethod()) - .andStatusNotEqualTo("Trash") - .andPathEqualTo(request.getPath()) - .andNameEqualTo(request.getName()) - .andProjectIdEqualTo(request.getProjectId()) - .andIdNotEqualTo(request.getId()); - } else { - example.createCriteria() - .andStatusNotEqualTo("Trash") - .andNameEqualTo(request.getName()) - .andProjectIdEqualTo(request.getProjectId()) - .andIdNotEqualTo(request.getId()); - } - - return apiDefinitionMapper.selectByExample(example); - - } - private ApiDefinitionWithBLOBs updateTest(SaveApiDefinitionRequest request) { checkNameExist(request); if (StringUtils.equals(request.getMethod(), "ESB")) { @@ -787,10 +745,10 @@ public class ApiDefinitionService { } } - private ApiDefinition importCreate(ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionMapper batchMapper, - ApiTestCaseMapper apiTestCaseMapper, ExtApiDefinitionMapper extApiDefinitionMapper, + private ApiDefinition importCreate(ApiDefinitionWithBLOBs apiDefinition, ApiDefinitionMapper batchMapper, ApiTestCaseMapper apiTestCaseMapper, + ExtApiDefinitionMapper extApiDefinitionMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases, List<MockConfigImportDTO> mocks, - Boolean repeatable) { + List<ApiDefinitionWithBLOBs> updateList) { SaveApiDefinitionRequest saveReq = new SaveApiDefinitionRequest(); BeanUtils.copyBean(saveReq, apiDefinition); apiDefinition.setCreateTime(System.currentTimeMillis()); @@ -803,27 +761,13 @@ public class ApiDefinitionService { } else { apiDefinition.setUserId(apiDefinition.getUserId()); } - if (apiDefinition.getModuleId() == null) { - if (StringUtils.isEmpty(apiDefinition.getModuleId()) || "default-module".equals(apiDefinition.getModuleId())) { - initModulePathAndId(apiDefinition.getProjectId(), apiDefinition); - } - } apiDefinition.setDescription(apiDefinition.getDescription()); + List<ApiDefinitionWithBLOBs> collect = updateList.stream().filter(t -> t.getId().equals(apiDefinition.getId())).collect(Collectors.toList()); - List<ApiDefinition> sameRequest; - if (repeatable == null || !repeatable) { - sameRequest = getSameRequest(saveReq); - } else { - // 如果勾选了允许重复,则判断更新要加上name字段 - sameRequest = getSameRequestWithName(saveReq); - } - if (CollectionUtils.isEmpty(sameRequest)) { - sameRequest = getSameRequestById(apiDefinition.getId(), apiTestImportRequest.getProjectId()); - } if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) { - _importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, extApiDefinitionMapper, apiTestImportRequest, cases, mocks); + _importCreate(collect, batchMapper, apiTestCaseMapper, apiDefinition, extApiDefinitionMapper, apiTestImportRequest, cases, mocks); } else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) { - if (CollectionUtils.isEmpty(sameRequest)) { + if (CollectionUtils.isEmpty(collect)) { //postman 可能含有前置脚本,接口定义去掉脚本 apiDefinition.setOrder(getImportNextOrder(apiTestImportRequest.getProjectId())); String originId = apiDefinition.getId(); @@ -845,13 +789,13 @@ public class ApiDefinitionService { reSetImportCasesApiId(cases, originId, apiDefinition.getId()); reSetImportMocksApiId(mocks, originId, apiDefinition.getId(), apiDefinition.getNum()); apiDefinition.setRequest(requestStr); - importApiCase(apiDefinition, apiTestImportRequest); + importApiCase(apiDefinition, apiTestImportRequest, apiTestCaseMapper); } else { //不覆盖的接口,如果没有sameRequest则不导入。此时清空mock信息 mocks.clear(); } } else { - _importCreate(sameRequest, batchMapper, apiDefinition, apiTestCaseMapper, extApiDefinitionMapper, apiTestImportRequest, cases, mocks); + _importCreate(collect, batchMapper, apiTestCaseMapper, apiDefinition, extApiDefinitionMapper, apiTestImportRequest, cases, mocks); } return apiDefinition; @@ -877,8 +821,8 @@ public class ApiDefinitionService { return order; } - private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition, - ApiTestCaseMapper apiTestCaseMapper, ExtApiDefinitionMapper extApiDefinitionMapper, + private void _importCreate(List<ApiDefinitionWithBLOBs> sameRequest, ApiDefinitionMapper batchMapper, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionWithBLOBs apiDefinition, + ExtApiDefinitionMapper extApiDefinitionMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases, List<MockConfigImportDTO> mocks) { String originId = apiDefinition.getId(); @@ -902,7 +846,7 @@ public class ApiDefinitionService { batchMapper.insert(apiDefinition); String request = setImportHashTree(apiDefinition); apiDefinition.setRequest(request); - importApiCase(apiDefinition, apiTestImportRequest); + importApiCase(apiDefinition, apiTestImportRequest, apiTestCaseMapper); } else { if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) { setImportTCPHashTree(apiDefinition); @@ -914,13 +858,17 @@ public class ApiDefinitionService { if (StringUtils.isEmpty(apiTestImportRequest.getUpdateVersionId())) { apiTestImportRequest.setUpdateVersionId(apiTestImportRequest.getDefaultVersion()); } - Optional<ApiDefinition> apiOp = sameRequest.stream() + Optional<ApiDefinitionWithBLOBs> apiOp = sameRequest.stream() .filter(api -> StringUtils.equals(api.getVersionId(), apiTestImportRequest.getUpdateVersionId())) .findFirst(); if (!apiOp.isPresent()) { apiDefinition.setId(UUID.randomUUID().toString()); - apiDefinition.setRefId(sameRequest.get(0).getRefId()); + if (sameRequest.get(0).getRefId() != null) { + apiDefinition.setRefId(sameRequest.get(0).getRefId()); + } else { + apiDefinition.setRefId(apiDefinition.getId()); + } apiDefinition.setVersionId(apiTestImportRequest.getUpdateVersionId()); apiDefinition.setNum(sameRequest.get(0).getNum()); // 使用第一个num当作本次的num apiDefinition.setOrder(sameRequest.get(0).getOrder()); @@ -929,16 +877,26 @@ public class ApiDefinitionService { } batchMapper.insert(apiDefinition); } else { - ApiDefinition existApi = apiOp.get(); + ApiDefinitionWithBLOBs existApi = apiOp.get(); apiDefinition.setStatus(existApi.getStatus()); apiDefinition.setOriginalState(existApi.getOriginalState()); apiDefinition.setCaseStatus(existApi.getCaseStatus()); apiDefinition.setNum(existApi.getNum()); //id 不变 apiDefinition.setRefId(existApi.getRefId()); + if (existApi.getRefId() != null) { + apiDefinition.setRefId(existApi.getRefId()); + } else { + apiDefinition.setRefId(apiDefinition.getId()); + } apiDefinition.setVersionId(apiTestImportRequest.getUpdateVersionId()); if (existApi.getUserId() != null) { apiDefinition.setUserId(existApi.getUserId()); } + //Check whether the content has changed, if not, do not change the creation time + Boolean toChangeTime = checkIsSynchronize(existApi, apiDefinition); + if (!toChangeTime) { + apiDefinition.setUpdateTime(existApi.getUpdateTime()); + } // case 设置版本 cases.forEach(c -> { c.setVersionId(apiDefinition.getVersionId()); @@ -950,14 +908,12 @@ public class ApiDefinitionService { //如果存在则修改 apiDefinition.setId(existApi.getId()); String request = setImportHashTree(apiDefinition); - apiDefinition.setModuleId(existApi.getModuleId()); - apiDefinition.setModulePath(existApi.getModulePath()); apiDefinition.setOrder(existApi.getOrder()); - apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); + batchMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); apiDefinition.setRequest(request); reSetImportCasesApiId(cases, originId, apiDefinition.getId()); reSetImportMocksApiId(mocks, originId, apiDefinition.getId(), apiDefinition.getNum()); - importApiCase(apiDefinition, apiTestImportRequest); + importApiCase(apiDefinition, apiTestImportRequest, apiTestCaseMapper); } else { apiDefinition.setId(existApi.getId()); if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) { @@ -966,7 +922,7 @@ public class ApiDefinitionService { apiDefinition.setOrder(existApi.getOrder()); reSetImportCasesApiId(cases, originId, apiDefinition.getId()); reSetImportMocksApiId(mocks, originId, apiDefinition.getId(), apiDefinition.getNum()); - apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); + batchMapper.updateByPrimaryKeyWithBLOBs(apiDefinition); } } extApiDefinitionMapper.clearLatestVersion(apiDefinition.getRefId()); @@ -974,6 +930,82 @@ public class ApiDefinitionService { } } + public Boolean checkIsSynchronize(ApiDefinitionWithBLOBs existApi, ApiDefinitionWithBLOBs apiDefinition) { + + ApiDefinition exApi; + ApiDefinition api; + exApi = existApi; + api = apiDefinition; + ObjectMapper objectMapper = new ObjectMapper(); + String exApiString = null; + String apiString = null; + try { + exApiString = objectMapper.writeValueAsString(exApi); + apiString = objectMapper.writeValueAsString(api); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + //Compare the basic information of the API. If it contains the comparison that needs to be done for the synchronization information, + // put the data into the to-be-synchronized + if (!StringUtils.equals(exApiString, apiString)) { + if (!StringUtils.equals(apiDefinition.getMethod(), existApi.getMethod())) { + return true; + } + if (!StringUtils.equals(apiDefinition.getProtocol(), existApi.getProtocol())) { + return true; + } + + if (!StringUtils.equals(apiDefinition.getPath(), existApi.getPath())) { + return true; + } + + return true; + } + + if (!StringUtils.equals(existApi.getRemark(), apiDefinition.getRemark())) { + return true; + } + + if (!StringUtils.equals(existApi.getDescription(), apiDefinition.getDescription())) { + return true; + } + + if (!StringUtils.equals(existApi.getResponse(), apiDefinition.getResponse())) { + return true; + } + + JsonNode exApiRequest = null; + JsonNode apiRequest = null; + try { + exApiRequest = objectMapper.readTree(existApi.getRequest()); + apiRequest = objectMapper.readTree(apiDefinition.getRequest()); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + + if (exApiRequest == null || apiRequest == null) { + return false; + } + if (!StringUtils.equals(exApiRequest.get("headers").toString(), apiRequest.get("headers").toString())) { + return true; + } + + if (!StringUtils.equals(exApiRequest.get("arguments").toString(), apiRequest.get("arguments").toString())) { + return true; + } + + if (!StringUtils.equals(exApiRequest.get("rest").toString(), apiRequest.get("rest").toString())) { + return true; + } + + if (!StringUtils.equals(exApiRequest.get("body").toString(), apiRequest.get("body").toString())) { + return true; + } + + return false; + } + /** * 如果是MS格式,带用例导出,最后创建用例,重新设置接口id * @@ -1023,17 +1055,18 @@ public class ApiDefinitionService { } private void importMsCase(ApiDefinitionImport apiImport, SqlSession sqlSession, - ApiTestImportRequest request) { + ApiTestImportRequest request, ApiTestCaseMapper apiTestCaseMapper) { List<ApiTestCaseWithBLOBs> cases = apiImport.getCases(); if (CollectionUtils.isNotEmpty(cases)) { int batchCount = 0; for (int i = 0; i < cases.size(); i++) { ApiTestCaseWithBLOBs item = cases.get(i); - ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = apiDefinitionMapper.selectByPrimaryKey(item.getApiDefinitionId()); - if (apiDefinitionWithBLOBs == null) { + List<ApiDefinitionWithBLOBs> data = apiImport.getData(); + List<ApiDefinitionWithBLOBs> collect = data.stream().filter(t -> t.getId().equals(item.getApiDefinitionId())).collect(Collectors.toList()); + if (collect.isEmpty()) { continue; } - insertOrUpdateImportCase(item, request, apiDefinitionWithBLOBs); + insertOrUpdateImportCase(item, request, collect.get(0), apiTestCaseMapper); } if (batchCount % 300 == 0) { sqlSession.flushStatements(); @@ -1045,7 +1078,7 @@ public class ApiDefinitionService { * 导入是插件或者postman时创建用例 * postman考虑是否有前置脚本 */ - private void importApiCase(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest apiTestImportRequest) { + private void importApiCase(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest apiTestImportRequest, ApiTestCaseMapper apiTestCaseMapper) { try { if (StringUtils.equalsAnyIgnoreCase(apiTestImportRequest.getPlatform(), ApiImportPlatform.Plugin.name(), ApiImportPlatform.Postman.name())) { ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs(); @@ -1055,16 +1088,21 @@ public class ApiDefinitionService { if (apiTestCase.getName().length() > 255) { apiTestCase.setName(apiTestCase.getName().substring(0, 255)); } - insertOrUpdateImportCase(apiTestCase, apiTestImportRequest, apiDefinition); + insertOrUpdateImportCase(apiTestCase, apiTestImportRequest, apiDefinition, apiTestCaseMapper); } } catch (Exception e) { LogUtil.error("导入创建用例异常", e); } } - private void insertOrUpdateImportCase(ApiTestCaseWithBLOBs apiTestCase, ApiTestImportRequest apiTestImportRequest, ApiDefinitionWithBLOBs apiDefinition) { + private void insertOrUpdateImportCase(ApiTestCaseWithBLOBs apiTestCase, ApiTestImportRequest apiTestImportRequest, ApiDefinitionWithBLOBs apiDefinition, ApiTestCaseMapper apiTestCaseMapper) { SaveApiTestCaseRequest checkRequest = new SaveApiTestCaseRequest(); - checkRequest.setName(apiTestCase.getName()); + if (apiTestCase.getName().length() > 255) { + apiTestCase.setName(apiTestCase.getName().substring(0, 255)); + checkRequest.setName(apiTestCase.getName().substring(0, 255)); + } else { + checkRequest.setName(apiTestCase.getName()); + } checkRequest.setApiDefinitionId(apiTestCase.getApiDefinitionId()); checkRequest.setId(apiTestCase.getId()); ApiTestCase sameCase = apiTestCaseService.getSameCase(checkRequest); @@ -1221,6 +1259,10 @@ public class ApiDefinitionService { MSException.throwException(Translator.get("connection_timeout")); } } + Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); + if (StringUtils.equals(request.getType(), "schedule")) { + request.setProtocol("HTTP"); + } try { apiImport = (ApiDefinitionImport) Objects.requireNonNull(runService).parse(file == null ? null : file.getInputStream(), request); if (apiImport.getMocks() == null) { @@ -1242,7 +1284,7 @@ public class ApiDefinitionService { paramMap.put("url", request.getSwaggerUrl()); paramMap.put("projectId", request.getProjectId()); NoticeModel noticeModel = NoticeModel.builder() - .operator(SessionUtils.getUserId()) + .operator(project.getCreateUser()) .context(context) .testId(scheduleId) .subject(Translator.get("swagger_url_scheduled_import_notification")) @@ -1267,7 +1309,7 @@ public class ApiDefinitionService { Map<String, Object> paramMap = new HashMap<>(); paramMap.put("url", request.getSwaggerUrl()); NoticeModel noticeModel = NoticeModel.builder() - .operator(SessionUtils.getUserId()) + .operator(project.getCreateUser()) .context(context) .testId(scheduleId) .subject(Translator.get("swagger_url_scheduled_import_notification")) @@ -1287,21 +1329,39 @@ public class ApiDefinitionService { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); currentApiCaseOrder.remove(); currentApiOrder.remove(); - List<ApiDefinitionWithBLOBs> data = apiImport.getData(); - data = this.initApiModuleId(data); - ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); - ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); - ExtApiDefinitionMapper extApiDefinitionMapper = sqlSession.getMapper(ExtApiDefinitionMapper.class); + String defaultVersion = extProjectVersionMapper.getDefaultVersion(request.getProjectId()); + request.setDefaultVersion(defaultVersion); + List<ApiDefinitionWithBLOBs> initData = apiImport.getData(); Project project = projectMapper.selectByPrimaryKey(request.getProjectId()); ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.URL_REPEATABLE.name()); boolean urlRepeat = config.getUrlRepeatable(); + //过滤(一次只导入一个协议) + List<ApiDefinitionWithBLOBs> filterData = initData.stream().filter(t -> t.getProtocol().equals(request.getProtocol())).collect(Collectors.toList()); + if (filterData.isEmpty()) { + return; + } + UpdateApiModuleDTO updateApiModuleDTO = apiModuleService.checkApiModule(request, apiImport, filterData, StringUtils.equals("fullCoverage", request.getModeId()), urlRepeat); + List<ApiDefinitionWithBLOBs> updateList = updateApiModuleDTO.getNeedUpdateList(); + List<ApiDefinitionWithBLOBs> data = updateApiModuleDTO.getDefinitionWithBLOBs(); + List<ApiModule> moduleList = updateApiModuleDTO.getModuleList(); + + ApiDefinitionMapper batchMapper = sqlSession.getMapper(ApiDefinitionMapper.class); + ApiTestCaseMapper apiTestCaseMapper = sqlSession.getMapper(ApiTestCaseMapper.class); + ExtApiDefinitionMapper extApiDefinitionMapper = sqlSession.getMapper(ExtApiDefinitionMapper.class); + ApiModuleMapper apiModuleMapper = sqlSession.getMapper(ApiModuleMapper.class); + int num = 0; if (!CollectionUtils.isEmpty(data) && data.get(0) != null && data.get(0).getProjectId() != null) { num = getNextNum(data.get(0).getProjectId()); } - String defaultVersion = extProjectVersionMapper.getDefaultVersion(request.getProjectId()); - request.setDefaultVersion(defaultVersion); + + if (moduleList != null) { + for (ApiModule apiModule : moduleList) { + apiModuleMapper.insert(apiModule); + } + } + for (int i = 0; i < data.size(); i++) { ApiDefinitionWithBLOBs item = data.get(i); this.setModule(item); @@ -1314,14 +1374,14 @@ public class ApiDefinitionService { String apiId = item.getId(); EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId); request.setModeId("fullCoverage");//标准版ESB数据导入不区分是否覆盖,默认都为覆盖 - importCreate(item, batchMapper, apiTestCaseMapper, extApiDefinitionMapper, request, apiImport.getCases(), apiImport.getMocks(), urlRepeat); + importCreate(item, batchMapper, apiTestCaseMapper, extApiDefinitionMapper, request, apiImport.getCases(), apiImport.getMocks(), updateList); if (model != null) { apiImport.getEsbApiParamsMap().remove(apiId); model.setResourceId(item.getId()); apiImport.getEsbApiParamsMap().put(item.getId(), model); } } else { - importCreate(item, batchMapper, apiTestCaseMapper, extApiDefinitionMapper, request, apiImport.getCases(), apiImport.getMocks(), urlRepeat); + importCreate(item, batchMapper, apiTestCaseMapper, extApiDefinitionMapper, request, apiImport.getCases(), apiImport.getMocks(), updateList); } if (i % 300 == 0) { sqlSession.flushStatements(); @@ -1341,7 +1401,6 @@ public class ApiDefinitionService { model.setId(exiteModelList.get(0).getId()); esbApiParamsMapper.updateByPrimaryKeyWithBLOBs(model); } - } } @@ -1351,7 +1410,7 @@ public class ApiDefinitionService { } if (!CollectionUtils.isEmpty(apiImport.getCases())) { - importMsCase(apiImport, sqlSession, request); + importMsCase(apiImport, sqlSession, request, apiTestCaseMapper); } if (sqlSession != null && sqlSessionFactory != null) { SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java index b87a1d19bb..b63e786803 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiModuleService.java @@ -2,10 +2,9 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; -import io.metersphere.api.dto.definition.ApiDefinitionRequest; -import io.metersphere.api.dto.definition.ApiDefinitionResult; -import io.metersphere.api.dto.definition.ApiModuleDTO; -import io.metersphere.api.dto.definition.DragModuleRequest; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.*; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiDefinitionMapper; import io.metersphere.base.mapper.ApiModuleMapper; @@ -13,6 +12,7 @@ import io.metersphere.base.mapper.ext.ExtApiDefinitionMapper; import io.metersphere.base.mapper.ext.ExtApiModuleMapper; import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.BeanUtils; import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.SessionUtils; import io.metersphere.i18n.Translator; @@ -49,8 +49,6 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { @Resource private ExtApiDefinitionMapper extApiDefinitionMapper; @Resource - private ApiDefinitionMapper apiDefinitionMapper; - @Resource private TestPlanProjectService testPlanProjectService; @Resource private ProjectService projectService; @@ -72,11 +70,16 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { return apiModuleMapper.selectByPrimaryKey(id); } + + public List<ApiModuleDTO> getApiModulesByProjectAndPro(String projectId, String protocol) { + return extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol); + } + public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol, String versionId) { // 判断当前项目下是否有默认模块,没有添加默认模块 this.getDefaultNode(projectId, protocol); - List<ApiModuleDTO> apiModules = extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol); ApiDefinitionRequest request = new ApiDefinitionRequest(); + List<ApiModuleDTO> apiModules = getApiModulesByProjectAndPro(projectId, protocol); request.setProjectId(projectId); request.setProtocol(protocol); List<String> list = new ArrayList<>(); @@ -162,7 +165,7 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { return addNodeWithoutValidate(node); } - private double getNextLevelPos(String projectId, int level, String parentId) { + public double getNextLevelPos(String projectId, int level, String parentId) { List<ApiModule> list = getPos(projectId, level, parentId, "pos desc"); if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) { return list.get(0).getPos() + DEFAULT_POS; @@ -219,7 +222,7 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { if (apiCases.isEmpty()) { return null; } - List<ApiModuleDTO> testCaseNodes = extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol); + List<ApiModuleDTO> testCaseNodes = getApiModulesByProjectAndPro(projectId, protocol); List<String> caseIds = apiCases.stream() .map(TestPlanApiCase::getApiCaseId) @@ -453,31 +456,23 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { } } - public ApiModule getModuleByName(String projectId, String protocol) { + public ApiModule getModuleByNameAndLevel(String projectId, String protocol, String name, Integer level) { ApiModuleExample example = new ApiModuleExample(); - ApiModuleExample.Criteria criteria = example.createCriteria(); - criteria.andNameEqualTo("bug") - .andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol); + example.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol).andNameEqualTo(name).andLevelEqualTo(level); List<ApiModule> modules = apiModuleMapper.selectByExample(example); if (CollectionUtils.isNotEmpty(modules)) { return modules.get(0); } else { - ApiModule node = new ApiModule(); - node.setName("bug"); - node.setLevel(1); - node.setPos(0.0); - node.setParentId(null); - node.setProjectId(projectId); - node.setProtocol(protocol); - node.setCreateTime(System.currentTimeMillis()); - node.setUpdateTime(System.currentTimeMillis()); - node.setId(UUID.randomUUID().toString()); - node.setCreateUser(SessionUtils.getUserId()); - apiModuleMapper.insertSelective(node); - return node; + return null; } } + public List<ApiModule> getMListByProAndProtocol(String projectId, String protocol) { + ApiModuleExample example = new ApiModuleExample(); + example.createCriteria().andProjectIdEqualTo(projectId).andProtocolEqualTo(protocol); + return apiModuleMapper.selectByExample(example); + } + public String getLogDetails(List<String> ids) { ApiModuleExample example = new ApiModuleExample(); ApiModuleExample.Criteria criteria = example.createCriteria(); @@ -597,10 +592,647 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> { }); returnMap.put(protocol, idLIst); } - } } } return returnMap; } + + /** + * 上传文件时对文件的模块进行检测 + * + * @param data + * @param fullCoverage 是否覆盖接口 + * @return Return to the newly added module list and api list + */ + public UpdateApiModuleDTO checkApiModule(ApiTestImportRequest request, ApiDefinitionImport apiImport, List<ApiDefinitionWithBLOBs> data, Boolean fullCoverage, boolean urlRepeat) { + Boolean fullCoverageApi = request.getCoverModule(); + String projectId = request.getProjectId(); + String protocol = request.getProtocol(); + //上传文件时选的模块ID + String chooseModuleId = request.getModuleId(); + + if (fullCoverage == null) { + fullCoverage = false; + } + + if (fullCoverageApi == null) { + fullCoverageApi = false; + } + + //标准版ESB数据导入不区分是否覆盖,默认都为覆盖 + if (apiImport.getEsbApiParamsMap() != null) { + fullCoverage = true; + } + Set<String> versionSet = new HashSet<>(); + + if (fullCoverage) { + setFullVersionSet(request, versionSet); + } else { + String updateVersionId = getUpdateVersionId(request); + versionSet.add(updateVersionId); + } + + //需要新增的模块,key 为模块路径 + Map<String, ApiModule> moduleMap = new HashMap<>(); + //系统原有的需要更新的list, + List<ApiDefinitionWithBLOBs> toUpdateList = new ArrayList<>(); + //获取当前项目的当前协议下的所有模块的Tree + List<ApiModuleDTO> apiModules = this.getApiModulesByProjectAndPro(projectId, protocol); + List<ApiModuleDTO> nodeTreeByProjectId = this.getNodeTrees(apiModules); + + //所有模块的ID 及其自身 的map + Map<String, ApiModuleDTO> idModuleMap = apiModules.stream().collect(Collectors.toMap(ApiModuleDTO::getId, apiModuleDTO -> apiModuleDTO)); + + //父级ID与其子模块集合的map + Map<String, List<ApiModule>> pidChildrenMap = new HashMap<>(); + //所有模块的ID 及其全路径的map + Map<String, String> idPathMap = new HashMap<>(); + + String initParentModulePath = "/root"; + Map<String, String> initParentModulePathMap = new HashMap<>(); + initParentModulePathMap.put("root", initParentModulePath); + buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap, initParentModulePathMap); + + //获取选中的模块 + ApiModuleDTO chooseModule = null; + if (chooseModuleId != null) { + chooseModule = idModuleMap.get(chooseModuleId); + } + + List<ApiDefinitionWithBLOBs> optionData = new ArrayList<>(); + + if (protocol.equals("HTTP")) { + //去重 如果url可重复 则模块+名称+请求方式+路径 唯一,否则 请求方式+路径唯一, + //覆盖模式留重复的最后一个,不覆盖留第一个 + removeHTTPRepeat(data, fullCoverage, urlRepeat, optionData); + + //处理模块 + setModule(moduleMap, pidChildrenMap, idPathMap, idModuleMap, optionData, chooseModule); + //系统内重复的数据 + List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs = getRepeatBLOBsList(projectId, versionSet, chooseModule, optionData); + //处理数据 + if (urlRepeat) { + moduleMap = getRepeatApiModuleMap(fullCoverage, fullCoverageApi, moduleMap, toUpdateList, idPathMap, chooseModule, optionData, repeatApiDefinitionWithBLOBs); + } else { + moduleMap = getOnlyApiModuleMap(fullCoverage, fullCoverageApi, moduleMap, toUpdateList, idPathMap, chooseModule, optionData, repeatApiDefinitionWithBLOBs); + } + } else { + //去重,TCP,SQL,DUBBO 模块下名称唯一 + removeRepeat(data, fullCoverage, optionData); + + //处理模块 + setModule(moduleMap, pidChildrenMap, idPathMap, idModuleMap, optionData, chooseModule); + + //处理数据 + List<String> nameList = optionData.stream().map(ApiDefinitionWithBLOBs::getName).collect(Collectors.toList()); + + //获取系统内重复数据 + List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByProtocol(nameList, protocol, versionSet); + + Map<String, ApiDefinitionWithBLOBs> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.toMap(t -> t.getName() + t.getModulePath(), api -> api)); + Map<String, ApiDefinitionWithBLOBs> nameModuleMap = getNameApiMap(idPathMap, chooseModule, optionData, repeatApiDefinitionWithBLOBs); + + //处理数据 + if (fullCoverage) { + if (fullCoverageApi) { + coverModule(toUpdateList, nameModuleMap, repeatDataMap); + } else { + moduleMap = cover(moduleMap, toUpdateList, nameModuleMap, repeatDataMap); + } + } else { + //不覆盖 + removeRepeat(optionData, nameModuleMap, repeatDataMap); + } + } + return getUpdateApiModuleDTO(moduleMap, toUpdateList, optionData); + } + + + private UpdateApiModuleDTO getUpdateApiModuleDTO(Map<String, ApiModule> moduleMap, List<ApiDefinitionWithBLOBs> toUpdateList, List<ApiDefinitionWithBLOBs> optionData) { + UpdateApiModuleDTO updateApiModuleDTO = new UpdateApiModuleDTO(); + updateApiModuleDTO.setModuleList(new ArrayList<>(moduleMap.values())); + updateApiModuleDTO.setNeedUpdateList(toUpdateList); + updateApiModuleDTO.setDefinitionWithBLOBs(optionData); + return updateApiModuleDTO; + } + + private Map<String, ApiDefinitionWithBLOBs> getNameApiMap(Map<String, String> idPathMap, ApiModuleDTO chooseModule, List<ApiDefinitionWithBLOBs> optionData, List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs) { + Map<String, ApiDefinitionWithBLOBs> nameModuleMap = null; + if (chooseModule != null) { + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + nameModuleMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + chooseModulePath, api -> api)); + } + } else { + nameModuleMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), api -> api)); + } + return nameModuleMap; + } + + private List<ApiDefinitionWithBLOBs> getRepeatBLOBsList(String projectId, Set<String> versionSet, ApiModuleDTO chooseModule, List<ApiDefinitionWithBLOBs> optionData) { + List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs; + if (chooseModule != null) { + repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBsSameUrl(optionData, projectId, chooseModule.getId(), versionSet); + } else { + repeatApiDefinitionWithBLOBs = extApiDefinitionMapper.selectRepeatByBLOBs(optionData, projectId, versionSet); + } + return repeatApiDefinitionWithBLOBs; + } + + private void removeRepeat(List<ApiDefinitionWithBLOBs> optionData, Map<String, ApiDefinitionWithBLOBs> nameModuleMap, Map<String, ApiDefinitionWithBLOBs> repeatDataMap) { + if (nameModuleMap != null) { + Map<String, ApiDefinitionWithBLOBs> finalNameModuleMap = nameModuleMap; + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = finalNameModuleMap.get(k); + if (apiDefinitionWithBLOBs != null) { + optionData.remove(apiDefinitionWithBLOBs); + } + }); + } + } + + private Map<String, ApiModule> cover(Map<String, ApiModule> moduleMap, List<ApiDefinitionWithBLOBs> toUpdateList, Map<String, ApiDefinitionWithBLOBs> nameModuleMap, Map<String, ApiDefinitionWithBLOBs> repeatDataMap) { + //覆盖但不覆盖模块 + if (nameModuleMap != null) { + //导入文件没有新增场景无需创建接口模块 + if (repeatDataMap.size() >= nameModuleMap.size()) { + moduleMap = new HashMap<>(); + } + Map<String, ApiDefinitionWithBLOBs> finalNameModuleMap = nameModuleMap; + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = finalNameModuleMap.get(k); + if (apiDefinitionWithBLOBs != null) { + apiDefinitionWithBLOBs.setId(v.getId()); + apiDefinitionWithBLOBs.setVersionId(v.getVersionId()); + apiDefinitionWithBLOBs.setModuleId(v.getModuleId()); + apiDefinitionWithBLOBs.setModulePath(v.getModulePath()); + toUpdateList.add(apiDefinitionWithBLOBs); + } + }); + } + return moduleMap; + } + + private void coverModule(List<ApiDefinitionWithBLOBs> toUpdateList, Map<String, ApiDefinitionWithBLOBs> nameModuleMap, Map<String, ApiDefinitionWithBLOBs> repeatDataMap) { + if (nameModuleMap != null) { + Map<String, ApiDefinitionWithBLOBs> finalNameModuleMap = nameModuleMap; + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = finalNameModuleMap.get(k); + if (apiDefinitionWithBLOBs != null) { + apiDefinitionWithBLOBs.setId(v.getId()); + apiDefinitionWithBLOBs.setVersionId(v.getVersionId()); + toUpdateList.add(apiDefinitionWithBLOBs); + } + }); + } + } + + private void removeRepeat(List<ApiDefinitionWithBLOBs> data, Boolean fullCoverage, List<ApiDefinitionWithBLOBs> optionData) { + LinkedHashMap<String, List<ApiDefinitionWithBLOBs>> methodPathMap = data.stream().collect(Collectors.groupingBy(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), LinkedHashMap::new, Collectors.toList())); + if (fullCoverage) { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } + + private Map<String, ApiModule> getOnlyApiModuleMap(Boolean fullCoverage, Boolean fullCoverageApi, Map<String, ApiModule> moduleMap, List<ApiDefinitionWithBLOBs> toUpdateList, Map<String, String> idPathMap, ApiModuleDTO chooseModule, List<ApiDefinitionWithBLOBs> optionData, List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs) { + Map<String, ApiDefinitionWithBLOBs> methodPathMap; + Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath())); + + //按照原来的顺序 + if (chooseModule != null) { + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + methodPathMap = optionData.stream().collect(Collectors.toMap(t -> t.getMethod() + chooseModulePath, api -> api)); + } else { + methodPathMap = optionData.stream().collect(Collectors.toMap(t -> t.getMethod() + t.getPath(), api -> api)); + } + + if (fullCoverage) { + if (fullCoverageApi) { + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + startCoverModule(toUpdateList, optionData, methodPathMap, repeatDataMap); + } + } else { + //不覆盖模块 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + if (repeatDataMap.size() >= methodPathMap.size()) { + //导入文件没有新增接口无需创建接口模块 + moduleMap = new HashMap<>(); + } + startCover(toUpdateList, optionData, methodPathMap, repeatDataMap); + } + } + } else { + //不覆盖,同一接口不做更新 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + removeSameData(repeatDataMap, methodPathMap, optionData); + } + } + return moduleMap; + } + + private Map<String, ApiModule> getRepeatApiModuleMap(Boolean fullCoverage, Boolean fullCoverageApi, Map<String, ApiModule> moduleMap, List<ApiDefinitionWithBLOBs> toUpdateList, Map<String, String> idPathMap, ApiModuleDTO chooseModule, List<ApiDefinitionWithBLOBs> optionData, List<ApiDefinitionWithBLOBs> repeatApiDefinitionWithBLOBs) { + Map<String, ApiDefinitionWithBLOBs> methodPathMap; + //按照原来的顺序 + if (chooseModule != null) { + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + methodPathMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + t.getMethod() + t.getPath() + chooseModulePath, api -> api)); + } else { + methodPathMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + t.getMethod() + t.getPath() + (t.getModulePath() == null ? "" : t.getModulePath()), api -> api)); + } + + Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap = repeatApiDefinitionWithBLOBs.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + t.getModulePath())); + + //覆盖接口 + if (fullCoverage) { + //允许覆盖模块,用导入的重复数据的最后一条覆盖查询的所有重复数据 + if (fullCoverageApi) { + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + startCoverModule(toUpdateList, optionData, methodPathMap, repeatDataMap); + } + } else { + //覆盖但不覆盖模块 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + moduleMap = judgeModuleMap(moduleMap, methodPathMap, repeatDataMap); + startCover(toUpdateList, optionData, methodPathMap, repeatDataMap); + } + } + } else { + //不覆盖,同一接口不做更新 + if (!repeatApiDefinitionWithBLOBs.isEmpty()) { + removeSameData(repeatDataMap, methodPathMap, optionData); + } + + } + return moduleMap; + } + + private void removeHTTPRepeat(List<ApiDefinitionWithBLOBs> data, Boolean fullCoverage, boolean urlRepeat, List<ApiDefinitionWithBLOBs> optionData) { + if (urlRepeat) { + LinkedHashMap<String, List<ApiDefinitionWithBLOBs>> methodPathMap = data.stream().collect(Collectors.groupingBy(t -> t.getName() + t.getMethod() + t.getPath() + (t.getModulePath() == null ? "" : t.getModulePath()), LinkedHashMap::new, Collectors.toList())); + if (fullCoverage) { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } else { + LinkedHashMap<String, List<ApiDefinitionWithBLOBs>> methodPathMap = data.stream().collect(Collectors.groupingBy(t -> t.getMethod() + t.getPath(), LinkedHashMap::new, Collectors.toList())); + if (fullCoverage) { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + methodPathMap.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } + } + + private void setFullVersionSet(ApiTestImportRequest request, Set<String> versionSet) { + String creatVersionId; + if (request.getVersionId() != null) { + creatVersionId = request.getVersionId(); + } else { + creatVersionId = request.getDefaultVersion(); + } + versionSet.add(creatVersionId); + String updateVersionId; + if (request.getUpdateVersionId() != null) { + updateVersionId = request.getUpdateVersionId(); + } else { + updateVersionId = request.getDefaultVersion(); + } + versionSet.add(updateVersionId); + } + + private String getUpdateVersionId(ApiTestImportRequest request) { + String updateVersionId; + if (request.getVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getVersionId(); + } + return updateVersionId; + } + + private void removeSameData(Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap, Map<String, ApiDefinitionWithBLOBs> methodPathMap, List<ApiDefinitionWithBLOBs> optionData) { + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + optionData.remove(apiDefinitionWithBLOBs); + } + }); + } + + private void startCoverModule(List<ApiDefinitionWithBLOBs> toUpdateList, List<ApiDefinitionWithBLOBs> optionData, Map<String, ApiDefinitionWithBLOBs> methodPathMap, Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap) { + List<ApiDefinitionWithBLOBs> coverApiList = new ArrayList<>(); + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + for (ApiDefinitionWithBLOBs definitionWithBLOBs : v) { + ApiDefinitionWithBLOBs api = new ApiDefinitionWithBLOBs(); + BeanUtils.copyBean(api, apiDefinitionWithBLOBs); + api.setId(definitionWithBLOBs.getId()); + api.setVersionId(definitionWithBLOBs.getVersionId()); + api.setOrder(definitionWithBLOBs.getOrder()); + api.setRefId(apiDefinitionWithBLOBs.getRefId()); + api.setLatest(apiDefinitionWithBLOBs.getLatest()); + coverApiList.add(api); + } + optionData.remove(apiDefinitionWithBLOBs); + } + }); + buildOtherParam(toUpdateList, optionData, coverApiList); + } + + private void startCover(List<ApiDefinitionWithBLOBs> toUpdateList, List<ApiDefinitionWithBLOBs> optionData, Map<String, ApiDefinitionWithBLOBs> methodPathMap, Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap) { + List<ApiDefinitionWithBLOBs> coverApiList = new ArrayList<>(); + repeatDataMap.forEach((k, v) -> { + ApiDefinitionWithBLOBs apiDefinitionWithBLOBs = methodPathMap.get(k); + if (apiDefinitionWithBLOBs != null) { + for (ApiDefinitionWithBLOBs definitionWithBLOBs : v) { + ApiDefinitionWithBLOBs api = new ApiDefinitionWithBLOBs(); + BeanUtils.copyBean(api, apiDefinitionWithBLOBs); + api.setId(definitionWithBLOBs.getId()); + api.setVersionId(definitionWithBLOBs.getVersionId()); + api.setModuleId(definitionWithBLOBs.getModuleId()); + api.setModulePath(definitionWithBLOBs.getModulePath()); + api.setOrder(definitionWithBLOBs.getOrder()); + api.setRefId(apiDefinitionWithBLOBs.getRefId()); + api.setLatest(apiDefinitionWithBLOBs.getLatest()); + coverApiList.add(api); + } + optionData.remove(apiDefinitionWithBLOBs); + } + }); + buildOtherParam(toUpdateList, optionData, coverApiList); + } + + private Map<String, ApiModule> judgeModuleMap(Map<String, ApiModule> moduleMap, Map<String, ApiDefinitionWithBLOBs> methodPathMap, Map<String, List<ApiDefinitionWithBLOBs>> repeatDataMap) { + Set<String> repeatKeys = repeatDataMap.keySet(); + Set<String> importKeys = methodPathMap.keySet(); + List<String> repeatKeyList = new ArrayList<>(repeatKeys); + List<String> importKeysList = new ArrayList<>(importKeys); + List<String> intersection = repeatKeyList.stream().filter(item -> importKeysList.contains(item)).collect(Collectors.toList()); + if (intersection.size() == importKeysList.size()) { + //导入文件没有新增接口无需创建接口模块 + moduleMap = new HashMap<>(); + } + return moduleMap; + } + + private void buildOtherParam(List<ApiDefinitionWithBLOBs> toUpdateList, List<ApiDefinitionWithBLOBs> optionData, List<ApiDefinitionWithBLOBs> coverApiList) { + optionData.addAll(coverApiList); + toUpdateList.addAll(coverApiList); + } + + private List<ApiDefinitionWithBLOBs> setModule(Map<String, ApiModule> moduleMap, Map<String, List<ApiModule>> pidChildrenMap, + Map<String, String> idPathMap, Map<String, ApiModuleDTO> idModuleMap, List<ApiDefinitionWithBLOBs> data, ApiModuleDTO chooseModule) { + for (ApiDefinitionWithBLOBs datum : data) { + String modulePath = datum.getModulePath(); + ApiModule apiModule = moduleMap.get(modulePath); + if (chooseModule != null) { + dealChooseModuleData(moduleMap, pidChildrenMap, idPathMap, idModuleMap, chooseModule, datum, modulePath); + } else { + dealNoModuleData(moduleMap, pidChildrenMap, idPathMap, idModuleMap, datum, modulePath, apiModule); + } + } + return data; + } + + private void dealNoModuleData(Map<String, ApiModule> moduleMap, Map<String, List<ApiModule>> pidChildrenMap, Map<String, String> idPathMap, Map<String, ApiModuleDTO> idModuleMap, ApiDefinitionWithBLOBs datum, String modulePath, ApiModule apiModule) { + String[] pathTree; + if (StringUtils.isNotBlank(modulePath)) { + //导入时没选模块但接口有模块的,根据modulePath,和当前协议查询当前项目里是否有同名称模块,如果有,就在该模块下建立接口,否则新建模块 + pathTree = getPathTree(modulePath); + if (apiModule != null) { + datum.setModuleId(apiModule.getId()); + datum.setModulePath(modulePath); + } else { + List<ApiModule> moduleList = pidChildrenMap.get("root"); + ApiModule minModule = getMinModule(pathTree, moduleList, null, pidChildrenMap, moduleMap, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } + } else { + //导入时即没选中模块,接口自身也没模块的,直接返会当前项目,当前协议下的默认模块 + List<ApiModule> moduleList = pidChildrenMap.get("root"); + for (ApiModule module : moduleList) { + if (module.getName().equals("未规划接口")) { + datum.setModuleId(module.getId()); + datum.setModulePath("/" + module.getName()); + } + } + } + } + + private void dealChooseModuleData(Map<String, ApiModule> moduleMap, Map<String, List<ApiModule>> pidChildrenMap, Map<String, String> idPathMap, Map<String, ApiModuleDTO> idModuleMap, ApiModuleDTO chooseModule, ApiDefinitionWithBLOBs datum, String modulePath) { + String[] pathTree; + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + //导入时选了模块,且接口有模块的 + if (StringUtils.isNotBlank(modulePath)) { + List<ApiModule> moduleList = pidChildrenMap.get(chooseModuleParentId); + pathTree = getPathTree(chooseModulePath + modulePath); + + ApiModule chooseModuleOne = JSON.parseObject(JSON.toJSONString(chooseModule), ApiModule.class); + ApiModule minModule = getMinModule(pathTree, moduleList, chooseModuleOne, pidChildrenMap, moduleMap, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } else { + //导入时选了模块,且接口没有模块的 + datum.setModuleId(chooseModule.getId()); + datum.setModulePath(idPathMap.get(chooseModule.getId())); + } + } + + private String getChooseModulePath(Map<String, String> idPathMap, ApiModuleDTO chooseModule, String chooseModuleParentId) { + String s; + if (chooseModuleParentId.equals("root")) { + s = "/" + chooseModule.getName(); + } else { + s = idPathMap.get(chooseModuleParentId); + } + return s; + } + + private String getChooseModuleParentId(ApiModuleDTO chooseModule) { + if (chooseModule.getParentId() == null) { + chooseModule.setParentId("root"); + } + String chooseModuleParentId = chooseModule.getParentId(); + return chooseModuleParentId; + } + + private String[] getPathTree(String modulePath) { + String substring = modulePath.substring(0, 1); + if (substring.equals("/")) { + modulePath = modulePath.substring(1); + } + if (modulePath.contains("/")) { + //如果模块有层级,逐级查找,如果某一级不在当前项目了,则新建该层级的模块及其子集 + return modulePath.split("/"); + } else { + return new String[]{modulePath}; + } + } + + private ApiModule getMinModule(String[] tagTree, List<ApiModule> parentModuleList, ApiModule parentModule, Map<String, List<ApiModule>> pidChildrenMap, Map<String, ApiModule> moduleMap + , Map<String, String> idPathMap, Map<String, ApiModuleDTO> idModuleMap) { + //如果parentModule==null 则证明需要创建根目录同级的模块 + ApiModule returnModule = null; + for (int i = 0; i < tagTree.length; i++) { + int finalI = i; + List<ApiModule> collect = parentModuleList.stream().filter(t -> t.getName().equals(tagTree[finalI])).collect(Collectors.toList()); + if (collect.isEmpty()) { + if (i == 0) { + //证明需要在根目录创建, + parentModule = new ApiModule(); + parentModule.setProjectId(pidChildrenMap.get("root").get(0).getProjectId()); + parentModule.setId("root"); + parentModule.setLevel(0); + parentModule.setProtocol(pidChildrenMap.get("root").get(0).getProtocol()); + } else { + if (!parentModuleList.isEmpty() && parentModule == null) { + String parentId = parentModuleList.get(0).getParentId(); + ApiModuleDTO apiModuleDTO = idModuleMap.get(parentId); + parentModule = JSON.parseObject(JSON.toJSONString(apiModuleDTO), ApiModule.class); + } + } + return createModule(tagTree, i, parentModule, moduleMap, pidChildrenMap, idPathMap); + } else { + returnModule = collect.get(0); + parentModule = collect.get(0); + parentModuleList = pidChildrenMap.get(collect.get(0).getId()); + } + } + return returnModule; + } + + private ApiModule createModule(String[] tagTree, int i, ApiModule parentModule, Map<String, ApiModule> moduleMap, Map<String, List<ApiModule>> pidChildrenMap, Map<String, String> idPathMap) { + ApiModule returnModule = null; + for (int i1 = i; i1 < tagTree.length; i1++) { + String pathName = tagTree[i1]; + ApiModule newModule = this.getNewModule(pathName, parentModule.getProjectId(), parentModule.getLevel() + 1); + String parentId; + if (parentModule.getId().equals("root")) { + parentId = null; + } else { + parentId = parentModule.getId(); + } + double pos = this.getNextLevelPos(parentModule.getProjectId(), parentModule.getLevel() + 1, parentId); + newModule.setPos(pos); + newModule.setProtocol(parentModule.getProtocol()); + newModule.setParentId(parentId); + List<ApiModule> moduleList = pidChildrenMap.get(parentModule.getId()); + if (moduleList != null) { + moduleList.add(newModule); + } else { + moduleList = new ArrayList<>(); + moduleList.add(newModule); + pidChildrenMap.put(parentModule.getId(), moduleList); + } + + String parentPath = idPathMap.get(parentModule.getId()); + String path; + if (StringUtils.isNotBlank(parentPath)) { + path = parentPath + "/" + pathName; + } else { + path = "/" + pathName; + } + idPathMap.put(newModule.getId(), path); + moduleMap.putIfAbsent(path, newModule); + parentModule = newModule; + returnModule = newModule; + } + return returnModule; + } + + private void buildProcessData(List<ApiModuleDTO> nodeTreeByProjectId, Map<String, List<ApiModule>> pidChildrenMap, Map<String, String> idPathMap, Map<String, String> parentModulePathMap) { + //当前层级的模块的所有子模块的集合 + Map<String, List<ApiModuleDTO>> idChildrenMap = new HashMap<>(); + int i = 0; + Map<String, List<ApiModule>> idModuleMap = new HashMap<>(); + for (ApiModuleDTO apiModuleDTO : nodeTreeByProjectId) { + if (StringUtils.isBlank(apiModuleDTO.getParentId())) { + apiModuleDTO.setParentId("root"); + } + String parentModulePath = parentModulePathMap.get(apiModuleDTO.getParentId()); + if (parentModulePath != null) { + if (parentModulePath.equals("/root")) { + apiModuleDTO.setPath("/" + apiModuleDTO.getName()); + } else { + apiModuleDTO.setPath(parentModulePath + "/" + apiModuleDTO.getName()); + } + } else { + apiModuleDTO.setPath("/" + apiModuleDTO.getName()); + } + idPathMap.put(apiModuleDTO.getId(), apiModuleDTO.getPath()); + + ApiModule apiModule = buildModule(idModuleMap, apiModuleDTO); + if (pidChildrenMap.get(apiModuleDTO.getParentId()) != null) { + pidChildrenMap.get(apiModuleDTO.getParentId()).add(apiModule); + } else { + pidChildrenMap.put(apiModuleDTO.getParentId(), idModuleMap.get(apiModuleDTO.getId())); + } + i = i + 1; + List<ApiModuleDTO> childrenList = idChildrenMap.get(apiModuleDTO.getId()); + if (apiModuleDTO.getChildren() != null) { + if (childrenList != null) { + childrenList.addAll(apiModuleDTO.getChildren()); + } else { + idChildrenMap.put(apiModuleDTO.getId(), apiModuleDTO.getChildren()); + } + } else { + if (childrenList == null) { + pidChildrenMap.put(apiModuleDTO.getId(), new ArrayList<>()); + } + } + parentModulePathMap.put(apiModuleDTO.getId(), apiModuleDTO.getPath()); + } + if (i == nodeTreeByProjectId.size() && nodeTreeByProjectId.size() > 0) { + Collection<List<ApiModuleDTO>> values = idChildrenMap.values(); + List<ApiModuleDTO> childrenList = new ArrayList<>(); + for (List<ApiModuleDTO> value : values) { + childrenList.addAll(value); + } + buildProcessData(childrenList, pidChildrenMap, idPathMap, parentModulePathMap); + } + } + + private ApiModule buildModule(Map<String, List<ApiModule>> idModuleMap, ApiModuleDTO apiModuleDTO) { + ApiModule apiModule = new ApiModule(); + apiModule.setId(apiModuleDTO.getId()); + apiModule.setName(apiModuleDTO.getName()); + apiModule.setParentId(apiModuleDTO.getParentId()); + apiModule.setProjectId(apiModuleDTO.getProjectId()); + apiModule.setProtocol(apiModuleDTO.getProtocol()); + apiModule.setLevel(apiModuleDTO.getLevel()); + List<ApiModule> moduleList = idModuleMap.get(apiModuleDTO.getId()); + if (moduleList != null) { + moduleList.add(apiModule); + } else { + moduleList = new ArrayList<>(); + moduleList.add(apiModule); + idModuleMap.put(apiModuleDTO.getId(), moduleList); + } + return apiModule; + } + } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index 475448c326..25c0dcdd86 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -2,10 +2,8 @@ package io.metersphere.api.service; import com.alibaba.fastjson.JSON; -import io.metersphere.api.dto.automation.ApiScenarioDTO; -import io.metersphere.api.dto.automation.ApiScenarioModuleDTO; -import io.metersphere.api.dto.automation.ApiScenarioRequest; -import io.metersphere.api.dto.automation.DragApiScenarioModuleRequest; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.automation.*; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.ApiScenarioModuleMapper; @@ -88,21 +86,21 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD moduleIds = this.nodeList(nodes, node.getId(), moduleIds); moduleIds.add(node.getId()); for (String moduleId : moduleIds) { - if(!allModuleIdList.contains(moduleId)){ + if (!allModuleIdList.contains(moduleId)) { allModuleIdList.add(moduleId); } } } request.setModuleIds(allModuleIdList); - List<Map<String,Object>> moduleCountList = extApiScenarioMapper.listModuleByCollection(request); - Map<String,Integer> moduleCountMap = this.parseModuleCountList(moduleCountList); + List<Map<String, Object>> moduleCountList = extApiScenarioMapper.listModuleByCollection(request); + Map<String, Integer> moduleCountMap = this.parseModuleCountList(moduleCountList); nodes.forEach(node -> { List<String> moduleIds = new ArrayList<>(); moduleIds = this.nodeList(nodes, node.getId(), moduleIds); moduleIds.add(node.getId()); int countNum = 0; for (String moduleId : moduleIds) { - if(moduleCountMap.containsKey(moduleId)){ + if (moduleCountMap.containsKey(moduleId)) { countNum += moduleCountMap.get(moduleId).intValue(); } } @@ -110,17 +108,18 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD }); return getNodeTrees(nodes); } + private Map<String, Integer> parseModuleCountList(List<Map<String, Object>> moduleCountList) { - Map<String,Integer> returnMap = new HashMap<>(); - for (Map<String, Object> map: moduleCountList){ + Map<String, Integer> returnMap = new HashMap<>(); + for (Map<String, Object> map : moduleCountList) { Object moduleIdObj = map.get("moduleId"); Object countNumObj = map.get("countNum"); - if(moduleIdObj!= null && countNumObj != null){ + if (moduleIdObj != null && countNumObj != null) { String moduleId = String.valueOf(moduleIdObj); try { Integer countNumInteger = new Integer(String.valueOf(countNumObj)); - returnMap.put(moduleId,countNumInteger); - }catch (Exception e){ + returnMap.put(moduleId, countNumInteger); + } catch (Exception e) { } } } @@ -140,7 +139,7 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD return list; } - private double getNextLevelPos(String projectId, int level, String parentId) { + public double getNextLevelPos(String projectId, int level, String parentId) { List<ApiScenarioModule> list = getPos(projectId, level, parentId, "pos desc"); if (!CollectionUtils.isEmpty(list) && list.get(0) != null && list.get(0).getPos() != null) { return list.get(0).getPos() + DEFAULT_POS; @@ -465,9 +464,424 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD record.setProjectId(projectId); record.setCreateUser(SessionUtils.getUserId()); apiScenarioModuleMapper.insert(record); - return record; - }else { + return record; + } else { return list.get(0); } } + + /** + * 上传文件时对文件的模块进行检测 + * + * @param data + * @param fullCoverage 是否覆盖接口 + * @param fullCoverageScenario 是否更新当前接口所在模块 + * @return Return to the newly added module map + */ + public UpdateScenarioModuleDTO checkScenarioModule(ApiTestImportRequest request, List<ApiScenarioWithBLOBs> data, Boolean fullCoverage, Boolean fullCoverageScenario) { + //需要新增的模块,key 为模块路径 + Map<String, ApiScenarioModule> moduleMap = new HashMap<>(); + List<ApiScenarioWithBLOBs> toUpdateList = new ArrayList<>(); + + //上传文件时选的模块ID + String chooseModuleId = request.getModuleId(); + String projectId = request.getProjectId(); + + if (fullCoverageScenario == null) { + fullCoverageScenario = false; + } + + //获取当前项目的当前协议下的所有模块的Tree + List<ApiScenarioModuleDTO> scenarioModules = extApiScenarioModuleMapper.getNodeTreeByProjectId(projectId); + List<ApiScenarioModuleDTO> nodeTreeByProjectId = this.getNodeTrees(scenarioModules); + + Map<String, ApiScenarioModuleDTO> idModuleMap = scenarioModules.stream().collect(Collectors.toMap(ApiScenarioModuleDTO::getId, scenarioModuleDTO -> scenarioModuleDTO)); + + Map<String, List<ApiScenarioModule>> pidChildrenMap = new HashMap<>(); + Map<String, String> idPathMap = new HashMap<>(); + //构建以上两种数据 + String initParentModulePath = "/root"; + Map<String, String> initParentModulePathMap = new HashMap<>(); + initParentModulePathMap.put("root", initParentModulePath); + buildProcessData(nodeTreeByProjectId, pidChildrenMap, idPathMap, initParentModulePathMap); + + ApiScenarioModuleDTO chooseModule = null; + if (chooseModuleId != null) { + chooseModule = idModuleMap.get(chooseModuleId); + } + + Set<String> versionSet = new HashSet<>(); + + if (fullCoverage) { + setFullVersionSet(request, versionSet); + } else { + String updateVersionId = getUpdateVersionId(request); + versionSet.add(updateVersionId); + } + + + List<ApiScenarioWithBLOBs> optionData = new ArrayList<>(); + + //覆盖模式留重复的最后一个,不覆盖留第一个 + LinkedHashMap<String, List<ApiScenarioWithBLOBs>> nameModuleMapList = data.stream().collect(Collectors.groupingBy(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), LinkedHashMap::new, Collectors.toList())); + removeRepeat(fullCoverage, optionData, nameModuleMapList); + + //处理模块 + setModule(optionData, moduleMap, pidChildrenMap, idPathMap, idModuleMap, chooseModule); + + //系统内重复的数据 + List<ApiScenarioWithBLOBs> repeatApiScenarioWithBLOBs; + if (chooseModule != null) { + repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBsSameUrl(optionData, projectId, chooseModule.getId(), versionSet); + } else { + repeatApiScenarioWithBLOBs = extApiScenarioMapper.selectRepeatByBLOBs(optionData, projectId, versionSet); + } + + Map<String, ApiScenarioWithBLOBs> nameModuleMap = null; + Map<String, ApiScenarioWithBLOBs> repeatDataMap = repeatApiScenarioWithBLOBs.stream().collect(Collectors.toMap(t -> t.getName() + t.getModulePath(), scenario -> scenario)); + if (chooseModule != null) { + if (!repeatApiScenarioWithBLOBs.isEmpty()) { + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + nameModuleMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + chooseModulePath, scenario -> scenario)); + } + } else { + nameModuleMap = optionData.stream().collect(Collectors.toMap(t -> t.getName() + (t.getModulePath() == null ? "" : t.getModulePath()), scenario -> scenario)); + } + //处理数据 + if (fullCoverage) { + if (fullCoverageScenario) { + startCoverModule(toUpdateList, nameModuleMap, repeatDataMap); + } else { + //覆盖但不覆盖模块 + if (nameModuleMap != null) { + //导入文件没有新增场景无需创建接口模块 + moduleMap = judgeModuleMap(moduleMap, nameModuleMap, repeatDataMap); + startCover(toUpdateList, nameModuleMap, repeatDataMap); + } + } + } else { + //不覆盖 + removeRepeat(optionData, nameModuleMap, repeatDataMap); + } + + UpdateScenarioModuleDTO updateScenarioModuleDTO = new UpdateScenarioModuleDTO(); + updateScenarioModuleDTO.setModuleList(new ArrayList<>(moduleMap.values())); + updateScenarioModuleDTO.setNeedUpdateList(toUpdateList); + updateScenarioModuleDTO.setApiScenarioWithBLOBsList(optionData); + return updateScenarioModuleDTO; + } + + private void setFullVersionSet(ApiTestImportRequest request, Set<String> versionSet) { + String creatVersionId; + if (request.getVersionId() != null) { + creatVersionId = request.getVersionId(); + } else { + creatVersionId = request.getDefaultVersion(); + } + versionSet.add(creatVersionId); + String updateVersionId; + if (request.getUpdateVersionId() != null) { + updateVersionId = request.getUpdateVersionId(); + } else { + updateVersionId = request.getDefaultVersion(); + } + versionSet.add(updateVersionId); + } + + private void removeRepeat(List<ApiScenarioWithBLOBs> optionData, Map<String, ApiScenarioWithBLOBs> nameModuleMap, Map<String, ApiScenarioWithBLOBs> repeatDataMap) { + if (repeatDataMap != null) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); + if (apiScenarioWithBLOBs != null) { + optionData.remove(apiScenarioWithBLOBs); + } + }); + } + } + + private void startCover(List<ApiScenarioWithBLOBs> toUpdateList, Map<String, ApiScenarioWithBLOBs> nameModuleMap, Map<String, ApiScenarioWithBLOBs> repeatDataMap) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); + if (apiScenarioWithBLOBs != null) { + apiScenarioWithBLOBs.setId(v.getId()); + apiScenarioWithBLOBs.setVersionId(v.getVersionId()); + apiScenarioWithBLOBs.setApiScenarioModuleId(v.getApiScenarioModuleId()); + apiScenarioWithBLOBs.setModulePath(v.getModulePath()); + toUpdateList.add(apiScenarioWithBLOBs); + } + }); + } + + private Map<String, ApiScenarioModule> judgeModuleMap(Map<String, ApiScenarioModule> moduleMap, Map<String, ApiScenarioWithBLOBs> nameModuleMap, Map<String, ApiScenarioWithBLOBs> repeatDataMap) { + if (repeatDataMap.size() >= nameModuleMap.size()) { + moduleMap = new HashMap<>(); + } + return moduleMap; + } + + private void startCoverModule(List<ApiScenarioWithBLOBs> toUpdateList, Map<String, ApiScenarioWithBLOBs> nameModuleMap, Map<String, ApiScenarioWithBLOBs> repeatDataMap) { + if (repeatDataMap != null) { + repeatDataMap.forEach((k, v) -> { + ApiScenarioWithBLOBs apiScenarioWithBLOBs = nameModuleMap.get(k); + if (apiScenarioWithBLOBs != null) { + apiScenarioWithBLOBs.setId(v.getId()); + apiScenarioWithBLOBs.setVersionId(v.getVersionId()); + toUpdateList.add(apiScenarioWithBLOBs); + } + }); + } + } + + private void removeRepeat(Boolean fullCoverage, List<ApiScenarioWithBLOBs> optionData, LinkedHashMap<String, List<ApiScenarioWithBLOBs>> nameModuleMapList) { + if (fullCoverage) { + nameModuleMapList.forEach((k, v) -> { + optionData.add(v.get(v.size() - 1)); + }); + } else { + nameModuleMapList.forEach((k, v) -> { + optionData.add(v.get(0)); + }); + } + } + + private String getUpdateVersionId(ApiTestImportRequest request) { + String updateVersionId; + if (request.getVersionId() == null) { + updateVersionId = request.getDefaultVersion(); + } else { + updateVersionId = request.getVersionId(); + } + return updateVersionId; + } + + private void setModule(List<ApiScenarioWithBLOBs> data, Map<String, ApiScenarioModule> map, Map<String, List<ApiScenarioModule>> pidChildrenMap, Map<String, String> idPathMap, Map<String, ApiScenarioModuleDTO> idModuleMap, ApiScenarioModuleDTO chooseModule) { + for (ApiScenarioWithBLOBs datum : data) { + StringBuilder path = new StringBuilder(); + path.append("/"); + String[] tagTree; + String modulePath = datum.getModulePath(); + ApiScenarioModule scenarioModule = map.get(modulePath); + if (chooseModule != null) { + String chooseModuleParentId = getChooseModuleParentId(chooseModule); + String chooseModulePath = getChooseModulePath(idPathMap, chooseModule, chooseModuleParentId); + //导入时选了模块,且接口有模块的 + if (StringUtils.isNotBlank(modulePath)) { + //选中模块的同级模块集合,用于和场景的全路径做对比 + List<ApiScenarioModule> parentModuleList = pidChildrenMap.get(chooseModuleParentId); + //场景的全部路径的集合 + tagTree = getTagTree(chooseModulePath + modulePath); + + ApiScenarioModule chooseModuleOne = JSON.parseObject(JSON.toJSONString(chooseModule), ApiScenarioModule.class); + ApiScenarioModule minModule = getMinModule(tagTree, parentModuleList, chooseModuleOne, pidChildrenMap, map, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setApiScenarioModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } else { + //导入时选了模块,且接口没有模块的 + datum.setApiScenarioModuleId(chooseModule.getId()); + datum.setModulePath(idPathMap.get(chooseModule.getId())); + } + } else { + if (StringUtils.isNotBlank(modulePath)) { + //导入时没选模块但接口有模块的,根据modulePath,和当前协议查询当前项目里是否有同名称模块,如果有,就在该模块下建立接口,否则新建模块 + tagTree = getTagTree(modulePath); + if (scenarioModule != null) { + datum.setApiScenarioModuleId(scenarioModule.getId()); + datum.setModulePath(modulePath); + } else { + //父级同级的模块list + ApiScenarioModule minModule = getMinModule(tagTree, pidChildrenMap.get("root"), null, pidChildrenMap, map, idPathMap, idModuleMap); + String id = minModule.getId(); + datum.setApiScenarioModuleId(id); + datum.setModulePath(idPathMap.get(id)); + } + } else { + //导入时即没选中模块,接口自身也没模块的,直接返会当前项目,当前协议下的默认模块 + List<ApiScenarioModule> moduleList = pidChildrenMap.get("root"); + for (ApiScenarioModule module : moduleList) { + if (module.getName().equals("未规划场景")) { + datum.setApiScenarioModuleId(module.getId()); + datum.setModulePath("/" + module.getName()); + } + } + } + } + } + } + + private String getChooseModuleParentId(ApiScenarioModuleDTO chooseModule) { + if (chooseModule.getParentId() == null) { + chooseModule.setParentId("root"); + } + String chooseModuleParentId = chooseModule.getParentId(); + return chooseModuleParentId; + } + + private String getChooseModulePath(Map<String, String> idPathMap, ApiScenarioModuleDTO chooseModule, String chooseModuleParentId) { + String s; + if (chooseModuleParentId.equals("root")) { + s = "/" + chooseModule.getName(); + } else { + s = idPathMap.get(chooseModuleParentId); + } + return s; + } + + private String[] getTagTree(String modulePath) { + String substring = modulePath.substring(0, 1); + if (substring.equals("/")) { + modulePath = modulePath.substring(1); + } + if (modulePath.contains("/")) { + //如果模块有层级,逐级查找,如果某一级不在当前项目了,则新建该层级的模块及其子集 + return modulePath.split("/"); + } else { + return new String[]{modulePath}; + } + } + + private ApiScenarioModule getMinModule(String[] tagTree, List<ApiScenarioModule> parentModuleList, ApiScenarioModule parentModule, Map<String, List<ApiScenarioModule>> pidChildrenMap, Map<String, ApiScenarioModule> map, Map<String, String> idPathMap, Map<String, ApiScenarioModuleDTO> idModuleMap) { + //如果parentModule==null 则证明需要创建根目录同级的模块 + ApiScenarioModule returnModule = null; + + for (int i = 0; i < tagTree.length; i++) { + int finalI = i; + //查找上一级里面是否有当前全路径的第一级,没有则需要创建 + List<ApiScenarioModule> collect = parentModuleList.stream().filter(t -> t.getName().equals(tagTree[finalI])).collect(Collectors.toList()); + + if (collect.isEmpty()) { + if (i == 0) { + //证明需要在根目录创建, + parentModule = new ApiScenarioModule(); + parentModule.setProjectId(pidChildrenMap.get("root").get(0).getProjectId()); + parentModule.setId("root"); + parentModule.setLevel(0); + } else { + if (!parentModuleList.isEmpty() && parentModule == null) { + String parentId = parentModuleList.get(0).getParentId(); + ApiScenarioModuleDTO apiScenarioModuleDTO = idModuleMap.get(parentId); + parentModule = JSON.parseObject(JSON.toJSONString(apiScenarioModuleDTO), ApiScenarioModule.class); + } + } + return createModule(tagTree, i, parentModule, map, pidChildrenMap, idPathMap); + } else { + returnModule = collect.get(0); + parentModule = collect.get(0); + parentModuleList = pidChildrenMap.get(collect.get(0).getId()); + } + } + return returnModule; + } + + + private ApiScenarioModule createModule(String[] tagTree, int i, ApiScenarioModule parentModule, Map<String, ApiScenarioModule> map, Map<String, List<ApiScenarioModule>> pidChildrenMap, Map<String, String> idPathMap) { + + ApiScenarioModule returnModule = null; + for (int i1 = i; i1 < tagTree.length; i1++) { + String pathName = tagTree[i1]; + + //创建模块 + ApiScenarioModule newModule = this.getNewModule(pathName, parentModule.getProjectId(), parentModule.getLevel() + 1); + String parentId; + if (parentModule.getId().equals("root")) { + parentId = null; + } else { + parentId = parentModule.getId(); + } + double pos = this.getNextLevelPos(parentModule.getProjectId(), parentModule.getLevel() + 1, parentId); + newModule.setPos(pos); + newModule.setParentId(parentId); + List<ApiScenarioModule> moduleList = pidChildrenMap.get(parentModule.getId()); + if (moduleList != null) { + moduleList.add(newModule); + } else { + moduleList = new ArrayList<>(); + moduleList.add(newModule); + pidChildrenMap.put(parentModule.getId(), moduleList); + } + + String parentPath = idPathMap.get(parentModule.getId()); + String path; + if (StringUtils.isNotBlank(parentPath)) { + path = parentPath + "/" + pathName; + } else { + path = "/" + pathName; + } + idPathMap.put(newModule.getId(), path); + map.putIfAbsent(path, newModule); + parentModule = newModule; + returnModule = newModule; + } + return returnModule; + } + + private void buildProcessData(List<ApiScenarioModuleDTO> nodeTreeByProjectId, Map<String, List<ApiScenarioModule>> pidChildrenMap, Map<String, String> idPathMap, Map<String, String> parentModulePathMap) { + Map<String, List<ApiScenarioModuleDTO>> idChildrenMap = new HashMap<>(); + int i = 0; + Map<String, List<ApiScenarioModule>> idModuleMap = new HashMap<>(); + for (ApiScenarioModuleDTO scenarioModuleDTO : nodeTreeByProjectId) { + if (StringUtils.isBlank(scenarioModuleDTO.getParentId())) { + scenarioModuleDTO.setParentId("root"); + } + String parentModulePath = parentModulePathMap.get(scenarioModuleDTO.getParentId()); + if (parentModulePath != null) { + if (parentModulePath.equals("/root")) { + scenarioModuleDTO.setPath("/" + scenarioModuleDTO.getName()); + } else { + scenarioModuleDTO.setPath(parentModulePath + "/" + scenarioModuleDTO.getName()); + } + } else { + scenarioModuleDTO.setPath("/" + scenarioModuleDTO.getName()); + } + idPathMap.put(scenarioModuleDTO.getId(), scenarioModuleDTO.getPath()); + + ApiScenarioModule scenarioModule = buildModule(idModuleMap, scenarioModuleDTO); + if (pidChildrenMap.get(scenarioModuleDTO.getParentId()) != null) { + pidChildrenMap.get(scenarioModuleDTO.getParentId()).add(scenarioModule); + } else { + pidChildrenMap.put(scenarioModuleDTO.getParentId(), idModuleMap.get(scenarioModuleDTO.getId())); + } + i = i + 1; + List<ApiScenarioModuleDTO> childrenList = idChildrenMap.get(scenarioModuleDTO.getId()); + if (scenarioModuleDTO.getChildren() != null) { + if (childrenList != null) { + childrenList.addAll(scenarioModuleDTO.getChildren()); + } else { + idChildrenMap.put(scenarioModuleDTO.getId(), scenarioModuleDTO.getChildren()); + } + } else { + if (childrenList == null) { + pidChildrenMap.put(scenarioModuleDTO.getId(), new ArrayList<>()); + } + } + parentModulePathMap.put(scenarioModuleDTO.getId(), scenarioModuleDTO.getPath()); + } + if (i == nodeTreeByProjectId.size() && nodeTreeByProjectId.size() > 0) { + Collection<List<ApiScenarioModuleDTO>> values = idChildrenMap.values(); + List<ApiScenarioModuleDTO> childrenList = new ArrayList<>(); + for (List<ApiScenarioModuleDTO> value : values) { + childrenList.addAll(value); + } + buildProcessData(childrenList, pidChildrenMap, idPathMap, parentModulePathMap); + } + } + + private ApiScenarioModule buildModule(Map<String, List<ApiScenarioModule>> IdModuleMap, ApiScenarioModuleDTO scenarioModuleDTO) { + ApiScenarioModule scenarioModule = new ApiScenarioModule(); + scenarioModule.setId(scenarioModuleDTO.getId()); + scenarioModule.setName(scenarioModuleDTO.getName()); + scenarioModule.setParentId(scenarioModuleDTO.getParentId()); + scenarioModule.setProjectId(scenarioModuleDTO.getProjectId()); + scenarioModule.setLevel(scenarioModuleDTO.getLevel()); + List<ApiScenarioModule> moduleList = IdModuleMap.get(scenarioModuleDTO.getId()); + if (moduleList != null) { + moduleList.add(scenarioModule); + } else { + moduleList = new ArrayList<>(); + moduleList.add(scenarioModule); + IdModuleMap.put(scenarioModuleDTO.getId(), moduleList); + } + return scenarioModule; + } } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java index b088e3b601..395da1207f 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.java @@ -9,6 +9,7 @@ import io.metersphere.api.dto.scenario.Scenario; import io.metersphere.base.domain.ApiDefinition; import io.metersphere.base.domain.ApiDefinitionExample; import io.metersphere.base.domain.ApiDefinitionExampleWithOperation; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; import io.metersphere.controller.request.BaseQueryRequest; import io.metersphere.dto.RelationshipGraphData; import org.apache.ibatis.annotations.Param; @@ -64,13 +65,13 @@ public interface ExtApiDefinitionMapper { ApiDefinition selectUrlAndMethodById(String id); - int checkOriginalStatusByIds(@Param("ids")List<String> ids); + int checkOriginalStatusByIds(@Param("ids") List<String> ids); List<String> selectProjectIds(); List<String> getIdsOrderByUpdateTime(@Param("projectId") String projectId); - Long getPreOrder(@Param("projectId")String projectId, @Param("baseOrder") Long baseOrder); + Long getPreOrder(@Param("projectId") String projectId, @Param("baseOrder") Long baseOrder); Long getLastOrder(@Param("projectId") String projectId, @Param("baseOrder") Long baseOrder); @@ -89,4 +90,11 @@ public interface ExtApiDefinitionMapper { List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId); String selectNameById(String testId); + + List<ApiDefinitionWithBLOBs> selectRepeatByBLOBs(@Param("blobs") List<ApiDefinitionWithBLOBs> blobs, @Param("projectId") String projectId, @Param("versionIds") Set<String> versionIds); + + List<ApiDefinitionWithBLOBs> selectRepeatByBLOBsSameUrl(@Param("blobs") List<ApiDefinitionWithBLOBs> blobs, @Param("projectId") String projectId, @Param("moduleId") String moduleId, @Param("versionIds") Set<String> versionIds); + + List<ApiDefinitionWithBLOBs> selectRepeatByProtocol(@Param("names") List<String> names, @Param("protocol") String protocol, @Param("versionIds") Set<String> versionIds); + } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml index 17a4fe94eb..14a73ce78e 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiDefinitionMapper.xml @@ -81,15 +81,17 @@ </where> </sql> <sql id="Base_Column_List"> - id, project_id, name,module_id,module_path,protocol ,path,method ,description, status, user_id, create_time, update_time - </sql> + id + , project_id, name,module_id,module_path,protocol ,path,method ,description, status, user_id, create_time, update_time + </sql> <sql id="Blob_Column_List"> request </sql> <select id="selectByIds" resultType="io.metersphere.api.dto.definition.ApiComputeResult"> SELECT t1.api_definition_id apiDefinitionId,count(t1.id) caseTotal, - SUM(case when t2.status ='success' then 1 else 0 end) as success ,SUM(case when t2.status ='error' then 1 else 0 end) as error, + SUM(case when t2.status ='success' then 1 else 0 end) as success ,SUM(case when t2.status ='error' then 1 else 0 + end) as error, CONCAT(FORMAT(SUM(IF (t2.`status`='success',1,0))/COUNT(t1.id)*100,2),'%') passRate FROM api_test_case t1 LEFT JOIN api_definition_exec_result t2 ON t1.last_result_id=t2.id @@ -102,7 +104,8 @@ <select id="selectByIdsAndStatusIsNotTrash" resultType="io.metersphere.api.dto.definition.ApiComputeResult"> SELECT t1.api_definition_id apiDefinitionId,count(t1.id) caseTotal, - SUM(case when t2.status ='success' then 1 else 0 end) as success ,SUM(case when t2.status ='error' then 1 else 0 end) as error, + SUM(case when t2.status ='success' then 1 else 0 end) as success ,SUM(case when t2.status ='error' then 1 else 0 + end) as error, CONCAT(FORMAT(SUM(IF (t2.`status`='success',1,0))/COUNT(t1.id)*100,2),'%') passRate FROM api_test_case t1 LEFT JOIN api_definition_exec_result t2 ON t1.last_result_id=t2.id @@ -193,7 +196,18 @@ <property name="object" value="${condition}.tags"/> </include> </if> - + <if test="${condition}.module != null"> + and api_definition.module_path + <include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition"> + <property name="object" value="${condition}.module"/> + </include> + </if> + <if test="${condition}.caseCount != null"> + and api_definition.case_total + <include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.condition"> + <property name="object" value="${condition}.caseCount"/> + </include> + </if> </sql> @@ -242,10 +256,13 @@ </sql> <select id="list" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult"> - select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.original_state, + select api_definition.id, api_definition.project_id, api_definition.num, + api_definition.tags,api_definition.original_state, api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method, api_definition.description,api_definition.request,api_definition.response,api_definition.environment_id, - api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, api_definition.delete_user_id, api_definition.create_user,api_definition.delete_time, api_definition.remark, api_definition.version_id, + api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, + api_definition.delete_user_id, api_definition.create_user,api_definition.delete_time, api_definition.remark, + api_definition.version_id, project_version.name as version_name, api_definition.ref_id, user.name as user_name from api_definition left join user on api_definition.user_id = user.id @@ -268,12 +285,16 @@ </select> <select id="weekList" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult"> - select api_definition.id, api_definition.project_id, api_definition.num, api_definition.tags,api_definition.original_state, + select api_definition.id, api_definition.project_id, api_definition.num, + api_definition.tags,api_definition.original_state, api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method, api_definition.description,api_definition.environment_id, - api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, project.name as - project_name, user.name as user_name,deleteUser.name AS delete_user,api_definition.delete_time, api_definition.remark - from (select * from api_definition where update_time >= #{startTimestamp} order by update_time desc)api_definition + api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time, + project.name as + project_name, user.name as user_name,deleteUser.name AS delete_user,api_definition.delete_time, + api_definition.remark + from (select * from api_definition where update_time >= #{startTimestamp} order by update_time + desc)api_definition left join project on api_definition.project_id = project.id left join user on api_definition.user_id = user.id left join user deleteUser on api_definition.delete_user_id = deleteUser.id @@ -303,7 +324,8 @@ from api_definition left join project on api_definition.project_id = project.id left join user on api_definition.user_id = user.id - left join project_version on api_definition.project_id = project_version.project_id and api_definition.version_id = project_version.id + left join project_version on api_definition.project_id = project_version.project_id and + api_definition.version_id = project_version.id WHERE api_definition.id IN <foreach collection="ids" item="v" separator="," open="(" close=")"> #{v} @@ -347,33 +369,48 @@ </update> <select id="countProtocolByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult"> - SELECT protocol AS groupField,count(DISTINCT ref_id) AS countNumber + SELECT protocol AS groupField, count(DISTINCT ref_id) AS countNumber FROM api_definition WHERE project_id = #{0} - AND `status` != 'Trash' + AND `status` != 'Trash' AND latest = 1 GROUP BY protocol </select> <select id="countStateByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult"> - SELECT status AS groupField,count(id) AS countNumber FROM api_definition WHERE project_id = #{0} AND `status` != 'Trash' AND latest = 1 GROUP BY status + SELECT status AS groupField, count(id) AS countNumber + FROM api_definition + WHERE project_id = #{0} + AND `status` != 'Trash' AND latest = 1 + GROUP BY status </select> <select id="countByProjectIDAndCreateInThisWeek" resultType="java.lang.Long"> - SELECT count(id) AS countNumber FROM api_definition + SELECT count(id) AS countNumber + FROM api_definition WHERE project_id = #{projectId} - AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} AND `status` != 'Trash' AND latest = 1 + AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} + AND `status` != 'Trash' AND latest = 1 </select> <select id="countApiCoverageByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult"> - SELECT count(api.id) AS countNumber, if(test_case_api.api_definition_id is null,"uncoverage","coverage") AS groupField FROM api_definition api left Join ( + SELECT count(api.id) AS countNumber, + if(test_case_api.api_definition_id is null, "uncoverage", "coverage") AS groupField + FROM api_definition api + left Join ( SELECT DISTINCT api_definition_id FROM api_test_case WHERE status is null or status != 'Trash' ) test_case_api ON api.id = test_case_api.api_definition_id - WHERE api.project_id = #{0} and api.`status` != 'Trash' and api.latest = 1 + WHERE api.project_id = #{0} + and api.`status` != 'Trash' and api.latest = 1 GROUP BY groupField </select> <select id="getNextNum" resultType="io.metersphere.base.domain.ApiDefinition"> - SELECT * FROM api_definition WHERE api_definition.project_id = #{projectId} ORDER BY num DESC LIMIT 1; + SELECT * + FROM api_definition + WHERE api_definition.project_id = #{projectId} + ORDER BY num DESC LIMIT 1; </select> <select id="selectUrlAndMethodById" resultType="io.metersphere.base.domain.ApiDefinition"> - SELECT method,path FROM api_definition WHERE id = #{0} + SELECT method, path + FROM api_definition + WHERE id = #{0} </select> <select id="listRelevance" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult"> select @@ -405,7 +442,8 @@ api_definition.`order`, api_definition.ref_id from api_definition - left join project_version on api_definition.project_id = project_version.project_id and api_definition.version_id = project_version.id + left join project_version on api_definition.project_id = project_version.project_id and + api_definition.version_id = project_version.id <where> <if test="request.combine != null"> <include refid="combine"> @@ -600,9 +638,10 @@ </select> <select id="selectEffectiveIdByProjectId" resultType="io.metersphere.base.domain.ApiDefinition"> - select id,path,method + select id, path, method from api_definition - WHERE project_id = #{0} AND status != 'Trash' AND protocol = 'HTTP' AND latest = 1 + WHERE project_id = #{0} + AND status != 'Trash' AND protocol = 'HTTP' AND latest = 1 </select> <select id="moduleCount" resultType="java.lang.Integer"> @@ -801,10 +840,14 @@ </sql> <select id="selectProjectIds" resultType="java.lang.String"> - select DISTINCT project_id from api_definition; + select DISTINCT project_id + from api_definition; </select> <select id="getIdsOrderByUpdateTime" resultType="java.lang.String"> - select id from api_definition where project_id = #{projectId} order by update_time ASC; + select id + from api_definition + where project_id = #{projectId} + order by update_time ASC; </select> <select id="getLastOrder" resultType="java.lang.Long"> @@ -824,8 +867,10 @@ </select> <select id="countQuotedApiByProjectId" resultType="java.lang.Long"> - SELECT COUNT(id) FROM api_definition - WHERE project_id = #{0} AND `status` != 'Trash' + SELECT COUNT(id) + FROM api_definition + WHERE project_id = #{0} + AND `status` != 'Trash' AND ( id IN ( SELECT reference_id FROM api_scenario_reference_id WHERE api_scenario_id in ( @@ -866,7 +911,8 @@ and api_definition.status != 'Trash'; </select> - <select id="countByExample" parameterType="io.metersphere.base.domain.ApiDefinitionExample" resultType="java.lang.Long"> + <select id="countByExample" parameterType="io.metersphere.base.domain.ApiDefinitionExample" + resultType="java.lang.Long"> select count(DISTINCT ref_id) from api_definition <if test="_parameter != null"> <include refid="io.metersphere.base.mapper.ApiDefinitionMapper.Example_Where_Clause"/> @@ -888,44 +934,41 @@ <update id="clearLatestVersion"> UPDATE api_definition SET latest = 0 - <where> - <if test="refId != null"> - and ref_id = #{refId} - </if> - </where> + where ref_id = #{refId} </update> <update id="addLatestVersion"> UPDATE api_definition - INNER JOIN (( - SELECT tmp.id - FROM api_definition tmp - JOIN project_version - ON tmp.project_id = project_version.project_id AND - tmp.version_id = project_version.id AND project_version.latest = TRUE - WHERE ref_id = #{refId,jdbcType=VARCHAR} - LIMIT 1 - ) - UNION ALL - ( - SELECT tmp.id - FROM api_definition tmp - JOIN project_version - ON tmp.project_id = project_version.project_id AND - tmp.version_id = project_version.id - AND NOT EXISTS(SELECT ref_id - FROM api_definition tmp2 - JOIN project_version - ON tmp2.project_id = - project_version.project_id AND - version_id = - project_version.id AND - project_version.latest = TRUE - WHERE tmp.ref_id = tmp2.ref_id) - WHERE tmp.ref_id = #{refId,jdbcType=VARCHAR} - ORDER BY tmp.update_time DESC - LIMIT 1)) AS t ON api_definition.id = t.id - SET api_definition.latest = TRUE + INNER JOIN (( + SELECT tmp.id + FROM api_definition tmp + JOIN project_version + ON tmp.project_id = project_version.project_id AND + tmp.version_id = project_version.id AND project_version.latest = TRUE + WHERE ref_id = #{refId,jdbcType=VARCHAR} + LIMIT 1 + ) + UNION ALL + ( + SELECT tmp.id + FROM api_definition tmp + JOIN project_version + ON tmp.project_id = project_version.project_id AND + tmp.version_id = project_version.id + AND NOT EXISTS (SELECT ref_id + FROM api_definition tmp2 + JOIN project_version + ON tmp2.project_id = + project_version.project_id AND + version_id = + project_version.id AND + project_version.latest = TRUE + WHERE tmp.ref_id = tmp2.ref_id) + WHERE tmp.ref_id = #{refId,jdbcType=VARCHAR} + ORDER BY tmp.update_time DESC + LIMIT 1)) AS t + ON api_definition.id = t.id + SET api_definition.latest = TRUE WHERE ref_id = #{refId,jdbcType=VARCHAR} </update> @@ -933,13 +976,70 @@ SELECT DISTINCT ref_id FROM api_definition WHERE ref_id NOT IN ( - SELECT DISTINCT ref_id - FROM api_definition - WHERE version_id = #{versionId} AND project_id = #{projectId} - ) AND project_id = #{projectId} + SELECT DISTINCT ref_id + FROM api_definition + WHERE version_id = #{versionId} + AND project_id = #{projectId} + ) + AND project_id = #{projectId} </select> <select id="selectNameById" resultType="java.lang.String"> - SELECT name FROM api_definition WHERE id = #{0} + SELECT name + FROM api_definition + WHERE id = #{0} </select> + + <select id="selectRepeatByBLOBs" resultType="io.metersphere.base.domain.ApiDefinitionWithBLOBs"> + SELECT * from api_definition + <include refid="Same_Where_Clause"/> + and status != 'Trash' + and project_id = #{projectId} + and version_id in + <foreach collection="versionIds" item="versionId" separator="," open="(" close=")"> + #{versionId} + </foreach> + </select> + <select id="selectRepeatByBLOBsSameUrl" resultType="io.metersphere.base.domain.ApiDefinitionWithBLOBs"> + SELECT * from api_definition + <include refid="Same_Where_Clause"/> + and status != 'TRASH' + and project_id = #{projectId} + and module_id = #{moduleId} + and version_id in + <foreach collection="versionIds" item="versionId" separator="," open="(" close=")"> + #{versionId} + </foreach> + </select> + <select id="selectRepeatByProtocol" resultType="io.metersphere.base.domain.ApiDefinitionWithBLOBs"> + SELECT * from api_definition + where name in + <foreach collection="names" item="name" separator="," open="(" close=")"> + #{name} + </foreach> + and version_id in + <foreach collection="versionIds" item="versionId" separator="," open="(" close=")"> + #{versionId} + </foreach> + and protocol = #{protocol} + </select> + <sql id="Same_Where_Clause"> + <where> + <if test="blobs"> + <trim prefix="(" prefixOverrides="and" suffix=")"> + <foreach collection="blobs" item="blob" separator="or"> + <trim prefix="(" prefixOverrides="and" suffix=")"> + <if test="blob.method"> + and api_definition.method = #{blob.method} + </if> + <if test="blob.path"> + and api_definition.path = #{blob.path} + </if> + </trim> + </foreach> + </trim> + </if> + </where> + </sql> + </mapper> diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java index 568e9010a9..66d880ca87 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java @@ -90,4 +90,10 @@ public interface ExtApiScenarioMapper { List<String> selectRefIdsForVersionChange(@Param("versionId") String versionId, @Param("projectId") String projectId); List<ApiScenarioWithBLOBs> selectByStatusIsNotTrash(); + + List<ApiScenarioWithBLOBs> selectRepeatByBLOBs(@Param("blobs") List<ApiScenarioWithBLOBs> blobs, @Param("projectId") String projectId, @Param("versionIds") Set<String> versionIds); + + List<ApiScenarioWithBLOBs> selectRepeatByBLOBsSameUrl(@Param("blobs") List<ApiScenarioWithBLOBs> blobs, @Param("projectId") String projectId, @Param("moduleId") String moduleId, @Param("versionIds") Set<String> versionIds); + + } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index 0ffcdd12b6..5df55a31a4 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -754,4 +754,46 @@ FROM api_scenario WHERE `status` != 'Trash' AND project_id IN (SELECT id FROM project); </select> + <select id="selectRepeatByBLOBs" resultType="io.metersphere.base.domain.ApiScenarioWithBLOBs"> + SELECT * from api_scenario + <include refid="Same_Where_Clause"/> + and status != 'Trash' + and project_id = #{projectId} + and version_id in + <foreach collection="versionIds" item="versionId" separator="," open="(" close=")"> + #{versionId} + </foreach> + </select> + + <select id="selectRepeatByBLOBsSameUrl" resultType="io.metersphere.base.domain.ApiScenarioWithBLOBs"> + SELECT * from api_scenario + <include refid="Same_Where_Clause"/> + and status != 'TRASH' + and api_scenario_module_id = #{moduleId} + and project_id = #{projectId} + and version_id in + <foreach collection="versionIds" item="versionId" separator="," open="(" close=")"> + #{versionId} + </foreach> + </select> + + <sql id="Same_Where_Clause"> + <where> + <if test="blobs"> + <trim prefix="(" prefixOverrides="and" suffix=")"> + <foreach collection="blobs" item="blob" separator="or"> + <trim prefix="(" prefixOverrides="and" suffix=")"> + <if test="blob.name"> + and api_scenario.name = #{blob.name} + </if> + </trim> + + </foreach> + </trim> + </if> + + </where> + </sql> + </mapper> + diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml index 6d52431ea6..ced38fd300 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml @@ -103,9 +103,10 @@ parameterType="io.metersphere.performance.request.QueryTestPlanRequest"> SELECT load_test.*, project.name AS project_name, user.name AS user_name, project_version.name as version_name FROM load_test - LEFT JOIN project ON load_test.project_id = project.id - LEFT JOIN user ON load_test.user_id = user.id - LEFT JOIN project_version on project.id = project_version.project_id AND project_version.id = load_test.version_id + LEFT JOIN project ON load_test.project_id = project.id + LEFT JOIN user ON load_test.user_id = user.id + LEFT JOIN project_version on project.id = project_version.project_id AND project_version.id = + load_test.version_id <where> <if test="request.combine != null"> <include refid="combine"> @@ -191,7 +192,7 @@ <select id="checkLoadTestOwner" resultType="int"> SELECT COUNT(1) FROM load_test - LEFT JOIN project ON load_test.project_id = project.id + LEFT JOIN project ON load_test.project_id = project.id <where> <if test="testId != null"> and load_test.id = #{testId} @@ -205,7 +206,10 @@ </where> </select> <select id="getNextNum" resultType="io.metersphere.base.domain.LoadTest"> - select * from load_test lt where lt.project_id = #{projectId} ORDER BY num DESC LIMIT 1; + select * + from load_test lt + where lt.project_id = #{projectId} + ORDER BY num DESC LIMIT 1; </select> <select id="moduleCount" resultType="java.lang.Integer"> @@ -271,7 +275,7 @@ </foreach> </if> </sql> - + <sql id="queryWhereCondition"> <where> <if test="request.combine != null"> @@ -316,7 +320,6 @@ </sql> - <select id="getProjectFiles" resultType="io.metersphere.base.domain.FileMetadata"> SELECT file_metadata.* FROM file_metadata @@ -332,10 +335,14 @@ </select> <select id="selectProjectIds" resultType="java.lang.String"> - select DISTINCT project_id from load_test; + select DISTINCT project_id + from load_test; </select> <select id="getIdsOrderByUpdateTime" resultType="java.lang.String"> - select id from load_test where project_id = #{projectId} order by update_time ASC; + select id + from load_test + where project_id = #{projectId} + order by update_time ASC; </select> <select id="getLastOrder" resultType="java.lang.Long"> @@ -368,62 +375,61 @@ <update id="addLatestVersion"> UPDATE load_test - INNER JOIN (( - SELECT tmp.id - FROM load_test tmp - JOIN project_version - ON tmp.project_id = project_version.project_id AND - tmp.version_id = project_version.id AND project_version.latest = TRUE - WHERE ref_id = #{refId,jdbcType=VARCHAR} - LIMIT 1 - ) - UNION ALL - ( - SELECT tmp.id - FROM load_test tmp - JOIN project_version - ON tmp.project_id = project_version.project_id AND - tmp.version_id = project_version.id - AND NOT EXISTS(SELECT ref_id - FROM load_test tmp2 - JOIN project_version - ON tmp2.project_id = - project_version.project_id AND - version_id = - project_version.id AND - project_version.latest = TRUE - WHERE tmp.ref_id = tmp2.ref_id) - WHERE tmp.ref_id = #{refId,jdbcType=VARCHAR} - ORDER BY tmp.update_time DESC - LIMIT 1)) AS t ON load_test.id = t.id - SET load_test.latest = TRUE + INNER JOIN (( + SELECT tmp.id + FROM load_test tmp + JOIN project_version + ON tmp.project_id = project_version.project_id AND + tmp.version_id = project_version.id AND project_version.latest = TRUE + WHERE ref_id = #{refId,jdbcType=VARCHAR} + LIMIT 1 + ) + UNION ALL + ( + SELECT tmp.id + FROM load_test tmp + JOIN project_version + ON tmp.project_id = project_version.project_id AND + tmp.version_id = project_version.id + AND NOT EXISTS (SELECT ref_id + FROM load_test tmp2 + JOIN project_version + ON tmp2.project_id = + project_version.project_id AND + version_id = + project_version.id AND + project_version.latest = TRUE + WHERE tmp.ref_id = tmp2.ref_id) + WHERE tmp.ref_id = #{refId,jdbcType=VARCHAR} + ORDER BY tmp.update_time DESC + LIMIT 1)) AS t + ON load_test.id = t.id + SET load_test.latest = TRUE WHERE ref_id = #{refId,jdbcType=VARCHAR} </update> <update id="clearLatestVersion"> UPDATE load_test SET latest = 0 - <where> - <if test="refId != null"> - and ref_id = #{refId} - </if> - </where> + where ref_id = #{refId} </update> <select id="selectRefIdsForVersionChange" resultType="java.lang.String"> SELECT DISTINCT ref_id FROM load_test WHERE ref_id NOT IN ( - SELECT DISTINCT ref_id - FROM load_test - WHERE version_id = #{versionId} AND project_id = #{projectId} - ) AND project_id = #{projectId} + SELECT DISTINCT ref_id + FROM load_test + WHERE version_id = #{versionId} + AND project_id = #{projectId} + ) + AND project_id = #{projectId} </select> <select id="getFileMetadataByIds" resultType="io.metersphere.base.domain.FileMetadata"> SELECT file_metadata.* FROM load_test_file - JOIN file_metadata ON file_id = file_metadata.id + JOIN file_metadata ON file_id = file_metadata.id WHERE test_id = #{testId} ORDER BY sort </select> diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtSwaggerUrlScheduleMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtSwaggerUrlScheduleMapper.xml index e803a7256b..60b6707435 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtSwaggerUrlScheduleMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtSwaggerUrlScheduleMapper.xml @@ -12,7 +12,7 @@ sup.config, sch.value as rule, sch.enable, - sch.id as taskId + sch.id as taskId FROM swagger_url_project sup INNER JOIN schedule sch ON sup.id = sch.resource_id WHERE sup.project_id = #{projectId} diff --git a/frontend/src/business/components/api/definition/components/import/ApiImport.vue b/frontend/src/business/components/api/definition/components/import/ApiImport.vue index 7f7914c083..77ca545ae0 100644 --- a/frontend/src/business/components/api/definition/components/import/ApiImport.vue +++ b/frontend/src/business/components/api/definition/components/import/ApiImport.vue @@ -438,11 +438,6 @@ export default { param.saved = this.saved; param.model = this.model; if (this.currentModule) { - if (!this.formData.moduleId || this.formData.moduleId.length === 0) { - param.moduleId = this.currentModule[0].id; - } else { - param.moduleId = this.formData.moduleId - } param.modeId = this.formData.modeId } param.projectId = this.projectId; @@ -572,5 +567,4 @@ export default { height: 200px; } - </style>