Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Captain.B 2020-04-08 16:47:01 +08:00
commit e1cdc4830f
11 changed files with 160 additions and 186 deletions

View File

@ -78,12 +78,12 @@ public class ReportController {
} }
@GetMapping("/content/load_chart/{reportId}") @GetMapping("/content/load_chart/{reportId}")
public ChartsData getLoadChartData(@PathVariable String reportId) { public List<ChartsData> getLoadChartData(@PathVariable String reportId) {
return reportService.getLoadChartData(reportId); return reportService.getLoadChartData(reportId);
} }
@GetMapping("/content/res_chart/{reportId}") @GetMapping("/content/res_chart/{reportId}")
public ChartsData getResponseTimeChartData(@PathVariable String reportId) { public List<ChartsData> getResponseTimeChartData(@PathVariable String reportId) {
return reportService.getResponseTimeChartData(reportId); return reportService.getResponseTimeChartData(reportId);
} }

View File

@ -1,6 +1,5 @@
package io.metersphere.report; package io.metersphere.report;
import com.alibaba.fastjson.JSONObject;
import com.opencsv.bean.CsvToBean; import com.opencsv.bean.CsvToBean;
import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.bean.CsvToBeanBuilder;
import com.opencsv.bean.HeaderColumnNameMappingStrategy; import com.opencsv.bean.HeaderColumnNameMappingStrategy;
@ -10,6 +9,7 @@ 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.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -312,18 +312,10 @@ public class JtlResolver {
} }
public static ChartsData getLoadChartData(String jtlString) { public static List<ChartsData> getLoadChartData(String jtlString) {
ChartsData data = new ChartsData(); List<ChartsData> chartsDataList = new ArrayList<>();
List<Metric> totalMetricList = JtlResolver.resolver(jtlString); List<Metric> totalMetricList = JtlResolver.resolver(jtlString);
List<String> users = new ArrayList<>();
List<String> hits = new ArrayList<>();
List<String> errors = new ArrayList<>();
List<String> timeList = new ArrayList<>();
Map<String, Object> resultMap = new HashMap<>(5);
DecimalFormat decimalFormat = new DecimalFormat("0.0");
if (totalMetricList != null) { if (totalMetricList != null) {
for (Metric metric : totalMetricList) { for (Metric metric : totalMetricList) {
metric.setTimestamp(stampToDate(metric.getTimestamp())); metric.setTimestamp(stampToDate(metric.getTimestamp()));
@ -331,7 +323,6 @@ public class JtlResolver {
} }
Map<String, List<Metric>> collect = Objects.requireNonNull(totalMetricList).stream().collect(Collectors.groupingBy(Metric::getTimestamp)); Map<String, List<Metric>> collect = Objects.requireNonNull(totalMetricList).stream().collect(Collectors.groupingBy(Metric::getTimestamp));
List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(collect.entrySet()); List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(collect.entrySet());
entries.sort(JtlResolver::sortByDate);
for (Map.Entry<String, List<Metric>> entry : entries) { for (Map.Entry<String, List<Metric>> entry : entries) {
int failSize = 0; int failSize = 0;
@ -345,31 +336,38 @@ public class JtlResolver {
} }
} }
String timeStamp = "";
try { try {
timeList.add(formatDate(entry.getKey())); timeStamp = formatDate(entry.getKey());
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
hits.add(decimalFormat.format(metrics.size() * 1.0 / maxUsers));
users.add(String.valueOf(maxUsers));
errors.add(String.valueOf(failSize));
}
resultMap.put("users", users);
resultMap.put("hits", hits);
resultMap.put("errors", errors);
JSONObject serices = new JSONObject(resultMap);
data.setxAxis(String.join(",", timeList));
data.setSerices(serices.toString());
return data;
}
public static ChartsData getResponseTimeChartData(String jtlString) {
ChartsData chartsData = new ChartsData(); ChartsData chartsData = new ChartsData();
chartsData.setxAxis(timeStamp);
chartsData.setGroupName("hits");
chartsData.setyAxis(new BigDecimal(metrics.size() * 1.0 / maxUsers));
chartsDataList.add(chartsData);
chartsData = new ChartsData();
chartsData.setxAxis(timeStamp);
chartsData.setGroupName("users");
chartsData.setyAxis(new BigDecimal(maxUsers));
chartsDataList.add(chartsData);
chartsData = new ChartsData();
chartsData.setxAxis(timeStamp);
chartsData.setGroupName("errors");
chartsData.setyAxis(new BigDecimal(failSize));
chartsDataList.add(chartsData);
}
return chartsDataList;
}
public static List<ChartsData> getResponseTimeChartData(String jtlString) {
List<ChartsData> chartsDataList = new ArrayList<>();
List<Metric> totalMetricList = JtlResolver.resolver(jtlString); List<Metric> totalMetricList = JtlResolver.resolver(jtlString);
totalMetricList.forEach(metric -> { totalMetricList.forEach(metric -> {
@ -378,35 +376,34 @@ public class JtlResolver {
Map<String, List<Metric>> metricMap = totalMetricList.stream().collect(Collectors.groupingBy(Metric::getTimestamp)); Map<String, List<Metric>> metricMap = totalMetricList.stream().collect(Collectors.groupingBy(Metric::getTimestamp));
List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(metricMap.entrySet()); List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(metricMap.entrySet());
entries.sort(JtlResolver::sortByDate);
List<String> resTimeList = new ArrayList<>();
List<String> users = 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)); Map<String, List<Metric>> metricsMap = metricList.stream().collect(Collectors.groupingBy(Metric::getThreadName));
int maxUsers = metricsMap.size(); 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();
String timeStamp = "";
try { try {
timestampList.add(formatDate(entry.getKey())); timeStamp = formatDate(entry.getKey());
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
users.add(String.valueOf(maxUsers)); ChartsData chartsData = new ChartsData();
resTimeList.add(String.valueOf(sumElapsedTime / metricList.size())); chartsData.setxAxis(timeStamp);
chartsData.setGroupName("users");
chartsData.setyAxis(new BigDecimal(maxUsers));
chartsDataList.add(chartsData);
ChartsData chartsData2 = new ChartsData();
chartsData2.setxAxis(timeStamp);
chartsData2.setGroupName("responseTime");
chartsData2.setyAxis(new BigDecimal(sumElapsedTime * 1.0 / metricList.size()));
chartsDataList.add(chartsData2);
} }
Map<String, Object> resultMap = new HashMap<>(2); return chartsDataList;
resultMap.put("users", users);
resultMap.put("resTime", resTimeList);
JSONObject serices = new JSONObject(resultMap);
chartsData.setxAxis(String.join(",", timestampList));
chartsData.setSerices(serices.toString());
return chartsData;
} }
private static String stampToDate(String timeStamp) { private static String stampToDate(String timeStamp) {
@ -426,24 +423,4 @@ public class JtlResolver {
return after.format(before.parse(dateString)); return after.format(before.parse(dateString));
} }
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;
try {
date1 = simpleDateFormat.parse(map1.getKey());
date2 = simpleDateFormat.parse(map2.getKey());
} catch (ParseException e) {
e.printStackTrace();
}
Long time1 = date1.getTime();
Long time2 = date2.getTime();
if (time1.equals(time2)) {
return 0;
} else {
return time1 > time2 ? 1 : -1;
}
}
} }

View File

@ -1,9 +1,33 @@
package io.metersphere.report.base; package io.metersphere.report.base;
import java.math.BigDecimal;
public class ChartsData { public class ChartsData {
/**
* X
*/
private String xAxis; private String xAxis;
private String serices;
/**
* Y
*/
private BigDecimal yAxis = BigDecimal.ZERO;
/**
* Y 轴右侧
*/
private BigDecimal yAxis2 = BigDecimal.ZERO;
/**
* series 名称
*/
private String groupName;
/**
* 描述
*/
private String description;
public String getxAxis() { public String getxAxis() {
return xAxis; return xAxis;
@ -13,11 +37,35 @@ public class ChartsData {
this.xAxis = xAxis; this.xAxis = xAxis;
} }
public String getSerices() { public BigDecimal getyAxis() {
return serices; return yAxis;
} }
public void setSerices(String serices) { public void setyAxis(BigDecimal yAxis) {
this.serices=serices; this.yAxis = yAxis;
}
public BigDecimal getyAxis2() {
return yAxis2;
}
public void setyAxis2(BigDecimal yAxis2) {
this.yAxis2 = yAxis2;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
} }
} }

View File

@ -84,20 +84,20 @@ public class ReportService {
return testOverview; return testOverview;
} }
public ChartsData getLoadChartData(String id) { public List<ChartsData> getLoadChartData(String id) {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
ChartsData chartsData = JtlResolver.getLoadChartData(content); List<ChartsData> chartsDataList = JtlResolver.getLoadChartData(content);
return chartsData; return chartsDataList;
} }
public ChartsData getResponseTimeChartData(String id) { public List<ChartsData> getResponseTimeChartData(String id) {
checkReportStatus(id); checkReportStatus(id);
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
String content = loadTestReport.getContent(); String content = loadTestReport.getContent();
ChartsData chartsData = JtlResolver.getResponseTimeChartData(content); List<ChartsData> chartsDataList = JtlResolver.getResponseTimeChartData(content);
return chartsData; return chartsDataList;
} }
public void checkReportStatus(String reportId) { public void checkReportStatus(String reportId) {

View File

@ -214,7 +214,7 @@ const router = new VueRouter({
component: TestCase, component: TestCase,
}, },
{ {
path: "plan/:projectId", path: "plan/:type",
name: "testPlan", name: "testPlan",
component: TestPlan component: TestPlan
}, },

View File

@ -105,13 +105,8 @@
color: '#65A2FF' color: '#65A2FF'
}, },
}, },
legend: { legend: {},
bottom: 10, xAxis: {},
data: ['Users', 'Hits/s', 'Error(s)']
},
xAxis: {
type: 'category',
},
yAxis: [{ yAxis: [{
name: 'User', name: 'User',
type: 'value', type: 'value',
@ -128,28 +123,9 @@
// interval: 5 / 5 // interval: 5 / 5
} }
], ],
series: [ 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.generateOption(loadOption, data);
}
this.loadOption = this.generateLoadOption(loadOption, data);
}) })
this.$get("/report/content/res_chart/" + this.id, res => { this.$get("/report/content/res_chart/" + this.id, res => {
let data = res.data; let data = res.data;
@ -162,13 +138,8 @@
color: '#99743C' color: '#99743C'
}, },
}, },
legend: { legend: {},
bottom: 10, xAxis: {},
data: ['Users', 'Response Time']
},
xAxis: {
type: 'category'
},
yAxis: [{ yAxis: [{
name: 'User', name: 'User',
type: 'value', type: 'value',
@ -182,77 +153,40 @@
min: 0 min: 0
} }
], ],
series: [ series: []
{ }
name: 'Users', this.resOption = this.generateOption(resOption, data);
color: '#0CA74A', })
},
generateOption(option, data) {
let chartData = data;
let legend = [], series = {}, xAxis = [], seriesData = [];
chartData.forEach(item => {
if (!xAxis.includes(item.xAxis)) {
xAxis.push(item.xAxis);
}
xAxis.sort()
let name = item.groupName
if (!legend.includes(name)) {
legend.push(name)
series[name] = []
}
series[name].splice(xAxis.indexOf(item.xAxis), 0, item.yAxis.toFixed(2));
})
this.$set(option.legend, "data", legend);
this.$set(option.legend, "bottom", 10);
this.$set(option.xAxis, "data", xAxis);
for (let name in series) {
let data = series[name];
let items = {
name: name,
type: 'line', type: 'line',
yAxisIndex: 0 data: data
}, };
{ seriesData.push(items);
name: 'Response Time',
color: '#99743C',
type: 'line',
yAxisIndex: 1
} }
] this.$set(option, "series", seriesData);
} return option;
this.resOption = this.generateResponseOption(resOption, data);
})
},
_objToStrMap(obj){
let strMap = new Map();
for (let k of Object.keys(obj)) {
strMap.set(k,obj[k]);
}
return strMap;
},
_jsonToMap(jsonStr){
return this._objToStrMap(JSON.parse(jsonStr));
},
generateLoadOption(loadOption, data) {
let map = this._jsonToMap(data.serices);
let xAxis = data.xAxis;
this.$set(loadOption.xAxis, "data", xAxis.split(','));
let user = map.get("users").slice(0);
let hit = map.get("hits").slice(0);
user.sort(function (a,b) {
return parseInt(a) - parseInt(b);
})
hit.sort(function (a,b) {
return parseFloat(a) - parseFloat(b);
})
this.$set(loadOption.yAxis[0], "max",user[user.length-1]);
this.$set(loadOption.yAxis[0], "interval", user[user.length-1]/5);
this.$set(loadOption.yAxis[1], "max", hit[hit.length-1]);
this.$set(loadOption.yAxis[1], "interval", hit[hit.length-1]/5);
this.$set(loadOption.series[0], "data", map.get("users"));
this.$set(loadOption.series[1], "data", map.get("hits"));
this.$set(loadOption.series[2], "data", map.get("errors"));
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: {

View File

@ -88,6 +88,7 @@
} }
if (path.indexOf("/track/case/edit") >= 0){ if (path.indexOf("/track/case/edit") >= 0){
this.openRecentTestCaseEditDialog(); this.openRecentTestCaseEditDialog();
this.$router.push('/track/case/all');
} }
} }
}, },

