完成解析jmx文件逻辑

This commit is contained in:
haifeng414 2020-02-19 20:25:18 +08:00
parent 5457a369da
commit b9f58a8910
11 changed files with 378 additions and 8 deletions

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants;
public enum LoadTestFileType {
public enum EngineType {
JMX
}

View File

@ -1,10 +1,14 @@
package io.metersphere.engine;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class EngineContext {
private String engineId;
private String engineType;
private InputStream inputStream;
private Map<String, Object> properties = new HashMap<>();
public String getEngineId() {
return engineId;
@ -14,6 +18,14 @@ public class EngineContext {
this.engineId = engineId;
}
public String getEngineType() {
return engineType;
}
public void setEngineType(String engineType) {
this.engineType = engineType;
}
public InputStream getInputStream() {
return inputStream;
}
@ -21,4 +33,12 @@ public class EngineContext {
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public void addProperty(String key, Object value) {
this.properties.put(key, value);
}
public Object getProperty(String key) {
return this.properties.get(key);
}
}

View File

@ -1,27 +1,54 @@
package io.metersphere.engine;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.FileContent;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.commons.constants.LoadTestFileType;
import io.metersphere.commons.constants.EngineType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.engine.jmx.JmxEngine;
import io.metersphere.parse.EngineSourceParser;
import io.metersphere.parse.EngineSourceParserFactory;
import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class EngineFactory {
public static Engine createEngine(String engineType) {
final LoadTestFileType type = LoadTestFileType.valueOf(engineType);
final EngineType type = EngineType.valueOf(engineType);
if (type == LoadTestFileType.JMX) {
if (type == EngineType.JMX) {
return new JmxEngine();
}
return null;
}
public static EngineContext createContext(LoadTestWithBLOBs loadTest, FileContent fileContent) {
public static EngineContext createContext(LoadTestWithBLOBs loadTest, FileMetadata fileMetadata, FileContent fileContent) throws Exception {
final EngineContext engineContext = new EngineContext();
engineContext.setEngineId(loadTest.getId());
engineContext.setInputStream(new ByteArrayInputStream(fileContent.getFile().getBytes(StandardCharsets.UTF_8)));
engineContext.setEngineType(fileMetadata.getType());
if (!StringUtils.isEmpty(loadTest.getLoadConfiguration())) {
final JSONArray jsonArray = JSONObject.parseArray(loadTest.getLoadConfiguration());
for (int i = 0; i < jsonArray.size(); i++) {
final JSONObject jsonObject = jsonArray.getJSONObject(i);
engineContext.addProperty(jsonObject.getString("key"), jsonObject.get("value"));
}
}
final EngineSourceParser engineSourceParser = EngineSourceParserFactory.createEngineSourceParser(engineContext.getEngineType());
if (engineSourceParser == null) {
MSException.throwException("未知的文件类型!");
}
final InputStream inputStream = engineSourceParser.parse(engineContext, engineContext.getInputStream());
engineContext.setInputStream(inputStream);
return engineContext;
}

View File

@ -0,0 +1,9 @@
package io.metersphere.parse;
import io.metersphere.engine.EngineContext;
import java.io.InputStream;
public interface EngineSourceParser {
InputStream parse(EngineContext context, InputStream source) throws Exception;
}

View File

@ -0,0 +1,16 @@
package io.metersphere.parse;
import io.metersphere.commons.constants.EngineType;
import io.metersphere.parse.xml.XmlEngineSourceParse;
public class EngineSourceParserFactory {
public static EngineSourceParser createEngineSourceParser(String type) {
final EngineType engineType = EngineType.valueOf(type);
if (EngineType.JMX.equals(engineType)) {
return new XmlEngineSourceParse();
}
return null;
}
}

View File

@ -0,0 +1,32 @@
package io.metersphere.parse.xml;
import io.metersphere.engine.EngineContext;
import io.metersphere.parse.EngineSourceParser;
import io.metersphere.parse.xml.reader.DocumentParser;
import io.metersphere.parse.xml.reader.DocumentParserFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
public class XmlEngineSourceParse implements EngineSourceParser {
@Override
public InputStream parse(EngineContext context, InputStream source) throws Exception {
final InputSource inputSource = new InputSource(source);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
final Document document = docBuilder.parse(inputSource);
final DocumentParser documentParser = createDocumentParser(context.getEngineType());
return documentParser.parse(context, document);
}
private DocumentParser createDocumentParser(String type) {
return DocumentParserFactory.createDocumentParser(type);
}
}

View File

@ -0,0 +1,10 @@
package io.metersphere.parse.xml.reader;
import io.metersphere.engine.EngineContext;
import org.w3c.dom.Document;
import java.io.InputStream;
public interface DocumentParser {
InputStream parse(EngineContext context, Document document) throws Exception;
}

View File

@ -0,0 +1,16 @@
package io.metersphere.parse.xml.reader;
import io.metersphere.commons.constants.EngineType;
import io.metersphere.parse.xml.reader.jmx.JmeterDocumentParser;
public class DocumentParserFactory {
public static DocumentParser createDocumentParser(String type) {
final EngineType engineType = EngineType.valueOf(type);
if (EngineType.JMX.equals(engineType)) {
return new JmeterDocumentParser();
}
return null;
}
}

View File

@ -0,0 +1,116 @@
package io.metersphere.parse.xml.reader.jmx;
import io.metersphere.engine.EngineContext;
import io.metersphere.parse.xml.reader.DocumentParser;
import org.junit.platform.commons.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
public class JmeterDocumentParser implements DocumentParser {
private final static String HASH_TREE_ELEMENT = "hashTree";
private final static String STRING_PROP = "stringProp";
private final static String CONCURRENCY_THREAD_GROUP = "com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup";
private EngineContext context;
@Override
public InputStream parse(EngineContext context, Document document) throws Exception {
this.context = context;
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;
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
parseHashTree(ele);
}
}
return documentToInputStream(document);
}
private InputStream documentToInputStream(Document document) throws TransformerException {
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
final String resultStr = writer.toString();
return new ByteArrayInputStream(resultStr.getBytes(StandardCharsets.UTF_8));
}
private 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, CONCURRENCY_THREAD_GROUP)) {
processConcurrencyThreadGroup(ele);
}
}
}
}
}
private void processConcurrencyThreadGroup(Element concurrencyThreadGroup) {
if (concurrencyThreadGroup.getChildNodes().getLength() > 0) {
final NodeList childNodes = concurrencyThreadGroup.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, STRING_PROP)) {
parseStringProp(ele);
}
}
}
}
}
private void parseStringProp(Element stringProp) {
if (stringProp.getChildNodes().getLength() > 0 && context.getProperty(stringProp.getAttribute("name")) != null) {
stringProp.getFirstChild().setNodeValue(context.getProperty(stringProp.getAttribute("name")).toString());
}
}
private boolean nodeNameEquals(Node node, String desiredName) {
return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName());
}
private boolean invalid(Element ele) {
return !StringUtils.isBlank(ele.getAttribute("enabled")) && !Boolean.parseBoolean(ele.getAttribute("enabled"));
}
}

