feat: 功能用例导入支持选择版本
This commit is contained in:
parent
85fe565b74
commit
c01fb7b575
|
@ -1,550 +0,0 @@
|
||||||
package io.metersphere.excel.listener;
|
|
||||||
|
|
||||||
import com.alibaba.excel.context.AnalysisContext;
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import io.metersphere.base.domain.TestCase;
|
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
|
||||||
import io.metersphere.commons.utils.*;
|
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
|
||||||
import io.metersphere.excel.utils.ExcelValidateHelper;
|
|
||||||
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.track.service.TestCaseService;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TestCaseDataIgnoreErrorListener extends EasyExcelListener<TestCaseExcelData> {
|
|
||||||
|
|
||||||
private TestCaseService testCaseService;
|
|
||||||
|
|
||||||
private String projectId;
|
|
||||||
|
|
||||||
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
|
||||||
|
|
||||||
protected boolean isUpdated = false; //判断是否更新过用例,将会传给前端
|
|
||||||
|
|
||||||
public boolean isUseCustomId;
|
|
||||||
|
|
||||||
public String importType;
|
|
||||||
|
|
||||||
Set<String> testCaseNames;
|
|
||||||
|
|
||||||
Set<String> customIds;
|
|
||||||
|
|
||||||
Set<String> savedCustomIds;
|
|
||||||
|
|
||||||
Set<String> userIds;
|
|
||||||
|
|
||||||
private List<String> names = new LinkedList<>();
|
|
||||||
private List<String> ids = new LinkedList<>();
|
|
||||||
|
|
||||||
public List<String> getNames() {
|
|
||||||
return this.names;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getIds() {
|
|
||||||
return this.ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNames(List<String> names) {
|
|
||||||
this.names = names;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIds(List<String> ids) {
|
|
||||||
this.ids = ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUpdated() {
|
|
||||||
return isUpdated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestCaseDataIgnoreErrorListener(Class clazz, String projectId, Set<String> testCaseNames, Set<String> savedCustomIds, Set<String> userIds,boolean isUseCustomId,String importType) {
|
|
||||||
this.clazz = clazz;
|
|
||||||
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
|
||||||
this.projectId = projectId;
|
|
||||||
this.testCaseNames = testCaseNames;
|
|
||||||
this.userIds = userIds;
|
|
||||||
this.isUseCustomId = isUseCustomId;
|
|
||||||
this.importType = importType;
|
|
||||||
this.customIds = new HashSet<>();
|
|
||||||
this.savedCustomIds = savedCustomIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String validate(TestCaseExcelData data, String errMsg) {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
|
||||||
|
|
||||||
if(isUseCustomId || StringUtils.equals(this.importType,FunctionCaseImportEnum.Update.name())){
|
|
||||||
if(data.getCustomNum() == null){
|
|
||||||
stringBuilder.append(Translator.get("id_required")+";");
|
|
||||||
}else {
|
|
||||||
String customId = data.getCustomNum().toString();
|
|
||||||
if(StringUtils.isEmpty(customId)){
|
|
||||||
stringBuilder.append(Translator.get("id_required")+";");
|
|
||||||
}else if(customIds.contains(customId)) {
|
|
||||||
stringBuilder.append(Translator.get("id_repeat_in_table") + ";");
|
|
||||||
}else if(StringUtils.equals(FunctionCaseImportEnum.Create.name(),importType) && savedCustomIds.contains(customId)){
|
|
||||||
stringBuilder.append(Translator.get("custom_num_is_exist") + ";");
|
|
||||||
}else if(StringUtils.equals(FunctionCaseImportEnum.Update.name(),importType) && !savedCustomIds.contains(customId)){
|
|
||||||
stringBuilder.append(Translator.get("custom_num_is_not_exist") + ";");
|
|
||||||
}else {
|
|
||||||
customIds.add(customId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
//校验”所属模块"
|
|
||||||
if (nodePath != null) {
|
|
||||||
String[] nodes = nodePath.split("/");
|
|
||||||
//校验模块深度
|
|
||||||
if (nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
|
|
||||||
stringBuilder.append(Translator.get("test_case_node_level_tip") +
|
|
||||||
TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level") + "; ");
|
|
||||||
}
|
|
||||||
//模块名不能为空
|
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
|
||||||
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
|
|
||||||
stringBuilder.append(Translator.get("module_not_null") + "; ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//增加字数校验,每一层不能超过100字
|
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
|
||||||
String nodeStr = nodes[i];
|
|
||||||
if (StringUtils.isNotEmpty(nodeStr)) {
|
|
||||||
if (nodeStr.trim().length() > 100) {
|
|
||||||
stringBuilder.append(Translator.get("module") + Translator.get("test_track.length_less_than") + "100:" + nodeStr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//校验维护人
|
|
||||||
if (StringUtils.isBlank(data.getMaintainer())) {
|
|
||||||
data.setMaintainer(SessionUtils.getUserId());
|
|
||||||
} else {
|
|
||||||
if (!userIds.contains(data.getMaintainer())) {
|
|
||||||
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
校验Excel中是否有ID
|
|
||||||
有的话校验ID是否已在当前项目中存在,存在则更新用例,
|
|
||||||
不存在则继续校验看是否重复,不重复则新建用例。
|
|
||||||
*/
|
|
||||||
if (null != data.getCustomNum()) { //当前读取的数据有ID
|
|
||||||
if(StringUtils.equals(this.importType,FunctionCaseImportEnum.Update.name())){
|
|
||||||
String checkResult = null;
|
|
||||||
if(isUseCustomId){
|
|
||||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
|
||||||
}else {
|
|
||||||
checkResult = testCaseService.checkIdExist(Integer.parseInt(data.getCustomNum()), projectId);
|
|
||||||
}
|
|
||||||
if (null != checkResult) { //该ID在当前项目中存在
|
|
||||||
//如果前面所经过的校验都没报错
|
|
||||||
if (StringUtils.isEmpty(stringBuilder)) {
|
|
||||||
updateList.add(data); //将当前数据存入更新列表
|
|
||||||
stringBuilder.append("update_testcase"); //该信息用于在invoke方法中判断是否该更新用例
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
该ID在当前数据库中不存在,应当继续校验用例是否重复,
|
|
||||||
在下面的校验过程中,num的值会被用于判断是否重复,所以应当先设置为null
|
|
||||||
*/
|
|
||||||
if(!StringUtils.equals(this.importType,FunctionCaseImportEnum.Update.name())){
|
|
||||||
data.setNum(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
校验用例
|
|
||||||
*/
|
|
||||||
if (testCaseNames.contains(data.getName())) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setProjectId(projectId);
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
testCase.setType("functional");
|
|
||||||
|
|
||||||
boolean dbExist = testCaseService.exist(testCase);
|
|
||||||
boolean excelExist = false;
|
|
||||||
|
|
||||||
if (dbExist) {
|
|
||||||
// db exist
|
|
||||||
stringBuilder.append(Translator.get("test_case_already_exists") + ":" + data.getName() + "; ");
|
|
||||||
} else {
|
|
||||||
// @Data 重写了 equals 和 hashCode 方法
|
|
||||||
excelExist = excelDataList.contains(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excelExist) {
|
|
||||||
// excel exist
|
|
||||||
stringBuilder.append(Translator.get("test_case_already_exists_excel") + ":" + data.getName() + "; ");
|
|
||||||
} else {
|
|
||||||
if(!dbExist){
|
|
||||||
excelDataList.add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
testCaseNames.add(data.getName());
|
|
||||||
excelDataList.add(data);
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveData() {
|
|
||||||
if (!(list.size() == 0)) {
|
|
||||||
Collections.reverse(list); //因为saveImportData里面是先分配最大的ID,这个ID应该先发给list中最后的数据,所以要reverse
|
|
||||||
List<TestCaseWithBLOBs> result = list.stream()
|
|
||||||
.map(item -> this.convert2TestCase(item))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
testCaseService.saveImportData(result, projectId);
|
|
||||||
this.setNames(result.stream().map(TestCase::getName).collect(Collectors.toList()));
|
|
||||||
this.setIds(result.stream().map(TestCase::getId).collect(Collectors.toList()));
|
|
||||||
this.isUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(updateList.size() == 0)) {
|
|
||||||
List<TestCaseWithBLOBs> result2 = updateList.stream()
|
|
||||||
.map(item -> this.convert2TestCaseForUpdate(item))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if(this.isUseCustomId){
|
|
||||||
testCaseService.updateImportDataCustomId(result2, projectId);
|
|
||||||
}else {
|
|
||||||
testCaseService.updateImportDataCarryId(result2, projectId);
|
|
||||||
}
|
|
||||||
this.setNames(result2.stream().map(TestCase::getName).collect(Collectors.toList()));
|
|
||||||
this.setIds(result2.stream().map(TestCase::getId).collect(Collectors.toList()));
|
|
||||||
this.isUpdated = true;
|
|
||||||
updateList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private TestCaseWithBLOBs convert2TestCase(TestCaseExcelData data) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setId(UUID.randomUUID().toString());
|
|
||||||
testCase.setProjectId(this.projectId);
|
|
||||||
testCase.setCreateTime(System.currentTimeMillis());
|
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
|
||||||
if(this.isUseCustomId){
|
|
||||||
testCase.setCustomNum(data.getCustomNum().toString());
|
|
||||||
}
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
|
|
||||||
if (!nodePath.startsWith("/")) {
|
|
||||||
nodePath = "/" + nodePath;
|
|
||||||
}
|
|
||||||
if (nodePath.endsWith("/")) {
|
|
||||||
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
|
||||||
}
|
|
||||||
testCase.setNodePath(nodePath);
|
|
||||||
|
|
||||||
JSONArray customArr = new JSONArray();
|
|
||||||
String caseStatusValue = "";
|
|
||||||
if(StringUtils.equalsAny(data.getStatus(),"Underway","underway","进行中","進行中")){
|
|
||||||
caseStatusValue = "Underway";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Prepare","prepare","未开始","未開始")){
|
|
||||||
caseStatusValue = "Prepare";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Completed","completed","已完成","已完成")){
|
|
||||||
caseStatusValue = "Completed";
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(caseStatusValue)){
|
|
||||||
JSONObject statusObj = new JSONObject();
|
|
||||||
statusObj.put("id",UUID.randomUUID().toString());
|
|
||||||
statusObj.put("name","用例状态");
|
|
||||||
statusObj.put("value",caseStatusValue);
|
|
||||||
statusObj.put("customData",null);
|
|
||||||
customArr.add(statusObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(StringUtils.isNotEmpty(data.getMaintainer())){
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
obj.put("id",UUID.randomUUID().toString());
|
|
||||||
obj.put("name","责任人");
|
|
||||||
obj.put("value",data.getMaintainer());
|
|
||||||
obj.put("customData",null);
|
|
||||||
customArr.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(customArr.size()>0){
|
|
||||||
testCase.setCustomFields(customArr.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//将标签设置为前端可解析的格式
|
|
||||||
String modifiedTags = modifyTagPattern(data);
|
|
||||||
testCase.setTags(modifiedTags);
|
|
||||||
testCase.setType("functional");
|
|
||||||
if (StringUtils.isNotBlank(data.getStepModel())
|
|
||||||
&& StringUtils.equals(data.getStepModel(), TestCaseConstants.StepModel.TEXT.name())) {
|
|
||||||
testCase.setStepDescription(data.getStepDesc());
|
|
||||||
testCase.setExpectedResult(data.getStepResult());
|
|
||||||
} else {
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
}
|
|
||||||
return testCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Excel中的数据对象转换为用于更新操作的用例数据对象,
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setProjectId(this.projectId);
|
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
|
||||||
|
|
||||||
//调整nodePath格式
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
if (!nodePath.startsWith("/")) {
|
|
||||||
nodePath = "/" + nodePath;
|
|
||||||
}
|
|
||||||
if (nodePath.endsWith("/")) {
|
|
||||||
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
|
||||||
}
|
|
||||||
testCase.setNodePath(nodePath);
|
|
||||||
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
|
|
||||||
JSONArray customArr = new JSONArray();
|
|
||||||
String caseStatusValue = "";
|
|
||||||
if(StringUtils.equalsAny(data.getStatus(),"Underway","underway","进行中","進行中")){
|
|
||||||
caseStatusValue = "Underway";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Prepare","prepare","未开始","未開始")){
|
|
||||||
caseStatusValue = "Prepare";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Completed","completed","已完成","已完成")){
|
|
||||||
caseStatusValue = "Completed";
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(caseStatusValue)){
|
|
||||||
JSONObject statusObj = new JSONObject();
|
|
||||||
statusObj.put("id",UUID.randomUUID().toString());
|
|
||||||
statusObj.put("name","用例状态");
|
|
||||||
statusObj.put("value",caseStatusValue);
|
|
||||||
statusObj.put("customData",null);
|
|
||||||
customArr.add(statusObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(StringUtils.isNotEmpty(data.getMaintainer())){
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
obj.put("id",UUID.randomUUID().toString());
|
|
||||||
obj.put("name","责任人");
|
|
||||||
obj.put("value",data.getMaintainer());
|
|
||||||
obj.put("customData",null);
|
|
||||||
customArr.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(customArr.size()>0){
|
|
||||||
testCase.setCustomFields(customArr.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//将标签设置为前端可解析的格式
|
|
||||||
String modifiedTags = modifyTagPattern(data);
|
|
||||||
testCase.setTags(modifiedTags);
|
|
||||||
|
|
||||||
if(!isUseCustomId){
|
|
||||||
testCase.setNum(Integer.parseInt(data.getCustomNum()));
|
|
||||||
testCase.setCustomNum(null);
|
|
||||||
}
|
|
||||||
return testCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调整tags格式,便于前端进行解析。
|
|
||||||
* 例如对于:标签1,标签2。将调整为:["标签1","标签2"]。
|
|
||||||
*/
|
|
||||||
public String modifyTagPattern(TestCaseExcelData data) {
|
|
||||||
String tags = data.getTags();
|
|
||||||
try {
|
|
||||||
if (StringUtils.isNotBlank(tags)) {
|
|
||||||
JSONArray.parse(tags);
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
return "[]";
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (tags != null) {
|
|
||||||
Stream<String> stringStream = Arrays.stream(tags.split("[,;,;]")); //当标签值以中英文的逗号和分号分隔时才能正确解析
|
|
||||||
List<String> tagList = stringStream.map(tag -> tag = "\"" + tag + "\"")
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
String modifiedTags = StringUtils.join(tagList, ",");
|
|
||||||
modifiedTags = "[" + modifiedTags + "]";
|
|
||||||
return modifiedTags;
|
|
||||||
} else {
|
|
||||||
return "[]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getSteps(TestCaseExcelData data) {
|
|
||||||
JSONArray jsonArray = new JSONArray();
|
|
||||||
|
|
||||||
List<String> stepDescList = new ArrayList<>();
|
|
||||||
List<String> stepResList = new ArrayList<>();
|
|
||||||
ListUtils<String> listUtils = new ListUtils<String>();
|
|
||||||
if (data.getStepDesc() != null) {
|
|
||||||
String[] stepDesc = data.getStepDesc().split("\r\n|\n");
|
|
||||||
StringBuffer stepBuffer = new StringBuffer();
|
|
||||||
int lastStepIndex = 1;
|
|
||||||
for (String row : stepDesc) {
|
|
||||||
RowInfo rowInfo = this.parseIndexInRow(row);
|
|
||||||
int rowIndex = rowInfo.index;
|
|
||||||
String rowMessage = rowInfo.rowInfo;
|
|
||||||
if(rowIndex > -1){
|
|
||||||
listUtils.set(stepDescList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
stepBuffer = new StringBuffer();
|
|
||||||
lastStepIndex = rowIndex;
|
|
||||||
stepBuffer.append(rowMessage);
|
|
||||||
}else {
|
|
||||||
stepBuffer.append(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(stepBuffer.toString())){
|
|
||||||
listUtils.set(stepDescList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stepDescList.add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getStepResult() != null) {
|
|
||||||
String [] stepRes = data.getStepResult().split("\r\n|\n");
|
|
||||||
StringBuffer stepBuffer = new StringBuffer();
|
|
||||||
int lastStepIndex = 1;
|
|
||||||
for (String row : stepRes) {
|
|
||||||
RowInfo rowInfo = this.parseIndexInRow(row);
|
|
||||||
int rowIndex = rowInfo.index;
|
|
||||||
String rowMessage = rowInfo.rowInfo;
|
|
||||||
if(rowIndex > -1){
|
|
||||||
listUtils.set(stepResList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
stepBuffer = new StringBuffer();
|
|
||||||
lastStepIndex = rowIndex;
|
|
||||||
stepBuffer.append(rowMessage);
|
|
||||||
}else {
|
|
||||||
stepBuffer.append(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(stepBuffer.toString())){
|
|
||||||
listUtils.set(stepResList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stepResList.add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = stepDescList.size() > stepResList.size() ? stepDescList.size() : stepResList.size();
|
|
||||||
|
|
||||||
for (int i = 0; i < index; i++) {
|
|
||||||
|
|
||||||
// 保持插入顺序,判断用例是否有相同的steps
|
|
||||||
JSONObject step = new JSONObject(true);
|
|
||||||
step.put("num", i + 1);
|
|
||||||
if (i < stepDescList.size()) {
|
|
||||||
step.put("desc", stepDescList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < stepResList.size()) {
|
|
||||||
step.put("result", stepResList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonArray.add(step);
|
|
||||||
}
|
|
||||||
return jsonArray.toJSONString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private RowInfo parseIndexInRow(String row) {
|
|
||||||
RowInfo rowInfo = new RowInfo();
|
|
||||||
String parseString = row;
|
|
||||||
int index = -1;
|
|
||||||
String rowMessage = row;
|
|
||||||
String [] indexSplitCharArr = new String[]{")",")","]","】",".",",",",","。"};
|
|
||||||
if(StringUtils.startsWithAny(row,"(","(","[","【")){
|
|
||||||
parseString = parseString.substring(1);
|
|
||||||
}
|
|
||||||
for (String splitChar : indexSplitCharArr) {
|
|
||||||
if(StringUtils.contains(parseString,splitChar)){
|
|
||||||
String[] rowSplit = StringUtils.split(parseString,splitChar);
|
|
||||||
if(rowSplit.length > 0){
|
|
||||||
String indexString = rowSplit[0];
|
|
||||||
if(StringUtils.isNumeric(indexString)){
|
|
||||||
try {
|
|
||||||
index = Integer.parseInt(indexString);
|
|
||||||
rowMessage = StringUtils.substring(parseString,indexString.length()+splitChar.length());
|
|
||||||
}catch (Exception e){}
|
|
||||||
|
|
||||||
if(index > -1){
|
|
||||||
break;
|
|
||||||
}else {
|
|
||||||
rowMessage = row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rowInfo.index = index;
|
|
||||||
if(rowMessage == null){
|
|
||||||
rowMessage = "";
|
|
||||||
}
|
|
||||||
rowInfo.rowInfo = rowMessage;
|
|
||||||
return rowInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(TestCaseExcelData testCaseExcelData, AnalysisContext analysisContext) {
|
|
||||||
String errMsg;
|
|
||||||
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
|
||||||
String updateMsg = "update_testcase";
|
|
||||||
try {
|
|
||||||
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
|
||||||
errMsg = ExcelValidateHelper.validateEntity(testCaseExcelData);
|
|
||||||
//自定义校验规则
|
|
||||||
errMsg = validate(testCaseExcelData, errMsg);
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
errMsg = Translator.get("parse_data_error");
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringUtils.isEmpty(errMsg)) {
|
|
||||||
|
|
||||||
//如果errMsg只有"update testcase",说明用例待更新
|
|
||||||
if (!errMsg.equals(updateMsg)) {
|
|
||||||
ExcelErrData excelErrData = new ExcelErrData(testCaseExcelData, rowIndex,
|
|
||||||
Translator.get("number") + " " + rowIndex + " " + Translator.get("row") + Translator.get("error")
|
|
||||||
+ ":" + errMsg);
|
|
||||||
|
|
||||||
errList.add(excelErrData);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.add(testCaseExcelData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errList.isEmpty() && list.size() > BATCH_COUNT) {
|
|
||||||
saveData();
|
|
||||||
list.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RowInfo{
|
|
||||||
public int index;
|
|
||||||
public String rowInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,588 +0,0 @@
|
||||||
package io.metersphere.excel.listener;
|
|
||||||
|
|
||||||
import com.alibaba.excel.context.AnalysisContext;
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import io.metersphere.base.domain.TestCase;
|
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
|
||||||
import io.metersphere.commons.utils.*;
|
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
|
||||||
import io.metersphere.excel.utils.ExcelValidateHelper;
|
|
||||||
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
|
||||||
import io.metersphere.i18n.Translator;
|
|
||||||
import io.metersphere.track.service.TestCaseService;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
|
|
||||||
|
|
||||||
private TestCaseService testCaseService;
|
|
||||||
|
|
||||||
private String projectId;
|
|
||||||
|
|
||||||
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
|
||||||
|
|
||||||
protected boolean isUpdated = false; //判断是否更新过用例,将会传给前端
|
|
||||||
|
|
||||||
public boolean isUseCustomId;
|
|
||||||
|
|
||||||
public String importType;
|
|
||||||
|
|
||||||
Set<String> testCaseNames;
|
|
||||||
|
|
||||||
Set<String> customIds;
|
|
||||||
|
|
||||||
Set<String> savedCustomIds;
|
|
||||||
|
|
||||||
Set<String> userIds;
|
|
||||||
|
|
||||||
private List<String> names = new LinkedList<>();
|
|
||||||
private List<String> ids = new LinkedList<>();
|
|
||||||
|
|
||||||
public boolean isUpdated() {
|
|
||||||
return isUpdated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestCaseDataListener(Class clazz, String projectId, Set<String> testCaseNames,Set<String> savedCustomIds, Set<String> userIds,boolean isUseCustomId,String importType) {
|
|
||||||
this.clazz = clazz;
|
|
||||||
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
|
||||||
this.projectId = projectId;
|
|
||||||
this.testCaseNames = testCaseNames;
|
|
||||||
this.userIds = userIds;
|
|
||||||
this.isUseCustomId = isUseCustomId;
|
|
||||||
this.importType = importType;
|
|
||||||
customIds = new HashSet<>();
|
|
||||||
this.savedCustomIds = savedCustomIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String validate(TestCaseExcelData data, String errMsg) {
|
|
||||||
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
|
||||||
if(isUseCustomId || StringUtils.equals(this.importType,FunctionCaseImportEnum.Update.name())){
|
|
||||||
if(data.getCustomNum() == null){
|
|
||||||
stringBuilder.append(Translator.get("id_required")+";");
|
|
||||||
}else {
|
|
||||||
String customId = data.getCustomNum().toString();
|
|
||||||
if(StringUtils.isEmpty(customId)){
|
|
||||||
stringBuilder.append(Translator.get("id_required")+";");
|
|
||||||
}else if(customIds.contains(customId)) {
|
|
||||||
stringBuilder.append(Translator.get("id_repeat_in_table") + ";");
|
|
||||||
}else if(StringUtils.equals(FunctionCaseImportEnum.Create.name(),importType) && savedCustomIds.contains(customId)){
|
|
||||||
stringBuilder.append(Translator.get("custom_num_is_exist") + ";");
|
|
||||||
}else if(StringUtils.equals(FunctionCaseImportEnum.Update.name(),importType) && !savedCustomIds.contains(customId)){
|
|
||||||
stringBuilder.append(Translator.get("custom_num_is_not_exist") + ";");
|
|
||||||
}else {
|
|
||||||
customIds.add(customId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
//校验”所属模块"
|
|
||||||
if (nodePath != null) {
|
|
||||||
String[] nodes = nodePath.split("/");
|
|
||||||
//校验模块深度
|
|
||||||
if (nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
|
|
||||||
stringBuilder.append(Translator.get("test_case_node_level_tip") +
|
|
||||||
TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level") + "; ");
|
|
||||||
}
|
|
||||||
//模块名不能为空
|
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
|
||||||
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
|
|
||||||
stringBuilder.append(Translator.get("module_not_null") + "; ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//增加字数校验,每一层不能超过100字
|
|
||||||
for (int i = 0; i < nodes.length; i++) {
|
|
||||||
String nodeStr = nodes[i];
|
|
||||||
if (StringUtils.isNotEmpty(nodeStr)) {
|
|
||||||
if (nodeStr.trim().length() > 100) {
|
|
||||||
stringBuilder.append(Translator.get("module") + Translator.get("test_track.length_less_than") + "100:" + nodeStr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//校验维护人
|
|
||||||
if (StringUtils.isBlank(data.getMaintainer())) {
|
|
||||||
data.setMaintainer(SessionUtils.getUserId());
|
|
||||||
} else {
|
|
||||||
if (!userIds.contains(data.getMaintainer())) {
|
|
||||||
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
校验Excel中是否有ID
|
|
||||||
有的话校验ID是否已在当前项目中存在,存在则更新用例,
|
|
||||||
不存在则继续校验看是否重复,不重复则新建用例。
|
|
||||||
*/
|
|
||||||
if (null != data.getCustomNum()) { //当前读取的数据有ID
|
|
||||||
|
|
||||||
if(StringUtils.equals(this.importType,FunctionCaseImportEnum.Update.name())){
|
|
||||||
String checkResult = null;
|
|
||||||
if(isUseCustomId){
|
|
||||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
|
||||||
}else {
|
|
||||||
int customNumId = -1;
|
|
||||||
try{
|
|
||||||
customNumId = Integer.parseInt(data.getCustomNum());
|
|
||||||
}catch (Exception e){
|
|
||||||
}
|
|
||||||
if(customNumId < 0){
|
|
||||||
stringBuilder.append(Translator.get("id_not_rightful") + "["+data.getCustomNum()+"]; ");
|
|
||||||
}else {
|
|
||||||
checkResult = testCaseService.checkIdExist(customNumId, projectId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (null != checkResult) { //该ID在当前项目中存在
|
|
||||||
//如果前面所经过的校验都没报错
|
|
||||||
if (StringUtils.isEmpty(stringBuilder)) {
|
|
||||||
data.setId(checkResult);
|
|
||||||
updateList.add(data); //将当前数据存入更新列表
|
|
||||||
stringBuilder.append("update_testcase"); //该信息用于在invoke方法中判断是否该更新用例
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
该ID在当前数据库中不存在,应当继续校验用例是否重复,
|
|
||||||
在下面的校验过程中,num的值会被用于判断是否重复,所以应当先设置为null
|
|
||||||
*/
|
|
||||||
data.setNum(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
校验用例
|
|
||||||
*/
|
|
||||||
if (testCaseNames.contains(data.getName())) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setProjectId(projectId);
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
testCase.setType("functional");
|
|
||||||
|
|
||||||
boolean dbExist = testCaseService.exist(testCase);
|
|
||||||
boolean excelExist = false;
|
|
||||||
|
|
||||||
if (dbExist) {
|
|
||||||
// db exist
|
|
||||||
stringBuilder.append(Translator.get("test_case_already_exists") + ":" + data.getName() + "; ");
|
|
||||||
} else {
|
|
||||||
// @Data 重写了 equals 和 hashCode 方法
|
|
||||||
excelExist = excelDataList.contains(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excelExist) {
|
|
||||||
// excel exist
|
|
||||||
stringBuilder.append(Translator.get("test_case_already_exists_excel") + ":" + data.getName() + "; ");
|
|
||||||
} else {
|
|
||||||
if(!dbExist){
|
|
||||||
excelDataList.add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
testCaseNames.add(data.getName());
|
|
||||||
excelDataList.add(data);
|
|
||||||
}
|
|
||||||
return stringBuilder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getNames() {
|
|
||||||
return this.names;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getIds() {
|
|
||||||
return this.ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNames(List<String> names) {
|
|
||||||
this.names = names;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIds(List<String> ids) {
|
|
||||||
this.ids = ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveData() {
|
|
||||||
|
|
||||||
//excel中用例都有错误时就返回,只要有用例可用于更新或者插入就不返回
|
|
||||||
if (!errList.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(list.size() == 0)) {
|
|
||||||
Collections.reverse(list); //因为saveImportData里面是先分配最大的ID,这个ID应该先发给list中最后的数据,所以要reverse
|
|
||||||
List<TestCaseWithBLOBs> result = list.stream()
|
|
||||||
.map(item -> this.convert2TestCase(item))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
testCaseService.saveImportData(result, projectId);
|
|
||||||
this.setNames(result.stream().map(TestCase::getName).collect(Collectors.toList()));
|
|
||||||
this.setIds(result.stream().map(TestCase::getId).collect(Collectors.toList()));
|
|
||||||
this.isUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(updateList.size() == 0)) {
|
|
||||||
List<TestCaseWithBLOBs> result2 = updateList.stream()
|
|
||||||
.map(item -> this.convert2TestCaseForUpdate(item))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
if(this.isUseCustomId){
|
|
||||||
testCaseService.updateImportDataCustomId(result2, projectId);
|
|
||||||
}else {
|
|
||||||
testCaseService.updateImportDataCarryId(result2, projectId);
|
|
||||||
}
|
|
||||||
this.isUpdated = true;
|
|
||||||
this.setNames(result2.stream().map(TestCase::getName).collect(Collectors.toList()));
|
|
||||||
this.setIds(result2.stream().map(TestCase::getId).collect(Collectors.toList()));
|
|
||||||
updateList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private TestCaseWithBLOBs convert2TestCase(TestCaseExcelData data) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setId(UUID.randomUUID().toString());
|
|
||||||
testCase.setProjectId(this.projectId);
|
|
||||||
testCase.setCreateTime(System.currentTimeMillis());
|
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
|
||||||
if(this.isUseCustomId){
|
|
||||||
testCase.setCustomNum(data.getCustomNum().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
|
|
||||||
if (!nodePath.startsWith("/")) {
|
|
||||||
nodePath = "/" + nodePath;
|
|
||||||
}
|
|
||||||
if (nodePath.endsWith("/")) {
|
|
||||||
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
|
||||||
}
|
|
||||||
testCase.setNodePath(nodePath);
|
|
||||||
|
|
||||||
//将标签设置为前端可解析的格式
|
|
||||||
String modifiedTags = modifyTagPattern(data);
|
|
||||||
testCase.setTags(modifiedTags);
|
|
||||||
testCase.setType("functional");
|
|
||||||
|
|
||||||
JSONArray customArr = new JSONArray();
|
|
||||||
String caseStatusValue = "";
|
|
||||||
if(StringUtils.equalsAny(data.getStatus(),"Underway","进行中","進行中")){
|
|
||||||
caseStatusValue = "Underway";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Prepare","未开始","未開始")){
|
|
||||||
caseStatusValue = "Prepare";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Completed","已完成","已完成")){
|
|
||||||
caseStatusValue = "Completed";
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(caseStatusValue)){
|
|
||||||
|
|
||||||
testCase.setStatus(caseStatusValue);
|
|
||||||
|
|
||||||
JSONObject statusObj = new JSONObject();
|
|
||||||
statusObj.put("id",UUID.randomUUID().toString());
|
|
||||||
statusObj.put("name","用例状态");
|
|
||||||
statusObj.put("value",caseStatusValue);
|
|
||||||
statusObj.put("customData",null);
|
|
||||||
statusObj.put("type","select");
|
|
||||||
customArr.add(statusObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(StringUtils.isNotEmpty(data.getMaintainer())){
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
obj.put("id",UUID.randomUUID().toString());
|
|
||||||
obj.put("name","责任人");
|
|
||||||
obj.put("value",data.getMaintainer());
|
|
||||||
obj.put("customData",null);
|
|
||||||
obj.put("type","member");
|
|
||||||
customArr.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(StringUtils.isNotEmpty(data. getPriority())){
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
obj.put("id",UUID.randomUUID().toString());
|
|
||||||
obj.put("name","用例等级");
|
|
||||||
obj.put("value",data.getPriority());
|
|
||||||
obj.put("customData",null);
|
|
||||||
obj.put("type","select");
|
|
||||||
customArr.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(customArr.size()>0){
|
|
||||||
testCase.setCustomFields(customArr.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(data.getStepModel())
|
|
||||||
&& StringUtils.equals(data.getStepModel(), TestCaseConstants.StepModel.TEXT.name())) {
|
|
||||||
testCase.setStepDescription(data.getStepDesc());
|
|
||||||
testCase.setExpectedResult(data.getStepResult());
|
|
||||||
} else {
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
}
|
|
||||||
return testCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将Excel中的数据对象转换为用于更新操作的用例数据对象,
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
|
||||||
BeanUtils.copyBean(testCase, data);
|
|
||||||
testCase.setProjectId(this.projectId);
|
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
|
||||||
|
|
||||||
//调整nodePath格式
|
|
||||||
String nodePath = data.getNodePath();
|
|
||||||
if (!nodePath.startsWith("/")) {
|
|
||||||
nodePath = "/" + nodePath;
|
|
||||||
}
|
|
||||||
if (nodePath.endsWith("/")) {
|
|
||||||
nodePath = nodePath.substring(0, nodePath.length() - 1);
|
|
||||||
}
|
|
||||||
testCase.setNodePath(nodePath);
|
|
||||||
|
|
||||||
String steps = getSteps(data);
|
|
||||||
testCase.setSteps(steps);
|
|
||||||
|
|
||||||
JSONArray customArr = new JSONArray();
|
|
||||||
String caseStatusValue = "";
|
|
||||||
if(StringUtils.equalsAny(data.getStatus(),"Underway","进行中","進行中")){
|
|
||||||
caseStatusValue = "Underway";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Prepare","未开始","未開始")){
|
|
||||||
caseStatusValue = "Prepare";
|
|
||||||
}else if(StringUtils.equalsAny(data.getStatus(),"Completed","已完成","已完成")){
|
|
||||||
caseStatusValue = "Completed";
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(caseStatusValue)){
|
|
||||||
JSONObject statusObj = new JSONObject();
|
|
||||||
statusObj.put("id",UUID.randomUUID().toString());
|
|
||||||
statusObj.put("name","用例状态");
|
|
||||||
statusObj.put("value",caseStatusValue);
|
|
||||||
statusObj.put("customData",null);
|
|
||||||
customArr.add(statusObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(StringUtils.isNotEmpty(data.getMaintainer())){
|
|
||||||
JSONObject obj = new JSONObject();
|
|
||||||
obj.put("id",UUID.randomUUID().toString());
|
|
||||||
obj.put("name","责任人");
|
|
||||||
obj.put("value",data.getMaintainer());
|
|
||||||
obj.put("customData",null);
|
|
||||||
customArr.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(customArr.size()>0){
|
|
||||||
testCase.setCustomFields(customArr.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//将标签设置为前端可解析的格式
|
|
||||||
String modifiedTags = modifyTagPattern(data);
|
|
||||||
testCase.setTags(modifiedTags);
|
|
||||||
|
|
||||||
if(!isUseCustomId){
|
|
||||||
testCase.setNum(Integer.parseInt(data.getCustomNum()));
|
|
||||||
testCase.setCustomNum(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return testCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调整tags格式,便于前端进行解析。
|
|
||||||
* 例如对于:标签1,标签2。将调整为:["标签1","标签2"]。
|
|
||||||
*/
|
|
||||||
public String modifyTagPattern(TestCaseExcelData data) {
|
|
||||||
String tags = data.getTags();
|
|
||||||
try {
|
|
||||||
if (StringUtils.isNotBlank(tags)) {
|
|
||||||
JSONArray.parse(tags);
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
return "[]";
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (tags != null) {
|
|
||||||
Stream<String> stringStream = Arrays.stream(tags.split("[,;,;]")); //当标签值以中英文的逗号和分号分隔时才能正确解析
|
|
||||||
List<String> tagList = stringStream.map(tag -> tag = "\"" + tag + "\"")
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
String modifiedTags = StringUtils.join(tagList, ",");
|
|
||||||
modifiedTags = "[" + modifiedTags + "]";
|
|
||||||
return modifiedTags;
|
|
||||||
} else {
|
|
||||||
return "[]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getSteps(TestCaseExcelData data) {
|
|
||||||
JSONArray jsonArray = new JSONArray();
|
|
||||||
|
|
||||||
List<String> stepDescList = new ArrayList<>();
|
|
||||||
List<String> stepResList = new ArrayList<>();
|
|
||||||
ListUtils<String> listUtils = new ListUtils<String>();
|
|
||||||
if (data.getStepDesc() != null) {
|
|
||||||
String desc = data.getStepDesc().replaceAll("\\n([1-9]\\.)", "\r\n$1");
|
|
||||||
String [] stepDesc = desc.split("\r\n");
|
|
||||||
StringBuffer stepBuffer = new StringBuffer();
|
|
||||||
int lastStepIndex = 1;
|
|
||||||
for (String row : stepDesc) {
|
|
||||||
RowInfo rowInfo = this.parseIndexInRow(row);
|
|
||||||
int rowIndex = rowInfo.index;
|
|
||||||
String rowMessage = rowInfo.rowInfo;
|
|
||||||
if(rowIndex > -1){
|
|
||||||
listUtils.set(stepDescList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
stepBuffer = new StringBuffer();
|
|
||||||
lastStepIndex = rowIndex;
|
|
||||||
stepBuffer.append(rowMessage);
|
|
||||||
}else {
|
|
||||||
stepBuffer.append(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(stepBuffer.toString())){
|
|
||||||
listUtils.set(stepDescList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stepDescList.add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.getStepResult() != null) {
|
|
||||||
String stepResult = data.getStepResult().replaceAll("\\n([1-9]\\.)", "\r\n$1");
|
|
||||||
String [] stepRes = stepResult.split("\r\n");
|
|
||||||
StringBuffer stepBuffer = new StringBuffer();
|
|
||||||
int lastStepIndex = 1;
|
|
||||||
for (String row : stepRes) {
|
|
||||||
RowInfo rowInfo = this.parseIndexInRow(row);
|
|
||||||
int rowIndex = rowInfo.index;
|
|
||||||
String rowMessage = rowInfo.rowInfo;
|
|
||||||
if(rowIndex > -1){
|
|
||||||
listUtils.set(stepResList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
stepBuffer = new StringBuffer();
|
|
||||||
lastStepIndex = rowIndex;
|
|
||||||
stepBuffer.append(rowMessage);
|
|
||||||
}else {
|
|
||||||
stepBuffer.append(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(StringUtils.isNotEmpty(stepBuffer.toString())){
|
|
||||||
listUtils.set(stepResList,lastStepIndex-1,stepBuffer.toString(),"");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stepResList.add("");
|
|
||||||
}
|
|
||||||
|
|
||||||
int index = stepDescList.size() > stepResList.size() ? stepDescList.size() : stepResList.size();
|
|
||||||
|
|
||||||
for (int i = 0; i < index; i++) {
|
|
||||||
|
|
||||||
// 保持插入顺序,判断用例是否有相同的steps
|
|
||||||
JSONObject step = new JSONObject(true);
|
|
||||||
step.put("num", i + 1);
|
|
||||||
if (i < stepDescList.size()) {
|
|
||||||
step.put("desc", stepDescList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < stepResList.size()) {
|
|
||||||
step.put("result", stepResList.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonArray.add(step);
|
|
||||||
}
|
|
||||||
return jsonArray.toJSONString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private RowInfo parseIndexInRow(String row) {
|
|
||||||
RowInfo rowInfo = new RowInfo();
|
|
||||||
String parseString = row;
|
|
||||||
int index = -1;
|
|
||||||
String rowMessage = row;
|
|
||||||
String [] indexSplitCharArr = new String[]{")",")","]","】",".",",",",","。"};
|
|
||||||
if(StringUtils.startsWithAny(row,"(","(","[","【")){
|
|
||||||
parseString = parseString.substring(1);
|
|
||||||
}
|
|
||||||
for (String splitChar : indexSplitCharArr) {
|
|
||||||
if(StringUtils.contains(parseString,splitChar)){
|
|
||||||
String[] rowSplit = StringUtils.split(parseString,splitChar);
|
|
||||||
if(rowSplit.length > 0){
|
|
||||||
String indexString = rowSplit[0];
|
|
||||||
if(StringUtils.isNumeric(indexString)){
|
|
||||||
try {
|
|
||||||
index = Integer.parseInt(indexString);
|
|
||||||
rowMessage = StringUtils.substring(parseString,indexString.length()+splitChar.length());
|
|
||||||
}catch (Exception e){}
|
|
||||||
|
|
||||||
if(index > -1){
|
|
||||||
break;
|
|
||||||
}else {
|
|
||||||
rowMessage = row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rowInfo.index = index;
|
|
||||||
if(rowMessage == null){
|
|
||||||
rowMessage = "";
|
|
||||||
}
|
|
||||||
rowInfo.rowInfo = rowMessage;
|
|
||||||
return rowInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invoke(TestCaseExcelData testCaseExcelData, AnalysisContext analysisContext) {
|
|
||||||
String errMsg;
|
|
||||||
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
|
|
||||||
String updateMsg = "update_testcase";
|
|
||||||
try {
|
|
||||||
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
|
|
||||||
errMsg = ExcelValidateHelper.validateEntity(testCaseExcelData);
|
|
||||||
//自定义校验规则
|
|
||||||
errMsg = validate(testCaseExcelData, errMsg);
|
|
||||||
} catch (NoSuchFieldException e) {
|
|
||||||
errMsg = Translator.get("parse_data_error");
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringUtils.isEmpty(errMsg)) {
|
|
||||||
|
|
||||||
//如果errMsg只有"update testcase",说明用例待更新
|
|
||||||
if (!errMsg.equals(updateMsg)) {
|
|
||||||
ExcelErrData excelErrData = new ExcelErrData(testCaseExcelData, rowIndex,
|
|
||||||
Translator.get("number") + " " + rowIndex + " " + Translator.get("row") + Translator.get("error")
|
|
||||||
+ ":" + errMsg);
|
|
||||||
|
|
||||||
errList.add(excelErrData);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
list.add(testCaseExcelData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.size() > BATCH_COUNT) {
|
|
||||||
saveData();
|
|
||||||
list.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RowInfo{
|
|
||||||
public int index;
|
|
||||||
public String rowInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,13 +17,13 @@ import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.excel.utils.ExcelValidateHelper;
|
import io.metersphere.excel.utils.ExcelValidateHelper;
|
||||||
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
|
import io.metersphere.track.request.testcase.TestCaseImportRequest;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -37,8 +37,6 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
|
|
||||||
private Class excelDataClass;
|
private Class excelDataClass;
|
||||||
|
|
||||||
boolean isIgnoreError = false;
|
|
||||||
|
|
||||||
protected List<ExcelErrData<TestCaseExcelData>> errList = new ArrayList<>();
|
protected List<ExcelErrData<TestCaseExcelData>> errList = new ArrayList<>();
|
||||||
|
|
||||||
protected List<TestCaseExcelData> excelDataList = new ArrayList<>();
|
protected List<TestCaseExcelData> excelDataList = new ArrayList<>();
|
||||||
|
@ -53,46 +51,33 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
|
|
||||||
private TestCaseService testCaseService;
|
private TestCaseService testCaseService;
|
||||||
|
|
||||||
private String projectId;
|
|
||||||
|
|
||||||
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
||||||
|
|
||||||
protected List<TestCaseExcelData> list = new ArrayList<>();
|
protected List<TestCaseExcelData> list = new ArrayList<>();
|
||||||
|
|
||||||
protected boolean isUpdated = false; //判断是否更新过用例,将会传给前端
|
protected boolean isUpdated = false; //判断是否更新过用例,将会传给前端
|
||||||
|
|
||||||
public boolean isUseCustomId;
|
|
||||||
|
|
||||||
public String importType;
|
|
||||||
|
|
||||||
Set<String> testCaseNames;
|
|
||||||
|
|
||||||
Set<String> customIds;
|
Set<String> customIds;
|
||||||
|
|
||||||
Set<String> savedCustomIds;
|
|
||||||
|
|
||||||
Set<String> userIds;
|
|
||||||
|
|
||||||
private List<String> names = new LinkedList<>();
|
private List<String> names = new LinkedList<>();
|
||||||
private List<String> ids = new LinkedList<>();
|
private List<String> ids = new LinkedList<>();
|
||||||
|
|
||||||
Map<String,CustomFieldDao> customFieldsMap = new HashMap<>();
|
Map<String,CustomFieldDao> customFieldsMap = new HashMap<>();
|
||||||
|
|
||||||
|
private TestCaseImportRequest request;
|
||||||
|
|
||||||
public boolean isUpdated() {
|
public boolean isUpdated() {
|
||||||
return isUpdated;
|
return isUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseNoModelDataListener(boolean isIgnoreError,Class c,List<CustomFieldDao> customFields, String projectId, Set<String> testCaseNames, Set<String> savedCustomIds, Set<String> userIds, boolean isUseCustomId, String importType) {
|
public TestCaseNoModelDataListener(TestCaseImportRequest request, Class c) {
|
||||||
this.excelDataClass = c;
|
this.excelDataClass = c;
|
||||||
this.isIgnoreError = isIgnoreError;
|
|
||||||
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
this.testCaseService = (TestCaseService) CommonBeanFactory.getBean("testCaseService");
|
||||||
this.projectId = projectId;
|
|
||||||
this.testCaseNames = testCaseNames;
|
|
||||||
this.userIds = userIds;
|
|
||||||
this.isUseCustomId = isUseCustomId;
|
|
||||||
this.importType = importType;
|
|
||||||
customIds = new HashSet<>();
|
customIds = new HashSet<>();
|
||||||
this.savedCustomIds = savedCustomIds;
|
|
||||||
|
|
||||||
|
this.request = request;
|
||||||
|
|
||||||
|
List<CustomFieldDao> customFields = request.getCustomFields();
|
||||||
if(CollectionUtils.isNotEmpty(customFields)){
|
if(CollectionUtils.isNotEmpty(customFields)){
|
||||||
for (CustomFieldDao dto:customFields) {
|
for (CustomFieldDao dto:customFields) {
|
||||||
String name = dto.getName();
|
String name = dto.getName();
|
||||||
|
@ -166,8 +151,10 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
}
|
}
|
||||||
|
|
||||||
public String validate(TestCaseExcelData data, String errMsg) {
|
public String validate(TestCaseExcelData data, String errMsg) {
|
||||||
|
Set<String> savedCustomIds = request.getSavedCustomIds();
|
||||||
|
String importType = request.getImportType();
|
||||||
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
StringBuilder stringBuilder = new StringBuilder(errMsg);
|
||||||
if (isUseCustomId || StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
if (request.isUseCustomId() || StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
||||||
if (data.getCustomNum() == null) {
|
if (data.getCustomNum() == null) {
|
||||||
stringBuilder.append(Translator.get("id_required") + ";");
|
stringBuilder.append(Translator.get("id_required") + ";");
|
||||||
} else {
|
} else {
|
||||||
|
@ -231,7 +218,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
if (StringUtils.isBlank(data.getMaintainer())) {
|
if (StringUtils.isBlank(data.getMaintainer())) {
|
||||||
data.setMaintainer(SessionUtils.getUserId());
|
data.setMaintainer(SessionUtils.getUserId());
|
||||||
} else {
|
} else {
|
||||||
if (!userIds.contains(data.getMaintainer())) {
|
if (!request.getUserIds().contains(data.getMaintainer())) {
|
||||||
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,10 +239,10 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
*/
|
*/
|
||||||
if (null != data.getCustomNum()) { //当前读取的数据有ID
|
if (null != data.getCustomNum()) { //当前读取的数据有ID
|
||||||
|
|
||||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Update.name())) {
|
||||||
String checkResult = null;
|
String checkResult = null;
|
||||||
if (isUseCustomId) {
|
if (request.isUseCustomId()) {
|
||||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum(), request.getProjectId());
|
||||||
} else {
|
} else {
|
||||||
int customNumId = -1;
|
int customNumId = -1;
|
||||||
try {
|
try {
|
||||||
|
@ -265,7 +252,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
if (customNumId < 0) {
|
if (customNumId < 0) {
|
||||||
stringBuilder.append(Translator.get("id_not_rightful") + "[" + data.getCustomNum() + "]; ");
|
stringBuilder.append(Translator.get("id_not_rightful") + "[" + data.getCustomNum() + "]; ");
|
||||||
} else {
|
} else {
|
||||||
checkResult = testCaseService.checkIdExist(customNumId, projectId);
|
checkResult = testCaseService.checkIdExist(customNumId, request.getProjectId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (null != checkResult) { //该ID在当前项目中存在
|
if (null != checkResult) { //该ID在当前项目中存在
|
||||||
|
@ -290,10 +277,10 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
/*
|
/*
|
||||||
校验用例
|
校验用例
|
||||||
*/
|
*/
|
||||||
if (testCaseNames.contains(data.getName())) {
|
if (request.getTestCaseNames().contains(data.getName())) {
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
BeanUtils.copyBean(testCase, data);
|
BeanUtils.copyBean(testCase, data);
|
||||||
testCase.setProjectId(projectId);
|
testCase.setProjectId(request.getProjectId());
|
||||||
String steps = getSteps(data);
|
String steps = getSteps(data);
|
||||||
testCase.setSteps(steps);
|
testCase.setSteps(steps);
|
||||||
testCase.setType("functional");
|
testCase.setType("functional");
|
||||||
|
@ -319,7 +306,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
testCaseNames.add(data.getName());
|
request.getTestCaseNames().add(data.getName());
|
||||||
excelDataList.add(data);
|
excelDataList.add(data);
|
||||||
}
|
}
|
||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
|
@ -344,7 +331,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
public void saveData() {
|
public void saveData() {
|
||||||
|
|
||||||
//excel中用例都有错误时就返回,只要有用例可用于更新或者插入就不返回
|
//excel中用例都有错误时就返回,只要有用例可用于更新或者插入就不返回
|
||||||
if (!errList.isEmpty() && !isIgnoreError) {
|
if (!errList.isEmpty() && !request.isIgnore()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +340,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
List<TestCaseWithBLOBs> result = list.stream()
|
List<TestCaseWithBLOBs> result = list.stream()
|
||||||
.map(item -> this.convert2TestCase(item))
|
.map(item -> this.convert2TestCase(item))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
testCaseService.saveImportData(result, projectId);
|
testCaseService.saveImportData(result, request);
|
||||||
this.names = result.stream().map(TestCase::getName).collect(Collectors.toList());
|
this.names = result.stream().map(TestCase::getName).collect(Collectors.toList());
|
||||||
this.ids = result.stream().map(TestCase::getId).collect(Collectors.toList());
|
this.ids = result.stream().map(TestCase::getId).collect(Collectors.toList());
|
||||||
this.isUpdated = true;
|
this.isUpdated = true;
|
||||||
|
@ -363,11 +350,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
List<TestCaseWithBLOBs> result2 = updateList.stream()
|
List<TestCaseWithBLOBs> result2 = updateList.stream()
|
||||||
.map(item -> this.convert2TestCaseForUpdate(item))
|
.map(item -> this.convert2TestCaseForUpdate(item))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
if (this.isUseCustomId) {
|
testCaseService.updateImportData(result2, request);
|
||||||
testCaseService.updateImportDataCustomId(result2, projectId);
|
|
||||||
} else {
|
|
||||||
testCaseService.updateImportDataCarryId(result2, projectId);
|
|
||||||
}
|
|
||||||
this.isUpdated = true;
|
this.isUpdated = true;
|
||||||
this.names = result2.stream().map(TestCase::getName).collect(Collectors.toList());
|
this.names = result2.stream().map(TestCase::getName).collect(Collectors.toList());
|
||||||
this.ids = result2.stream().map(TestCase::getId).collect(Collectors.toList());
|
this.ids = result2.stream().map(TestCase::getId).collect(Collectors.toList());
|
||||||
|
@ -381,11 +364,11 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
BeanUtils.copyBean(testCase, data);
|
BeanUtils.copyBean(testCase, data);
|
||||||
testCase.setId(UUID.randomUUID().toString());
|
testCase.setId(UUID.randomUUID().toString());
|
||||||
testCase.setProjectId(this.projectId);
|
testCase.setProjectId(request.getProjectId());
|
||||||
testCase.setCreateTime(System.currentTimeMillis());
|
testCase.setCreateTime(System.currentTimeMillis());
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
testCase.setUpdateTime(System.currentTimeMillis());
|
||||||
if (this.isUseCustomId) {
|
if (request.isUseCustomId()) {
|
||||||
testCase.setCustomNum(data.getCustomNum().toString());
|
testCase.setCustomNum(data.getCustomNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
String nodePath = data.getNodePath();
|
String nodePath = data.getNodePath();
|
||||||
|
@ -440,7 +423,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
BeanUtils.copyBean(testCase, data);
|
BeanUtils.copyBean(testCase, data);
|
||||||
testCase.setProjectId(this.projectId);
|
testCase.setProjectId(request.getProjectId());
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
testCase.setUpdateTime(System.currentTimeMillis());
|
||||||
|
|
||||||
//调整nodePath格式
|
//调整nodePath格式
|
||||||
|
@ -477,7 +460,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
||||||
String modifiedTags = modifyTagPattern(data);
|
String modifiedTags = modifyTagPattern(data);
|
||||||
testCase.setTags(modifiedTags);
|
testCase.setTags(modifiedTags);
|
||||||
|
|
||||||
if (!isUseCustomId) {
|
if (!request.isUseCustomId()) {
|
||||||
testCase.setNum(Integer.parseInt(data.getCustomNum()));
|
testCase.setNum(Integer.parseInt(data.getCustomNum()));
|
||||||
testCase.setCustomNum(null);
|
testCase.setCustomNum(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,27 @@
|
||||||
package io.metersphere.track.request.testcase;
|
package io.metersphere.track.request.testcase;
|
||||||
|
|
||||||
|
import io.metersphere.dto.CustomFieldDao;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class TestCaseImportRequest {
|
public class TestCaseImportRequest {
|
||||||
private String projectId;
|
private String projectId;
|
||||||
private String userId;
|
private String userId;
|
||||||
private String importType;
|
private String importType;
|
||||||
private String version;
|
private String versionId;
|
||||||
private boolean ignore;
|
private boolean ignore;
|
||||||
|
|
||||||
|
private Set<String> userIds;
|
||||||
|
/**
|
||||||
|
* 已存在用例名称
|
||||||
|
*/
|
||||||
|
private Set<String> testCaseNames;
|
||||||
|
private List<CustomFieldDao> customFields;
|
||||||
|
private Set<String> savedCustomIds;
|
||||||
|
private boolean isUseCustomId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,7 +298,6 @@ public class TestCaseService {
|
||||||
TestCaseWithBLOBs oldTestCase = testCaseMapper.selectByPrimaryKey(testCase.getId());
|
TestCaseWithBLOBs oldTestCase = testCaseMapper.selectByPrimaryKey(testCase.getId());
|
||||||
testCase.setId(UUID.randomUUID().toString());
|
testCase.setId(UUID.randomUUID().toString());
|
||||||
testCase.setNum(oldTestCase.getNum());
|
testCase.setNum(oldTestCase.getNum());
|
||||||
testCase.setVersionId(testCase.getVersionId());
|
|
||||||
testCase.setCreateTime(System.currentTimeMillis());
|
testCase.setCreateTime(System.currentTimeMillis());
|
||||||
testCase.setUpdateTime(System.currentTimeMillis());
|
testCase.setUpdateTime(System.currentTimeMillis());
|
||||||
testCase.setCreateUser(SessionUtils.getUserId());
|
testCase.setCreateUser(SessionUtils.getUserId());
|
||||||
|
@ -708,6 +707,10 @@ public class TestCaseService {
|
||||||
if (multipartFile == null) {
|
if (multipartFile == null) {
|
||||||
MSException.throwException(Translator.get("upload_fail"));
|
MSException.throwException(Translator.get("upload_fail"));
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isBlank(request.getVersionId()) && StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Create.name())) {
|
||||||
|
// 创建如果没选版本就创建最新版本,更新时没选就更新最近版本的用例
|
||||||
|
request.setVersionId(extProjectVersionMapper.getDefaultVersion(request.getProjectId()));
|
||||||
|
}
|
||||||
if (multipartFile.getOriginalFilename().endsWith(".xmind")) {
|
if (multipartFile.getOriginalFilename().endsWith(".xmind")) {
|
||||||
return testCaseXmindImport(multipartFile, request, httpRequest);
|
return testCaseXmindImport(multipartFile, request, httpRequest);
|
||||||
} else {
|
} else {
|
||||||
|
@ -723,11 +726,11 @@ public class TestCaseService {
|
||||||
|
|
||||||
private ExcelResponse getImportResponse(List<ExcelErrData<TestCaseExcelData>> errList, boolean isUpdated) {
|
private ExcelResponse getImportResponse(List<ExcelErrData<TestCaseExcelData>> errList, boolean isUpdated) {
|
||||||
ExcelResponse excelResponse = new ExcelResponse();
|
ExcelResponse excelResponse = new ExcelResponse();
|
||||||
|
excelResponse.setIsUpdated(isUpdated);
|
||||||
//如果包含错误信息就导出错误信息
|
//如果包含错误信息就导出错误信息
|
||||||
if (!errList.isEmpty()) {
|
if (!errList.isEmpty()) {
|
||||||
excelResponse.setSuccess(false);
|
excelResponse.setSuccess(false);
|
||||||
excelResponse.setErrList(errList);
|
excelResponse.setErrList(errList);
|
||||||
excelResponse.setIsUpdated(isUpdated);
|
|
||||||
} else {
|
} else {
|
||||||
excelResponse.setSuccess(true);
|
excelResponse.setSuccess(true);
|
||||||
}
|
}
|
||||||
|
@ -746,7 +749,9 @@ public class TestCaseService {
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
XmindCaseParser xmindParser = new XmindCaseParser(this, request.getUserId(), projectId, testCaseNames, useCunstomId, request.getImportType());
|
request.setTestCaseNames(testCaseNames);
|
||||||
|
request.setUseCustomId(useCunstomId);
|
||||||
|
XmindCaseParser xmindParser = new XmindCaseParser(request);
|
||||||
errList = xmindParser.parse(multipartFile);
|
errList = xmindParser.parse(multipartFile);
|
||||||
if (CollectionUtils.isEmpty(xmindParser.getNodePaths())
|
if (CollectionUtils.isEmpty(xmindParser.getNodePaths())
|
||||||
&& CollectionUtils.isEmpty(xmindParser.getTestCase())
|
&& CollectionUtils.isEmpty(xmindParser.getTestCase())
|
||||||
|
@ -767,12 +772,12 @@ public class TestCaseService {
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(xmindParser.getTestCase())) {
|
if (CollectionUtils.isNotEmpty(xmindParser.getTestCase())) {
|
||||||
// Collections.reverse(xmindParser.getTestCase());
|
// Collections.reverse(xmindParser.getTestCase());
|
||||||
this.saveImportData(xmindParser.getTestCase(), projectId);
|
this.saveImportData(xmindParser.getTestCase(), request);
|
||||||
names = xmindParser.getTestCase().stream().map(TestCase::getName).collect(Collectors.toList());
|
names = xmindParser.getTestCase().stream().map(TestCase::getName).collect(Collectors.toList());
|
||||||
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
if (CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
||||||
this.updateImportData(xmindParser.getUpdateTestCase(), projectId);
|
this.updateImportData(xmindParser.getUpdateTestCase(), request);
|
||||||
names.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getName).collect(Collectors.toList()));
|
names.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getName).collect(Collectors.toList()));
|
||||||
ids.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getId).collect(Collectors.toList()));
|
ids.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getId).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
@ -784,7 +789,7 @@ public class TestCaseService {
|
||||||
if (CollectionUtils.isNotEmpty(continueCaseList) || CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
if (CollectionUtils.isNotEmpty(continueCaseList) || CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
||||||
if (CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
if (CollectionUtils.isNotEmpty(xmindParser.getUpdateTestCase())) {
|
||||||
continueCaseList.removeAll(xmindParser.getUpdateTestCase());
|
continueCaseList.removeAll(xmindParser.getUpdateTestCase());
|
||||||
this.updateImportData(xmindParser.getUpdateTestCase(), projectId);
|
this.updateImportData(xmindParser.getUpdateTestCase(), request);
|
||||||
names = xmindParser.getTestCase().stream().map(TestCase::getName).collect(Collectors.toList());
|
names = xmindParser.getTestCase().stream().map(TestCase::getName).collect(Collectors.toList());
|
||||||
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -794,7 +799,7 @@ public class TestCaseService {
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(continueCaseList)) {
|
if (CollectionUtils.isNotEmpty(continueCaseList)) {
|
||||||
// Collections.reverse(continueCaseList);
|
// Collections.reverse(continueCaseList);
|
||||||
this.saveImportData(continueCaseList, projectId);
|
this.saveImportData(continueCaseList, request);
|
||||||
names.addAll(continueCaseList.stream().map(TestCase::getName).collect(Collectors.toList()));
|
names.addAll(continueCaseList.stream().map(TestCase::getName).collect(Collectors.toList()));
|
||||||
ids.addAll(continueCaseList.stream().map(TestCase::getId).collect(Collectors.toList()));
|
ids.addAll(continueCaseList.stream().map(TestCase::getId).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
@ -809,7 +814,7 @@ public class TestCaseService {
|
||||||
LogUtil.error(e);
|
LogUtil.error(e);
|
||||||
MSException.throwException(e.getMessage());
|
MSException.throwException(e.getMessage());
|
||||||
}
|
}
|
||||||
return getImportResponse(errList, false);
|
return getImportResponse(errList, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExcelResponse testCaseExcelImport(MultipartFile multipartFile, TestCaseImportRequest request,
|
private ExcelResponse testCaseExcelImport(MultipartFile multipartFile, TestCaseImportRequest request,
|
||||||
|
@ -866,8 +871,12 @@ public class TestCaseService {
|
||||||
} else {
|
} else {
|
||||||
customFields = testCaseTemplate.getCustomFields();
|
customFields = testCaseTemplate.getCustomFields();
|
||||||
}
|
}
|
||||||
TestCaseNoModelDataListener easyExcelListener = new TestCaseNoModelDataListener(request.isIgnore(), clazz, customFields, projectId, testCaseNames,
|
request.setUserIds(userIds);
|
||||||
savedIds, userIds, useCunstomId, request.getImportType());
|
request.setTestCaseNames(testCaseNames);
|
||||||
|
request.setCustomFields(customFields);
|
||||||
|
request.setSavedCustomIds(savedIds);
|
||||||
|
request.setUseCustomId(useCunstomId);
|
||||||
|
TestCaseNoModelDataListener easyExcelListener = new TestCaseNoModelDataListener(request, clazz);
|
||||||
|
|
||||||
//读取excel数据
|
//读取excel数据
|
||||||
EasyExcelFactory.read(multipartFile.getInputStream(), easyExcelListener).sheet().doRead();
|
EasyExcelFactory.read(multipartFile.getInputStream(), easyExcelListener).sheet().doRead();
|
||||||
|
@ -883,7 +892,8 @@ public class TestCaseService {
|
||||||
return getImportResponse(errList, isUpdated);
|
return getImportResponse(errList, isUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
public void saveImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
|
||||||
|
String projectId = request.getProjectId();
|
||||||
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
Project project = projectService.getProjectById(projectId);
|
Project project = projectService.getProjectById(projectId);
|
||||||
|
@ -909,6 +919,9 @@ public class TestCaseService {
|
||||||
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
testcase.setStatus(TestCaseReviewStatus.Prepare.name());
|
testcase.setStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
testcase.setOrder(nextOrder);
|
testcase.setOrder(nextOrder);
|
||||||
|
testcase.setRefId(testcase.getId());
|
||||||
|
testcase.setVersionId(request.getVersionId());
|
||||||
|
testcase.setLatest(true);
|
||||||
mapper.insert(testcase);
|
mapper.insert(testcase);
|
||||||
nextOrder += ServiceUtils.ORDER_STEP;
|
nextOrder += ServiceUtils.ORDER_STEP;
|
||||||
}
|
}
|
||||||
|
@ -919,34 +932,35 @@ public class TestCaseService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
// public void updateImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
|
||||||
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
// String projectId = request.getProjectId();
|
||||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
// Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
// SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
try {
|
// TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||||
if (!testCases.isEmpty()) {
|
// try {
|
||||||
AtomicInteger sort = new AtomicInteger();
|
// if (!testCases.isEmpty()) {
|
||||||
AtomicInteger num = new AtomicInteger();
|
// AtomicInteger sort = new AtomicInteger();
|
||||||
num.set(getNextNum(projectId) + testCases.size());
|
// AtomicInteger num = new AtomicInteger();
|
||||||
testCases.forEach(testcase -> {
|
// num.set(getNextNum(projectId) + testCases.size());
|
||||||
TestCaseWithBLOBs oldCase = testCaseMapper.selectByPrimaryKey(testcase.getId());
|
// testCases.forEach(testcase -> {
|
||||||
String customFieldStr = this.updateCustomField(oldCase.getCustomFields(), testcase.getPriority());
|
// TestCaseWithBLOBs oldCase = testCaseMapper.selectByPrimaryKey(testcase.getId());
|
||||||
testcase.setUpdateTime(System.currentTimeMillis());
|
// String customFieldStr = this.updateCustomField(oldCase.getCustomFields(), testcase.getPriority());
|
||||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
// testcase.setUpdateTime(System.currentTimeMillis());
|
||||||
testcase.setSort(sort.getAndIncrement());
|
// testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||||
if (testcase.getNum() == null) {
|
// testcase.setSort(sort.getAndIncrement());
|
||||||
testcase.setNum(num.decrementAndGet());
|
// if (testcase.getNum() == null) {
|
||||||
}
|
// testcase.setNum(num.decrementAndGet());
|
||||||
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
// }
|
||||||
testcase.setCustomFields(customFieldStr);
|
// testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
mapper.updateByPrimaryKeySelective(testcase);
|
// testcase.setCustomFields(customFieldStr);
|
||||||
});
|
// mapper.updateByPrimaryKeySelective(testcase);
|
||||||
sqlSession.flushStatements();
|
// });
|
||||||
}
|
// sqlSession.flushStatements();
|
||||||
} finally {
|
// }
|
||||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
// } finally {
|
||||||
}
|
// SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
private String updateCustomField(String customFields, String priority) {
|
private String updateCustomField(String customFields, String priority) {
|
||||||
try {
|
try {
|
||||||
|
@ -971,68 +985,55 @@ public class TestCaseService {
|
||||||
* feat(测试跟踪):通过Excel导入导出时有ID字段,可通过Excel导入来更新用例。 (#1727)
|
* feat(测试跟踪):通过Excel导入导出时有ID字段,可通过Excel导入来更新用例。 (#1727)
|
||||||
*
|
*
|
||||||
* @param testCases
|
* @param testCases
|
||||||
* @param projectId
|
* @param request
|
||||||
*/
|
*/
|
||||||
public void updateImportDataCarryId(List<TestCaseWithBLOBs> testCases, String projectId) {
|
public void updateImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
|
||||||
|
|
||||||
|
String projectId = request.getProjectId();
|
||||||
|
List<TestCase> insertCases = new ArrayList<>();
|
||||||
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||||
|
|
||||||
/*
|
|
||||||
获取用例的“网页上所显示id”与“数据库ID”映射。
|
|
||||||
*/
|
|
||||||
List<Integer> nums = testCases.stream()
|
|
||||||
.map(TestCase::getNum)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
TestCaseExample example = new TestCaseExample();
|
TestCaseExample example = new TestCaseExample();
|
||||||
example.createCriteria().andNumIn(nums)
|
TestCaseExample.Criteria criteria = example.createCriteria();
|
||||||
.andProjectIdEqualTo(projectId);
|
criteria.andProjectIdEqualTo(projectId);
|
||||||
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
|
||||||
Map<Integer, String> numIdMap = testCasesList.stream()
|
|
||||||
.collect(Collectors.toMap(TestCase::getNum, TestCase::getId));
|
|
||||||
|
|
||||||
|
if (request.isUseCustomId()) {
|
||||||
if (!testCases.isEmpty()) {
|
List<String> nums = testCases.stream()
|
||||||
AtomicInteger sort = new AtomicInteger();
|
.map(TestCase::getCustomNum)
|
||||||
testCases.forEach(testcase -> {
|
.collect(Collectors.toList());
|
||||||
testcase.setUpdateTime(System.currentTimeMillis());
|
criteria.andCustomNumIn(nums);
|
||||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
} else {
|
||||||
testcase.setSort(sort.getAndIncrement());
|
List<Integer> nums = testCases.stream()
|
||||||
testcase.setId(numIdMap.get(testcase.getNum()));
|
.map(TestCase::getNum)
|
||||||
mapper.updateByPrimaryKeySelective(testcase);
|
.collect(Collectors.toList());
|
||||||
});
|
criteria.andNumIn(nums);
|
||||||
}
|
}
|
||||||
sqlSession.flushStatements();
|
|
||||||
if (sqlSession != null && sqlSessionFactory != null) {
|
// 获取用例的“网页上所显示id”与“数据库ID”映射。
|
||||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
Map<Object, TestCase> customIdMap;
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(request.getVersionId())) {
|
||||||
|
// 没选版本更新最新版本
|
||||||
|
criteria.andLatestEqualTo(true);
|
||||||
|
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
||||||
|
customIdMap = testCasesList.stream()
|
||||||
|
.collect(Collectors.toMap(i -> request.isUseCustomId() ? i.getCustomNum() : i.getNum(), i -> i, (k1, k2) -> k1));
|
||||||
|
} else {
|
||||||
|
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
||||||
|
customIdMap = testCasesList.stream()
|
||||||
|
.collect(Collectors.toMap(i -> request.isUseCustomId() ? i.getCustomNum() : i.getNum(),
|
||||||
|
i -> i, (k1, k2) -> {
|
||||||
|
// 查找出来多条,选取当前版本的用例,没有的话随便保存一条,以便新建的时候设置对应的ref_id
|
||||||
|
if (k1.getVersionId().equals(request.getVersionId())) {
|
||||||
|
return k1;
|
||||||
|
} else if (k2.getVersionId().equals(request.getVersionId())) {
|
||||||
|
return k2;
|
||||||
|
}
|
||||||
|
return k1;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 把Excel中带ID的数据更新到数据库
|
|
||||||
* feat(测试跟踪):通过Excel导入导出时有ID字段,可通过Excel导入来更新用例。 (#1727)
|
|
||||||
*
|
|
||||||
* @param testCases
|
|
||||||
* @param projectId
|
|
||||||
*/
|
|
||||||
public void updateImportDataCustomId(List<TestCaseWithBLOBs> testCases, String projectId) {
|
|
||||||
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
|
||||||
|
|
||||||
/*
|
|
||||||
获取用例的“网页上所显示id”与“数据库ID”映射。
|
|
||||||
*/
|
|
||||||
List<String> customIds = testCases.stream()
|
|
||||||
.map(TestCase::getCustomNum)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
TestCaseExample example = new TestCaseExample();
|
|
||||||
example.createCriteria().andCustomNumIn(customIds)
|
|
||||||
.andProjectIdEqualTo(projectId);
|
|
||||||
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
|
||||||
Map<String, String> customIdMap = testCasesList.stream()
|
|
||||||
.collect(Collectors.toMap(TestCase::getCustomNum, TestCase::getId, (k1, k2) -> k1));
|
|
||||||
|
|
||||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
|
||||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
|
||||||
try {
|
try {
|
||||||
if (!testCases.isEmpty()) {
|
if (!testCases.isEmpty()) {
|
||||||
AtomicInteger sort = new AtomicInteger();
|
AtomicInteger sort = new AtomicInteger();
|
||||||
|
@ -1040,11 +1041,43 @@ public class TestCaseService {
|
||||||
testcase.setUpdateTime(System.currentTimeMillis());
|
testcase.setUpdateTime(System.currentTimeMillis());
|
||||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||||
testcase.setSort(sort.getAndIncrement());
|
testcase.setSort(sort.getAndIncrement());
|
||||||
testcase.setId(customIdMap.get(testcase.getCustomNum()));
|
TestCase dbCase = request.isUseCustomId() ? customIdMap.get(testcase.getCustomNum()) : customIdMap.get(testcase.getNum());
|
||||||
mapper.updateByPrimaryKeySelective(testcase);
|
testcase.setId(dbCase.getId());
|
||||||
|
testcase.setRefId(dbCase.getId());
|
||||||
|
if (StringUtils.isNotBlank(request.getVersionId())) {
|
||||||
|
// 选了版本就更新到对应的版本
|
||||||
|
if (dbCase.getVersionId().equals(request.getVersionId())) {
|
||||||
|
mapper.updateByPrimaryKeySelective(testcase);
|
||||||
|
} else { // 没有对应的版本就新建对应版本用例
|
||||||
|
testcase.setCreateTime(System.currentTimeMillis());
|
||||||
|
testcase.setVersionId(request.getVersionId());
|
||||||
|
testcase.setId(UUID.randomUUID().toString());
|
||||||
|
testcase.setOrder(dbCase.getOrder());
|
||||||
|
testcase.setCreateUser(SessionUtils.getUserId());
|
||||||
|
testcase.setCreateUser(SessionUtils.getUserId());
|
||||||
|
testcase.setCreateUser(SessionUtils.getUserId());
|
||||||
|
testcase.setCustomNum(dbCase.getCustomNum());
|
||||||
|
testcase.setNum(dbCase.getNum());
|
||||||
|
testcase.setType(dbCase.getType());
|
||||||
|
if (StringUtils.isBlank(testcase.getStatus())) {
|
||||||
|
testcase.setStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
|
}
|
||||||
|
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||||
|
insertCases.add(testcase); // 由于是批处理,这里先保存,最后再执行
|
||||||
|
mapper.insert(testcase);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mapper.updateByPrimaryKeySelective(testcase);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
sqlSession.flushStatements();
|
sqlSession.flushStatements();
|
||||||
|
|
||||||
|
insertCases.forEach(item -> {
|
||||||
|
checkAndSetLatestVersion(item.getRefId(), request.getVersionId(), request.getProjectId());
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtil.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
import io.metersphere.commons.constants.TestCaseConstants;
|
import io.metersphere.commons.constants.TestCaseConstants;
|
||||||
import io.metersphere.commons.utils.BeanUtils;
|
import io.metersphere.commons.utils.BeanUtils;
|
||||||
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
import io.metersphere.excel.domain.ExcelErrData;
|
import io.metersphere.excel.domain.ExcelErrData;
|
||||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||||
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
||||||
import io.metersphere.i18n.Translator;
|
import io.metersphere.i18n.Translator;
|
||||||
|
import io.metersphere.track.request.testcase.TestCaseImportRequest;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
import io.metersphere.xmind.parser.XmindParser;
|
import io.metersphere.xmind.parser.XmindParser;
|
||||||
import io.metersphere.xmind.parser.pojo.Attached;
|
import io.metersphere.xmind.parser.pojo.Attached;
|
||||||
|
@ -32,16 +34,10 @@ import java.util.regex.Pattern;
|
||||||
public class XmindCaseParser {
|
public class XmindCaseParser {
|
||||||
|
|
||||||
private TestCaseService testCaseService;
|
private TestCaseService testCaseService;
|
||||||
private String maintainer;
|
|
||||||
private String projectId;
|
|
||||||
/**
|
/**
|
||||||
* 过程校验记录
|
* 过程校验记录
|
||||||
*/
|
*/
|
||||||
private DetailUtil process;
|
private DetailUtil process;
|
||||||
/**
|
|
||||||
* 已存在用例名称
|
|
||||||
*/
|
|
||||||
private Set<String> testCaseNames;
|
|
||||||
/**
|
/**
|
||||||
* 转换后的案例信息
|
* 转换后的案例信息
|
||||||
*/
|
*/
|
||||||
|
@ -64,15 +60,11 @@ public class XmindCaseParser {
|
||||||
|
|
||||||
private List<String> errorPath;
|
private List<String> errorPath;
|
||||||
|
|
||||||
private boolean isUseCustomId;
|
private TestCaseImportRequest request;
|
||||||
|
|
||||||
private String importType;
|
public XmindCaseParser(TestCaseImportRequest request) {
|
||||||
|
this.testCaseService = CommonBeanFactory.getBean(TestCaseService.class);
|
||||||
public XmindCaseParser(TestCaseService testCaseService, String userId, String projectId, Set<String> testCaseNames, boolean isUseCustomId, String importType) {
|
this.request = request;
|
||||||
this.testCaseService = testCaseService;
|
|
||||||
this.maintainer = userId;
|
|
||||||
this.projectId = projectId;
|
|
||||||
this.testCaseNames = testCaseNames;
|
|
||||||
testCases = new LinkedList<>();
|
testCases = new LinkedList<>();
|
||||||
updateTestCases = new LinkedList<>();
|
updateTestCases = new LinkedList<>();
|
||||||
compartDatas = new ArrayList<>();
|
compartDatas = new ArrayList<>();
|
||||||
|
@ -80,8 +72,6 @@ public class XmindCaseParser {
|
||||||
nodePaths = new ArrayList<>();
|
nodePaths = new ArrayList<>();
|
||||||
continueValidatedCase = new ArrayList<>();
|
continueValidatedCase = new ArrayList<>();
|
||||||
errorPath = new ArrayList<>();
|
errorPath = new ArrayList<>();
|
||||||
this.isUseCustomId = isUseCustomId;
|
|
||||||
this.importType = importType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TC_REGEX = "(?:tc:|tc:|tc)";
|
private static final String TC_REGEX = "(?:tc:|tc:|tc)";
|
||||||
|
@ -94,12 +84,12 @@ public class XmindCaseParser {
|
||||||
compartDatas.clear();
|
compartDatas.clear();
|
||||||
testCases.clear();
|
testCases.clear();
|
||||||
updateTestCases.clear();
|
updateTestCases.clear();
|
||||||
testCaseNames.clear();
|
request.getTestCaseNames().clear();
|
||||||
nodePaths.clear();
|
nodePaths.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestCaseWithBLOBs> getTestCase() {
|
public List<TestCaseWithBLOBs> getTestCase() {
|
||||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Create.name())) {
|
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Create.name())) {
|
||||||
return this.testCases;
|
return this.testCases;
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
@ -107,7 +97,7 @@ public class XmindCaseParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TestCaseWithBLOBs> getUpdateTestCase() {
|
public List<TestCaseWithBLOBs> getUpdateTestCase() {
|
||||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Update.name())) {
|
||||||
return this.updateTestCases;
|
return this.updateTestCases;
|
||||||
} else {
|
} else {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
@ -205,20 +195,6 @@ public class XmindCaseParser {
|
||||||
process.add(Translator.get("functional_method_tip"), nodePath + data.getName());
|
process.add(Translator.get("functional_method_tip"), nodePath + data.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (testCaseNames.contains(data.getName())) {
|
|
||||||
// TestCaseWithBLOBs bloBs = testCaseService.checkTestCaseExist(data);
|
|
||||||
// if (bloBs != null) {
|
|
||||||
// // process.add(Translator.get("test_case_already_exists_excel"), nodePath + "/" + data.getName());
|
|
||||||
// // 记录需要变更的用例
|
|
||||||
// BeanUtils.copyBean(bloBs, data, "id");
|
|
||||||
// updateTestCases.add(bloBs);
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// } else {
|
|
||||||
// testCaseNames.add(data.getName());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 用例等级和用例性质处理
|
// 用例等级和用例性质处理
|
||||||
if (!priorityList.contains(data.getPriority())) {
|
if (!priorityList.contains(data.getPriority())) {
|
||||||
validatePass = false;
|
validatePass = false;
|
||||||
|
@ -239,15 +215,17 @@ public class XmindCaseParser {
|
||||||
compartDatas.add(compartData);
|
compartDatas.add(compartData);
|
||||||
|
|
||||||
|
|
||||||
|
String importType = request.getImportType();
|
||||||
|
String projectId = request.getProjectId();
|
||||||
|
boolean isUseCustomId = request.isUseCustomId();
|
||||||
|
|
||||||
//自定义ID判断
|
//自定义ID判断
|
||||||
if (StringUtils.isEmpty(data.getCustomNum())) {
|
if (StringUtils.isEmpty(data.getCustomNum())) {
|
||||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
if (StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
||||||
validatePass = false;
|
|
||||||
process.add(Translator.get("id_required"), nodePath + "/" + compartData.getName());
|
process.add(Translator.get("id_required"), nodePath + "/" + compartData.getName());
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (isUseCustomId) {
|
if (isUseCustomId) {
|
||||||
validatePass = false;
|
|
||||||
process.add(Translator.get("custom_num_is_not_exist"), nodePath + "/" + compartData.getName());
|
process.add(Translator.get("custom_num_is_not_exist"), nodePath + "/" + compartData.getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -255,10 +233,10 @@ public class XmindCaseParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
//判断更新
|
//判断更新
|
||||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
if (StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
||||||
String checkResult = null;
|
String checkResult;
|
||||||
if (isUseCustomId) {
|
if (isUseCustomId) {
|
||||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum(), projectId);
|
||||||
} else {
|
} else {
|
||||||
checkResult = testCaseService.checkIdExist(Integer.parseInt(data.getCustomNum()), projectId);
|
checkResult = testCaseService.checkIdExist(Integer.parseInt(data.getCustomNum()), projectId);
|
||||||
}
|
}
|
||||||
|
@ -361,8 +339,8 @@ public class XmindCaseParser {
|
||||||
*/
|
*/
|
||||||
private void formatTestCase(String title, String nodePath, List<Attached> attacheds) {
|
private void formatTestCase(String title, String nodePath, List<Attached> attacheds) {
|
||||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||||
testCase.setProjectId(projectId);
|
testCase.setProjectId(request.getProjectId());
|
||||||
testCase.setMaintainer(maintainer);
|
testCase.setMaintainer(request.getUserId());
|
||||||
testCase.setPriority(priorityList.get(0));
|
testCase.setPriority(priorityList.get(0));
|
||||||
testCase.setMethod("manual");
|
testCase.setMethod("manual");
|
||||||
testCase.setType("functional");
|
testCase.setType("functional");
|
||||||
|
@ -416,7 +394,7 @@ public class XmindCaseParser {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
testCase.setRemark(rc.toString());
|
testCase.setRemark(rc.toString());
|
||||||
if (isUseCustomId || StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
if (request.isUseCustomId() || StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Update.name())) {
|
||||||
testCase.setCustomNum(customId.toString());
|
testCase.setCustomNum(customId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
:file-list="fileList">
|
:file-list="fileList">
|
||||||
<template v-slot:trigger>
|
<template v-slot:trigger>
|
||||||
<el-button size="mini" type="success" plain>{{$t('commons.please_select')}}</el-button>
|
<el-button size="mini" type="success" plain>{{$t('commons.please_select')}}</el-button>
|
||||||
|
<version-select style="margin-left: 25px" v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:tip>
|
<template v-slot:tip>
|
||||||
<div v-if="isExcel" class="el-upload__tip">{{$t('test_track.case.import.upload_limit')}}</div>
|
<div v-if="isExcel" class="el-upload__tip">{{$t('test_track.case.import.upload_limit')}}</div>
|
||||||
|
@ -61,11 +62,6 @@
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row class="import-row">
|
|
||||||
<el-button :disabled="!lastFile" size="small" @click="upload(false)">{{$t('test_track.case.import.click_upload')}}</el-button>
|
|
||||||
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<el-row>
|
<el-row>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="errFile in errList" :key="errFile.rowNum">
|
<li v-for="errFile in errList" :key="errFile.rowNum">
|
||||||
|
@ -74,11 +70,15 @@
|
||||||
</ul>
|
</ul>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row style="text-align: right" v-if="showContinueBtn">
|
<el-row style="text-align: right" >
|
||||||
<div style="margin-right: 20px;margin-bottom: 10px;">
|
<div v-if="showContinueBtn" style="margin-right: 20px;margin-bottom: 10px;">
|
||||||
<el-checkbox :value="true" :disabled="true">{{ $t('test_track.case.import.ignore_error') }}</el-checkbox>
|
<el-checkbox :value="true" :disabled="true">{{ $t('test_track.case.import.ignore_error') }}</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" @click="upload(true)">{{ $t('test_track.case.import.continue_upload') }}
|
<el-button v-if="showContinueBtn" type="primary" @click="upload(true)">
|
||||||
|
{{ $t('test_track.case.import.continue_upload') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button v-if="!showContinueBtn" type="primary" @click="upload(false)">
|
||||||
|
{{ $t('test_track.case.import.click_upload') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button @click="$emit('close')">{{ $t('commons.cancel') }}</el-button>
|
<el-button @click="$emit('close')">{{ $t('commons.cancel') }}</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -104,7 +104,7 @@ export default {
|
||||||
showContinueBtn: false,
|
showContinueBtn: false,
|
||||||
uploadIgnoreError: false,
|
uploadIgnoreError: false,
|
||||||
lastFile: null,
|
lastFile: null,
|
||||||
version: null
|
versionId: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -177,7 +177,7 @@ export default {
|
||||||
projectId: getCurrentProjectID(),
|
projectId: getCurrentProjectID(),
|
||||||
userId: getCurrentUserId(),
|
userId: getCurrentUserId(),
|
||||||
importType: this.importType,
|
importType: this.importType,
|
||||||
version: this.version,
|
versionId: this.versionId,
|
||||||
ignore: isIgnore
|
ignore: isIgnore
|
||||||
};
|
};
|
||||||
this.result = this.$fileUpload('/test/case/import',
|
this.result = this.$fileUpload('/test/case/import',
|
||||||
|
@ -198,7 +198,7 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
changeVersion(data) {
|
changeVersion(data) {
|
||||||
this.version = data;
|
this.versionId = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue