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.FunctionCaseImportEnum;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.track.request.testcase.TestCaseImportRequest;
|
||||
import io.metersphere.track.service.TestCaseService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -37,8 +37,6 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
|
||||
private Class excelDataClass;
|
||||
|
||||
boolean isIgnoreError = false;
|
||||
|
||||
protected List<ExcelErrData<TestCaseExcelData>> errList = new ArrayList<>();
|
||||
|
||||
protected List<TestCaseExcelData> excelDataList = new ArrayList<>();
|
||||
|
@ -53,46 +51,33 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
|
||||
private TestCaseService testCaseService;
|
||||
|
||||
private String projectId;
|
||||
|
||||
protected List<TestCaseExcelData> updateList = new ArrayList<>(); //存储待更新用例的集合
|
||||
|
||||
protected List<TestCaseExcelData> list = 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<>();
|
||||
|
||||
Map<String,CustomFieldDao> customFieldsMap = new HashMap<>();
|
||||
|
||||
private TestCaseImportRequest request;
|
||||
|
||||
public boolean 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.isIgnoreError = isIgnoreError;
|
||||
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;
|
||||
|
||||
this.request = request;
|
||||
|
||||
List<CustomFieldDao> customFields = request.getCustomFields();
|
||||
if(CollectionUtils.isNotEmpty(customFields)){
|
||||
for (CustomFieldDao dto:customFields) {
|
||||
String name = dto.getName();
|
||||
|
@ -166,8 +151,10 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
}
|
||||
|
||||
public String validate(TestCaseExcelData data, String errMsg) {
|
||||
Set<String> savedCustomIds = request.getSavedCustomIds();
|
||||
String importType = request.getImportType();
|
||||
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) {
|
||||
stringBuilder.append(Translator.get("id_required") + ";");
|
||||
} else {
|
||||
|
@ -231,7 +218,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
if (StringUtils.isBlank(data.getMaintainer())) {
|
||||
data.setMaintainer(SessionUtils.getUserId());
|
||||
} else {
|
||||
if (!userIds.contains(data.getMaintainer())) {
|
||||
if (!request.getUserIds().contains(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 (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
||||
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Update.name())) {
|
||||
String checkResult = null;
|
||||
if (isUseCustomId) {
|
||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
||||
if (request.isUseCustomId()) {
|
||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum(), request.getProjectId());
|
||||
} else {
|
||||
int customNumId = -1;
|
||||
try {
|
||||
|
@ -265,7 +252,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
if (customNumId < 0) {
|
||||
stringBuilder.append(Translator.get("id_not_rightful") + "[" + data.getCustomNum() + "]; ");
|
||||
} else {
|
||||
checkResult = testCaseService.checkIdExist(customNumId, projectId);
|
||||
checkResult = testCaseService.checkIdExist(customNumId, request.getProjectId());
|
||||
}
|
||||
}
|
||||
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();
|
||||
BeanUtils.copyBean(testCase, data);
|
||||
testCase.setProjectId(projectId);
|
||||
testCase.setProjectId(request.getProjectId());
|
||||
String steps = getSteps(data);
|
||||
testCase.setSteps(steps);
|
||||
testCase.setType("functional");
|
||||
|
@ -319,7 +306,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
}
|
||||
|
||||
} else {
|
||||
testCaseNames.add(data.getName());
|
||||
request.getTestCaseNames().add(data.getName());
|
||||
excelDataList.add(data);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
|
@ -344,7 +331,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
public void saveData() {
|
||||
|
||||
//excel中用例都有错误时就返回,只要有用例可用于更新或者插入就不返回
|
||||
if (!errList.isEmpty() && !isIgnoreError) {
|
||||
if (!errList.isEmpty() && !request.isIgnore()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -353,7 +340,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
List<TestCaseWithBLOBs> result = list.stream()
|
||||
.map(item -> this.convert2TestCase(item))
|
||||
.collect(Collectors.toList());
|
||||
testCaseService.saveImportData(result, projectId);
|
||||
testCaseService.saveImportData(result, request);
|
||||
this.names = result.stream().map(TestCase::getName).collect(Collectors.toList());
|
||||
this.ids = result.stream().map(TestCase::getId).collect(Collectors.toList());
|
||||
this.isUpdated = true;
|
||||
|
@ -363,11 +350,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
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);
|
||||
}
|
||||
testCaseService.updateImportData(result2, request);
|
||||
this.isUpdated = true;
|
||||
this.names = result2.stream().map(TestCase::getName).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();
|
||||
BeanUtils.copyBean(testCase, data);
|
||||
testCase.setId(UUID.randomUUID().toString());
|
||||
testCase.setProjectId(this.projectId);
|
||||
testCase.setProjectId(request.getProjectId());
|
||||
testCase.setCreateTime(System.currentTimeMillis());
|
||||
testCase.setUpdateTime(System.currentTimeMillis());
|
||||
if (this.isUseCustomId) {
|
||||
testCase.setCustomNum(data.getCustomNum().toString());
|
||||
if (request.isUseCustomId()) {
|
||||
testCase.setCustomNum(data.getCustomNum());
|
||||
}
|
||||
|
||||
String nodePath = data.getNodePath();
|
||||
|
@ -440,7 +423,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
private TestCaseWithBLOBs convert2TestCaseForUpdate(TestCaseExcelData data) {
|
||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||
BeanUtils.copyBean(testCase, data);
|
||||
testCase.setProjectId(this.projectId);
|
||||
testCase.setProjectId(request.getProjectId());
|
||||
testCase.setUpdateTime(System.currentTimeMillis());
|
||||
|
||||
//调整nodePath格式
|
||||
|
@ -477,7 +460,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
|
|||
String modifiedTags = modifyTagPattern(data);
|
||||
testCase.setTags(modifiedTags);
|
||||
|
||||
if (!isUseCustomId) {
|
||||
if (!request.isUseCustomId()) {
|
||||
testCase.setNum(Integer.parseInt(data.getCustomNum()));
|
||||
testCase.setCustomNum(null);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
package io.metersphere.track.request.testcase;
|
||||
|
||||
import io.metersphere.dto.CustomFieldDao;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestCaseImportRequest {
|
||||
private String projectId;
|
||||
private String userId;
|
||||
private String importType;
|
||||
private String version;
|
||||
private String versionId;
|
||||
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());
|
||||
testCase.setId(UUID.randomUUID().toString());
|
||||
testCase.setNum(oldTestCase.getNum());
|
||||
testCase.setVersionId(testCase.getVersionId());
|
||||
testCase.setCreateTime(System.currentTimeMillis());
|
||||
testCase.setUpdateTime(System.currentTimeMillis());
|
||||
testCase.setCreateUser(SessionUtils.getUserId());
|
||||
|
@ -708,6 +707,10 @@ public class TestCaseService {
|
|||
if (multipartFile == null) {
|
||||
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")) {
|
||||
return testCaseXmindImport(multipartFile, request, httpRequest);
|
||||
} else {
|
||||
|
@ -723,11 +726,11 @@ public class TestCaseService {
|
|||
|
||||
private ExcelResponse getImportResponse(List<ExcelErrData<TestCaseExcelData>> errList, boolean isUpdated) {
|
||||
ExcelResponse excelResponse = new ExcelResponse();
|
||||
excelResponse.setIsUpdated(isUpdated);
|
||||
//如果包含错误信息就导出错误信息
|
||||
if (!errList.isEmpty()) {
|
||||
excelResponse.setSuccess(false);
|
||||
excelResponse.setErrList(errList);
|
||||
excelResponse.setIsUpdated(isUpdated);
|
||||
} else {
|
||||
excelResponse.setSuccess(true);
|
||||
}
|
||||
|
@ -746,7 +749,9 @@ public class TestCaseService {
|
|||
.collect(Collectors.toSet());
|
||||
|
||||
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);
|
||||
if (CollectionUtils.isEmpty(xmindParser.getNodePaths())
|
||||
&& CollectionUtils.isEmpty(xmindParser.getTestCase())
|
||||
|
@ -767,12 +772,12 @@ public class TestCaseService {
|
|||
}
|
||||
if (CollectionUtils.isNotEmpty(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());
|
||||
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
||||
}
|
||||
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()));
|
||||
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(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());
|
||||
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
|
||||
}
|
||||
|
@ -794,7 +799,7 @@ public class TestCaseService {
|
|||
}
|
||||
if (CollectionUtils.isNotEmpty(continueCaseList)) {
|
||||
// Collections.reverse(continueCaseList);
|
||||
this.saveImportData(continueCaseList, projectId);
|
||||
this.saveImportData(continueCaseList, request);
|
||||
names.addAll(continueCaseList.stream().map(TestCase::getName).collect(Collectors.toList()));
|
||||
ids.addAll(continueCaseList.stream().map(TestCase::getId).collect(Collectors.toList()));
|
||||
|
||||
|
@ -809,7 +814,7 @@ public class TestCaseService {
|
|||
LogUtil.error(e);
|
||||
MSException.throwException(e.getMessage());
|
||||
}
|
||||
return getImportResponse(errList, false);
|
||||
return getImportResponse(errList, true);
|
||||
}
|
||||
|
||||
private ExcelResponse testCaseExcelImport(MultipartFile multipartFile, TestCaseImportRequest request,
|
||||
|
@ -866,8 +871,12 @@ public class TestCaseService {
|
|||
} else {
|
||||
customFields = testCaseTemplate.getCustomFields();
|
||||
}
|
||||
TestCaseNoModelDataListener easyExcelListener = new TestCaseNoModelDataListener(request.isIgnore(), clazz, customFields, projectId, testCaseNames,
|
||||
savedIds, userIds, useCunstomId, request.getImportType());
|
||||
request.setUserIds(userIds);
|
||||
request.setTestCaseNames(testCaseNames);
|
||||
request.setCustomFields(customFields);
|
||||
request.setSavedCustomIds(savedIds);
|
||||
request.setUseCustomId(useCunstomId);
|
||||
TestCaseNoModelDataListener easyExcelListener = new TestCaseNoModelDataListener(request, clazz);
|
||||
|
||||
//读取excel数据
|
||||
EasyExcelFactory.read(multipartFile.getInputStream(), easyExcelListener).sheet().doRead();
|
||||
|
@ -883,7 +892,8 @@ public class TestCaseService {
|
|||
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);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
Project project = projectService.getProjectById(projectId);
|
||||
|
@ -909,6 +919,9 @@ public class TestCaseService {
|
|||
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||
testcase.setStatus(TestCaseReviewStatus.Prepare.name());
|
||||
testcase.setOrder(nextOrder);
|
||||
testcase.setRefId(testcase.getId());
|
||||
testcase.setVersionId(request.getVersionId());
|
||||
testcase.setLatest(true);
|
||||
mapper.insert(testcase);
|
||||
nextOrder += ServiceUtils.ORDER_STEP;
|
||||
}
|
||||
|
@ -919,34 +932,35 @@ public class TestCaseService {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateImportData(List<TestCaseWithBLOBs> testCases, String projectId) {
|
||||
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||
try {
|
||||
if (!testCases.isEmpty()) {
|
||||
AtomicInteger sort = new AtomicInteger();
|
||||
AtomicInteger num = new AtomicInteger();
|
||||
num.set(getNextNum(projectId) + testCases.size());
|
||||
testCases.forEach(testcase -> {
|
||||
TestCaseWithBLOBs oldCase = testCaseMapper.selectByPrimaryKey(testcase.getId());
|
||||
String customFieldStr = this.updateCustomField(oldCase.getCustomFields(), testcase.getPriority());
|
||||
testcase.setUpdateTime(System.currentTimeMillis());
|
||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
testcase.setSort(sort.getAndIncrement());
|
||||
if (testcase.getNum() == null) {
|
||||
testcase.setNum(num.decrementAndGet());
|
||||
}
|
||||
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||
testcase.setCustomFields(customFieldStr);
|
||||
mapper.updateByPrimaryKeySelective(testcase);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
} finally {
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
}
|
||||
}
|
||||
// public void updateImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
|
||||
// String projectId = request.getProjectId();
|
||||
// Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
|
||||
// SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
// TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||
// try {
|
||||
// if (!testCases.isEmpty()) {
|
||||
// AtomicInteger sort = new AtomicInteger();
|
||||
// AtomicInteger num = new AtomicInteger();
|
||||
// num.set(getNextNum(projectId) + testCases.size());
|
||||
// testCases.forEach(testcase -> {
|
||||
// TestCaseWithBLOBs oldCase = testCaseMapper.selectByPrimaryKey(testcase.getId());
|
||||
// String customFieldStr = this.updateCustomField(oldCase.getCustomFields(), testcase.getPriority());
|
||||
// testcase.setUpdateTime(System.currentTimeMillis());
|
||||
// testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
// testcase.setSort(sort.getAndIncrement());
|
||||
// if (testcase.getNum() == null) {
|
||||
// testcase.setNum(num.decrementAndGet());
|
||||
// }
|
||||
// testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
|
||||
// testcase.setCustomFields(customFieldStr);
|
||||
// mapper.updateByPrimaryKeySelective(testcase);
|
||||
// });
|
||||
// sqlSession.flushStatements();
|
||||
// }
|
||||
// } finally {
|
||||
// SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
// }
|
||||
// }
|
||||
|
||||
private String updateCustomField(String customFields, String priority) {
|
||||
try {
|
||||
|
@ -971,68 +985,55 @@ public class TestCaseService {
|
|||
* feat(测试跟踪):通过Excel导入导出时有ID字段,可通过Excel导入来更新用例。 (#1727)
|
||||
*
|
||||
* @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);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
|
||||
|
||||
/*
|
||||
获取用例的“网页上所显示id”与“数据库ID”映射。
|
||||
*/
|
||||
List<Integer> nums = testCases.stream()
|
||||
.map(TestCase::getNum)
|
||||
.collect(Collectors.toList());
|
||||
TestCaseExample example = new TestCaseExample();
|
||||
example.createCriteria().andNumIn(nums)
|
||||
.andProjectIdEqualTo(projectId);
|
||||
List<TestCase> testCasesList = testCaseMapper.selectByExample(example);
|
||||
Map<Integer, String> numIdMap = testCasesList.stream()
|
||||
.collect(Collectors.toMap(TestCase::getNum, TestCase::getId));
|
||||
TestCaseExample.Criteria criteria = example.createCriteria();
|
||||
criteria.andProjectIdEqualTo(projectId);
|
||||
|
||||
|
||||
if (!testCases.isEmpty()) {
|
||||
AtomicInteger sort = new AtomicInteger();
|
||||
testCases.forEach(testcase -> {
|
||||
testcase.setUpdateTime(System.currentTimeMillis());
|
||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
testcase.setSort(sort.getAndIncrement());
|
||||
testcase.setId(numIdMap.get(testcase.getNum()));
|
||||
mapper.updateByPrimaryKeySelective(testcase);
|
||||
});
|
||||
if (request.isUseCustomId()) {
|
||||
List<String> nums = testCases.stream()
|
||||
.map(TestCase::getCustomNum)
|
||||
.collect(Collectors.toList());
|
||||
criteria.andCustomNumIn(nums);
|
||||
} else {
|
||||
List<Integer> nums = testCases.stream()
|
||||
.map(TestCase::getNum)
|
||||
.collect(Collectors.toList());
|
||||
criteria.andNumIn(nums);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
if (sqlSession != null && sqlSessionFactory != null) {
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
|
||||
// 获取用例的“网页上所显示id”与“数据库ID”映射。
|
||||
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 {
|
||||
if (!testCases.isEmpty()) {
|
||||
AtomicInteger sort = new AtomicInteger();
|
||||
|
@ -1040,11 +1041,43 @@ public class TestCaseService {
|
|||
testcase.setUpdateTime(System.currentTimeMillis());
|
||||
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
|
||||
testcase.setSort(sort.getAndIncrement());
|
||||
testcase.setId(customIdMap.get(testcase.getCustomNum()));
|
||||
mapper.updateByPrimaryKeySelective(testcase);
|
||||
TestCase dbCase = request.isUseCustomId() ? customIdMap.get(testcase.getCustomNum()) : customIdMap.get(testcase.getNum());
|
||||
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();
|
||||
|
||||
insertCases.forEach(item -> {
|
||||
checkAndSetLatestVersion(item.getRefId(), request.getVersionId(), request.getProjectId());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
} finally {
|
||||
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@ import com.google.common.collect.ImmutableMap;
|
|||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||
import io.metersphere.commons.constants.TestCaseConstants;
|
||||
import io.metersphere.commons.utils.BeanUtils;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.excel.domain.ExcelErrData;
|
||||
import io.metersphere.excel.domain.TestCaseExcelData;
|
||||
import io.metersphere.excel.utils.FunctionCaseImportEnum;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.track.request.testcase.TestCaseImportRequest;
|
||||
import io.metersphere.track.service.TestCaseService;
|
||||
import io.metersphere.xmind.parser.XmindParser;
|
||||
import io.metersphere.xmind.parser.pojo.Attached;
|
||||
|
@ -32,16 +34,10 @@ import java.util.regex.Pattern;
|
|||
public class XmindCaseParser {
|
||||
|
||||
private TestCaseService testCaseService;
|
||||
private String maintainer;
|
||||
private String projectId;
|
||||
/**
|
||||
* 过程校验记录
|
||||
*/
|
||||
private DetailUtil process;
|
||||
/**
|
||||
* 已存在用例名称
|
||||
*/
|
||||
private Set<String> testCaseNames;
|
||||
/**
|
||||
* 转换后的案例信息
|
||||
*/
|
||||
|
@ -64,15 +60,11 @@ public class XmindCaseParser {
|
|||
|
||||
private List<String> errorPath;
|
||||
|
||||
private boolean isUseCustomId;
|
||||
private TestCaseImportRequest request;
|
||||
|
||||
private String importType;
|
||||
|
||||
public XmindCaseParser(TestCaseService testCaseService, String userId, String projectId, Set<String> testCaseNames, boolean isUseCustomId, String importType) {
|
||||
this.testCaseService = testCaseService;
|
||||
this.maintainer = userId;
|
||||
this.projectId = projectId;
|
||||
this.testCaseNames = testCaseNames;
|
||||
public XmindCaseParser(TestCaseImportRequest request) {
|
||||
this.testCaseService = CommonBeanFactory.getBean(TestCaseService.class);
|
||||
this.request = request;
|
||||
testCases = new LinkedList<>();
|
||||
updateTestCases = new LinkedList<>();
|
||||
compartDatas = new ArrayList<>();
|
||||
|
@ -80,8 +72,6 @@ public class XmindCaseParser {
|
|||
nodePaths = new ArrayList<>();
|
||||
continueValidatedCase = new ArrayList<>();
|
||||
errorPath = new ArrayList<>();
|
||||
this.isUseCustomId = isUseCustomId;
|
||||
this.importType = importType;
|
||||
}
|
||||
|
||||
private static final String TC_REGEX = "(?:tc:|tc:|tc)";
|
||||
|
@ -94,12 +84,12 @@ public class XmindCaseParser {
|
|||
compartDatas.clear();
|
||||
testCases.clear();
|
||||
updateTestCases.clear();
|
||||
testCaseNames.clear();
|
||||
request.getTestCaseNames().clear();
|
||||
nodePaths.clear();
|
||||
}
|
||||
|
||||
public List<TestCaseWithBLOBs> getTestCase() {
|
||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Create.name())) {
|
||||
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Create.name())) {
|
||||
return this.testCases;
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
|
@ -107,7 +97,7 @@ public class XmindCaseParser {
|
|||
}
|
||||
|
||||
public List<TestCaseWithBLOBs> getUpdateTestCase() {
|
||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
||||
if (StringUtils.equals(request.getImportType(), FunctionCaseImportEnum.Update.name())) {
|
||||
return this.updateTestCases;
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
|
@ -205,20 +195,6 @@ public class XmindCaseParser {
|
|||
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())) {
|
||||
validatePass = false;
|
||||
|
@ -239,15 +215,17 @@ public class XmindCaseParser {
|
|||
compartDatas.add(compartData);
|
||||
|
||||
|
||||
String importType = request.getImportType();
|
||||
String projectId = request.getProjectId();
|
||||
boolean isUseCustomId = request.isUseCustomId();
|
||||
|
||||
//自定义ID判断
|
||||
if (StringUtils.isEmpty(data.getCustomNum())) {
|
||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
||||
validatePass = false;
|
||||
if (StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
||||
process.add(Translator.get("id_required"), nodePath + "/" + compartData.getName());
|
||||
return false;
|
||||
} else {
|
||||
if (isUseCustomId) {
|
||||
validatePass = false;
|
||||
process.add(Translator.get("custom_num_is_not_exist"), nodePath + "/" + compartData.getName());
|
||||
return false;
|
||||
}
|
||||
|
@ -255,10 +233,10 @@ public class XmindCaseParser {
|
|||
}
|
||||
|
||||
//判断更新
|
||||
if (StringUtils.equals(this.importType, FunctionCaseImportEnum.Update.name())) {
|
||||
String checkResult = null;
|
||||
if (StringUtils.equals(importType, FunctionCaseImportEnum.Update.name())) {
|
||||
String checkResult;
|
||||
if (isUseCustomId) {
|
||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum().toString(), projectId);
|
||||
checkResult = testCaseService.checkCustomIdExist(data.getCustomNum(), projectId);
|
||||
} else {
|
||||
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) {
|
||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||
testCase.setProjectId(projectId);
|
||||
testCase.setMaintainer(maintainer);
|
||||
testCase.setProjectId(request.getProjectId());
|
||||
testCase.setMaintainer(request.getUserId());
|
||||
testCase.setPriority(priorityList.get(0));
|
||||
testCase.setMethod("manual");
|
||||
testCase.setType("functional");
|
||||
|
@ -416,7 +394,7 @@ public class XmindCaseParser {
|
|||
});
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
:file-list="fileList">
|
||||
<template v-slot:trigger>
|
||||
<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 v-slot:tip>
|
||||
<div v-if="isExcel" class="el-upload__tip">{{$t('test_track.case.import.upload_limit')}}</div>
|
||||
|
@ -61,11 +62,6 @@
|
|||
</el-upload>
|
||||
</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>
|
||||
<ul>
|
||||
<li v-for="errFile in errList" :key="errFile.rowNum">
|
||||
|
@ -74,11 +70,15 @@
|
|||
</ul>
|
||||
</el-row>
|
||||
|
||||
<el-row style="text-align: right" v-if="showContinueBtn">
|
||||
<div style="margin-right: 20px;margin-bottom: 10px;">
|
||||
<el-row style="text-align: right" >
|
||||
<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>
|
||||
</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 @click="$emit('close')">{{ $t('commons.cancel') }}</el-button>
|
||||
</el-row>
|
||||
|
@ -104,7 +104,7 @@ export default {
|
|||
showContinueBtn: false,
|
||||
uploadIgnoreError: false,
|
||||
lastFile: null,
|
||||
version: null
|
||||
versionId: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -177,7 +177,7 @@ export default {
|
|||
projectId: getCurrentProjectID(),
|
||||
userId: getCurrentUserId(),
|
||||
importType: this.importType,
|
||||
version: this.version,
|
||||
versionId: this.versionId,
|
||||
ignore: isIgnore
|
||||
};
|
||||
this.result = this.$fileUpload('/test/case/import',
|
||||
|
@ -198,7 +198,7 @@ export default {
|
|||
});
|
||||
},
|
||||
changeVersion(data) {
|
||||
this.version = data;
|
||||
this.versionId = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue