fix(性能测试): 压力配置上可以选择场景是否顺序执行
This commit is contained in:
parent
c7c55541f0
commit
b4d8c693ba
|
@ -41,6 +41,7 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
private final static String RESPONSE_ASSERTION = "ResponseAssertion";
|
||||
private final static String CSV_DATA_SET = "CSVDataSet";
|
||||
private EngineContext context;
|
||||
private boolean containsIterationThread = false;
|
||||
|
||||
@Override
|
||||
public String parse(EngineContext context, Document document) throws Exception {
|
||||
|
@ -96,10 +97,10 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
processCheckoutArguments(ele);
|
||||
processCheckoutResponseAssertion(ele);
|
||||
processCheckoutSerializeThreadgroups(ele);
|
||||
processCheckoutBackendListener(ele);
|
||||
} else if (nodeNameEquals(ele, CONCURRENCY_THREAD_GROUP)) {
|
||||
processThreadGroupName(ele);
|
||||
processCheckoutTimer(ele);
|
||||
processCheckoutBackendListener(ele);
|
||||
} else if (nodeNameEquals(ele, VARIABLE_THROUGHPUT_TIMER)) {
|
||||
processVariableThroughputTimer(ele);
|
||||
} else if (nodeNameEquals(ele, THREAD_GROUP)) {
|
||||
|
@ -112,6 +113,7 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
}
|
||||
if ("ITERATION".equals(o)) {
|
||||
processIterationThreadGroup(ele);
|
||||
this.containsIterationThread = true; // 包括按照迭代次数的线程组
|
||||
}
|
||||
} else {
|
||||
processThreadGroup(ele);
|
||||
|
@ -119,7 +121,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
|
||||
processThreadGroupName(ele);
|
||||
processCheckoutTimer(ele);
|
||||
processCheckoutBackendListener(ele);
|
||||
} else if (nodeNameEquals(ele, BACKEND_LISTENER)) {
|
||||
processBackendListener(ele);
|
||||
} else if (nodeNameEquals(ele, CONFIG_TEST_ELEMENT)) {
|
||||
|
@ -144,14 +145,19 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
}
|
||||
|
||||
private void processCheckoutSerializeThreadgroups(Element element) {
|
||||
Object serializeThreadGroups = context.getProperty("serializeThreadGroups");
|
||||
String serializeThreadGroup = "false";
|
||||
if (serializeThreadGroups instanceof List) {
|
||||
Object o = ((List<?>) serializeThreadGroups).get(0);
|
||||
serializeThreadGroup = o.toString();
|
||||
}
|
||||
NodeList childNodes = element.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node item = childNodes.item(i);
|
||||
if (nodeNameEquals(item, BOOL_PROP)) {
|
||||
String serializeName = ((Element) item).getAttribute("name");
|
||||
if (StringUtils.equals(serializeName, "TestPlan.serialize_threadgroups")) {
|
||||
// 保存线程组是否是顺序执行
|
||||
context.addProperty("serialize_threadgroups", item.getTextContent());
|
||||
item.setTextContent(serializeThreadGroup);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -542,6 +548,15 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
}
|
||||
|
||||
private void processBackendListener(Element backendListener) {
|
||||
String duration = "0";
|
||||
Object expectedDurations = context.getProperty("expectedDuration");
|
||||
if (expectedDurations instanceof List) {
|
||||
Object o = ((List<?>) expectedDurations).get(0);// 预计执行时间已经计算好
|
||||
duration = o.toString() + "000"; // 转成 ms
|
||||
}
|
||||
if (this.containsIterationThread) {
|
||||
duration = Integer.MAX_VALUE + ""; // 如果包含了按照迭代次数的线程组,预计执行时间很长
|
||||
}
|
||||
KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class);
|
||||
Document document = backendListener.getOwnerDocument();
|
||||
// 清空child
|
||||
|
@ -586,7 +601,7 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
collectionProp.appendChild(createKafkaProp(document, "test.name", context.getTestName()));
|
||||
collectionProp.appendChild(createKafkaProp(document, "test.startTime", context.getStartTime().toString()));
|
||||
collectionProp.appendChild(createKafkaProp(document, "test.reportId", context.getReportId()));
|
||||
collectionProp.appendChild(createKafkaProp(document, "test.expectedDuration", (String) context.getProperty("expectedDuration")));
|
||||
collectionProp.appendChild(createKafkaProp(document, "test.expectedDuration", duration));// ms
|
||||
collectionProp.appendChild(createKafkaProp(document, "test.expectedDelayEndTime", kafkaProperties.getExpectedDelayEndTime())); // 30s
|
||||
|
||||
elementProp.appendChild(collectionProp);
|
||||
|
@ -612,15 +627,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
listenerParent = listenerParent.getNextSibling();
|
||||
}
|
||||
|
||||
NodeList childNodes = listenerParent.getChildNodes();
|
||||
for (int i = 0, l = childNodes.getLength(); i < l; i++) {
|
||||
Node item = childNodes.item(i);
|
||||
if (nodeNameEquals(item, BACKEND_LISTENER)) {
|
||||
// 如果已经存在,不再添加
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add class name
|
||||
Element backendListener = document.createElement(BACKEND_LISTENER);
|
||||
backendListener.setAttribute("guiclass", "BackendListenerGui");
|
||||
|
@ -729,8 +735,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
// 处理预计结束时间
|
||||
processExpectedDuration(duration);
|
||||
|
||||
threadGroup.setAttribute("enabled", enabled);
|
||||
if (BooleanUtils.toBoolean(deleted)) {
|
||||
|
@ -824,30 +828,18 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
enabled = o.toString();
|
||||
}
|
||||
|
||||
Object durations = context.getProperty("duration");
|
||||
String duration = "2";
|
||||
if (durations instanceof List) {
|
||||
Object o = ((List<?>) durations).get(0);
|
||||
((List<?>) durations).remove(0);
|
||||
duration = o.toString();
|
||||
}
|
||||
|
||||
switch (unit) {
|
||||
case "M":
|
||||
duration = String.valueOf(Long.parseLong(duration) * 60);
|
||||
hold = String.valueOf(Long.parseLong(hold) * 60);
|
||||
rampUp = String.valueOf(Long.parseLong(rampUp) * 60);
|
||||
break;
|
||||
case "H":
|
||||
duration = String.valueOf(Long.parseLong(duration) * 60 * 60);
|
||||
hold = String.valueOf(Long.parseLong(hold) * 60 * 60);
|
||||
rampUp = String.valueOf(Long.parseLong(rampUp) * 60 * 60);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// 处理预计结束时间
|
||||
processExpectedDuration(duration);
|
||||
|
||||
threadGroup.setAttribute("enabled", enabled);
|
||||
if (BooleanUtils.toBoolean(deleted)) {
|
||||
|
@ -868,26 +860,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
threadGroup.appendChild(createStringProp(document, "Unit", "S"));
|
||||
}
|
||||
|
||||
private void processExpectedDuration(String duration) {
|
||||
Long d = Long.parseLong(duration);
|
||||
Object serialize = context.getProperty("serialize_threadgroups");
|
||||
String expectedDuration = (String) context.getProperty("expectedDuration");
|
||||
if (StringUtils.isBlank(expectedDuration)) {
|
||||
expectedDuration = "0";
|
||||
}
|
||||
long durationTime = Long.parseLong(expectedDuration);
|
||||
|
||||
if (BooleanUtils.toBoolean((String) serialize)) {
|
||||
// 顺序执行线程组
|
||||
context.addProperty("expectedDuration", String.valueOf(durationTime + d * 1000));
|
||||
} else {
|
||||
// 同时执行线程组
|
||||
if (durationTime < d * 1000) {
|
||||
context.addProperty("expectedDuration", String.valueOf(d * 1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processIterationThreadGroup(Element threadGroup) {
|
||||
// 检查 threadgroup 后面的hashtree是否为空
|
||||
Node hashTree = threadGroup.getNextSibling();
|
||||
|
@ -956,10 +928,6 @@ public class JmeterDocumentParser implements DocumentParser {
|
|||
threadGroup.appendChild(createStringProp(document, "ThreadGroup.duration", "10"));
|
||||
threadGroup.appendChild(createStringProp(document, "ThreadGroup.delay", ""));
|
||||
threadGroup.appendChild(createBoolProp(document, "ThreadGroup.same_user_on_next_iteration", true));
|
||||
|
||||
// 处理预计结束时间, (按照迭代次数 * 线程数)s
|
||||
String duration = String.valueOf(Long.parseLong(loops) * Long.parseLong(threads));
|
||||
processExpectedDuration(duration);
|
||||
}
|
||||
|
||||
private void processCheckoutTimer(Element element) {
|
||||
|
|
|
@ -229,30 +229,6 @@ export default {
|
|||
}
|
||||
};
|
||||
},
|
||||
stringToByte(str) {
|
||||
var bytes = new Array();
|
||||
var len, c;
|
||||
len = str.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
c = str.charCodeAt(i);
|
||||
if (c >= 0x010000 && c <= 0x10FFFF) {
|
||||
bytes.push(((c >> 18) & 0x07) | 0xF0);
|
||||
bytes.push(((c >> 12) & 0x3F) | 0x80);
|
||||
bytes.push(((c >> 6) & 0x3F) | 0x80);
|
||||
bytes.push((c & 0x3F) | 0x80);
|
||||
} else if (c >= 0x000800 && c <= 0x00FFFF) {
|
||||
bytes.push(((c >> 12) & 0x0F) | 0xE0);
|
||||
bytes.push(((c >> 6) & 0x3F) | 0x80);
|
||||
bytes.push((c & 0x3F) | 0x80);
|
||||
} else if (c >= 0x000080 && c <= 0x0007FF) {
|
||||
bytes.push(((c >> 6) & 0x1F) | 0xC0);
|
||||
bytes.push((c & 0x3F) | 0x80);
|
||||
} else {
|
||||
bytes.push(c & 0xFF);
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
},
|
||||
cancel() {
|
||||
this.$router.push({path: '/performance/test/all'})
|
||||
},
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('load_test.serialize_threadgroups')">
|
||||
<el-switch v-model="serializeThreadGroups"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
@ -177,6 +180,8 @@ import {findThreadGroup} from "@/business/components/performance/test/model/Thre
|
|||
|
||||
const HANDLER = "handler";
|
||||
const THREAD_GROUP_TYPE = "tgType";
|
||||
const EXPECTED_DURATION = "expectedDuration";
|
||||
const SERIALIZE_THREAD_GROUPS = "serializeThreadGroups";
|
||||
const TARGET_LEVEL = "TargetLevel";
|
||||
const RAMP_UP = "RampUp";
|
||||
const ITERATE_RAMP_UP = "iterateRampUpTime";
|
||||
|
@ -231,6 +236,7 @@ export default {
|
|||
threadGroups: [],
|
||||
resourcePoolResourceLength: 1,
|
||||
maxThreadNumbers: 5000,
|
||||
serializeThreadGroups: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -317,6 +323,9 @@ export default {
|
|||
case THREAD_GROUP_TYPE:
|
||||
this.threadGroups[i].tgType = item.value;
|
||||
break;
|
||||
case SERIALIZE_THREAD_GROUPS:
|
||||
this.serializeThreadGroups = item.value;// 所有的线程组值一样
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -639,9 +648,52 @@ export default {
|
|||
}
|
||||
return this.$t('schedule.cron.seconds');
|
||||
},
|
||||
calculateDuration() {
|
||||
let expectedDuration = 0;
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
if (this.serializeThreadGroups) {
|
||||
switch (this.threadGroups[i].unit) {
|
||||
case "S":
|
||||
expectedDuration += this.threadGroups[i].duration;
|
||||
break;
|
||||
case "M":
|
||||
expectedDuration += this.threadGroups[i].duration * 60;
|
||||
break;
|
||||
case "H":
|
||||
expectedDuration += this.threadGroups[i].duration * 60 * 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let tmp = 0;
|
||||
switch (this.threadGroups[i].unit) {
|
||||
case "S":
|
||||
tmp = this.threadGroups[i].duration;
|
||||
break;
|
||||
case "M":
|
||||
tmp = this.threadGroups[i].duration * 60;
|
||||
break;
|
||||
case "H":
|
||||
tmp = this.threadGroups[i].duration * 60 * 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (expectedDuration < tmp) {
|
||||
expectedDuration = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return expectedDuration;
|
||||
},
|
||||
convertProperty() {
|
||||
/// todo:下面4个属性是jmeter ConcurrencyThreadGroup plugin的属性,这种硬编码不太好吧,在哪能转换这种属性?
|
||||
let result = [];
|
||||
// 先计算执行时间
|
||||
let expectedDuration = this.calculateDuration();
|
||||
|
||||
// 再组织数据
|
||||
for (let i = 0; i < this.threadGroups.length; i++) {
|
||||
result.push([
|
||||
{key: HANDLER, value: this.threadGroups[i].handler},
|
||||
|
@ -659,8 +711,11 @@ export default {
|
|||
{key: ENABLED, value: this.threadGroups[i].enabled},
|
||||
{key: DELETED, value: this.threadGroups[i].deleted},
|
||||
{key: THREAD_GROUP_TYPE, value: this.threadGroups[i].tgType},
|
||||
{key: EXPECTED_DURATION, value: expectedDuration},
|
||||
{key: SERIALIZE_THREAD_GROUPS, value: this.serializeThreadGroups},
|
||||
]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -523,6 +523,7 @@ export default {
|
|||
response_timeout: 'Timeout to response',
|
||||
custom_http_code: 'Custom HTTP response success status code',
|
||||
separated_by_commas: 'Separated by commas',
|
||||
serialize_threadgroups:'Whether the scene is executed sequentially',
|
||||
create: 'Create Test',
|
||||
select_resource_pool: 'Please Select Resource Pool',
|
||||
resource_pool_is_null: 'Resource Pool is empty',
|
||||
|
|
|
@ -523,6 +523,7 @@ export default {
|
|||
create: '创建测试',
|
||||
run: '一键运行',
|
||||
select_resource_pool: '请选择资源池',
|
||||
serialize_threadgroups: '场景是否顺序执行',
|
||||
resource_pool_is_null: '资源池为空',
|
||||
download_log_file: '下载完整日志文件',
|
||||
pressure_prediction_chart: '压力预估图',
|
||||
|
|
|
@ -523,6 +523,7 @@ export default {
|
|||
create: '創建測試',
|
||||
run: '壹鍵運行',
|
||||
select_resource_pool: '請選擇資源池',
|
||||
serialize_threadgroups: '場景是否順序執行',
|
||||
resource_pool_is_null: '資源池為空',
|
||||
download_log_file: '下載完整日誌文件',
|
||||
pressure_prediction_chart: '壓力預估圖',
|
||||
|
|
Loading…
Reference in New Issue