fix: 接口模块名带有/导出导入异常

This commit is contained in:
chenjianxing 2021-07-20 20:55:56 +08:00 committed by jianxing
parent 326152f53e
commit 47558a6438
17 changed files with 277 additions and 81 deletions

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto.automation.parse;
import io.metersphere.api.dto.automation.ApiScenarioModuleDTO;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.service.ApiScenarioModuleService;
import io.metersphere.base.domain.ApiScenarioModule;
import io.metersphere.commons.utils.BeanUtils;
@ -8,6 +9,7 @@ import io.metersphere.commons.utils.CommonBeanFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Iterator;
import java.util.List;
public class ApiScenarioImportUtil {
@ -61,4 +63,47 @@ public class ApiScenarioImportUtil {
module.setId(apiModules.get(0).getId());
}
}
private static void createNodeTree(NodeTree nodeTree, String pid, String projectId,
ApiScenarioModuleService apiModuleService, String path, int baseLevel) {
ApiScenarioModule module = new ApiScenarioModule();
BeanUtils.copyBean(module, nodeTree);
apiModuleService.buildNewModule(module);
module.setProjectId(projectId);
module.setParentId(pid);
module.setLevel(module.getLevel() + baseLevel);
createModule(module);
nodeTree.setNewId(module.getId());
path = path + nodeTree.getName();
nodeTree.setPath(path);
List<NodeTree> children = nodeTree.getChildren();
if (CollectionUtils.isNotEmpty(children)) {
String finalPath = path;
children.forEach(item -> {
createNodeTree(item, module.getId(), projectId, apiModuleService, finalPath + "/", baseLevel);
});
}
}
/**
* 根据导出的模块树创建新的模块树
* @param nodeTree
* @param projectId
*/
public static void createNodeTree(List<NodeTree> nodeTree, String projectId, String moduleId) {
ApiScenarioModuleService apiModuleService = CommonBeanFactory.getBean(ApiScenarioModuleService.class);
Iterator<NodeTree> iterator = nodeTree.iterator();
boolean hasModuleSelected = false;
ApiScenarioModuleDTO selectModule = null;
if (StringUtils.isNotBlank(moduleId) && !"root".equals(moduleId)) {
selectModule = apiModuleService.getNode(moduleId);
hasModuleSelected = true;
}
while (iterator.hasNext()) {
NodeTree node = iterator.next();
createNodeTree(node, hasModuleSelected ? selectModule.getId() : null,
projectId, apiModuleService, "/", hasModuleSelected ? selectModule.getLevel() : 0);
}
}
}

View File

