fix(测试跟踪): 导出的测试报告性能用例日志详情和测试配置无信息

--bug=1016326 --user=李玉号 【测试跟踪】导出测试报告,查看性能用例测试结果,日志详情和测试配置看不了
https://www.tapd.cn/55049933/s/1234600
This commit is contained in:
shiziyuan9527 2022-08-26 17:15:13 +08:00 committed by f2c-ci-robot[bot]
parent c6b13415d8
commit bf8b9fbec1
8 changed files with 221 additions and 129 deletions

View File

@ -1,12 +1,16 @@
package io.metersphere.dto; package io.metersphere.dto;
import io.metersphere.base.domain.LoadTestReportLog;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Getter @Getter
@Setter @Setter
public class LogDetailDTO { public class LogDetailDTO {
private String resourceId; private String resourceId;
private String resourceName; private String resourceName;
private String content; private String content;
private List<LoadTestReportLog> reportLogs;
} }

View File

@ -1,9 +1,9 @@
package io.metersphere.track.dto; package io.metersphere.track.dto;
import io.metersphere.base.domain.LoadTestReportWithBLOBs; import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.TestPlanLoadCase;
import io.metersphere.base.domain.TestPlanLoadCaseWithBLOBs; import io.metersphere.base.domain.TestPlanLoadCaseWithBLOBs;
import io.metersphere.dto.LogDetailDTO; import io.metersphere.dto.LogDetailDTO;
import io.metersphere.dto.TestResourcePoolDTO;
import io.metersphere.performance.base.*; import io.metersphere.performance.base.*;
import io.metersphere.performance.dto.LoadTestExportJmx; import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.dto.MetricData; import io.metersphere.performance.dto.MetricData;
@ -35,7 +35,7 @@ public class TestPlanLoadCaseDTO extends TestPlanLoadCaseWithBLOBs {
private long startTime; private long startTime;
private long endTime; private long endTime;
private String fixLoadConfiguration; private String fixLoadConfiguration;
// private LoadTestExportJmx jmxContent; // private LoadTestExportJmx jmxContent;
private List<LoadTestExportJmx> fixJmxContent; private List<LoadTestExportJmx> fixJmxContent;
private TestOverview testOverview; private TestOverview testOverview;
private List<ChartsData> loadChartData; private List<ChartsData> loadChartData;
@ -48,6 +48,7 @@ public class TestPlanLoadCaseDTO extends TestPlanLoadCaseWithBLOBs {
private List<ErrorsTop5> reportErrorsTop5; private List<ErrorsTop5> reportErrorsTop5;
private List<LogDetailDTO> reportLogResource; private List<LogDetailDTO> reportLogResource;
private List<Monitor> reportResource; private List<Monitor> reportResource;
private List<MetricData> metricData; private List<MetricData> metricData;
private List<TestResourcePoolDTO> resourcePools;
} }
} }

View File

