fix(接口测试): 修复修改case的前后置操作,测试计划执行未同步的缺陷

--bug=1028019 --user=王孝刚 【测试跟踪】github#25703,测试计划关联场景,场景中引用了case, case
修改,测试计划执行未同步更新 https://www.tapd.cn/55049933/s/1397246
This commit is contained in:
wxg0103 2023-07-25 19:28:30 +08:00 committed by fit2-zhao
parent 7c3e5b7d02
commit c57c49da6c
1 changed files with 125 additions and 55 deletions

View File

@ -74,11 +74,9 @@ import java.io.File;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public class ElementUtil { public class ElementUtil {
private static final String PRE = "PRE"; private static final String PRE = "PRE";
@ -443,51 +441,126 @@ public class ElementUtil {
element.setHashTree(targetHashTree); element.setHashTree(targetHashTree);
return; return;
} }
// 合并步骤 Map<String, LinkedList<MsTestElement>> source = groupCase(element.getHashTree());
List<MsTestElement> sourceList = Stream.of(element.getHashTree(), targetHashTree) Map<String, LinkedList<MsTestElement>> target = groupCase(targetHashTree);
.flatMap(Collection::stream) List<MsTestElement> pre = ElementUtil.mergeCaseHashTree(source.get(PRE), target.get(PRE));
.distinct() List<MsTestElement> post = ElementUtil.mergeCaseHashTree(source.get(POST), target.get(POST));
.collect(Collectors.toList()); List<MsTestElement> rules = mergeCaseHashTree(source.get(ASSERTIONS), target.get(ASSERTIONS));
List<MsTestElement> step = new LinkedList<>();
// 历史数据补充id if (CollectionUtils.isNotEmpty(pre)) {
sourceList.forEach(item -> { step.addAll(pre);
if (StringUtils.isBlank(item.getId())) {
item.setId(UUID.randomUUID().toString());
} }
}); if (CollectionUtils.isNotEmpty(post)) {
step.addAll(post);
//对sourceList根据id去重并且保持原有顺序
sourceList = sourceList.stream()
.collect(Collectors.toMap(MsTestElement::getId, Function.identity(), (oldValue, newValue) -> oldValue, LinkedHashMap::new))
.values()
.stream()
.collect(Collectors.toList());
//删除不需要的元素
for (int i = 0; i < sourceList.size(); i++) {
MsTestElement item = sourceList.get(i);
if (!StringUtils.equals(item.getLabel(), SCENARIO_REF)
&& targetHashTree.stream().noneMatch(target -> StringUtils.equals(target.getId(), item.getId()))) {
sourceList.remove(i);
} }
if (CollectionUtils.isNotEmpty(rules)) {
step.addAll(rules);
} }
element.getHashTree().clear(); element.getHashTree().clear();
element.getHashTree().addAll(sourceList); element.getHashTree().addAll(step);
} catch (Exception e) { } catch (Exception e) {
element.setHashTree(targetHashTree); element.setHashTree(targetHashTree);
} }
} }
public static List<JSONObject> mergeHashTree(List<JSONObject> sources, List<JSONObject> targets) { public static Map<String, LinkedList<MsTestElement>> groupCase(List<MsTestElement> elements) {
Map<String, LinkedList<MsTestElement>> groupMap = new LinkedHashMap<>();
if (elements != null) {
for (int i = 0; i < elements.size(); i++) {
MsTestElement item = elements.get(i);
if (ElementConstants.ASSERTIONS.equals(item.getType())) {
if (groupMap.containsKey(ASSERTIONS)) {
groupMap.get(ASSERTIONS).add(item);
} else {
groupMap.put(ASSERTIONS, new LinkedList<MsTestElement>() {{
this.add(item);
}});
}
} else if (preOperates.contains(item.getType())) {
if (groupMap.containsKey(PRE)) {
groupMap.get(PRE).add(item);
} else {
groupMap.put(PRE, new LinkedList<MsTestElement>() {{
this.add(item);
}});
}
} else if (postOperates.contains(item.getType())) {
if (groupMap.containsKey(POST)) {
groupMap.get(POST).add(item);
} else {
groupMap.put(POST, new LinkedList<MsTestElement>() {{
this.add(item);
}});
}
}
}
}
return groupMap;
}
public static List<MsTestElement> mergeCaseHashTree(List<MsTestElement> targets, List<MsTestElement> sources) {
try {
List<String> sourceIds = new ArrayList<>();
List<String> delIds = new ArrayList<>();
Map<String, MsTestElement> updateMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(sources)) {
for (int i = 0; i < sources.size(); i++) {
MsTestElement msTestElement = sources.get(i);
if (StringUtils.isNotEmpty(msTestElement.getId())) {
updateMap.put(msTestElement.getId(), msTestElement);
}
}
}
// 找出待更新内容和源已经被删除的内容
if (CollectionUtils.isNotEmpty(targets)) {
for (int i = 0; i < targets.size(); i++) {
MsTestElement msTestElement = targets.get(i);
if (msTestElement == null) {
continue;
}
sourceIds.add(msTestElement.getId());
if (!StringUtils.equals(msTestElement.getLabel(), SCENARIO_REF)
&& StringUtils.isNotEmpty(msTestElement.getId())) {
if (updateMap.containsKey(msTestElement.getId())) {
targets.set(i, updateMap.get(msTestElement.getId()));
updateMap.remove(msTestElement.getId());
} else {
delIds.add(msTestElement.getId());
}
}
}
}
// 删除多余的步骤 delIds中包含的全都干掉
targets.removeIf(msTestElement -> delIds.contains(msTestElement.getId()));
// 补充新增的源引用步骤
if (CollectionUtils.isNotEmpty(sources)) {
for (int i = 0; i < sources.size(); i++) {
MsTestElement msTestElement = sources.get(i);
if (!sourceIds.contains(msTestElement.getId())) {
targets.add(msTestElement);
}
}
}
} catch (Exception e) {
return sources;
}
//根据index排序
targets.sort(Comparator.comparing(MsTestElement::getIndex));
return targets;
}
public static List<JSONObject> mergeHashTree(List<JSONObject> targets, List<JSONObject> sources) {
try { try {
List<String> sourceIds = new ArrayList<>(); List<String> sourceIds = new ArrayList<>();
List<String> delIds = new ArrayList<>(); List<String> delIds = new ArrayList<>();
Map<String, JSONObject> updateMap = new HashMap<>(); Map<String, JSONObject> updateMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(targets)) { if (CollectionUtils.isNotEmpty(sources)) {
for (int i = 0; i < targets.size(); i++) { for (int i = 0; i < sources.size(); i++) {
JSONObject item = targets.get(i); JSONObject item = sources.get(i);
item.put(MsHashTreeConstants.DISABLED, true); item.put(MsHashTreeConstants.DISABLED, true);
item.put(ElementConstants.REF_ENABLE, true); item.put(ElementConstants.REF_ENABLE, true);
if (StringUtils.isNotEmpty(item.optString(ElementConstants.ID))) { if (StringUtils.isNotEmpty(item.optString(ElementConstants.ID))) {
@ -496,9 +569,9 @@ public class ElementUtil {
} }
} }
// 找出待更新内容和源已经被删除的内容 // 找出待更新内容和源已经被删除的内容
if (CollectionUtils.isNotEmpty(sources)) { if (CollectionUtils.isNotEmpty(targets)) {
for (int i = 0; i < sources.size(); i++) { for (int i = 0; i < targets.size(); i++) {
JSONObject object = sources.get(i); JSONObject object = targets.get(i);
if (object == null) { if (object == null) {
continue; continue;
} }
@ -506,7 +579,7 @@ public class ElementUtil {
if (!StringUtils.equals(object.optString("label"), SCENARIO_REF) if (!StringUtils.equals(object.optString("label"), SCENARIO_REF)
&& StringUtils.isNotEmpty(object.optString(ElementConstants.ID))) { && StringUtils.isNotEmpty(object.optString(ElementConstants.ID))) {
if (updateMap.containsKey(object.optString(ElementConstants.ID))) { if (updateMap.containsKey(object.optString(ElementConstants.ID))) {
sources.set(i, updateMap.get(object.optString(ElementConstants.ID))); targets.set(i, updateMap.get(object.optString(ElementConstants.ID)));
updateMap.remove(object.optString(ElementConstants.ID)); updateMap.remove(object.optString(ElementConstants.ID));
} else { } else {
delIds.add(object.optString(ElementConstants.ID)); delIds.add(object.optString(ElementConstants.ID));
@ -515,33 +588,29 @@ public class ElementUtil {
// 历史数据兼容 // 历史数据兼容
if (!object.has(ElementConstants.ID) if (!object.has(ElementConstants.ID)
&& !StringUtils.equals(object.optString("label"), SCENARIO_REF) && !StringUtils.equals(object.optString("label"), SCENARIO_REF)
&& i < targets.size()) { && i < sources.size()) {
sources.set(i, targets.get(i)); targets.set(i, sources.get(i));
} }
} }
} }
// 删除多余的步骤 // 删除多余的步骤
for (int i = 0; i < sources.size(); i++) { targets.removeIf(msTestElement -> delIds.contains(msTestElement.optString(ElementConstants.ID)));
JSONObject source = sources.get(i);
if (delIds.contains(source.optString(ElementConstants.ID))) {
sources.remove(i);
}
}
// 补充新增的源引用步骤 // 补充新增的源引用步骤
if (CollectionUtils.isNotEmpty(targets)) { if (CollectionUtils.isNotEmpty(sources)) {
for (int i = 0; i < targets.size(); i++) { for (int i = 0; i < sources.size(); i++) {
JSONObject item = sources.get(i); JSONObject item = sources.get(i);
if (!sourceIds.contains(item.optString(ElementConstants.ID))) { if (!sourceIds.contains(item.optString(ElementConstants.ID))) {
sources.add(item); targets.add(item);
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
return targets;
}
return sources; return sources;
} }
return targets;
}
public static String getResourceId(String resourceId, ParameterConfig config, MsTestElement parent, String indexPath) { public static String getResourceId(String resourceId, ParameterConfig config, MsTestElement parent, String indexPath) {
if (StringUtils.isNotEmpty(config.getScenarioId()) && StringUtils.equals(config.getReportType(), RunModeConstants.SET_REPORT.toString())) { if (StringUtils.isNotEmpty(config.getScenarioId()) && StringUtils.equals(config.getReportType(), RunModeConstants.SET_REPORT.toString())) {
@ -748,7 +817,7 @@ public class ElementUtil {
.filter(ScenarioVariable::isConstantValid).forEach(keyValue -> .filter(ScenarioVariable::isConstantValid).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), arguments.addArgument(keyValue.getName(),
StringUtils.isNotBlank(keyValue.getValue()) StringUtils.isNotBlank(keyValue.getValue())
? keyValue.getValue().replaceAll("[\r\n]","") : keyValue.getValue(), "=")); ? keyValue.getValue().replaceAll("[\r\n]", "") : keyValue.getValue(), "="));
List<ScenarioVariable> variableList = variables.stream() List<ScenarioVariable> variableList = variables.stream()
.filter(ScenarioVariable::isListValid).collect(Collectors.toList()); .filter(ScenarioVariable::isListValid).collect(Collectors.toList());
variableList.forEach(item -> { variableList.forEach(item -> {
@ -772,7 +841,7 @@ public class ElementUtil {
keyValue.getValue() != null && keyValue.getValue().startsWith("@") keyValue.getValue() != null && keyValue.getValue().startsWith("@")
? ScriptEngineUtils.buildFunctionCallString(keyValue.getValue()) ? ScriptEngineUtils.buildFunctionCallString(keyValue.getValue())
: (StringUtils.isNotBlank(keyValue.getValue()) : (StringUtils.isNotBlank(keyValue.getValue())
? keyValue.getValue().replaceAll("[\r\n]","") ? keyValue.getValue().replaceAll("[\r\n]", "")
: keyValue.getValue()), "=")); : keyValue.getValue()), "="));
// List类型的变量 // List类型的变量
List<ScenarioVariable> variableList = config.getConfig().get(projectId).getCommonConfig().getVariables().stream() List<ScenarioVariable> variableList = config.getConfig().get(projectId).getCommonConfig().getVariables().stream()
@ -1183,13 +1252,14 @@ public class ElementUtil {
} }
return false; return false;
} }
@NotNull @NotNull
public static List<String> getProjectIds(String scenarioDefinition) { public static List<String> getProjectIds(String scenarioDefinition) {
Pattern pattern = Pattern.compile("\"projectId\"\\s*:\\s*\"?([^\"]*)\"?,"); Pattern pattern = Pattern.compile("\"projectId\"\\s*:\\s*\"?([^\"]*)\"?,");
Matcher matcher = pattern.matcher(scenarioDefinition); Matcher matcher = pattern.matcher(scenarioDefinition);
List<String> projectIdLists = new ArrayList<>(); List<String> projectIdLists = new ArrayList<>();
while (matcher.find()) { while (matcher.find()) {
if (!projectIdLists.contains(matcher.group(1))){ if (!projectIdLists.contains(matcher.group(1))) {
projectIdLists.add(matcher.group(1)); projectIdLists.add(matcher.group(1));
} }
} }