This commit is contained in:
chenjianxing 2020-04-01 11:50:03 +08:00
commit 968af6614f
10 changed files with 239 additions and 39 deletions

View File

@ -1,5 +1,16 @@
package io.metersphere.commons.constants;
public enum FileType {
JMX, CSV
JMX(".jmx"), CSV(".csv");
// 保存后缀
private String suffix;
FileType(String suffix) {
this.suffix = suffix;
}
public String suffix() {
return this.suffix;
}
}

View File

@ -1,22 +0,0 @@
package io.metersphere.commons.constants;
public enum JmeterReportType {
AggregateReport,
SynthesisReport,
ThreadsStateOverTime,
BytesThroughputOverTime,
HitsPerSecond,
LatenciesOverTime,
PerfMon,
DbMon,
JMXMon,
ResponseCodesPerSecond,
ResponseTimesDistribution,
ResponseTimesOverTime,
ResponseTimesPercentiles,
ThroughputVsThreads,
TimesVsThreads,
TransactionsPerSecond,
PageDataExtractorOverTime,
MergeResults,
}

View File

@ -5,6 +5,7 @@ import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.metersphere.base.domain.LoadTestWithBLOBs;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
@ -74,7 +75,7 @@ public class KubernetesTestEngine extends AbstractEngine {
setName(configMapName);
}});
item.setData(new HashMap<String, String>() {{
put(context.getTestId() + ".jmx", context.getContent());
put(context.getTestId() + FileType.JMX.suffix(), context.getContent());
if (MapUtils.isNotEmpty(context.getTestData())) {
putAll(context.getTestData());
}

View File

@ -18,6 +18,7 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.List;
public class JmeterDocumentParser implements DocumentParser {
@ -32,6 +33,7 @@ public class JmeterDocumentParser implements DocumentParser {
private final static String CONFIG_TEST_ELEMENT = "ConfigTestElement";
private final static String DNS_CACHE_MANAGER = "DNSCacheManager";
private final static String ARGUMENTS = "Arguments";
private final static String RESPONSE_ASSERTION = "ResponseAssertion";
private EngineContext context;
@Override
@ -87,6 +89,7 @@ public class JmeterDocumentParser implements DocumentParser {
processCheckoutConfigTestElement(ele);
processCheckoutDnsCacheManager(ele);
processCheckoutArguments(ele);
processCheckoutResponseAssertion(ele);
} else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) {
processConcurrencyThreadGroup(ele);
processCheckoutTimer(ele);
@ -107,13 +110,86 @@ public class JmeterDocumentParser implements DocumentParser {
processDnsCacheManager(ele);
} else if (nodeNameEquals(ele, ARGUMENTS)) {
processArguments(ele);
} else if (nodeNameEquals(ele, RESPONSE_ASSERTION)) {
processResponseAssertion(ele);
}
}
}
}
}
private void processResponseAssertion(Element element) {
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if (item instanceof Element && nodeNameEquals(item, "collectionProp")) {
removeChildren(item);
Document document = item.getOwnerDocument();
Object params = context.getProperty("statusCode");
if (params instanceof List) {
HashSet set = new HashSet((List) params);
for (Object p : set) {
element.appendChild(createStringProp(document, p.toString(), p.toString()));
}
}
}
}
}
private void processCheckoutResponseAssertion(Element element) {
if (context.getProperty("statusCode") == null || JSON.parseArray(context.getProperty("statusCode").toString()).size() == 0) {
return;
}
Document document = element.getOwnerDocument();
Node hashTree = element.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
}
NodeList childNodes = hashTree.getChildNodes();
for (int i = 0, l = childNodes.getLength(); i < l; i++) {
Node item = childNodes.item(i);
if (nodeNameEquals(item, RESPONSE_ASSERTION)) {
// 如果已经存在不再添加
return;
}
}
/*
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="50548">301</stringProp>
<stringProp name="49586">200</stringProp>
</collectionProp>
<stringProp name="Assertion.custom_message"></stringProp>
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">33</intProp>
</ResponseAssertion>
*/
// add class name
Element responseAssertion = document.createElement(RESPONSE_ASSERTION);
responseAssertion.setAttribute("guiclass", "AssertionGui");
responseAssertion.setAttribute("testclass", "ResponseAssertion");
responseAssertion.setAttribute("testname", "Response Assertion");
responseAssertion.setAttribute("enabled", "true");
Element collectionProp = document.createElement(COLLECTION_PROP);
collectionProp.setAttribute("name", "Asserion.test_strings");
//
responseAssertion.appendChild(collectionProp);
responseAssertion.appendChild(createStringProp(document, "Assertion.custom_message", ""));
responseAssertion.appendChild(createStringProp(document, "Assertion.test_field", ""));
responseAssertion.appendChild(createBoolProp(document, "Assertion.assume_success", false));
responseAssertion.appendChild(createIntProp(document, "Assertion.test_type", 33));
hashTree.appendChild(responseAssertion);
hashTree.appendChild(document.createElement(HASH_TREE_ELEMENT));
}
private void processCheckoutArguments(Element ele) {
if (context.getProperty("params") == null || JSON.parseArray(context.getProperty("params").toString()).size() == 0) {
return;
}
Node hashTree = ele.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
@ -154,6 +230,9 @@ public class JmeterDocumentParser implements DocumentParser {
}
private void processCheckoutDnsCacheManager(Element ele) {
if (context.getProperty("domains") == null || JSON.parseArray(context.getProperty("domains").toString()).size() == 0) {
return;
}
Node hashTree = ele.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
@ -204,6 +283,9 @@ public class JmeterDocumentParser implements DocumentParser {
}
private void processCheckoutConfigTestElement(Element ele) {
if (context.getProperty("timeout") == null || StringUtils.isBlank(context.getProperty("timeout").toString())) {
return;
}
Node hashTree = ele.getNextSibling();
while (!(hashTree instanceof Element)) {
hashTree = hashTree.getNextSibling();
@ -438,6 +520,13 @@ public class JmeterDocumentParser implements DocumentParser {
return tearDownSwitch;
}
private Element createIntProp(Document document, String name, int value) {
Element tearDownSwitch = document.createElement("intProp");
tearDownSwitch.setAttribute("name", name);
tearDownSwitch.appendChild(document.createTextNode(String.valueOf(value)));
return tearDownSwitch;
}
private void processBackendListener(Element backendListener) {
KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class);
Document document = backendListener.getOwnerDocument();
@ -557,7 +646,6 @@ public class JmeterDocumentParser implements DocumentParser {
threadGroup.appendChild(createStringProp(document, "Hold", "12"));
threadGroup.appendChild(createStringProp(document, "LogFilename", ""));
threadGroup.appendChild(createStringProp(document, "Iterations", "1"));
// todo 单位是S 要修改 成M
threadGroup.appendChild(createStringProp(document, "Unit", "M"));
}

View File

@ -10,6 +10,8 @@ import org.apache.commons.lang3.StringUtils;
import java.io.Reader;
import java.io.StringReader;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@ -282,4 +284,69 @@ public class JtlResolver {
return testOverview;
}
public static ChartsData getLoadChartData(String jtlString) {
ChartsData data = new ChartsData();
List<Metric> total = JtlResolver.resolver(jtlString);
////
List<String> users = new ArrayList<>();
List<String> hits = new ArrayList<>();
List<String> erorrs = new ArrayList<>();
List<String> timeList = new ArrayList<>();
////
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DecimalFormat df = new DecimalFormat("0.0");
total.sort(Comparator.comparing(metric -> Long.valueOf(metric.getTimestamp())));
total.forEach(metric -> {
metric.setTimestamp(stampToDate(metric.getTimestamp()));
});
Map<String, List<Metric>> collect = total.stream().collect(Collectors.groupingBy(Metric::getTimestamp));
List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(collect.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<String, List<Metric>>>() {
@Override
public int compare(Map.Entry<String, List<Metric>> t1, Map.Entry<String, List<Metric>> t2) {
Date date1 = null,date2 = null;
try {
date1 = sdf.parse(t1.getKey());
date2 = sdf.parse(t2.getKey());
} catch (ParseException e) {
e.printStackTrace();
}
return (int) (date1.getTime() - date2.getTime());
}
});
for (int i = 0; i < entries.size(); i++) {
int failSize = 0;
Map.Entry<String, List<Metric>> map = entries.get(i);
List<Metric> metrics = map.getValue();
for (int j = 0; j < metrics.size(); j++) {
Metric metric = metrics.get(j);
String success = metric.getSuccess();
if (!"true".equals(success)){
failSize++;
}
}
timeList.add(map.getKey());
hits.add(String.valueOf(metrics.size()));
users.add(String.valueOf(metrics.size()));
erorrs.add(String.valueOf(failSize));
}
return data;
}
private static String stampToDate(String s){
String res;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long lt = Long.parseLong(s);
Date date = new Date(lt);
res = simpleDateFormat.format(date);
return res;
}
}

View File

@ -0,0 +1,41 @@
package io.metersphere.report.base;
public class ChartsData {
private String xAxis;
private String yAxis;
private String yAxis1;
private String serices;
public String getxAxis() {
return xAxis;
}
public void setxAxis(String xAxis) {
this.xAxis = xAxis;
}
public String getyAxis() {
return yAxis;
}
public void setyAxis(String yAxis) {
this.yAxis = yAxis;
}
public String getyAxis1() {
return yAxis1;
}
public void setyAxis1(String yAxis1) {
this.yAxis1 = yAxis1;
}
public String getSerices() {
return serices;
}
public void setSerices(String serices) {
this.serices = serices;
}
}

View File

@ -113,7 +113,7 @@ CREATE TABLE IF NOT EXISTS `system_parameter` (
CREATE TABLE IF NOT EXISTS `test_resource` (
`id` varchar(50) NOT NULL COMMENT 'Test resource ID',
`description` varchar(255) DEFAULT NULL COMMENT 'Test resource description',
`test_resource_pool_id` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT 'Test resource pool ID this test resource belongs to',
`configuration` longtext COMMENT 'Test resource configuration',
`status` varchar(64) NOT NULL COMMENT 'Test resource status',
`create_time` bigint(13) NOT NULL COMMENT 'Create timestamp',
@ -239,7 +239,7 @@ CREATE TABLE IF NOT EXISTS `test_plan` (
`executor_match_rule` varchar(255) DEFAULT NULL COMMENT 'Executor match rule)',
`tags` text COMMENT 'Test plan tags (JSON format)',
`create_time` bigint(13) NOT NULL COMMENT 'Create timestamp',
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp'
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp',
PRIMARY KEY (`id`)
)
ENGINE = InnoDB
@ -275,8 +275,8 @@ CREATE TABLE IF NOT EXISTS `test_case` (
`remark` text DEFAULT NULL COMMENT 'Test case remark',
`steps` text DEFAULT NULL COMMENT 'Test case steps (JSON format)',
`create_time` bigint(13) NOT NULL COMMENT 'Create timestamp',
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp'
PRIMARY KEY (`id`),
`update_time` bigint(13) NOT NULL COMMENT 'Update timestamp',
PRIMARY KEY (`id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4

View File

@ -204,7 +204,7 @@
name: "PerformanceAdvancedConfig",
data() {
return {
timeout: 10,
timeout: 100,
statusCode: [],
domains: [],
params: [],
@ -339,12 +339,16 @@
configurations() {
this.domains.forEach(d => this.delOriginObject(d));
this.params.forEach(d => this.delOriginObject(d));
let statusCode = [];
if (this.statusCodeStr) {
statusCode = this.statusCodeStr.split(',');
}
return {
timeout: this.timeout,
statusCode: this.statusCodeStr.split(','),
statusCode: statusCode,
params: this.params,
domains: this.domains,
}
};
},
}
}

View File

@ -82,6 +82,7 @@
getFileMetadata(testPlan) {
this.fileList = [];
this.tableData = [];
this.uploadList = [];
this.result = this.$get(this.getFileMetadataPath + "/" + testPlan.id, response => {
let files = response.data;
@ -184,10 +185,10 @@
validConfig() {
let newJmxNum = 0, oldJmxNum = 0;
if (this.uploadList.length > 0) {
newJmxNum = this.uploadList.filter(f => f.name.endsWith(".jmx")).length;
newJmxNum = this.uploadList.filter(f => f.name.toLowerCase().endsWith(".jmx")).length;
}
if (this.fileList.length > 0) {
oldJmxNum = this.fileList.filter(f => f.name.endsWith(".jmx")).length;
oldJmxNum = this.fileList.filter(f => f.name.toLowerCase().endsWith(".jmx")).length;
}
if (newJmxNum + oldJmxNum !== 1) {
this.$message({

View File

@ -86,11 +86,16 @@
},
xAxis: {
type: 'category',
data: ['12:40', '12:50', '13:00', '13:10', '13:20', '13:30', '13:40']
data: ["10:22:01", "10:22:02", "10:22:04", "10:22:06",
"10:22:07", "10:22:08", "10:22:09", "10:22:10", "10:22:11", "10:22:12"]
},
yAxis: [{
name: 'User',
type: 'value',
min: 0,
max: 30,
splitNumber: 5,
interval: 30 / 5
},
{
name: 'Hits/s',
@ -101,20 +106,23 @@
{
name: 'Users',
color: '#0CA74A',
data: [20, 40, 40, 40, 40, 40, 40],
data: [6,9,10,15,1,10,25,19,15,2],
type: 'line',
yAxisIndex: 0
},
{
name: 'Hits/s',
color: '#65A2FF',
data: [15, 38, 35, 39, 36, 37, 5],
data: [1,1,1,1,1,1,1,1,1,1],
type: 'line',
yAxisIndex: 1
},
{
name: 'Error(s)',
color: '#E6113C',
data: [0, 0, 0, 0, 0, 0, 0],
data: [0,0,0,0,1,1,2,0,5,2],
type: 'line',
yAxisIndex: 1
}
]
},
@ -125,7 +133,8 @@
},
xAxis: {
type: 'category',
data: ['12:40', '12:50', '13:00', '13:10', '13:20', '13:30', '13:40']
data: ["2020-03-25 10:22:01", "2020-03-25 10:22:02", "2020-03-25 10:22:04", "2020-03-25 10:22:06",
"2020-03-25 10:22:07", "2020-03-25 10:22:08", "2020-03-25 10:22:09", "2020-03-25 10:22:10", "2020-03-25 10:22:11", "2020-03-25 10:22:12"]
},
yAxis: [{
name: 'User',