View File

@ -31,9 +31,6 @@
<span style="padding-left: 5px;">{{$t('test_track.case_list')}}</span> <span style="padding-left: 5px;">{{$t('test_track.case_list')}}</span>
</el-menu-item> </el-menu-item>
<el-menu-item :index="testCaseEditPath" class="blank_item"></el-menu-item> <el-menu-item :index="testCaseEditPath" class="blank_item"></el-menu-item>
<!--<el-menu-item :index="'/' + beaseUrl + '/case/create'">-->
<!--<el-button type="text">{{$t('test_track.create_case')}}</el-button>-->
<!--</el-menu-item>-->
</el-submenu> </el-submenu>
<el-submenu v-if="isCurrentWorkspaceUser" <el-submenu v-if="isCurrentWorkspaceUser"

View File

@ -25,6 +25,20 @@
return { return {
} }
}, },
mounted() {
if (this.$route.path.indexOf("/track/plan/create") >= 0){
this.openTestPlanEditDialog();
this.$router.push('/track/plan/all');
}
},
watch: {
'$route'(to, from) {
if (to.path.indexOf("/track/plan/create") >= 0){
this.openTestPlanEditDialog();
this.$router.push('/track/plan/all');
}
}
},
methods: { methods: {
openTestPlanEditDialog(data) { openTestPlanEditDialog(data) {
this.$refs.testPlanEditDialog.openTestPlanEditDialog(data); this.$refs.testPlanEditDialog.openTestPlanEditDialog(data);

View File

@ -13,19 +13,20 @@
<test-case-plan-list <test-case-plan-list
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog" @openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
@editTestPlanTestCase="editTestPlanTestCase" @editTestPlanTestCase="editTestPlanTestCase"
@refresh="refresh"
:plan-id="planId" :plan-id="planId"
ref="testCasePlanList"></test-case-plan-list> ref="testCasePlanList"></test-case-plan-list>
</el-main> </el-main>
</el-container> </el-container>
<test-case-relevance <test-case-relevance
@refresh="getPlanCases" @refresh="refresh"
:plan-id="planId" :plan-id="planId"
ref="testCaseRelevance"></test-case-relevance> ref="testCaseRelevance"></test-case-relevance>
<test-plan-test-case-edit <test-plan-test-case-edit
ref="testPlanTestCaseEdit" ref="testPlanTestCaseEdit"
@refresh="getPlanCases"> @refresh="refresh">
</test-plan-test-case-edit> </test-plan-test-case-edit>
@ -65,7 +66,8 @@
}, },
methods: { methods: {
refresh() { refresh() {
this.getPlanCases();
this.getNodeTreeByPlanId();
}, },
getPlanCases(nodeIds) { getPlanCases(nodeIds) {
this.$refs.testCasePlanList.initTableData(nodeIds); this.$refs.testCasePlanList.initTableData(nodeIds);

View File

@ -211,6 +211,7 @@
let testCaseId = testCase.id; let testCaseId = testCase.id;
this.$post('/test/plan/case/delete/' + testCaseId, {}, () => { this.$post('/test/plan/case/delete/' + testCaseId, {}, () => {
this.initTableData(); this.initTableData();
this.$emit("refresh");
this.$message({ this.$message({
message: this.$t('commons.delete_success'), message: this.$t('commons.delete_success'),
type: 'success' type: 'success'