Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
6ee4ca09
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,体验更适合开发者的 AI 搜索 >>
提交
6ee4ca09
编写于
10月 20, 2020
作者:
F
fit2-zhao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor(测试跟踪): 导入用例提示消息优化,按照类型进行划分
上级
9d05edc6
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
117 addition
and
51 deletion
+117
-51
backend/src/main/java/io/metersphere/track/service/TestCaseService.java
...in/java/io/metersphere/track/service/TestCaseService.java
+9
-13
backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
...d/src/main/java/io/metersphere/xmind/XmindCaseParser.java
+26
-34
backend/src/main/java/io/metersphere/xmind/parser/XmindParser.java
...rc/main/java/io/metersphere/xmind/parser/XmindParser.java
+1
-1
backend/src/main/java/io/metersphere/xmind/utils/ProcMessage.java
...src/main/java/io/metersphere/xmind/utils/ProcMessage.java
+78
-0
frontend/src/i18n/en-US.js
frontend/src/i18n/en-US.js
+1
-1
frontend/src/i18n/zh-CN.js
frontend/src/i18n/zh-CN.js
+1
-1
frontend/src/i18n/zh-TW.js
frontend/src/i18n/zh-TW.js
+1
-1
未找到文件。
backend/src/main/java/io/metersphere/track/service/TestCaseService.java
浏览文件 @
6ee4ca09
...
...
@@ -263,25 +263,22 @@ public class TestCaseService {
.
map
(
TestCase:
:
getName
)
.
collect
(
Collectors
.
toSet
());
List
<
ExcelErrData
<
TestCaseExcelData
>>
errList
=
null
;
if
(
multipartFile
==
null
)
if
(
multipartFile
==
null
)
{
MSException
.
throwException
(
Translator
.
get
(
"upload_fail"
));
}
if
(
multipartFile
.
getOriginalFilename
().
endsWith
(
".xmind"
))
{
try
{
errList
=
new
ArrayList
<>();
XmindCaseParser
xmindParser
=
new
XmindCaseParser
(
this
,
userId
,
projectId
,
testCaseNames
);
String
processLog
=
xmindParser
.
parse
(
multipartFile
);
if
(!
StringUtils
.
isEmpty
(
processLog
))
{
excelResponse
.
setSuccess
(
false
);
ExcelErrData
excelErrData
=
new
ExcelErrData
(
null
,
1
,
Translator
.
get
(
"upload_fail"
)
+
":"
+
processLog
);
errList
.
add
(
excelErrData
);
excelResponse
.
setErrList
(
errList
);
}
else
if
(
xmindParser
.
getNodePaths
().
isEmpty
()
&&
xmindParser
.
getTestCase
().
isEmpty
())
{
excelResponse
.
setSuccess
(
false
);
errList
=
xmindParser
.
parse
(
multipartFile
);
if
(
xmindParser
.
getNodePaths
().
isEmpty
()
&&
xmindParser
.
getTestCase
().
isEmpty
())
{
if
(
errList
==
null
)
{
errList
=
new
ArrayList
<>();
}
ExcelErrData
excelErrData
=
new
ExcelErrData
(
null
,
1
,
Translator
.
get
(
"upload_fail"
)
+
":"
+
Translator
.
get
(
"upload_content_is_null"
));
errList
.
add
(
excelErrData
);
excelResponse
.
setErrList
(
errList
);
}
else
{
}
if
(
errList
.
isEmpty
())
{
if
(!
xmindParser
.
getNodePaths
().
isEmpty
())
{
testCaseNodeService
.
createNodes
(
xmindParser
.
getNodePaths
(),
projectId
);
}
...
...
@@ -290,7 +287,6 @@ public class TestCaseService {
this
.
saveImportData
(
xmindParser
.
getTestCase
(),
projectId
);
xmindParser
.
clear
();
}
excelResponse
.
setSuccess
(
true
);
}
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
e
.
getMessage
(),
e
);
...
...
backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java
浏览文件 @
6ee4ca09
...
...
@@ -6,12 +6,14 @@ import com.google.common.collect.ImmutableMap;
import
io.metersphere.base.domain.TestCaseWithBLOBs
;
import
io.metersphere.commons.constants.TestCaseConstants
;
import
io.metersphere.commons.utils.BeanUtils
;
import
io.metersphere.excel.domain.ExcelErrData
;
import
io.metersphere.excel.domain.TestCaseExcelData
;
import
io.metersphere.i18n.Translator
;
import
io.metersphere.track.service.TestCaseService
;
import
io.metersphere.xmind.parser.XmindParser
;
import
io.metersphere.xmind.parser.pojo.Attached
;
import
io.metersphere.xmind.parser.pojo.JsonRootBean
;
import
io.metersphere.xmind.utils.ProcMessage
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.web.multipart.MultipartFile
;
...
...
@@ -32,7 +34,7 @@ public class XmindCaseParser {
/**
* 过程校验记录
*/
private
StringBuffer
process
;
private
ProcMessage
process
;
/**
* 已存在用例名称
*/
...
...
@@ -57,7 +59,7 @@ public class XmindCaseParser {
this
.
testCaseNames
=
testCaseNames
;
testCases
=
new
LinkedList
<>();
compartDatas
=
new
ArrayList
<>();
process
=
new
StringBuffer
();
process
=
new
ProcMessage
();
nodePaths
=
new
ArrayList
<>();
}
...
...
@@ -90,15 +92,15 @@ public class XmindCaseParser {
nodePaths
.
forEach
(
nodePath
->
{
String
[]
nodes
=
nodePath
.
split
(
"/"
);
if
(
nodes
.
length
>
TestCaseConstants
.
MAX_NODE_DEPTH
+
1
)
{
process
.
a
ppen
d
(
Translator
.
get
(
"test_case_node_level_tip"
)
+
TestCaseConstants
.
MAX_NODE_DEPTH
+
Translator
.
get
(
"test_case_node_level"
)
+
"; "
);
process
.
a
d
d
(
Translator
.
get
(
"test_case_node_level_tip"
)
+
TestCaseConstants
.
MAX_NODE_DEPTH
+
Translator
.
get
(
"test_case_node_level"
)
,
nodePath
);
}
String
path
=
""
;
for
(
int
i
=
0
;
i
<
nodes
.
length
;
i
++)
{
if
(
i
!=
0
&&
StringUtils
.
equals
(
nodes
[
i
].
trim
(),
""
))
{
process
.
a
ppend
(
Translator
.
get
(
"module"
)
+
":【"
+
path
+
"】"
+
Translator
.
get
(
"module_not_null"
)
+
"; "
);
process
.
a
dd
(
Translator
.
get
(
"module_not_null"
),
path
);
}
else
if
(
nodes
[
i
].
trim
().
length
()
>
30
)
{
process
.
a
ppend
(
nodes
[
i
].
trim
()
+
":"
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"30 ;"
);
process
.
a
dd
(
Translator
.
get
(
"module"
)
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"30"
,
path
+
nodes
[
i
].
trim
()
);
}
else
{
path
+=
nodes
[
i
].
trim
()
+
"/"
;
}
...
...
@@ -109,7 +111,7 @@ public class XmindCaseParser {
/**
* 验证用例的合规性
*/
private
boolean
validate
(
TestCaseWithBLOBs
data
)
{
private
void
validate
(
TestCaseWithBLOBs
data
)
{
String
nodePath
=
data
.
getNodePath
();
if
(!
nodePath
.
startsWith
(
"/"
))
{
nodePath
=
"/"
+
nodePath
;
...
...
@@ -119,37 +121,36 @@ public class XmindCaseParser {
}
data
.
setNodePath
(
nodePath
);
StringBuilder
stringBuilder
=
new
StringBuilder
();
if
(
data
.
getName
().
length
()
>
50
)
{
stringBuilder
.
append
(
data
.
getName
()
+
":"
+
Translator
.
get
(
"test_case"
)
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"50 ;"
);
process
.
add
(
Translator
.
get
(
"test_case"
)
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"50"
,
nodePath
+
data
.
getName
()
);
}
if
(!
StringUtils
.
isEmpty
(
nodePath
))
{
String
[]
nodes
=
nodePath
.
split
(
"/"
);
if
(
nodes
.
length
>
TestCaseConstants
.
MAX_NODE_DEPTH
+
1
)
{
stringBuilder
.
appen
d
(
Translator
.
get
(
"test_case_node_level_tip"
)
+
TestCaseConstants
.
MAX_NODE_DEPTH
+
Translator
.
get
(
"test_case_node_level"
)
+
"; "
);
process
.
ad
d
(
Translator
.
get
(
"test_case_node_level_tip"
)
+
TestCaseConstants
.
MAX_NODE_DEPTH
+
Translator
.
get
(
"test_case_node_level"
)
,
nodePath
);
}
for
(
int
i
=
0
;
i
<
nodes
.
length
;
i
++)
{
if
(
i
!=
0
&&
StringUtils
.
equals
(
nodes
[
i
].
trim
(),
""
))
{
stringBuilder
.
append
(
Translator
.
get
(
"test_case"
)
+
":【"
+
data
.
getName
()
+
"】"
+
Translator
.
get
(
"module_not_null"
)
+
"; "
);
process
.
add
(
Translator
.
get
(
"test_case"
)
+
Translator
.
get
(
"module_not_null"
),
nodePath
+
data
.
getName
()
);
break
;
}
else
if
(
nodes
[
i
].
trim
().
length
()
>
30
)
{
stringBuilder
.
append
(
nodes
[
i
].
trim
()
+
":"
+
Translator
.
get
(
"module"
)
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"30 ;"
);
process
.
add
(
Translator
.
get
(
"module"
)
+
Translator
.
get
(
"test_track.length_less_than"
)
+
"30 "
,
nodes
[
i
].
trim
()
);
break
;
}
}
}
if
(
StringUtils
.
equals
(
data
.
getType
(),
TestCaseConstants
.
Type
.
Functional
.
getValue
())
&&
StringUtils
.
equals
(
data
.
getMethod
(),
TestCaseConstants
.
Method
.
Auto
.
getValue
()))
{
stringBuilder
.
append
(
Translator
.
get
(
"functional_method_tip"
)
+
"; "
);
process
.
add
(
Translator
.
get
(
"functional_method_tip"
),
nodePath
+
data
.
getName
()
);
}
if
(
testCaseNames
.
contains
(
data
.
getName
()))
{
boolean
dbExist
=
testCaseService
.
exist
(
data
);
if
(
dbExist
)
{
stringBuilder
.
append
(
Translator
.
get
(
"test_case_already_exists_excel"
)
+
":"
+
data
.
getName
()
+
"; "
);
process
.
add
(
Translator
.
get
(
"test_case_already_exists_excel"
),
nodePath
+
data
.
getName
()
);
}
}
else
{
testCaseNames
.
add
(
data
.
getName
());
...
...
@@ -157,26 +158,19 @@ public class XmindCaseParser {
// 用例等级和用例性质处理
if
(!
priorityList
.
contains
(
data
.
getPriority
()))
{
stringBuilder
.
append
(
data
.
getName
()
+
":"
+
Translator
.
get
(
"test_case_priority"
)
+
Translator
.
get
(
"incorrect_format"
)
+
"; "
);
process
.
add
(
Translator
.
get
(
"test_case_priority"
)
+
Translator
.
get
(
"incorrect_format"
),
nodePath
+
data
.
getName
()
);
}
if
(
data
.
getType
()
==
null
)
{
stringBuilder
.
append
(
data
.
getName
()
+
":"
+
Translator
.
get
(
"test_case_type"
)
+
Translator
.
get
(
"incorrect_format"
)
+
"; "
);
process
.
add
(
Translator
.
get
(
"test_case_type"
)
+
Translator
.
get
(
"incorrect_format"
),
nodePath
+
data
.
getName
()
);
}
// 重复用例校验
TestCaseExcelData
compartData
=
new
TestCaseExcelData
();
BeanUtils
.
copyBean
(
compartData
,
data
);
if
(
compartDatas
.
contains
(
compartData
))
{
stringBuilder
.
append
(
Translator
.
get
(
"test_case_already_exists_excel"
)
+
":"
+
compartData
.
getName
()
+
"; "
);
}
if
(!
StringUtils
.
isEmpty
(
stringBuilder
.
toString
()))
{
process
.
append
(
stringBuilder
.
toString
());
return
false
;
process
.
add
(
Translator
.
get
(
"test_case_already_exists_excel"
),
nodePath
+
compartData
.
getName
());
}
compartDatas
.
add
(
compartData
);
return
true
;
}
/**
...
...
@@ -267,7 +261,7 @@ public class XmindCaseParser {
String
tc
=
title
.
replace
(
":"
,
":"
);
String
[]
tcArr
=
tc
.
split
(
":"
);
if
(
tcArr
.
length
!=
2
)
{
process
.
a
ppend
(
Translator
.
get
(
"test_case_name"
)
+
"【 "
+
title
+
" 】"
+
Translator
.
get
(
"incorrect_format"
)
);
process
.
a
dd
(
Translator
.
get
(
"test_case_name"
)
+
Translator
.
get
(
"incorrect_format"
),
title
);
return
;
}
// 用例名称
...
...
@@ -301,17 +295,15 @@ public class XmindCaseParser {
});
}
testCase
.
setSteps
(
this
.
getSteps
(
steps
));
testCases
.
add
(
testCase
);
// 校验合规性
if
(
validate
(
testCase
))
{
testCases
.
add
(
testCase
);
}
validate
(
testCase
);
}
/**
* 导入思维导图处理
*/
public
String
parse
(
MultipartFile
multipartFile
)
{
public
List
<
ExcelErrData
<
TestCaseExcelData
>>
parse
(
MultipartFile
multipartFile
)
{
try
{
// 获取思维导图内容
List
<
JsonRootBean
>
roots
=
XmindParser
.
parseObject
(
multipartFile
);
...
...
@@ -321,7 +313,7 @@ public class XmindCaseParser {
for
(
Attached
item
:
root
.
getRootTopic
().
getChildren
().
getAttached
())
{
// 用例
if
(
isAvailable
(
item
.
getTitle
(),
TC_REGEX
))
{
return
replace
(
item
.
getTitle
(),
TC_REGEX
)
+
":"
+
Translator
.
get
(
"test_case_create_module_fail"
);
return
process
.
parse
(
replace
(
item
.
getTitle
(),
TC_REGEX
)
+
":"
+
Translator
.
get
(
"test_case_create_module_fail"
)
);
}
else
{
String
nodePath
=
item
.
getTitle
();
item
.
setPath
(
nodePath
);
...
...
@@ -344,8 +336,8 @@ public class XmindCaseParser {
//检查目录合规性
this
.
validate
();
}
catch
(
Exception
ex
)
{
return
ex
.
getMessage
(
);
return
process
.
parse
(
ex
.
getMessage
()
);
}
return
process
.
toString
();
return
process
.
parse
();
}
}
backend/src/main/java/io/metersphere/xmind/parser/XmindParser.java
浏览文件 @
6ee4ca09
...
...
@@ -73,7 +73,7 @@ public class XmindParser {
JsonRootBean
jsonRootBean
=
JSON
.
parseObject
(
content
,
JsonRootBean
.
class
);
jsonRootBeans
.
add
(
jsonRootBean
);
}
if
(
caseCount
>
5
00
)
{
if
(
caseCount
>
8
00
)
{
MSException
.
throwException
(
Translator
.
get
(
"import_xmind_count_error"
));
}
}
...
...
backend/src/main/java/io/metersphere/xmind/utils/ProcMessage.java
0 → 100644
浏览文件 @
6ee4ca09
package
io.metersphere.xmind.utils
;
import
com.sun.deploy.util.StringUtils
;
import
io.metersphere.excel.domain.ExcelErrData
;
import
io.metersphere.excel.domain.TestCaseExcelData
;
import
io.metersphere.i18n.Translator
;
import
lombok.Getter
;
import
lombok.Setter
;
import
java.io.Serializable
;
import
java.util.ArrayList
;
import
java.util.LinkedHashMap
;
import
java.util.List
;
import
java.util.Map
;
@Getter
@Setter
public
class
ProcMessage
implements
Serializable
{
private
Map
<
String
,
StringBuilder
>
process
;
public
ProcMessage
()
{
process
=
new
LinkedHashMap
<>();
}
public
void
add
(
String
type
,
String
msContent
)
{
if
(
process
.
containsKey
(
type
))
{
process
.
get
(
type
).
append
(
msContent
+
";"
);
}
else
{
process
.
put
(
type
,
new
StringBuilder
(
msContent
+
";"
));
}
}
public
List
<
ExcelErrData
<
TestCaseExcelData
>>
parse
(
String
content
)
{
List
<
ExcelErrData
<
TestCaseExcelData
>>
errList
=
new
ArrayList
<>();
ExcelErrData
excelErrData
=
new
ExcelErrData
(
null
,
1
,
content
);
errList
.
add
(
excelErrData
);
return
errList
;
}
public
List
<
ExcelErrData
<
TestCaseExcelData
>>
parse
()
{
List
<
ExcelErrData
<
TestCaseExcelData
>>
errList
=
new
ArrayList
<>();
List
<
String
>
result
=
new
ArrayList
<>();
process
.
entrySet
().
parallelStream
().
reduce
(
result
,
(
first
,
second
)
->
{
first
.
add
(
second
.
getKey
()
+
":"
+
second
.
getValue
());
return
first
;
},
(
first
,
second
)
->
{
if
(
first
==
second
)
{
return
first
;
}
first
.
addAll
(
second
);
return
first
;
});
for
(
int
i
=
0
;
i
<
result
.
size
();
i
++)
{
ExcelErrData
excelErrData
=
new
ExcelErrData
(
null
,
i
,
result
.
get
(
i
));
errList
.
add
(
excelErrData
);
}
return
errList
;
}
@Override
public
String
toString
()
{
List
<
String
>
result
=
new
ArrayList
<>();
process
.
entrySet
().
parallelStream
().
reduce
(
result
,
(
first
,
second
)
->
{
first
.
add
(
second
.
getKey
()
+
":"
+
second
.
getValue
());
return
first
;
},
(
first
,
second
)
->
{
if
(
first
==
second
)
{
return
first
;
}
first
.
addAll
(
second
);
return
first
;
});
return
StringUtils
.
join
(
result
,
"\n"
);
}
}
frontend/src/i18n/en-US.js
浏览文件 @
6ee4ca09
...
...
@@ -748,7 +748,7 @@ export default {
click_upload
:
"
Upload
"
,
upload_limit
:
"
Only XLS/XLSX/XMIND files can be uploaded, and no more than 20M
"
,
upload_xmind_format
:
"
Upload files can only be .xmind format
"
,
upload_xmind
:
"
Only xmind files can be uploaded, and no more than
5
00
"
,
upload_xmind
:
"
Only xmind files can be uploaded, and no more than
8
00
"
,
upload_limit_count
:
"
Only one file can be uploaded at a time
"
,
upload_limit_format
:
"
Upload files can only be XLS, XLSX format!
"
,
upload_limit_size
:
"
Upload file size cannot exceed 20MB!
"
,
...
...
frontend/src/i18n/zh-CN.js
浏览文件 @
6ee4ca09
...
...
@@ -751,7 +751,7 @@ export default {
download_template
:
"
下载模版
"
,
click_upload
:
"
点击上传
"
,
upload_limit
:
"
只能上传xls/xlsx文件,且不超过20M
"
,
upload_xmind
:
"
支持文件类型:.xmind;一次至多导入
5
00 条用例
"
,
upload_xmind
:
"
支持文件类型:.xmind;一次至多导入
8
00 条用例
"
,
upload_xmind_format
:
"
上传文件只能是 .xmind 格式
"
,
upload_limit_other_size
:
"
上传文件大小不能超过
"
,
upload_limit_count
:
"
一次只能上传一个文件
"
,
...
...
frontend/src/i18n/zh-TW.js
浏览文件 @
6ee4ca09
...
...
@@ -751,7 +751,7 @@ export default {
download_template
:
"
下載模版
"
,
click_upload
:
"
點擊上傳
"
,
upload_limit
:
"
只能上傳xls/xlsx文件,且不超過20M
"
,
upload_xmind
:
"
支持文件類型:.xmind;壹次至多導入
5
00 條用例
"
,
upload_xmind
:
"
支持文件類型:.xmind;壹次至多導入
8
00 條用例
"
,
upload_xmind_format
:
"
上傳文件只能是 .xmind 格式
"
,
upload_limit_other_size
:
"
上傳文件大小不能超過
"
,
upload_limit_count
:
"
壹次只能上傳壹個文件
"
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录