fix(接口定义): 导入Jmeter

This commit is contained in:
fit2-zhao 2021-02-04 14:48:04 +08:00
parent e69ee40438
commit 935bcbfafe
6 changed files with 226 additions and 212 deletions

View File

@ -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<ApiScenarioWithBLOBs> paseObj(MsScenario msScenario, ApiTestImportRequest request) {
List<ApiScenarioWithBLOBs> 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<KeyValue> 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<String, String> 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<KeyValue> 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<String, String> parserUrl(String url) {
// 传递的URL参数
Map<String, String> 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<MsTestElement> 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;
}
}

View File

@ -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;
}
}

View File

@ -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<MsTestElement> 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())) {

View File

@ -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<MsTestElement> hashTree, ParameterConfig config) {
for (MsTestElement el : hashTree) {
el.toHashTree(tree, el.hashTree, config);

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants;
public enum ApiImportPlatform {
Metersphere, Postman, Swagger2, Plugin
Metersphere, Postman, Swagger2, Plugin, Jmeter
}