feat(测试跟踪): 功能用例导入支持自定义字段

--story=1008224 --user=陈建星 用例导出/导入支持自定义字段 https://www.tapd.cn/55049933/s/1228391
This commit is contained in:
AnAngle 2022-08-21 15:56:08 +08:00 committed by jianxing
parent 522abf855b
commit 173941f131
3 changed files with 110 additions and 36 deletions

View File

@ -3,10 +3,12 @@ package io.metersphere.excel.listener;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
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.base.domain.ext.CustomFieldResource;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.CustomFieldValidateException;
import io.metersphere.commons.exception.MSException;
@ -37,6 +39,8 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static io.metersphere.xpack.ui.constants.ArgTypeEnum.testCase;
/**
* 由于功能案例中含有自定义字段导入的时候使用无模板对象的读取方式
*
@ -100,6 +104,8 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
private HashMap<String, AbstractCustomFieldValidator> customFieldValidatorMap;
private Map<String, List<CustomFieldResource>> testCaseCustomFieldMap = new HashMap<>();
public boolean isUpdated() {
return isUpdated;
}
@ -215,6 +221,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
private void handleMergeData(Map<Integer, String> data, Integer rowIndex) {
this.isMergeRow = false;
this.isMergeLastRow = false;
if (getNameColIndex() == null) {
MSException.throwException("缺少名称表头");
}
data.keySet().forEach(col -> {
Iterator<ExcelMergeInfo> iterator = mergeInfoSet.iterator();
while (iterator.hasNext()) {
@ -268,6 +277,9 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
}
private void validateDbExist(TestCaseExcelData data, StringBuilder stringBuilder) {
if (this.isUpdateModel()) {
return;
}
if (request.getTestCaseNames().contains(data.getName())) {
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
BeanUtils.copyBean(testCase, data);
@ -491,7 +503,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
List<TestCaseWithBLOBs> result = list.stream()
.map(item -> this.convert2TestCase(item))
.collect(Collectors.toList());
testCaseService.saveImportData(result, request);
testCaseService.saveImportData(result, request, testCaseCustomFieldMap);
this.names = result.stream().map(TestCase::getName).collect(Collectors.toList());
this.ids = result.stream().map(TestCase::getId).collect(Collectors.toList());
this.isUpdated = true;
@ -501,13 +513,13 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
List<TestCaseWithBLOBs> result2 = updateList.stream()
.map(item -> this.convert2TestCaseForUpdate(item))
.collect(Collectors.toList());
testCaseService.updateImportData(result2, request);
testCaseService.updateImportData(result2, request, testCaseCustomFieldMap);
this.isUpdated = true;
this.names = result2.stream().map(TestCase::getName).collect(Collectors.toList());
this.ids = result2.stream().map(TestCase::getId).collect(Collectors.toList());
updateList.clear();
}
customFieldsMap.clear();
}
private TestCaseWithBLOBs convert2TestCase(TestCaseExcelData data) {
@ -517,9 +529,37 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
if (request.isUseCustomId()) {
testCase.setCustomNum(data.getCustomNum());
}
buildTestCaseCustomFieldMap(data, testCase);
return testCase;
}
/**
* 暂存功能自定义字段
* @param data
* @param testCase
*/
private void buildTestCaseCustomFieldMap(TestCaseExcelData data, TestCaseWithBLOBs testCase) {
Map<String, String> customData = data.getCustomData();
List<CustomFieldResource> testCaseCustomFields = new ArrayList<>();
customData.forEach((k, v) -> {
if (StringUtils.isNotBlank(v)) {
CustomFieldDao customFieldDao = customFieldsMap.get(k);
if (customFieldDao != null) {
CustomFieldResource customFieldResource = new CustomFieldResource();
customFieldResource.setFieldId(customFieldDao.getId());
customFieldResource.setValue(JSON.toJSONString(v));
customFieldResource.setResourceId(testCase.getId());
testCaseCustomFields.add(customFieldResource);
}
}
});
if (CollectionUtils.isNotEmpty(testCaseCustomFields)) {
testCaseCustomFieldMap.put(testCase.getId(), testCaseCustomFields);
}
}
@NotNull
private TestCaseWithBLOBs parseData(TestCaseExcelData data) {
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
@ -572,6 +612,7 @@ public class TestCaseNoModelDataListener extends AnalysisEventListener<Map<Integ
testCase.setNum(Integer.parseInt(data.getCustomNum()));
testCase.setCustomNum(null);
}
buildTestCaseCustomFieldMap(data, testCase);
return testCase;
}

