Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
d54b32ce
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,发现更多精彩内容 >>
提交
d54b32ce
编写于
8月 25, 2020
作者:
C
chenjianxing
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(接口测试): 接口测试支持文件上传
上级
9a9d702a
变更
20
隐藏空白更改
内联
并排
Showing
20 changed file
with
409 addition
and
61 deletion
+409
-61
backend/src/main/java/io/metersphere/api/controller/APITestController.java
...java/io/metersphere/api/controller/APITestController.java
+4
-4
backend/src/main/java/io/metersphere/api/dto/SaveAPITestRequest.java
.../main/java/io/metersphere/api/dto/SaveAPITestRequest.java
+2
-0
backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java
...c/main/java/io/metersphere/api/dto/scenario/KeyValue.java
+5
-0
backend/src/main/java/io/metersphere/api/dto/scenario/request/BodyFile.java
...ava/io/metersphere/api/dto/scenario/request/BodyFile.java
+10
-0
backend/src/main/java/io/metersphere/api/service/APITestService.java
.../main/java/io/metersphere/api/service/APITestService.java
+68
-5
backend/src/main/java/io/metersphere/controller/TestController.java
...c/main/java/io/metersphere/controller/TestController.java
+17
-4
backend/src/main/java/io/metersphere/xpack
backend/src/main/java/io/metersphere/xpack
+1
-1
frontend/src/business/components/api/test/ApiTestConfig.vue
frontend/src/business/components/api/test/ApiTestConfig.vue
+48
-2
frontend/src/business/components/api/test/components/ApiVariable.vue
...c/business/components/api/test/components/ApiVariable.vue
+45
-27
frontend/src/business/components/api/test/components/body/ApiBody.vue
.../business/components/api/test/components/body/ApiBody.vue
+10
-4
frontend/src/business/components/api/test/components/body/ApiBodyFileUpload.vue
...components/api/test/components/body/ApiBodyFileUpload.vue
+116
-0
frontend/src/business/components/api/test/components/import/ApiImport.vue
...iness/components/api/test/components/import/ApiImport.vue
+1
-1
frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue
...nents/api/test/components/request/ApiDubboRequestForm.vue
+1
-1
frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue
...onents/api/test/components/request/ApiHttpRequestForm.vue
+1
-1
frontend/src/business/components/api/test/model/JMX.js
frontend/src/business/components/api/test/model/JMX.js
+19
-0
frontend/src/business/components/api/test/model/ScenarioModel.js
...d/src/business/components/api/test/model/ScenarioModel.js
+43
-7
frontend/src/business/components/track/case/components/TestCaseImport.vue
...iness/components/track/case/components/TestCaseImport.vue
+1
-1
frontend/src/business/components/xpack
frontend/src/business/components/xpack
+1
-1
frontend/src/common/js/ajax.js
frontend/src/common/js/ajax.js
+9
-2
frontend/src/common/js/utils.js
frontend/src/common/js/utils.js
+7
-0
未找到文件。
backend/src/main/java/io/metersphere/api/controller/APITestController.java
浏览文件 @
d54b32ce
...
...
@@ -60,13 +60,13 @@ public class APITestController {
}
@PostMapping
(
value
=
"/create"
,
consumes
=
{
"multipart/form-data"
})
public
void
create
(
@RequestPart
(
"request"
)
SaveAPITestRequest
request
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
)
{
apiTestService
.
create
(
request
,
file
);
public
void
create
(
@RequestPart
(
"request"
)
SaveAPITestRequest
request
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
,
@RequestPart
(
value
=
"files"
)
List
<
MultipartFile
>
bodyFiles
)
{
apiTestService
.
create
(
request
,
file
,
bodyFiles
);
}
@PostMapping
(
value
=
"/update"
,
consumes
=
{
"multipart/form-data"
})
public
void
update
(
@RequestPart
(
"request"
)
SaveAPITestRequest
request
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
)
{
apiTestService
.
update
(
request
,
file
);
public
void
update
(
@RequestPart
(
"request"
)
SaveAPITestRequest
request
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
,
@RequestPart
(
value
=
"files"
)
List
<
MultipartFile
>
bodyFiles
)
{
apiTestService
.
update
(
request
,
file
,
bodyFiles
);
}
@PostMapping
(
value
=
"/copy"
)
...
...
backend/src/main/java/io/metersphere/api/dto/SaveAPITestRequest.java
浏览文件 @
d54b32ce
...
...
@@ -24,4 +24,6 @@ public class SaveAPITestRequest {
private
Schedule
schedule
;
private
String
triggerMode
;
private
List
<
String
>
bodyUploadIds
;
}
backend/src/main/java/io/metersphere/api/dto/scenario/KeyValue.java
浏览文件 @
d54b32ce
package
io.metersphere.api.dto.scenario
;
import
io.metersphere.api.dto.scenario.request.BodyFile
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
KeyValue
{
private
String
name
;
private
String
value
;
private
String
type
;
private
List
<
BodyFile
>
files
;
private
String
description
;
public
KeyValue
()
{
...
...
backend/src/main/java/io/metersphere/api/dto/scenario/request/BodyFile.java
0 → 100644
浏览文件 @
d54b32ce
package
io.metersphere.api.dto.scenario.request
;
import
lombok.Data
;
@Data
public
class
BodyFile
{
private
String
id
;
private
String
name
;
}
backend/src/main/java/io/metersphere/api/service/APITestService.java
浏览文件 @
d54b32ce
...
...
@@ -29,6 +29,7 @@ import io.metersphere.service.ScheduleService;
import
io.metersphere.track.service.TestCaseService
;
import
org.apache.dubbo.common.URL
;
import
org.apache.dubbo.common.constants.CommonConstants
;
import
org.aspectj.util.FileUtil
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.CollectionUtils
;
...
...
@@ -36,9 +37,7 @@ import org.springframework.web.multipart.MultipartFile;
import
javax.annotation.Resource
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.*
;
import
java.util.*
;
import
java.util.stream.Collectors
;
...
...
@@ -63,6 +62,8 @@ public class APITestService {
@Resource
private
TestCaseService
testCaseService
;
private
static
final
String
BODY_FILE_DIR
=
"/opt/metersphere/data/body"
;
public
List
<
APITestResult
>
list
(
QueryAPITestRequest
request
)
{
request
.
setOrders
(
ServiceUtils
.
getDefaultOrder
(
request
.
getOrders
()));
return
extApiTestMapper
.
list
(
request
);
...
...
@@ -73,24 +74,63 @@ public class APITestService {
return
extApiTestMapper
.
list
(
request
);
}
public
void
create
(
SaveAPITestRequest
request
,
MultipartFile
file
)
{
public
void
create
(
SaveAPITestRequest
request
,
MultipartFile
file
,
List
<
MultipartFile
>
bodyFiles
)
{
if
(
file
==
null
)
{
throw
new
IllegalArgumentException
(
Translator
.
get
(
"file_cannot_be_null"
));
}
checkQuota
();
List
<
String
>
bodyUploadIds
=
new
ArrayList
<>(
request
.
getBodyUploadIds
())
;
request
.
setBodyUploadIds
(
null
);
ApiTest
test
=
createTest
(
request
);
createBodyFiles
(
test
,
bodyUploadIds
,
bodyFiles
);
saveFile
(
test
.
getId
(),
file
);
}
public
void
update
(
SaveAPITestRequest
request
,
MultipartFile
file
)
{
public
void
update
(
SaveAPITestRequest
request
,
MultipartFile
file
,
List
<
MultipartFile
>
bodyFiles
)
{
if
(
file
==
null
)
{
throw
new
IllegalArgumentException
(
Translator
.
get
(
"file_cannot_be_null"
));
}
deleteFileByTestId
(
request
.
getId
());
List
<
String
>
bodyUploadIds
=
new
ArrayList
<>(
request
.
getBodyUploadIds
())
;
request
.
setBodyUploadIds
(
null
);
ApiTest
test
=
updateTest
(
request
);
createBodyFiles
(
test
,
bodyUploadIds
,
bodyFiles
);
saveFile
(
test
.
getId
(),
file
);
}
private
void
createBodyFiles
(
ApiTest
test
,
List
<
String
>
bodyUploadIds
,
List
<
MultipartFile
>
bodyFiles
)
{
if
(
bodyFiles
==
null
||
bodyFiles
.
isEmpty
())
{
}
String
dir
=
BODY_FILE_DIR
+
"/"
+
test
.
getId
();
File
testDir
=
new
File
(
dir
);
if
(!
testDir
.
exists
())
{
testDir
.
mkdirs
();
}
for
(
int
i
=
0
;
i
<
bodyUploadIds
.
size
();
i
++)
{
MultipartFile
item
=
bodyFiles
.
get
(
i
);
File
file
=
new
File
(
testDir
+
"/"
+
bodyUploadIds
.
get
(
i
)
+
"_"
+
item
.
getOriginalFilename
());
InputStream
in
=
null
;
OutputStream
out
=
null
;
try
{
file
.
createNewFile
();
in
=
item
.
getInputStream
();
out
=
new
FileOutputStream
(
file
);
FileUtil
.
copyStream
(
in
,
out
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
try
{
in
.
close
();
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
}
public
void
copy
(
SaveAPITestRequest
request
)
{
checkQuota
();
request
.
setName
(
request
.
getName
()
+
" Copy"
);
...
...
@@ -117,6 +157,20 @@ public class APITestService {
apiTestFile
.
setFileId
(
fileMetadata
.
getId
());
apiTestFileMapper
.
insert
(
apiTestFile
);
}
copyBodyFiles
(
copy
.
getId
(),
request
.
getId
());
}
public
void
copyBodyFiles
(
String
target
,
String
source
)
{
String
sourceDir
=
BODY_FILE_DIR
+
"/"
+
source
;
String
targetDir
=
BODY_FILE_DIR
+
"/"
+
target
;
File
sourceFile
=
new
File
(
sourceDir
);
if
(
sourceFile
.
exists
())
{
try
{
FileUtil
.
copyDir
(
sourceFile
,
new
File
(
targetDir
));
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
public
APITestResult
get
(
String
id
)
{
...
...
@@ -142,6 +196,15 @@ public class APITestService {
apiReportService
.
deleteByTestId
(
testId
);
scheduleService
.
deleteByResourceId
(
testId
);
apiTestMapper
.
deleteByPrimaryKey
(
testId
);
deleteBodyFiles
(
testId
);
}
public
void
deleteBodyFiles
(
String
testId
)
{
File
file
=
new
File
(
BODY_FILE_DIR
+
"/"
+
testId
);
FileUtil
.
deleteContents
(
file
);
if
(
file
.
exists
())
{
file
.
delete
();
}
}
public
String
run
(
SaveAPITestRequest
request
)
{
...
...
backend/src/main/java/io/metersphere/controller/TestController.java
浏览文件 @
d54b32ce
package
io.metersphere.controller
;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.commons.utils.SessionUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.List
;
import
java.util.stream.Collectors
;
@RestController
@RequestMapping
(
value
=
"/test"
)
public
class
TestController
{
@PostMapping
(
value
=
"/upload"
,
consumes
=
{
"multipart/form-data"
})
public
Object
testUpload
(
@RequestPart
(
value
=
"id"
)
String
id
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
,
@RequestPart
(
value
=
"files"
)
List
<
MultipartFile
>
bodyFiles
)
{
JSONObject
jsonObject
=
new
JSONObject
();
jsonObject
.
put
(
"id"
,
id
);
jsonObject
.
put
(
"file"
,
file
.
getOriginalFilename
());
jsonObject
.
put
(
"files"
,
bodyFiles
.
stream
().
map
(
MultipartFile:
:
getOriginalFilename
).
collect
(
Collectors
.
toList
()));
return
jsonObject
;
}
@GetMapping
(
value
=
"/{str}"
)
public
Object
getString
(
@PathVariable
String
str
)
throws
InterruptedException
{
if
(
StringUtils
.
equals
(
"error"
,
str
))
{
...
...
@@ -28,4 +40,5 @@ public class TestController {
}
return
ResultHolder
.
success
(
str
);
}
}
\ No newline at end of file
xpack
@
b86032cb
比较
defbf12f
...
b86032cb
Subproject commit
defbf12ffac99eef6a026b87491090f2263b769d
Subproject commit
b86032cbbda9a9e6028308aa95a887cff2192f1c
frontend/src/business/components/api/test/ApiTestConfig.vue
浏览文件 @
d54b32ce
...
...
@@ -70,6 +70,7 @@
import
{
checkoutTestManagerOrTestUser
,
downloadFile
}
from
"
@/common/js/utils
"
;
import
MsScheduleConfig
from
"
../../common/components/MsScheduleConfig
"
;
import
ApiImport
from
"
./components/import/ApiImport
"
;
import
{
getUUID
}
from
"
../../../../common/js/utils
"
;
export
default
{
name
:
"
MsApiTestConfig
"
,
...
...
@@ -149,13 +150,15 @@
return
;
}
this
.
change
=
false
;
let
bodyFiles
=
this
.
getBodyUploadFiles
();
let
url
=
this
.
create
?
"
/api/create
"
:
"
/api/update
"
;
let
jmx
=
this
.
test
.
toJMX
();
let
blob
=
new
Blob
([
jmx
.
xml
],
{
type
:
"
application/octet-stream
"
});
let
file
=
new
File
([
blob
],
jmx
.
name
);
this
.
result
=
this
.
$fileUpload
(
url
,
file
,
this
.
test
,
response
=>
{
this
.
result
=
this
.
$fileUpload
(
url
,
file
,
bodyFiles
,
this
.
test
,
response
=>
{
if
(
callback
)
callback
();
this
.
create
=
false
;
this
.
resetBodyFile
();
});
},
saveTest
()
{
...
...
@@ -184,6 +187,49 @@
this
.
runTest
();
})
},
getBodyUploadFiles
()
{
let
bodyUploadFiles
=
[];
this
.
test
.
bodyUploadIds
=
[];
this
.
test
.
scenarioDefinition
.
forEach
(
scenario
=>
{
scenario
.
requests
.
forEach
(
request
=>
{
if
(
request
.
body
)
{
request
.
body
.
kvs
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
let
fileId
=
getUUID
().
substring
(
0
,
8
);
item
.
name
=
item
.
file
.
name
;
item
.
id
=
fileId
;
this
.
test
.
bodyUploadIds
.
push
(
fileId
);
bodyUploadFiles
.
push
(
item
.
file
);
// item.file = undefined;
}
});
}
});
}
});
});
return
bodyUploadFiles
;
},
resetBodyFile
()
{
//下次保存不再上传已传文件
this
.
test
.
scenarioDefinition
.
forEach
(
scenario
=>
{
scenario
.
requests
.
forEach
(
request
=>
{
if
(
request
.
body
)
{
request
.
body
.
kvs
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
item
.
file
=
undefined
;
}
});
}
});
}
});
});
},
cancel
()
{
this
.
$router
.
push
(
'
/api/test/list/all
'
);
},
...
...
@@ -256,7 +302,7 @@
let
jmx
=
runningTest
.
toJMX
();
let
blob
=
new
Blob
([
jmx
.
xml
],
{
type
:
"
application/octet-stream
"
});
let
file
=
new
File
([
blob
],
jmx
.
name
);
this
.
$fileUpload
(
url
,
file
,
this
.
test
,
response
=>
{
this
.
$fileUpload
(
url
,
file
,
null
,
this
.
test
,
response
=>
{
this
.
debugReportId
=
response
.
data
;
});
}
...
...
frontend/src/business/components/api/test/components/ApiVariable.vue
浏览文件 @
d54b32ce
...
...
@@ -6,15 +6,21 @@
<div
class=
"kv-row"
v-for=
"(item, index) in parameters"
:key=
"index"
>
<el-row
type=
"flex"
:gutter=
"20"
justify=
"space-between"
align=
"middle"
>
<el-col>
<el-input
v-if=
"!suggestions"
:disabled=
"isReadOnly"
v-model=
"item.name"
size=
"small"
maxlength=
"200"
@
change=
"change"
:placeholder=
"keyText"
show-word-limit
/>
<el-input
v-if=
"!suggestions"
:disabled=
"isReadOnly"
v-model=
"item.name"
size=
"small"
maxlength=
"200"
@
change=
"change"
:placeholder=
"keyText"
show-word-limit
>
<template
v-slot:prepend
>
<el-select
v-if=
"type === 'body'"
:disabled=
"isReadOnly"
class=
"kv-type"
v-model=
"item.type"
>
<el-option
value=
"text"
/>
<el-option
value=
"file"
/>
</el-select>
</
template
>
</el-input>
<el-autocomplete
:disabled=
"isReadOnly"
:maxlength=
"200"
v-if=
"suggestions"
v-model=
"item.name"
size=
"small"
:fetch-suggestions=
"querySearch"
@
change=
"change"
:placeholder=
"keyText"
show-word-limit
/>
:fetch-suggestions=
"querySearch"
@
change=
"change"
:placeholder=
"keyText"
show-word-limit
/>
</el-col>
<el-col>
<el-col
v-if=
"item.type !== 'file'"
>
<el-autocomplete
:disabled=
"isReadOnly"
size=
"small"
...
...
@@ -28,6 +34,10 @@
<i
slot=
"suffix"
class=
"el-input__icon el-icon-edit"
style=
"cursor: pointer;"
@
click=
"advanced(item)"
></i>
</el-autocomplete>
</el-col>
<el-col
v-if=
"item.type === 'file'"
>
<ms-api-body-file-upload
:parameter=
"item"
/>
</el-col>
<el-col
class=
"kv-delete"
>
<el-button
size=
"mini"
class=
"el-icon-delete-solid"
circle
@
click=
"remove(index)"
:disabled=
"isDisable(index) || isReadOnly"
/>
...
...
@@ -44,10 +54,11 @@
import
{
KeyValue
,
Scenario
}
from
"
../model/ScenarioModel
"
;
import
{
MOCKJS_FUNC
}
from
"
@/common/js/constants
"
;
import
MsApiVariableAdvance
from
"
@/business/components/api/test/components/ApiVariableAdvance
"
;
import
MsApiBodyFileUpload
from
"
./body/ApiBodyFileUpload
"
;
export
default
{
name
:
"
MsApiVariable
"
,
components
:
{
MsApiVariableAdvance
},
components
:
{
MsApi
BodyFileUpload
,
MsApi
VariableAdvance
},
props
:
{
keyPlaceholder
:
String
,
valuePlaceholder
:
String
,
...
...
@@ -55,6 +66,10 @@ export default {
parameters
:
Array
,
environment
:
Object
,
scenario
:
Scenario
,
type
:
{
type
:
String
,
default
:
''
},
isReadOnly
:
{
type
:
Boolean
,
default
:
false
...
...
@@ -93,7 +108,7 @@ export default {
}
});
if
(
isNeedCreate
)
{
this
.
parameters
.
push
(
new
KeyValue
());
this
.
parameters
.
push
(
new
KeyValue
(
null
,
null
,
'
text
'
));
}
this
.
$emit
(
'
change
'
,
this
.
parameters
);
// TODO 检查key重复
...
...
@@ -133,35 +148,38 @@ export default {
},
created
()
{
if
(
this
.
parameters
.
length
===
0
)
{
this
.
parameters
.
push
(
new
KeyValue
());
this
.
parameters
.
push
(
new
KeyValue
(
null
,
null
,
'
text
'
));
}
}
}
</
script
>
<
style
scoped
>
.kv-description
{
font-size
:
13px
;
}
.kv-description
{
font-size
:
13px
;
}
.kv-row
{
margin-top
:
10px
;
}
.kv-row
{
margin-top
:
10px
;
}
.kv-delete
{
width
:
60px
;
}
.kv-delete
{
width
:
60px
;
}
.el-autocomplete
{
width
:
100%
;
}
.el-autocomplete
{
width
:
100%
;
}
.advanced-item-value
>>>
.el-dialog__body
{
padding
:
15px
25px
;
}
.advanced-item-value
>>>
.el-dialog__body
{
padding
:
15px
25px
;
}
.el-row
{
margin-bottom
:
5px
;
}
.el-row
{
margin-bottom
:
5px
;
}
.kv-type
{
width
:
70px
;
}
</
style
>
frontend/src/business/components/api/test/components/ApiBody.vue
→
frontend/src/business/components/api/test/components/
body/
ApiBody.vue
浏览文件 @
d54b32ce
...
...
@@ -16,6 +16,7 @@
:environment=
"environment"
:scenario=
"scenario"
:extract=
"extract"
type=
"body"
:description=
"$t('api_test.request.parameters_desc')"
v-if=
"body.isKV()"
/>
<div
class=
"body-raw"
v-if=
"body.type == 'Raw'"
>
...
...
@@ -26,10 +27,10 @@
</
template
>
<
script
>
import
MsApiKeyValue
from
"
./ApiKeyValue
"
;
import
{
Body
,
BODY_FORMAT
,
BODY_TYPE
,
Scenario
}
from
"
../model/ScenarioModel
"
;
import
MsCodeEdit
from
"
../../../common/components/MsCodeEdit
"
;
import
MsDropdown
from
"
../../../common/components/MsDropdown
"
;
import
MsApiKeyValue
from
"
.
.
/ApiKeyValue
"
;
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
"
;
export
default
{
...
...
@@ -66,6 +67,11 @@ export default {
if
(
!
this
.
body
.
format
)
{
this
.
body
.
format
=
BODY_FORMAT
.
TEXT
;
}
this
.
body
.
kvs
.
forEach
(
param
=>
{
if
(
!
param
.
type
)
{
param
.
type
=
'
text
'
;
}
});
}
}
</
script
>
...
...
frontend/src/business/components/api/test/components/body/ApiBodyFileUpload.vue
0 → 100644
浏览文件 @
d54b32ce
<
template
>
<span>
<el-upload
action=
"#"
class=
"api-body-upload"
list-type=
"picture-card"
:http-request=
"upload"
:beforeUpload=
"uploadValidate"
:file-list=
"parameter.files"
ref=
"upload"
>
<div
class=
"upload-default"
>
<i
class=
"el-icon-plus"
/>
</div>
<div
class=
"upload-item"
slot=
"file"
slot-scope=
"
{file}" >
<span>
{{
file
.
file
?
file
.
file
.
name
:
file
.
name
}}
</span>
<span
class=
"el-upload-list__item-actions"
>
<!--
<span
v-if=
"!disabled"
class=
"el-upload-list__item-delete"
@
click=
"handleDownload(file)"
>
-->
<!--
<i
class=
"el-icon-download"
/>
-->
<!--
</span>
-->
<span
v-if=
"!disabled"
class=
"el-upload-list__item-delete"
@
click=
"handleRemove(file)"
>
<i
class=
"el-icon-delete"
/>
</span>
</span>
</div>
</el-upload>
</span>
</
template
>
<
script
>
export
default
{
name
:
"
MsApiBodyFileUpload
"
,
data
()
{
return
{
disabled
:
false
,
};
},
props
:
{
parameter
:
Object
,
default
()
{
return
{}
}
},
methods
:
{
handleRemove
(
file
)
{
this
.
$refs
.
upload
.
handleRemove
(
file
);
for
(
let
i
=
0
;
i
<
this
.
parameter
.
files
.
length
;
i
++
)
{
if
(
file
.
name
===
this
.
parameter
.
files
[
i
].
name
)
{
this
.
parameter
.
files
.
splice
(
i
,
1
);
this
.
$refs
.
upload
.
handleRemove
(
file
);
break
;
}
}
},
upload
(
file
)
{
this
.
parameter
.
files
.
push
(
file
);
},
uploadValidate
(
file
)
{
// if (file.size / 1024 / 1024 > 20) {
// this.$warning(this.$t('test_track.case.import.upload_limit_size'));
// return false;
// }
return
true
;
},
},
created
()
{
if
(
!
this
.
parameter
.
files
)
{
this
.
parameter
.
files
=
[];
}
}
}
</
script
>
<
style
scoped
>
.el-upload
{
background-color
:
black
;
}
.api-body-upload
>>>
.el-upload
{
height
:
32px
;
width
:
32px
;
}
.upload-default
{
min-height
:
32px
;
width
:
32px
;
line-height
:
32px
;
}
.el-icon-plus
{
font-size
:
16px
;
}
.api-body-upload
>>>
.el-upload-list__item
{
height
:
32px
;
width
:
auto
;
padding
:
6px
;
margin-bottom
:
0px
;
}
.api-body-upload
>>>
.el-upload-list--picture-card
{
}
.api-body-upload
{
min-height
:
32px
;
/*border: 1px solid #EBEEF5;*/
/*padding: 2px;*/
/*border-radius: 4px;*/
}
.upload-item
{
}
</
style
>
frontend/src/business/components/api/test/components/import/ApiImport.vue
浏览文件 @
d54b32ce
...
...
@@ -237,7 +237,7 @@
if
(
!
this
.
swaggerUrlEable
)
{
param
.
swaggerUrl
=
undefined
;
}
this
.
result
=
this
.
$fileUpload
(
'
/api/import
'
,
param
.
file
,
param
,
response
=>
{
this
.
result
=
this
.
$fileUpload
(
'
/api/import
'
,
param
.
file
,
null
,
param
,
response
=>
{
let
res
=
response
.
data
;
this
.
$success
(
this
.
$t
(
'
test_track.case.import.success
'
));
this
.
visible
=
false
;
...
...
frontend/src/business/components/api/test/components/request/ApiDubboRequestForm.vue
浏览文件 @
d54b32ce
...
...
@@ -56,7 +56,7 @@
<
script
>
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
MsApiBody
from
"
../ApiBody
"
;
import
MsApiBody
from
"
../
body/
ApiBody
"
;
import
MsApiAssertions
from
"
../assertion/ApiAssertions
"
;
import
{
DubboRequest
,
Scenario
}
from
"
../../model/ScenarioModel
"
;
import
MsApiExtract
from
"
../extract/ApiExtract
"
;
...
...
frontend/src/business/components/api/test/components/request/ApiHttpRequestForm.vue
浏览文件 @
d54b32ce
...
...
@@ -82,7 +82,7 @@
<
script
>
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
MsApiBody
from
"
../ApiBody
"
;
import
MsApiBody
from
"
../
body/
ApiBody
"
;
import
MsApiAssertions
from
"
../assertion/ApiAssertions
"
;
import
{
HttpRequest
,
KeyValue
,
Scenario
}
from
"
../../model/ScenarioModel
"
;
import
MsApiExtract
from
"
../extract/ApiExtract
"
;
...
...
frontend/src/business/components/api/test/model/JMX.js
浏览文件 @
d54b32ce
...
...
@@ -328,6 +328,25 @@ export class HTTPSamplerArguments extends Element {
}
}
export
class
HTTPsamplerFiles
extends
Element
{
constructor
(
args
)
{
super
(
'
elementProp
'
,
{
name
:
"
HTTPsampler.Files
"
,
elementType
:
"
HTTPFileArgs
"
,
});
this
.
args
=
args
||
{};
let
collectionProp
=
this
.
collectionProp
(
'
HTTPFileArgs.files
'
);
this
.
args
.
forEach
(
arg
=>
{
let
elementProp
=
collectionProp
.
elementProp
(
arg
.
value
,
'
HTTPFileArg
'
);
elementProp
.
stringProp
(
'
File.path
'
,
arg
.
value
);
elementProp
.
stringProp
(
'
File.paramname
'
,
arg
.
name
);
elementProp
.
stringProp
(
'
File.mimetype
'
,
arg
.
metadata
||
"
application/octet-stream
"
);
});
}
}
export
class
CookieManager
extends
DefaultTestElement
{
constructor
(
testName
)
{
super
(
'
CookieManager
'
,
'
CookiePanel
'
,
'
CookieManager
'
,
testName
);
...
...
frontend/src/business/components/api/test/model/ScenarioModel.js
浏览文件 @
d54b32ce
...
...
@@ -6,7 +6,7 @@ import {
Element
,
HashTree
,
HeaderManager
,
HTTPSamplerArguments
,
HTTPSamplerArguments
,
HTTPsamplerFiles
,
HTTPSamplerProxy
,
JSONPathAssertion
,
JSONPostProcessor
,
...
...
@@ -38,6 +38,8 @@ export const uuid = function () {
});
}
export
const
BODY_FILE_DIR
=
"
/opt/metersphere/data/body
"
;
//存放body文件上传目录
export
const
calculate
=
function
(
itemValue
)
{
if
(
!
itemValue
)
{
return
;
...
...
@@ -528,7 +530,7 @@ export class Body extends BaseConfig {
export
class
KeyValue
extends
BaseConfig
{
constructor
()
{
let
options
,
key
,
value
;
let
options
,
key
,
value
,
type
;
if
(
arguments
.
length
===
1
)
{
options
=
arguments
[
0
];
}
...
...
@@ -537,16 +539,27 @@ export class KeyValue extends BaseConfig {
key
=
arguments
[
0
];
value
=
arguments
[
1
];
}
if
(
arguments
.
length
===
3
)
{
key
=
arguments
[
0
];
value
=
arguments
[
1
];
type
=
arguments
[
2
];
}
super
();
this
.
name
=
key
;
this
.
value
=
value
;
this
.
type
=
type
;
this
.
files
=
undefined
;
this
.
set
(
options
);
}
isValid
()
{
return
!!
this
.
name
||
!!
this
.
value
;
return
(
!!
this
.
name
||
!!
this
.
value
)
&&
this
.
type
!==
'
file
'
;
}
isFile
()
{
return
(
!!
this
.
name
||
!!
this
.
value
)
&&
this
.
type
===
'
file
'
;
}
}
...
...
@@ -807,13 +820,13 @@ class JMXGenerator {
if
(
!
test
||
!
test
.
id
||
!
(
test
instanceof
Test
))
return
undefined
;
let
testPlan
=
new
TestPlan
(
test
.
name
);
this
.
addScenarios
(
testPlan
,
test
.
scenarioDefinition
);
this
.
addScenarios
(
testPlan
,
test
.
id
,
test
.
scenarioDefinition
);
this
.
jmeterTestPlan
=
new
JMeterTestPlan
();
this
.
jmeterTestPlan
.
put
(
testPlan
);
}
addScenarios
(
testPlan
,
scenarios
)
{
addScenarios
(
testPlan
,
testId
,
scenarios
)
{
scenarios
.
forEach
(
s
=>
{
if
(
s
.
enable
)
{
...
...
@@ -842,7 +855,7 @@ class JMXGenerator {
if
(
request
.
method
.
toUpperCase
()
===
'
GET
'
)
{
this
.
addRequestArguments
(
sampler
,
request
);
}
else
{
this
.
addRequestBody
(
sampler
,
request
);
this
.
addRequestBody
(
sampler
,
request
,
testId
);
}
}
...
...
@@ -965,10 +978,11 @@ class JMXGenerator {
}
}
addRequestBody
(
httpSamplerProxy
,
request
)
{
addRequestBody
(
httpSamplerProxy
,
request
,
testId
)
{
let
body
=
[];
if
(
request
.
body
.
isKV
())
{
body
=
this
.
filterKV
(
request
.
body
.
kvs
);
this
.
addRequestBodyFile
(
httpSamplerProxy
,
request
,
testId
);
}
else
{
httpSamplerProxy
.
boolProp
(
'
HTTPSampler.postBodyRaw
'
,
true
);
body
.
push
({
name
:
''
,
value
:
request
.
body
.
raw
,
encode
:
false
});
...
...
@@ -977,6 +991,22 @@ class JMXGenerator {
httpSamplerProxy
.
add
(
new
HTTPSamplerArguments
(
body
));
}
addRequestBodyFile
(
httpSamplerProxy
,
request
,
testId
)
{
let
files
=
[];
let
kvs
=
this
.
filterKVFile
(
request
.
body
.
kvs
);
kvs
.
forEach
(
kv
=>
{
if
(
kv
.
files
)
{
kv
.
files
.
forEach
(
file
=>
{
let
arg
=
{};
arg
.
name
=
kv
.
name
;
arg
.
value
=
BODY_FILE_DIR
+
'
/
'
+
testId
+
'
/
'
+
file
.
id
+
'
_
'
+
file
.
name
;
files
.
push
(
arg
);
});
}
});
httpSamplerProxy
.
add
(
new
HTTPsamplerFiles
(
files
));
}
addRequestAssertion
(
httpSamplerProxy
,
request
)
{
let
assertions
=
request
.
assertions
;
if
(
assertions
.
regex
.
length
>
0
)
{
...
...
@@ -1066,6 +1096,12 @@ class JMXGenerator {
return
kvs
.
filter
(
this
.
filter
);
}
filterKVFile
(
kvs
)
{
return
kvs
.
filter
(
kv
=>
{
return
kv
.
isFile
();
});
}
toXML
()
{
let
xml
=
'
<?xml version="1.0" encoding="UTF-8"?>
\n
'
;
xml
+=
this
.
jmeterTestPlan
.
toXML
();
...
...
frontend/src/business/components/track/case/components/TestCaseImport.vue
浏览文件 @
d54b32ce
...
...
@@ -102,7 +102,7 @@
upload
(
file
)
{
this
.
isLoading
=
false
;
this
.
fileList
.
push
(
file
.
file
);
this
.
result
=
this
.
$fileUpload
(
'
/test/case/import/
'
+
this
.
projectId
,
file
.
file
,
{},
response
=>
{
this
.
result
=
this
.
$fileUpload
(
'
/test/case/import/
'
+
this
.
projectId
,
file
.
file
,
null
,
{},
response
=>
{
let
res
=
response
.
data
;
if
(
res
.
success
)
{
this
.
$success
(
this
.
$t
(
'
test_track.case.import.success
'
));
...
...
xpack
@
7e4d80cc
比较
06fc0a32
...
7e4d80cc
Subproject commit
06fc0a321a9886419be5c607ddaa6b40efb5179b
Subproject commit
7e4d80cc2b870a8cac6dbb9fe6711ab6041faf6d
frontend/src/common/js/ajax.js
浏览文件 @
d54b32ce
...
...
@@ -142,9 +142,16 @@ export default {
});
};
Vue
.
prototype
.
$fileUpload
=
function
(
url
,
file
,
param
,
success
,
failure
)
{
Vue
.
prototype
.
$fileUpload
=
function
(
url
,
file
,
files
,
param
,
success
,
failure
)
{
let
formData
=
new
FormData
();
formData
.
append
(
"
file
"
,
file
);
if
(
file
)
{
formData
.
append
(
"
file
"
,
file
);
}
if
(
files
)
{
files
.
forEach
(
f
=>
{
formData
.
append
(
"
files
"
,
f
);
})
}
formData
.
append
(
'
request
'
,
new
Blob
([
JSON
.
stringify
(
param
)],
{
type
:
"
application/json
"
}));
let
axiosRequestConfig
=
{
method
:
'
POST
'
,
...
...
frontend/src/common/js/utils.js
浏览文件 @
d54b32ce
...
...
@@ -187,4 +187,11 @@ export function removeGoBackListener(callback) {
window
.
removeEventListener
(
'
popstate
'
,
callback
);
}
export
function
getUUID
()
{
function
S4
()
{
return
(((
1
+
Math
.
random
())
*
0x10000
)
|
0
).
toString
(
16
).
substring
(
1
);
}
return
(
S4
()
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
"
-
"
+
S4
()
+
S4
()
+
S4
());
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录