fix(接口测试): 修复场景导入多个场景引用同一个用例接口会生成多个用例问题

本次提交还优化了批量删除比较慢的问题
https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001018092
--user=郭雨琦
This commit is contained in:
guoyuqi 2022-10-17 17:56:59 +08:00 committed by xiaomeinvG
parent 4b0ee06876
commit 3de2b85fda
3 changed files with 125 additions and 78 deletions

View File

@ -29,6 +29,7 @@ import org.json.JSONArray;
import org.json.JSONObject;
import java.util.*;
import java.util.stream.Collectors;
public class ApiScenarioImportUtil {
@ -159,7 +160,7 @@ public class ApiScenarioImportUtil {
}
}
public static void checkCase(int i, JSONObject object, String versionId, String projectId, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper, Map<String, ApiDefinition> definitionMap) {
public static void checkCase(JSONObject object, String versionId, String projectId, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper, Map<String, ApiDefinition> definitionMap,Map<String, Set<String>> apiIdCaseNameMap) {
ApiTestCaseService testCaseService = CommonBeanFactory.getBean(ApiTestCaseService.class);
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
ApiTestCaseWithBLOBs bloBs = testCaseService.get(object.optString("id"));
@ -174,7 +175,7 @@ public class ApiScenarioImportUtil {
request.setName(object.optString("name"));
ApiTestCase sameCase = testCaseService.getSameCase(request);
if (sameCase == null) {
structureCaseByJson(i, object, testCaseService, apiDefinition, apiTestCaseMapper);
structureCaseByJson(object, testCaseService, apiDefinition, apiTestCaseMapper,apiIdCaseNameMap);
} else {
object.put("id", sameCase.getId());
object.put("resourceId", sameCase.getId());
@ -184,13 +185,13 @@ public class ApiScenarioImportUtil {
}
}
} else {
ApiDefinitionResult apiDefinitionResult = structureApiDefinitionByJson(i, apiDefinitionService, object, versionId, projectId, apiDefinitionMapper, definitionMap);
structureCaseByJson(i, object, testCaseService, apiDefinitionResult, apiTestCaseMapper);
ApiDefinitionResult apiDefinitionResult = structureApiDefinitionByJson(apiDefinitionService, object, versionId, projectId, apiDefinitionMapper, definitionMap);
structureCaseByJson(object, testCaseService, apiDefinitionResult, apiTestCaseMapper,apiIdCaseNameMap);
}
}
}
public static ApiDefinitionResult structureApiDefinitionByJson(int i, ApiDefinitionService apiDefinitionService, JSONObject object, String versionId, String projectId, ApiDefinitionMapper apiDefinitionMapper, Map<String, ApiDefinition> definitionMap) {
public static ApiDefinitionResult structureApiDefinitionByJson(ApiDefinitionService apiDefinitionService, JSONObject object, String versionId, String projectId, ApiDefinitionMapper apiDefinitionMapper, Map<String, ApiDefinition> definitionMap) {
ApiDefinitionResult test = new ApiDefinitionResult();
apiDefinitionService.checkQuota(projectId);
String protocal = object.optString("protocal");
@ -208,7 +209,14 @@ public class ApiScenarioImportUtil {
}
String id = UUID.randomUUID().toString();
test.setId(id);
test.setNum(apiDefinitionService.getNextNum(projectId) + i);
if (MapUtils.isEmpty(definitionMap)){
test.setNum(apiDefinitionService.getNextNum(projectId));
}else {
ArrayList<ApiDefinition> apiDefinitions = new ArrayList<>(definitionMap.values());
List<Integer> collect = apiDefinitions.stream().map(ApiDefinition::getNum).collect(Collectors.toList());
Collections.sort(collect);
test.setNum(collect.get(collect.size()-1)+1);
}
test.setName(object.optString("name"));
if (StringUtils.isBlank(object.optString("path"))) {
if (StringUtils.isNotBlank(object.optString("url"))) {
@ -256,7 +264,12 @@ public class ApiScenarioImportUtil {
return test;
}
public static void structureCaseByJson(int i, JSONObject object, ApiTestCaseService testCaseService, ApiDefinition apiDefinition, ApiTestCaseMapper apiTestCaseMapper) {
public static void structureCaseByJson(JSONObject object, ApiTestCaseService testCaseService, ApiDefinition apiDefinition, ApiTestCaseMapper apiTestCaseMapper,Map<String, Set<String>> apiIdCaseNameMap) {
String caseMapKey = apiDefinition.getId();
Set<String> caseNameSet = apiIdCaseNameMap.get(caseMapKey);
if (CollectionUtils.isNotEmpty(caseNameSet) && caseNameSet.contains(object.optString("name"))){
return;
}
String projectId = apiDefinition.getProjectId();
ApiDefinitionService apiDefinitionService = CommonBeanFactory.getBean(ApiDefinitionService.class);
ApiTestCaseWithBLOBs apiTestCase = new ApiTestCaseWithBLOBs();
@ -272,7 +285,11 @@ public class ApiScenarioImportUtil {
apiTestCase.setUpdateTime(System.currentTimeMillis());
apiTestCase.setVersionId(apiDefinition.getVersionId());
apiTestCase.setPriority("P0");
apiTestCase.setNum(testCaseService.getNextNum(apiTestCase.getApiDefinitionId(), apiDefinition.getNum() + i, projectId));
if (CollectionUtils.isEmpty(caseNameSet)){
apiTestCase.setNum(testCaseService.getNextNum(apiTestCase.getApiDefinitionId(), apiDefinition.getNum(), projectId));
}else {
apiTestCase.setNum(apiDefinition.getNum()*1000+caseNameSet.size()+1);
}
object.put("id", apiTestCase.getId());
object.put("resourceId", apiTestCase.getId());
object.put("projectId", projectId);
@ -286,6 +303,14 @@ public class ApiScenarioImportUtil {
if (apiTestCase.getName().length() > 255) {
apiTestCase.setName(apiTestCase.getName().substring(0, 255));
}
Set<String> strings = apiIdCaseNameMap.get(caseMapKey);
if (CollectionUtils.isEmpty(strings)){
Set<String>addCaseNameSet = new HashSet<>();
addCaseNameSet.add(apiTestCase.getName());
apiIdCaseNameMap.put(caseMapKey,addCaseNameSet);
}else {
strings.add(apiTestCase.getName());
}
apiTestCaseMapper.insert(apiTestCase);
}

View File

@ -522,31 +522,32 @@ public class ApiDefinitionService {
if (CollectionUtils.isEmpty(apiIds)) {
return;
}
apiIds.forEach(apiId -> {
// 把所有版本的api移到回收站
ApiDefinitionWithBLOBs api = apiDefinitionMapper.selectByPrimaryKey(apiId);
if (api == null) {
return;
}
ApiDefinitionExampleWithOperation example = new ApiDefinitionExampleWithOperation();
example.createCriteria().andRefIdEqualTo(api.getRefId());
example.setOperator(SessionUtils.getUserId());
example.setOperationTime(System.currentTimeMillis());
extApiDefinitionMapper.removeToGcByExample(example);
ApiDefinitionExample apiDefinitionExample = new ApiDefinitionExample();
apiDefinitionExample.createCriteria().andIdIn(apiIds);
List<ApiDefinition> apiDefinitions = apiDefinitionMapper.selectByExample(apiDefinitionExample);
if (CollectionUtils.isEmpty(apiDefinitions)){
return;
}
List<String> refIds = apiDefinitions.stream().map(ApiDefinition::getRefId).collect(Collectors.toList());
ApiDefinitionExampleWithOperation example = new ApiDefinitionExampleWithOperation();
example.createCriteria().andRefIdIn(refIds);
example.setOperator(SessionUtils.getUserId());
example.setOperationTime(System.currentTimeMillis());
extApiDefinitionMapper.removeToGcByExample(example);
ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setRefId(api.getRefId());
List<String> ids = extApiDefinitionMapper.selectIds(request);
apiDefinitionExample = new ApiDefinitionExample();
apiDefinitionExample.createCriteria().andRefIdIn(refIds);
List<ApiDefinition> apiDefinitionList = apiDefinitionMapper.selectByExample(apiDefinitionExample);
List<String> ids = apiDefinitionList.stream().map(ApiDefinition::getId).collect(Collectors.toList());
// 把所有版本的api case移到回收站
List<String> apiCaseIds = apiTestCaseService.selectCaseIdsByApiIds(ids);
if (CollectionUtils.isNotEmpty(apiCaseIds)) {
ApiTestBatchRequest apiTestBatchRequest = new ApiTestBatchRequest();
apiTestBatchRequest.setIds(apiCaseIds);
apiTestBatchRequest.setUnSelectIds(new ArrayList<>());
apiTestCaseService.deleteToGcByParam(apiTestBatchRequest);
}
});
// 把所有版本的api case移到回收站
List<String> apiCaseIds = apiTestCaseService.selectCaseIdsByApiIds(ids);
if (CollectionUtils.isNotEmpty(apiCaseIds)) {
ApiTestBatchRequest apiTestBatchRequest = new ApiTestBatchRequest();
apiTestBatchRequest.setIds(apiCaseIds);
apiTestBatchRequest.setUnSelectIds(new ArrayList<>());
apiTestCaseService.deleteToGcByParam(apiTestBatchRequest);
}
}
public void reduction(ApiBatchRequest request) {

View File

@ -401,16 +401,15 @@ public class ApiScenarioService {
return scenario;
}
private void checkReferenceCase(ApiScenarioWithBLOBs scenario, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) {
private void checkReferenceCase(ApiScenarioWithBLOBs scenario) {
if (scenario == null || StringUtils.isEmpty(scenario.getScenarioDefinition())) {
return;
}
JSONObject element = JSONUtil.parseObject(scenario.getScenarioDefinition());
JSONArray hashTree = element.optJSONArray(ElementConstants.HASH_TREE);
ApiScenarioImportUtil.formatHashTree(hashTree);
setReferenced(hashTree, scenario.getVersionId(), scenario.getProjectId(), apiTestCaseMapper, apiDefinitionMapper, true);
setReferenced(hashTree, scenario.getProjectId());
scenario.setScenarioDefinition(element.toString());
}
private void checkAndSetLatestVersion(String refId) {
@ -586,27 +585,33 @@ public class ApiScenarioService {
}
public void removeToGc(List<String> apiIds) {
for (String id : apiIds) {
ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(id);
if (scenario == null) {
return;
}
List<String> scenarioIds = new ArrayList<>();
if (StringUtils.isNotBlank(scenario.getRefId())) {
ApiScenarioRequest request = new ApiScenarioRequest();
request.setRefId(scenario.getRefId());
scenarioIds = extApiScenarioMapper.selectIdsByQuery(request);
} else {
scenarioIds.add(scenario.getId());
}
//将这些场景的定时任务删除掉
scenarioIds.forEach(scenarioId -> scheduleService.deleteByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name()));
ApiScenarioExampleWithOperation example = new ApiScenarioExampleWithOperation();
example.createCriteria().andRefIdEqualTo(scenario.getRefId());
example.setOperator(SessionUtils.getUserId());
example.setOperationTime(System.currentTimeMillis());
extApiScenarioMapper.removeToGcByExample(example);
if (CollectionUtils.isEmpty(apiIds)){
return;
}
ApiScenarioExample apiScenarioExample = new ApiScenarioExample();
apiScenarioExample.createCriteria().andIdIn(apiIds);
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(apiScenarioExample);
if (CollectionUtils.isEmpty(apiScenarios)){
return;
}
List<String> refIds = apiScenarios.stream().map(ApiScenario::getRefId).collect(toList());
apiScenarioExample = new ApiScenarioExample();
apiScenarioExample.createCriteria().andRefIdIn(refIds);
List<ApiScenario> apiScenarioVersions = apiScenarioMapper.selectByExample(apiScenarioExample);
if (CollectionUtils.isEmpty(apiScenarioVersions)){
return;
}
List<String> scenarioIds = apiScenarioVersions.stream().map(ApiScenario::getId).collect(toList());
scenarioIds.forEach(scenarioId -> scheduleService.deleteByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name()));
ApiScenarioExampleWithOperation example = new ApiScenarioExampleWithOperation();
example.createCriteria().andRefIdIn(refIds);
example.setOperator(SessionUtils.getUserId());
example.setOperationTime(System.currentTimeMillis());
extApiScenarioMapper.removeToGcByExample(example);
}
public void reduction(List<String> ids) {
@ -1162,7 +1167,7 @@ public class ApiScenarioService {
}
}
private void _importCreate(List<ApiScenarioWithBLOBs> sameRequest, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, ApiScenarioWithBLOBs scenarioWithBLOBs, ApiTestImportRequest apiTestImportRequest, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) {
private void _importCreate(List<ApiScenarioWithBLOBs> sameRequest, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, ApiScenarioWithBLOBs scenarioWithBLOBs, ApiTestImportRequest apiTestImportRequest) {
if (CollectionUtils.isEmpty(sameRequest)) {
// 没有这个场景 新增
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
@ -1185,7 +1190,7 @@ public class ApiScenarioService {
}
}
checkReferenceCase(scenarioWithBLOBs, apiTestCaseMapper, apiDefinitionMapper);
checkReferenceCase(scenarioWithBLOBs);
sendImportScenarioCreateNotice(scenarioWithBLOBs);
batchMapper.insert(scenarioWithBLOBs);
apiScenarioReferenceIdService.saveApiAndScenarioRelation(scenarioWithBLOBs);
@ -1207,7 +1212,7 @@ public class ApiScenarioService {
scenarioWithBLOBs.setRefId(sameRequest.get(0).getRefId() == null ? sameRequest.get(0).getId() : sameRequest.get(0).getRefId());
scenarioWithBLOBs.setNum(sameRequest.get(0).getNum()); // 使用第一个num当作本次的num
scenarioWithBLOBs.setOrder(sameRequest.get(0).getOrder());
checkReferenceCase(scenarioWithBLOBs, apiTestCaseMapper, apiDefinitionMapper);
checkReferenceCase(scenarioWithBLOBs);
sendImportScenarioCreateNotice(scenarioWithBLOBs);
batchMapper.insert(scenarioWithBLOBs);
} else {
@ -1217,7 +1222,7 @@ public class ApiScenarioService {
scenarioWithBLOBs.setVersionId(apiTestImportRequest.getUpdateVersionId());
scenarioWithBLOBs.setOrder(existScenario.getOrder());
scenarioWithBLOBs.setNum(existScenario.getNum());
checkReferenceCase(scenarioWithBLOBs, apiTestCaseMapper, apiDefinitionMapper);
checkReferenceCase(scenarioWithBLOBs);
sendImportScenarioUpdateNotice(scenarioWithBLOBs);
batchMapper.updateByPrimaryKeyWithBLOBs(scenarioWithBLOBs);
}
@ -1227,7 +1232,7 @@ public class ApiScenarioService {
}
}
private ApiScenarioWithBLOBs importCreate(ApiScenarioWithBLOBs request, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, ApiTestImportRequest apiTestImportRequest, List<ApiScenarioWithBLOBs> sameList, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper) {
private ApiScenarioWithBLOBs importCreate(ApiScenarioWithBLOBs request, ApiScenarioMapper batchMapper, ExtApiScenarioMapper extApiScenarioMapper, ApiTestImportRequest apiTestImportRequest, List<ApiScenarioWithBLOBs> sameList) {
final ApiScenarioWithBLOBs scenarioWithBLOBs = new ApiScenarioWithBLOBs();
BeanUtils.copyBean(scenarioWithBLOBs, request);
scenarioWithBLOBs.setUpdateTime(System.currentTimeMillis());
@ -1270,8 +1275,9 @@ public class ApiScenarioService {
}
if (StringUtils.equals("fullCoverage", apiTestImportRequest.getModeId())) {
_importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper);
} else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
_importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest);
}
else if (StringUtils.equals("incrementalMerge", apiTestImportRequest.getModeId())) {
scenarioWithBLOBs.setId(UUID.randomUUID().toString());
scenarioWithBLOBs.setCreateTime(System.currentTimeMillis());
if (CollectionUtils.isEmpty(sameList)) {
@ -1296,7 +1302,7 @@ public class ApiScenarioService {
if (scenarioWithBLOBs.getRefId() == null) {
scenarioWithBLOBs.setRefId(scenarioWithBLOBs.getId());
}
checkReferenceCase(scenarioWithBLOBs, apiTestCaseMapper, apiDefinitionMapper);
checkReferenceCase(scenarioWithBLOBs);
sendImportScenarioCreateNotice(scenarioWithBLOBs);
batchMapper.insert(scenarioWithBLOBs);
// 存储依赖关系
@ -1310,7 +1316,7 @@ public class ApiScenarioService {
}
} else {
_importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest, apiTestCaseMapper, apiDefinitionMapper);
_importCreate(sameList, batchMapper, extApiScenarioMapper, scenarioWithBLOBs, apiTestImportRequest);
}
return scenarioWithBLOBs;
}
@ -1379,6 +1385,8 @@ public class ApiScenarioService {
request.setOpenCustomNum(config.getScenarioCustomNum());
}
Map<String, ApiDefinition> definitionMap = new HashMap<>();
Map<String, Set<String>> apiIdCaseNameMap = new HashMap<>();
for (int i = 0; i < data.size(); i++) {
ApiScenarioWithBLOBs item = data.get(i);
JSONObject jsonObject = JSONUtil.parseObject(JSON.toJSONString(item));
@ -1415,7 +1423,13 @@ public class ApiScenarioService {
item.setUserId(SessionUtils.getUserId());
item.setPrincipal(SessionUtils.getUserId());
// 导入之后刷新latest
importCreate(item, batchMapper, extApiScenarioMapper, request, sameList, apiTestCaseMapper, apiDefinitionMapper);
ApiScenarioWithBLOBs apiScenarioWithBLOBs = importCreate(item, batchMapper, extApiScenarioMapper, request, sameList);
JSONObject element = JSONUtil.parseObject(apiScenarioWithBLOBs.getScenarioDefinition());
JSONArray hashTree = element.optJSONArray(ElementConstants.HASH_TREE);
ApiScenarioImportUtil.formatHashTree(hashTree);
String projectId = apiScenarioWithBLOBs.getProjectId();
String versionId = apiScenarioWithBLOBs.getVersionId();
creatCase(apiTestCaseMapper, apiDefinitionMapper, definitionMap, hashTree, projectId, versionId,apiIdCaseNameMap);
if (i % 300 == 0) {
sqlSession.flushStatements();
}
@ -1427,6 +1441,24 @@ public class ApiScenarioService {
}
}
private void creatCase(ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper, Map<String, ApiDefinition> definitionMap, JSONArray hashTree, String projectId, String versionId,Map<String, Set<String>> apiIdCaseNameMap) {
if (hashTree==null) {
return;
}
for (int i = 0; i < hashTree.length(); i++) {
JSONObject object = (JSONObject) hashTree.get(i);
String referenced = object.optString("referenced");
if (StringUtils.isNotBlank(referenced) && StringUtils.equals(referenced, "REF")) {
// 检测引用对象是否存在若果不存在则改成复制对象
String refType = object.optString("refType");
if (StringUtils.isNotEmpty(refType) && refType.equals("CASE")) {
ApiScenarioImportUtil.checkCase(object, versionId, projectId, apiTestCaseMapper, apiDefinitionMapper, definitionMap,apiIdCaseNameMap);
}
}
creatCase(apiTestCaseMapper,apiDefinitionMapper,definitionMap,object.optJSONArray(ElementConstants.HASH_TREE), projectId,versionId, apiIdCaseNameMap);
}
}
private void replenishScenarioModuleIdPath(String request, ApiScenarioModuleMapper apiScenarioModuleMapper, ApiScenarioWithBLOBs item) {
ApiScenarioModuleExample example = new ApiScenarioModuleExample();
example.createCriteria().andProjectIdEqualTo(request).andNameEqualTo("未规划场景");
@ -2075,10 +2107,9 @@ public class ApiScenarioService {
return strings;
}
private void setReferenced(JSONArray hashTree, String versionId, String projectId, ApiTestCaseMapper apiTestCaseMapper, ApiDefinitionMapper apiDefinitionMapper, boolean isAdd) {
private void setReferenced(JSONArray hashTree, String projectId) {
// 将引用转成复制
if (hashTree != null) {
Map<String, ApiDefinition> definitionMap = new HashMap<>();
for (int i = 0; i < hashTree.length(); i++) {
JSONObject object = (JSONObject) hashTree.get(i);
String referenced = object.optString("referenced");
@ -2086,9 +2117,7 @@ public class ApiScenarioService {
// 检测引用对象是否存在若果不存在则改成复制对象
String refType = object.optString("refType");
if (StringUtils.isNotEmpty(refType)) {
if (refType.equals("CASE") && isAdd) {
ApiScenarioImportUtil.checkCase(i, object, versionId, projectId, apiTestCaseMapper, apiDefinitionMapper, definitionMap);
} else {
if (!refType.equals("CASE")){
checkAutomation(object);
object.put("projectId", projectId);
}
@ -2108,15 +2137,7 @@ public class ApiScenarioService {
if (environmentMap != null) {
object.put("environmentMap", new HashMap<>());
}
if (StringUtils.isNotEmpty(object.optString("refType")) && object.optString("refType").equals("CASE")) {
if (object.has(ElementConstants.HASH_TREE) && object.optJSONArray(ElementConstants.HASH_TREE) != null) {
setReferenced(object.optJSONArray(ElementConstants.HASH_TREE), versionId, projectId, apiTestCaseMapper, apiDefinitionMapper, true);
}
} else {
if (object.has(ElementConstants.HASH_TREE) && object.optJSONArray(ElementConstants.HASH_TREE) != null) {
setReferenced(object.optJSONArray(ElementConstants.HASH_TREE), versionId, projectId, apiTestCaseMapper, apiDefinitionMapper, false);
}
}
setReferenced(object.optJSONArray(ElementConstants.HASH_TREE), projectId);
}
}