From 935bcbfafe3624d14177a1d1bb3dd089d3fc66d6 Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Thu, 4 Feb 2021 14:48:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E5=AE=9A=E4=B9=89):=20?= =?UTF-8?q?=E5=AF=BC=E5=85=A5Jmeter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/automation/parse/MsJmeterParser.java | 388 +++++++++--------- .../parse/ScenarioImportParserFactory.java | 5 +- .../dto/definition/request/MsScenario.java | 16 +- .../dto/definition/request/MsTestElement.java | 8 +- .../request/unknown/MsJmeterElement.java | 19 + .../commons/constants/ApiImportPlatform.java | 2 +- 6 files changed, 226 insertions(+), 212 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java 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 62356b905c..7963944b20 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 @@ -1,224 +1,208 @@ package io.metersphere.api.dto.automation.parse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import io.metersphere.api.dto.ApiTestImportRequest; -import io.metersphere.commons.utils.LogUtil; -import io.metersphere.commons.utils.ScriptEngineUtils; -import org.apache.commons.lang3.StringUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; +import io.metersphere.api.dto.definition.request.MsScenario; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.assertions.MsAssertions; +import io.metersphere.api.dto.definition.request.controller.MsIfController; +import io.metersphere.api.dto.definition.request.controller.MsLoopController; +import io.metersphere.api.dto.definition.request.extract.MsExtract; +import io.metersphere.api.dto.definition.request.processors.MsJSR223Processor; +import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor; +import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor; +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; +import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; +import io.metersphere.api.dto.definition.request.timer.MsConstantTimer; +import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement; +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.ApiScenarioModule; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import io.metersphere.base.domain.TestPlan; +import io.metersphere.commons.utils.BeanUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.jmeter.config.ConfigTestElement; +import org.apache.jmeter.extractor.JSR223PostProcessor; +import org.apache.jmeter.modifiers.JSR223PreProcessor; +import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; +import org.apache.jmeter.protocol.http.util.HTTPFileArg; +import org.apache.jmeter.protocol.java.sampler.JSR223Sampler; +import org.apache.jmeter.protocol.tcp.sampler.TCPSampler; +import org.apache.jmeter.save.SaveService; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jorphan.collections.HashTree; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Map; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; public class MsJmeterParser extends ScenarioImportAbstractParser { - private final static String HASH_TREE_ELEMENT = "hashTree"; - private final static String STRING_PROP = "stringProp"; - private final static String ARGUMENTS = "Arguments"; - private final static String COLLECTION_PROP = "collectionProp"; - private final static String HTTP_SAMPLER_PROXY = "HTTPSamplerProxy"; - private final static String ELEMENT_PROP = "elementProp"; - @Override public ScenarioImport parse(InputStream inputSource, ApiTestImportRequest request) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { - DocumentBuilder docBuilder = factory.newDocumentBuilder(); - final Document document = docBuilder.parse(inputSource); - final Element jmeterTestPlan = document.getDocumentElement(); - NodeList childNodes = jmeterTestPlan.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - Element ele = (Element) node; - parseHashTree(ele); - } - } - return null; + Object scriptWrapper = SaveService.loadElement(inputSource); + HashTree testPlan = this.getHashTree(scriptWrapper); + MsScenario scenario = new MsScenario(); + scenario.setHashTree(new LinkedList<>()); + getTree(testPlan, scenario); + + + ScenarioImport scenarioImport = new ScenarioImport(); + scenarioImport.setData(paseObj(scenario, request)); + scenarioImport.setProjectid(request.getProjectId()); } catch (Exception e) { - LogUtil.error(e.getMessage(), e); - return null; + e.printStackTrace(); } + return null; } - private static void parseHashTree(Element hashTree) { - if (invalid(hashTree)) { - return; - } - if (hashTree.getChildNodes().getLength() > 0) { - final NodeList childNodes = hashTree.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node instanceof Element) { - Element ele = (Element) node; - if (invalid(ele)) { - continue; - } - if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) { - parseHashTree(ele); - } else if (nodeNameEquals(ele, ARGUMENTS)) { - processArguments(ele); - } else if (nodeNameEquals(ele, HTTP_SAMPLER_PROXY)) { - processHttpSamplerProxy(ele); - } + private List paseObj(MsScenario msScenario, ApiTestImportRequest request) { + List scenarioWithBLOBsList = new ArrayList<>(); + ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs(); + ApiScenarioModule module = buildModule(getSelectModule(request.getModuleId()), msScenario.getName()); + scenarioWithBLOBs.setName(msScenario.getName()); + scenarioWithBLOBs.setProjectId(request.getProjectId()); + if (msScenario != null && CollectionUtils.isNotEmpty(msScenario.getHashTree())) { + scenarioWithBLOBs.setStepTotal(msScenario.getHashTree().size()); + } + if (module != null) { + scenarioWithBLOBs.setApiScenarioModuleId(module.getId()); + scenarioWithBLOBs.setModulePath("/" + module.getName()); + } + scenarioWithBLOBs.setId(UUID.randomUUID().toString()); + scenarioWithBLOBs.setScenarioDefinition(JSON.toJSONString(msScenario)); + scenarioWithBLOBsList.add(scenarioWithBLOBs); + return scenarioWithBLOBsList; + } + + private HashTree getHashTree(Object scriptWrapper) throws Exception { + Field field = scriptWrapper.getClass().getDeclaredField("testPlan"); + field.setAccessible(true); + return (HashTree) field.get(scriptWrapper); + } + + private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, HTTPSamplerProxy source) { + try { + BeanUtils.copyBean(samplerProxy, source); + if (source != null && source.getHTTPFiles().length > 0) { + samplerProxy.getBody().setBinary(new ArrayList<>()); + samplerProxy.getBody().setType(Body.FORM_DATA); + List keyValues = new LinkedList<>(); + for (HTTPFileArg arg : source.getHTTPFiles()) { + KeyValue keyValue = new KeyValue(arg.getProperty("Argument.name").toString(), arg.getProperty("Argument.value").toString()); + keyValue.setContentType(arg.getProperty("HTTPArgument.content_type").toString()); + keyValues.add(keyValue); } + samplerProxy.getBody().setKvs(keyValues); } - } - } - - private static void processHttpSamplerProxy(Element ele) { - if (invalid(ele)) { - return; - } - NodeList childNodes = ele.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (!(item instanceof Element)) { - continue; - } - Element element = (Element) item; - if (nodeNameEquals(element, ELEMENT_PROP) && "HTTPsampler.Arguments".equals(element.getAttribute("name"))) { - processArguments(element); - } else if ("HTTPSampler.path".equals(element.getAttribute("name"))) { - processStringProp(element); - } - } - } - - private static void processArguments(Element ele) { - if (invalid(ele)) { - return; - } - NodeList childNodes = ele.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node item = childNodes.item(i); - if (!(item instanceof Element)) { - continue; - } - Element element = (Element) item; - if (nodeNameEquals(item, COLLECTION_PROP) && "Arguments.arguments".equals(element.getAttribute("name"))) { - NodeList elementProps = item.getChildNodes(); - for (int j = 0; j < elementProps.getLength(); j++) { - Node elementProp = elementProps.item(j); - if (!(elementProp instanceof Element)) { - continue; - } - NodeList stringProps = elementProp.getChildNodes(); - for (int k = 0; k < stringProps.getLength(); k++) { - Node stringProp = stringProps.item(k); - if (!(stringProp instanceof Element)) { - continue; - } - processStringProp((Element) stringProp); - } - } - } - } - } - - private static void processStringProp(Element ele) { - String name = ele.getAttribute("name"); - switch (name) { - case "HTTPSampler.path": - String path = ele.getTextContent(); - Map parser = parserUrl(path); - String url = parser.get("URL"); - String params = parser.keySet().stream().filter(k -> !"URL".equals(k)).reduce("?", (u, k) -> { - String v = parser.get(k); - if (!StringUtils.equals("?", u)) { - u += "&"; - } - v = ScriptEngineUtils.calculate(v); - // urlencoder - try { - v = URLEncoder.encode(v, "UTF-8"); - } catch (UnsupportedEncodingException e) { - LogUtil.error(e); - } - u += k + "=" + v; - return u; + samplerProxy.setProtocol(RequestType.HTTP); + if (source.getArguments() != null) { + List keyValues = new LinkedList<>(); + source.getArguments().getArgumentsAsMap().forEach((k, v) -> { + KeyValue keyValue = new KeyValue(k, v); + keyValues.add(keyValue); }); - //rest参数处理 - if (url.contains("@")) { - String vars[] = url.split("@"); - for (String item : vars) { - if (item.endsWith("/")) { - item = item.substring(0, item.length() - 1); - } - url = url.replace("@" + item, ScriptEngineUtils.calculate("@" + item)); - } - } - ele.setTextContent(url + ((params != null && !params.equals("?")) ? params : "")); - break; - case "Argument.value": - String textContent = ele.getTextContent(); - if (StringUtils.startsWith(textContent, "@")) { - ele.setTextContent(ScriptEngineUtils.calculate(textContent)); - } - break; - default: - break; - } - } - - private static boolean nodeNameEquals(Node node, String desiredName) { - return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName()); - } - - private static boolean invalid(Element ele) { - return !StringUtils.isBlank(ele.getAttribute("enabled")) && !Boolean.parseBoolean(ele.getAttribute("enabled")); - } - - private static Map parserUrl(String url) { -// 传递的URL参数 - Map strUrlParas = new HashMap<>(); - - String strUrl; - String strUrlParams; - - -// 解析访问地址 - if (url.contains("?")) { - String[] strUrlPatten = url.split("\\?"); - strUrl = strUrlPatten[0]; - strUrlParams = strUrlPatten[1]; - - } else { - strUrl = url; - strUrlParams = url; - } - - strUrlParas.put("URL", strUrl); -// 解析参数 - String[] params = null; - - if (strUrlParams.contains("&")) { - params = strUrlParams.split("&"); - } else { - params = new String[]{strUrlParams}; - } - -// 保存参数到参数容器 - for (String p : params) { - if (p.contains("=")) { - String[] param = p.split("="); - if (param.length == 1) { - strUrlParas.put(param[0], ""); - } else { - - String key = param[0]; - String value = param[1]; - - strUrlParas.put(key, value); + if (CollectionUtils.isNotEmpty(keyValues)) { + samplerProxy.setArguments(keyValues); } } + samplerProxy.setPath(source.getPath()); + samplerProxy.setMethod(source.getMethod()); + if (source.getUrl() != null) { + samplerProxy.setUrl(source.getUrl().toString()); + } + samplerProxy.setId(UUID.randomUUID().toString()); + samplerProxy.setType("HTTPSamplerProxy"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void convertTCPSampler(MsTCPSampler msTCPSampler, TCPSampler tcpSampler) { + tcpSampler.setName(tcpSampler.getName()); + msTCPSampler.setServer(tcpSampler.getServer()); + msTCPSampler.setPort(tcpSampler.getPort() + ""); + msTCPSampler.setCtimeout(tcpSampler.getConnectTimeout() + ""); + msTCPSampler.setReUseConnection(tcpSampler.getProperty(TCPSampler.RE_USE_CONNECTION).getBooleanValue()); + msTCPSampler.setNodelay(tcpSampler.getProperty(TCPSampler.NODELAY).getBooleanValue()); + msTCPSampler.setCloseConnection(tcpSampler.isCloseConnection()); + msTCPSampler.setSoLinger(tcpSampler.getSoLinger() + ""); + msTCPSampler.setEolByte(tcpSampler.getEolByte() + ""); + msTCPSampler.setRequest(tcpSampler.getRequestData()); + msTCPSampler.setUsername(tcpSampler.getProperty(ConfigTestElement.USERNAME).getStringValue()); + msTCPSampler.setPassword(tcpSampler.getProperty(ConfigTestElement.PASSWORD).getStringValue()); + } + + private void getTree(HashTree tree, MsScenario scenario) { + for (Object key : tree.keySet()) { + if (key instanceof TestPlan) { + scenario.setName(((TestPlan) key).getName()); + } else if (key instanceof ThreadGroup) { + MsScenario msScenario = new MsScenario(((ThreadGroup) key).getName()); + if (CollectionUtils.isEmpty(scenario.getHashTree())) { + List msTestElementList = new LinkedList<>(); + msTestElementList.add(msScenario); + } + scenario.getHashTree().add(msScenario); + } else if (key instanceof HTTPSamplerProxy) { + MsHTTPSamplerProxy element = new MsHTTPSamplerProxy(); + element.setBody(new Body()); + HTTPSamplerProxy request = (HTTPSamplerProxy) key; + convertHttpSampler(element, request); + scenario.getHashTree().add(element); + } else if (key instanceof TCPSampler) { + MsTCPSampler msTCPSampler = new MsTCPSampler(); + TCPSampler tcpSampler = (TCPSampler) key; + convertTCPSampler(msTCPSampler, tcpSampler); + scenario.getHashTree().add(msTCPSampler); + } else if (key instanceof MsDubboSampler) { + + } else if (key instanceof MsJDBCSampler) { + + } else if (key instanceof JSR223Sampler) { + JSR223Sampler jsr223Sampler = (JSR223Sampler) key; + MsJSR223Processor processor = new MsJSR223Processor(); + BeanUtils.copyBean(processor, jsr223Sampler); + scenario.getHashTree().add(processor); + } else if (key instanceof JSR223PostProcessor) { + JSR223PostProcessor jsr223Sampler = (JSR223PostProcessor) key; + MsJSR223PostProcessor processor = new MsJSR223PostProcessor(); + BeanUtils.copyBean(processor, jsr223Sampler); + scenario.getHashTree().add(processor); + } else if (key instanceof JSR223PreProcessor) { + JSR223PreProcessor jsr223Sampler = (JSR223PreProcessor) key; + MsJSR223PreProcessor processor = new MsJSR223PreProcessor(); + BeanUtils.copyBean(processor, jsr223Sampler); + scenario.getHashTree().add(processor); + } else if (key instanceof MsAssertions) { + + } else if (key instanceof MsExtract) { + + } else if (key instanceof MsConstantTimer) { + + } else if (key instanceof MsIfController) { + + } else if (key instanceof MsLoopController) { + + } else { + MsJmeterElement jmeterElement = new MsJmeterElement(); + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(key)); + jmeterElement.setName(jsonObject.get(TestElement.NAME) == null ? "" : jsonObject.get(TestElement.NAME).toString()); + jmeterElement.setJmeterElement(key); + scenario.getHashTree().add(jmeterElement); + } + HashTree node = tree.get(key); + if (node != null) { + getTree(node, scenario); + } } - return strUrlParas; } } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java index f425fd1dd0..fc251b0ddc 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/parse/ScenarioImportParserFactory.java @@ -9,10 +9,9 @@ public class ScenarioImportParserFactory { return new MsScenarioParser(); } else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) { return new MsPostmanParser(); + } else if (StringUtils.equals(ApiImportPlatform.Jmeter.name(), platform)) { + return new MsJmeterParser(); } -// else if (StringUtils.equals(ApiImportPlatform.Swagger2.name(), platform)) { -// return new Swagger2Parser(); -// } return null; } } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index 71cbff9d69..de6e1b6356 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -34,8 +34,6 @@ import java.util.stream.Collectors; public class MsScenario extends MsTestElement { private String type = "scenario"; - @JSONField(ordinal = 20) - private String name; @JSONField(ordinal = 21) private String referenced; @@ -51,6 +49,16 @@ public class MsScenario extends MsTestElement { private static final String BODY_FILE_DIR = "/opt/metersphere/data/body"; + public MsScenario() { + } + + public MsScenario(String name) { + if (StringUtils.isEmpty(name)) { + this.setName("Scenario"); + } + this.setName(name); + } + @Override public void toHashTree(HashTree tree, List hashTree, ParameterConfig config) { if (!this.isEnable()) { @@ -72,7 +80,7 @@ public class MsScenario extends MsTestElement { } } - config.setStep(this.name); + config.setStep(this.getName()); config.setStepType("SCENARIO"); config.setEnableCookieShare(enableCookieShare); if (StringUtils.isNotEmpty(environmentId)) { @@ -109,7 +117,7 @@ public class MsScenario extends MsTestElement { private Arguments arguments(ParameterConfig config) { Arguments arguments = new Arguments(); arguments.setEnabled(true); - arguments.setName(name + "Variables"); + arguments.setName(this.getName() + "Variables"); arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("ArgumentsPanel")); if (CollectionUtils.isNotEmpty(this.getVariables())) { diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java index b328123763..69d573f617 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsTestElement.java @@ -22,6 +22,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler; import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler; import io.metersphere.api.dto.definition.request.timer.MsConstantTimer; +import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement; import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; import io.metersphere.api.dto.scenario.KeyValue; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; @@ -70,11 +71,12 @@ import java.util.stream.Collectors; @JsonSubTypes.Type(value = MsIfController.class, name = "IfController"), @JsonSubTypes.Type(value = MsScenario.class, name = "scenario"), @JsonSubTypes.Type(value = MsLoopController.class, name = "LoopController"), + @JsonSubTypes.Type(value = MsJmeterElement.class, name = "JmeterElement"), }) @JSONType(seeAlso = {MsHTTPSamplerProxy.class, MsHeaderManager.class, MsJSR223Processor.class, MsJSR223PostProcessor.class, MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class, - MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class, MsLoopController.class}, typeKey = "type") + MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class, MsLoopController.class, MsJmeterElement.class}, typeKey = "type") @Data public abstract class MsTestElement { private String type; @@ -103,7 +105,9 @@ public abstract class MsTestElement { private static final String BODY_FILE_DIR = "/opt/metersphere/data/body"; - // 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境 + /** + * todo 公共环境逐层传递,如果自身有环境 以自身引用环境为准否则以公共环境作为请求环境 + */ public void toHashTree(HashTree tree, List hashTree, ParameterConfig config) { for (MsTestElement el : hashTree) { el.toHashTree(tree, el.hashTree, config); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java new file mode 100644 index 0000000000..1e97f0758d --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/unknown/MsJmeterElement.java @@ -0,0 +1,19 @@ +package io.metersphere.api.dto.definition.request.unknown; + +import com.alibaba.fastjson.annotation.JSONType; +import io.metersphere.api.dto.definition.request.MsTestElement; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 暂时存放所有未知的Jmeter Element对象 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@JSONType(typeName = "JmeterElement") +public class MsJmeterElement extends MsTestElement { + private String type = "JmeterElement"; + + private Object jmeterElement; + +} diff --git a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java index ae9d45396f..7470f26b48 100644 --- a/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java +++ b/backend/src/main/java/io/metersphere/commons/constants/ApiImportPlatform.java @@ -1,5 +1,5 @@ package io.metersphere.commons.constants; public enum ApiImportPlatform { - Metersphere, Postman, Swagger2, Plugin + Metersphere, Postman, Swagger2, Plugin, Jmeter }