View File

@ -59,6 +59,7 @@ import io.metersphere.xmind.XmindCaseParser;
import io.metersphere.xmind.pojo.TestCaseXmindData;
import io.metersphere.xmind.utils.XmindExportUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@ -993,12 +994,12 @@ public class TestCaseService {
testCaseNodeService.createNodes(xmindParser.getNodePaths(), projectId);
}
if (CollectionUtils.isNotEmpty(xmindParser.getTestCase())) {
this.saveImportData(xmindParser.getTestCase(), request);
this.saveImportData(xmindParser.getTestCase(), request, null);
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(), request);
this.updateImportData(xmindParser.getUpdateTestCase(), request, null);
names.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getName).collect(Collectors.toList()));
ids.addAll(xmindParser.getUpdateTestCase().stream().map(TestCase::getId).collect(Collectors.toList()));
}
@ -1010,7 +1011,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(), request);
this.updateImportData(xmindParser.getUpdateTestCase(), request, null);
names = xmindParser.getTestCase().stream().map(TestCase::getName).collect(Collectors.toList());
ids = xmindParser.getTestCase().stream().map(TestCase::getId).collect(Collectors.toList());
}
@ -1019,7 +1020,7 @@ public class TestCaseService {
testCaseNodeService.createNodes(nodePathList, projectId);
}
if (CollectionUtils.isNotEmpty(continueCaseList)) {
this.saveImportData(continueCaseList, request);
this.saveImportData(continueCaseList, request, null);
names.addAll(continueCaseList.stream().map(TestCase::getName).collect(Collectors.toList()));
ids.addAll(continueCaseList.stream().map(TestCase::getId).collect(Collectors.toList()));
@ -1105,12 +1106,15 @@ public class TestCaseService {
return getImportResponse(errList, isUpdated);
}
public void saveImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
public void saveImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request,
Map<String, List<CustomFieldResource>> testCaseCustomFieldMap) {
String projectId = request.getProjectId();
Map<String, String> nodePathMap = testCaseNodeService.createNodeByTestCases(testCases, projectId);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
Project project = projectService.getProjectById(projectId);
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
CustomFieldTestCaseMapper customFieldTestCaseMapper = sqlSession.getMapper(CustomFieldTestCaseMapper.class);
ProjectConfig config = projectApplicationService.getSpecificTypeValue(project.getId(), ProjectApplicationType.CASE_CUSTOM_NUM.name());
boolean customNum = config.getCaseCustomNum();
try {
@ -1118,7 +1122,9 @@ public class TestCaseService {
Integer num = importCreateNum.get();
Integer beforeInsertId = beforeImportCreateNum.get();
for (TestCaseWithBLOBs testCase : testCases) {
testCase.setId(UUID.randomUUID().toString());
if (StringUtils.isBlank(testCase.getId())) {
testCase.setId(UUID.randomUUID().toString());
}
testCase.setCreateUser(SessionUtils.getUserId());
testCase.setCreateTime(System.currentTimeMillis());
testCase.setUpdateTime(System.currentTimeMillis());
@ -1148,6 +1154,8 @@ public class TestCaseService {
testCase.setVersionId(request.getVersionId());
testCase.setLatest(true);
mapper.insert(testCase);
batchInsertCustomFieldTestCase(testCaseCustomFieldMap, customFieldTestCaseMapper, testCase);
}
importCreateNum.set(num);
@ -1167,13 +1175,15 @@ public class TestCaseService {
* @param testCases
* @param request
*/
public void updateImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request) {
public void updateImportData(List<TestCaseWithBLOBs> testCases, TestCaseImportRequest request, Map<String, List<CustomFieldResource>> testCaseCustomFieldMap) {
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);
CustomFieldTestCaseMapper customFieldTestCaseMapper = sqlSession.getMapper(CustomFieldTestCaseMapper.class);
TestCaseExample example = new TestCaseExample();
TestCaseExample.Criteria criteria = example.createCriteria();
criteria.andProjectIdEqualTo(projectId);
@ -1216,36 +1226,47 @@ public class TestCaseService {
try {
if (!testCases.isEmpty()) {
testCases.forEach(testcase -> {
testcase.setUpdateTime(System.currentTimeMillis());
testcase.setNodeId(nodePathMap.get(testcase.getNodePath()));
TestCase dbCase = request.isUseCustomId() ? customIdMap.get(testcase.getCustomNum()) : customIdMap.get(testcase.getNum());
testcase.setId(dbCase.getId());
testcase.setRefId(dbCase.getRefId());
testCases.forEach(testCase -> {
testCase.setUpdateTime(System.currentTimeMillis());
testCase.setNodeId(nodePathMap.get(testCase.getNodePath()));
TestCase dbCase = request.isUseCustomId() ? customIdMap.get(testCase.getCustomNum()) : customIdMap.get(testCase.getNum());
testCase.setId(dbCase.getId());
testCase.setRefId(dbCase.getRefId());
if (StringUtils.isBlank(request.getVersionId())) {
request.setVersionId(extProjectVersionMapper.getDefaultVersion(projectId));
}
// 选了版本就更新到对应的版本
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.setLatest(false);
testcase.setType(dbCase.getType());
if (StringUtils.isBlank(testcase.getStatus())) {
testcase.setStatus(TestCaseReviewStatus.Prepare.name());
mapper.updateByPrimaryKeySelective(testCase);
// 先删除
if (MapUtils.isNotEmpty(testCaseCustomFieldMap)) {
CustomFieldTestCaseExample customFieldTestCaseExample = new CustomFieldTestCaseExample();
customFieldTestCaseExample.createCriteria().andResourceIdEqualTo(testCase.getId());
customFieldTestCaseMapper.deleteByExample(customFieldTestCaseExample);
}
testcase.setReviewStatus(TestCaseReviewStatus.Prepare.name());
insertCases.add(testcase); // 由于是批处理这里先保存最后再执行
mapper.insert(testcase);
// 再添加
batchInsertCustomFieldTestCase(testCaseCustomFieldMap, customFieldTestCaseMapper, testCase);
} else { // 没有对应的版本就新建对应版本用例
testCase.setCreateTime(System.currentTimeMillis());
testCase.setVersionId(request.getVersionId());
testCase.setId(UUID.randomUUID().toString());
testCase.setOrder(dbCase.getOrder());
testCase.setCreateUser(SessionUtils.getUserId());
testCase.setCustomNum(dbCase.getCustomNum());
testCase.setNum(dbCase.getNum());
testCase.setLatest(false);
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);
batchInsertCustomFieldTestCase(testCaseCustomFieldMap, customFieldTestCaseMapper, testCase);
}
});
}
@ -1261,6 +1282,17 @@ public class TestCaseService {
}
}
private void batchInsertCustomFieldTestCase(Map<String, List<CustomFieldResource>> testCaseCustomFieldMap,
CustomFieldTestCaseMapper customFieldTestCaseMapper, TestCaseWithBLOBs testCase) {
if (MapUtils.isEmpty(testCaseCustomFieldMap)) {
return;
}
List<CustomFieldResource> customFieldResources = testCaseCustomFieldMap.get(testCase.getId());
if (CollectionUtils.isNotEmpty(customFieldResources)) {
customFieldResources.forEach(customFieldTestCaseMapper::insert);
}
}
public void download(String fileName, HttpServletResponse res) throws IOException {
if (StringUtils.isEmpty(fileName)) {
fileName = "xmind.xml";

View File

@ -107,8 +107,9 @@ public class CustomFieldSelectValidator extends AbstractCustomFieldValidator {
@NotNull
private Map<String, String> getTextMap(List<CustomFieldOption> options) {
return options.stream()
.collect(Collectors.toMap(CustomFieldOption::getValue, CustomFieldOption::getText));
HashMap<String, String> textMap = new HashMap<>();
options.forEach(item -> textMap.put(item.getText(), item.getValue()));
return textMap;
}
@NotNull