feat(性能测试): 支持配置不同的线程组参数
This commit is contained in:
parent
1e5e19417e
commit
2d1a5a1995
|
@ -104,6 +104,12 @@ public class PerformanceTestController {
|
|||
return performanceTestService.getLoadConfiguration(testId);
|
||||
}
|
||||
|
||||
@GetMapping("/get-jmx-content/{testId}")
|
||||
public String getJmxContent(@PathVariable String testId) {
|
||||
checkOwnerService.checkPerformanceTestOwner(testId);
|
||||
return performanceTestService.getJmxContent(testId);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteTestPlanRequest request) {
|
||||
checkOwnerService.checkPerformanceTestOwner(request.getId());
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.apache.commons.collections.CollectionUtils;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class AbstractEngine implements Engine {
|
||||
|
@ -81,9 +82,22 @@ public abstract class AbstractEngine implements Engine {
|
|||
String loadConfiguration = t.getLoadConfiguration();
|
||||
JSONArray jsonArray = JSON.parseArray(loadConfiguration);
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JSONObject o = jsonArray.getJSONObject(i);
|
||||
if (StringUtils.equals(o.getString("key"), "TargetLevel")) {
|
||||
s = o.getInteger("value");
|
||||
if (jsonArray.get(i) instanceof Map) {
|
||||
JSONObject o = jsonArray.getJSONObject(i);
|
||||
if (StringUtils.equals(o.getString("key"), "TargetLevel")) {
|
||||
s = o.getInteger("value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (jsonArray.get(i) instanceof List) {
|
||||
JSONArray o = jsonArray.getJSONArray(i);
|
||||
for (int j = 0; j < o.size(); j++) {
|
||||
JSONObject b = o.getJSONObject(j);
|
||||
if (StringUtils.equals(b.getString("key"), "TargetLevel")) {
|
||||
s += b.getInteger("value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
|
|
|
@ -10,7 +10,6 @@ public class EngineContext {
|
|||
private String fileType;
|
||||
private String content;
|
||||
private String resourcePoolId;
|
||||
private Long threadNum;
|
||||
private Long startTime;
|
||||
private String reportId;
|
||||
private Integer resourceIndex;
|
||||
|
@ -95,14 +94,6 @@ public class EngineContext {
|
|||
this.resourcePoolId = resourcePoolId;
|
||||
}
|
||||
|
||||
public Long getThreadNum() {
|
||||
return threadNum;
|
||||
}
|
||||
|
||||
public void setThreadNum(Long threadNum) {
|
||||
this.threadNum = threadNum;
|
||||
}
|
||||
|
||||
public Long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.metersphere.base.domain.TestResourcePool;
|
|||
import io.metersphere.commons.constants.FileType;
|
||||
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.config.KafkaProperties;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.performance.engine.docker.DockerTestEngine;
|
||||
|
@ -22,6 +23,7 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -52,7 +54,7 @@ public class EngineFactory {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static EngineContext createContext(LoadTestWithBLOBs loadTest, String resourceId, long threadNum, long startTime, String reportId, int resourceIndex) {
|
||||
public static EngineContext createContext(LoadTestWithBLOBs loadTest, String resourceId, double ratio, long startTime, String reportId, int resourceIndex) {
|
||||
final List<FileMetadata> fileMetadataList = fileService.getFileMetadataByTestId(loadTest.getId());
|
||||
if (org.springframework.util.CollectionUtils.isEmpty(fileMetadataList)) {
|
||||
MSException.throwException(Translator.get("run_load_test_file_not_found") + loadTest.getId());
|
||||
|
@ -73,7 +75,6 @@ public class EngineFactory {
|
|||
engineContext.setTestName(loadTest.getName());
|
||||
engineContext.setNamespace(loadTest.getProjectId());
|
||||
engineContext.setFileType(jmxFile.getType());
|
||||
engineContext.setThreadNum(threadNum);
|
||||
engineContext.setResourcePoolId(loadTest.getTestResourcePoolId());
|
||||
engineContext.setStartTime(startTime);
|
||||
engineContext.setReportId(reportId);
|
||||
|
@ -90,8 +91,34 @@ public class EngineFactory {
|
|||
final JSONArray jsonArray = JSONObject.parseArray(loadTest.getLoadConfiguration());
|
||||
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
final JSONObject jsonObject = jsonArray.getJSONObject(i);
|
||||
engineContext.addProperty(jsonObject.getString("key"), jsonObject.get("value"));
|
||||
if (jsonArray.get(i) instanceof Map) {
|
||||
JSONObject o = jsonArray.getJSONObject(i);
|
||||
String key = o.getString("key");
|
||||
if ("TargetLevel".equals(key)) {
|
||||
engineContext.addProperty(key, Math.round(((Integer) o.get("value")) * ratio));
|
||||
} else {
|
||||
engineContext.addProperty(key, o.get("value"));
|
||||
}
|
||||
}
|
||||
if (jsonArray.get(i) instanceof List) {
|
||||
JSONArray o = jsonArray.getJSONArray(i);
|
||||
for (int j = 0; j < o.size(); j++) {
|
||||
JSONObject b = o.getJSONObject(j);
|
||||
String key = b.getString("key");
|
||||
Object values = engineContext.getProperty(key);
|
||||
if (values == null) {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
if (values instanceof List) {
|
||||
Object value = b.get("value");
|
||||
if ("TargetLevel".equals(key)) {
|
||||
value = Math.round(((Integer) b.get("value")) * ratio);
|
||||
}
|
||||
((List<Object>) values).add(value);
|
||||
engineContext.addProperty(key, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -112,8 +139,10 @@ public class EngineFactory {
|
|||
String content = engineSourceParser.parse(engineContext, source);
|
||||
engineContext.setContent(content);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.base.domain.TestResource;
|
|||
import io.metersphere.commons.constants.ResourceStatusEnum;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.controller.ResultHolder;
|
||||
import io.metersphere.dto.NodeDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
|
@ -52,19 +53,21 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
|
||||
for (int i = 0, size = resourceList.size(); i < size; i++) {
|
||||
int ratio = resourceRatio.get(i);
|
||||
double realThreadNum = ((double) ratio / totalThreadNum) * threadNum;
|
||||
runTest(resourceList.get(i), Math.round(realThreadNum), i);
|
||||
// double realThreadNum = ((double) ratio / totalThreadNum) * threadNum;
|
||||
runTest(resourceList.get(i), ((double) ratio / totalThreadNum), i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void runTest(TestResource resource, long realThreadNum, int resourceIndex) {
|
||||
private void runTest(TestResource resource, double ratio, int resourceIndex) {
|
||||
EngineContext context = null;
|
||||
try {
|
||||
context = EngineFactory.createContext(loadTest, resource.getId(), realThreadNum, this.getStartTime(), this.getReportId(), resourceIndex);
|
||||
context = EngineFactory.createContext(loadTest, resource.getId(), ratio, this.getStartTime(), this.getReportId(), resourceIndex);
|
||||
} catch (MSException e) {
|
||||
LogUtil.error(e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -777,8 +777,22 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
elementProp.setAttribute("elementType", "com.blazemeter.jmeter.control.VirtualUserController");
|
||||
threadGroup.appendChild(elementProp);
|
||||
// 持续时长
|
||||
String duration = context.getProperty("duration").toString();
|
||||
String rampUp = context.getProperty("RampUp").toString();
|
||||
Object durations = context.getProperty("duration");
|
||||
String duration;
|
||||
if (durations instanceof List) {
|
||||
Object o = ((List<?>) durations).get(0);
|
||||
duration = o.toString();
|
||||
} else {
|
||||
duration = durations.toString();
|
||||
}
|
||||
Object rampUps = context.getProperty("RampUp");
|
||||
String rampUp;
|
||||
if (rampUps instanceof List) {
|
||||
Object o = ((List<?>) rampUps).get(0);
|
||||
rampUp = o.toString();
|
||||
} else {
|
||||
rampUp = rampUps.toString();
|
||||
}
|
||||
int realHold = Integer.parseInt(duration) - Integer.parseInt(rampUp);
|
||||
threadGroup.appendChild(createStringProp(document, "ThreadGroup.on_sample_error", "continue"));
|
||||
threadGroup.appendChild(createStringProp(document, "TargetLevel", "2"));
|
||||
|
@ -803,9 +817,18 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
</collectionProp>
|
||||
</kg.apc.jmeter.timers.VariableThroughputTimer>
|
||||
*/
|
||||
if (context.getProperty("rpsLimitEnable") == null || StringUtils.equals(context.getProperty("rpsLimitEnable").toString(), "false")) {
|
||||
if (context.getProperty("rpsLimitEnable") == null) {
|
||||
return;
|
||||
}
|
||||
Object rpsLimitEnables = context.getProperty("rpsLimitEnable");
|
||||
if (rpsLimitEnables instanceof List) {
|
||||
Object o = ((List<?>) rpsLimitEnables).get(0);
|
||||
((List<?>) rpsLimitEnables).remove(0);
|
||||
if (o == null || "false".equals(o.toString())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Document document = element.getOwnerDocument();
|
||||
|
||||
|
||||
|
@ -866,11 +889,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
if (nodeNameEquals(ele, STRING_PROP)) {
|
||||
parseStringProp(ele);
|
||||
}
|
||||
|
||||
// 设置具体的线程数
|
||||
if (nodeNameEquals(ele, STRING_PROP) && "TargetLevel".equals(ele.getAttribute("name"))) {
|
||||
ele.getFirstChild().setNodeValue(context.getThreadNum().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -902,11 +920,28 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
stringPropCount++;
|
||||
} else {
|
||||
stringPropCount = 0;
|
||||
Integer duration = (Integer) context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数
|
||||
Object durations = context.getProperty("duration");// 传入的是分钟数, 需要转化成秒数
|
||||
Integer duration;
|
||||
if (durations instanceof List) {
|
||||
Object o = ((List<?>) durations).get(0);
|
||||
duration = (Integer) o;
|
||||
((List<?>) durations).remove(0);
|
||||
} else {
|
||||
duration = (Integer) durations;
|
||||
}
|
||||
prop.getFirstChild().setNodeValue(String.valueOf(duration * 60));
|
||||
continue;
|
||||
}
|
||||
prop.getFirstChild().setNodeValue(context.getProperty("rpsLimit").toString());
|
||||
Object rpsLimits = context.getProperty("rpsLimit");
|
||||
String rpsLimit;
|
||||
if (rpsLimits instanceof List) {
|
||||
Object o = ((List<?>) rpsLimits).get(0);
|
||||
((List<?>) rpsLimits).remove(0);
|
||||
rpsLimit = o.toString();
|
||||
} else {
|
||||
rpsLimit = rpsLimits.toString();
|
||||
}
|
||||
prop.getFirstChild().setNodeValue(rpsLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -920,8 +955,15 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
}
|
||||
|
||||
private void parseStringProp(Element stringProp) {
|
||||
if (stringProp.getChildNodes().getLength() > 0 && context.getProperty(stringProp.getAttribute("name")) != null) {
|
||||
stringProp.getFirstChild().setNodeValue(context.getProperty(stringProp.getAttribute("name")).toString());
|
||||
Object threadParams = context.getProperty(stringProp.getAttribute("name"));
|
||||
if (stringProp.getChildNodes().getLength() > 0 && threadParams != null) {
|
||||
if (threadParams instanceof List) {
|
||||
Object o = ((List<?>) threadParams).get(0);
|
||||
((List<?>) threadParams).remove(0);
|
||||
stringProp.getFirstChild().setNodeValue(o.toString());
|
||||
} else {
|
||||
stringProp.getFirstChild().setNodeValue(threadParams.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -345,6 +345,17 @@ public class PerformanceTestService {
|
|||
return Optional.ofNullable(loadTestWithBLOBs).orElse(new LoadTestWithBLOBs()).getLoadConfiguration();
|
||||
}
|
||||
|
||||
public String getJmxContent(String testId) {
|
||||
List<FileMetadata> fileMetadataList = fileService.getFileMetadataByTestId(testId);
|
||||
for (FileMetadata metadata : fileMetadataList) {
|
||||
if (FileType.JMX.name().equals(metadata.getType())) {
|
||||
FileContent fileContent = fileService.getFileContent(metadata.getId());
|
||||
return new String(fileContent.getFile());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<LoadTestWithBLOBs> selectByTestResourcePoolId(String resourcePoolId) {
|
||||
LoadTestExample example = new LoadTestExample();
|
||||
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePoolId);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 24047fea950a74f7848a9fdaa857a22b884c4ce2
|
||||
Subproject commit 57d6f78efa4b0300be188e8b024511ceef0873ed
|
|
@ -37,7 +37,8 @@
|
|||
"nprogress": "^0.2.0",
|
||||
"el-table-infinite-scroll": "^1.0.10",
|
||||
"vue-pdf": "^4.2.0",
|
||||
"diffable-html": "^4.0.0"
|
||||
"diffable-html": "^4.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
|
|
|
@ -1,98 +1,81 @@
|
|||
<template>
|
||||
<div v-loading="result.loading" class="pressure-config-container">
|
||||
<el-row>
|
||||
<el-col :span="10">
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.thread_num') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.input_thread_num')"
|
||||
v-model="threadNumber"
|
||||
@change="calculateChart"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.duration') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.duration')"
|
||||
v-model="duration"
|
||||
:min="1"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.rps_limit') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-switch v-model="rpsLimitEnable" :disabled="true"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.input_rps_limit')"
|
||||
v-model="rpsLimit"
|
||||
@change="calculateChart"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form :inline="true" class="input-bottom-border">
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_within') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="duration"
|
||||
v-model="rampUpTime"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_minutes') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="Math.min(threadNumber, rampUpTime)"
|
||||
v-model="step"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_times') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<el-col>
|
||||
<ms-chart class="chart-container" ref="chart1" :options="orgOptions" :autoresize="true"></ms-chart>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-collapse v-model="activeNames">
|
||||
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
||||
v-for="(threadGroup, index) in threadGroups"
|
||||
:key="index">
|
||||
<el-col :span="10">
|
||||
<el-form :inline="true">
|
||||
<el-form-item :label="$t('load_test.thread_num')">
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.input_thread_num')"
|
||||
v-model="threadGroup.threadNumber"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.duration')">
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.duration')"
|
||||
v-model="threadGroup.duration"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.rps_limit')">
|
||||
<el-switch v-model="rpsLimitEnable"/>
|
||||
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
:placeholder="$t('load_test.input_rps_limit')"
|
||||
v-model="threadGroup.rpsLimit"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="threadGroup.duration"
|
||||
v-model="threadGroup.rampUpTime"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
||||
<el-input-number
|
||||
:disabled="true"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
||||
v-model="threadGroup.step"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<ms-chart class="chart-container" :options="threadGroup.orgOptions" :autoresize="true"></ms-chart>
|
||||
</el-col>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
||||
|
||||
const TARGET_LEVEL = "TargetLevel";
|
||||
const RAMP_UP = "RampUp";
|
||||
|
@ -108,62 +91,91 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
threadNumber: 10,
|
||||
duration: 10,
|
||||
rampUpTime: 10,
|
||||
step: 10,
|
||||
rpsLimit: 10,
|
||||
threadNumber: 0,
|
||||
duration: 0,
|
||||
rampUpTime: 0,
|
||||
step: 0,
|
||||
rpsLimit: 0,
|
||||
rpsLimitEnable: false,
|
||||
orgOptions: {},
|
||||
resourcePool: null,
|
||||
resourcePools: [],
|
||||
activeNames: ["0"],
|
||||
threadGroups: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getLoadConfig();
|
||||
// this.getJmxContent();
|
||||
},
|
||||
methods: {
|
||||
calculateLoadConfiguration: function (data) {
|
||||
data.forEach(d => {
|
||||
switch (d.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadNumber = d.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.rampUpTime = d.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.duration = d.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.step = d.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.rpsLimit = d.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let d = data[i];
|
||||
if (d instanceof Array) {
|
||||
d.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 DURATION:
|
||||
this.threadGroups[i].duration = 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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
this.calculateChart(this.threadGroups[i]);
|
||||
} else {
|
||||
switch (d.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadGroups[0].threadNumber = d.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.threadGroups[0].rampUpTime = d.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.threadGroups[0].duration = d.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.threadGroups[0].step = d.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.threadGroups[0].rpsLimit = d.value;
|
||||
break;
|
||||
case RPS_LIMIT_ENABLE:
|
||||
this.threadGroups[0].rpsLimitEnable = d.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.calculateChart(this.threadGroups[0]);
|
||||
}
|
||||
});
|
||||
|
||||
this.threadNumber = this.threadNumber || 10;
|
||||
this.duration = this.duration || 30;
|
||||
this.rampUpTime = this.rampUpTime || 12;
|
||||
this.step = this.step || 3;
|
||||
this.rpsLimit = this.rpsLimit || 10;
|
||||
|
||||
this.calculateChart();
|
||||
}
|
||||
},
|
||||
getLoadConfig() {
|
||||
if (!this.report.id) {
|
||||
return;
|
||||
}
|
||||
this.$get("/performance/report/" + this.report.id, res => {
|
||||
this.result = this.$get("/performance/report/" + this.report.id, res => {
|
||||
let data = res.data;
|
||||
if (data) {
|
||||
if (data.loadConfiguration) {
|
||||
let d = JSON.parse(data.loadConfiguration);
|
||||
this.calculateLoadConfiguration(d);
|
||||
} else {
|
||||
this.$get('/performance/get-load-config/' + this.report.testId, (response) => {
|
||||
this.$get('/performance/get-load-config/' + this.report.id, (response) => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data);
|
||||
this.calculateLoadConfiguration(data);
|
||||
|
@ -175,14 +187,30 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
calculateChart() {
|
||||
if (this.duration < this.rampUpTime) {
|
||||
this.rampUpTime = this.duration;
|
||||
getJmxContent() {
|
||||
console.log(this.report.testId);
|
||||
if (!this.report.testId) {
|
||||
return;
|
||||
}
|
||||
if (this.rampUpTime < this.step) {
|
||||
this.step = this.rampUpTime;
|
||||
this.result = this.$get('/performance/get-jmx-content/' + this.report.testId, (response) => {
|
||||
if (response.data) {
|
||||
this.threadGroups = findThreadGroup(response.data);
|
||||
this.threadGroups.forEach(tg => {
|
||||
tg.orgOptions = {};
|
||||
});
|
||||
this.getLoadConfig();
|
||||
}
|
||||
});
|
||||
},
|
||||
calculateTotalChart() {
|
||||
let handler = this;
|
||||
if (handler.duration < handler.rampUpTime) {
|
||||
handler.rampUpTime = handler.duration;
|
||||
}
|
||||
this.orgOptions = {
|
||||
if (handler.rampUpTime < handler.step) {
|
||||
handler.step = handler.rampUpTime;
|
||||
}
|
||||
handler.orgOptions = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
|
@ -235,16 +263,130 @@ export default {
|
|||
},
|
||||
}]
|
||||
};
|
||||
let timePeriod = Math.floor(this.rampUpTime / this.step);
|
||||
let threads = [];
|
||||
for (let i = 0; i < handler.threadGroups.length; i++) {
|
||||
let tg = handler.threadGroups[i];
|
||||
threads[i] = [];
|
||||
|
||||
let timePeriod = Math.floor(tg.rampUpTime / tg.step);
|
||||
let timeInc = timePeriod;
|
||||
|
||||
let threadPeriod = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc1 = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc2 = Math.ceil(tg.threadNumber / tg.step);
|
||||
let inc2count = tg.threadNumber - tg.step * threadInc1;
|
||||
for (let j = 0; j <= tg.duration; j++) {
|
||||
|
||||
if (j > timePeriod) {
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
threadPeriod = threadPeriod + threadInc2;
|
||||
inc2count--;
|
||||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > tg.threadNumber) {
|
||||
threadPeriod = tg.threadNumber;
|
||||
}
|
||||
}
|
||||
// x 轴
|
||||
let xAxis = handler.orgOptions.xAxis.data;
|
||||
if (xAxis.indexOf(j) < 0) {
|
||||
xAxis.push(j);
|
||||
}
|
||||
threads[i].push(threadPeriod);
|
||||
}
|
||||
}
|
||||
let maxLength = 0;
|
||||
for (let i = 0; i < threads.length; i++) {
|
||||
if (maxLength < threads[i].length) {
|
||||
maxLength = threads[i].length;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
let temp = 0;
|
||||
for (let j = 0; j < threads.length; j++) {
|
||||
if (threads[j].length <= maxLength) {
|
||||
temp += threads[j][i] || 0;
|
||||
}
|
||||
}
|
||||
handler.orgOptions.series[0].data.push(temp);
|
||||
}
|
||||
},
|
||||
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.orgOptions = {
|
||||
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: {
|
||||
normal: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(137, 189, 27, 0.3)'
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: 'rgba(137, 189, 27, 0)'
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
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(this.threadNumber / this.step);
|
||||
let threadInc1 = Math.floor(this.threadNumber / this.step);
|
||||
let threadInc2 = Math.ceil(this.threadNumber / this.step);
|
||||
let inc2count = this.threadNumber - this.step * threadInc1;
|
||||
for (let i = 0; i <= this.duration; i++) {
|
||||
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 轴
|
||||
this.orgOptions.xAxis.data.push(i);
|
||||
handler.orgOptions.xAxis.data.push(i);
|
||||
if (i > timePeriod) {
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
|
@ -253,25 +395,22 @@ export default {
|
|||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > this.threadNumber) {
|
||||
threadPeriod = this.threadNumber;
|
||||
if (threadPeriod > handler.threadNumber) {
|
||||
threadPeriod = handler.threadNumber;
|
||||
}
|
||||
this.orgOptions.series[0].data.push(threadPeriod);
|
||||
handler.orgOptions.series[0].data.push(threadPeriod);
|
||||
} else {
|
||||
this.orgOptions.series[0].data.push(threadPeriod);
|
||||
handler.orgOptions.series[0].data.push(threadPeriod);
|
||||
}
|
||||
}
|
||||
this.calculateTotalChart();
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
report: {
|
||||
handler(val) {
|
||||
if (!val.testId) {
|
||||
return;
|
||||
}
|
||||
this.getLoadConfig();
|
||||
'report.testId': {
|
||||
handler() {
|
||||
this.getJmxContent();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +434,7 @@ export default {
|
|||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.el-col .el-form {
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
|
||||
<el-tabs class="testplan-config" v-model="active" type="border-card" :stretch="true">
|
||||
<el-tab-pane :label="$t('load_test.basic_config')">
|
||||
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"/>
|
||||
<performance-basic-config :is-read-only="isReadOnly" :test-plan="testPlan" ref="basicConfig"
|
||||
@fileChange="fileChange"/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('load_test.pressure_config')">
|
||||
<performance-pressure-config :is-read-only="isReadOnly" :test-plan="testPlan" :test-id="testId"
|
||||
|
@ -304,6 +305,18 @@ export default {
|
|||
return {
|
||||
pass: true
|
||||
}
|
||||
},
|
||||
fileChange(threadGroups) {
|
||||
let handler = this.$refs.pressureConfig;
|
||||
handler.threadGroups = threadGroups;
|
||||
threadGroups.forEach(tg => {
|
||||
tg.threadNumber = tg.threadNumber || 10;
|
||||
tg.duration = tg.duration || 10;
|
||||
tg.rampUpTime = tg.rampUpTime || 5;
|
||||
tg.step = tg.step || 5;
|
||||
tg.rpsLimit = tg.rpsLimit || 10;
|
||||
handler.calculateChart(tg);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
|
||||
<script>
|
||||
import {Message} from "element-ui";
|
||||
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
||||
|
||||
export default {
|
||||
name: "PerformanceBasicConfig",
|
||||
|
@ -90,6 +91,19 @@ export default {
|
|||
if (this.testPlan.id) {
|
||||
this.getFileMetadata(this.testPlan)
|
||||
}
|
||||
},
|
||||
uploadList() {
|
||||
let self = this;
|
||||
let fileList = self.uploadList.filter(f => f.name.endsWith(".jmx"));
|
||||
if (fileList.length > 0) {
|
||||
let file = fileList[0];
|
||||
let jmxReader = new FileReader();
|
||||
jmxReader.onload = function (event) {
|
||||
let threadGroups = findThreadGroup(event.target.result);
|
||||
self.$emit('fileChange', threadGroups);
|
||||
};
|
||||
jmxReader.readAsText(file);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,91 +1,9 @@
|
|||
<template>
|
||||
<div v-loading="result.loading" class="pressure-config-container">
|
||||
<el-row>
|
||||
<el-col :span="10">
|
||||
<el-col>
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.thread_num') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:placeholder="$t('load_test.input_thread_num')"
|
||||
v-model="threadNumber"
|
||||
@change="calculateChart"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.duration') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:placeholder="$t('load_test.duration')"
|
||||
v-model="duration"
|
||||
:min="1"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true">
|
||||
<el-form-item>
|
||||
<el-form-item>
|
||||
<div class="config-form-label">{{ $t('load_test.rps_limit') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-switch v-model="rpsLimitEnable"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="isReadOnly || !rpsLimitEnable"
|
||||
:placeholder="$t('load_test.input_rps_limit')"
|
||||
v-model="rpsLimit"
|
||||
@change="calculateChart"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-form :inline="true" class="input-bottom-border">
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_within') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="duration"
|
||||
v-model="rampUpTime"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_minutes') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="Math.min(threadNumber, rampUpTime)"
|
||||
v-model="step"
|
||||
@change="calculateChart"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.ramp_up_time_times') }}</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-form :inline="true" class="input-bottom-border">
|
||||
<el-form-item>
|
||||
<div>{{ $t('load_test.select_resource_pool') }}</div>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-form-item :label="$t('load_test.select_resource_pool')">
|
||||
<el-select v-model="resourcePool" :disabled="isReadOnly" size="mini">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
|
@ -96,18 +14,85 @@
|
|||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<ms-chart class="chart-container" ref="chart1" :options="orgOptions" :autoresize="true"></ms-chart>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-collapse v-model="activeNames">
|
||||
<el-collapse-item :title="threadGroup.attributes.testname" :name="index"
|
||||
v-for="(threadGroup, index) in threadGroups"
|
||||
:key="index">
|
||||
<el-col :span="10">
|
||||
<el-form :inline="true">
|
||||
<el-form-item :label="$t('load_test.thread_num')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:placeholder="$t('load_test.input_thread_num')"
|
||||
v-model="threadGroup.threadNumber"
|
||||
@change="calculateChart(threadGroup)"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.duration')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
:placeholder="$t('load_test.duration')"
|
||||
v-model="threadGroup.duration"
|
||||
:min="1"
|
||||
@change="calculateChart(threadGroup)"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.rps_limit')">
|
||||
<el-switch v-model="rpsLimitEnable"/>
|
||||
|
||||
<el-input-number
|
||||
:disabled="isReadOnly || !threadGroup.rpsLimitEnable"
|
||||
:placeholder="$t('load_test.input_rps_limit')"
|
||||
v-model="threadGroup.rpsLimit"
|
||||
@change="calculateChart(threadGroup)"
|
||||
:min="1"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_within')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="threadGroup.duration"
|
||||
v-model="threadGroup.rampUpTime"
|
||||
@change="calculateChart(threadGroup)"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_minutes')">
|
||||
<el-input-number
|
||||
:disabled="isReadOnly"
|
||||
placeholder=""
|
||||
:min="1"
|
||||
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
|
||||
v-model="threadGroup.step"
|
||||
@change="calculateChart(threadGroup)"
|
||||
size="mini"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.ramp_up_time_times')"/>
|
||||
</el-form>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="title">{{ $t('load_test.pressure_prediction_chart') }}</div>
|
||||
<ms-chart class="chart-container" :options="threadGroup.orgOptions" :autoresize="true"></ms-chart>
|
||||
</el-col>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import echarts from "echarts";
|
||||
import MsChart from "@/business/components/common/chart/MsChart";
|
||||
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
|
||||
|
||||
const TARGET_LEVEL = "TargetLevel";
|
||||
const RAMP_UP = "RampUp";
|
||||
|
@ -134,22 +119,24 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
threadNumber: 10,
|
||||
duration: 10,
|
||||
rampUpTime: 10,
|
||||
step: 10,
|
||||
rpsLimit: 10,
|
||||
threadNumber: 0,
|
||||
duration: 0,
|
||||
rampUpTime: 0,
|
||||
step: 0,
|
||||
rpsLimit: 0,
|
||||
rpsLimitEnable: false,
|
||||
orgOptions: {},
|
||||
resourcePool: null,
|
||||
resourcePools: [],
|
||||
activeNames: ["0"],
|
||||
threadGroups: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.testId) {
|
||||
this.getLoadConfig();
|
||||
this.getJmxContent();
|
||||
} else {
|
||||
this.calculateChart();
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
this.resourcePool = this.testPlan.testResourcePoolId;
|
||||
this.getResourcePools();
|
||||
|
@ -160,9 +147,9 @@ export default {
|
|||
},
|
||||
testId() {
|
||||
if (this.testId) {
|
||||
this.getLoadConfig();
|
||||
this.getJmxContent();
|
||||
} else {
|
||||
this.calculateChart();
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
this.getResourcePools();
|
||||
},
|
||||
|
@ -178,56 +165,89 @@ export default {
|
|||
})
|
||||
},
|
||||
getLoadConfig() {
|
||||
if (this.testId) {
|
||||
|
||||
this.$get('/performance/get-load-config/' + this.testId, (response) => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data);
|
||||
|
||||
data.forEach(d => {
|
||||
this.$get('/performance/get-load-config/' + this.testId, (response) => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let d = data[i];
|
||||
if (d instanceof Array) {
|
||||
d.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 DURATION:
|
||||
this.threadGroups[i].duration = 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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
this.calculateChart(this.threadGroups[i]);
|
||||
} else {
|
||||
switch (d.key) {
|
||||
case TARGET_LEVEL:
|
||||
this.threadNumber = d.value;
|
||||
this.threadGroups[0].threadNumber = d.value;
|
||||
break;
|
||||
case RAMP_UP:
|
||||
this.rampUpTime = d.value;
|
||||
this.threadGroups[0].rampUpTime = d.value;
|
||||
break;
|
||||
case DURATION:
|
||||
this.duration = d.value;
|
||||
this.threadGroups[0].duration = d.value;
|
||||
break;
|
||||
case STEPS:
|
||||
this.step = d.value;
|
||||
this.threadGroups[0].step = d.value;
|
||||
break;
|
||||
case RPS_LIMIT:
|
||||
this.rpsLimit = d.value;
|
||||
this.threadGroups[0].rpsLimit = d.value;
|
||||
break;
|
||||
case RPS_LIMIT_ENABLE:
|
||||
this.rpsLimitEnable = d.value;
|
||||
this.threadGroups[0].rpsLimitEnable = d.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.calculateChart(this.threadGroups[0]);
|
||||
}
|
||||
}
|
||||
this.calculateTotalChart();
|
||||
}
|
||||
});
|
||||
},
|
||||
getJmxContent() {
|
||||
if (this.testId) {
|
||||
this.$get('/performance/get-jmx-content/' + this.testId, (response) => {
|
||||
if (response.data) {
|
||||
this.threadGroups = findThreadGroup(response.data);
|
||||
this.threadGroups.forEach(tg => {
|
||||
tg.orgOptions = {};
|
||||
});
|
||||
|
||||
this.threadNumber = this.threadNumber || 10;
|
||||
this.duration = this.duration || 30;
|
||||
this.rampUpTime = this.rampUpTime || 12;
|
||||
this.step = this.step || 3;
|
||||
this.rpsLimit = this.rpsLimit || 10;
|
||||
|
||||
this.calculateChart();
|
||||
this.getLoadConfig();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
calculateChart() {
|
||||
if (this.duration < this.rampUpTime) {
|
||||
this.rampUpTime = this.duration;
|
||||
calculateTotalChart() {
|
||||
let handler = this;
|
||||
if (handler.duration < handler.rampUpTime) {
|
||||
handler.rampUpTime = handler.duration;
|
||||
}
|
||||
if (this.rampUpTime < this.step) {
|
||||
this.step = this.rampUpTime;
|
||||
if (handler.rampUpTime < handler.step) {
|
||||
handler.step = handler.rampUpTime;
|
||||
}
|
||||
this.orgOptions = {
|
||||
handler.orgOptions = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
|
@ -280,16 +300,130 @@ export default {
|
|||
},
|
||||
}]
|
||||
};
|
||||
let timePeriod = Math.floor(this.rampUpTime / this.step);
|
||||
let threads = [];
|
||||
for (let i = 0; i < handler.threadGroups.length; i++) {
|
||||
let tg = handler.threadGroups[i];
|
||||
threads[i] = [];
|
||||
|
||||
let timePeriod = Math.floor(tg.rampUpTime / tg.step);
|
||||
let timeInc = timePeriod;
|
||||
|
||||
let threadPeriod = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc1 = Math.floor(tg.threadNumber / tg.step);
|
||||
let threadInc2 = Math.ceil(tg.threadNumber / tg.step);
|
||||
let inc2count = tg.threadNumber - tg.step * threadInc1;
|
||||
for (let j = 0; j <= tg.duration; j++) {
|
||||
|
||||
if (j > timePeriod) {
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
threadPeriod = threadPeriod + threadInc2;
|
||||
inc2count--;
|
||||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > tg.threadNumber) {
|
||||
threadPeriod = tg.threadNumber;
|
||||
}
|
||||
}
|
||||
// x 轴
|
||||
let xAxis = handler.orgOptions.xAxis.data;
|
||||
if (xAxis.indexOf(j) < 0) {
|
||||
xAxis.push(j);
|
||||
}
|
||||
threads[i].push(threadPeriod);
|
||||
}
|
||||
}
|
||||
let maxLength = 0;
|
||||
for (let i = 0; i < threads.length; i++) {
|
||||
if (maxLength < threads[i].length) {
|
||||
maxLength = threads[i].length;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < maxLength; i++) {
|
||||
let temp = 0;
|
||||
for (let j = 0; j < threads.length; j++) {
|
||||
if (threads[j].length <= maxLength) {
|
||||
temp += threads[j][i] || 0;
|
||||
}
|
||||
}
|
||||
handler.orgOptions.series[0].data.push(temp);
|
||||
}
|
||||
},
|
||||
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.orgOptions = {
|
||||
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: {
|
||||
normal: {
|
||||
width: 1
|
||||
}
|
||||
},
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(137, 189, 27, 0.3)'
|
||||
}, {
|
||||
offset: 0.8,
|
||||
color: 'rgba(137, 189, 27, 0)'
|
||||
}], false),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
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(this.threadNumber / this.step);
|
||||
let threadInc1 = Math.floor(this.threadNumber / this.step);
|
||||
let threadInc2 = Math.ceil(this.threadNumber / this.step);
|
||||
let inc2count = this.threadNumber - this.step * threadInc1;
|
||||
for (let i = 0; i <= this.duration; i++) {
|
||||
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 轴
|
||||
this.orgOptions.xAxis.data.push(i);
|
||||
handler.orgOptions.xAxis.data.push(i);
|
||||
if (i > timePeriod) {
|
||||
timePeriod += timeInc;
|
||||
if (inc2count > 0) {
|
||||
|
@ -298,14 +432,15 @@ export default {
|
|||
} else {
|
||||
threadPeriod = threadPeriod + threadInc1;
|
||||
}
|
||||
if (threadPeriod > this.threadNumber) {
|
||||
threadPeriod = this.threadNumber;
|
||||
if (threadPeriod > handler.threadNumber) {
|
||||
threadPeriod = handler.threadNumber;
|
||||
}
|
||||
this.orgOptions.series[0].data.push(threadPeriod);
|
||||
handler.orgOptions.series[0].data.push(threadPeriod);
|
||||
} else {
|
||||
this.orgOptions.series[0].data.push(threadPeriod);
|
||||
handler.orgOptions.series[0].data.push(threadPeriod);
|
||||
}
|
||||
}
|
||||
this.calculateTotalChart();
|
||||
},
|
||||
validConfig() {
|
||||
if (!this.resourcePool) {
|
||||
|
@ -315,24 +450,31 @@ export default {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!this.threadNumber || !this.duration || !this.rampUpTime || !this.step || !this.rpsLimit) {
|
||||
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||
this.$emit('changeActive', '1');
|
||||
return false;
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
if (!this.threadGroups[i].threadNumber || !this.threadGroups[i].duration
|
||||
|| !this.threadGroups[i].rampUpTime || !this.threadGroups[i].step || !this.threadGroups[i].rpsLimit) {
|
||||
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
|
||||
this.$emit('changeActive', '1');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
convertProperty() {
|
||||
/// todo:下面4个属性是jmeter ConcurrencyThreadGroup plugin的属性,这种硬编码不太好吧,在哪能转换这种属性?
|
||||
return [
|
||||
{key: TARGET_LEVEL, value: this.threadNumber},
|
||||
{key: RAMP_UP, value: this.rampUpTime},
|
||||
{key: STEPS, value: this.step},
|
||||
{key: DURATION, value: this.duration},
|
||||
{key: RPS_LIMIT, value: this.rpsLimit},
|
||||
{key: RPS_LIMIT_ENABLE, value: this.rpsLimitEnable},
|
||||
];
|
||||
let result = [];
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
result.push([
|
||||
{key: TARGET_LEVEL, value: this.threadGroups[i].threadNumber},
|
||||
{key: RAMP_UP, value: this.threadGroups[i].rampUpTime},
|
||||
{key: STEPS, value: this.threadGroups[i].step},
|
||||
{key: DURATION, value: this.threadGroups[i].duration},
|
||||
{key: RPS_LIMIT, value: this.threadGroups[i].rpsLimit},
|
||||
{key: RPS_LIMIT_ENABLE, value: this.threadGroups[i].rpsLimitEnable},
|
||||
]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,6 +498,7 @@ export default {
|
|||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.el-col .el-form {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import {xml2json} from "xml-js";
|
||||
|
||||
let travel = function (elements, threadGroups) {
|
||||
if (!elements) {
|
||||
return;
|
||||
}
|
||||
for (let element of elements) {
|
||||
if (element.name === 'ThreadGroup') {
|
||||
threadGroups.push(element);
|
||||
}
|
||||
travel(element.elements, threadGroups)
|
||||
}
|
||||
}
|
||||
|
||||
export function findThreadGroup(jmxContent) {
|
||||
let jmxJson = JSON.parse(xml2json(jmxContent));
|
||||
let threadGroups = [];
|
||||
travel(jmxJson.elements, threadGroups);
|
||||
return threadGroups;
|
||||
}
|
Loading…
Reference in New Issue