refactor(性能测试): 重构性能测试解析jmx的方式

This commit is contained in:
CaptainB 2022-01-21 13:48:09 +08:00 committed by 刘瑞斌
parent ff664cd1b9
commit 285ca02ba1
9 changed files with 497 additions and 585 deletions

View File

@ -8,7 +8,7 @@ public class EngineContext {
private String testName;
private String namespace;
private String fileType;
private String content;
private byte[] content;
private String resourcePoolId;
private String reportId;
private Integer resourceIndex;
@ -52,11 +52,11 @@ public class EngineContext {
return this.properties.get(key);
}
public String getContent() {
public byte[] getContent() {
return content;
}
public void setContent(String content) {
public void setContent(byte[] content) {
this.content = content;
}

View File

@ -25,25 +25,15 @@ import org.apache.commons.beanutils.ConstructorUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.reflections8.Reflections;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
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.annotation.Resource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
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.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
@ -239,7 +229,7 @@ public class EngineFactory {
engineContext.setTestResourceFiles(testResourceFiles);
try (ByteArrayInputStream source = new ByteArrayInputStream(jmxBytes)) {
String content = engineSourceParser.parse(engineContext, source);
byte[] content = engineSourceParser.parse(engineContext, source);
engineContext.setContent(content);
} catch (MSException e) {
LogUtil.error(e.getMessage(), e);
@ -309,80 +299,75 @@ public class EngineFactory {
return props.toString().getBytes(StandardCharsets.UTF_8);
}
public static byte[] mergeJmx(List<FileMetadata> jmxFiles) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Element hashTree = null;
Document rootDocument = null;
for (FileMetadata fileMetadata : jmxFiles) {
FileContent fileContent = fileService.getFileContent(fileMetadata.getId());
final InputSource inputSource = new InputSource(new ByteArrayInputStream(fileContent.getFile()));
InputStream inputSource = new ByteArrayInputStream(fileContent.getFile());
if (hashTree == null) {
rootDocument = docBuilder.parse(inputSource);
Element jmeterTestPlan = rootDocument.getDocumentElement();
NodeList childNodes = jmeterTestPlan.getChildNodes();
rootDocument = EngineSourceParserFactory.getDocument(inputSource);
Element jmeterTestPlan = rootDocument.getRootElement();
List<Element> childNodes = jmeterTestPlan.elements();
outer:
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node instanceof Element) {
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
NodeList childNodes1 = node.getChildNodes();
for (int j = 0; j < childNodes1.getLength(); j++) {
Node item = childNodes1.item(j);
if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) {
hashTree = (Element) node;
break outer;
}
for (Element node : childNodes) {
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
List<Element> childNodes1 = node.elements();
for (Element item : childNodes1) {
if (StringUtils.equalsIgnoreCase("TestPlan", item.getName())) {
hashTree = getNextSibling(item);
break outer;
}
}
}
} else {
Document document = docBuilder.parse(inputSource);
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) {
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
Element secondHashTree = (Element) node;
NodeList secondChildNodes = secondHashTree.getChildNodes();
for (int j = 0; j < secondChildNodes.getLength(); j++) {
Node item = secondChildNodes.item(j);
if (StringUtils.equalsIgnoreCase("TestPlan", item.getNodeName())) {
continue;
}
if (StringUtils.equalsIgnoreCase("hashTree", item.getNodeName())) {
NodeList itemChildNodes = item.getChildNodes();
for (int k = 0; k < itemChildNodes.getLength(); k++) {
Node item1 = itemChildNodes.item(k);
Node newNode = item1.cloneNode(true);
rootDocument.adoptNode(newNode);
hashTree.appendChild(newNode);
}
}
Document document = EngineSourceParserFactory.getDocument(inputSource);
Element jmeterTestPlan = document.getRootElement();
List<Element> childNodes = jmeterTestPlan.elements();
for (Element node : childNodes) {
// jmeterTestPlan的子元素肯定是<hashTree></hashTree>
Element secondHashTree = node;
List<Element> secondChildNodes = secondHashTree.elements();
for (Element item : secondChildNodes) {
if (StringUtils.equalsIgnoreCase("TestPlan", item.getName())) {
secondHashTree = getNextSibling(item);
break;
}
}
if (StringUtils.equalsIgnoreCase("hashTree", secondHashTree.getName())) {
List<Element> itemChildNodes = secondHashTree.elements();
for (Element item1 : itemChildNodes) {
hashTree.add((Element) item1.clone());
}
}
}
}
//
inputSource.close();
}
return documentToBytes(rootDocument);
return EngineSourceParserFactory.formatXml(rootDocument);
} catch (Exception e) {
MSException.throwException(e);
}
return new byte[0];
}
private static byte[] documentToBytes(Document document) throws TransformerException {
DOMSource domSource = new DOMSource(document);
ByteArrayOutputStream out = new ByteArrayOutputStream();
StreamResult result = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, result);
return out.toByteArray();
private static Element getNextSibling(Element ele) {
Element parent = ele.getParent();
if (parent != null) {
Iterator<Element> iterator = parent.elementIterator();
while (iterator.hasNext()) {
Element next = iterator.next();
if (ele.equals(next)) {
return iterator.next();
}
}
}
return null;
}
@Resource

View File

@ -5,5 +5,5 @@ import io.metersphere.performance.engine.EngineContext;
import java.io.InputStream;
public interface EngineSourceParser {
String parse(EngineContext context, InputStream source) throws Exception;
byte[] parse(EngineContext context, InputStream source) throws Exception;
}

View File

@ -1,16 +1,96 @@
package io.metersphere.performance.parse;
import io.metersphere.commons.constants.FileType;
import io.metersphere.performance.parse.xml.XmlEngineSourceParse;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.performance.parse.xml.reader.JmeterDocumentParser;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class EngineSourceParserFactory {
public static final boolean IS_TRANS = true;
public static EngineSourceParser createEngineSourceParser(String type) {
final FileType engineType = FileType.valueOf(type);
if (FileType.JMX.equals(engineType)) {
return new XmlEngineSourceParse();
return new JmeterDocumentParser();
}
return null;
}
public static Document getDocument(InputStream source) throws DocumentException {
SAXReader reader = new SAXReader();
if (!IS_TRANS) {
reader.setXMLFilter(EngineSourceParserFactory.getFilter());
}
return reader.read(source);
}
public static byte[] formatXml(Document document) throws Exception {
OutputFormat format = OutputFormat.createPrettyPrint();
try (
ByteArrayOutputStream out = new ByteArrayOutputStream();
) {
XMLWriter xw = new XMLWriter(out, format);
xw.setEscapeText(IS_TRANS);
xw.write(document);
xw.flush();
xw.close();
return out.toByteArray();
} catch (IOException e) {
LogUtil.error(e);
}
return new byte[0];
}
public static XMLFilterImpl getFilter() {
return new XMLFilterImpl() {
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String text = new String(ch, start, length);
if (length == 1) {
if (StringUtils.equals("&", text)) {
char[] escape = "&amp;".toCharArray();
super.characters(escape, start, escape.length);
return;
}
if (StringUtils.equals("\"", text)) {
char[] escape = "&quot;".toCharArray();
super.characters(escape, start, escape.length);
return;
}
if (StringUtils.equals("'", text)) {
char[] escape = "&apos;".toCharArray();
super.characters(escape, start, escape.length);
return;
}
if (StringUtils.equals("<", text)) {
char[] escape = "&lt;".toCharArray();
super.characters(escape, start, escape.length);
return;
}
if (StringUtils.equals(">", text)) {
char[] escape = "&gt;".toCharArray();
super.characters(escape, start, escape.length);
return;
}
}
super.characters(ch, start, length);
}
};
}
}

View File

@ -1,32 +0,0 @@
package io.metersphere.performance.parse.xml;
import io.metersphere.performance.engine.EngineContext;
import io.metersphere.performance.parse.EngineSourceParser;
import io.metersphere.performance.parse.xml.reader.DocumentParser;
import io.metersphere.performance.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 String 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.getFileType());
return documentParser.parse(context, document);
}
private DocumentParser createDocumentParser(String type) {
return DocumentParserFactory.createDocumentParser(type);
}
}

View File

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

View File

@ -1,18 +0,0 @@
package io.metersphere.performance.parse.xml.reader;
import io.metersphere.commons.constants.FileType;
import io.metersphere.performance.parse.xml.reader.jmx.JmeterDocumentParser;
public class DocumentParserFactory {
public static DocumentParser createDocumentParser(String type) {
final FileType fileType = FileType.valueOf(type);
switch (fileType) {
case JMX:
return new JmeterDocumentParser();
default:
break;
}
return null;
}
}

View File

@ -13,7 +13,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@ -60,11 +59,11 @@ public class JmeterFileService {
Map<String, byte[]> files = new HashMap<>();
// 每个测试生成一个文件夹
files.put(fileName, context.getContent().getBytes(StandardCharsets.UTF_8));
files.put(fileName, context.getContent());
// 保存jmx
LoadTestReportWithBLOBs record = new LoadTestReportWithBLOBs();
record.setId(context.getReportId());
record.setJmxContent(context.getContent());
record.setJmxContent(new String(context.getContent()));
extLoadTestReportMapper.updateJmxContentIfAbsent(record);
// 保存 byte[]
Map<String, byte[]> jarFiles = context.getTestResourceFiles();