Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
3f73ecd5
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,发现更多精彩内容 >>
提交
3f73ecd5
编写于
10月 12, 2020
作者:
W
wenyann
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'origin/master'
上级
55c06e0f
fea37387
变更
55
隐藏空白更改
内联
并排
Showing
55 changed file
with
971 addition
and
382 deletion
+971
-382
backend/pom.xml
backend/pom.xml
+7
-0
backend/src/main/java/io/metersphere/api/controller/APIReportController.java
...va/io/metersphere/api/controller/APIReportController.java
+1
-0
backend/src/main/java/io/metersphere/api/controller/APITestController.java
...java/io/metersphere/api/controller/APITestController.java
+2
-0
backend/src/main/java/io/metersphere/api/dto/QueryAPIReportRequest.java
...in/java/io/metersphere/api/dto/QueryAPIReportRequest.java
+1
-0
backend/src/main/java/io/metersphere/api/dto/QueryAPITestRequest.java
...main/java/io/metersphere/api/dto/QueryAPITestRequest.java
+1
-0
backend/src/main/java/io/metersphere/api/dto/scenario/Scenario.java
...c/main/java/io/metersphere/api/dto/scenario/Scenario.java
+1
-0
backend/src/main/java/io/metersphere/api/dto/scenario/TCPConfig.java
.../main/java/io/metersphere/api/dto/scenario/TCPConfig.java
+19
-0
backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java
...io/metersphere/api/dto/scenario/request/DubboRequest.java
+0
-6
backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java
.../io/metersphere/api/dto/scenario/request/HttpRequest.java
+0
-6
backend/src/main/java/io/metersphere/api/dto/scenario/request/Request.java
...java/io/metersphere/api/dto/scenario/request/Request.java
+2
-1
backend/src/main/java/io/metersphere/api/dto/scenario/request/RequestType.java
.../io/metersphere/api/dto/scenario/request/RequestType.java
+2
-0
backend/src/main/java/io/metersphere/api/dto/scenario/request/TCPRequest.java
...a/io/metersphere/api/dto/scenario/request/TCPRequest.java
+42
-0
backend/src/main/java/io/metersphere/api/jmeter/JMeterVars.java
...d/src/main/java/io/metersphere/api/jmeter/JMeterVars.java
+15
-3
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
.../java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
+3
-0
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestReportMapper.xml
...io/metersphere/base/mapper/ext/ExtApiTestReportMapper.xml
+3
-0
backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml
...java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml
+3
-0
backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestReportMapper.xml
...o/metersphere/base/mapper/ext/ExtLoadTestReportMapper.xml
+3
-0
backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml
...java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml
+4
-2
backend/src/main/java/io/metersphere/config/ShiroConfig.java
backend/src/main/java/io/metersphere/config/ShiroConfig.java
+0
-2
backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java
...e/performance/controller/PerformanceReportController.java
+1
-0
backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java
...ere/performance/controller/PerformanceTestController.java
+1
-0
backend/src/main/java/io/metersphere/performance/controller/request/ReportRequest.java
...rsphere/performance/controller/request/ReportRequest.java
+1
-0
backend/src/main/java/io/metersphere/security/LoginFilter.java
...nd/src/main/java/io/metersphere/security/LoginFilter.java
+0
-36
backend/src/main/java/io/metersphere/track/controller/TestCaseController.java
...a/io/metersphere/track/controller/TestCaseController.java
+1
-0
backend/src/main/java/io/metersphere/track/dto/TestPlanDTO.java
...d/src/main/java/io/metersphere/track/dto/TestPlanDTO.java
+1
-0
backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java
...ersphere/track/request/testcase/QueryTestCaseRequest.java
+2
-0
backend/src/main/java/io/metersphere/track/request/testplan/QueryTestPlanRequest.java
...ersphere/track/request/testplan/QueryTestPlanRequest.java
+1
-0
backend/src/main/java/io/metersphere/track/service/TestCaseService.java
...in/java/io/metersphere/track/service/TestCaseService.java
+1
-1
backend/src/main/java/io/metersphere/track/service/TestPlanService.java
...in/java/io/metersphere/track/service/TestPlanService.java
+4
-2
backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
...d/src/main/java/io/metersphere/xmind/XmindCaseParser.java
+41
-16
backend/src/main/java/io/metersphere/xmind/parser/XmindParser.java
...rc/main/java/io/metersphere/xmind/parser/XmindParser.java
+14
-13
backend/src/main/java/io/metersphere/xmind/parser/ZipUtils.java
...d/src/main/java/io/metersphere/xmind/parser/ZipUtils.java
+6
-4
backend/src/main/java/io/metersphere/xmind/utils/FileUtil.java
...nd/src/main/java/io/metersphere/xmind/utils/FileUtil.java
+6
-2
backend/src/main/java/io/metersphere/xpack
backend/src/main/java/io/metersphere/xpack
+1
-1
frontend/package.json
frontend/package.json
+2
-1
frontend/src/business/components/api/report/ApiReportViewHeader.vue
...rc/business/components/api/report/ApiReportViewHeader.vue
+1
-1
frontend/src/business/components/api/test/components/ApiScenarioForm.vue
...siness/components/api/test/components/ApiScenarioForm.vue
+5
-0
frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue
...nents/api/test/components/environment/EnvironmentEdit.vue
+6
-1
frontend/src/business/components/api/test/components/request/ApiRequestConfig.vue
...mponents/api/test/components/request/ApiRequestConfig.vue
+1
-0
frontend/src/business/components/api/test/components/request/ApiRequestForm.vue
...components/api/test/components/request/ApiRequestForm.vue
+107
-94
frontend/src/business/components/api/test/components/request/ApiTcpRequestForm.vue
...ponents/api/test/components/request/ApiTcpRequestForm.vue
+178
-0
frontend/src/business/components/api/test/components/request/tcp/TcpConfig.vue
.../components/api/test/components/request/tcp/TcpConfig.vue
+115
-0
frontend/src/business/components/api/test/model/EnvironmentModel.js
...rc/business/components/api/test/model/EnvironmentModel.js
+4
-1
frontend/src/business/components/api/test/model/JMX.js
frontend/src/business/components/api/test/model/JMX.js
+21
-1
frontend/src/business/components/api/test/model/ScenarioModel.js
...d/src/business/components/api/test/model/ScenarioModel.js
+110
-53
frontend/src/business/components/settings/CurrentUser.vue
frontend/src/business/components/settings/CurrentUser.vue
+58
-45
frontend/src/business/components/track/plan/components/TestPlanEdit.vue
...usiness/components/track/plan/components/TestPlanEdit.vue
+11
-9
frontend/src/business/components/track/plan/components/TestPlanList.vue
...usiness/components/track/plan/components/TestPlanList.vue
+2
-2
frontend/src/business/components/track/plan/view/comonents/TestPlanTestCaseEdit.vue
...onents/track/plan/view/comonents/TestPlanTestCaseEdit.vue
+48
-38
frontend/src/business/components/track/review/components/TestCaseReviewEdit.vue
...components/track/review/components/TestCaseReviewEdit.vue
+6
-6
frontend/src/business/components/xpack
frontend/src/business/components/xpack
+1
-1
frontend/src/business/permission.js
frontend/src/business/permission.js
+11
-3
frontend/src/i18n/en-US.js
frontend/src/i18n/en-US.js
+42
-21
frontend/src/i18n/zh-CN.js
frontend/src/i18n/zh-CN.js
+26
-5
frontend/src/i18n/zh-TW.js
frontend/src/i18n/zh-TW.js
+26
-5
未找到文件。
backend/pom.xml
浏览文件 @
3f73ecd5
...
...
@@ -171,6 +171,13 @@
<version>
${jmeter.version}
</version>
</dependency>
<dependency>
<groupId>
org.apache.jmeter
</groupId>
<artifactId>
ApacheJMeter_tcp
</artifactId>
<version>
${jmeter.version}
</version>
</dependency>
<dependency>
<groupId>
com.microsoft.sqlserver
</groupId>
<artifactId>
mssql-jdbc
</artifactId>
...
...
backend/src/main/java/io/metersphere/api/controller/APIReportController.java
浏览文件 @
3f73ecd5
...
...
@@ -34,6 +34,7 @@ public class APIReportController {
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
QueryAPIReportRequest
request
=
new
QueryAPIReportRequest
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
request
.
setUserId
(
SessionUtils
.
getUserId
());
PageHelper
.
startPage
(
1
,
count
,
true
);
return
apiReportService
.
recentTest
(
request
);
}
...
...
backend/src/main/java/io/metersphere/api/controller/APITestController.java
浏览文件 @
3f73ecd5
...
...
@@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.*;
import
org.springframework.web.multipart.MultipartFile
;
import
javax.annotation.Resource
;
import
java.util.List
;
@RestController
...
...
@@ -36,6 +37,7 @@ public class APITestController {
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
QueryAPITestRequest
request
=
new
QueryAPITestRequest
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
request
.
setUserId
(
SessionUtils
.
getUserId
());
PageHelper
.
startPage
(
1
,
count
,
true
);
return
apiTestService
.
recentTest
(
request
);
}
...
...
backend/src/main/java/io/metersphere/api/dto/QueryAPIReportRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -15,6 +15,7 @@ public class QueryAPIReportRequest {
private
String
projectId
;
private
String
name
;
private
String
workspaceId
;
private
String
userId
;
private
boolean
recent
=
false
;
private
List
<
OrderRequest
>
orders
;
private
Map
<
String
,
List
<
String
>>
filters
;
...
...
backend/src/main/java/io/metersphere/api/dto/QueryAPITestRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -16,6 +16,7 @@ public class QueryAPITestRequest {
private
String
projectId
;
private
String
name
;
private
String
workspaceId
;
private
String
userId
;
private
boolean
recent
=
false
;
private
List
<
OrderRequest
>
orders
;
private
Map
<
String
,
List
<
String
>>
filters
;
...
...
backend/src/main/java/io/metersphere/api/dto/scenario/Scenario.java
浏览文件 @
3f73ecd5
...
...
@@ -16,6 +16,7 @@ public class Scenario {
private
List
<
KeyValue
>
headers
;
private
List
<
Request
>
requests
;
private
DubboConfig
dubboConfig
;
private
TCPConfig
tcpConfig
;
private
List
<
DatabaseConfig
>
databaseConfigs
;
private
Boolean
enable
;
}
backend/src/main/java/io/metersphere/api/dto/scenario/TCPConfig.java
0 → 100644
浏览文件 @
3f73ecd5
package
io.metersphere.api.dto.scenario
;
import
lombok.Data
;
@Data
public
class
TCPConfig
{
private
String
classname
;
private
String
server
;
private
Integer
port
;
private
Integer
ctimeout
;
private
Integer
timeout
;
private
Boolean
reUseConnection
;
private
Boolean
nodelay
;
private
Boolean
closeConnection
;
private
String
soLinger
;
private
String
eolByte
;
private
String
username
;
private
String
password
;
}
backend/src/main/java/io/metersphere/api/dto/scenario/request/DubboRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -4,8 +4,6 @@ import com.alibaba.fastjson.annotation.JSONField;
import
com.alibaba.fastjson.annotation.JSONType
;
import
com.fasterxml.jackson.annotation.JsonProperty
;
import
io.metersphere.api.dto.scenario.KeyValue
;
import
io.metersphere.api.dto.scenario.processor.BeanShellPostProcessor
;
import
io.metersphere.api.dto.scenario.processor.BeanShellPreProcessor
;
import
io.metersphere.api.dto.scenario.request.dubbo.ConfigCenter
;
import
io.metersphere.api.dto.scenario.request.dubbo.ConsumerAndService
;
import
io.metersphere.api.dto.scenario.request.dubbo.RegistryCenter
;
...
...
@@ -39,8 +37,4 @@ public class DubboRequest extends Request {
private
List
<
KeyValue
>
args
;
@JSONField
(
ordinal
=
9
)
private
List
<
KeyValue
>
attachmentArgs
;
@JSONField
(
ordinal
=
12
)
private
BeanShellPreProcessor
beanShellPreProcessor
;
@JSONField
(
ordinal
=
13
)
private
BeanShellPostProcessor
beanShellPostProcessor
;
}
backend/src/main/java/io/metersphere/api/dto/scenario/request/HttpRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -4,8 +4,6 @@ import com.alibaba.fastjson.annotation.JSONField;
import
com.alibaba.fastjson.annotation.JSONType
;
import
io.metersphere.api.dto.scenario.Body
;
import
io.metersphere.api.dto.scenario.KeyValue
;
import
io.metersphere.api.dto.scenario.processor.BeanShellPostProcessor
;
import
io.metersphere.api.dto.scenario.processor.BeanShellPreProcessor
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
...
...
@@ -31,10 +29,6 @@ public class HttpRequest extends Request {
private
List
<
KeyValue
>
headers
;
@JSONField
(
ordinal
=
8
)
private
Body
body
;
@JSONField
(
ordinal
=
11
)
private
BeanShellPreProcessor
beanShellPreProcessor
;
@JSONField
(
ordinal
=
12
)
private
BeanShellPostProcessor
beanShellPostProcessor
;
@JSONField
(
ordinal
=
14
)
private
Long
connectTimeout
;
@JSONField
(
ordinal
=
15
)
...
...
backend/src/main/java/io/metersphere/api/dto/scenario/request/Request.java
浏览文件 @
3f73ecd5
...
...
@@ -16,7 +16,8 @@ import lombok.Data;
@JsonSubTypes
({
@JsonSubTypes
.
Type
(
value
=
HttpRequest
.
class
,
name
=
RequestType
.
HTTP
),
@JsonSubTypes
.
Type
(
value
=
DubboRequest
.
class
,
name
=
RequestType
.
DUBBO
),
@JsonSubTypes
.
Type
(
value
=
SqlRequest
.
class
,
name
=
RequestType
.
SQL
)
@JsonSubTypes
.
Type
(
value
=
SqlRequest
.
class
,
name
=
RequestType
.
SQL
),
@JsonSubTypes
.
Type
(
value
=
TCPRequest
.
class
,
name
=
RequestType
.
TCP
)
})
@JSONType
(
seeAlso
=
{
HttpRequest
.
class
,
DubboRequest
.
class
,
SqlRequest
.
class
},
typeKey
=
"type"
)
@Data
...
...
backend/src/main/java/io/metersphere/api/dto/scenario/request/RequestType.java
浏览文件 @
3f73ecd5
...
...
@@ -7,4 +7,6 @@ public class RequestType {
public
static
final
String
DUBBO
=
"DUBBO"
;
public
static
final
String
SQL
=
"SQL"
;
public
static
final
String
TCP
=
"TCP"
;
}
backend/src/main/java/io/metersphere/api/dto/scenario/request/TCPRequest.java
0 → 100644
浏览文件 @
3f73ecd5
package
io.metersphere.api.dto.scenario.request
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
com.alibaba.fastjson.annotation.JSONType
;
import
lombok.Data
;
import
lombok.EqualsAndHashCode
;
@EqualsAndHashCode
(
callSuper
=
true
)
@Data
@JSONType
(
typeName
=
RequestType
.
TCP
)
public
class
TCPRequest
extends
Request
{
// type 必须放最前面,以便能够转换正确的类
private
String
type
=
RequestType
.
TCP
;
@JSONField
(
ordinal
=
50
)
private
Boolean
useEnvironment
;
@JSONField
(
ordinal
=
51
)
private
String
classname
;
@JSONField
(
ordinal
=
52
)
private
String
server
;
@JSONField
(
ordinal
=
53
)
private
Integer
port
;
@JSONField
(
ordinal
=
54
)
private
Integer
ctimeout
;
@JSONField
(
ordinal
=
55
)
private
Integer
timeout
;
@JSONField
(
ordinal
=
56
)
private
Boolean
reUseConnection
;
@JSONField
(
ordinal
=
57
)
private
Boolean
nodelay
;
@JSONField
(
ordinal
=
58
)
private
Boolean
closeConnection
;
@JSONField
(
ordinal
=
59
)
private
String
soLinger
;
@JSONField
(
ordinal
=
60
)
private
String
eolByte
;
@JSONField
(
ordinal
=
61
)
private
String
request
;
@JSONField
(
ordinal
=
62
)
private
String
username
;
@JSONField
(
ordinal
=
63
)
private
String
password
;
}
backend/src/main/java/io/metersphere/api/jmeter/JMeterVars.java
浏览文件 @
3f73ecd5
...
...
@@ -18,10 +18,18 @@ public class JMeterVars {
private
JMeterVars
()
{
}
// 数据和线程变量保持一致
/**
* 数据和线程变量保持一致
*/
private
static
Map
<
Integer
,
JMeterVariables
>
variables
=
new
HashMap
<>();
// 线程执行过程调用提取变量值
/**
* 线程执行过程调用提取变量值
*
* @param testId
* @param vars
* @param extract
*/
public
static
void
addVars
(
Integer
testId
,
JMeterVariables
vars
,
String
extract
)
{
JMeterVariables
vs
=
new
JMeterVariables
();
...
...
@@ -36,7 +44,11 @@ public class JMeterVars {
variables
.
put
(
testId
,
vs
);
}
// 处理所有请求,有提取变量的请求增加后置脚本提取变量值
/**
* 处理所有请求,有提取变量的请求增加后置脚本提取变量值
*
* @param tree
*/
public
static
void
addJSR223PostProcessor
(
HashTree
tree
)
{
for
(
Object
key
:
tree
.
keySet
())
{
HashTree
node
=
tree
.
get
(
key
);
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestMapper.xml
浏览文件 @
3f73ecd5
...
...
@@ -120,6 +120,9 @@
<if
test=
"request.id != null"
>
AND api_test.id = #{request.id}
</if>
<if
test=
"request.userId != null"
>
AND api_test.user_id = #{request.userId}
</if>
<if
test=
"request.filters != null and request.filters.size() > 0"
>
<foreach
collection=
"request.filters.entrySet()"
index=
"key"
item=
"values"
>
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiTestReportMapper.xml
浏览文件 @
3f73ecd5
...
...
@@ -85,6 +85,9 @@
<if
test=
"request.name != null"
>
and r.name like CONCAT('%', #{request.name},'%')
</if>
<if
test=
"request.userId != null"
>
AND r.user_id = #{request.userId,jdbcType=VARCHAR}
</if>
<if
test=
"request.projectId != null"
>
AND project.id = #{request.projectId}
</if>
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestMapper.xml
浏览文件 @
3f73ecd5
...
...
@@ -67,6 +67,9 @@
<if
test=
"request.name != null"
>
and load_test.name like CONCAT('%', #{request.name},'%')
</if>
<if
test=
"request.userId != null"
>
and load_test.user_id= #{request.userId}
</if>
<if
test=
"request.workspaceId != null"
>
AND project.workspace_id = #{request.workspaceId}
</if>
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtLoadTestReportMapper.xml
浏览文件 @
3f73ecd5
...
...
@@ -84,6 +84,9 @@
<if
test=
"reportRequest.name != null"
>
AND ltr.name like CONCAT('%', #{reportRequest.name},'%')
</if>
<if
test=
"reportRequest.userId != null"
>
AND ltr.user_id = #{reportRequest.userId,jdbcType=VARCHAR}
</if>
<if
test=
"reportRequest.workspaceId != null"
>
AND workspace_id = #{reportRequest.workspaceId,jdbcType=VARCHAR}
</if>
...
...
backend/src/main/java/io/metersphere/base/mapper/ext/ExtTestPlanMapper.xml
浏览文件 @
3f73ecd5
...
...
@@ -4,7 +4,8 @@
<resultMap
id=
"BaseResultMap"
type=
"io.metersphere.track.dto.TestPlanDTO"
extends=
"io.metersphere.base.mapper.TestPlanMapper.BaseResultMap"
>
<result
column=
"project_name"
property=
"projectName"
/>
<result
column=
"project_name"
property=
"projectName"
jdbcType=
"VARCHAR"
/>
<result
column=
"user_name"
property=
"userName"
jdbcType=
"VARCHAR"
/>
</resultMap>
<sql
id=
"condition"
>
<choose>
...
...
@@ -97,7 +98,8 @@
<select
id=
"list"
resultMap=
"BaseResultMap"
parameterType=
"io.metersphere.track.request.testcase.QueryTestPlanRequest"
>
select test_plan.* from test_plan
select test_plan.*, user.name as user_name from test_plan
LEFT JOIN user ON user.id = test_plan.principal
<where>
<if
test=
"request.combine != null"
>
<include
refid=
"combine"
>
...
...
backend/src/main/java/io/metersphere/config/ShiroConfig.java
浏览文件 @
3f73ecd5
...
...
@@ -35,7 +35,6 @@ public class ShiroConfig implements EnvironmentAware {
@Bean
public
ShiroFilterFactoryBean
getShiroFilterFactoryBean
(
DefaultWebSecurityManager
sessionManager
)
{
ShiroFilterFactoryBean
shiroFilterFactoryBean
=
new
ShiroFilterFactoryBean
();
// shiroFilterFactoryBean.getFilters().put("authc", new LoginFilter());
shiroFilterFactoryBean
.
setLoginUrl
(
"/login"
);
shiroFilterFactoryBean
.
setSecurityManager
(
sessionManager
);
shiroFilterFactoryBean
.
setUnauthorizedUrl
(
"/403"
);
...
...
@@ -44,7 +43,6 @@ public class ShiroConfig implements EnvironmentAware {
shiroFilterFactoryBean
.
getFilters
().
put
(
"apikey"
,
new
ApiKeyFilter
());
Map
<
String
,
String
>
filterChainDefinitionMap
=
shiroFilterFactoryBean
.
getFilterChainDefinitionMap
();
ShiroUtils
.
loadBaseFilterChain
(
filterChainDefinitionMap
);
// filterChainDefinitionMap.put("/**", "apikey, authc");
filterChainDefinitionMap
.
put
(
"/**"
,
"apikey"
);
return
shiroFilterFactoryBean
;
}
...
...
backend/src/main/java/io/metersphere/performance/controller/PerformanceReportController.java
浏览文件 @
3f73ecd5
...
...
@@ -35,6 +35,7 @@ public class PerformanceReportController {
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
ReportRequest
request
=
new
ReportRequest
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
request
.
setUserId
(
SessionUtils
.
getUserId
());
// 最近 `count` 个项目
PageHelper
.
startPage
(
1
,
count
);
return
reportService
.
getRecentReportList
(
request
);
...
...
backend/src/main/java/io/metersphere/performance/controller/PerformanceTestController.java
浏览文件 @
3f73ecd5
...
...
@@ -44,6 +44,7 @@ public class PerformanceTestController {
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
QueryTestPlanRequest
request
=
new
QueryTestPlanRequest
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
request
.
setUserId
(
SessionUtils
.
getUserId
());
PageHelper
.
startPage
(
1
,
count
,
true
);
return
performanceTestService
.
recentTestPlans
(
request
);
}
...
...
backend/src/main/java/io/metersphere/performance/controller/request/ReportRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -12,6 +12,7 @@ import java.util.Map;
public
class
ReportRequest
{
private
String
name
;
private
String
workspaceId
;
private
String
userId
;
private
List
<
OrderRequest
>
orders
;
private
Map
<
String
,
List
<
String
>>
filters
;
private
Map
<
String
,
Object
>
combine
;
...
...
backend/src/main/java/io/metersphere/security/LoginFilter.java
已删除
100644 → 0
浏览文件 @
55c06e0f
package
io.metersphere.security
;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.controller.ResultHolder
;
import
org.apache.shiro.web.filter.authc.FormAuthenticationFilter
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
public
class
LoginFilter
extends
FormAuthenticationFilter
{
@Override
protected
boolean
isAccessAllowed
(
ServletRequest
request
,
ServletResponse
response
,
Object
mappedValue
)
{
if
(((
HttpServletRequest
)
request
).
getMethod
().
toUpperCase
().
equals
(
"OPTIONS"
))
{
return
true
;
}
return
super
.
isAccessAllowed
(
request
,
response
,
mappedValue
);
}
@Override
protected
boolean
onAccessDenied
(
ServletRequest
request
,
ServletResponse
response
)
throws
Exception
{
HttpServletRequest
httpServletRequest
=
(
HttpServletRequest
)
request
;
if
(
httpServletRequest
.
getServletPath
().
endsWith
(
"login"
))
{
return
super
.
onAccessDenied
(
request
,
response
);
}
HttpServletResponse
httpServletResponse
=
(
HttpServletResponse
)
response
;
httpServletResponse
.
setCharacterEncoding
(
"UTF-8"
);
httpServletResponse
.
setContentType
(
"application/json"
);
httpServletResponse
.
setHeader
(
"authentication-status"
,
"invalid"
);
ResultHolder
result
=
ResultHolder
.
error
(
"Authentication Status Invalid"
);
httpServletResponse
.
getWriter
().
write
(
JSONObject
.
toJSON
(
result
).
toString
());
return
true
;
}
}
backend/src/main/java/io/metersphere/track/controller/TestCaseController.java
浏览文件 @
3f73ecd5
...
...
@@ -63,6 +63,7 @@ public class TestCaseController {
String
currentWorkspaceId
=
SessionUtils
.
getCurrentWorkspaceId
();
QueryTestCaseRequest
request
=
new
QueryTestCaseRequest
();
request
.
setWorkspaceId
(
currentWorkspaceId
);
request
.
setUserId
(
SessionUtils
.
getUserId
());
return
testCaseService
.
recentTestPlans
(
request
,
count
);
}
...
...
backend/src/main/java/io/metersphere/track/dto/TestPlanDTO.java
浏览文件 @
3f73ecd5
...
...
@@ -10,5 +10,6 @@ import java.util.List;
@Setter
public
class
TestPlanDTO
extends
TestPlan
{
private
String
projectName
;
private
String
userName
;
private
List
<
String
>
projectIds
;
}
backend/src/main/java/io/metersphere/track/request/testcase/QueryTestCaseRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -26,6 +26,8 @@ public class QueryTestCaseRequest extends TestCase {
private
String
workspaceId
;
private
String
userId
;
private
Map
<
String
,
Object
>
combine
;
private
String
reviewId
;
...
...
backend/src/main/java/io/metersphere/track/request/testplan/QueryTestPlanRequest.java
浏览文件 @
3f73ecd5
...
...
@@ -11,6 +11,7 @@ import java.util.Map;
@Setter
public
class
QueryTestPlanRequest
extends
TestPlanRequest
{
private
String
workspaceId
;
private
String
userId
;
private
List
<
OrderRequest
>
orders
;
private
Map
<
String
,
List
<
String
>>
filters
;
private
Map
<
String
,
Object
>
combine
;
...
...
backend/src/main/java/io/metersphere/track/service/TestCaseService.java
浏览文件 @
3f73ecd5
...
...
@@ -252,7 +252,7 @@ public class TestCaseService {
PageHelper
.
startPage
(
1
,
count
,
true
);
TestCaseExample
testCaseExample
=
new
TestCaseExample
();
testCaseExample
.
createCriteria
().
andProjectIdIn
(
projectIds
);
testCaseExample
.
createCriteria
().
andProjectIdIn
(
projectIds
)
.
andMaintainerEqualTo
(
request
.
getUserId
())
;
testCaseExample
.
setOrderByClause
(
"update_time desc, sort desc"
);
return
testCaseMapper
.
selectByExample
(
testCaseExample
);
}
...
...
backend/src/main/java/io/metersphere/track/service/TestPlanService.java
浏览文件 @
3f73ecd5
...
...
@@ -37,6 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
import
org.springframework.util.CollectionUtils
;
import
javax.annotation.Resource
;
import
java.util.*
;
import
java.util.stream.Collectors
;
...
...
@@ -119,7 +120,7 @@ public class TestPlanService {
if
(
TestPlanStatus
.
Underway
.
name
().
equals
(
testPlan
.
getStatus
()))
{
testPlan
.
setActualStartTime
(
System
.
currentTimeMillis
());
}
else
if
(
TestPlanStatus
.
Completed
.
name
().
equals
(
testPlan
.
getStatus
()))
{
}
else
if
(
TestPlanStatus
.
Completed
.
name
().
equals
(
testPlan
.
getStatus
()))
{
//已完成,写入实际完成时间
testPlan
.
setActualEndTime
(
System
.
currentTimeMillis
());
}
...
...
@@ -248,7 +249,8 @@ public class TestPlanService {
return
null
;
}
TestPlanExample
testPlanTestCaseExample
=
new
TestPlanExample
();
testPlanTestCaseExample
.
createCriteria
().
andWorkspaceIdEqualTo
(
currentWorkspaceId
);
testPlanTestCaseExample
.
createCriteria
().
andWorkspaceIdEqualTo
(
currentWorkspaceId
)
.
andPrincipalEqualTo
(
SessionUtils
.
getUserId
());
testPlanTestCaseExample
.
setOrderByClause
(
"update_time desc"
);
return
testPlanMapper
.
selectByExample
(
testPlanTestCaseExample
);
}
...
...
backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
浏览文件 @
3f73ecd5
...
...
@@ -30,14 +30,25 @@ public class XmindCaseParser {
private
TestCaseService
testCaseService
;
private
String
maintainer
;
private
String
projectId
;
private
StringBuffer
process
;
// 过程校验记录
// 已存在用例名称
/**
* 过程校验记录
*/
private
StringBuffer
process
;
/**
* 已存在用例名称
*/
private
Set
<
String
>
testCaseNames
;
// 转换后的案例信息
/**
* 转换后的案例信息
*/
private
List
<
TestCaseWithBLOBs
>
testCases
;
// 案例详情重写了hashCode方法去重用
/**
* 案例详情重写了hashCode方法去重用
*/
private
List
<
TestCaseExcelData
>
compartDatas
;
// 记录没有用例的目录
/**
* 记录没有用例的目录
*/
private
List
<
String
>
nodePaths
;
public
XmindCaseParser
(
TestCaseService
testCaseService
,
String
userId
,
String
projectId
,
Set
<
String
>
testCaseNames
)
{
...
...
@@ -89,7 +100,9 @@ public class XmindCaseParser {
});
}
// 递归处理案例数据
/**
* 递归处理案例数据
*/
private
void
recursion
(
Attached
parent
,
int
level
,
List
<
Attached
>
attacheds
)
{
for
(
Attached
item
:
attacheds
)
{
if
(
isAvailable
(
item
.
getTitle
(),
TC_REGEX
))
{
// 用例
...
...
@@ -115,23 +128,27 @@ public class XmindCaseParser {
}
private
boolean
isAvailable
(
String
str
,
String
regex
)
{
if
(
StringUtils
.
isEmpty
(
str
)
||
StringUtils
.
isEmpty
(
regex
))
if
(
StringUtils
.
isEmpty
(
str
)
||
StringUtils
.
isEmpty
(
regex
))
{
return
false
;
}
Pattern
pattern
=
Pattern
.
compile
(
regex
,
Pattern
.
CASE_INSENSITIVE
);
Matcher
result
=
pattern
.
matcher
(
str
);
return
result
.
find
();
}
private
String
replace
(
String
str
,
String
regex
)
{
if
(
StringUtils
.
isEmpty
(
str
)
||
StringUtils
.
isEmpty
(
regex
))
if
(
StringUtils
.
isEmpty
(
str
)
||
StringUtils
.
isEmpty
(
regex
))
{
return
str
;
}
Pattern
pattern
=
Pattern
.
compile
(
regex
,
Pattern
.
CASE_INSENSITIVE
);
Matcher
result
=
pattern
.
matcher
(
str
);
str
=
result
.
replaceAll
(
""
);
return
str
;
}
// 获取步骤数据
/**
* 获取步骤数据
*/
private
String
getSteps
(
List
<
Attached
>
attacheds
)
{
JSONArray
jsonArray
=
new
JSONArray
();
for
(
int
i
=
0
;
i
<
attacheds
.
size
();
i
++)
{
...
...
@@ -147,7 +164,9 @@ public class XmindCaseParser {
return
jsonArray
.
toJSONString
();
}
// 初始化一个用例
/**
* 初始化一个用例
*/
private
void
newTestCase
(
String
title
,
String
nodePath
,
List
<
Attached
>
attacheds
)
{
TestCaseWithBLOBs
testCase
=
new
TestCaseWithBLOBs
();
testCase
.
setProjectId
(
projectId
);
...
...
@@ -157,7 +176,7 @@ public class XmindCaseParser {
testCase
.
setType
(
"functional"
);
String
tc
=
title
.
replace
(
":"
,
":"
);
String
tcArr
[]
=
tc
.
split
(
":"
);
String
[]
tcArr
=
tc
.
split
(
":"
);
if
(
tcArr
.
length
!=
2
)
{
process
.
append
(
Translator
.
get
(
"test_case_name"
)
+
"【 "
+
title
+
" 】"
+
Translator
.
get
(
"incorrect_format"
));
return
;
...
...
@@ -175,7 +194,7 @@ public class XmindCaseParser {
// 用例等级和用例性质处理
if
(
tcArr
[
0
].
indexOf
(
"-"
)
!=
-
1
)
{
String
otArr
[]
=
tcArr
[
0
].
split
(
"-"
);
String
[]
otArr
=
tcArr
[
0
].
split
(
"-"
);
for
(
String
item
:
otArr
)
{
if
(
item
.
toUpperCase
().
startsWith
(
"P"
))
{
testCase
.
setPriority
(
item
.
toUpperCase
());
...
...
@@ -222,7 +241,9 @@ public class XmindCaseParser {
compartDatas
.
add
(
compartData
);
}
// 验证合法性
/**
* 验证合法性
*/
private
boolean
validate
(
TestCaseWithBLOBs
data
)
{
String
nodePath
=
data
.
getNodePath
();
StringBuilder
stringBuilder
=
new
StringBuilder
();
...
...
@@ -265,7 +286,9 @@ public class XmindCaseParser {
return
true
;
}
// 导入思维导图处理
/**
* 导入思维导图处理
*/
public
String
parse
(
MultipartFile
multipartFile
)
{
try
{
// 获取思维导图内容
...
...
@@ -274,7 +297,8 @@ public class XmindCaseParser {
if
(
root
!=
null
&&
root
.
getRootTopic
()
!=
null
&&
root
.
getRootTopic
().
getChildren
()
!=
null
)
{
// 判断是模块还是用例
for
(
Attached
item
:
root
.
getRootTopic
().
getChildren
().
getAttached
())
{
if
(
isAvailable
(
item
.
getTitle
(),
TC_REGEX
))
{
// 用例
// 用例
if
(
isAvailable
(
item
.
getTitle
(),
TC_REGEX
))
{
return
replace
(
item
.
getTitle
(),
TC_REGEX
)
+
":"
+
Translator
.
get
(
"test_case_create_module_fail"
);
}
else
{
String
nodePath
=
item
.
getTitle
();
...
...
@@ -288,7 +312,8 @@ public class XmindCaseParser {
if
(
nodePath
.
endsWith
(
"/"
))
{
nodePath
=
nodePath
.
substring
(
0
,
nodePath
.
length
()
-
1
);
}
nodePaths
.
add
(
nodePath
);
// 没有用例的路径
// 没有用例的路径
nodePaths
.
add
(
nodePath
);
}
}
}
...
...
backend/src/main/java/io/metersphere/xmind/parser/XmindParser.java
浏览文件 @
3f73ecd5
...
...
@@ -7,7 +7,6 @@ import io.metersphere.xmind.parser.pojo.JsonRootBean;
import
io.metersphere.xmind.utils.FileUtil
;
import
org.apache.commons.compress.archivers.ArchiveException
;
import
org.dom4j.DocumentException
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.io.File
;
...
...
@@ -21,9 +20,9 @@ import java.util.Objects;
* @Description 解析主体
*/
public
class
XmindParser
{
public
static
final
String
xmindZenJson
=
"content.json"
;
public
static
final
String
xmindLegacyContent
=
"content.xml"
;
public
static
final
String
xmindLegacyComments
=
"comments.xml"
;
public
static
final
String
CONTENT_JSON
=
"content.json"
;
public
static
final
String
CONTENT_XML
=
"content.xml"
;
public
static
final
String
COMMENTS_XML
=
"comments.xml"
;
/**
* 解析脑图文件,返回content整合后的内容
...
...
@@ -38,8 +37,9 @@ public class XmindParser {
File
file
=
FileUtil
.
multipartFileToFile
(
multipartFile
);
List
<
String
>
contents
=
null
;
String
res
=
null
;
if
(
file
==
null
||
!
file
.
exists
())
if
(
file
==
null
||
!
file
.
exists
())
{
MSException
.
throwException
(
Translator
.
get
(
"incorrect_format"
));
}
try
{
res
=
ZipUtils
.
extract
(
file
);
if
(
isXmindZen
(
res
,
file
))
{
...
...
@@ -56,8 +56,9 @@ public class XmindParser {
FileUtil
.
deleteDir
(
dir
);
}
// 删除零时文件
if
(
file
!=
null
)
if
(
file
!=
null
)
{
file
.
delete
();
}
}
return
contents
;
}
...
...
@@ -86,9 +87,9 @@ public class XmindParser {
public
static
List
<
String
>
getXmindZenContent
(
File
file
,
String
extractFileDir
)
throws
IOException
,
ArchiveException
{
List
<
String
>
keys
=
new
ArrayList
<>();
keys
.
add
(
xmindZenJson
);
keys
.
add
(
CONTENT_JSON
);
Map
<
String
,
String
>
map
=
ZipUtils
.
getContents
(
keys
,
file
,
extractFileDir
);
String
content
=
map
.
get
(
xmindZenJson
);
String
content
=
map
.
get
(
CONTENT_JSON
);
return
XmindZen
.
getContent
(
content
);
}
...
...
@@ -98,12 +99,12 @@ public class XmindParser {
public
static
List
<
String
>
getXmindLegacyContent
(
File
file
,
String
extractFileDir
)
throws
IOException
,
ArchiveException
,
DocumentException
{
List
<
String
>
keys
=
new
ArrayList
<>();
keys
.
add
(
xmindLegacyContent
);
keys
.
add
(
xmindLegacyComments
);
keys
.
add
(
CONTENT_XML
);
keys
.
add
(
COMMENTS_XML
);
Map
<
String
,
String
>
map
=
ZipUtils
.
getContents
(
keys
,
file
,
extractFileDir
);
String
contentXml
=
map
.
get
(
xmindLegacyContent
);
String
commentsXml
=
map
.
get
(
xmindLegacyComments
);
String
contentXml
=
map
.
get
(
CONTENT_XML
);
String
commentsXml
=
map
.
get
(
COMMENTS_XML
);
List
<
String
>
xmlContent
=
XmindLegacy
.
getContent
(
contentXml
,
commentsXml
);
return
xmlContent
;
...
...
@@ -115,7 +116,7 @@ public class XmindParser {
if
(
parent
.
isDirectory
())
{
String
[]
files
=
parent
.
list
(
new
ZipUtils
.
FileFilter
());
for
(
int
i
=
0
;
i
<
Objects
.
requireNonNull
(
files
).
length
;
i
++)
{
if
(
files
[
i
].
equals
(
xmindZenJson
))
{
if
(
files
[
i
].
equals
(
CONTENT_JSON
))
{
return
true
;
}
}
...
...
backend/src/main/java/io/metersphere/xmind/parser/ZipUtils.java
浏览文件 @
3f73ecd5
...
...
@@ -14,7 +14,7 @@ import java.util.Objects;
*/
public
class
ZipUtils
{
private
static
final
String
currentPath
=
System
.
getProperty
(
"user.dir"
);
private
static
final
String
CURRENT_PATH
=
System
.
getProperty
(
"user.dir"
);
/**
* 找到压缩文件中匹配的子文件,返回的为 getContents("comments.xml, unzip
...
...
@@ -25,7 +25,7 @@ public class ZipUtils {
public
static
Map
<
String
,
String
>
getContents
(
List
<
String
>
subFileNames
,
File
file
,
String
extractFileDir
)
throws
IOException
,
ArchiveException
{
String
destFilePath
=
extractFileDir
;
Map
<
String
,
String
>
map
=
new
HashMap
<>();
Map
<
String
,
String
>
map
=
new
HashMap
<>(
16
);
File
destFile
=
new
File
(
destFilePath
);
if
(
destFile
.
isDirectory
())
{
String
[]
res
=
destFile
.
list
(
new
FileFilter
());
...
...
@@ -49,12 +49,14 @@ public class ZipUtils {
*/
public
static
String
extract
(
File
file
)
throws
IOException
,
ArchiveException
{
Expander
expander
=
new
Expander
();
String
destFileName
=
currentPath
+
File
.
separator
+
"XMind"
+
System
.
currentTimeMillis
();
// 目标文件夹名字
String
destFileName
=
CURRENT_PATH
+
File
.
separator
+
"XMind"
+
System
.
currentTimeMillis
();
expander
.
expand
(
file
,
new
File
(
destFileName
));
return
destFileName
;
}
// 这是一个内部类过滤器,策略模式
/**
* 这是一个内部类过滤器,策略模式
*/
static
class
FileFilter
implements
FilenameFilter
{
@Override
public
boolean
accept
(
File
dir
,
String
name
)
{
...
...
backend/src/main/java/io/metersphere/xmind/utils/FileUtil.java
浏览文件 @
3f73ecd5
...
...
@@ -8,9 +8,14 @@ import java.io.FileOutputStream;
import
java.io.InputStream
;
import
java.io.OutputStream
;
/**
* 工具类
*/
public
class
FileUtil
{
//获取流文件
/**
* 获取流文件
*/
private
static
void
inputStreamToFile
(
InputStream
ins
,
File
file
)
{
try
(
OutputStream
os
=
new
FileOutputStream
(
file
);)
{
int
bytesRead
=
0
;
...
...
@@ -57,5 +62,4 @@ public class FileUtil {
return
dir
.
delete
();
}
}
xpack
@
ee74568b
比较
cf6b0652
...
ee74568b
Subproject commit
cf6b06526324326a563d933e07118fac014a63b4
Subproject commit
ee74568be0beba46da19616f5832e83f9164c688
frontend/package.json
浏览文件 @
3f73ecd5
...
...
@@ -33,7 +33,8 @@
"json-bigint"
:
"^1.0.0"
,
"html2canvas"
:
"^1.0.0-rc.7"
,
"jspdf"
:
"^2.1.1"
,
"yan-progress"
:
"^1.0.3"
"yan-progress"
:
"^1.0.3"
,
"nprogress"
:
"^0.2.0"
},
"devDependencies"
:
{
"@vue/cli-plugin-babel"
:
"^4.1.0"
,
...
...
frontend/src/business/components/api/report/ApiReportViewHeader.vue
浏览文件 @
3f73ecd5
...
...
@@ -4,7 +4,7 @@
<el-col>
<span>
{{
report
.
projectName
}}
/
</span>
<router-link
:to=
"path"
>
{{
report
.
testName
}}
</router-link>
<span
class=
"time"
>
{{
report
.
createTime
|
timestampFormatDate
}}
</span>
<span
class=
"time"
>
{{
report
.
createTime
|
timestampFormatDate
}}
</span>
<el-button
:disabled=
"isReadOnly"
class=
"export-button"
plain
type=
"primary"
size=
"mini"
@
click=
"handleExport(report.name)"
style=
"margin-left: 1200px"
>
{{
$t
(
'
test_track.plan_view.export_report
'
)
}}
...
...
frontend/src/business/components/api/test/components/ApiScenarioForm.vue
浏览文件 @
3f73ecd5
...
...
@@ -49,6 +49,9 @@
<div
class=
"dubbo-config-title"
>
Consumer
&
Service
</div>
<ms-dubbo-consumer-service
:consumer=
"scenario.dubboConfig.consumerAndService"
:is-read-only=
"isReadOnly"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.environment.tcp_config')"
name=
"tcp"
>
<ms-tcp-config
:config=
"scenario.tcpConfig"
:is-read-only=
"isReadOnly"
/>
</el-tab-pane>
</el-tabs>
<api-environment-config
ref=
"environmentConfig"
@
close=
"environmentConfigClose"
/>
...
...
@@ -68,10 +71,12 @@ import MsDubboConfigCenter from "@/business/components/api/test/components/reque
import
MsDubboConsumerService
from
"
@/business/components/api/test/components/request/dubbo/ConsumerAndService
"
;
import
MsDatabaseConfig
from
"
./request/database/DatabaseConfig
"
;
import
{
parseEnvironment
}
from
"
../model/EnvironmentModel
"
;
import
MsTcpConfig
from
"
@/business/components/api/test/components/request/tcp/TcpConfig
"
;
export
default
{
name
:
"
MsApiScenarioForm
"
,
components
:
{
MsTcpConfig
,
MsDatabaseConfig
,
MsDubboConsumerService
,
MsDubboConfigCenter
,
MsDubboRegistryCenter
,
ApiEnvironmentConfig
,
MsApiScenarioVariables
,
MsApiKeyValue
...
...
frontend/src/business/components/api/test/components/environment/EnvironmentEdit.vue
浏览文件 @
3f73ecd5
...
...
@@ -20,6 +20,9 @@
<el-tab-pane
:label=
"$t('api_test.environment.database_config')"
name=
"sql"
>
<ms-database-config
:configs=
"environment.config.databaseConfigs"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.environment.tcp_config')"
name=
"tcp"
>
<ms-tcp-config
:config=
"environment.config.tcpConfig"
/>
</el-tab-pane>
</el-tabs>
<div
class=
"environment-footer"
>
...
...
@@ -35,16 +38,18 @@
import
MsApiScenarioVariables
from
"
../ApiScenarioVariables
"
;
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
MsDialogFooter
from
"
../../../../common/components/MsDialogFooter
"
;
import
{
REQUEST_HEADERS
}
from
"
../../../../../..
/common/js/constants
"
;
import
{
REQUEST_HEADERS
}
from
"
@
/common/js/constants
"
;
import
{
Environment
}
from
"
../../model/EnvironmentModel
"
;
import
MsApiHostTable
from
"
../ApiHostTable
"
;
import
MsDatabaseConfig
from
"
../request/database/DatabaseConfig
"
;
import
MsEnvironmentHttpConfig
from
"
./EnvironmentHttpConfig
"
;
import
MsEnvironmentCommonConfig
from
"
./EnvironmentCommonConfig
"
;
import
MsTcpConfig
from
"
@/business/components/api/test/components/request/tcp/TcpConfig
"
;
export
default
{
name
:
"
EnvironmentEdit
"
,
components
:
{
MsTcpConfig
,
MsEnvironmentCommonConfig
,
MsEnvironmentHttpConfig
,
MsDatabaseConfig
,
MsApiHostTable
,
MsDialogFooter
,
MsApiKeyValue
,
MsApiScenarioVariables
},
...
...
frontend/src/business/components/api/test/components/request/ApiRequestConfig.vue
浏览文件 @
3f73ecd5
...
...
@@ -50,6 +50,7 @@
<el-radio
:label=
"types.HTTP"
>
HTTP
</el-radio>
<el-radio
:label=
"types.DUBBO"
>
DUBBO
</el-radio>
<el-radio
:label=
"types.SQL"
>
SQL
</el-radio>
<el-radio
:label=
"types.TCP"
>
TCP
</el-radio>
</el-radio-group>
<el-button
slot=
"reference"
:disabled=
"isReadOnly"
class=
"request-create"
type=
"primary"
size=
"mini"
icon=
"el-icon-plus"
plain
/>
...
...
frontend/src/business/components/api/test/components/request/ApiRequestForm.vue
浏览文件 @
3f73ecd5
...
...
@@ -2,22 +2,32 @@
<div
class=
"request-form"
>
<component
@
runDebug=
"runDebug"
:is=
"component"
:is-read-only=
"isReadOnly"
:request=
"request"
:scenario=
"scenario"
/>
<el-divider
v-if=
"isCompleted"
></el-divider>
<ms-request-result-tail
v-loading=
"debugReportLoading"
v-if=
"isCompleted"
:request=
"request.debugRequestResult ? request.debugRequestResult :
{responseResult: {}, subRequestResults: []}"
:scenario-name="request.debugScenario ? request.debugScenario.name : ''" ref="msDebugResult"/>
<ms-request-result-tail
v-loading=
"debugReportLoading"
v-if=
"isCompleted"
:request=
"request.debugRequestResult ? request.debugRequestResult :
{responseResult: {}, subRequestResults: []}"
:scenario-name="request.debugScenario ? request.debugScenario.name : ''"
ref="msDebugResult"/>
</div>
</
template
>
<
script
>
import
{
JSR223Processor
,
Request
,
RequestFactory
,
Scenario
}
from
"
../../model/ScenarioModel
"
;
import
MsApiHttpRequestForm
from
"
./ApiHttpRequestForm
"
;
import
MsApiDubboRequestForm
from
"
./ApiDubboRequestForm
"
;
import
MsScenarioResults
from
"
../../../report/components/ScenarioResults
"
;
import
MsRequestResultTail
from
"
../../../report/components/RequestResultTail
"
;
import
MsApiSqlRequestForm
from
"
./ApiSqlRequestForm
"
;
import
{
JSR223Processor
,
Request
,
RequestFactory
,
Scenario
}
from
"
../../model/ScenarioModel
"
;
import
MsApiHttpRequestForm
from
"
./ApiHttpRequestForm
"
;
import
MsApiTcpRequestForm
from
"
./ApiTcpRequestForm
"
;
import
MsApiDubboRequestForm
from
"
./ApiDubboRequestForm
"
;
import
MsScenarioResults
from
"
../../../report/components/ScenarioResults
"
;
import
MsRequestResultTail
from
"
../../../report/components/RequestResultTail
"
;
import
MsApiSqlRequestForm
from
"
./ApiSqlRequestForm
"
;
export
default
{
name
:
"
MsApiRequestForm
"
,
components
:
{
MsApiSqlRequestForm
,
MsRequestResultTail
,
MsScenarioResults
,
MsApiDubboRequestForm
,
MsApiHttpRequestForm
},
components
:
{
MsApiSqlRequestForm
,
MsRequestResultTail
,
MsScenarioResults
,
MsApiDubboRequestForm
,
MsApiHttpRequestForm
,
MsApiTcpRequestForm
},
props
:
{
scenario
:
Scenario
,
request
:
Request
,
...
...
@@ -27,104 +37,107 @@ export default {
},
debugReportId
:
String
},
data
()
{
return
{
reportId
:
""
,
content
:
{
scenarios
:[]},
debugReportLoading
:
false
,
showDebugReport
:
false
}
},
computed
:
{
component
({
request
:
{
type
}})
{
let
name
;
switch
(
type
)
{
case
RequestFactory
.
TYPES
.
DUBBO
:
name
=
"
MsApiDubboRequestForm
"
;
break
;
case
RequestFactory
.
TYPES
.
SQL
:
name
=
"
MsApiSqlRequestForm
"
;
break
;
default
:
name
=
"
MsApiHttpRequestForm
"
;
}
return
name
;
},
isCompleted
()
{
return
!!
this
.
request
.
debugReport
;
}
},
watch
:
{
debugReportId
()
{
this
.
getReport
();
}
},
mounted
()
{
//兼容旧版本 beanshell
if
(
!
this
.
request
.
jsr223PreProcessor
.
script
&&
this
.
request
.
beanShellPreProcessor
)
{
this
.
request
.
jsr223PreProcessor
=
new
JSR223Processor
(
this
.
request
.
beanShellPreProcessor
);
}
if
(
!
this
.
request
.
jsr223PostProcessor
.
script
&&
this
.
request
.
beanShellPostProcessor
)
{
this
.
request
.
jsr223PostProcessor
=
new
JSR223Processor
(
this
.
request
.
beanShellPostProcessor
);
data
()
{
return
{
reportId
:
""
,
content
:
{
scenarios
:
[]},
debugReportLoading
:
false
,
showDebugReport
:
false
}
},
computed
:
{
component
({
request
:
{
type
}})
{
let
name
;
switch
(
type
)
{
case
RequestFactory
.
TYPES
.
DUBBO
:
name
=
"
MsApiDubboRequestForm
"
;
break
;
case
RequestFactory
.
TYPES
.
SQL
:
name
=
"
MsApiSqlRequestForm
"
;
break
;
case
RequestFactory
.
TYPES
.
TCP
:
name
=
"
MsApiTcpRequestForm
"
;
break
;
default
:
name
=
"
MsApiHttpRequestForm
"
;
}
return
name
;
},
methods
:
{
getReport
()
{
if
(
this
.
debugReportId
)
{
this
.
debugReportLoading
=
true
;
this
.
showDebugReport
=
true
;
this
.
request
.
debugReport
=
{};
let
url
=
"
/api/report/get/
"
+
this
.
debugReportId
;
this
.
$get
(
url
,
response
=>
{
let
report
=
response
.
data
||
{};
let
res
=
{};
if
(
response
.
data
)
{
try
{
res
=
JSON
.
parse
(
report
.
content
);
}
catch
(
e
)
{
throw
e
;
}
if
(
res
)
{
this
.
debugReportLoading
=
false
;
this
.
request
.
debugReport
=
res
;
if
(
res
.
scenarios
&&
res
.
scenarios
.
length
>
0
)
{
this
.
request
.
debugScenario
=
res
.
scenarios
[
0
];
this
.
request
.
debugRequestResult
=
this
.
request
.
debugScenario
.
requestResults
[
0
];
this
.
deleteReport
(
this
.
debugReportId
);
}
else
{
this
.
request
.
debugScenario
=
new
Scenario
();
this
.
request
.
debugRequestResult
=
{
responseResult
:
{},
subRequestResults
:
[]};
}
this
.
$refs
.
msDebugResult
.
reload
();
isCompleted
()
{
return
!!
this
.
request
.
debugReport
;
}
},
watch
:
{
debugReportId
()
{
this
.
getReport
();
}
},
mounted
()
{
//兼容旧版本 beanshell
if
(
!
this
.
request
.
jsr223PreProcessor
.
script
&&
this
.
request
.
beanShellPreProcessor
)
{
this
.
request
.
jsr223PreProcessor
=
new
JSR223Processor
(
this
.
request
.
beanShellPreProcessor
);
}
if
(
!
this
.
request
.
jsr223PostProcessor
.
script
&&
this
.
request
.
beanShellPostProcessor
)
{
this
.
request
.
jsr223PostProcessor
=
new
JSR223Processor
(
this
.
request
.
beanShellPostProcessor
);
}
},
methods
:
{
getReport
()
{
if
(
this
.
debugReportId
)
{
this
.
debugReportLoading
=
true
;
this
.
showDebugReport
=
true
;
this
.
request
.
debugReport
=
{};
let
url
=
"
/api/report/get/
"
+
this
.
debugReportId
;
this
.
$get
(
url
,
response
=>
{
let
report
=
response
.
data
||
{};
let
res
=
{};
if
(
response
.
data
)
{
try
{
res
=
JSON
.
parse
(
report
.
content
);
}
catch
(
e
)
{
throw
e
;
}
if
(
res
)
{
this
.
debugReportLoading
=
false
;
this
.
request
.
debugReport
=
res
;
if
(
res
.
scenarios
&&
res
.
scenarios
.
length
>
0
)
{
this
.
request
.
debugScenario
=
res
.
scenarios
[
0
];
this
.
request
.
debugRequestResult
=
this
.
request
.
debugScenario
.
requestResults
[
0
];
this
.
deleteReport
(
this
.
debugReportId
);
}
else
{
setTimeout
(
this
.
getReport
,
2000
)
this
.
request
.
debugScenario
=
new
Scenario
();
this
.
request
.
debugRequestResult
=
{
responseResult
:
{},
subRequestResults
:
[]};
}
this
.
$refs
.
msDebugResult
.
reload
();
}
else
{
this
.
debugReportLoading
=
false
;
setTimeout
(
this
.
getReport
,
2000
)
}
});
}
},
deleteReport
(
reportId
)
{
this
.
$post
(
'
/api/report/delete
'
,
{
id
:
reportId
});
},
runDebug
()
{
this
.
$emit
(
'
runDebug
'
,
this
.
request
);
}
else
{
this
.
debugReportLoading
=
false
;
}
});
}
},
deleteReport
(
reportId
)
{
this
.
$post
(
'
/api/report/delete
'
,
{
id
:
reportId
});
},
runDebug
()
{
this
.
$emit
(
'
runDebug
'
,
this
.
request
);
}
}
}
</
script
>
<
style
scoped
>
.scenario-results
{
margin-top
:
20px
;
}
.scenario-results
{
margin-top
:
20px
;
}
.request-form
>>>
.debug-button
{
margin-left
:
auto
;
display
:
block
;
margin-right
:
10px
;
}
.request-form
>>>
.debug-button
{
margin-left
:
auto
;
display
:
block
;
margin-right
:
10px
;
}
</
style
>
frontend/src/business/components/api/test/components/request/ApiTcpRequestForm.vue
0 → 100644
浏览文件 @
3f73ecd5
<
template
>
<el-form
class=
"tcp"
:model=
"request"
:rules=
"rules"
ref=
"request"
label-width=
"auto"
:disabled=
"isReadOnly"
>
<el-form-item
:label=
"$t('api_test.request.name')"
prop=
"name"
>
<el-input
v-model=
"request.name"
maxlength=
"300"
show-word-limit
/>
</el-form-item>
<el-form-item
label=
"TCPClient"
prop=
"classname"
>
<el-select
v-model=
"request.classname"
style=
"width: 100%"
>
<el-option
v-for=
"c in classes"
:key=
"c"
:label=
"c"
:value=
"c"
/>
</el-select>
</el-form-item>
<el-row
:gutter=
"10"
>
<el-col
:span=
"16"
>
<el-form-item
:label=
"$t('api_test.request.tcp.server')"
prop=
"server"
>
<el-input
v-model=
"request.server"
maxlength=
"300"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.port')"
prop=
"port"
label-width=
"60px"
>
<el-input-number
v-model=
"request.port"
controls-position=
"right"
:min=
"0"
:max=
"65535"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.connect')"
prop=
"ctimeout"
>
<el-input-number
v-model=
"request.ctimeout"
controls-position=
"right"
:min=
"0"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.response')"
prop=
"timeout"
>
<el-input-number
v-model=
"request.timeout"
controls-position=
"right"
:min=
"0"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.so_linger')"
prop=
"soLinger"
>
<el-input
v-model=
"request.soLinger"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.eol_byte')"
prop=
"eolByte"
>
<el-input
v-model=
"request.eolByte"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"6"
>
<el-form-item>
<el-switch
v-model=
"request.useEnvironment"
:active-text=
"$t('api_test.request.refer_to_environment')"
@
change=
"useEnvironmentChange"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item>
<el-switch
v-model=
"request.reUseConnection"
:active-text=
"$t('api_test.request.tcp.re_use_connection')"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item>
<el-switch
v-model=
"request.closeConnection"
:active-text=
"$t('api_test.request.tcp.close_connection')"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item>
<el-switch
v-model=
"request.nodelay"
:active-text=
"$t('api_test.request.tcp.no_delay')"
>
</el-switch>
</el-form-item>
</el-col>
</el-row>
<el-form-item
:label=
"$t('api_test.request.tcp.request')"
prop=
"request"
>
<el-input
type=
"textarea"
v-model=
"request.request"
:autosize=
"
{minRows: 4, maxRows: 6}">
</el-input>
</el-form-item>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.username')"
prop=
"username"
>
<el-input
v-model=
"request.username"
maxlength=
"100"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.password')"
prop=
"password"
>
<el-input
v-model=
"request.password"
maxlength=
"30"
show-word-limit
show-password
autocomplete=
"new-password"
/>
</el-form-item>
</el-col>
</el-row>
<el-button
:disabled=
"!request.enable || !scenario.enable || isReadOnly"
class=
"debug-button"
size=
"small"
type=
"primary"
@
click=
"runDebug"
>
{{
$t
(
'
api_test.request.debug
'
)
}}
</el-button>
<el-tabs
v-model=
"activeName"
>
<el-tab-pane
:label=
"$t('api_test.request.assertions.label')"
name=
"assertions"
>
<ms-api-assertions
:is-read-only=
"isReadOnly"
:assertions=
"request.assertions"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.request.extract.label')"
name=
"extract"
>
<ms-api-extract
:is-read-only=
"isReadOnly"
:extract=
"request.extract"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.request.processor.pre_exec_script')"
name=
"beanShellPreProcessor"
>
<ms-jsr233-processor
:is-read-only=
"isReadOnly"
:jsr223-processor=
"request.jsr223PreProcessor"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.request.processor.post_exec_script')"
name=
"beanShellPostProcessor"
>
<ms-jsr233-processor
:is-read-only=
"isReadOnly"
:jsr223-processor=
"request.jsr223PostProcessor"
/>
</el-tab-pane>
</el-tabs>
</el-form>
</
template
>
<
script
>
import
{
Scenario
,
TCPRequest
}
from
"
@/business/components/api/test/model/ScenarioModel
"
;
import
MsApiAssertions
from
"
@/business/components/api/test/components/assertion/ApiAssertions
"
;
import
MsApiExtract
from
"
@/business/components/api/test/components/extract/ApiExtract
"
;
import
MsJsr233Processor
from
"
@/business/components/api/test/components/processor/Jsr233Processor
"
;
export
default
{
name
:
"
MsApiTcpRequestForm
"
,
components
:
{
MsJsr233Processor
,
MsApiExtract
,
MsApiAssertions
},
props
:
{
request
:
TCPRequest
,
scenario
:
Scenario
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
activeName
:
"
assertions
"
,
classes
:
TCPRequest
.
CLASSES
,
rules
:
{
server
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.required
'
,
[
this
.
$t
(
'
api_test.request.tcp.server
'
)]),
trigger
:
'
blur
'
}
],
}
}
},
methods
:
{
useEnvironmentChange
(
value
)
{
if
(
value
&&
!
this
.
request
.
environment
)
{
this
.
$error
(
this
.
$t
(
'
api_test.request.please_add_environment_to_scenario
'
),
2000
);
this
.
request
.
useEnvironment
=
false
;
}
this
.
$refs
[
"
request
"
].
clearValidate
();
},
runDebug
()
{
this
.
$emit
(
'
runDebug
'
);
}
},
}
</
script
>
<
style
scoped
>
.tcp
>>>
.el-input-number
{
width
:
100%
;
}
</
style
>
frontend/src/business/components/api/test/components/request/tcp/TcpConfig.vue
0 → 100644
浏览文件 @
3f73ecd5
<
template
>
<el-form
class=
"tcp"
:model=
"config"
:rules=
"rules"
ref=
"config"
label-width=
"120px"
:disabled=
"isReadOnly"
size=
"small"
>
<el-form-item
label=
"TCPClient"
prop=
"classname"
>
<el-select
v-model=
"config.classname"
style=
"width: 100%"
>
<el-option
v-for=
"c in classes"
:key=
"c"
:label=
"c"
:value=
"c"
/>
</el-select>
</el-form-item>
<el-row
:gutter=
"10"
>
<el-col
:span=
"16"
>
<el-form-item
:label=
"$t('api_test.request.tcp.server')"
prop=
"server"
>
<el-input
v-model=
"config.server"
maxlength=
"300"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.port')"
prop=
"port"
label-width=
"60px"
>
<el-input-number
v-model=
"config.port"
controls-position=
"right"
:min=
"0"
:max=
"65535"
:controls=
"false"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.connect')"
prop=
"ctimeout"
>
<el-input-number
v-model=
"config.ctimeout"
controls-position=
"right"
:min=
"0"
:step=
"1000"
:controls=
"false"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.response')"
prop=
"timeout"
>
<el-input-number
v-model=
"config.timeout"
controls-position=
"right"
:min=
"0"
:step=
"1000"
:controls=
"false"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.so_linger')"
prop=
"soLinger"
>
<el-input
v-model=
"config.soLinger"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.eol_byte')"
prop=
"eolByte"
>
<el-input
v-model=
"config.eolByte"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"8"
>
<el-form-item>
<el-switch
v-model=
"config.reUseConnection"
:active-text=
"$t('api_test.request.tcp.re_use_connection')"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item>
<el-switch
v-model=
"config.closeConnection"
:active-text=
"$t('api_test.request.tcp.close_connection')"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item>
<el-switch
v-model=
"config.nodelay"
:active-text=
"$t('api_test.request.tcp.no_delay')"
>
</el-switch>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.username')"
prop=
"username"
>
<el-input
v-model=
"config.username"
maxlength=
"100"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.password')"
prop=
"password"
>
<el-input
v-model=
"config.password"
maxlength=
"30"
show-word-limit
show-password
autocomplete=
"new-password"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</
template
>
<
script
>
import
{
TCPConfig
}
from
"
@/business/components/api/test/model/ScenarioModel
"
;
export
default
{
name
:
"
MsTcpConfig
"
,
props
:
{
config
:
TCPConfig
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
},
},
data
()
{
return
{
classes
:
TCPConfig
.
CLASSES
,
rules
:
{}
}
},
}
</
script
>
<
style
scoped
>
.tcp
>>>
.el-input-number
{
width
:
100%
;
}
</
style
>
frontend/src/business/components/api/test/model/EnvironmentModel.js
浏览文件 @
3f73ecd5
import
{
BaseConfig
,
DatabaseConfig
,
KeyValue
}
from
"
./ScenarioModel
"
;
import
{
TCPConfig
}
from
"
@/business/components/api/test/model/ScenarioModel
"
;
export
class
Environment
extends
BaseConfig
{
constructor
(
options
=
{})
{
...
...
@@ -26,14 +27,17 @@ export class Config extends BaseConfig {
this
.
commonConfig
=
undefined
;
this
.
httpConfig
=
undefined
;
this
.
databaseConfigs
=
[];
this
.
tcpConfig
=
undefined
;
this
.
set
(
options
);
this
.
sets
({
databaseConfigs
:
DatabaseConfig
},
options
);
}
initOptions
(
options
=
{})
{
this
.
commonConfig
=
new
CommonConfig
(
options
.
commonConfig
);
this
.
httpConfig
=
new
HttpConfig
(
options
.
httpConfig
);
options
.
databaseConfigs
=
options
.
databaseConfigs
||
[];
options
.
tcpConfig
=
new
TCPConfig
(
options
.
tcpConfig
);
return
options
;
}
}
...
...
@@ -91,7 +95,6 @@ export class Host extends BaseConfig {
}
/* ---------- Functions ------- */
export
function
compatibleWithEnvironment
(
environment
)
{
...
...
frontend/src/business/components/api/test/model/JMX.js
浏览文件 @
3f73ecd5
...
...
@@ -291,6 +291,26 @@ export class JDBCSampler extends DefaultTestElement {
}
}
export
class
TCPSampler
extends
DefaultTestElement
{
constructor
(
testName
,
request
=
{})
{
super
(
'
TCPSampler
'
,
'
TCPSamplerGui
'
,
'
TCPSampler
'
,
testName
);
this
.
stringProp
(
"
TCPSampler.classname
"
,
request
.
classname
);
this
.
stringProp
(
"
TCPSampler.server
"
,
request
.
server
);
this
.
stringProp
(
"
TCPSampler.port
"
,
request
.
port
);
this
.
stringProp
(
"
TCPSampler.ctimeout
"
,
request
.
ctimeout
);
this
.
stringProp
(
"
TCPSampler.timeout
"
,
request
.
timeout
);
this
.
boolProp
(
"
TCPSampler.reUseConnection
"
,
request
.
reUseConnection
);
this
.
boolProp
(
"
TCPSampler.nodelay
"
,
request
.
nodelay
);
this
.
boolProp
(
"
TCPSampler.closeConnection
"
,
request
.
closeConnection
);
this
.
stringProp
(
"
TCPSampler.soLinger
"
,
request
.
soLinger
);
this
.
stringProp
(
"
TCPSampler.EolByte
"
,
request
.
eolByte
);
this
.
stringProp
(
"
TCPSampler.request
"
,
request
.
request
);
this
.
stringProp
(
"
ConfigTestElement.username
"
,
request
.
username
);
this
.
stringProp
(
"
ConfigTestElement.password
"
,
request
.
password
);
}
}
export
class
HTTPSamplerProxy
extends
DefaultTestElement
{
constructor
(
testName
,
options
=
{})
{
super
(
'
HTTPSamplerProxy
'
,
'
HttpTestSampleGui
'
,
'
HTTPSamplerProxy
'
,
testName
);
...
...
@@ -335,7 +355,7 @@ export class HTTPSamplerArguments extends Element {
let
collectionProp
=
this
.
collectionProp
(
'
Arguments.arguments
'
);
this
.
args
.
forEach
(
arg
=>
{
if
(
arg
.
enable
===
true
||
arg
.
enable
===
undefined
)
{
// 非禁用的条件加入执行
if
(
arg
.
enable
===
true
||
arg
.
enable
===
undefined
)
{
// 非禁用的条件加入执行
let
elementProp
=
collectionProp
.
elementProp
(
arg
.
name
,
'
HTTPArgument
'
);
elementProp
.
boolProp
(
'
HTTPArgument.always_encode
'
,
arg
.
encode
,
true
);
elementProp
.
boolProp
(
'
HTTPArgument.use_equals
'
,
arg
.
equals
,
true
);
...
...
frontend/src/business/components/api/test/model/ScenarioModel.js
浏览文件 @
3f73ecd5
...
...
@@ -25,7 +25,7 @@ import {
ThreadGroup
,
XPath2Extractor
,
IfController
as
JMXIfController
,
ConstantTimer
as
JMXConstantTimer
,
ConstantTimer
as
JMXConstantTimer
,
TCPSampler
,
}
from
"
./JMX
"
;
import
Mock
from
"
mockjs
"
;
import
{
funcFilters
}
from
"
@/common/js/func-filter
"
;
...
...
@@ -111,12 +111,16 @@ export const EXTRACT_TYPE = {
export
class
BaseConfig
{
set
(
options
)
{
set
(
options
,
notUndefined
)
{
options
=
this
.
initOptions
(
options
)
for
(
let
name
in
options
)
{
if
(
options
.
hasOwnProperty
(
name
))
{
if
(
!
(
this
[
name
]
instanceof
Array
))
{
this
[
name
]
=
options
[
name
];
if
(
notUndefined
===
true
)
{
this
[
name
]
=
options
[
name
]
===
undefined
?
this
[
name
]
:
options
[
name
];
}
else
{
this
[
name
]
=
options
[
name
];
}
}
}
}
...
...
@@ -219,6 +223,7 @@ export class Scenario extends BaseConfig {
this
.
enableCookieShare
=
false
;
this
.
enable
=
true
;
this
.
databaseConfigs
=
[];
this
.
tcpConfig
=
undefined
;
this
.
set
(
options
);
this
.
sets
({
...
...
@@ -234,6 +239,7 @@ export class Scenario extends BaseConfig {
options
.
requests
=
options
.
requests
||
[
new
RequestFactory
()];
options
.
databaseConfigs
=
options
.
databaseConfigs
||
[];
options
.
dubboConfig
=
new
DubboConfig
(
options
.
dubboConfig
);
options
.
tcpConfig
=
new
TCPConfig
(
options
.
tcpConfig
);
return
options
;
}
...
...
@@ -286,6 +292,7 @@ export class RequestFactory {
HTTP
:
"
HTTP
"
,
DUBBO
:
"
DUBBO
"
,
SQL
:
"
SQL
"
,
TCP
:
"
TCP
"
,
}
constructor
(
options
=
{})
{
...
...
@@ -295,6 +302,8 @@ export class RequestFactory {
return
new
DubboRequest
(
options
);
case
RequestFactory
.
TYPES
.
SQL
:
return
new
SqlRequest
(
options
);
case
RequestFactory
.
TYPES
.
TCP
:
return
new
TCPRequest
(
options
);
default
:
return
new
HttpRequest
(
options
);
}
...
...
@@ -305,9 +314,15 @@ export class Request extends BaseConfig {
constructor
(
type
,
options
=
{})
{
super
();
this
.
type
=
type
;
options
.
id
=
options
.
id
||
uuid
();
this
.
timer
=
options
.
timer
=
new
ConstantTimer
(
options
.
timer
);
this
.
controller
=
options
.
controller
=
new
IfController
(
options
.
controller
);
this
.
id
=
options
.
id
||
uuid
();
this
.
name
=
options
.
name
;
this
.
enable
=
options
.
enable
===
undefined
?
true
:
options
.
enable
;
this
.
assertions
=
new
Assertions
(
options
.
assertions
);
this
.
extract
=
new
Extract
(
options
.
extract
);
this
.
jsr223PreProcessor
=
new
JSR223Processor
(
options
.
jsr223PreProcessor
);
this
.
jsr223PostProcessor
=
new
JSR223Processor
(
options
.
jsr223PostProcessor
);
this
.
timer
=
new
ConstantTimer
(
options
.
timer
);
this
.
controller
=
new
IfController
(
options
.
controller
);
}
showType
()
{
...
...
@@ -322,41 +337,22 @@ export class Request extends BaseConfig {
export
class
HttpRequest
extends
Request
{
constructor
(
options
)
{
super
(
RequestFactory
.
TYPES
.
HTTP
,
options
);
this
.
name
=
undefined
;
this
.
url
=
undefined
;
this
.
path
=
undefined
;
this
.
method
=
undefined
;
this
.
url
=
options
.
url
;
this
.
path
=
options
.
path
;
this
.
method
=
options
.
method
||
"
GET
"
;
this
.
parameters
=
[];
this
.
headers
=
[];
this
.
body
=
undefined
;
this
.
assertions
=
undefined
;
this
.
extract
=
undefined
;
this
.
environment
=
undefined
;
this
.
useEnvironment
=
undefined
;
this
.
body
=
new
Body
(
options
.
body
);
this
.
environment
=
options
.
environment
;
this
.
useEnvironment
=
options
.
useEnvironment
;
this
.
debugReport
=
undefined
;
this
.
beanShellPreProcessor
=
undefined
;
this
.
beanShellPostProcessor
=
undefined
;
this
.
jsr223PreProcessor
=
undefined
;
this
.
jsr223PostProcessor
=
undefined
;
this
.
enable
=
true
;
this
.
connectTimeout
=
60
*
1000
;
this
.
responseTimeout
=
undefined
;
this
.
followRedirects
=
true
;
this
.
connectTimeout
=
options
.
connectTimeout
||
60
*
1000
;
this
.
responseTimeout
=
options
.
responseTimeout
;
this
.
followRedirects
=
options
.
followRedirects
===
undefined
?
true
:
options
.
followRedirects
;
this
.
set
(
options
);
this
.
sets
({
parameters
:
KeyValue
,
headers
:
KeyValue
},
options
);
}
initOptions
(
options
=
{})
{
options
.
method
=
options
.
method
||
"
GET
"
;
options
.
body
=
new
Body
(
options
.
body
);
options
.
assertions
=
new
Assertions
(
options
.
assertions
);
options
.
extract
=
new
Extract
(
options
.
extract
);
options
.
jsr223PreProcessor
=
new
JSR223Processor
(
options
.
jsr223PreProcessor
);
options
.
jsr223PostProcessor
=
new
JSR223Processor
(
options
.
jsr223PostProcessor
);
return
options
;
}
isValid
(
environmentId
,
environment
)
{
if
(
this
.
enable
)
{
if
(
this
.
useEnvironment
)
{
...
...
@@ -412,7 +408,6 @@ export class DubboRequest extends Request {
constructor
(
options
=
{})
{
super
(
RequestFactory
.
TYPES
.
DUBBO
,
options
);
this
.
name
=
options
.
name
;
this
.
protocol
=
options
.
protocol
||
DubboRequest
.
PROTOCOLS
.
DUBBO
;
this
.
interface
=
options
.
interface
;
this
.
method
=
options
.
method
;
...
...
@@ -421,16 +416,9 @@ export class DubboRequest extends Request {
this
.
consumerAndService
=
new
ConsumerAndService
(
options
.
consumerAndService
);
this
.
args
=
[];
this
.
attachmentArgs
=
[];
this
.
assertions
=
new
Assertions
(
options
.
assertions
);
this
.
extract
=
new
Extract
(
options
.
extract
);
// Scenario.dubboConfig
this
.
dubboConfig
=
undefined
;
this
.
debugReport
=
undefined
;
this
.
beanShellPreProcessor
=
new
BeanShellProcessor
(
options
.
beanShellPreProcessor
);
this
.
beanShellPostProcessor
=
new
BeanShellProcessor
(
options
.
beanShellPostProcessor
);
this
.
enable
=
options
.
enable
===
undefined
?
true
:
options
.
enable
;
this
.
jsr223PreProcessor
=
new
JSR223Processor
(
options
.
jsr223PreProcessor
);
this
.
jsr223PostProcessor
=
new
JSR223Processor
(
options
.
jsr223PostProcessor
);
this
.
sets
({
args
:
KeyValue
,
attachmentArgs
:
KeyValue
},
options
);
}
...
...
@@ -485,8 +473,6 @@ export class SqlRequest extends Request {
constructor
(
options
=
{})
{
super
(
RequestFactory
.
TYPES
.
SQL
,
options
);
this
.
id
=
options
.
id
||
uuid
();
this
.
name
=
options
.
name
;
this
.
useEnvironment
=
options
.
useEnvironment
;
this
.
resultVariable
=
options
.
resultVariable
;
this
.
variableNames
=
options
.
variableNames
;
...
...
@@ -495,11 +481,6 @@ export class SqlRequest extends Request {
this
.
query
=
options
.
query
;
// this.queryType = options.queryType;
this
.
queryTimeout
=
options
.
queryTimeout
||
60000
;
this
.
enable
=
options
.
enable
===
undefined
?
true
:
options
.
enable
;
this
.
assertions
=
new
Assertions
(
options
.
assertions
);
this
.
extract
=
new
Extract
(
options
.
extract
);
this
.
jsr223PreProcessor
=
new
JSR223Processor
(
options
.
jsr223PreProcessor
);
this
.
jsr223PostProcessor
=
new
JSR223Processor
(
options
.
jsr223PostProcessor
);
this
.
sets
({
args
:
KeyValue
,
attachmentArgs
:
KeyValue
},
options
);
}
...
...
@@ -537,6 +518,67 @@ export class SqlRequest extends Request {
}
}
export
class
TCPConfig
extends
BaseConfig
{
static
CLASSES
=
[
"
TCPClientImpl
"
,
"
BinaryTCPClientImpl
"
,
"
LengthPrefixedBinaryTCPClientImpl
"
]
constructor
(
options
=
{})
{
super
();
this
.
classname
=
options
.
classname
||
TCPConfig
.
CLASSES
[
0
];
this
.
server
=
options
.
server
;
this
.
port
=
options
.
port
;
this
.
ctimeout
=
options
.
ctimeout
;
// Connect
this
.
timeout
=
options
.
timeout
;
// Response
this
.
reUseConnection
=
options
.
reUseConnection
===
undefined
?
true
:
options
.
reUseConnection
;
this
.
nodelay
=
options
.
nodelay
===
undefined
?
false
:
options
.
nodelay
;
this
.
closeConnection
=
options
.
closeConnection
===
undefined
?
false
:
options
.
closeConnection
;
this
.
soLinger
=
options
.
soLinger
;
this
.
eolByte
=
options
.
eolByte
;
this
.
username
=
options
.
username
;
this
.
password
=
options
.
password
;
}
}
export
class
TCPRequest
extends
Request
{
constructor
(
options
=
{})
{
super
(
RequestFactory
.
TYPES
.
TCP
,
options
);
this
.
useEnvironment
=
options
.
useEnvironment
;
this
.
debugReport
=
undefined
;
//设置TCPConfig的属性
this
.
set
(
new
TCPConfig
(
options
));
this
.
request
=
options
.
request
;
}
isValid
()
{
if
(
this
.
enable
)
{
if
(
!
this
.
server
)
{
return
{
isValid
:
false
,
info
:
'
api_test.request.tcp.server_cannot_be_empty
'
}
}
}
return
{
isValid
:
true
}
}
showType
()
{
return
"
TCP
"
;
}
showMethod
()
{
return
"
TCP
"
;
}
clone
()
{
return
new
TCPRequest
(
this
);
}
}
export
class
ConfigCenter
extends
BaseConfig
{
static
PROTOCOLS
=
[
"
zookeeper
"
,
"
nacos
"
,
"
apollo
"
];
...
...
@@ -658,7 +700,7 @@ export class Body extends BaseConfig {
export
class
KeyValue
extends
BaseConfig
{
constructor
(
options
)
{
options
=
options
||
{};
options
.
enable
=
options
.
enable
!=
false
?
true
:
fals
e
;
options
.
enable
=
options
.
enable
===
undefined
?
true
:
options
.
enabl
e
;
super
();
this
.
name
=
undefined
;
...
...
@@ -1003,6 +1045,19 @@ class JMXDubboRequest {
}
}
class
JMXTCPRequest
{
constructor
(
request
,
scenario
)
{
let
obj
=
request
.
clone
();
if
(
request
.
useEnvironment
)
{
obj
.
set
(
scenario
.
environment
.
config
.
tcpConfig
,
true
);
return
obj
;
}
obj
.
set
(
scenario
.
tcpConfig
,
true
);
return
obj
;
}
}
class
JMeterTestPlan
extends
Element
{
constructor
()
{
super
(
'
jmeterTestPlan
'
,
{
...
...
@@ -1060,6 +1115,8 @@ class JMXGenerator {
}
else
if
(
request
instanceof
SqlRequest
)
{
request
.
dataSource
=
scenario
.
databaseConfigMap
.
get
(
request
.
dataSource
);
sampler
=
new
JDBCSampler
(
request
.
name
||
""
,
request
);
}
else
if
(
request
instanceof
TCPRequest
)
{
sampler
=
new
TCPSampler
(
request
.
name
||
""
,
new
JMXTCPRequest
(
request
,
scenario
));
}
this
.
addDNSCacheManager
(
sampler
,
scenario
.
environment
,
request
.
useEnvironment
);
...
...
@@ -1135,7 +1192,7 @@ class JMXGenerator {
let
domain
=
environment
.
config
.
httpConfig
.
domain
;
let
validHosts
=
[];
hosts
.
forEach
(
item
=>
{
if
(
item
.
domain
!=
undefined
&&
domain
!
=
undefined
)
{
if
(
item
.
domain
!=
=
undefined
&&
domain
!=
=
undefined
)
{
let
d
=
item
.
domain
.
trim
().
replace
(
"
http://
"
,
""
).
replace
(
"
https://
"
,
""
);
if
(
d
===
domain
.
trim
())
{
item
.
domain
=
d
;
// 域名去掉协议
...
...
@@ -1295,7 +1352,7 @@ class JMXGenerator {
body
.
push
({
name
:
''
,
value
:
request
.
body
.
raw
,
encode
:
false
,
enable
:
true
});
}
if
(
request
.
method
!=
'
GET
'
)
{
if
(
request
.
method
!=
=
'
GET
'
)
{
httpSamplerProxy
.
add
(
new
HTTPSamplerArguments
(
body
));
}
}
...
...
@@ -1304,7 +1361,7 @@ class JMXGenerator {
let
files
=
[];
let
kvs
=
this
.
filterKVFile
(
request
.
body
.
kvs
);
kvs
.
forEach
(
kv
=>
{
if
((
kv
.
enable
!=
false
)
&&
kv
.
files
)
{
if
((
kv
.
enable
!=
=
false
)
&&
kv
.
files
)
{
kv
.
files
.
forEach
(
file
=>
{
let
arg
=
{};
arg
.
name
=
kv
.
name
;
...
...
frontend/src/business/components/settings/CurrentUser.vue
浏览文件 @
3f73ecd5
<
template
>
<el-row
type=
"flex"
align=
"middle"
class=
"current-user"
>
<el-avatar
shape=
"square"
size=
"small"
:src=
"squareUrl"
/>
<span
class=
"username"
>
{{
currentUser
.
name
}}
</span>
<div
class=
"icon-title"
>
{{
currentUser
.
name
.
substring
(
0
,
1
)
}}
</div>
<span
class=
"username"
>
{{
currentUser
.
name
}}
</span>
</el-row>
</
template
>
<
script
>
import
{
getCurrentUser
}
from
"
../../../common/js/utils
"
;
export
default
{
name
:
"
MsCurrentUser
"
,
data
()
{
return
{
editVisible
:
false
,
id
:
"
123456
"
,
squareUrl
:
"
https://cube.elemecdn.com/9/c2/f0ee8a3c7c9638a54940382568c9dpng.png
"
,
form
:
{}
}
},
methods
:
{
edit
()
{
this
.
editVisible
=
true
;
this
.
form
=
Object
.
assign
({},
this
.
currentUser
);
},
submit
()
{
this
.
editVisible
=
false
;
}
import
{
getCurrentUser
}
from
"
@/common/js/utils
"
;
export
default
{
name
:
"
MsCurrentUser
"
,
data
()
{
return
{
editVisible
:
false
,
id
:
"
123456
"
,
form
:
{}
}
},
methods
:
{
edit
()
{
this
.
editVisible
=
true
;
this
.
form
=
Object
.
assign
({},
this
.
currentUser
);
},
computed
:
{
currentUser
:
()
=>
{
return
getCurrentUser
();
}
submit
()
{
this
.
editVisible
=
false
;
}
},
computed
:
{
currentUser
:
()
=>
{
return
getCurrentUser
();
}
}
}
</
script
>
<
style
scoped
>
.current-user
.username
{
display
:
inline-block
;
font-size
:
16px
;
font-weight
:
500
;
margin
:
0
5px
;
overflow-x
:
hidden
;
padding-bottom
:
0
;
text-overflow
:
ellipsis
;
vertical-align
:
middle
;
white-space
:
nowrap
;
width
:
180px
;
}
.current-user
.username
{
display
:
inline-block
;
font-size
:
16px
;
font-weight
:
500
;
margin
:
0
5px
;
overflow-x
:
hidden
;
padding-bottom
:
0
;
text-overflow
:
ellipsis
;
vertical-align
:
middle
;
white-space
:
nowrap
;
width
:
180px
;
}
.current-user
.edit
{
opacity
:
0
;
}
.current-user
.edit
{
opacity
:
0
;
}
.current-user
:hover
.edit
{
opacity
:
1
;
}
.icon-title
{
color
:
#fff
;
width
:
30px
;
background-color
:
#72dc91
;
height
:
30px
;
line-height
:
30px
;
text-align
:
center
;
border-radius
:
30px
;
font-size
:
14px
;
}
.current-user
:hover
.edit
{
opacity
:
1
;
}
</
style
>
frontend/src/business/components/track/plan/components/TestPlanEdit.vue
浏览文件 @
3f73ecd5
...
...
@@ -3,7 +3,7 @@
<div>
<el-dialog
:close-on-click-modal=
"false"
:title=
"operationType == 'edit' ? $t('test_track.plan.edit_plan') : $t('test_track.plan.create_plan')"
:title=
"operationType ==
=
'edit' ? $t('test_track.plan.edit_plan') : $t('test_track.plan.create_plan')"
:visible.sync=
"dialogFormVisible"
@
close=
"close"
width=
"65%"
>
...
...
@@ -75,7 +75,8 @@
:label=
"$t('test_track.plan.planned_start_time')"
:label-width=
"formLabelWidth"
prop=
"plannedStartTime"
>
<el-date-picker
:placeholder=
"$t('test_track.plan.planned_start_time')"
v-model=
"form.plannedStartTime"
type=
"datetime"
value-format=
"timestamp"
></el-date-picker>
<el-date-picker
:placeholder=
"$t('test_track.plan.planned_start_time')"
v-model=
"form.plannedStartTime"
type=
"datetime"
value-format=
"timestamp"
></el-date-picker>
</el-form-item>
</el-col>
...
...
@@ -84,7 +85,8 @@
:label=
"$t('test_track.plan.planned_end_time')"
:label-width=
"formLabelWidth"
prop=
"plannedEndTime"
>
<el-date-picker
:placeholder=
"$t('test_track.plan.planned_end_time')"
v-model=
"form.plannedEndTime"
type=
"datetime"
value-format=
"timestamp"
></el-date-picker>
<el-date-picker
:placeholder=
"$t('test_track.plan.planned_end_time')"
v-model=
"form.plannedEndTime"
type=
"datetime"
value-format=
"timestamp"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
...
...
@@ -102,7 +104,7 @@
</el-col>
</el-row>
<el-row
v-if=
"operationType == 'edit'"
type=
"flex"
justify=
"left"
style=
"margin-top: 10px;"
>
<el-row
v-if=
"operationType ==
=
'edit'"
type=
"flex"
justify=
"left"
style=
"margin-top: 10px;"
>
<el-col
:span=
"19"
:offset=
"1"
>
<el-form-item
:label=
"$t('test_track.plan.plan_status')"
:label-width=
"formLabelWidth"
prop=
"status"
>
<test-plan-status-button
:status=
"form.status"
@
statusChange=
"statusChange"
/>
...
...
@@ -134,9 +136,9 @@
<
script
>
import
{
WORKSPACE_ID
}
from
'
../../../../..
/common/js/constants
'
;
import
{
WORKSPACE_ID
}
from
'
@
/common/js/constants
'
;
import
TestPlanStatusButton
from
"
../common/TestPlanStatusButton
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
../../../../..
/common/js/utils
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
@
/common/js/utils
"
;
import
{
LIST_CHANGE
,
TrackEvent
}
from
"
@/business/components/common/head/ListEvent
"
;
export
default
{
...
...
@@ -194,7 +196,7 @@ export default {
let
param
=
{};
Object
.
assign
(
param
,
this
.
form
);
param
.
name
=
param
.
name
.
trim
();
if
(
param
.
name
==
''
)
{
if
(
param
.
name
==
=
''
)
{
this
.
$warning
(
this
.
$t
(
'
test_track.plan.input_plan_name
'
));
return
;
}
...
...
@@ -206,7 +208,7 @@ export default {
this
.
dbProjectIds
.
forEach
(
dbId
=>
{
if
(
nowIds
.
indexOf
(
dbId
)
===
-
1
&&
sign
)
{
sign
=
false
;
this
.
$confirm
(
'
取消项目关联会同时取消该项目下已关联的测试用例
'
,
'
提示
'
,
{
this
.
$confirm
(
this
.
$t
(
'
test_track.case.cancel_relevance_project
'
),
this
.
$t
(
'
commons.prompt
'
)
,
{
confirmButtonText
:
this
.
$t
(
'
commons.confirm
'
),
cancelButtonText
:
this
.
$t
(
'
commons.cancel
'
),
type
:
'
warning
'
...
...
@@ -263,7 +265,7 @@ export default {
resetForm
()
{
//防止点击修改后,点击新建触发校验
if
(
this
.
$refs
[
'
planFrom
'
])
{
this
.
$refs
[
'
planFrom
'
].
validate
((
valid
)
=>
{
this
.
$refs
[
'
planFrom
'
].
validate
(()
=>
{
this
.
$refs
[
'
planFrom
'
].
resetFields
();
this
.
form
.
name
=
''
;
this
.
form
.
projectIds
=
[];
...
...
frontend/src/business/components/track/plan/components/TestPlanList.vue
浏览文件 @
3f73ecd5
...
...
@@ -20,7 +20,7 @@
show-overflow-tooltip
>
</el-table-column>
<el-table-column
prop=
"
principal
"
prop=
"
userName
"
:label=
"$t('test_track.plan.plan_principal')"
show-overflow-tooltip
>
</el-table-column>
...
...
@@ -141,7 +141,7 @@ import MsTableOperatorButton from "../../../common/components/MsTableOperatorBut
import
MsTableOperator
from
"
../../../common/components/MsTableOperator
"
;
import
PlanStatusTableItem
from
"
../../common/tableItems/plan/PlanStatusTableItem
"
;
import
PlanStageTableItem
from
"
../../common/tableItems/plan/PlanStageTableItem
"
;
import
{
_filter
,
_sort
,
checkoutTestManagerOrTestUser
}
from
"
../../../../..
/common/js/utils
"
;
import
{
_filter
,
_sort
,
checkoutTestManagerOrTestUser
}
from
"
@
/common/js/utils
"
;
import
TestReportTemplateList
from
"
../view/comonents/TestReportTemplateList
"
;
import
TestCaseReportView
from
"
../view/comonents/report/TestCaseReportView
"
;
import
MsDeleteConfirm
from
"
../../../common/components/MsDeleteConfirm
"
;
...
...
frontend/src/business/components/track/plan/view/comonents/TestPlanTestCaseEdit.vue
浏览文件 @
3f73ecd5
...
...
@@ -26,11 +26,15 @@
</el-col>
<el-col
:span=
"12"
class=
"head-right"
>
<span
class=
"head-right-tip"
v-if=
"index + 1 == testCases.length"
>
{{
$t
(
'
test_track.plan_view.pre_case
'
)
}}
:
{{
testCases
[
index
-
1
]
?
testCases
[
index
-
1
].
name
:
''
}}
<span
class=
"head-right-tip"
v-if=
"index + 1 === testCases.length"
>
{{
$t
(
'
test_track.plan_view.pre_case
'
)
}}
:
{{
testCases
[
index
-
1
]
?
testCases
[
index
-
1
].
name
:
''
}}
</span>
<span
class=
"head-right-tip"
v-if=
"index + 1 != testCases.length"
>
{{
$t
(
'
test_track.plan_view.next_case
'
)
}}
:
{{
testCases
[
index
+
1
]
?
testCases
[
index
+
1
].
name
:
''
}}
<span
class=
"head-right-tip"
v-if=
"index + 1 !== testCases.length"
>
{{
$t
(
'
test_track.plan_view.next_case
'
)
}}
:
{{
testCases
[
index
+
1
]
?
testCases
[
index
+
1
].
name
:
''
}}
</span>
<el-button
plain
size=
"mini"
icon=
"el-icon-arrow-up"
...
...
@@ -49,7 +53,7 @@
</el-row>
<el-row
style=
"margin-top: 0
px
;"
>
<el-row
style=
"margin-top: 0;"
>
<el-col>
<el-divider
content-position=
"left"
>
{{
testCase
.
name
}}
</el-divider>
</el-col>
...
...
@@ -65,9 +69,9 @@
</el-col>
<el-col
:span=
"5"
>
<span
class=
"cast_label"
>
{{
$t
(
'
test_track.case.case_type
'
)
}}
:
</span>
<span
class=
"cast_item"
v-if=
"testCase.type == 'functional'"
>
{{
$t
(
'
commons.functional
'
)
}}
</span>
<span
class=
"cast_item"
v-if=
"testCase.type == 'performance'"
>
{{
$t
(
'
commons.performance
'
)
}}
</span>
<span
class=
"cast_item"
v-if=
"testCase.type == 'api'"
>
{{
$t
(
'
commons.api
'
)
}}
</span>
<span
class=
"cast_item"
v-if=
"testCase.type ==
=
'functional'"
>
{{
$t
(
'
commons.functional
'
)
}}
</span>
<span
class=
"cast_item"
v-if=
"testCase.type ==
=
'performance'"
>
{{
$t
(
'
commons.performance
'
)
}}
</span>
<span
class=
"cast_item"
v-if=
"testCase.type ==
=
'api'"
>
{{
$t
(
'
commons.api
'
)
}}
</span>
</el-col>
<el-col
:span=
"13"
>
<test-plan-test-case-status-button
class=
"status-button"
...
...
@@ -81,8 +85,8 @@
<el-row>
<el-col
:span=
"4"
:offset=
"1"
>
<span
class=
"cast_label"
>
{{
$t
(
'
test_track.case.method
'
)
}}
:
</span>
<span
v-if=
"testCase.method == 'manual'"
>
{{
$t
(
'
test_track.case.manual
'
)
}}
</span>
<span
v-if=
"testCase.method == 'auto'"
>
{{
$t
(
'
test_track.case.auto
'
)
}}
</span>
<span
v-if=
"testCase.method ==
=
'manual'"
>
{{
$t
(
'
test_track.case.manual
'
)
}}
</span>
<span
v-if=
"testCase.method ==
=
'auto'"
>
{{
$t
(
'
test_track.case.auto
'
)
}}
</span>
</el-col>
<el-col
:span=
"5"
>
<span
class=
"cast_label"
>
{{
$t
(
'
test_track.case.module
'
)
}}
:
</span>
...
...
@@ -101,25 +105,26 @@
</el-col>
</el-row>
<el-row
v-if=
"testCase.method == 'auto' && testCase.testId"
>
<el-row
v-if=
"testCase.method ==
=
'auto' && testCase.testId"
>
<el-col
class=
"test-detail"
:span=
"20"
:offset=
"1"
>
<el-tabs
v-model=
"activeTab"
type=
"border-card"
@
tab-click=
"testTabChange"
>
<el-tab-pane
name=
"detail"
:label=
"$t('test_track.plan_view.test_detail')"
>
<api-test-detail
:is-read-only=
"isReadOnly"
v-if=
"testCase.type == 'api'"
@
runTest=
"testRun"
<api-test-detail
:is-read-only=
"isReadOnly"
v-if=
"testCase.type ==
=
'api'"
@
runTest=
"testRun"
:id=
"testCase.testId"
ref=
"apiTestDetail"
/>
<performance-test-detail
:is-read-only=
"isReadOnly"
v-if=
"testCase.type == 'performance'"
<performance-test-detail
:is-read-only=
"isReadOnly"
v-if=
"testCase.type ==
=
'performance'"
@
runTest=
"testRun"
:id=
"testCase.testId"
ref=
"performanceTestDetail"
/>
</el-tab-pane>
<el-tab-pane
name=
"result"
:label=
"$t('test_track.plan_view.test_result')"
>
<api-test-result
:report-id=
"testCase.reportId"
v-if=
" testCase.type == 'api'"
ref=
"apiTestResult"
/>
<api-test-result
:report-id=
"testCase.reportId"
v-if=
" testCase.type === 'api'"
ref=
"apiTestResult"
/>
<performance-test-result
:is-read-only=
"isReadOnly"
:report-id=
"testCase.reportId"
v-if=
"testCase.type == 'performance'"
ref=
"performanceTestResult"
/>
v-if=
"testCase.type ==
=
'performance'"
ref=
"performanceTestResult"
/>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
<el-row
v-if=
"testCase.method && testCase.method != 'auto'"
>
<el-row
v-if=
"testCase.method && testCase.method !=
=
'auto'"
>
<el-col
:span=
"20"
:offset=
"1"
>
<div>
<span
class=
"cast_label"
>
{{
$t
(
'
test_track.case.steps
'
)
}}
:
</span>
...
...
@@ -219,8 +224,11 @@
<ckeditor
:editor=
"editor"
:disabled=
"isReadOnly"
:config=
"editorConfig"
v-model=
"testCase.issues.content"
/>
<el-row
v-if=
"hasTapdId"
>
Tapd平台处理人:
<el-select
v-model=
"testCase.tapdUsers"
placeholder=
"请选择处理人"
style=
"width: 20%"
multiple
{{ $t('test_track.issue.please_choose_current_owner') }}
<el-select
v-model=
"testCase.tapdUsers"
multiple
style=
"width: 20%"
:placeholder=
"$t('test_track.issue.please_choose_current_owner')"
collapse-tags
>
<el-option
v-for=
"(userInfo, index) in users"
:key=
"index"
:label=
"userInfo.user"
:value=
"userInfo.user"
/>
...
...
@@ -277,7 +285,7 @@
<el-col
:span=
"15"
:offset=
"1"
>
<div>
<span
class=
"cast_label"
>
{{ $t('commons.remark') }}:
</span>
<span
v-if=
"testCase.remark == null || testCase.remark == ''"
<span
v-if=
"testCase.remark == null || testCase.remark ==
=
''"
style=
"color: darkgrey"
>
{{ $t('commons.not_filled') }}
</span>
</div>
<div>
...
...
@@ -309,8 +317,7 @@ import ApiTestDetail from "./test/ApiTestDetail";
import
ApiTestResult
from
"
./test/ApiTestResult
"
;
import
PerformanceTestDetail
from
"
./test/PerformanceTestDetail
"
;
import
PerformanceTestResult
from
"
./test/PerformanceTestResult
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
../../../../../../common/js/utils
"
;
import
{
CURRENT_PROJECT
}
from
"
../../../../../../common/js/constants
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
@/common/js/utils
"
;
export
default
{
name
:
"
TestPlanTestCaseEdit
"
,
...
...
@@ -332,7 +339,6 @@ export default {
issues
:
[],
editor
:
ClassicEditor
,
editorConfig
:
{
// 'increaseIndent','decreaseIndent'
toolbar
:
[
'
heading
'
,
'
|
'
,
'
bold
'
,
'
italic
'
,
'
link
'
,
'
bulletedList
'
,
'
numberedList
'
,
'
blockQuote
'
,
'
insertTable
'
,
'
|
'
,
'
undo
'
,
'
redo
'
],
},
readConfig
:
{
toolbar
:
[]},
...
...
@@ -368,6 +374,7 @@ export default {
},
statusChange
(
status
)
{
this
.
testCase
.
status
=
status
;
this
.
saveCase
();
},
saveCase
()
{
let
param
=
{};
...
...
@@ -388,11 +395,14 @@ export default {
}
param
.
results
=
JSON
.
stringify
(
param
.
results
);
param
.
issues
=
JSON
.
stringify
(
this
.
testCase
.
issues
);
this
.
$post
(
'
/test/plan/case/edit
'
,
param
,
()
=>
{
this
.
$success
(
this
.
$t
(
'
commons.save_success
'
));
this
.
updateTestCases
(
param
);
this
.
setPlanStatus
(
this
.
testCase
.
planId
);
// 结果为Pass时 自动跳转到下一用例
if
(
this
.
testCase
.
status
===
'
Pass
'
&&
this
.
index
<
this
.
testCases
.
length
-
1
)
{
this
.
handleNext
();
}
});
},
updateTestCases
(
param
)
{
...
...
@@ -448,11 +458,11 @@ export default {
},
initTest
()
{
this
.
$nextTick
(()
=>
{
if
(
this
.
testCase
.
method
==
'
auto
'
)
{
if
(
this
.
$refs
.
apiTestDetail
&&
this
.
testCase
.
type
==
'
api
'
)
{
if
(
this
.
testCase
.
method
==
=
'
auto
'
)
{
if
(
this
.
$refs
.
apiTestDetail
&&
this
.
testCase
.
type
==
=
'
api
'
)
{
this
.
$refs
.
apiTestDetail
.
init
();
}
else
if
(
this
.
testCase
.
type
==
'
performance
'
)
{
}
else
if
(
this
.
testCase
.
type
==
=
'
performance
'
)
{
this
.
$refs
.
performanceTestDetail
.
init
();
}
}
...
...
@@ -464,7 +474,7 @@ export default {
this
.
activeTab
=
'
result
'
;
},
testTabChange
(
data
)
{
if
(
this
.
testCase
.
type
==
'
performance
'
&&
data
.
paneName
==
'
result
'
)
{
if
(
this
.
testCase
.
type
==
=
'
performance
'
&&
data
.
paneName
=
==
'
result
'
)
{
this
.
$refs
.
performanceTestResult
.
checkReportStatus
();
this
.
$refs
.
performanceTestResult
.
init
();
}
...
...
@@ -485,7 +495,7 @@ export default {
});
},
getRelatedTest
()
{
if
(
this
.
testCase
.
method
==
'
auto
'
&&
this
.
testCase
.
testId
&&
this
.
testCase
.
testId
!
=
'
other
'
)
{
if
(
this
.
testCase
.
method
==
=
'
auto
'
&&
this
.
testCase
.
testId
&&
this
.
testCase
.
testId
!=
=
'
other
'
)
{
this
.
$get
(
'
/
'
+
this
.
testCase
.
type
+
'
/get/
'
+
this
.
testCase
.
testId
,
response
=>
{
let
data
=
response
.
data
;
if
(
data
)
{
...
...
@@ -495,7 +505,7 @@ export default {
this
.
$warning
(
this
.
$t
(
"
test_track.case.relate_test_not_find
"
));
}
});
}
else
if
(
this
.
testCase
.
testId
===
'
other
'
&&
this
.
testCase
.
method
==
'
auto
'
)
{
}
else
if
(
this
.
testCase
.
testId
===
'
other
'
&&
this
.
testCase
.
method
==
=
'
auto
'
)
{
this
.
$warning
(
this
.
$t
(
"
test_track.case.other_relate_test_not_find
"
));
}
},
...
...
@@ -506,9 +516,9 @@ export default {
let
actualResult
=
this
.
addPLabel
(
'
[
'
+
this
.
$t
(
'
test_track.plan_view.actual_result
'
)
+
'
]
'
);
this
.
testCase
.
steps
.
forEach
(
step
=>
{
let
stepPrefix
=
this
.
$t
(
'
test_track.plan_view.step
'
)
+
step
.
num
+
'
:
'
;
desc
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
desc
==
undefined
?
''
:
step
.
desc
));
result
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
result
==
undefined
?
''
:
step
.
result
));
actualResult
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
actualResult
==
undefined
?
''
:
step
.
actualResult
));
desc
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
desc
==
=
undefined
?
''
:
step
.
desc
));
result
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
result
==
=
undefined
?
''
:
step
.
result
));
actualResult
+=
this
.
addPLabel
(
stepPrefix
+
(
step
.
actualResult
==
=
undefined
?
''
:
step
.
actualResult
));
});
this
.
testCase
.
issues
.
content
=
desc
+
this
.
addPLabel
(
''
)
+
result
+
this
.
addPLabel
(
''
)
+
actualResult
+
this
.
addPLabel
(
''
);
...
...
@@ -517,8 +527,7 @@ export default {
if
(
project
.
tapdId
)
{
this
.
hasTapdId
=
true
;
this
.
result
=
this
.
$get
(
"
/issues/tapd/user/
"
+
this
.
testCase
.
caseId
,
response
=>
{
let
data
=
response
.
data
;
this
.
users
=
data
;
this
.
users
=
response
.
data
;
})
}
})
...
...
@@ -531,27 +540,29 @@ export default {
this
.
$post
(
'
/test/plan/edit/status/
'
+
planId
);
},
stepResultChange
()
{
if
(
this
.
testCase
.
method
==
'
manual
'
)
{
if
(
this
.
testCase
.
method
==
=
'
manual
'
)
{
this
.
isFailure
=
this
.
testCase
.
steptResults
.
filter
(
s
=>
{
return
s
.
executeResult
===
'
Failure
'
||
s
.
executeResult
===
'
Blocking
'
;
}).
length
>
0
;
}
},
saveIssues
()
{
if
(
!
this
.
testCase
.
issues
.
title
||
!
this
.
testCase
.
issues
.
content
)
{
this
.
$warning
(
this
.
$t
(
'
test_track.issue.title_description_required
'
));
return
;
}
let
param
=
{};
param
.
title
=
this
.
testCase
.
issues
.
title
;
param
.
content
=
this
.
testCase
.
issues
.
content
;
param
.
testCaseId
=
this
.
testCase
.
caseId
;
param
.
tapdUsers
=
this
.
testCase
.
tapdUsers
;
this
.
result
=
this
.
$post
(
"
/issues/add
"
,
param
,
()
=>
{
this
.
$success
(
this
.
$t
(
'
commons.save_success
'
));
this
.
getIssues
(
param
.
testCaseId
);
});
this
.
issuesSwitch
=
false
;
this
.
testCase
.
issues
.
title
=
""
;
this
.
testCase
.
issues
.
content
=
""
;
...
...
@@ -559,8 +570,7 @@ export default {
},
getIssues
(
caseId
)
{
this
.
result
=
this
.
$get
(
"
/issues/get/
"
+
caseId
,
response
=>
{
let
data
=
response
.
data
;
this
.
issues
=
data
;
this
.
issues
=
response
.
data
;
})
},
closeIssue
(
row
)
{
...
...
frontend/src/business/components/track/review/components/TestCaseReviewEdit.vue
浏览文件 @
3f73ecd5
...
...
@@ -80,7 +80,7 @@
</el-col>
</el-row>
<el-row
v-if=
"operationType == 'edit'"
type=
"flex"
justify=
"left"
style=
"margin-top: 10px;"
>
<el-row
v-if=
"operationType ==
=
'edit'"
type=
"flex"
justify=
"left"
style=
"margin-top: 10px;"
>
<el-col
:span=
"19"
:offset=
"1"
>
<el-form-item
:label=
"$t('test_track.review.review_status')"
:label-width=
"formLabelWidth"
prop=
"status"
>
<test-plan-status-button
:status=
"form.status"
@
statusChange=
"statusChange"
/>
...
...
@@ -110,8 +110,8 @@
<
script
>
import
TestPlanStatusButton
from
"
../../plan/common/TestPlanStatusButton
"
;
import
{
WORKSPACE_ID
}
from
"
../../../../..
/common/js/constants
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
../../../../..
/common/js/utils
"
;
import
{
WORKSPACE_ID
}
from
"
@
/common/js/constants
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
@
/common/js/utils
"
;
export
default
{
name
:
"
TestCaseReviewEdit
"
,
...
...
@@ -169,7 +169,7 @@ export default {
let
param
=
{};
Object
.
assign
(
param
,
this
.
form
);
param
.
name
=
param
.
name
.
trim
();
if
(
param
.
name
==
''
)
{
if
(
param
.
name
==
=
''
)
{
this
.
$warning
(
this
.
$t
(
'
test_track.plan.input_plan_name
'
));
return
;
}
...
...
@@ -183,7 +183,7 @@ export default {
this
.
dbProjectIds
.
forEach
(
dbId
=>
{
if
(
nowIds
.
indexOf
(
dbId
)
===
-
1
&&
sign
)
{
sign
=
false
;
this
.
$confirm
(
'
取消项目关联会同时取消该项目下已关联的测试用例
'
,
'
提示
'
,
{
this
.
$confirm
(
this
.
$t
(
'
test_track.case.cancel_relevance_project
'
),
this
.
$t
(
'
commons.prompt
'
)
,
{
confirmButtonText
:
this
.
$t
(
'
commons.confirm
'
),
cancelButtonText
:
this
.
$t
(
'
commons.cancel
'
),
type
:
'
warning
'
...
...
@@ -240,7 +240,7 @@ export default {
resetForm
()
{
//防止点击修改后,点击新建触发校验
if
(
this
.
$refs
[
'
reviewForm
'
])
{
this
.
$refs
[
'
reviewForm
'
].
validate
((
valid
)
=>
{
this
.
$refs
[
'
reviewForm
'
].
validate
(()
=>
{
this
.
$refs
[
'
reviewForm
'
].
resetFields
();
this
.
form
.
name
=
''
;
this
.
form
.
stage
=
''
;
...
...
xpack
@
cc38137a
比较
06d935cd
...
cc38137a
Subproject commit
06d935cd1d22ab36f09763745c2aff8ad3fb08c1
Subproject commit
cc38137a69a0f20fadece9c0f9f50a9468c4ace9
frontend/src/business/permission.js
浏览文件 @
3f73ecd5
import
router
from
'
./components/common/router/router
'
import
{
TokenKey
}
from
'
@/common/js/constants
'
;
import
{
hasRolePermissions
,
hasRoles
}
from
"
@/common/js/utils
"
;
import
NProgress
from
'
nprogress
'
// progress bar
import
'
nprogress/nprogress.css
'
// progress bar style
const
whiteList
=
[
'
/login
'
];
// no redirect whitelist
NProgress
.
configure
({
showSpinner
:
false
})
// NProgress Configuration
export
const
permission
=
{
inserted
(
el
,
binding
)
{
checkRolePermission
(
el
,
binding
,
'
permission
'
);
...
...
@@ -33,6 +36,8 @@ function checkRolePermission(el, binding, type) {
}
router
.
beforeEach
(
async
(
to
,
from
,
next
)
=>
{
// start progress bar
NProgress
.
start
();
// determine whether the user has logged in
const
user
=
JSON
.
parse
(
localStorage
.
getItem
(
TokenKey
));
...
...
@@ -40,6 +45,7 @@ router.beforeEach(async (to, from, next) => {
if
(
user
)
{
if
(
to
.
path
===
'
/login
'
)
{
next
({
path
:
'
/
'
});
NProgress
.
done
();
// hack: https://github.com/PanJiaChen/vue-element-admin/pull/2939
}
else
{
// const roles = user.roles.filter(r => r.id);
// TODO 设置路由的权限
...
...
@@ -50,14 +56,16 @@ router.beforeEach(async (to, from, next) => {
if
(
whiteList
.
indexOf
(
to
.
path
)
!==
-
1
)
{
// in the free login whitelist, go directly
next
()
next
()
;
}
else
{
// other pages that do not have permission to access are redirected to the login page.
next
(
`/login`
)
next
(
`/login`
);
NProgress
.
done
();
}
}
});
router
.
afterEach
(()
=>
{
// finish progress bar
NProgress
.
done
();
});
frontend/src/i18n/en-US.js
浏览文件 @
3f73ecd5
...
...
@@ -113,6 +113,7 @@ export default {
formatErr
:
'
Format Error
'
,
id
:
'
ID
'
,
cannot_be_null
:
'
not null
'
,
required
:
"
{0} is required
"
,
millisecond
:
'
ms
'
,
please_upload
:
'
Please upload file
'
,
reference_documentation
:
"
Reference documentation
"
,
...
...
@@ -305,7 +306,7 @@ export default {
api_test_report
:
'
Api Test Report
'
,
load_test_report
:
'
Load Test Report
'
,
test_plan_report
:
'
Test Plan Report
'
,
recent
:
'
R
ecent Report
'
,
recent
:
'
My r
ecent Report
'
,
search_by_name
:
'
Search by Name
'
,
test_name
:
'
Test
'
,
test_overview
:
'
Test Overview
'
,
...
...
@@ -343,7 +344,7 @@ export default {
run
:
'
One click operation
'
,
operating
:
'
Operating
'
,
pressure_prediction_chart
:
'
Pressure Prediction Chart
'
,
recent
:
'
R
ecent Tests
'
,
recent
:
'
My r
ecent Tests
'
,
search_by_name
:
'
Search by name
'
,
project_name
:
'
Project
'
,
delete_confirm
:
'
Are you sure want to delete test:
'
,
...
...
@@ -435,6 +436,7 @@ export default {
common_config
:
"
Common Config
"
,
http_config
:
"
HTTP Config
"
,
database_config
:
"
Database Config
"
,
tcp_config
:
"
TCP Config
"
,
},
scenario
:
{
scenario
:
"
Scenario
"
,
...
...
@@ -555,22 +557,38 @@ export default {
input_registry_center
:
"
Please enter the registry center
"
,
input_consumer_service
:
"
Please enter the consumer & service
"
,
check_registry_center
:
"
Can't get interface list, please check the registry center
"
,
}
},
sql
:
{
dataSource
:
"
Data Source
"
,
sql_script
:
"
Sql Script
"
,
timeout
:
"
Timeout(ms)
"
,
database_driver
:
"
Driver
"
,
database_url
:
"
Database URL
"
,
username
:
"
Username
"
,
password
:
"
Password
"
,
pool_max
:
"
Max Number of Configuration
"
,
query_timeout
:
"
Max Wait(ms)
"
,
name_cannot_be_empty
:
"
SQL request name cannot be empty
"
,
dataSource_cannot_be_empty
:
"
SQL request datasource cannot be empty
"
,
result_variable
:
"
Result variable
"
,
variable_names
:
"
Variable names
"
,
},
sql
:
{
dataSource
:
"
Data Source
"
,
sql_script
:
"
Sql Script
"
,
timeout
:
"
Timeout(ms)
"
,
database_driver
:
"
Driver
"
,
database_url
:
"
Database URL
"
,
username
:
"
Username
"
,
password
:
"
Password
"
,
pool_max
:
"
Max Number of Configuration
"
,
query_timeout
:
"
Max Wait(ms)
"
,
name_cannot_be_empty
:
"
SQL request name cannot be empty
"
,
dataSource_cannot_be_empty
:
"
SQL request datasource cannot be empty
"
,
result_variable
:
"
Result variable
"
,
variable_names
:
"
Variable names
"
,
},
tcp
:
{
server
:
"
Server Name or IP
"
,
port
:
"
Port Number
"
,
connect
:
"
Connect(ms)
"
,
response
:
"
Response(ms)
"
,
re_use_connection
:
"
Re-use connection
"
,
no_delay
:
"
Set NoDelay
"
,
close_connection
:
"
Close connection
"
,
so_linger
:
"
SO LINGER
"
,
eol_byte
:
"
End of line byte value
"
,
request
:
"
Text to Send
"
,
username
:
"
Username
"
,
password
:
"
Password
"
,
login
:
"
Login Configuration
"
,
server_cannot_be_empty
:
"
Server name or IP cannot be empty
"
,
},
},
api_import
:
{
label
:
"
Import
"
,
...
...
@@ -633,8 +651,8 @@ export default {
save
:
"
Save
"
,
return
:
"
Return
"
,
length_less_than
:
"
The length less than
"
,
recent_plan
:
"
R
ecent plan
"
,
recent_case
:
"
R
ecent case
"
,
recent_plan
:
"
My r
ecent plan
"
,
recent_case
:
"
My r
ecent case
"
,
recent_review
:
"
Recent review
"
,
pass_rate
:
"
Pass rate
"
,
execution_result
:
"
: Please select the execution result
"
,
...
...
@@ -699,6 +717,7 @@ export default {
status_prepare
:
'
Prepare
'
,
status_pass
:
'
Pass
'
,
status_un_pass
:
'
UnPass
'
,
cancel_relevance_project
:
"
Disassociating the project will also cancel the associated test cases under the project
"
,
import
:
{
import
:
"
Import test case
"
,
case_import
:
"
Import test case
"
,
...
...
@@ -878,7 +897,9 @@ export default {
delete
:
"
Delete
"
,
title_description_required
:
"
Title and description are required
"
,
close_success
:
"
Closed successfully
"
,
preview
:
"
Preview
"
preview
:
"
Preview
"
,
please_choose_current_owner
:
"
Please choose current owner
"
,
tapd_current_owner
:
"
Tapd Current Owner:
"
,
}
},
test_resource_pool
:
{
...
...
frontend/src/i18n/zh-CN.js
浏览文件 @
3f73ecd5
...
...
@@ -116,6 +116,7 @@ export default {
id
:
'
ID
'
,
millisecond
:
'
毫秒
'
,
cannot_be_null
:
'
不能为空
'
,
required
:
"
{0}是必填的
"
,
already_exists
:
'
名称不能重复
'
,
date
:
{
select_date
:
'
选择日期
'
,
...
...
@@ -305,7 +306,7 @@ export default {
api_test_report
:
'
接口测试报告
'
,
load_test_report
:
'
性能测试报告
'
,
test_plan_report
:
'
测试计划报告
'
,
recent
:
'
最近的报告
'
,
recent
:
'
我
最近的报告
'
,
search_by_name
:
'
根据名称搜索
'
,
test_name
:
'
所属测试
'
,
test_overview
:
'
测试概览
'
,
...
...
@@ -342,7 +343,7 @@ export default {
same_project_test
:
'
只能运行同一项目内的测试
'
,
already_exists
:
'
测试名称不能重复
'
,
operating
:
'
操作
'
,
recent
:
'
最近的测试
'
,
recent
:
'
我
最近的测试
'
,
search_by_name
:
'
根据名称搜索
'
,
project_name
:
'
所属项目
'
,
delete_confirm
:
'
确认删除测试:
'
,
...
...
@@ -436,6 +437,7 @@ export default {
common_config
:
"
通用配置
"
,
http_config
:
"
HTTP配置
"
,
database_config
:
"
数据库配置
"
,
tcp_config
:
"
TCP配置
"
,
},
scenario
:
{
scenario
:
"
场景
"
,
...
...
@@ -572,6 +574,22 @@ export default {
dataSource_cannot_be_empty
:
"
SQL请求数据源不能为空
"
,
result_variable
:
"
存储结果
"
,
variable_names
:
"
按列存储
"
,
},
tcp
:
{
server
:
"
服务器名或IP
"
,
port
:
"
端口
"
,
connect
:
"
连接(ms)
"
,
response
:
"
响应(ms)
"
,
re_use_connection
:
"
Re-use connection
"
,
no_delay
:
"
设置无延迟
"
,
close_connection
:
"
关闭连接
"
,
so_linger
:
"
SO LINGER
"
,
eol_byte
:
"
行尾(EOL)字节值
"
,
request
:
"
要发送的文本
"
,
username
:
"
用户名
"
,
password
:
"
密码
"
,
login
:
"
登录设置
"
,
server_cannot_be_empty
:
"
服务器名或IP不能为空
"
,
}
},
api_import
:
{
...
...
@@ -635,8 +653,8 @@ export default {
save
:
"
保 存
"
,
return
:
"
返 回
"
,
length_less_than
:
"
长度必须小于
"
,
recent_plan
:
"
最近的计划
"
,
recent_case
:
"
最近的用例
"
,
recent_plan
:
"
我
最近的计划
"
,
recent_case
:
"
我
最近的用例
"
,
recent_review
:
"
最近的评审
"
,
pass_rate
:
"
通过率
"
,
execution_result
:
"
: 请选择执行结果
"
,
...
...
@@ -701,6 +719,7 @@ export default {
status_prepare
:
'
未开始
'
,
status_pass
:
'
通过
'
,
status_un_pass
:
'
未通过
'
,
cancel_relevance_project
:
"
取消项目关联会同时取消该项目下已关联的测试用例
"
,
import
:
{
import
:
"
导入用例
"
,
case_import
:
"
导入测试用例
"
,
...
...
@@ -880,7 +899,9 @@ export default {
delete
:
"
删除缺陷
"
,
title_description_required
:
"
标题和描述必填
"
,
close_success
:
"
关闭成功
"
,
preview
:
"
预览
"
preview
:
"
预览
"
,
please_choose_current_owner
:
"
请选择处理人
"
,
tapd_current_owner
:
"
Tapd平台处理人:
"
,
}
},
test_resource_pool
:
{
...
...
frontend/src/i18n/zh-TW.js
浏览文件 @
3f73ecd5
...
...
@@ -116,6 +116,7 @@ export default {
id
:
'
ID
'
,
millisecond
:
'
毫秒
'
,
cannot_be_null
:
'
不能為空
'
,
required
:
"
{0}是必填的
"
,
already_exists
:
'
名稱不能重復
'
,
date
:
{
select_date
:
'
選擇日期
'
,
...
...
@@ -305,7 +306,7 @@ export default {
api_test_report
:
'
接口測試報告
'
,
load_test_report
:
'
性能測試報告
'
,
test_plan_report
:
'
測試計劃報告
'
,
recent
:
'
最近的報告
'
,
recent
:
'
我
最近的報告
'
,
search_by_name
:
'
根據名稱搜索
'
,
test_name
:
'
所屬測試
'
,
test_overview
:
'
測試概覽
'
,
...
...
@@ -342,7 +343,7 @@ export default {
same_project_test
:
'
只能運行同壹項目內的測試
'
,
already_exists
:
'
測試名稱不能重復
'
,
operating
:
'
操作
'
,
recent
:
'
最近的測試
'
,
recent
:
'
我
最近的測試
'
,
search_by_name
:
'
根據名稱搜索
'
,
project_name
:
'
所屬項目
'
,
delete_confirm
:
'
確認刪除測試:
'
,
...
...
@@ -436,6 +437,7 @@ export default {
common_config
:
"
通用配置
"
,
http_config
:
"
HTTP配置
"
,
database_config
:
"
數據庫配置
"
,
tcp_config
:
"
TCP配置
"
,
},
scenario
:
{
scenario
:
"
場景
"
,
...
...
@@ -574,6 +576,22 @@ export default {
variable_names
:
"
按列存儲
"
,
}
},
tcp
:
{
server
:
"
服務器名或IP
"
,
port
:
"
端口
"
,
connect
:
"
連接(ms)
"
,
response
:
"
響應(ms)
"
,
re_use_connection
:
"
Re-use connection
"
,
no_delay
:
"
設置無延遲
"
,
close_connection
:
"
關閉連接
"
,
so_linger
:
"
SO LINGER
"
,
eol_byte
:
"
行尾(EOL)字節值
"
,
request
:
"
要發送的文本
"
,
username
:
"
用戶名
"
,
password
:
"
密碼
"
,
login
:
"
登錄設置
"
,
server_cannot_be_empty
:
"
服務器名或IP不能為空
"
,
},
api_import
:
{
label
:
"
導入
"
,
title
:
"
接口測試導入
"
,
...
...
@@ -635,8 +653,8 @@ export default {
save
:
"
保 存
"
,
return
:
"
返 回
"
,
length_less_than
:
"
長度必須小於
"
,
recent_plan
:
"
最近的計劃
"
,
recent_case
:
"
最近的用例
"
,
recent_plan
:
"
我
最近的計劃
"
,
recent_case
:
"
我
最近的用例
"
,
recent_review
:
"
最近的評審
"
,
pass_rate
:
"
通過率
"
,
execution_result
:
"
: 請選擇執行結果
"
,
...
...
@@ -701,6 +719,7 @@ export default {
status_prepare
:
'
未開始
'
,
status_pass
:
'
通過
'
,
status_un_pass
:
'
未通過
'
,
cancel_relevance_project
:
"
取消項目關聯會同時取消該項目下已關聯的測試用例
"
,
import
:
{
import
:
"
導入用例
"
,
case_import
:
"
導入測試用例
"
,
...
...
@@ -880,7 +899,9 @@ export default {
delete
:
"
刪除缺陷
"
,
title_description_required
:
"
標題和描述必填
"
,
close_success
:
"
關閉成功
"
,
preview
:
"
預覽
"
preview
:
"
預覽
"
,
please_choose_current_owner
:
"
請選擇處理人
"
,
tapd_current_owner
:
"
Tapd平台處理人:
"
,
}
},
test_resource_pool
:
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录