Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
6aa69cee
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,发现更多精彩内容 >>
提交
6aa69cee
编写于
4月 22, 2020
作者:
Q
q4speed
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
api测试,未完待续
上级
8dc32493
变更
31
隐藏空白更改
内联
并排
Showing
31 changed file
with
578 addition
and
368 deletion
+578
-368
backend/pom.xml
backend/pom.xml
+5
-0
backend/src/main/java/io/metersphere/api/controller/APITestController.java
...java/io/metersphere/api/controller/APITestController.java
+68
-0
backend/src/main/java/io/metersphere/api/dto/APITestResult.java
...d/src/main/java/io/metersphere/api/dto/APITestResult.java
+12
-0
backend/src/main/java/io/metersphere/api/dto/DeleteAPITestRequest.java
...ain/java/io/metersphere/api/dto/DeleteAPITestRequest.java
+11
-0
backend/src/main/java/io/metersphere/api/dto/QueryAPITestRequest.java
...main/java/io/metersphere/api/dto/QueryAPITestRequest.java
+16
-0
backend/src/main/java/io/metersphere/api/dto/SaveAPITestRequest.java
.../main/java/io/metersphere/api/dto/SaveAPITestRequest.java
+17
-0
backend/src/main/java/io/metersphere/api/service/ApiTestService.java
.../main/java/io/metersphere/api/service/ApiTestService.java
+100
-0
backend/src/main/java/io/metersphere/base/domain/ApiTest.java
...end/src/main/java/io/metersphere/base/domain/ApiTest.java
+10
-0
backend/src/main/java/io/metersphere/base/domain/ApiTestExample.java
.../main/java/io/metersphere/base/domain/ApiTestExample.java
+70
-0
backend/src/main/java/io/metersphere/base/domain/ApiTestWithBLOBs.java
...ain/java/io/metersphere/base/domain/ApiTestWithBLOBs.java
+5
-5
backend/src/main/java/io/metersphere/base/mapper/ApiTestMapper.xml
...rc/main/java/io/metersphere/base/mapper/ApiTestMapper.xml
+36
-17
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.java
...java/io/metersphere/base/mapper/ext/ExtApiTestMapper.java
+3
-3
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
.../java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
+2
-2
backend/src/main/java/io/metersphere/commons/constants/APITestStatus.java
.../java/io/metersphere/commons/constants/APITestStatus.java
+5
-0
backend/src/main/java/io/metersphere/controller/handler/ResultResponseBodyAdvice.java
...ersphere/controller/handler/ResultResponseBodyAdvice.java
+1
-1
backend/src/main/java/io/metersphere/dto/ApiTestDTO.java
backend/src/main/java/io/metersphere/dto/ApiTestDTO.java
+0
-15
backend/src/main/java/io/metersphere/service/ApiTestService.java
.../src/main/java/io/metersphere/service/ApiTestService.java
+0
-194
backend/src/main/resources/db/migration/V2__metersphere_ddl.sql
...d/src/main/resources/db/migration/V2__metersphere_ddl.sql
+10
-12
frontend/src/business/components/api/head/ApiHeaderMenus.vue
frontend/src/business/components/api/head/ApiHeaderMenus.vue
+38
-36
frontend/src/business/components/api/test/ApiTestConfig.vue
frontend/src/business/components/api/test/ApiTestConfig.vue
+31
-7
frontend/src/business/components/api/test/ApiTestList.vue
frontend/src/business/components/api/test/ApiTestList.vue
+19
-27
frontend/src/business/components/api/test/components/ApiAssertions.vue
...business/components/api/test/components/ApiAssertions.vue
+0
-7
frontend/src/business/components/api/test/components/ApiAssertionsEdit.vue
...ness/components/api/test/components/ApiAssertionsEdit.vue
+8
-1
frontend/src/business/components/api/test/components/ApiRequestConfig.vue
...iness/components/api/test/components/ApiRequestConfig.vue
+1
-4
frontend/src/business/components/api/test/components/ApiRequestForm.vue
...usiness/components/api/test/components/ApiRequestForm.vue
+2
-1
frontend/src/business/components/api/test/components/ApiScenarioConfig.vue
...ness/components/api/test/components/ApiScenarioConfig.vue
+19
-8
frontend/src/business/components/api/test/components/ApiScenarioForm.vue
...siness/components/api/test/components/ApiScenarioForm.vue
+2
-1
frontend/src/business/components/api/test/model/ScenarioModel.js
...d/src/business/components/api/test/model/ScenarioModel.js
+80
-10
frontend/src/business/components/common/head/CreateTest.vue
frontend/src/business/components/common/head/CreateTest.vue
+1
-1
frontend/src/business/components/common/router/router.js
frontend/src/business/components/common/router/router.js
+5
-16
frontend/src/i18n/zh-CN.js
frontend/src/i18n/zh-CN.js
+1
-0
未找到文件。
backend/pom.xml
浏览文件 @
6aa69cee
...
...
@@ -57,6 +57,11 @@
<artifactId>
spring-boot-starter-jetty
</artifactId>
</dependency>
<dependency>
<groupId>
org.projectlombok
</groupId>
<artifactId>
lombok
</artifactId>
</dependency>
<dependency>
<groupId>
org.mybatis.spring.boot
</groupId>
<artifactId>
mybatis-spring-boot-starter
</artifactId>
...
...
backend/src/main/java/io/metersphere/
controller/Api
TestController.java
→
backend/src/main/java/io/metersphere/
api/controller/API
TestController.java
浏览文件 @
6aa69cee
package
io.metersphere.controller
;
package
io.metersphere.
api.
controller
;
import
com.github.pagehelper.Page
;
import
com.github.pagehelper.PageHelper
;
import
io.metersphere.base.domain.FileMetadata
;
import
io.metersphere.api.dto.APITestResult
;
import
io.metersphere.api.dto.DeleteAPITestRequest
;
import
io.metersphere.api.dto.QueryAPITestRequest
;
import
io.metersphere.api.dto.SaveAPITestRequest
;
import
io.metersphere.api.service.ApiTestService
;
import
io.metersphere.base.domain.ApiTestWithBLOBs
;
import
io.metersphere.commons.constants.RoleConstants
;
import
io.metersphere.commons.utils.PageUtils
;
import
io.metersphere.commons.utils.Pager
;
import
io.metersphere.controller.request.testplan.*
;
import
io.metersphere.dto.ApiTestDTO
;
import
io.metersphere.service.FileService
;
import
io.metersphere.service.ApiTestService
;
import
io.metersphere.user.SessionUtils
;
import
org.apache.shiro.authz.annotation.Logical
;
import
org.apache.shiro.authz.annotation.RequiresRoles
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.MediaType
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
java.util.List
;
import
javax.annotation.Resource
;
@RestController
@RequestMapping
(
value
=
"/api"
)
@RequiresRoles
(
value
=
{
RoleConstants
.
TEST_MANAGER
,
RoleConstants
.
TEST_USER
,
RoleConstants
.
TEST_VIEWER
},
logical
=
Logical
.
OR
)
public
class
A
pi
TestController
{
public
class
A
PI
TestController
{
@Resource
private
ApiTestService
apiTestService
;
@Resource
private
FileService
fileService
;
@GetMapping
(
"recent/{count}"
)
public
List
<
A
piTestDTO
>
recentTestPlans
(
@PathVariable
int
count
)
{
public
List
<
A
PITestResult
>
recentTest
(
@PathVariable
int
count
)
{
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
Query
TestPlanRequest
request
=
new
QueryTestPlan
Request
();
Query
APITestRequest
request
=
new
QueryAPITest
Request
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
PageHelper
.
startPage
(
1
,
count
,
true
);
return
apiTestService
.
recentTest
Plans
(
request
);
return
apiTestService
.
recentTest
(
request
);
}
@PostMapping
(
"/list/{goPage}/{pageSize}"
)
public
Pager
<
List
<
A
piTestDTO
>>
list
(
@PathVariable
int
goPage
,
@PathVariable
int
pageSize
,
@RequestBody
QueryTestPlan
Request
request
)
{
public
Pager
<
List
<
A
PITestResult
>>
list
(
@PathVariable
int
goPage
,
@PathVariable
int
pageSize
,
@RequestBody
QueryAPITest
Request
request
)
{
Page
<
Object
>
page
=
PageHelper
.
startPage
(
goPage
,
pageSize
,
true
);
request
.
setWorkspaceId
(
SessionUtils
.
getCurrentWorkspaceId
());
return
PageUtils
.
setPageInfo
(
page
,
apiTestService
.
list
(
request
));
}
@PostMapping
(
value
=
"/save"
,
consumes
=
{
"multipart/form-data"
})
public
String
save
(
@RequestPart
(
"request"
)
SaveTestPlanRequest
request
,
@RequestPart
(
value
=
"file"
)
MultipartFile
file
)
{
return
apiTestService
.
save
(
request
,
file
);
}
@PostMapping
(
value
=
"/edit"
,
consumes
=
{
"multipart/form-data"
})
public
String
edit
(
@RequestPart
(
"request"
)
EditTestPlanRequest
request
,
@RequestPart
(
value
=
"file"
,
required
=
false
)
MultipartFile
file
)
{
return
apiTestService
.
edit
(
request
,
file
);
@PostMapping
(
value
=
"/save"
)
public
String
save
(
@RequestBody
SaveAPITestRequest
request
)
{
return
apiTestService
.
save
(
request
);
}
@GetMapping
(
"/get/{testId}"
)
public
ApiTest
DTO
get
(
@PathVariable
String
testId
)
{
public
ApiTest
WithBLOBs
get
(
@PathVariable
String
testId
)
{
return
apiTestService
.
get
(
testId
);
}
@GetMapping
(
"/get-runtime-config/{testId}"
)
public
String
getAdvancedConfiguration
(
@PathVariable
String
testId
)
{
return
apiTestService
.
getRuntimeConfiguration
(
testId
);
}
@PostMapping
(
"/delete"
)
public
void
delete
(
@RequestBody
Delete
TestPlan
Request
request
)
{
public
void
delete
(
@RequestBody
Delete
APITest
Request
request
)
{
apiTestService
.
delete
(
request
);
}
@PostMapping
(
"/run"
)
public
void
run
(
@RequestBody
RunTestPlanRequest
request
)
{
apiTestService
.
run
(
request
);
}
@GetMapping
(
"/file/metadata/{testId}"
)
public
FileMetadata
getFileMetadata
(
@PathVariable
String
testId
)
{
return
fileService
.
getApiFileMetadataByTestId
(
testId
);
}
@PostMapping
(
"/file/download"
)
public
ResponseEntity
<
byte
[]>
downloadJmx
(
@RequestBody
FileOperationRequest
fileOperationRequest
)
{
byte
[]
bytes
=
fileService
.
loadFileAsBytes
(
fileOperationRequest
.
getId
());
return
ResponseEntity
.
ok
()
.
contentType
(
MediaType
.
parseMediaType
(
"application/octet-stream"
))
.
header
(
HttpHeaders
.
CONTENT_DISPOSITION
,
"attachment; filename=\""
+
fileOperationRequest
.
getName
()
+
"\""
)
.
body
(
bytes
);
}
//
// @PostMapping("/run")
// public void run(@RequestBody RunTestPlanRequest request) {
// apiTestService.run(request);
// }
}
backend/src/main/java/io/metersphere/api/dto/APITestResult.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.api.dto
;
import
io.metersphere.base.domain.ApiTestWithBLOBs
;
import
lombok.Getter
;
import
lombok.Setter
;
@Setter
@Getter
public
class
APITestResult
extends
ApiTestWithBLOBs
{
private
String
projectName
;
}
backend/src/main/java/io/metersphere/api/dto/DeleteAPITestRequest.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.api.dto
;
import
lombok.Getter
;
import
lombok.Setter
;
@Setter
@Getter
public
class
DeleteAPITestRequest
{
private
String
id
;
}
backend/src/main/java/io/metersphere/api/dto/QueryAPITestRequest.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.api.dto
;
import
lombok.Getter
;
import
lombok.Setter
;
@Getter
@Setter
public
class
QueryAPITestRequest
{
private
String
id
;
private
String
projectId
;
private
String
name
;
private
String
workspaceId
;
private
boolean
recent
=
false
;
}
backend/src/main/java/io/metersphere/api/dto/SaveAPITestRequest.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.api.dto
;
import
lombok.Getter
;
import
lombok.Setter
;
@Setter
@Getter
public
class
SaveAPITestRequest
{
private
String
id
;
private
String
projectId
;
private
String
name
;
private
String
scenarioDefinition
;
}
backend/src/main/java/io/metersphere/api/service/ApiTestService.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.api.service
;
import
io.metersphere.api.dto.APITestResult
;
import
io.metersphere.api.dto.DeleteAPITestRequest
;
import
io.metersphere.api.dto.QueryAPITestRequest
;
import
io.metersphere.api.dto.SaveAPITestRequest
;
import
io.metersphere.base.domain.*
;
import
io.metersphere.base.mapper.*
;
import
io.metersphere.base.mapper.ext.ExtApiTestMapper
;
import
io.metersphere.commons.constants.APITestStatus
;
import
io.metersphere.commons.exception.MSException
;
import
io.metersphere.i18n.Translator
;
import
io.metersphere.service.FileService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.List
;
import
java.util.UUID
;
import
javax.annotation.Resource
;
@Service
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
class
ApiTestService
{
@Resource
private
ApiTestMapper
apiTestMapper
;
@Resource
private
ExtApiTestMapper
extApiTestMapper
;
@Resource
private
ProjectMapper
projectMapper
;
@Resource
private
FileMetadataMapper
fileMetadataMapper
;
@Resource
private
FileContentMapper
fileContentMapper
;
@Resource
private
ApiTestFileMapper
apiTestFileMapper
;
@Resource
private
FileService
fileService
;
public
List
<
APITestResult
>
list
(
QueryAPITestRequest
request
)
{
return
extApiTestMapper
.
list
(
request
);
}
public
List
<
APITestResult
>
recentTest
(
QueryAPITestRequest
request
)
{
request
.
setRecent
(
true
);
return
extApiTestMapper
.
list
(
request
);
}
public
String
save
(
SaveAPITestRequest
request
)
{
final
ApiTestWithBLOBs
test
;
if
(
StringUtils
.
isNotBlank
(
request
.
getId
()))
{
test
=
updateTest
(
request
);
}
else
{
test
=
createTest
(
request
);
}
return
test
.
getId
();
}
public
ApiTestWithBLOBs
get
(
String
id
)
{
return
apiTestMapper
.
selectByPrimaryKey
(
id
);
}
public
void
delete
(
DeleteAPITestRequest
request
)
{
apiTestMapper
.
deleteByPrimaryKey
(
request
.
getId
());
}
private
ApiTestWithBLOBs
updateTest
(
SaveAPITestRequest
request
)
{
final
ApiTestWithBLOBs
test
=
new
ApiTestWithBLOBs
();
test
.
setId
(
request
.
getId
());
test
.
setName
(
request
.
getName
());
test
.
setProjectId
(
request
.
getProjectId
());
test
.
setScenarioDefinition
(
request
.
getScenarioDefinition
());
test
.
setUpdateTime
(
System
.
currentTimeMillis
());
test
.
setStatus
(
APITestStatus
.
Saved
.
name
());
apiTestMapper
.
updateByPrimaryKeySelective
(
test
);
return
test
;
}
private
ApiTestWithBLOBs
createTest
(
SaveAPITestRequest
request
)
{
ApiTestExample
example
=
new
ApiTestExample
();
example
.
createCriteria
().
andNameEqualTo
(
request
.
getName
()).
andProjectIdEqualTo
(
request
.
getProjectId
());
if
(
apiTestMapper
.
countByExample
(
example
)
>
0
)
{
MSException
.
throwException
(
Translator
.
get
(
"load_test_already_exists"
));
}
final
ApiTestWithBLOBs
test
=
new
ApiTestWithBLOBs
();
test
.
setId
(
UUID
.
randomUUID
().
toString
());
test
.
setName
(
request
.
getName
());
test
.
setProjectId
(
request
.
getProjectId
());
test
.
setScenarioDefinition
(
request
.
getScenarioDefinition
());
test
.
setCreateTime
(
System
.
currentTimeMillis
());
test
.
setUpdateTime
(
System
.
currentTimeMillis
());
test
.
setStatus
(
APITestStatus
.
Saved
.
name
());
apiTestMapper
.
insert
(
test
);
return
test
;
}
}
backend/src/main/java/io/metersphere/base/domain/ApiTest.java
浏览文件 @
6aa69cee
...
...
@@ -11,6 +11,8 @@ public class ApiTest implements Serializable {
private
String
description
;
private
String
status
;
private
Long
createTime
;
private
Long
updateTime
;
...
...
@@ -49,6 +51,14 @@ public class ApiTest implements Serializable {
this
.
description
=
description
==
null
?
null
:
description
.
trim
();
}
public
String
getStatus
()
{
return
status
;
}
public
void
setStatus
(
String
status
)
{
this
.
status
=
status
==
null
?
null
:
status
.
trim
();
}
public
Long
getCreateTime
()
{
return
createTime
;
}
...
...
backend/src/main/java/io/metersphere/base/domain/ApiTestExample.java
浏览文件 @
6aa69cee
...
...
@@ -384,6 +384,76 @@ public class ApiTestExample {
return
(
Criteria
)
this
;
}
public
Criteria
andStatusIsNull
()
{
addCriterion
(
"status is null"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusIsNotNull
()
{
addCriterion
(
"status is not null"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusEqualTo
(
String
value
)
{
addCriterion
(
"status ="
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusNotEqualTo
(
String
value
)
{
addCriterion
(
"status <>"
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusGreaterThan
(
String
value
)
{
addCriterion
(
"status >"
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusGreaterThanOrEqualTo
(
String
value
)
{
addCriterion
(
"status >="
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusLessThan
(
String
value
)
{
addCriterion
(
"status <"
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusLessThanOrEqualTo
(
String
value
)
{
addCriterion
(
"status <="
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusLike
(
String
value
)
{
addCriterion
(
"status like"
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusNotLike
(
String
value
)
{
addCriterion
(
"status not like"
,
value
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusIn
(
List
<
String
>
values
)
{
addCriterion
(
"status in"
,
values
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusNotIn
(
List
<
String
>
values
)
{
addCriterion
(
"status not in"
,
values
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusBetween
(
String
value1
,
String
value2
)
{
addCriterion
(
"status between"
,
value1
,
value2
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andStatusNotBetween
(
String
value1
,
String
value2
)
{
addCriterion
(
"status not between"
,
value1
,
value2
,
"status"
);
return
(
Criteria
)
this
;
}
public
Criteria
andCreateTimeIsNull
()
{
addCriterion
(
"create_time is null"
);
return
(
Criteria
)
this
;
...
...
backend/src/main/java/io/metersphere/base/domain/ApiTestWithBLOBs.java
浏览文件 @
6aa69cee
...
...
@@ -3,18 +3,18 @@ package io.metersphere.base.domain;
import
java.io.Serializable
;
public
class
ApiTestWithBLOBs
extends
ApiTest
implements
Serializable
{
private
String
runtimeConfigura
tion
;
private
String
scenarioDefini
tion
;
private
String
schedule
;
private
static
final
long
serialVersionUID
=
1L
;
public
String
get
RuntimeConfigura
tion
()
{
return
runtimeConfigura
tion
;
public
String
get
ScenarioDefini
tion
()
{
return
scenarioDefini
tion
;
}
public
void
set
RuntimeConfiguration
(
String
runtimeConfigura
tion
)
{
this
.
runtimeConfiguration
=
runtimeConfiguration
==
null
?
null
:
runtimeConfigura
tion
.
trim
();
public
void
set
ScenarioDefinition
(
String
scenarioDefini
tion
)
{
this
.
scenarioDefinition
=
scenarioDefinition
==
null
?
null
:
scenarioDefini
tion
.
trim
();
}
public
String
getSchedule
()
{
...
...
backend/src/main/java/io/metersphere/base/mapper/ApiTestMapper.xml
浏览文件 @
6aa69cee
...
...
@@ -6,11 +6,12 @@
<result
column=
"project_id"
jdbcType=
"VARCHAR"
property=
"projectId"
/>
<result
column=
"name"
jdbcType=
"VARCHAR"
property=
"name"
/>
<result
column=
"description"
jdbcType=
"VARCHAR"
property=
"description"
/>
<result
column=
"status"
jdbcType=
"VARCHAR"
property=
"status"
/>
<result
column=
"create_time"
jdbcType=
"BIGINT"
property=
"createTime"
/>
<result
column=
"update_time"
jdbcType=
"BIGINT"
property=
"updateTime"
/>
</resultMap>
<resultMap
extends=
"BaseResultMap"
id=
"ResultMapWithBLOBs"
type=
"io.metersphere.base.domain.ApiTestWithBLOBs"
>
<result
column=
"
runtime_configuration"
jdbcType=
"LONGVARCHAR"
property=
"runtimeConfigura
tion"
/>
<result
column=
"
scenario_definition"
jdbcType=
"LONGVARCHAR"
property=
"scenarioDefini
tion"
/>
<result
column=
"schedule"
jdbcType=
"LONGVARCHAR"
property=
"schedule"
/>
</resultMap>
<sql
id=
"Example_Where_Clause"
>
...
...
@@ -72,10 +73,10 @@
</where>
</sql>
<sql
id=
"Base_Column_List"
>
id, project_id, name, description, create_time, update_time
id, project_id, name, description,
status,
create_time, update_time
</sql>
<sql
id=
"Blob_Column_List"
>
runtime_configura
tion, schedule
scenario_defini
tion, schedule
</sql>
<select
id=
"selectByExampleWithBLOBs"
parameterType=
"io.metersphere.base.domain.ApiTestExample"
resultMap=
"ResultMapWithBLOBs"
>
select
...
...
@@ -127,11 +128,13 @@
</delete>
<insert
id=
"insert"
parameterType=
"io.metersphere.base.domain.ApiTestWithBLOBs"
>
insert into api_test (id, project_id, name,
description, create_time, update_time,
runtime_configuration, schedule)
description, status, create_time,
update_time, scenario_definition, schedule
)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{runtimeConfiguration,jdbcType=LONGVARCHAR}, #{schedule,jdbcType=LONGVARCHAR})
#{description,jdbcType=VARCHAR}, #{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{scenarioDefinition,jdbcType=LONGVARCHAR}, #{schedule,jdbcType=LONGVARCHAR}
)
</insert>
<insert
id=
"insertSelective"
parameterType=
"io.metersphere.base.domain.ApiTestWithBLOBs"
>
insert into api_test
...
...
@@ -148,14 +151,17 @@
<if
test=
"description != null"
>
description,
</if>
<if
test=
"status != null"
>
status,
</if>
<if
test=
"createTime != null"
>
create_time,
</if>
<if
test=
"updateTime != null"
>
update_time,
</if>
<if
test=
"
runtimeConfigura
tion != null"
>
runtime_configura
tion,
<if
test=
"
scenarioDefini
tion != null"
>
scenario_defini
tion,
</if>
<if
test=
"schedule != null"
>
schedule,
...
...
@@ -174,14 +180,17 @@
<if
test=
"description != null"
>
#{description,jdbcType=VARCHAR},
</if>
<if
test=
"status != null"
>
#{status,jdbcType=VARCHAR},
</if>
<if
test=
"createTime != null"
>
#{createTime,jdbcType=BIGINT},
</if>
<if
test=
"updateTime != null"
>
#{updateTime,jdbcType=BIGINT},
</if>
<if
test=
"
runtimeConfigura
tion != null"
>
#{
runtimeConfigura
tion,jdbcType=LONGVARCHAR},
<if
test=
"
scenarioDefini
tion != null"
>
#{
scenarioDefini
tion,jdbcType=LONGVARCHAR},
</if>
<if
test=
"schedule != null"
>
#{schedule,jdbcType=LONGVARCHAR},
...
...
@@ -209,14 +218,17 @@
<if
test=
"record.description != null"
>
description = #{record.description,jdbcType=VARCHAR},
</if>
<if
test=
"record.status != null"
>
status = #{record.status,jdbcType=VARCHAR},
</if>
<if
test=
"record.createTime != null"
>
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if
test=
"record.updateTime != null"
>
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if
test=
"record.
runtimeConfigura
tion != null"
>
runtime_configuration = #{record.runtimeConfigura
tion,jdbcType=LONGVARCHAR},
<if
test=
"record.
scenarioDefini
tion != null"
>
scenario_definition = #{record.scenarioDefini
tion,jdbcType=LONGVARCHAR},
</if>
<if
test=
"record.schedule != null"
>
schedule = #{record.schedule,jdbcType=LONGVARCHAR},
...
...
@@ -232,9 +244,10 @@
project_id = #{record.projectId,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
runtime_configuration = #{record.runtimeConfigura
tion,jdbcType=LONGVARCHAR},
scenario_definition = #{record.scenarioDefini
tion,jdbcType=LONGVARCHAR},
schedule = #{record.schedule,jdbcType=LONGVARCHAR}
<if
test=
"_parameter != null"
>
<include
refid=
"Update_By_Example_Where_Clause"
/>
...
...
@@ -246,6 +259,7 @@
project_id = #{record.projectId,jdbcType=VARCHAR},
name = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT}
<if
test=
"_parameter != null"
>
...
...
@@ -264,14 +278,17 @@
<if
test=
"description != null"
>
description = #{description,jdbcType=VARCHAR},
</if>
<if
test=
"status != null"
>
status = #{status,jdbcType=VARCHAR},
</if>
<if
test=
"createTime != null"
>
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if
test=
"updateTime != null"
>
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if
test=
"
runtimeConfigura
tion != null"
>
runtime_configuration = #{runtimeConfigura
tion,jdbcType=LONGVARCHAR},
<if
test=
"
scenarioDefini
tion != null"
>
scenario_definition = #{scenarioDefini
tion,jdbcType=LONGVARCHAR},
</if>
<if
test=
"schedule != null"
>
schedule = #{schedule,jdbcType=LONGVARCHAR},
...
...
@@ -284,9 +301,10 @@
set project_id = #{projectId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
runtime_configuration = #{runtimeConfigura
tion,jdbcType=LONGVARCHAR},
scenario_definition = #{scenarioDefini
tion,jdbcType=LONGVARCHAR},
schedule = #{schedule,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
...
...
@@ -295,6 +313,7 @@
set project_id = #{projectId,jdbcType=VARCHAR},
name = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.java
浏览文件 @
6aa69cee
package
io.metersphere.base.mapper.ext
;
import
io.metersphere.
controller.request.testplan.QueryTestPlanReques
t
;
import
io.metersphere.
dto.ApiTestDTO
;
import
io.metersphere.
api.dto.APITestResul
t
;
import
io.metersphere.
api.dto.QueryAPITestRequest
;
import
org.apache.ibatis.annotations.Param
;
import
java.util.List
;
public
interface
ExtApiTestMapper
{
List
<
A
piTestDTO
>
list
(
@Param
(
"request"
)
QueryTestPlanRequest
params
);
List
<
A
PITestResult
>
list
(
@Param
(
"request"
)
QueryAPITestRequest
request
);
}
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
浏览文件 @
6aa69cee
...
...
@@ -2,12 +2,12 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper
namespace=
"io.metersphere.base.mapper.ext.ExtApiTestMapper"
>
<resultMap
id=
"BaseResultMap"
type=
"io.metersphere.
dto.ApiTestDTO
"
<resultMap
id=
"BaseResultMap"
type=
"io.metersphere.
api.dto.APITestResult
"
extends=
"io.metersphere.base.mapper.ApiTestMapper.BaseResultMap"
>
<result
column=
"project_name"
property=
"projectName"
/>
</resultMap>
<select
id=
"list"
resultMap=
"BaseResultMap"
parameterType=
"io.metersphere.
controller.request.testplan.QueryTestPlanReques
t"
>
<select
id=
"list"
resultMap=
"BaseResultMap"
parameterType=
"io.metersphere.
api.dto.APITestResul
t"
>
select api_test.*, project.name as project_name
from api_test
left join project on api_test.project_id = project.id
...
...
backend/src/main/java/io/metersphere/commons/constants/APITestStatus.java
0 → 100644
浏览文件 @
6aa69cee
package
io.metersphere.commons.constants
;
public
enum
APITestStatus
{
Saved
,
Starting
,
Running
,
Completed
,
Error
}
backend/src/main/java/io/metersphere/controller/handler/ResultResponseBodyAdvice.java
浏览文件 @
6aa69cee
...
...
@@ -15,7 +15,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* 统一处理返回结果集
*/
@RestControllerAdvice
(
value
=
{
"io.metersphere.controller"
})
@RestControllerAdvice
(
value
=
{
"io.metersphere.controller"
,
"io.metersphere.api.controller"
})
public
class
ResultResponseBodyAdvice
implements
ResponseBodyAdvice
<
Object
>
{
@Override
...
...
backend/src/main/java/io/metersphere/dto/ApiTestDTO.java
已删除
100644 → 0
浏览文件 @
8dc32493
package
io.metersphere.dto
;
import
io.metersphere.base.domain.LoadTest
;
public
class
ApiTestDTO
extends
LoadTest
{
private
String
projectName
;
public
String
getProjectName
()
{
return
projectName
;
}
public
void
setProjectName
(
String
projectName
)
{
this
.
projectName
=
projectName
;
}
}
backend/src/main/java/io/metersphere/service/ApiTestService.java
已删除
100644 → 0
浏览文件 @
8dc32493
package
io.metersphere.service
;
import
io.metersphere.base.domain.*
;
import
io.metersphere.base.mapper.*
;
import
io.metersphere.base.mapper.ext.ExtApiTestMapper
;
import
io.metersphere.commons.exception.MSException
;
import
io.metersphere.controller.request.testplan.*
;
import
io.metersphere.dto.ApiTestDTO
;
import
io.metersphere.i18n.Translator
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
java.io.IOException
;
import
java.util.List
;
import
java.util.Optional
;
import
java.util.UUID
;
@Service
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
class
ApiTestService
{
@Resource
private
ApiTestMapper
ApiTestMapper
;
@Resource
private
ExtApiTestMapper
extApiTestMapper
;
@Resource
private
ProjectMapper
projectMapper
;
@Resource
private
FileMetadataMapper
fileMetadataMapper
;
@Resource
private
FileContentMapper
fileContentMapper
;
@Resource
private
ApiTestFileMapper
ApiTestFileMapper
;
@Resource
private
FileService
fileService
;
public
List
<
ApiTestDTO
>
list
(
QueryTestPlanRequest
request
)
{
return
extApiTestMapper
.
list
(
request
);
}
public
void
delete
(
DeleteTestPlanRequest
request
)
{
ApiTestMapper
.
deleteByPrimaryKey
(
request
.
getId
());
fileService
.
deleteFileByTestId
(
request
.
getId
());
}
public
String
save
(
SaveTestPlanRequest
request
,
MultipartFile
file
)
{
if
(
file
==
null
)
{
throw
new
IllegalArgumentException
(
"文件不能为空!"
);
}
final
FileMetadata
fileMetadata
=
saveFile
(
file
);
final
ApiTestWithBLOBs
ApiTest
=
saveApiTest
(
request
);
ApiTestFile
ApiTestFile
=
new
ApiTestFile
();
ApiTestFile
.
setTestId
(
ApiTest
.
getId
());
ApiTestFile
.
setFileId
(
fileMetadata
.
getId
());
ApiTestFileMapper
.
insert
(
ApiTestFile
);
return
ApiTest
.
getId
();
}
private
ApiTestWithBLOBs
saveApiTest
(
SaveTestPlanRequest
request
)
{
ApiTestExample
example
=
new
ApiTestExample
();
example
.
createCriteria
().
andNameEqualTo
(
request
.
getName
()).
andProjectIdEqualTo
(
request
.
getProjectId
());
if
(
ApiTestMapper
.
countByExample
(
example
)
>
0
)
{
MSException
.
throwException
(
Translator
.
get
(
"function_test_already_exists"
));
}
final
ApiTestWithBLOBs
ApiTes
=
new
ApiTestWithBLOBs
();
ApiTes
.
setId
(
UUID
.
randomUUID
().
toString
());
ApiTes
.
setName
(
request
.
getName
());
ApiTes
.
setProjectId
(
request
.
getProjectId
());
ApiTes
.
setCreateTime
(
System
.
currentTimeMillis
());
ApiTes
.
setUpdateTime
(
System
.
currentTimeMillis
());
ApiTes
.
setDescription
(
"todo"
);
ApiTes
.
setRuntimeConfiguration
(
request
.
getRuntimeConfiguration
());
ApiTestMapper
.
insert
(
ApiTes
);
return
ApiTes
;
}
private
FileMetadata
saveFile
(
MultipartFile
file
)
{
final
FileMetadata
fileMetadata
=
new
FileMetadata
();
fileMetadata
.
setId
(
UUID
.
randomUUID
().
toString
());
fileMetadata
.
setName
(
file
.
getOriginalFilename
());
fileMetadata
.
setSize
(
file
.
getSize
());
fileMetadata
.
setCreateTime
(
System
.
currentTimeMillis
());
fileMetadata
.
setUpdateTime
(
System
.
currentTimeMillis
());
fileMetadata
.
setType
(
"jmx"
);
fileMetadataMapper
.
insert
(
fileMetadata
);
FileContent
fileContent
=
new
FileContent
();
fileContent
.
setFileId
(
fileMetadata
.
getId
());
try
{
fileContent
.
setFile
(
file
.
getBytes
());
}
catch
(
IOException
e
)
{
MSException
.
throwException
(
e
);
}
fileContentMapper
.
insert
(
fileContent
);
return
fileMetadata
;
}
public
String
edit
(
EditTestPlanRequest
request
,
MultipartFile
file
)
{
// 新选择了一个文件,删除原来的文件
if
(
file
!=
null
)
{
fileService
.
deleteFileByTestId
(
request
.
getId
());
final
FileMetadata
fileMetadata
=
saveFile
(
file
);
ApiTestFile
ApiTestFile
=
new
ApiTestFile
();
ApiTestFile
.
setTestId
(
request
.
getId
());
ApiTestFile
.
setFileId
(
fileMetadata
.
getId
());
ApiTestFileMapper
.
insert
(
ApiTestFile
);
}
final
ApiTestWithBLOBs
ApiTest
=
ApiTestMapper
.
selectByPrimaryKey
(
request
.
getId
());
if
(
ApiTest
==
null
)
{
MSException
.
throwException
(
"无法编辑测试,未找到测试:"
+
request
.
getId
());
}
else
{
ApiTest
.
setName
(
request
.
getName
());
ApiTest
.
setProjectId
(
request
.
getProjectId
());
ApiTest
.
setUpdateTime
(
System
.
currentTimeMillis
());
ApiTest
.
setDescription
(
"todo"
);
ApiTest
.
setRuntimeConfiguration
(
request
.
getRuntimeConfiguration
());
ApiTestMapper
.
updateByPrimaryKeySelective
(
ApiTest
);
}
return
request
.
getId
();
}
public
void
run
(
RunTestPlanRequest
request
)
{
final
ApiTestWithBLOBs
ApiTest
=
ApiTestMapper
.
selectByPrimaryKey
(
request
.
getId
());
// if (ApiTest == null) {
// MSException.throwException("无法运行测试,未找到测试:" + request.getId());
// }
//
// final List<FileMetadata> fileMetadataList = fileService.getFileMetadataByTestId(request.getId());
// if (fileMetadataList == null) {
// MSException.throwException("无法运行测试,无法获取测试文件元信息,测试ID:" + request.getId());
// }
//
// final FileContent fileContent = fileService.getFileContent(fileMetadata.getId());
// if (fileContent == null) {
// MSException.throwException("无法运行测试,无法获取测试文件内容,测试ID:" + request.getId());
// }
//
// System.out.println("开始运行:" + ApiTest.getName());
// final Engine engine = EngineFactory.createEngine(fileMetadata.getType());
// if (engine == null) {
// MSException.throwException(String.format("无法运行测试,未识别测试文件类型,测试ID:%s,文件类型:%s",
// request.getId(),
// fileMetadata.getType()));
// }
//
// boolean init = true;
// try {
//// init = engine.init(EngineFactory.createContext(ApiTest, fileMetadata, fileContent));
// } catch (Exception e) {
// MSException.throwException(e);
// }
// if (!init) {
// MSException.throwException(String.format("无法运行测试,初始化运行环境失败,测试ID:%s", request.getId()));
// }
//
//// engine.start();
/// todo:通过调用stop方法能够停止正在运行的engine,但是如果部署了多个backend实例,页面发送的停止请求如何定位到具体的engine
}
public
List
<
ApiTestDTO
>
recentTestPlans
(
QueryTestPlanRequest
request
)
{
// 查询最近的测试计划
request
.
setRecent
(
true
);
return
extApiTestMapper
.
list
(
request
);
}
public
ApiTestDTO
get
(
String
testId
)
{
QueryTestPlanRequest
request
=
new
QueryTestPlanRequest
();
request
.
setId
(
testId
);
List
<
ApiTestDTO
>
testDTOS
=
extApiTestMapper
.
list
(
request
);
if
(!
CollectionUtils
.
isEmpty
(
testDTOS
))
{
return
testDTOS
.
get
(
0
);
}
return
null
;
}
public
String
getRuntimeConfiguration
(
String
testId
)
{
ApiTestWithBLOBs
ApiTestWithBLOBs
=
ApiTestMapper
.
selectByPrimaryKey
(
testId
);
return
Optional
.
ofNullable
(
ApiTestWithBLOBs
).
orElse
(
new
ApiTestWithBLOBs
()).
getRuntimeConfiguration
();
}
}
backend/src/main/resources/db/migration/V2__metersphere_ddl.sql
浏览文件 @
6aa69cee
...
...
@@ -194,19 +194,17 @@ CREATE TABLE IF NOT EXISTS `workspace` (
-- api start
CREATE
TABLE
IF
NOT
EXISTS
`api_test`
(
`id`
varchar
(
50
)
NOT
NULL
COMMENT
'Test ID'
,
`project_id`
varchar
(
50
)
NOT
NULL
COMMENT
'Project ID this test belongs to'
,
`name`
varchar
(
64
)
NOT
NULL
COMMENT
'Test name'
,
`description`
varchar
(
255
)
DEFAULT
NULL
COMMENT
'Test description'
,
`runtime_configuration`
longtext
COMMENT
'Load configuration (JSON format)'
,
`schedule`
longtext
COMMENT
'Test schedule (cron list)'
,
`create_time`
bigint
(
13
)
NOT
NULL
COMMENT
'Create timestamp'
,
`update_time`
bigint
(
13
)
NOT
NULL
COMMENT
'Update timestamp'
,
`id`
varchar
(
50
)
COLLATE
utf8mb4_bin
NOT
NULL
COMMENT
'Test ID'
,
`project_id`
varchar
(
50
)
COLLATE
utf8mb4_bin
NOT
NULL
COMMENT
'Project ID this test belongs to'
,
`name`
varchar
(
64
)
COLLATE
utf8mb4_bin
NOT
NULL
COMMENT
'Test name'
,
`description`
varchar
(
255
)
COLLATE
utf8mb4_bin
DEFAULT
NULL
COMMENT
'Test description'
,
`scenario_definition`
longtext
COLLATE
utf8mb4_bin
COMMENT
'Scenario definition (JSON format)'
,
`schedule`
longtext
COLLATE
utf8mb4_bin
COMMENT
'Test schedule (cron list)'
,
`status`
varchar
(
64
)
COLLATE
utf8mb4_bin
DEFAULT
NULL
,
`create_time`
bigint
(
13
)
NOT
NULL
COMMENT
'Create timestamp'
,
`update_time`
bigint
(
13
)
NOT
NULL
COMMENT
'Update timestamp'
,
PRIMARY
KEY
(
`id`
)
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_bin
;
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_bin
;
CREATE
TABLE
IF
NOT
EXISTS
`api_test_file`
(
`test_id`
varchar
(
64
)
DEFAULT
NULL
,
...
...
frontend/src/business/components/api/head/ApiHeaderMenus.vue
浏览文件 @
6aa69cee
<
template
>
<div
id=
"menu-bar"
v-if=
"isRouterAlive"
>
<div
id=
"menu-bar"
>
<el-row
type=
"flex"
>
<el-col
:span=
"8"
>
<el-menu
class=
"header-menu"
:unique-opened=
"true"
mode=
"horizontal"
router
:default-active=
'$route.path'
>
...
...
@@ -22,10 +21,10 @@
<
template
v-slot:title
>
{{
$t
(
'
commons.test
'
)
}}
</
template
>
<ms-recent-list
:options=
"testRecent"
/>
<el-divider/>
<ms-show-all
:index=
"'/api/test/all'"
/>
<ms-show-all
:index=
"'/api/test/
list/
all'"
/>
<ms-create-button
:index=
"'/api/test/create'"
:title=
"$t('load_test.create')"
/>
<el-menu-item
:index=
"testCaseProjectPath"
class=
"blank_item"
></el-menu-item
>
<el-menu-item
:index=
"testEditPath"
class=
"blank_item"
></el-menu-item
>
<!-- <el-menu-item :index="testCaseProjectPath" class="blank_item"></el-menu-item>--
>
<!-- <el-menu-item :index="testEditPath" class="blank_item"></el-menu-item>--
>
</el-submenu>
<el-submenu
v-if=
"isCurrentWorkspaceUser"
...
...
@@ -34,7 +33,7 @@
<ms-recent-list
:options=
"reportRecent"
/>
<el-divider/>
<ms-show-all
:index=
"'/api/report/all'"
/>
<el-menu-item
:index=
"reportViewPath"
class=
"blank_item"
></el-menu-item
>
<!-- <el-menu-item :index="reportViewPath" class="blank_item"></el-menu-item>--
>
</el-submenu>
</el-menu>
</el-col>
...
...
@@ -63,10 +62,10 @@
data
()
{
return
{
isCurrentWorkspaceUser
:
false
,
testCaseProjectPath
:
''
,
testEditPath
:
''
,
reportViewPath
:
''
,
isRouterAlive
:
true
,
//
testCaseProjectPath: '',
//
testEditPath: '',
//
reportViewPath: '',
//
isRouterAlive: true,
projectRecent
:
{
title
:
this
.
$t
(
'
project.recent
'
),
url
:
"
/project/recent/5
"
,
...
...
@@ -82,6 +81,9 @@
url
:
"
/api/recent/5
"
,
index
:
function
(
item
)
{
return
'
/api/test/edit/
'
+
item
.
id
;
},
router
:
function
(
item
)
{
return
{
path
:
'
/api/test/edit
'
,
query
:
{
id
:
item
.
id
}}
}
},
reportRecent
:
{
...
...
@@ -93,35 +95,35 @@
}
}
},
watch
:
{
'
$route
'
(
to
,
from
)
{
let
path
=
to
.
path
;
//激活菜单栏
if
(
path
.
indexOf
(
"
/api/test/
"
)
>=
0
)
{
this
.
testCaseProjectPath
=
'
/api/test/
'
+
this
.
$route
.
params
.
projectId
;
this
.
reload
();
}
if
(
path
.
indexOf
(
"
/api/test/edit/
"
)
>=
0
)
{
this
.
testEditPath
=
'
/api/test/edit/
'
+
this
.
$route
.
params
.
testId
;
this
.
reload
();
}
if
(
path
.
indexOf
(
"
/api/report/view/
"
)
>=
0
)
{
this
.
reportViewPath
=
'
/api/report/view/
'
+
this
.
$route
.
params
.
reportId
;
this
.
reload
();
}
}
},
//
watch: {
//
'$route'(to, from) {
//
let path = to.path;
//
//激活菜单栏
//
if (path.indexOf("/api/test/") >= 0) {
//
this.testCaseProjectPath = '/api/test/' + this.$route.params.projectId;
//
this.reload();
//
}
//
if (path.indexOf("/api/test/edit/") >= 0) {
//
this.testEditPath = '/api/test/edit/' + this.$route.params.testId;
//
this.reload();
//
}
//
if (path.indexOf("/api/report/view/") >= 0) {
//
this.reportViewPath = '/api/report/view/' + this.$route.params.reportId;
//
this.reload();
//
}
//
}
//
},
mounted
()
{
this
.
isCurrentWorkspaceUser
=
checkoutCurrentWorkspace
();
},
methods
:
{
reload
()
{
this
.
isRouterAlive
=
false
;
this
.
$nextTick
(
function
()
{
this
.
isRouterAlive
=
true
;
})
}
}
//
methods: {
//
reload() {
//
this.isRouterAlive = false;
//
this.$nextTick(function () {
//
this.isRouterAlive = true;
//
})
//
}
//
}
}
</
script
>
...
...
frontend/src/business/components/api/test/ApiTestConfig.vue
浏览文件 @
6aa69cee
...
...
@@ -14,7 +14,7 @@
<el-button
type=
"primary"
plain
:disabled=
"isDisabled"
@
click=
"saveTest"
>
保存
</el-button>
</el-row>
</el-header>
<ms-api-scenario-config
:scenarios=
"test.scenarioDefinition"
/>
<ms-api-scenario-config
:scenarios=
"test.scenarioDefinition"
ref=
"config"
/>
</el-container>
</el-card>
</div>
...
...
@@ -23,24 +23,32 @@
<
script
>
import
MsApiScenarioConfig
from
"
./components/ApiScenarioConfig
"
;
import
{
Test
}
from
"
./model/ScenarioModel
"
export
default
{
name
:
"
MsApiTestConfig
"
,
components
:
{
MsApiScenarioConfig
},
props
:
[
"
id
"
],
data
()
{
return
{
result
:
{},
projects
:
[],
change
:
false
,
test
:
{
id
:
null
,
projectId
:
null
,
name
:
null
,
scenarioDefinition
:
[]
}
test
:
new
Test
()
}
},
beforeRouteUpdate
(
to
,
from
,
next
)
{
if
(
to
.
params
.
type
===
"
edit
"
)
{
this
.
getTest
(
to
.
query
.
id
);
}
else
{
this
.
test
=
new
Test
();
this
.
$refs
.
config
.
reset
();
}
next
();
},
watch
:
{
...
...
@@ -53,6 +61,19 @@
},
methods
:
{
getTest
:
function
(
id
)
{
this
.
result
=
this
.
$get
(
"
/api/get/
"
+
id
,
response
=>
{
let
item
=
response
.
data
;
this
.
test
.
reset
({
id
:
item
.
id
,
projectId
:
item
.
projectId
,
name
:
item
.
name
,
scenarioDefinition
:
JSON
.
parse
(
item
.
scenarioDefinition
),
});
this
.
$refs
.
config
.
reset
();
});
},
saveTest
:
function
()
{
this
.
change
=
false
;
...
...
@@ -83,6 +104,9 @@
this
.
result
=
this
.
$get
(
"
/project/listAll
"
,
response
=>
{
this
.
projects
=
response
.
data
;
})
if
(
this
.
id
)
{
this
.
getTest
(
this
.
id
);
}
}
}
</
script
>
...
...
frontend/src/business/components/api/test/ApiTestList.vue
浏览文件 @
6aa69cee
...
...
@@ -71,7 +71,6 @@
data
()
{
return
{
result
:
{},
deletePath
:
"
/api/delete
"
,
condition
:
""
,
projectId
:
null
,
tableData
:
[],
...
...
@@ -83,16 +82,18 @@
testId
:
null
,
}
},
watch
:
{
'
$route
'
(
to
)
{
this
.
projectId
=
to
.
params
.
projectId
;
this
.
search
();
}
beforeRouteUpdate
(
to
,
from
,
next
)
{
this
.
projectId
=
to
.
params
.
projectId
;
this
.
search
();
next
();
},
created
:
function
()
{
this
.
projectId
=
this
.
$route
.
params
.
projectId
;
this
.
search
();
},
methods
:
{
search
()
{
let
param
=
{
...
...
@@ -113,34 +114,27 @@
handleSelectionChange
(
val
)
{
this
.
multipleSelection
=
val
;
},
handleEdit
(
test
Plan
)
{
handleEdit
(
test
)
{
this
.
$router
.
push
({
path
:
'
/api/test/edit
/
'
+
testPlan
.
id
,
path
:
'
/api/test/edit
?id=
'
+
test
.
id
,
})
},
handleDelete
(
test
Plan
)
{
this
.
$alert
(
this
.
$t
(
'
load_test.delete_confirm
'
)
+
test
Plan
.
name
+
"
?
"
,
''
,
{
handleDelete
(
test
)
{
this
.
$alert
(
this
.
$t
(
'
load_test.delete_confirm
'
)
+
test
.
name
+
"
?
"
,
''
,
{
confirmButtonText
:
this
.
$t
(
'
commons.confirm
'
),
callback
:
(
action
)
=>
{
if
(
action
===
'
confirm
'
)
{
this
.
_handleDelete
(
testPlan
);
this
.
result
=
this
.
$post
(
"
/api/delete
"
,
{
id
:
test
.
id
},
()
=>
{
this
.
$message
({
message
:
this
.
$t
(
'
commons.delete_success
'
),
type
:
'
success
'
});
this
.
initTableData
();
});
}
}
});
},
_handleDelete
(
testPlan
)
{
let
data
=
{
id
:
testPlan
.
id
};
this
.
result
=
this
.
$post
(
this
.
deletePath
,
data
,
()
=>
{
this
.
$message
({
message
:
this
.
$t
(
'
commons.delete_success
'
),
type
:
'
success
'
});
this
.
initTableData
();
});
},
}
}
}
</
script
>
...
...
@@ -149,6 +143,4 @@
.test-content
{
width
:
100%
;
}
</
style
>
frontend/src/business/components/api/test/components/ApiAssertions.vue
浏览文件 @
6aa69cee
...
...
@@ -41,14 +41,7 @@
options
:
ASSERTION_TYPE
,
type
:
""
,
}
},
methods
:
{
createRegex
:
function
()
{
return
new
Regex
();
}
}
}
</
script
>
...
...
frontend/src/business/components/api/test/components/ApiAssertionsEdit.vue
浏览文件 @
6aa69cee
...
...
@@ -9,7 +9,7 @@
</div>
</div>
<div
class=
"assertion-item-editing response-time"
v-if=
"
assertions.responseTime.isValid()
"
>
<div
class=
"assertion-item-editing response-time"
v-if=
"
isShow
"
>
<div>
{{
$t
(
"
api_test.request.assertions.response_time
"
)
}}
</div>
...
...
@@ -31,6 +31,13 @@
props
:
{
assertions
:
Assertions
},
computed
:
{
isShow
()
{
let
rt
=
this
.
assertions
.
responseTime
;
return
rt
.
responseInTime
!==
null
&&
rt
.
responseInTime
>
0
;
}
}
}
</
script
>
...
...
frontend/src/business/components/api/test/components/ApiRequestConfig.vue
浏览文件 @
6aa69cee
...
...
@@ -80,10 +80,7 @@
},
created
()
{
if
(
this
.
requests
.
length
===
0
)
{
this
.
createRequest
();
this
.
select
(
this
.
requests
[
0
]);
}
this
.
select
(
this
.
requests
[
0
]);
}
}
</
script
>
...
...
frontend/src/business/components/api/test/components/ApiRequestForm.vue
浏览文件 @
6aa69cee
...
...
@@ -43,12 +43,13 @@
import
MsApiKeyValue
from
"
./ApiKeyValue
"
;
import
MsApiBody
from
"
./ApiBody
"
;
import
MsApiAssertions
from
"
./ApiAssertions
"
;
import
{
Request
}
from
"
../model/ScenarioModel
"
;
export
default
{
name
:
"
MsApiRequestForm
"
,
components
:
{
MsApiAssertions
,
MsApiBody
,
MsApiKeyValue
},
props
:
{
request
:
Objec
t
request
:
Reques
t
},
data
()
{
...
...
frontend/src/business/components/api/test/components/ApiScenarioConfig.vue
浏览文件 @
6aa69cee
...
...
@@ -6,7 +6,12 @@
<ms-api-collapse-item
v-for=
"(scenario, index) in scenarios"
:key=
"index"
:title=
"scenario.name"
:name=
"index"
>
<template
slot=
"title"
>
<div
class=
"scenario-name"
>
{{
scenario
.
name
}}
</div>
<div
class=
"scenario-name"
>
{{
scenario
.
name
}}
<span
id=
"hint"
v-if=
"!scenario.name"
>
{{
$t
(
'
api_test.scenario.config
'
)
}}
</span>
</div>
<el-dropdown
trigger=
"click"
@
command=
"handleCommand"
>
<span
class=
"el-dropdown-link el-icon-more scenario-btn"
/>
<el-dropdown-menu
slot=
"dropdown"
>
...
...
@@ -57,14 +62,13 @@
data
()
{
return
{
activeName
:
0
,
selected
:
Object
selected
:
[
Scenario
,
Request
]
}
},
methods
:
{
createScenario
:
function
()
{
let
scenario
=
new
Scenario
({
name
:
"
Scenario
"
});
this
.
scenarios
.
push
(
scenario
);
this
.
scenarios
.
push
(
new
Scenario
());
},
deleteScenario
:
function
(
index
)
{
this
.
scenarios
.
splice
(
index
,
1
);
...
...
@@ -85,6 +89,12 @@
},
select
:
function
(
obj
)
{
this
.
selected
=
obj
;
},
reset
:
function
()
{
this
.
$nextTick
(
function
()
{
this
.
activeName
=
0
;
this
.
select
(
this
.
scenarios
[
0
]);
});
}
},
...
...
@@ -98,10 +108,7 @@
},
created
()
{
if
(
this
.
scenarios
.
length
===
0
)
{
this
.
createScenario
();
this
.
select
(
this
.
scenarios
[
0
]);
}
this
.
select
(
this
.
scenarios
[
0
]);
}
}
</
script
>
...
...
@@ -131,6 +138,10 @@
width
:
100%
;
}
.scenario-name
>
#hint
{
color
:
#8a8b8d
;
}
.scenario-btn
{
text-align
:
center
;
padding
:
13px
;
...
...
frontend/src/business/components/api/test/components/ApiScenarioForm.vue
浏览文件 @
6aa69cee
...
...
@@ -21,12 +21,13 @@
<
script
>
import
MsApiKeyValue
from
"
./ApiKeyValue
"
;
import
{
Scenario
}
from
"
../model/ScenarioModel
"
;
export
default
{
name
:
"
MsApiScenarioForm
"
,
components
:
{
MsApiKeyValue
},
props
:
{
scenario
:
Object
scenario
:
Scenario
},
data
()
{
...
...
frontend/src/business/components/api/test/model/ScenarioModel.js
浏览文件 @
6aa69cee
import
{
generateId
}
from
"
element-ui/src/utils/util
"
;
const
assign
=
function
(
obj
,
options
)
{
for
(
let
name
in
options
)
{
if
(
options
.
hasOwnProperty
(
name
))
{
obj
[
name
]
=
options
[
name
];
if
(
options
)
{
for
(
let
name
in
options
)
{
if
(
options
.
hasOwnProperty
(
name
))
{
if
(
!
(
obj
[
name
]
instanceof
Array
))
{
obj
[
name
]
=
options
[
name
];
}
}
}
}
}
const
assigns
=
function
(
target
,
source
,
type
)
{
if
(
target
instanceof
Array
&&
source
instanceof
Array
)
{
if
(
source
&&
source
.
length
>
0
)
{
source
.
forEach
((
options
)
=>
{
target
.
push
(
new
type
(
options
));
})
}
}
}
...
...
@@ -19,8 +33,32 @@ export const ASSERTION_TYPE = {
RESPONSE_TIME
:
"
RESPONSE_TIME
"
}
export
class
Test
{
constructor
(
options
)
{
this
.
reset
(
options
);
}
reset
(
options
)
{
options
=
this
.
getDefaultOptions
(
options
);
this
.
id
=
null
;
this
.
name
=
null
;
this
.
projectId
=
null
;
this
.
scenarioDefinition
=
[];
assign
(
this
,
options
);
assigns
(
this
.
scenarioDefinition
,
options
.
scenarioDefinition
,
Scenario
);
}
getDefaultOptions
(
options
)
{
options
=
options
||
{};
options
.
scenarioDefinition
=
options
.
scenarioDefinition
||
[
new
Scenario
()];
return
options
;
}
}
export
class
Scenario
{
constructor
(
options
)
{
options
=
this
.
getDefaultOptions
(
options
);
this
.
name
=
null
;
this
.
url
=
null
;
this
.
variables
=
[];
...
...
@@ -28,32 +66,55 @@ export class Scenario {
this
.
requests
=
[];
assign
(
this
,
options
);
assigns
(
this
.
variables
,
options
.
variables
,
KeyValue
);
assigns
(
this
.
headers
,
options
.
headers
,
KeyValue
);
assigns
(
this
.
requests
,
options
.
requests
,
Request
);
}
getDefaultOptions
(
options
)
{
options
=
options
||
{};
options
.
requests
=
options
.
requests
||
[
new
Request
()];
return
options
;
}
}
export
class
Request
{
constructor
(
options
)
{
options
=
this
.
getDefaultOptions
(
options
);
this
.
randomId
=
generateId
();
this
.
name
=
null
;
this
.
url
=
null
;
this
.
method
=
null
;
this
.
parameters
=
[];
this
.
headers
=
[];
this
.
body
=
n
ew
Body
()
;
this
.
assertions
=
n
ew
Assertions
()
;
this
.
body
=
n
ull
;
this
.
assertions
=
n
ull
;
this
.
extract
=
[];
assign
(
this
,
options
);
assigns
(
this
.
parameters
,
options
.
parameters
,
KeyValue
);
assigns
(
this
.
headers
,
options
.
headers
,
KeyValue
);
// TODO assigns extract
}
getDefaultOptions
(
options
)
{
options
=
options
||
{};
options
.
method
=
"
GET
"
;
options
.
body
=
new
Body
(
options
.
body
);
options
.
assertions
=
new
Assertions
(
options
.
assertions
);
return
options
;
}
}
export
class
Body
{
constructor
(
options
)
{
options
=
options
||
{};
this
.
type
=
null
;
this
.
text
=
null
;
this
.
kvs
=
[];
assign
(
this
,
options
);
assigns
(
this
.
kvs
,
options
.
kvs
,
KeyValue
);
}
isKV
()
{
...
...
@@ -63,6 +124,7 @@ export class Body {
export
class
KeyValue
{
constructor
(
options
)
{
options
=
options
||
{};
this
.
key
=
null
;
this
.
value
=
null
;
...
...
@@ -72,11 +134,20 @@ export class KeyValue {
export
class
Assertions
{
constructor
(
options
)
{
options
=
this
.
getDefaultOptions
(
options
);
this
.
text
=
[];
this
.
regex
=
[];
this
.
responseTime
=
n
ew
ResponseTime
()
;
this
.
responseTime
=
n
ull
;
assign
(
this
,
options
);
assigns
(
this
.
text
,
options
.
text
,
KeyValue
);
assigns
(
this
.
regex
,
options
.
regex
,
KeyValue
);
}
getDefaultOptions
(
options
)
{
options
=
options
||
{};
options
.
responseTime
=
new
ResponseTime
(
options
.
responseTime
);
return
options
;
}
}
...
...
@@ -88,6 +159,7 @@ class AssertionType {
export
class
Text
extends
AssertionType
{
constructor
(
options
)
{
options
=
options
||
{};
super
(
ASSERTION_TYPE
.
TEXT
);
this
.
subject
=
null
;
this
.
condition
=
null
;
...
...
@@ -99,6 +171,7 @@ export class Text extends AssertionType {
export
class
Regex
extends
AssertionType
{
constructor
(
options
)
{
options
=
options
||
{};
super
(
ASSERTION_TYPE
.
REGEX
);
this
.
subject
=
null
;
this
.
expression
=
null
;
...
...
@@ -110,14 +183,11 @@ export class Regex extends AssertionType {
export
class
ResponseTime
extends
AssertionType
{
constructor
(
options
)
{
options
=
options
||
{};
super
(
ASSERTION_TYPE
.
RESPONSE_TIME
);
this
.
responseInTime
=
null
;
assign
(
this
,
options
);
}
isValid
()
{
return
this
.
responseInTime
!==
null
&&
this
.
responseInTime
>
0
;
}
}
frontend/src/business/components/common/head/CreateTest.vue
浏览文件 @
6aa69cee
...
...
@@ -9,7 +9,7 @@
name
:
"
MsCreateTest
"
,
props
:
{
show
:
Boolean
,
to
:
String
,
to
:
[
String
,
Object
]
,
title
:
{
type
:
String
,
default
:
function
()
{
...
...
frontend/src/business/components/common/router/router.js
浏览文件 @
6aa69cee
...
...
@@ -95,25 +95,14 @@ const router = new VueRouter({
component
:
ApiTestHome
,
},
{
path
:
'
test/create
'
,
name
:
"
createAPITest
"
,
path
:
"
test/:type
"
,
name
:
"
ApiTestConfig
"
,
component
:
ApiTestConfig
,
props
:
(
route
)
=>
({
id
:
route
.
query
.
id
})
},
{
path
:
"
test/edit/:testId
"
,
name
:
"
editAPITest
"
,
component
:
ApiTestConfig
,
props
:
{
content
:
(
route
)
=>
{
return
{
...
route
.
params
}
}
}
},
{
path
:
"
test/:projectId
"
,
name
:
"
fucPlan
"
,
path
:
"
test/list/:projectId
"
,
name
:
"
ApiTestList
"
,
component
:
ApiTestList
},
{
...
...
frontend/src/i18n/zh-CN.js
浏览文件 @
6aa69cee
...
...
@@ -173,6 +173,7 @@ export default {
input_name
:
"
请输入测试名称
"
,
select_project
:
"
请选择项目
"
,
scenario
:
{
config
:
"
场景配置
"
,
input_name
:
"
请输入场景名称
"
,
name
:
"
场景名称
"
,
base_url
:
"
基础URL
"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录