@ -194,6 +194,8 @@ public class TestPlanService {
private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper; private ExtTestPlanApiScenarioMapper extTestPlanApiScenarioMapper;
@Resource @Resource
private ExtTestPlanUiScenarioMapper extTestPlanUiScenarioMapper; private ExtTestPlanUiScenarioMapper extTestPlanUiScenarioMapper;
@Resource
private TestResourcePoolService testResourcePoolService;
public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) { public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) {
if (getTestPlanByName(testPlan.getName()).size() > 0) { if (getTestPlanByName(testPlan.getName()).size() > 0) {
@ -1664,9 +1666,8 @@ public class TestPlanService {
List<LoadTestExportJmx> jmxContent = performanceReportService.getJmxContent(reportId); List<LoadTestExportJmx> jmxContent = performanceReportService.getJmxContent(reportId);
if (!CollectionUtils.isEmpty(jmxContent)) { if (!CollectionUtils.isEmpty(jmxContent)) {
response.setJmxContent(JSONObject.toJSONString(jmxContent.get(0))); response.setJmxContent(JSONObject.toJSONString(jmxContent.get(0)));
response.setFixJmxContent(jmxContent);
} }
List<LoadTestExportJmx> fixJmxContent = performanceTestService.getJmxContent(item.getId());
response.setFixJmxContent(fixJmxContent);
// 概览 // 概览
TestOverview testOverview = performanceReportService.getTestOverview(reportId); TestOverview testOverview = performanceReportService.getTestOverview(reportId);
@ -1711,9 +1712,15 @@ public class TestPlanService {
// 日志详情 // 日志详情
List<LogDetailDTO> reportLogResource = performanceReportService.getReportLogResource(reportId); List<LogDetailDTO> reportLogResource = performanceReportService.getReportLogResource(reportId);
if (CollectionUtils.isNotEmpty(reportLogResource)) {
for (LogDetailDTO log : reportLogResource) {
List<LoadTestReportLog> reportLogs = performanceReportService.getReportLogs(reportId, log.getResourceId());
log.setReportLogs(reportLogs);
}
}
response.setReportLogResource(reportLogResource); response.setReportLogResource(reportLogResource);
// performanceReportService.getReportLogs(reportId, resourceId); List<TestResourcePoolDTO> testResourcePoolDTOS = testResourcePoolService.listValidQuotaResourcePools();
response.setResourcePools(testResourcePoolDTOS);
List<Monitor> reportResource = metricQueryService.queryReportResource(reportId); List<Monitor> reportResource = metricQueryService.queryReportResource(reportId);
response.setReportResource(reportResource); response.setReportResource(reportResource);
List<MetricData> metricData = metricQueryService.queryMetric(reportId); List<MetricData> metricData = metricQueryService.queryMetric(reportId);

View File

@ -85,7 +85,13 @@ export default {
} }
this.loading = true; this.loading = true;
if (this.planReportTemplate) { if (this.planReportTemplate) {
// this.handleGetLogResourceDetail(this.planReportTemplate.logResourceDetail, resourceId); let {reportLogResource} = this.planReportTemplate;
if (reportLogResource && reportLogResource.length > 0) {
let {reportLogs} = reportLogResource[0];
if (reportLogs) {
this.handleGetPlanTemplateLog(reportLogs);
}
}
} else if (this.isShare) { } else if (this.isShare) {
getSharePerformanceReportLogResourceDetail(this.shareId, this.id, resourceId, this.page || 1, data => { getSharePerformanceReportLogResourceDetail(this.shareId, this.id, resourceId, this.page || 1, data => {
this.handleGetLogResourceDetail(data, resourceId); this.handleGetLogResourceDetail(data, resourceId);
@ -96,6 +102,14 @@ export default {
}); });
} }
}, },
handleGetPlanTemplateLog(data) {
data.forEach(log => {
if (this.logContent) {
this.logContent.push(log);
}
});
this.loading = false;
},
handleGetLogResourceDetail(data, resourceId) { handleGetLogResourceDetail(data, resourceId) {
data.listObject.forEach(log => { data.listObject.forEach(log => {
if (this.logContent) { if (this.logContent) {

View File

@ -1,11 +1,11 @@
<template> <template>
<el-tabs> <el-tabs>
<el-tab-pane :label="$t('load_test.pressure_config')"> <el-tab-pane :label="$t('load_test.pressure_config')">
<performance-pressure-config :is-read-only="true" :test="test" :report="report" :report-id="reportId" <performance-pressure-config :is-read-only="true" :test="test" :report="report" :report-id="reportId" :plan-report-template="planReportTemplate"
:is-share="isShare" :share-id="shareId" @fileChange="fileChange"/> :is-share="isShare" :share-id="shareId" @fileChange="fileChange"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('load_test.advanced_config')"> <el-tab-pane :label="$t('load_test.advanced_config')">
<performance-advanced-config :is-read-only="true" :report-id="reportId" :report="report" :is-share="isShare" <performance-advanced-config :is-read-only="true" :report-id="reportId" :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
:share-id="shareId" ref="advancedConfig"/> :share-id="shareId" ref="advancedConfig"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@ -26,6 +26,7 @@ export default {
report: Object, report: Object,
isShare: Boolean, isShare: Boolean,
shareId: String, shareId: String,
planReportTemplate: Object,
}, },
methods: { methods: {
fileChange(threadGroups) { fileChange(threadGroups) {

View File

@ -507,6 +507,7 @@ export default {
}, },
isShare: Boolean, isShare: Boolean,
shareId: String, shareId: String,
planReportTemplate: Object,
}, },
mounted() { mounted() {
if (this.testId) { if (this.testId) {
@ -523,6 +524,14 @@ export default {
}, },
csvFiles() { csvFiles() {
this.refreshCsv(); this.refreshCsv();
},
planReportTemplate: {
handler() {
if (this.planReportTemplate) {
this.getAdvancedConfig();
}
},
deep: true
} }
}, },
methods: { methods: {
@ -534,24 +543,31 @@ export default {
if (this.isShare) { if (this.isShare) {
url = '/share/performance/report/get-advanced-config/' + this.shareId + '/' + this.reportId; url = '/share/performance/report/get-advanced-config/' + this.shareId + '/' + this.reportId;
} }
if (this.planReportTemplate) {
this.handleConfig(JSON.parse(this.planReportTemplate.advancedConfiguration));
return;
}
this.$get(url, (response) => { this.$get(url, (response) => {
if (response.data) { if (response.data) {
let data = JSON.parse(response.data); let data = JSON.parse(response.data);
this.timeout = data.timeout; this.handleConfig(data);
this.responseTimeout = data.responseTimeout;
this.statusCode = data.statusCode || [];
this.statusCodeStr = this.statusCode.join(',');
this.domains = data.domains || [];
this.params = data.params || [];
this.granularity = data.granularity;
this.monitorParams = data.monitorParams || [];
this.properties = data.properties || [];
this.systemProperties = data.systemProperties || [];
this.csvConfig = data.csvConfig;
this.refreshCsv();
} }
}); });
}, },
handleConfig(data) {
this.timeout = data.timeout;
this.responseTimeout = data.responseTimeout;
this.statusCode = data.statusCode || [];
this.statusCodeStr = this.statusCode.join(',');
this.domains = data.domains || [];
this.params = data.params || [];
this.granularity = data.granularity;
this.monitorParams = data.monitorParams || [];
this.properties = data.properties || [];
this.systemProperties = data.systemProperties || [];
this.csvConfig = data.csvConfig;
this.refreshCsv();
},
refreshCsv() { refreshCsv() {
if (this.csvConfig && this.csvFiles) { if (this.csvConfig && this.csvFiles) {
this.csvFiles.forEach(f => { this.csvFiles.forEach(f => {

View File

@ -247,6 +247,7 @@
<script> <script>
import MsChart from "@/business/components/common/chart/MsChart"; import MsChart from "@/business/components/common/chart/MsChart";
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup"; import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
import {getCurrentProjectID} from "@/common/js/utils";
const HANDLER = "handler"; const HANDLER = "handler";
const THREAD_GROUP_TYPE = "tgType"; const THREAD_GROUP_TYPE = "tgType";
@ -303,6 +304,9 @@ export default {
}, },
isShare: Boolean, isShare: Boolean,
shareId: String, shareId: String,
planReportTemplate: {
type: Object
},
}, },
data() { data() {
return { return {
@ -385,6 +389,18 @@ export default {
}, },
report() { report() {
this.resourcePool = this.report.testResourcePoolId; this.resourcePool = this.report.testResourcePoolId;
},
planReportTemplate: {
handler() {
if (this.planReportTemplate) {
let {resourcePools, testResourcePoolId} = this.planReportTemplate;
this.resourcePools = resourcePools;
this.resourcePool = testResourcePoolId;
this.handleResourcePool(resourcePools);
this.getJmxContent();
}
},
deep: true
} }
}, },
methods: { methods: {
@ -393,18 +409,121 @@ export default {
if (this.isShare) { if (this.isShare) {
url = '/share/testresourcepool/list/quota/valid'; url = '/share/testresourcepool/list/quota/valid';
} }
if (!getCurrentProjectID()) {
return;
}
this.result = this.$get(url, response => { this.result = this.$get(url, response => {
this.resourcePools = response.data; this.handleResourcePool(response.data);
// null
if (response.data.filter(p => p.id === this.resourcePool).length === 0) {
this.resourcePool = null;
// IDnull
this.setPoolNull = true;
}
this.resourcePoolChange();
}); });
}, },
handleResourcePool(data) {
this.resourcePools = data;
// null
if (data.filter(p => p.id === this.resourcePool).length === 0) {
this.resourcePool = null;
// IDnull
this.setPoolNull = true;
}
this.resourcePoolChange();
},
handleLoadConfig(data) {
for (let i = 0; i < this.threadGroups.length; i++) {
data[i].forEach(item => {
switch (item.key) {
case TARGET_LEVEL:
this.threadGroups[i].threadNumber = item.value;
break;
case RAMP_UP:
this.threadGroups[i].rampUpTime = item.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[i].iterateRampUp = item.value;
break;
case DURATION:
this.threadGroups[i].duration = item.value;
break;
case DURATION_HOURS:
this.threadGroups[i].durationHours = item.value;
break;
case DURATION_MINUTES:
this.threadGroups[i].durationMinutes = item.value;
break;
case DURATION_SECONDS:
this.threadGroups[i].durationSeconds = item.value;
break;
case UNIT:
this.threadGroups[i].unit = item.value;
break;
case STEPS:
this.threadGroups[i].step = item.value;
break;
case RPS_LIMIT:
this.threadGroups[i].rpsLimit = item.value;
break;
case RPS_LIMIT_ENABLE:
this.threadGroups[i].rpsLimitEnable = item.value;
break;
case THREAD_TYPE:
this.threadGroups[i].threadType = item.value;
break;
case ITERATE_NUM:
this.threadGroups[i].iterateNum = item.value;
break;
case ENABLED:
this.threadGroups[i].enabled = item.value;
break;
case DELETED:
this.threadGroups[i].deleted = item.value;
break;
case HANDLER:
this.threadGroups[i].handler = item.value;
break;
case THREAD_GROUP_TYPE:
this.threadGroups[i].tgType = item.value;
break;
case ON_SAMPLE_ERROR:
this.threadGroups[i].onSampleError = item.value;
break;
case STRATEGY:
this.threadGroups[i].strategy = item.value;
break;
case RESOURCE_NODE_INDEX:
this.threadGroups[i].resourceNodeIndex = item.value;
break;
case RATIOS:
this.threadGroups[i].ratios = item.value;
break;
case SERIALIZE_THREAD_GROUPS:
this.serializeThreadGroups = item.value;// 线
break;
case AUTO_STOP:
this.autoStop = item.value;// 线
break;
case AUTO_STOP_DELAY:
this.autoStopDelay = item.value;// 线
break;
default:
break;
}
//
this.$set(this.threadGroups[i], "unit", this.threadGroups[i].unit || 'S');
this.$set(this.threadGroups[i], "threadType", this.threadGroups[i].threadType || 'DURATION');
this.$set(this.threadGroups[i], "iterateNum", this.threadGroups[i].iterateNum || 1);
this.$set(this.threadGroups[i], "iterateRampUp", this.threadGroups[i].iterateRampUp || 10);
this.$set(this.threadGroups[i], "enabled", this.threadGroups[i].enabled || 'true');
this.$set(this.threadGroups[i], "deleted", this.threadGroups[i].deleted || 'false');
this.$set(this.threadGroups[i], "onSampleError", this.threadGroups[i].onSampleError || 'continue');
});
}
for (let i = 0; i < this.threadGroups.length; i++) {
let tg = this.threadGroups[i];
tg.durationHours = Math.floor(tg.duration / 3600);
tg.durationMinutes = Math.floor((tg.duration / 60 % 60));
tg.durationSeconds = Math.floor((tg.duration % 60));
}
this.resourcePoolChange();
this.calculateTotalChart();
},
getLoadConfig() { getLoadConfig() {
let url = ''; let url = '';
if (this.testId) { if (this.testId) {
@ -413,6 +532,13 @@ export default {
if (this.reportId) { if (this.reportId) {
url = '/performance/report/get-load-config/' + this.reportId; url = '/performance/report/get-load-config/' + this.reportId;
} }
if (this.planReportTemplate) {
let {loadConfiguration} = this.planReportTemplate;
if (loadConfiguration) {
this.handleLoadConfig(JSON.parse(loadConfiguration));
}
return;
}
if (!url) { if (!url) {
return; return;
} }
@ -422,102 +548,7 @@ export default {
this.$get(url, (response) => { this.$get(url, (response) => {
if (response.data) { if (response.data) {
let data = JSON.parse(response.data); let data = JSON.parse(response.data);
for (let i = 0; i < this.threadGroups.length; i++) { this.handleLoadConfig(data);
data[i].forEach(item => {
switch (item.key) {
case TARGET_LEVEL:
this.threadGroups[i].threadNumber = item.value;
break;
case RAMP_UP:
this.threadGroups[i].rampUpTime = item.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[i].iterateRampUp = item.value;
break;
case DURATION:
this.threadGroups[i].duration = item.value;
break;
case DURATION_HOURS:
this.threadGroups[i].durationHours = item.value;
break;
case DURATION_MINUTES:
this.threadGroups[i].durationMinutes = item.value;
break;
case DURATION_SECONDS:
this.threadGroups[i].durationSeconds = item.value;
break;
case UNIT:
this.threadGroups[i].unit = item.value;
break;
case STEPS:
this.threadGroups[i].step = item.value;
break;
case RPS_LIMIT:
this.threadGroups[i].rpsLimit = item.value;
break;
case RPS_LIMIT_ENABLE:
this.threadGroups[i].rpsLimitEnable = item.value;
break;
case THREAD_TYPE:
this.threadGroups[i].threadType = item.value;
break;
case ITERATE_NUM:
this.threadGroups[i].iterateNum = item.value;
break;
case ENABLED:
this.threadGroups[i].enabled = item.value;
break;
case DELETED:
this.threadGroups[i].deleted = item.value;
break;
case HANDLER:
this.threadGroups[i].handler = item.value;
break;
case THREAD_GROUP_TYPE:
this.threadGroups[i].tgType = item.value;
break;
case ON_SAMPLE_ERROR:
this.threadGroups[i].onSampleError = item.value;
break;
case STRATEGY:
this.threadGroups[i].strategy = item.value;
break;
case RESOURCE_NODE_INDEX:
this.threadGroups[i].resourceNodeIndex = item.value;
break;
case RATIOS:
this.threadGroups[i].ratios = item.value;
break;
case SERIALIZE_THREAD_GROUPS:
this.serializeThreadGroups = item.value;// 线
break;
case AUTO_STOP:
this.autoStop = item.value;// 线
break;
case AUTO_STOP_DELAY:
this.autoStopDelay = item.value;// 线
break;
default:
break;
}
//
this.$set(this.threadGroups[i], "unit", this.threadGroups[i].unit || 'S');
this.$set(this.threadGroups[i], "threadType", this.threadGroups[i].threadType || 'DURATION');
this.$set(this.threadGroups[i], "iterateNum", this.threadGroups[i].iterateNum || 1);
this.$set(this.threadGroups[i], "iterateRampUp", this.threadGroups[i].iterateRampUp || 10);
this.$set(this.threadGroups[i], "enabled", this.threadGroups[i].enabled || 'true');
this.$set(this.threadGroups[i], "deleted", this.threadGroups[i].deleted || 'false');
this.$set(this.threadGroups[i], "onSampleError", this.threadGroups[i].onSampleError || 'continue');
});
}
for (let i = 0; i < this.threadGroups.length; i++) {
let tg = this.threadGroups[i];
tg.durationHours = Math.floor(tg.duration / 3600);
tg.durationMinutes = Math.floor((tg.duration / 60 % 60));
tg.durationSeconds = Math.floor((tg.duration % 60));
}
this.resourcePoolChange();
this.calculateTotalChart();
} }
}); });
}, },
@ -529,13 +560,18 @@ export default {
if (this.reportId) { if (this.reportId) {
url = '/performance/report/get-jmx-content/' + this.reportId; url = '/performance/report/get-jmx-content/' + this.reportId;
} }
let threadGroups = [];
if (this.planReportTemplate) {
let {fixJmxContent} = this.planReportTemplate;
this.handlePlanReportJmxContent(fixJmxContent, threadGroups);
return;
}
if (!url) { if (!url) {
return; return;
} }
if (this.isShare) { if (this.isShare) {
url = '/share/performance/report/get-jmx-content/' + this.reportId; url = '/share/performance/report/get-jmx-content/' + this.reportId;
} }
let threadGroups = [];
this.$get(url, (response) => { this.$get(url, (response) => {
response.data.forEach(d => { response.data.forEach(d => {
threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name)); threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name));
@ -548,6 +584,17 @@ export default {
this.getLoadConfig(); this.getLoadConfig();
}); });
}, },
handlePlanReportJmxContent(fixJmxContent, threadGroups) {
fixJmxContent.forEach(d => {
threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name));
threadGroups.forEach(tg => {
tg.options = {};
});
});
this.threadGroups = threadGroups;
this.$emit('fileChange', threadGroups);
this.getLoadConfig();
},
resourcePoolChange() { resourcePoolChange() {
let result = this.resourcePools.filter(p => p.id === this.resourcePool); let result = this.resourcePools.filter(p => p.id === this.resourcePool);
if (result.length === 1) { if (result.length === 1) {

View File

@ -134,7 +134,9 @@
:share-id="shareId"/> :share-id="shareId"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane :label="$t('report.test_config')"> <el-tab-pane :label="$t('report.test_config')">
<ms-test-configuration :report-id="reportId" :report="report" :is-share="isShare" :share-id="shareId"/> <ms-test-configuration :report-id="reportId" :report="report"
:plan-report-template="planReportTemplate"
:is-share="isShare" :share-id="shareId"/>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>