@ -5,6 +5,7 @@ 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.parse.ms.NodeTree;
import io.metersphere.api.dto.definition.request.MsScenario;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.parse.MsAbstractParser;
@ -19,6 +20,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
@ -64,9 +66,22 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
}
private ScenarioImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ScenarioImport apiDefinitionImport = JSON.parseObject(testStr, ScenarioImport.class);
List<ApiScenarioWithBLOBs> data = apiDefinitionImport.getData();
ScenarioImport scenarioImport = JSON.parseObject(testStr, ScenarioImport.class);
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)) {
@ -81,15 +96,24 @@ public class MsScenarioParser extends MsAbstractParser<ScenarioImport> {
item.setScenarioDefinition(JSONObject.toJSONString(scenarioDefinition));
}
}
if (StringUtils.isBlank(item.getModulePath())) {
item.setApiScenarioModuleId(null);
if (finalNodeMap != 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);
}
parseModule(item.getModulePath(), importRequest, item);
item.setId(UUID.randomUUID().toString());
item.setProjectId(this.projectId);
});
}
return apiDefinitionImport;
return scenarioImport;
}
private void setCopy(JSONArray hashTree) {

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.automation.parse;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import lombok.Data;
@ -9,4 +10,5 @@ import java.util.List;
public class ScenarioImport {
private String projectId;
private List<ApiScenarioWithBLOBs> data;
private List<NodeTree> nodeTree;
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.base.domain.ApiDefinitionWithBLOBs;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.EsbApiParamsWithBLOBs;
@ -19,4 +20,6 @@ public class ApiDefinitionImport {
//ESB文件导入的附属数据类
private Map<String,EsbApiParamsWithBLOBs> esbApiParamsMap;
private List<NodeTree> nodeTree;
}

View File

@ -1,14 +1,17 @@
package io.metersphere.api.dto.definition.parse;
import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.service.ApiModuleService;
import io.metersphere.base.domain.ApiModule;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.SessionUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Iterator;
import java.util.List;
public class ApiDefinitionImportUtil {
@ -65,6 +68,48 @@ public class ApiDefinitionImportUtil {
return module;
}
private static void createNodeTree(NodeTree nodeTree, String pid, String projectId,
ApiModuleService apiModuleService, String path, int baseLevel) {
ApiModule module = new ApiModule();
BeanUtils.copyBean(module, nodeTree);
apiModuleService.buildNewModule(module);
module.setProjectId(projectId);
module.setParentId(pid);
module.setLevel(module.getLevel() + baseLevel);
createModule(module, SessionUtils.getUserId());
nodeTree.setNewId(module.getId());
path = path + nodeTree.getName();
nodeTree.setPath(path);
List<NodeTree> children = nodeTree.getChildren();
if (CollectionUtils.isNotEmpty(children)) {
String finalPath = path;
children.forEach(item -> {
createNodeTree(item, module.getId(), projectId, apiModuleService, finalPath + "/", baseLevel);
});
}
}
/**
* 根据导出的模块树创建新的模块树
* @param nodeTree
* @param projectId
*/
public static void createNodeTree(List<NodeTree> nodeTree, String projectId, String moduleId) {
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
Iterator<NodeTree> iterator = nodeTree.iterator();
boolean hasModuleSelected = false;
ApiModuleDTO selectModule = null;
if (StringUtils.isNotBlank(moduleId) && !"root".equals(moduleId)) {
selectModule = apiModuleService.getNode(moduleId);
hasModuleSelected = true;
}
while (iterator.hasNext()) {
NodeTree node = iterator.next();
createNodeTree(node, hasModuleSelected ? selectModule.getId() : null,
projectId, apiModuleService, "/", hasModuleSelected ? selectModule.getLevel() : 0);
}
}
public static ApiModule buildModule(ApiModule parentModule, String name, String projectId, String userId) {
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
ApiModule module;

View File

@ -4,6 +4,7 @@ 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.MsAbstractParser;
@ -16,6 +17,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
@ -68,6 +70,7 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
Map<String, List<ApiTestCaseWithBLOBs>> caseMap = new HashMap<>();
if (apiDefinitionImport.getCases() != null) {
apiDefinitionImport.getCases().forEach(item -> {
@ -79,19 +82,42 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
caseList.add(item);
});
}
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);
parseApiDefinition(apiDefinition, importRequest, caseMap, finalNodeMap);
});
return apiDefinitionImport;
}
private void parseApiDefinition(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest, Map<String, List<ApiTestCaseWithBLOBs>> caseMap) {
private void parseApiDefinition(ApiDefinitionWithBLOBs apiDefinition, ApiTestImportRequest importRequest,
Map<String, List<ApiTestCaseWithBLOBs>> caseMap, Map<String, NodeTree> nodeMap) {
String originId = apiDefinition.getId();
String id = UUID.randomUUID().toString();
if (StringUtils.isBlank(apiDefinition.getModulePath())) {
apiDefinition.setModuleId(null);
if (nodeMap != 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);
}
parseModule(apiDefinition.getModulePath(), importRequest, apiDefinition);
apiDefinition.setId(id);
apiDefinition.setProjectId(this.projectId);
String request = apiDefinition.getRequest();

View File

@ -0,0 +1,34 @@
package io.metersphere.api.dto.definition.parse.ms;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public class NodeTree {
private String id;
private String newId;
private String projectId;
private String name;
private String parentId;
private Integer level;
private Long createTime;
private Long updateTime;
private Double pos;
private Integer caseNum;
private List<NodeTree> children;
private String path;
}

View File

@ -2,6 +2,7 @@ package io.metersphere.api.parse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.definition.parse.ms.NodeTree;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.Body;
import io.metersphere.api.dto.scenario.KeyValue;
@ -11,8 +12,7 @@ import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public abstract class MsAbstractParser<T> extends ApiImportAbstractParser<T> {
@ -96,4 +96,63 @@ public abstract class MsAbstractParser<T> extends ApiImportAbstractParser<T> {
}
}
}
/**
* 删除没有用例的节点
* @param nodeTree
* @param ids
* @return
*/
public void cutDownTree(List<NodeTree> nodeTree, Set<String> ids) {
Iterator<NodeTree> iterator = nodeTree.iterator();
while (iterator.hasNext()) {
NodeTree item = iterator.next();
if (cutDownTree(item, ids)) {
iterator.remove();
}
}
}
private boolean cutDownTree(NodeTree nodeTree, Set<String> ids) {
boolean delete = true;
if (ids.contains(nodeTree.getId())) {
delete = false;
}
List<NodeTree> children = nodeTree.getChildren();
if (CollectionUtils.isNotEmpty(children)) {
Iterator<NodeTree> iterator = children.iterator();
while (iterator.hasNext()) {
NodeTree item = iterator.next();
if (cutDownTree(item, ids)) {
iterator.remove();
} else {
delete = false;
}
}
}
return delete;
}
public Map<String, NodeTree> getNodeMap(List<NodeTree> nodeTree) {
Map<String, NodeTree> nodeMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(nodeTree)) {
nodeTree.forEach(item -> {
getNodeMap(nodeMap, item);
});
}
return nodeMap;
}
private void getNodeMap(Map<String, NodeTree> nodeMap, NodeTree nodeTree) {
nodeMap.put(nodeTree.getId(), nodeTree);
List<NodeTree> children = nodeTree.getChildren();
if (CollectionUtils.isNotEmpty(children)) {
children.forEach(item -> {
getNodeMap(nodeMap, item);
});
}
}
}

