refactor(性能测试): 测试报告显示压力配置修改

This commit is contained in:
CaptainB 2021-11-12 17:57:48 +08:00 committed by 刘瑞斌
parent b095089bfe
commit a1ef933646
3 changed files with 197 additions and 199 deletions

View File

@ -413,12 +413,7 @@ export default {
let data = res.data;
if (data) {
this.status = data.status;
this.$set(this.report, "id", data.id);
this.$set(this.report, "status", data.status);
this.$set(this.report, "testId", data.testId);
this.$set(this.report, "name", data.name);
this.$set(this.report, "createTime", data.createTime);
this.$set(this.report, "loadConfiguration", data.loadConfiguration);
this.$set(this, "report", data);
this.checkReportStatus(data.status);
if (this.status === "Completed" || this.status === "Running") {
this.initReportTimeInfo();

View File

@ -37,7 +37,7 @@
</el-col>
</el-row>
</template>
<el-form :inline="true">
<el-form :inline="true" label-width="100px">
<el-form-item :label="$t('load_test.thread_num')">
<el-input-number
:disabled="true"
@ -47,7 +47,7 @@
size="mini"/>
</el-form-item>
<br>
<el-form-item>
<el-form-item label="执行方式">
<el-radio-group v-model="threadGroup.threadType" :disabled="true">
<el-radio label="DURATION">{{ $t('load_test.by_duration') }}</el-radio>
<el-radio label="ITERATION">{{ $t('load_test.by_iteration') }}</el-radio>
@ -55,7 +55,7 @@
</el-form-item>
<br>
<div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('schedule.cron.hours')">
<el-form-item :label="$t('load_test.duration')">
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationHours"
@ -64,7 +64,8 @@
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.minutes')">
<el-form-item :label="$t('schedule.cron.hours')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationMinutes"
@ -73,7 +74,8 @@
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.seconds')">
<el-form-item :label="$t('schedule.cron.minutes')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationSeconds"
@ -82,82 +84,120 @@
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.seconds')" label-width="20px"/>
<br>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" :disabled="true" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="true"
v-model="threadGroup.rpsLimit"
@change="calculateTotalChart()"
:min="1"
size="mini"/>
<el-form-item :label="$t('load_test.rps_limit_enable')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
</el-form-item>
<el-form-item :label="$t('load_test.rps_limit')">
<el-input-number controls-position="right"
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateTotalChart()"
:min="1"
:max="99999"
size="mini"/>
</el-form-item>
<br>
<div v-if="threadGroup.tgType === 'com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup'">
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart()"
size="mini"/>
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="getDuration(threadGroup)"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_minutes', [getUnitLabel(threadGroup)])">
<el-input-number
:disabled="true"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateTotalChart()"
size="mini"/>
<el-form-item label="Step" label-width="50px">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
</div>
<div v-if="threadGroup.tgType === 'ThreadGroup'">
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
:min="1"
v-model="threadGroup.rampUpTime"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_seconds', [getUnitLabel(threadGroup)])"/>
</div>
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="getDuration(threadGroup)"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
</div>
</div>
<div v-if="threadGroup.threadType === 'ITERATION'">
<el-form-item :label="$t('load_test.iterate_num')">
<el-input-number
:disabled="true"
v-model="threadGroup.iterateNum"
:min="1"
@change="calculateTotalChart()"
size="mini"/>
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.iterateNum"
:min="1"
:max="9999999"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit_enable')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
</el-form-item>
<el-form-item :label="$t('load_test.rps_limit')">
<el-switch v-model="threadGroup.rpsLimitEnable" :disabled="true" @change="calculateTotalChart()"/>
&nbsp;
<el-input-number
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateTotalChart()"
:min="1"
size="mini"/>
<el-input-number controls-position="right"
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
:min="1"
:max="99999"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.ramp_up_time_within')">
<el-input-number
:disabled="true"
:min="1"
v-model="threadGroup.iterateRampUp"
@change="calculateTotalChart()"
size="mini"/>
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
v-model="threadGroup.iterateRampUp"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('load_test.ramp_up_time_seconds', [getUnitLabel(threadGroup)])"/>
</div>
<div v-if="resourcePoolType === 'NODE'">
<el-form-item :label="$t('load_test.resource_strategy')">
<el-radio-group v-model="threadGroup.strategy" :disabled="true" size="mini">
<el-radio-button label="auto">{{ $t('load_test.auto_ratio') }}</el-radio-button>
<el-radio-button label="specify">{{ $t('load_test.specify_resource') }}</el-radio-button>
<el-radio-button label="custom">{{ $t('load_test.custom_ratio') }}</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-if="threadGroup.strategy === 'auto'"></div>
<div v-else-if="threadGroup.strategy === 'specify'">
<el-form-item :label="$t('load_test.specify_resource')">
<el-select v-model="threadGroup.resourceNodeIndex" :disabled="true" size="mini">
<el-option
v-for="(node, index) in resourceNodes"
:key="node.ip"
:label="node.ip"
:value="index">
</el-option>
</el-select>
</el-form-item>
</div>
<div v-else>
<el-table :data="threadGroup.resourceNodes" :max-height="200">
<el-table-column type="index" width="50"/>
<el-table-column prop="ip" label="IP"/>
<el-table-column prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"/>
<el-table-column prop="ratio" :label="$t('test_track.home.percentage')">
<template v-slot:default="{row}">
<el-input-number size="small" v-model="row.ratio" :min="0" :step=".1"
:max="1"></el-input-number>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-form>
</el-collapse-item>
@ -171,14 +211,15 @@
</template>
<script>
import echarts from "echarts";
import MsChart from "@/business/components/common/chart/MsChart";
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
import {
getOldPerformanceJmxContent,
getPerformanceJmxContent,
getPerformanceLoadConfig,
getPerformanceReport, getShareOldPerformanceJmxContent, getSharePerformanceJmxContent,
getPerformanceReport,
getShareOldPerformanceJmxContent,
getSharePerformanceJmxContent,
getSharePerformanceLoadConfig,
getSharePerformanceReport
} from "@/network/load-test";
@ -200,11 +241,11 @@ const ITERATE_NUM = "iterateNum";
const ITERATE_RAMP_UP = "iterateRampUpTime";
const ENABLED = "enabled";
const DELETED = "deleted";
const STRATEGY = "strategy";
const RESOURCE_NODE_INDEX = "resourceNodeIndex";
const RATIOS = "ratios";
const hexToRgba = function (hex, opacity) {
return 'rgba(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5)) + ','
+ parseInt('0x' + hex.slice(5, 7)) + ',' + opacity + ')';
};
const hexToRgb = function (hex) {
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
@ -228,12 +269,65 @@ export default {
resourcePools: [],
activeNames: ["0"],
threadGroups: [],
resourcePoolType: null,
resourceNodes: [],
};
},
activated() {
this.getJmxContent();
},
created() {
this.getResourcePools();
},
methods: {
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
this.resourcePoolChange();
});
},
resourcePoolChange() {
let result = this.resourcePools.filter(p => p.id === this.report.testResourcePoolId);
if (result.length === 1) {
let threadNumber = 0;
this.resourceNodes = [];
this.resourcePoolType = result[0].type;
result[0].resources.forEach(resource => {
let config = JSON.parse(resource.configuration);
threadNumber += config.maxConcurrency;
this.resourceNodes.push(config);
});
this.threadGroups.forEach(tg => {
let tgRatios = tg.ratios;
let resourceNodes = JSON.parse(JSON.stringify(this.resourceNodes));
let ratios = resourceNodes.map(n => n.maxConcurrency).reduce((total, curr) => {
total += curr;
return total;
}, 0);
let preSum = 0;
for (let i = 0; i < resourceNodes.length; i++) {
let n = resourceNodes[i];
if (resourceNodes.length === tgRatios.length) {
n.ratio = tgRatios[i];
continue;
}
if (i === resourceNodes.length - 1) {
n.ratio = (1 - preSum).toFixed(2);
} else {
n.ratio = (n.maxConcurrency / ratios).toFixed(2);
preSum += Number.parseFloat(n.ratio);
}
}
this.$set(tg, "resourceNodes", resourceNodes);
if (tg.resourceNodeIndex > resourceNodes.length - 1) {
this.$set(tg, "resourceNodeIndex", 0);
}
});
this.calculateTotalChart();
}
},
calculateLoadConfiguration: function (data) {
for (let i = 0; i < this.threadGroups.length; i++) {
let d = data[i];
@ -293,6 +387,15 @@ export default {
case THREAD_GROUP_TYPE:
this.threadGroups[i].tgType = 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;
default:
break;
}
@ -303,6 +406,8 @@ export default {
tg.durationMinutes = Math.floor((tg.duration / 60 % 60));
tg.durationSeconds = Math.floor((tg.duration % 60));
}
this.resourcePoolChange();
this.calculateTotalChart();
}
},
@ -312,7 +417,7 @@ export default {
}
if (this.planReportTemplate) {
this.handleGetLoadConfig(this.planReportTemplate);
} else if (this.isShare){
} else if (this.isShare) {
this.result = getSharePerformanceReport(this.shareId, this.report.id, data => {
this.handleGetLoadConfig(data);
});
@ -333,7 +438,7 @@ export default {
let data = JSON.parse(this.planReportTemplate.fixLoadConfiguration);
this.calculateLoadConfiguration(data);
}
} else if (this.isShare){
} else if (this.isShare) {
this.result = getSharePerformanceLoadConfig(this.shareId, this.report.id, data => {
if (data) {
data = JSON.parse(data);
@ -362,7 +467,7 @@ export default {
if (this.planReportTemplate.jmxContent) {
this.handleGetJmxContent(JSON.parse(this.planReportTemplate.jmxContent));
}
} else if (this.isShare){
} else if (this.isShare) {
this.result = getSharePerformanceJmxContent(this.shareId, this.report.id, data => {
this.handleGetJmxContent(data);
});
@ -388,7 +493,7 @@ export default {
if (!threadGroups || threadGroups.length === 0) {
if (this.planReportTemplate) {
this.planReportTemplate.fixJmxContent.forEach(d => this.handleGetOldJmxContent(d, threadGroups));
} else if (this.isShare){
} else if (this.isShare) {
this.result = getShareOldPerformanceJmxContent(this.shareId, this.report.testId, data => {
data.forEach(d => this.handleGetOldJmxContent(d, threadGroups));
});
@ -523,111 +628,9 @@ export default {
handler.options.series.push(seriesData);
}
},
calculateChart(threadGroup) {
let handler = this;
if (threadGroup) {
handler = threadGroup;
}
if (handler.duration < handler.rampUpTime) {
handler.rampUpTime = handler.duration;
}
if (handler.rampUpTime < handler.step) {
handler.step = handler.rampUpTime;
}
handler.options = {
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value'
},
tooltip: {
trigger: 'axis',
formatter: '{a}: {c0}',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
series: [{
name: 'User',
data: [],
type: 'line',
step: 'start',
smooth: false,
symbolSize: 5,
showSymbol: false,
lineStyle: {
width: 1
},
itemStyle: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
},
}]
};
let timePeriod = Math.floor(handler.rampUpTime / handler.step);
let timeInc = timePeriod;
let threadPeriod = Math.floor(handler.threadNumber / handler.step);
let threadInc1 = Math.floor(handler.threadNumber / handler.step);
let threadInc2 = Math.ceil(handler.threadNumber / handler.step);
let inc2count = handler.threadNumber - handler.step * threadInc1;
for (let i = 0; i <= handler.duration; i++) {
// x
handler.options.xAxis.data.push(i);
if (handler.tgType === 'ThreadGroup') {
handler.options.series[0].step = undefined;
if (i === 0) {
handler.options.series[0].data.push([0, 0]);
}
if (i >= handler.rampUpTime) {
handler.options.xAxis.data.push(handler.duration);
handler.options.series[0].data.push([i, handler.threadNumber]);
handler.options.series[0].data.push([handler.duration, handler.threadNumber]);
break;
}
} else {
handler.options.series[0].step = 'start';
if (i > timePeriod) {
timePeriod += timeInc;
if (inc2count > 0) {
threadPeriod = threadPeriod + threadInc2;
inc2count--;
} else {
threadPeriod = threadPeriod + threadInc1;
}
if (threadPeriod > handler.threadNumber) {
threadPeriod = handler.threadNumber;
handler.options.xAxis.data.push(handler.duration);
handler.options.series[0].data.push([handler.duration, handler.threadNumber]);
break;
}
handler.options.series[0].data.push([i, threadPeriod]);
} else {
handler.options.series[0].data.push([i, threadPeriod]);
}
}
}
this.calculateTotalChart();
},
getUnitLabel(tg) {
if (tg.unit === 'S') {
return this.$t('schedule.cron.seconds');
}
if (tg.unit === 'M') {
return this.$t('schedule.cron.minutes');
}
if (tg.unit === 'H') {
return this.$t('schedule.cron.hours');
}
return this.$t('schedule.cron.seconds');
getDuration(tg) {
tg.duration = tg.durationHours * 60 * 60 + tg.durationMinutes * 60 + tg.durationSeconds;
return tg.duration;
},
},
watch: {

View File

@ -13,7 +13,7 @@
<el-breadcrumb-item>{{ reportName }}</el-breadcrumb-item>
</el-breadcrumb>
</el-row>
<el-row class="ms-report-view-btns" v-if="!isPlanReport">
<el-row class="ms-report-view-btns" v-if="!isPlanReport">
<el-button :disabled="isReadOnly || report.status !== 'Running'" type="primary" plain size="mini"
@click="dialogFormVisible=true">
{{ $t('report.test_stop_now') }}
@ -61,7 +61,8 @@
:share-id="shareId" ref="testDetails"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_request_statistics')">
<ms-report-request-statistics :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
<ms-report-request-statistics :report="report" :is-share="isShare"
:plan-report-template="planReportTemplate"
:share-id="shareId" ref="requestStatistics"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_error_log')">
@ -69,7 +70,7 @@
:share-id="shareId" ref="errorLog"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_log_details')">
<ms-report-log-details :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
<ms-report-log-details :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
:share-id="shareId"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_monitor_details')">
@ -79,11 +80,13 @@
</el-tabs>
</div>
<ms-performance-report-export v-if="!isShare && !planReportTemplate" :title="reportName" id="performanceReportExport" v-show="reportExportVisible"
<ms-performance-report-export v-if="!isShare && !planReportTemplate" :title="reportName"
id="performanceReportExport" v-show="reportExportVisible"
:report="report"/>
</el-card>
<el-dialog :title="$t('report.test_stop_now_confirm')" :visible.sync="dialogFormVisible" width="30%" :append-to-body="true">
<el-dialog :title="$t('report.test_stop_now_confirm')" :visible.sync="dialogFormVisible" width="30%"
:append-to-body="true">
<p v-html="$t('report.force_stop_tips')"/>
<p v-html="$t('report.stop_tips')"/>
<div slot="footer" class="dialog-footer">
@ -155,7 +158,7 @@ export default {
reportExportVisible: false,
testPlan: {testResourcePoolId: null},
show: true,
}
};
},
props: {
reportId: String,
@ -191,7 +194,7 @@ export default {
} else {
this.$error(this.$t('report.not_exist'));
}
})
});
}
},
initReportTimeInfo() {
@ -360,10 +363,10 @@ export default {
aTag.download = this.reportName + ".jtl";
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(aTag.href)
URL.revokeObjectURL(aTag.href);
} else {
// IE10+
navigator.msSaveBlob(blob, this.filename)
navigator.msSaveBlob(blob, this.filename);
}
}).catch(e => {
let text = e.response.data.text();
@ -376,7 +379,7 @@ export default {
this.clearData();
if (this.planReportTemplate) {
this.handleInit(this.planReportTemplate);
} else if (this.isShare){
} else if (this.isShare) {
this.result = getSharePerformanceReport(this.shareId, this.reportId, data => {
this.handleInit(data);
});
@ -389,10 +392,7 @@ export default {
handleInit(data) {
if (data) {
this.status = data.status;
this.$set(this.report, "id", this.reportId);
this.$set(this.report, "status", data.status);
this.$set(this.report, "testId", data.testId);
this.$set(this.report, "loadConfiguration", data.loadConfiguration);
this.$set(this, "report", data);
this.checkReportStatus(data.status);
if (this.status === "Completed" || this.status === "Running") {
this.initReportTimeInfo();
@ -407,7 +407,7 @@ export default {
created() {
this.init();
}
}
};
</script>
<style scoped>