Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
fa23fcdf
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,发现更多精彩内容 >>
提交
fa23fcdf
编写于
8月 14, 2020
作者:
C
Captain.B
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(接口测试): 代码调整
上级
b86fbafa
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
224 addition
and
56 deletion
+224
-56
backend/src/main/java/io/metersphere/api/parse/JmxDocumentParser.java
...main/java/io/metersphere/api/parse/JmxDocumentParser.java
+125
-0
backend/src/main/java/io/metersphere/api/service/APITestService.java
.../main/java/io/metersphere/api/service/APITestService.java
+7
-1
backend/src/main/java/io/metersphere/commons/utils/ScriptEngineUtils.java
.../java/io/metersphere/commons/utils/ScriptEngineUtils.java
+33
-0
backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java
...erformance/parse/xml/reader/jmx/JmeterDocumentParser.java
+4
-1
frontend/src/business/components/api/test/components/ApiBody.vue
...d/src/business/components/api/test/components/ApiBody.vue
+43
-35
frontend/src/business/components/api/test/components/ApiVariable.vue
...c/business/components/api/test/components/ApiVariable.vue
+4
-4
frontend/src/business/components/api/test/components/ApiVariableAdvance.vue
...ess/components/api/test/components/ApiVariableAdvance.vue
+2
-5
frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue
...onents/api/test/components/request/ApiHttpRequestForm.vue
+6
-2
frontend/src/business/components/api/test/model/ScenarioModel.js
...d/src/business/components/api/test/model/ScenarioModel.js
+0
-8
未找到文件。
backend/src/main/java/io/metersphere/api/parse/JmxDocumentParser.java
0 → 100644
浏览文件 @
fa23fcdf
package
io.metersphere.api.parse
;
import
io.metersphere.commons.utils.LogUtil
;
import
io.metersphere.commons.utils.ScriptEngineUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.w3c.dom.Document
;
import
org.w3c.dom.Element
;
import
org.w3c.dom.Node
;
import
org.w3c.dom.NodeList
;
import
org.xml.sax.InputSource
;
import
javax.xml.parsers.DocumentBuilder
;
import
javax.xml.parsers.DocumentBuilderFactory
;
import
javax.xml.transform.Transformer
;
import
javax.xml.transform.TransformerException
;
import
javax.xml.transform.TransformerFactory
;
import
javax.xml.transform.dom.DOMSource
;
import
javax.xml.transform.stream.StreamResult
;
import
java.io.ByteArrayInputStream
;
import
java.io.StringWriter
;
public
class
JmxDocumentParser
{
private
final
static
String
HASH_TREE_ELEMENT
=
"hashTree"
;
private
final
static
String
STRING_PROP
=
"stringProp"
;
public
static
byte
[]
parse
(
byte
[]
source
)
{
final
InputSource
inputSource
=
new
InputSource
(
new
ByteArrayInputStream
(
source
));
DocumentBuilderFactory
factory
=
DocumentBuilderFactory
.
newInstance
();
try
{
DocumentBuilder
docBuilder
=
factory
.
newDocumentBuilder
();
final
Document
document
=
docBuilder
.
parse
(
inputSource
);
final
Element
jmeterTestPlan
=
document
.
getDocumentElement
();
NodeList
childNodes
=
jmeterTestPlan
.
getChildNodes
();
for
(
int
i
=
0
;
i
<
childNodes
.
getLength
();
i
++)
{
Node
node
=
childNodes
.
item
(
i
);
if
(
node
instanceof
Element
)
{
Element
ele
=
(
Element
)
node
;
parseHashTree
(
ele
);
}
}
return
documentToBytes
(
document
);
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
e
);
return
source
;
}
}
private
static
byte
[]
documentToBytes
(
Document
document
)
throws
TransformerException
{
DOMSource
domSource
=
new
DOMSource
(
document
);
StringWriter
writer
=
new
StringWriter
();
StreamResult
result
=
new
StreamResult
(
writer
);
TransformerFactory
tf
=
TransformerFactory
.
newInstance
();
Transformer
transformer
=
tf
.
newTransformer
();
transformer
.
transform
(
domSource
,
result
);
return
writer
.
toString
().
getBytes
();
}
private
static
void
parseHashTree
(
Element
hashTree
)
{
if
(
invalid
(
hashTree
))
{
return
;
}
if
(
hashTree
.
getChildNodes
().
getLength
()
>
0
)
{
final
NodeList
childNodes
=
hashTree
.
getChildNodes
();
for
(
int
i
=
0
;
i
<
childNodes
.
getLength
();
i
++)
{
Node
node
=
childNodes
.
item
(
i
);
if
(
node
instanceof
Element
)
{
Element
ele
=
(
Element
)
node
;
if
(
invalid
(
ele
))
{
continue
;
}
if
(
nodeNameEquals
(
ele
,
HASH_TREE_ELEMENT
))
{
parseHashTree
(
ele
);
}
else
{
if
(
nodeNameEquals
(
ele
,
STRING_PROP
))
{
processStringProp
(
ele
);
}
}
}
}
}
}
private
static
void
processStringProp
(
Element
ele
)
{
String
name
=
ele
.
getAttribute
(
"name"
);
NodeList
childNodes
;
switch
(
name
)
{
case
"HTTPSampler.path"
:
childNodes
=
ele
.
getChildNodes
();
for
(
int
i
=
0
;
i
<
childNodes
.
getLength
();
i
++)
{
Node
node
=
childNodes
.
item
(
i
);
if
(
node
instanceof
Element
)
{
String
nodeValue
=
node
.
getNodeValue
();
System
.
out
.
println
(
nodeValue
);
}
}
break
;
case
"Argument.value"
:
childNodes
=
ele
.
getChildNodes
();
for
(
int
i
=
0
;
i
<
childNodes
.
getLength
();
i
++)
{
Node
node
=
childNodes
.
item
(
i
);
if
(
node
instanceof
Element
)
{
String
nodeValue
=
node
.
getNodeValue
();
node
.
setNodeValue
(
ScriptEngineUtils
.
calculate
(
nodeValue
));
}
}
break
;
default
:
break
;
}
}
private
static
boolean
nodeNameEquals
(
Node
node
,
String
desiredName
)
{
return
desiredName
.
equals
(
node
.
getNodeName
())
||
desiredName
.
equals
(
node
.
getLocalName
());
}
private
static
boolean
invalid
(
Element
ele
)
{
return
!
StringUtils
.
isBlank
(
ele
.
getAttribute
(
"enabled"
))
&&
!
Boolean
.
parseBoolean
(
ele
.
getAttribute
(
"enabled"
));
}
}
backend/src/main/java/io/metersphere/api/service/APITestService.java
浏览文件 @
fa23fcdf
...
...
@@ -8,11 +8,15 @@ import io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter;
import
io.metersphere.api.jmeter.JMeterService
;
import
io.metersphere.api.parse.ApiImportParser
;
import
io.metersphere.api.parse.ApiImportParserFactory
;
import
io.metersphere.api.parse.JmxDocumentParser
;
import
io.metersphere.base.domain.*
;
import
io.metersphere.base.mapper.ApiTestFileMapper
;
import
io.metersphere.base.mapper.ApiTestMapper
;
import
io.metersphere.base.mapper.ext.ExtApiTestMapper
;
import
io.metersphere.commons.constants.*
;
import
io.metersphere.commons.constants.APITestStatus
;
import
io.metersphere.commons.constants.FileType
;
import
io.metersphere.commons.constants.ScheduleGroup
;
import
io.metersphere.commons.constants.ScheduleType
;
import
io.metersphere.commons.exception.MSException
;
import
io.metersphere.commons.utils.BeanUtils
;
import
io.metersphere.commons.utils.LogUtil
;
...
...
@@ -145,6 +149,8 @@ public class APITestService {
MSException
.
throwException
(
Translator
.
get
(
"file_cannot_be_null"
));
}
byte
[]
bytes
=
fileService
.
loadFileAsBytes
(
file
.
getFileId
());
// 解析 xml 处理 mock 数据
bytes
=
JmxDocumentParser
.
parse
(
bytes
);
InputStream
is
=
new
ByteArrayInputStream
(
bytes
);
APITestResult
apiTest
=
get
(
request
.
getId
());
...
...
backend/src/main/java/io/metersphere/commons/utils/ScriptEngineUtils.java
0 → 100644
浏览文件 @
fa23fcdf
package
io.metersphere.commons.utils
;
import
org.apache.commons.io.IOUtils
;
import
javax.script.ScriptEngine
;
import
javax.script.ScriptEngineManager
;
import
javax.script.ScriptException
;
import
java.nio.charset.StandardCharsets
;
public
class
ScriptEngineUtils
{
private
static
final
String
ENGINE_NAME
=
"graal.js"
;
private
static
ScriptEngine
engine
;
static
{
final
ScriptEngineManager
engineManager
=
new
ScriptEngineManager
();
engine
=
engineManager
.
getEngineByName
(
ENGINE_NAME
);
try
{
String
script
=
IOUtils
.
toString
(
ScriptEngineUtils
.
class
.
getResource
(
"/javascript/func.js"
),
StandardCharsets
.
UTF_8
);
engine
.
eval
(
script
);
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
e
);
}
}
public
static
String
calculate
(
String
input
)
{
try
{
return
engine
.
eval
(
input
).
toString
();
}
catch
(
ScriptException
e
)
{
LogUtil
.
error
(
e
);
return
input
;
}
}
}
backend/src/main/java/io/metersphere/performance/parse/xml/reader/jmx/JmeterDocumentParser.java
浏览文件 @
fa23fcdf
...
...
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.commons.exception.MSException
;
import
io.metersphere.commons.utils.CommonBeanFactory
;
import
io.metersphere.commons.utils.ScriptEngineUtils
;
import
io.metersphere.config.KafkaProperties
;
import
io.metersphere.i18n.Translator
;
import
io.metersphere.performance.engine.EngineContext
;
...
...
@@ -377,7 +378,9 @@ public class JmeterDocumentParser implements DocumentParser {
elementProp
.
setAttribute
(
"name"
,
jsonObject
.
getString
(
"name"
));
elementProp
.
setAttribute
(
"elementType"
,
"Argument"
);
elementProp
.
appendChild
(
createStringProp
(
document
,
"Argument.name"
,
jsonObject
.
getString
(
"name"
)));
elementProp
.
appendChild
(
createStringProp
(
document
,
"Argument.value"
,
jsonObject
.
getString
(
"value"
)));
// 处理 mock data
String
value
=
jsonObject
.
getString
(
"value"
);
elementProp
.
appendChild
(
createStringProp
(
document
,
"Argument.value"
,
ScriptEngineUtils
.
calculate
(
value
)));
elementProp
.
appendChild
(
createStringProp
(
document
,
"Argument.metadata"
,
"="
));
item
.
appendChild
(
elementProp
);
}
...
...
frontend/src/business/components/api/test/components/ApiBody.vue
浏览文件 @
fa23fcdf
...
...
@@ -2,17 +2,22 @@
<div>
<el-radio-group
v-model=
"body.type"
size=
"mini"
>
<el-radio-button
:disabled=
"isReadOnly"
:label=
"type.KV"
>
{{
$t
(
'
api_test.request.body_kv
'
)
}}
{{
$t
(
'
api_test.request.body_kv
'
)
}}
</el-radio-button>
<el-radio-button
:disabled=
"isReadOnly"
:label=
"type.RAW"
>
{{
$t
(
'
api_test.request.body_text
'
)
}}
{{
$t
(
'
api_test.request.body_text
'
)
}}
</el-radio-button>
</el-radio-group>
<ms-dropdown
:default-command=
"body.format"
v-if=
"body.type == 'Raw'"
:commands=
"modes"
@
command=
"modeChange"
/>
<ms-api-variable
:is-read-only=
"isReadOnly"
:items=
"body.kvs"
v-if=
"body.isKV()"
/>
<ms-api-variable
:is-read-only=
"isReadOnly"
:parameters=
"body.kvs"
:environment=
"environment"
:scenario=
"scenario"
:extract=
"extract"
:description=
"$t('api_test.request.parameters_desc')"
v-if=
"body.isKV()"
/>
<div
class=
"body-raw"
v-if=
"body.type == 'Raw'"
>
<ms-code-edit
:mode=
"body.format"
:read-only=
"isReadOnly"
:data.sync=
"body.raw"
:modes=
"modes"
ref=
"codeEdit"
/>
</div>
...
...
@@ -22,7 +27,7 @@
<
script
>
import
MsApiKeyValue
from
"
./ApiKeyValue
"
;
import
{
Body
,
BODY_FORMAT
,
BODY_TYPE
}
from
"
../model/ScenarioModel
"
;
import
{
Body
,
BODY_FORMAT
,
BODY_TYPE
,
Scenario
}
from
"
../model/ScenarioModel
"
;
import
MsCodeEdit
from
"
../../../common/components/MsCodeEdit
"
;
import
MsDropdown
from
"
../../../common/components/MsDropdown
"
;
import
MsApiVariable
from
"
@/business/components/api/test/components/ApiVariable
"
;
...
...
@@ -32,6 +37,9 @@ export default {
components
:
{
MsApiVariable
,
MsDropdown
,
MsCodeEdit
,
MsApiKeyValue
},
props
:
{
body
:
Body
,
scenario
:
Scenario
,
environment
:
Object
,
extract
:
Object
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
...
...
@@ -40,45 +48,45 @@ export default {
data
()
{
return
{
type
:
BODY_TYPE
,
modes
:
[
'
text
'
,
'
json
'
,
'
xml
'
,
'
html
'
]
};
},
type
:
BODY_TYPE
,
modes
:
[
'
text
'
,
'
json
'
,
'
xml
'
,
'
html
'
]
};
},
methods
:
{
modeChange
(
mode
)
{
this
.
body
.
format
=
mode
;
}
},
methods
:
{
modeChange
(
mode
)
{
this
.
body
.
format
=
mode
;
}
},
created
()
{
if
(
!
this
.
body
.
type
)
{
this
.
body
.
type
=
BODY_TYPE
.
KV
;
}
if
(
!
this
.
body
.
format
)
{
this
.
body
.
format
=
BODY_FORMAT
.
TEXT
;
}
created
()
{
if
(
!
this
.
body
.
type
)
{
this
.
body
.
type
=
BODY_TYPE
.
KV
;
}
if
(
!
this
.
body
.
format
)
{
this
.
body
.
format
=
BODY_FORMAT
.
TEXT
;
}
}
}
</
script
>
<
style
scoped
>
.textarea
{
margin-top
:
10px
;
}
.textarea
{
margin-top
:
10px
;
}
.body-raw
{
padding
:
15px
0
;
height
:
300px
;
}
.body-raw
{
padding
:
15px
0
;
height
:
300px
;
}
.el-dropdown
{
margin-left
:
20px
;
line-height
:
30px
;
}
.el-dropdown
{
margin-left
:
20px
;
line-height
:
30px
;
}
.ace_editor
{
border-radius
:
5px
;
}
.ace_editor
{
border-radius
:
5px
;
}
</
style
>
frontend/src/business/components/api/test/components/ApiVariable.vue
浏览文件 @
fa23fcdf
...
...
@@ -34,13 +34,14 @@
</el-col>
</el-row>
</div>
<ms-api-variable-advance
ref=
"variableAdvance"
:environment=
"environment"
:scenario=
"scenario"
:request=
"request"
<ms-api-variable-advance
ref=
"variableAdvance"
:environment=
"environment"
:scenario=
"scenario"
:parameters=
"parameters"
:current-item=
"currentItem"
/>
</div>
</
template
>
<
script
>
import
{
HttpRequest
,
KeyValue
,
Scenario
}
from
"
../model/ScenarioModel
"
;
import
{
KeyValue
,
Scenario
}
from
"
../model/ScenarioModel
"
;
import
{
MOCKJS_FUNC
}
from
"
@/common/js/constants
"
;
import
MsApiVariableAdvance
from
"
@/business/components/api/test/components/ApiVariableAdvance
"
;
...
...
@@ -51,7 +52,7 @@ export default {
keyPlaceholder
:
String
,
valuePlaceholder
:
String
,
description
:
String
,
request
:
HttpRequest
,
parameters
:
Array
,
environment
:
Object
,
scenario
:
Scenario
,
isReadOnly
:
{
...
...
@@ -63,7 +64,6 @@ export default {
data
()
{
return
{
currentItem
:
null
,
parameters
:
[],
}
},
computed
:
{
...
...
frontend/src/business/components/api/test/components/ApiVariableAdvance.vue
浏览文件 @
fa23fcdf
...
...
@@ -90,13 +90,13 @@
</
template
>
<
script
>
import
{
calculate
,
HttpRequest
,
Scenario
}
from
"
@/business/components/api/test/model/ScenarioModel
"
;
import
{
calculate
,
Scenario
}
from
"
@/business/components/api/test/model/ScenarioModel
"
;
import
{
JMETER_FUNC
,
MOCKJS_FUNC
}
from
"
@/common/js/constants
"
;
export
default
{
name
:
"
MsApiVariableAdvance
"
,
props
:
{
request
:
HttpRequest
,
parameters
:
Array
,
environment
:
Object
,
scenario
:
Scenario
,
currentItem
:
Object
,
...
...
@@ -162,9 +162,6 @@ export default {
this
.
itemValueVisible
=
true
;
},
prepareData
()
{
if
(
this
.
request
)
{
this
.
parameters
=
this
.
request
.
parameters
;
}
if
(
this
.
scenario
)
{
let
variables
=
this
.
scenario
.
variables
;
this
.
scenarioParams
=
[
...
...
frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue
浏览文件 @
fa23fcdf
...
...
@@ -46,7 +46,7 @@
<el-tabs
v-model=
"activeName"
>
<el-tab-pane
:label=
"$t('api_test.request.parameters')"
name=
"parameters"
>
<ms-api-variable
:is-read-only=
"isReadOnly"
:
request=
"request
"
:
parameters=
"request.parameters
"
:environment=
"request.environment"
:scenario=
"scenario"
:extract=
"request.extract"
...
...
@@ -56,7 +56,11 @@
<ms-api-key-value
:is-read-only=
"isReadOnly"
:suggestions=
"headerSuggestions"
:items=
"request.headers"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.request.body')"
name=
"body"
v-if=
"isNotGet"
>
<ms-api-body
:is-read-only=
"isReadOnly"
:body=
"request.body"
/>
<ms-api-body
:is-read-only=
"isReadOnly"
:body=
"request.body"
:scenario=
"scenario"
:extract=
"request.extract"
:environment=
"request.environment"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.request.assertions.label')"
name=
"assertions"
>
<ms-api-assertions
:is-read-only=
"isReadOnly"
:assertions=
"request.assertions"
/>
...
...
frontend/src/business/components/api/test/model/ScenarioModel.js
浏览文件 @
fa23fcdf
...
...
@@ -722,8 +722,6 @@ class JMXHttpRequest {
});
for
(
let
i
=
0
;
i
<
parameters
.
length
;
i
++
)
{
let
parameter
=
parameters
[
i
];
// 非 GET 请求中出现了 url 参数
parameter
.
value
=
calculate
(
parameter
.
value
);
path
+=
(
parameter
.
name
+
'
=
'
+
parameter
.
value
);
if
(
i
!==
parameters
.
length
-
1
)
{
path
+=
'
&
'
;
...
...
@@ -921,9 +919,6 @@ class JMXGenerator {
addRequestArguments
(
httpSamplerProxy
,
request
)
{
let
args
=
this
.
filterKV
(
request
.
parameters
);
args
.
forEach
(
arg
=>
{
arg
.
value
=
calculate
(
arg
.
value
);
});
if
(
args
.
length
>
0
)
{
httpSamplerProxy
.
add
(
new
HTTPSamplerArguments
(
args
));
}
...
...
@@ -933,9 +928,6 @@ class JMXGenerator {
let
body
=
[];
if
(
request
.
body
.
isKV
())
{
body
=
this
.
filterKV
(
request
.
body
.
kvs
);
body
.
forEach
(
arg
=>
{
arg
.
value
=
calculate
(
arg
.
value
);
});
}
else
{
httpSamplerProxy
.
boolProp
(
'
HTTPSampler.postBodyRaw
'
,
true
);
body
.
push
({
name
:
''
,
value
:
request
.
body
.
raw
,
encode
:
false
});
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录