Merge branch 'dev' of https://github.com/fit2cloudrd/metersphere-server into dev
This commit is contained in:
commit
2364fac57b
|
@ -12,10 +12,8 @@ import io.metersphere.engine.EngineContext;
|
||||||
import io.metersphere.engine.EngineFactory;
|
import io.metersphere.engine.EngineFactory;
|
||||||
import io.metersphere.engine.docker.request.BaseRequest;
|
import io.metersphere.engine.docker.request.BaseRequest;
|
||||||
import io.metersphere.engine.docker.request.TestRequest;
|
import io.metersphere.engine.docker.request.TestRequest;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -83,16 +81,6 @@ public class DockerTestEngine extends AbstractEngine {
|
||||||
testRequest.setImage(JMETER_IMAGE);
|
testRequest.setImage(JMETER_IMAGE);
|
||||||
testRequest.setTestData(context.getTestData());
|
testRequest.setTestData(context.getTestData());
|
||||||
|
|
||||||
// todo 判断测试状态
|
|
||||||
String taskStatusUri = String.format(BASE_URL + "/jmeter/task/status/" + testId, nodeIp, port);
|
|
||||||
List containerList = restTemplate.postForObject(taskStatusUri, testRequest, List.class);
|
|
||||||
for (int i = 0; i < containerList.size(); i++) {
|
|
||||||
HashMap h = (HashMap) containerList.get(i);
|
|
||||||
if (StringUtils.equals((String) h.get("State"), "running")) {
|
|
||||||
MSException.throwException("The test is running!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
restTemplate.postForObject(uri, testRequest, String.class);
|
restTemplate.postForObject(uri, testRequest, String.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import io.metersphere.report.base.*;
|
||||||
import io.metersphere.report.dto.ErrorsTop5DTO;
|
import io.metersphere.report.dto.ErrorsTop5DTO;
|
||||||
import io.metersphere.report.dto.RequestStatisticsDTO;
|
import io.metersphere.report.dto.RequestStatisticsDTO;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
|
@ -20,7 +19,6 @@ import java.util.stream.Collectors;
|
||||||
public class JtlResolver {
|
public class JtlResolver {
|
||||||
|
|
||||||
private static final Integer ERRORS_TOP_SIZE = 5;
|
private static final Integer ERRORS_TOP_SIZE = 5;
|
||||||
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
private static List<Metric> resolver(String jtlString) {
|
private static List<Metric> resolver(String jtlString) {
|
||||||
HeaderColumnNameMappingStrategy<Metric> ms = new HeaderColumnNameMappingStrategy<>();
|
HeaderColumnNameMappingStrategy<Metric> ms = new HeaderColumnNameMappingStrategy<>();
|
||||||
|
@ -378,27 +376,37 @@ public class JtlResolver {
|
||||||
entries.sort(JtlResolver::sortByDate);
|
entries.sort(JtlResolver::sortByDate);
|
||||||
|
|
||||||
List<String> resTimeList = new ArrayList<>();
|
List<String> resTimeList = new ArrayList<>();
|
||||||
|
List<String> users = new ArrayList<>();
|
||||||
List<String> timestampList = new ArrayList<>();
|
List<String> timestampList = new ArrayList<>();
|
||||||
|
|
||||||
for (Map.Entry<String, List<Metric>> entry : entries) {
|
for (Map.Entry<String, List<Metric>> entry : entries) {
|
||||||
List<Metric> metricList = entry.getValue();
|
List<Metric> metricList = entry.getValue();
|
||||||
|
Map<String, List<Metric>> metricsMap = metricList.stream().collect(Collectors.groupingBy(Metric::getThreadName));
|
||||||
|
int maxUsers = metricsMap.size();
|
||||||
int sumElapsedTime = metricList.stream().mapToInt(metric -> Integer.parseInt(metric.getElapsed())).sum();
|
int sumElapsedTime = metricList.stream().mapToInt(metric -> Integer.parseInt(metric.getElapsed())).sum();
|
||||||
timestampList.add(entry.getKey());
|
timestampList.add(entry.getKey());
|
||||||
|
users.add(String.valueOf(maxUsers));
|
||||||
resTimeList.add(String.valueOf(sumElapsedTime / metricList.size()));
|
resTimeList.add(String.valueOf(sumElapsedTime / metricList.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, Object> resultMap = new HashMap<>(2);
|
||||||
|
resultMap.put("users", users);
|
||||||
|
resultMap.put("resTime", resTimeList);
|
||||||
|
JSONObject serices = new JSONObject(resultMap);
|
||||||
chartsData.setxAxis(StringUtils.join(",", timestampList));
|
chartsData.setxAxis(StringUtils.join(",", timestampList));
|
||||||
chartsData.setSerices(StringUtils.join(",", resTimeList));
|
chartsData.setSerices(serices.toString());
|
||||||
return chartsData;
|
return chartsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stampToDate(String s) {
|
private static String stampToDate(String timeStamp) {
|
||||||
long lt = Long.parseLong(s);
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
|
long lt = Long.parseLong(timeStamp);
|
||||||
Date date = new Date(lt);
|
Date date = new Date(lt);
|
||||||
return simpleDateFormat.format(date);
|
return simpleDateFormat.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int sortByDate(Map.Entry<String, List<Metric>> map1, Map.Entry<String, List<Metric>> map2) {
|
private static int sortByDate(Map.Entry<String, List<Metric>> map1, Map.Entry<String, List<Metric>> map2) {
|
||||||
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
Date date1 = null, date2 = null;
|
Date date1 = null, date2 = null;
|
||||||
try {
|
try {
|
||||||
date1 = simpleDateFormat.parse(map1.getKey());
|
date1 = simpleDateFormat.parse(map1.getKey());
|
||||||
|
@ -406,6 +414,15 @@ public class JtlResolver {
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return (int) (Objects.requireNonNull(date1).getTime() - Objects.requireNonNull(date2).getTime());
|
|
||||||
|
Long time1 = date1.getTime();
|
||||||
|
Long time2 = date2.getTime();
|
||||||
|
|
||||||
|
if (time1.equals(time2)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return time1 > time2 ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -59,10 +59,10 @@
|
||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<chart ref="chart1" :options="option" :autoresize="true"></chart>
|
<chart ref="chart1" :options="loadOption" :autoresize="true"></chart>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<chart ref="chart2" :options="option2" :autoresize="true"></chart>
|
<chart ref="chart2" :options="resOption" :autoresize="true"></chart>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -79,84 +79,8 @@
|
||||||
avgResponseTime: "0",
|
avgResponseTime: "0",
|
||||||
responseTime90: "0",
|
responseTime90: "0",
|
||||||
avgBandwidth: "0",
|
avgBandwidth: "0",
|
||||||
option: {
|
loadOption: {},
|
||||||
legend: {
|
resOption: {}
|
||||||
top: 20,
|
|
||||||
data: ['Users', 'Hits/s', 'Error(s)']
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
},
|
|
||||||
yAxis: [{
|
|
||||||
name: 'User',
|
|
||||||
type: 'value',
|
|
||||||
min: 0,
|
|
||||||
splitNumber: 5,
|
|
||||||
// interval: 10 / 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Hits/s',
|
|
||||||
type: 'value',
|
|
||||||
splitNumber: 5,
|
|
||||||
min: 0,
|
|
||||||
// max: 5,
|
|
||||||
// interval: 5 / 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
color: '#0CA74A',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Hits/s',
|
|
||||||
color: '#65A2FF',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Error(s)',
|
|
||||||
color: '#E6113C',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
option2: {
|
|
||||||
legend: {
|
|
||||||
top: 20,
|
|
||||||
data: ['Users', 'Response Time']
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: []
|
|
||||||
},
|
|
||||||
yAxis: [{
|
|
||||||
name: 'User',
|
|
||||||
type: 'value',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Response Time',
|
|
||||||
type: 'value'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
color: '#0CA74A',
|
|
||||||
data: [],
|
|
||||||
type: 'line',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Response Time',
|
|
||||||
color: '#99743C',
|
|
||||||
data: [],
|
|
||||||
type: 'line',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -172,7 +96,108 @@
|
||||||
})
|
})
|
||||||
this.$get("/report/content/load_chart/" + this.id, res => {
|
this.$get("/report/content/load_chart/" + this.id, res => {
|
||||||
let data = res.data;
|
let data = res.data;
|
||||||
this.option = this.generateOption(data);
|
let loadOption = {
|
||||||
|
title: {
|
||||||
|
text: 'Load',
|
||||||
|
left: 'center',
|
||||||
|
top: 20,
|
||||||
|
textStyle: {
|
||||||
|
color: '#65A2FF'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
bottom: 10,
|
||||||
|
data: ['Users', 'Hits/s', 'Error(s)']
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
},
|
||||||
|
yAxis: [{
|
||||||
|
name: 'User',
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
splitNumber: 5,
|
||||||
|
// interval: 10 / 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Hits/s',
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 5,
|
||||||
|
min: 0,
|
||||||
|
// max: 5,
|
||||||
|
// interval: 5 / 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Users',
|
||||||
|
color: '#0CA74A',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Hits/s',
|
||||||
|
color: '#65A2FF',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Error(s)',
|
||||||
|
color: '#E6113C',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.loadOption = this.generateLoadOption(loadOption, data);
|
||||||
|
})
|
||||||
|
this.$get("/report/content/res_chart/" + this.id, res => {
|
||||||
|
let data = res.data;
|
||||||
|
let resOption = {
|
||||||
|
title: {
|
||||||
|
text: 'Response Time',
|
||||||
|
left: 'center',
|
||||||
|
top: 20,
|
||||||
|
textStyle: {
|
||||||
|
color: '#99743C'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
bottom: 10,
|
||||||
|
data: ['Users', 'Response Time']
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category'
|
||||||
|
},
|
||||||
|
yAxis: [{
|
||||||
|
name: 'User',
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 5,
|
||||||
|
min: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Response Time',
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 5,
|
||||||
|
min: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Users',
|
||||||
|
color: '#0CA74A',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Response Time',
|
||||||
|
color: '#99743C',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
this.resOption = this.generateResponseOption(resOption, data);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_objToStrMap(obj){
|
_objToStrMap(obj){
|
||||||
|
@ -185,55 +210,10 @@
|
||||||
_jsonToMap(jsonStr){
|
_jsonToMap(jsonStr){
|
||||||
return this._objToStrMap(JSON.parse(jsonStr));
|
return this._objToStrMap(JSON.parse(jsonStr));
|
||||||
},
|
},
|
||||||
generateOption(data) {
|
generateLoadOption(loadOption, data) {
|
||||||
let option = {
|
|
||||||
legend: {
|
|
||||||
top: 20,
|
|
||||||
data: ['Users', 'Hits/s', 'Error(s)']
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
},
|
|
||||||
yAxis: [{
|
|
||||||
name: 'User',
|
|
||||||
type: 'value',
|
|
||||||
min: 0,
|
|
||||||
splitNumber: 5,
|
|
||||||
// interval: 10 / 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Hits/s',
|
|
||||||
type: 'value',
|
|
||||||
splitNumber: 5,
|
|
||||||
min: 0,
|
|
||||||
// max: 5,
|
|
||||||
// interval: 5 / 5
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: 'Users',
|
|
||||||
color: '#0CA74A',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Hits/s',
|
|
||||||
color: '#65A2FF',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Error(s)',
|
|
||||||
color: '#E6113C',
|
|
||||||
type: 'line',
|
|
||||||
yAxisIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
let map = this._jsonToMap(data.serices);
|
let map = this._jsonToMap(data.serices);
|
||||||
let xAxis = data.xAxis;
|
let xAxis = data.xAxis;
|
||||||
this.$set(option.xAxis, "data", xAxis.split(','));
|
this.$set(loadOption.xAxis, "data", xAxis.split(','));
|
||||||
let user = map.get("users").slice(0);
|
let user = map.get("users").slice(0);
|
||||||
let hit = map.get("hits").slice(0);
|
let hit = map.get("hits").slice(0);
|
||||||
user.sort(function (a,b) {
|
user.sort(function (a,b) {
|
||||||
|
@ -242,16 +222,38 @@
|
||||||
hit.sort(function (a,b) {
|
hit.sort(function (a,b) {
|
||||||
return parseFloat(a) - parseFloat(b);
|
return parseFloat(a) - parseFloat(b);
|
||||||
})
|
})
|
||||||
this.$set(option.yAxis[0], "max",user[user.length-1]);
|
this.$set(loadOption.yAxis[0], "max",user[user.length-1]);
|
||||||
this.$set(option.yAxis[0], "interval", user[user.length-1]/5);
|
this.$set(loadOption.yAxis[0], "interval", user[user.length-1]/5);
|
||||||
this.$set(option.yAxis[1], "max", hit[hit.length-1]);
|
this.$set(loadOption.yAxis[1], "max", hit[hit.length-1]);
|
||||||
this.$set(option.yAxis[1], "interval", hit[hit.length-1]/5);
|
this.$set(loadOption.yAxis[1], "interval", hit[hit.length-1]/5);
|
||||||
|
|
||||||
this.$set(option.series[0], "data", map.get("users"));
|
this.$set(loadOption.series[0], "data", map.get("users"));
|
||||||
this.$set(option.series[1], "data", map.get("hits"));
|
this.$set(loadOption.series[1], "data", map.get("hits"));
|
||||||
this.$set(option.series[2], "data", map.get("errors"));
|
this.$set(loadOption.series[2], "data", map.get("errors"));
|
||||||
return option;
|
return loadOption;
|
||||||
}
|
},
|
||||||
|
generateResponseOption(resOption, data) {
|
||||||
|
let map = this._jsonToMap(data.serices);
|
||||||
|
let user = map.get("users").slice(0);
|
||||||
|
let res = map.get("resTime").slice(0);
|
||||||
|
user.sort(function (a,b) {
|
||||||
|
return parseInt(a) - parseInt(b);
|
||||||
|
})
|
||||||
|
res.sort(function (a,b) {
|
||||||
|
return parseFloat(a) - parseFloat(b);
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$set(resOption.yAxis[0], "max",user[user.length-1]);
|
||||||
|
this.$set(resOption.yAxis[0], "interval", user[user.length-1]/5);
|
||||||
|
this.$set(resOption.yAxis[1], "max", res[res.length-1]);
|
||||||
|
this.$set(resOption.yAxis[1], "interval", res[res.length-1]/5);
|
||||||
|
|
||||||
|
let xAxis = data.xAxis;
|
||||||
|
this.$set(resOption.xAxis, "data", xAxis.split(','));
|
||||||
|
this.$set(resOption.series[0], "data", map.get("users"));
|
||||||
|
this.$set(resOption.series[1], "data", map.get("resTime"));
|
||||||
|
return resOption;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
status() {
|
status() {
|
||||||
|
|
Loading…
Reference in New Issue