Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
512d2c31
M
metersphere
项目概览
MeterSphere
/
metersphere
上一次同步 3 年多
通知
25
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
metersphere
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
512d2c31
编写于
4月 02, 2021
作者:
C
Captain.B
提交者:
刘瑞斌
4月 02, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix(性能测试): 压力配置上可以选择场景是否顺序执行
上级
6e1545b6
变更
6
显示空白变更内容
内联
并排
Showing
6 changed file
with
78 addition
and
76 deletion
+78
-76
backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java
...erformance/parse/xml/reader/jmx/JmeterDocumentParser.java
+20
-52
frontend/src/business/components/performance/test/EditPerformanceTest.vue
...iness/components/performance/test/EditPerformanceTest.vue
+0
-24
frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue
...performance/test/components/PerformancePressureConfig.vue
+55
-0
frontend/src/i18n/en-US.js
frontend/src/i18n/en-US.js
+1
-0
frontend/src/i18n/zh-CN.js
frontend/src/i18n/zh-CN.js
+1
-0
frontend/src/i18n/zh-TW.js
frontend/src/i18n/zh-TW.js
+1
-0
未找到文件。
backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java
浏览文件 @
512d2c31
...
...
@@ -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
)
{
...
...
frontend/src/business/components/performance/test/EditPerformanceTest.vue
浏览文件 @
512d2c31
...
...
@@ -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
'
})
},
...
...
frontend/src/business/components/performance/test/components/PerformancePressureConfig.vue
浏览文件 @
512d2c31
...
...
@@ -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
;
}
}
...
...
frontend/src/i18n/en-US.js
浏览文件 @
512d2c31
...
...
@@ -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
'
,
...
...
frontend/src/i18n/zh-CN.js
浏览文件 @
512d2c31
...
...
@@ -523,6 +523,7 @@ export default {
create
:
'
创建测试
'
,
run
:
'
一键运行
'
,
select_resource_pool
:
'
请选择资源池
'
,
serialize_threadgroups
:
'
场景是否顺序执行
'
,
resource_pool_is_null
:
'
资源池为空
'
,
download_log_file
:
'
下载完整日志文件
'
,
pressure_prediction_chart
:
'
压力预估图
'
,
...
...
frontend/src/i18n/zh-TW.js
浏览文件 @
512d2c31
...
...
@@ -523,6 +523,7 @@ export default {
create
:
'
創建測試
'
,
run
:
'
壹鍵運行
'
,
select_resource_pool
:
'
請選擇資源池
'
,
serialize_threadgroups
:
'
場景是否順序執行
'
,
resource_pool_is_null
:
'
資源池為空
'
,
download_log_file
:
'
下載完整日誌文件
'
,
pressure_prediction_chart
:
'
壓力預估圖
'
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录