View File

@ -3,7 +3,7 @@ package io.metersphere.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
import io.metersphere.commons.constants.LoadTestFileType;
import io.metersphere.commons.constants.EngineType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.IOUtils;
import io.metersphere.controller.request.testplan.*;
@ -108,7 +108,7 @@ public class LoadTestService {
fileMetadata.setSize(file.getSize());
fileMetadata.setCreateTime(System.currentTimeMillis());
fileMetadata.setUpdateTime(System.currentTimeMillis());
fileMetadata.setType(LoadTestFileType.JMX.name());
fileMetadata.setType(EngineType.JMX.name());
fileMetadataMapper.insert(fileMetadata);
FileContent fileContent = new FileContent();
@ -171,7 +171,12 @@ public class LoadTestService {
fileMetadata.getType()));
}
final boolean init = engine.init(EngineFactory.createContext(loadTest, fileContent));
boolean init = true;
try {
init = engine.init(EngineFactory.createContext(loadTest, fileMetadata, fileContent));
} catch (Exception e) {
MSException.throwException(e);
}
if (!init) {
MSException.throwException(String.format("无法运行测试初始化运行环境失败测试ID%s", request.getId()));
}

View File

@ -0,0 +1,119 @@
package io.metersphere;
import org.junit.Test;
import org.junit.platform.commons.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.FileInputStream;
import java.io.StringWriter;
public class JmxFileParseTest {
private final static String HASH_TREE_ELEMENT = "hashTree";
private final static String STRING_PROP = "stringProp";
private final static String CONCURRENCY_THREAD_GROUP = "com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup";
@Test
public void parse() throws Exception {
File file = new File("/Users/dhf/Desktop/Concurrency Thread Group.jmx");
final FileInputStream inputStream = new FileInputStream(file);
final InputSource inputSource = new InputSource(inputStream);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
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;
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
parseHashTree(ele);
}
}
DOMSource domSource = new DOMSource(document);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
System.out.println("XML IN String format is: \n" + writer.toString());
}
private void parseHashTree(Element hashTree) {
if (!valid(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 (!valid(ele)) {
continue;
}
if (nodeNameEquals(ele, HASH_TREE_ELEMENT)) {
parseHashTree(ele);
} else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) {
processConcurrencyThreadGroup(ele);
}
}
}
}
}
private void processConcurrencyThreadGroup(Element concurrencyThreadGroup) {
if (concurrencyThreadGroup.getChildNodes().getLength() > 0) {
final NodeList childNodes = concurrencyThreadGroup.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (!valid(ele)) {
continue;
}
if (nodeNameEquals(ele, STRING_PROP)) {
parseStringProp(ele);
}
}
}
}
}
private void parseStringProp(Element stringProp) {
if (stringProp.getChildNodes().getLength() > 0) {
stringProp.getFirstChild().setNodeValue("1");
}
}
private boolean nodeNameEquals(Node node, String desiredName) {
return desiredName.equals(node.getNodeName()) || desiredName.equals(node.getLocalName());
}
private boolean valid(Element ele) {
return StringUtils.isBlank(ele.getAttribute("enabled")) || Boolean.parseBoolean(ele.getAttribute("enabled"));
}
}