View File

@ -246,15 +246,20 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
public ApiModule getNewModule(String name, String projectId, int level) {
ApiModule node = new ApiModule();
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
node.setId(UUID.randomUUID().toString());
buildNewModule(node);
node.setLevel(level);
node.setName(name);
node.setProjectId(projectId);
return node;
}
public ApiModule buildNewModule(ApiModule node) {
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
node.setId(UUID.randomUUID().toString());
return node;
}
private void validateNode(ApiModule node) {
if (node.getLevel() > TestCaseConstants.MAX_NODE_DEPTH) {
throw new RuntimeException(Translator.get("test_case_node_level_tip")

View File

@ -313,15 +313,19 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
public ApiScenarioModule getNewModule(String name, String projectId, int level) {
ApiScenarioModule node = new ApiScenarioModule();
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
node.setId(UUID.randomUUID().toString());
buildNewModule(node);
node.setLevel(level);
node.setName(name);
node.setProjectId(projectId);
return node;
}
public void buildNewModule(ApiScenarioModule node) {
node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis());
node.setId(UUID.randomUUID().toString());
}
public List<ApiScenarioModule> selectSameModule(ApiScenarioModule node) {
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
ApiScenarioModuleExample.Criteria criteria = example.createCriteria();

View File

@ -90,7 +90,6 @@ public class TapdPlatform extends AbstractIssuePlatform {
List<CustomFieldItemDTO> customFields = getCustomFields(issuesRequest.getCustomFields());
String url = "https://api.tapd.cn/bugs";
String tapdId = getProjectId(issuesRequest.getProjectId());
if (StringUtils.isBlank(tapdId)) {

View File

@ -184,8 +184,8 @@ export default {
},
methods: {
hasPermission,
exportAPI() {
this.$refs.apiScenarioList.exportApi();
exportAPI(nodeTree) {
this.$refs.apiScenarioList.exportApi(nodeTree);
},
exportJmx() {
this.$refs.apiScenarioList.exportJmx();

View File

@ -896,7 +896,7 @@ export default {
openScenario(item) {
this.$emit('openScenario', item);
},
exportApi() {
exportApi(nodeTree) {
let param = {};
this.projectId = getCurrentProjectID();
this.$get('project/get/' + this.projectId, response => {
@ -912,7 +912,7 @@ export default {
this.result = this.$post("/api/automation/export", param, response => {
this.result.loading = false;
let obj = response.data;
this.buildApiPath(obj.data);
obj.nodeTree = nodeTree;
downloadFile("Metersphere_Scenario_" + this.projectName + ".json", JSON.stringify(obj));
});
}
@ -936,15 +936,6 @@ export default {
}
});
},
buildApiPath(scenarios) {
scenarios.forEach((scenario) => {
this.moduleOptions.forEach(item => {
if (scenario.moduleId === item.id) {
scenario.modulePath = item.path;
}
});
});
},
getConditions() {
return this.condition;
},

View File

@ -119,7 +119,7 @@
label: this.$t('report.export_to_ms_format'),
permissions: ['PROJECT_API_SCENARIO:READ+EXPORT_SCENARIO'],
callback: () => {
this.$emit('exportAPI');
this.exportAPI();
}
},
{
@ -152,30 +152,6 @@
}
},
methods: {
handleCommand(e) {
switch (e) {
case "add-scenario":
this.addScenario();
break;
case "import":
this.result = this.$get("/api/automation/module/list/" + this.projectId, response => {
if (response.data != undefined && response.data != null) {
this.data = response.data;
this.data.forEach(node => {
buildTree(node, {path: ''});
});
}
});
this.$refs.apiImport.open(this.currentModule);
break;
case "export":
this.$emit('exportAPI');
break;
case "exportJmx":
this.$emit('exportJmx');
break;
}
},
handleImport() {
if (this.projectId) {
this.result = this.$get("/api/automation/module/list/" + this.projectId, response => {
@ -264,7 +240,7 @@
}
},
exportAPI() {
this.$emit('exportAPI');
this.$emit('exportAPI', this.data);
},
// debug() {
// this.$emit('debug');

View File

@ -530,12 +530,12 @@ export default {
apiCaseClose() {
this.showCasePage = true;
},
exportAPI(type) {
exportAPI(type, nodeTree) {
if (this.activeDom !== 'left') {
this.$warning('用例列表暂不支持导出,请切换成接口列表');
return;
}
this.$refs.apiDefList[0].exportApi(type);
this.$refs.apiDefList[0].exportApi(type, nodeTree);
},
refreshModule() {
this.$refs.nodeTree.list();

View File

@ -788,7 +788,7 @@ export default {
let ids = rowArray.map(s => s.id);
return ids;
},
exportApi(type) {
exportApi(type, nodeTree) {
let param = buildBatchParam(this, this.$refs.table.selectIds);
param.protocol = this.currentProtocol;
if (param.ids === undefined || param.ids.length < 1) {
@ -799,30 +799,13 @@ export default {
let obj = response.data;
if (type == 'MS') {
obj.protocol = this.currentProtocol;
this.buildApiPath(obj.data);
obj.nodeTree = nodeTree;
downloadFile("Metersphere_Api_" + this.projectName + ".json", JSON.stringify(obj));
} else {
downloadFile("Swagger_Api_" + this.projectName+ ".json", JSON.stringify(obj));
}
});
},
buildApiPath(apis) {
try {
let options = [];
this.moduleOptions.forEach(item => {
buildNodePath(item, {path: ''}, options);
});
apis.forEach((api) => {
options.forEach((item) => {
if (api.moduleId === item.id) {
api.modulePath = item.path;
}
});
});
} catch (e) {
console.log(e);
}
},
headerDragend(newWidth, oldWidth, column, event) {
let finalWidth = newWidth;
if (column.minWidth > finalWidth) {

View File

@ -221,7 +221,7 @@
}
},
exportAPI(type) {
this.$emit('exportAPI', type);
this.$emit('exportAPI', type, this.data);
},
debug() {
this.$emit('debug');