From 6ec19ba73457cba56cc49bde7754b6b93adb35ab Mon Sep 17 00:00:00 2001 From: fit2-zhao Date: Tue, 20 Jun 2023 20:44:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E5=B1=82=E5=B5=8C=E5=A5=97=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E5=9C=BA=E6=99=AF=E7=A6=81=E7=94=A8=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=B8=8D=E7=94=9F=E6=95=88=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【[接口测试]github24932接口自动化,场景内引用多层级场景时,设置场景步骤为“禁用”状态会失效】https://www.tapd.cn/55049933/bugtrace/bugs/view?bug_id=1155049933001026993 Signed-off-by: fit2-zhao --- .../dto/definition/request/ElementUtil.java | 107 ++++++++------- .../dto/definition/request/MsScenario.java | 53 ++----- .../definition/request/ParameterConfig.java | 4 + .../request/sampler/MsDebugSampler.java | 4 + .../request/sampler/MsDubboSampler.java | 3 + .../request/sampler/MsHTTPSamplerProxy.java | 4 + .../request/sampler/MsJDBCSampler.java | 3 + .../request/sampler/MsTCPSampler.java | 3 + .../scenario/ApiScenarioExecuteService.java | 8 +- .../commons/constants/ElementConstants.java | 4 + .../commons/utils/GenerateHashTreeUtil.java | 4 + .../service/MsHashTreeService.java | 129 ++++++++++++------ .../ApiScenarioReportStructureService.java | 4 +- .../service/scenario/ApiScenarioService.java | 6 +- .../scenario/common/ApiBaseComponent.vue | 5 +- .../component/ApiScenarioComponent.vue | 1 + .../components/assertion/ApiAssertions.vue | 2 + .../definition/components/step/JmxStep.vue | 1 + 18 files changed, 208 insertions(+), 137 deletions(-) diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java index 630d03f4fc..ab6122b49e 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ElementUtil.java @@ -28,6 +28,7 @@ import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs; import io.metersphere.base.domain.FileMetadata; import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.commons.constants.ElementConstants; +import io.metersphere.commons.constants.MsHashTreeConstants; import io.metersphere.commons.constants.PropertyConstant; import io.metersphere.commons.constants.StorageConstants; import io.metersphere.commons.exception.MSException; @@ -68,7 +69,6 @@ import org.apache.jorphan.collections.HashTree; import org.json.JSONArray; import org.json.JSONObject; -import java.io.ByteArrayOutputStream; import java.io.File; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -82,6 +82,8 @@ public class ElementUtil { private static final String ASSERTIONS = ElementConstants.ASSERTIONS; private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR; private static final String TEST_BEAN_GUI = "TestBeanGUI"; + private final static String SCENARIO_REF = "SCENARIO-REF-STEP"; + public final static List scriptList = new ArrayList() {{ this.add(ElementConstants.JSR223); this.add(ElementConstants.JSR223_PRE); @@ -91,7 +93,6 @@ public class ElementUtil { public static final String CLAZZ = "clazzName"; - public static Map getEnvironmentConfig(String environmentId, String projectId) { BaseEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(BaseEnvironmentService.class); ApiTestEnvironmentWithBLOBs environment = apiTestEnvironmentService.get(environmentId); @@ -463,73 +464,74 @@ public class ElementUtil { } } - public static List mergeHashTree(List sourceHashTree, List targetHashTree) { + public static List mergeHashTree(List sources, List targets) { try { List sourceIds = new ArrayList<>(); List delIds = new ArrayList<>(); Map updateMap = new HashMap<>(); - - if (CollectionUtils.isNotEmpty(targetHashTree)) { - for (int i = 0; i < targetHashTree.size(); i++) { - JSONObject item = targetHashTree.get(i); - item.put("disabled", true); - if (StringUtils.isNotEmpty(item.optString("id"))) { - updateMap.put(item.optString("id"), item); + if (CollectionUtils.isNotEmpty(targets)) { + for (int i = 0; i < targets.size(); i++) { + JSONObject item = targets.get(i); + item.put(MsHashTreeConstants.DISABLED, true); + item.put(ElementConstants.REF_ENABLE, true); + if (StringUtils.isNotEmpty(item.optString(ElementConstants.ID))) { + updateMap.put(item.optString(ElementConstants.ID), item); } } } // 找出待更新内容和源已经被删除的内容 - if (CollectionUtils.isNotEmpty(sourceHashTree)) { - for (int i = 0; i < sourceHashTree.size(); i++) { - JSONObject source = sourceHashTree.get(i); - if (source != null) { - sourceIds.add(source.optString("id")); - if (!StringUtils.equals(source.optString("label"), "SCENARIO-REF-STEP") && StringUtils.isNotEmpty(source.optString("id"))) { - if (updateMap.containsKey(source.optString("id"))) { - sourceHashTree.set(i, updateMap.get(source.optString("id"))); - } else { - delIds.add(source.optString("id")); - } - } - // 历史数据兼容 - if (!source.has("id") && !StringUtils.equals(source.optString("label"), "SCENARIO-REF-STEP") && i < targetHashTree.size()) { - sourceHashTree.set(i, targetHashTree.get(i)); + if (CollectionUtils.isNotEmpty(sources)) { + for (int i = 0; i < sources.size(); i++) { + JSONObject object = sources.get(i); + if (object == null) { + continue; + } + sourceIds.add(object.optString(ElementConstants.ID)); + if (!StringUtils.equals(object.optString("label"), SCENARIO_REF) + && StringUtils.isNotEmpty(object.optString(ElementConstants.ID))) { + if (updateMap.containsKey(object.optString(ElementConstants.ID))) { + sources.set(i, updateMap.get(object.optString(ElementConstants.ID))); + updateMap.remove(object.optString(ElementConstants.ID)); + } else { + delIds.add(object.optString(ElementConstants.ID)); } } + // 历史数据兼容 + if (!object.has(ElementConstants.ID) + && !StringUtils.equals(object.optString("label"), SCENARIO_REF) + && i < targets.size()) { + sources.set(i, targets.get(i)); + } } } + // 添加少的步骤 + if (MapUtils.isNotEmpty(updateMap)) { + updateMap.forEach((k, v) -> { + sources.add(v); + }); + } + // 删除多余的步骤 - for (int i = 0; i < sourceHashTree.size(); i++) { - JSONObject source = sourceHashTree.get(i); - if (delIds.contains(source.optString("id"))) { - sourceHashTree.remove(i); + for (int i = 0; i < sources.size(); i++) { + JSONObject source = sources.get(i); + if (delIds.contains(source.optString(ElementConstants.ID))) { + sources.remove(i); } } // 补充新增的源引用步骤 - if (CollectionUtils.isNotEmpty(targetHashTree)) { - for (int i = 0; i < targetHashTree.size(); i++) { - JSONObject item = sourceHashTree.get(i); - if (!sourceIds.contains(item.optString("id"))) { - sourceHashTree.add(item); + if (CollectionUtils.isNotEmpty(targets)) { + for (int i = 0; i < targets.size(); i++) { + JSONObject item = sources.get(i); + if (!sourceIds.contains(item.optString(ElementConstants.ID))) { + sources.add(item); } } } } catch (Exception e) { - return targetHashTree; + return targets; } - return sourceHashTree; - } - - public static String hashTreeToString(HashTree hashTree) { - try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) { - SaveService.saveTree(hashTree, bas); - return bas.toString(); - } catch (Exception e) { - e.printStackTrace(); - io.metersphere.plugin.core.utils.LogUtil.warn("HashTree error, can't log jmx scenarioDefinition"); - } - return null; + return sources; } public static String getResourceId(String resourceId, ParameterConfig config, MsTestElement parent, String indexPath) { @@ -1170,4 +1172,15 @@ public class ElementUtil { return false; } + public static boolean isEnable(MsTestElement element, ParameterConfig config) { + String path = ElementUtil.getFullIndexPath(element, ""); + if (StringUtils.isNotBlank(path) && path.endsWith("_")) { + path = path.substring(0, path.length() - 1); + } + String key = StringUtils.join(element.getId(), "_", path); + if (config.getKeyMap().containsKey(key)) { + return config.getKeyMap().get(key); + } + return true; + } } diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index 11514045ba..410eecb04b 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -20,6 +20,7 @@ import io.metersphere.environment.service.BaseEnvironmentService; import io.metersphere.plugin.core.MsParameter; import io.metersphere.plugin.core.MsTestElement; import io.metersphere.service.MsHashTreeService; +import io.metersphere.utils.LoggerUtil; import lombok.Data; import lombok.EqualsAndHashCode; import org.apache.commons.collections.CollectionUtils; @@ -27,7 +28,6 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Arguments; import org.apache.jorphan.collections.HashTree; -import org.json.JSONArray; import org.json.JSONObject; import java.util.HashMap; @@ -72,7 +72,7 @@ public class MsScenario extends MsTestElement { if (this.getReferenced() != null && this.getReferenced().equals(MsTestElementConstants.Deleted.name())) { return; } else if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced()) - && !this.setRefScenario(hashTree)) { + && !this.setRefScenario(hashTree, config)) { return; } // 设置共享cookie @@ -137,6 +137,7 @@ public class MsScenario extends MsTestElement { } if ((this.variableEnable == null && this.mixEnable == null) || BooleanUtils.isTrue(this.variableEnable) || BooleanUtils.isTrue(this.mixEnable)) { + newConfig.setKeyMap(config.getKeyMap()); ElementUtil.addCsvDataSet(scenarioTree, variables, this.isEnvironmentEnable() ? newConfig : config, "shareMode.group"); ElementUtil.addCounter(scenarioTree, variables); ElementUtil.addRandom(scenarioTree, variables); @@ -205,13 +206,21 @@ public class MsScenario extends MsTestElement { } } - private boolean setRefScenario(List hashTree) { + private boolean setRefScenario(List hashTree, ParameterConfig config) { try { ApiScenarioMapper apiAutomationService = CommonBeanFactory.getBean(ApiScenarioMapper.class); ApiScenarioWithBLOBs scenario = apiAutomationService.selectByPrimaryKey(this.getId()); if (scenario != null && StringUtils.isNotEmpty(scenario.getScenarioDefinition())) { - JSONObject elementOrg = JSONUtil.parseObject(scenario.getScenarioDefinition()); - JSONObject element = setRefEnable(this, elementOrg); + JSONObject element = JSONUtil.parseObject(scenario.getScenarioDefinition()); + String path = ElementUtil.getFullIndexPath(this, ""); + if (path.endsWith("_")) { + path = path.substring(0, path.length() - 1); + } + element.put(MsHashTreeService.INDEX, path); + boolean enable = config.getKeyMap().get(this.getId() + "_" + path); + if (!enable) { + return false; + } // 历史数据处理 ElementUtil.dataFormatting(element.optJSONArray(ElementConstants.HASH_TREE)); this.setName(scenario.getName()); @@ -231,43 +240,11 @@ public class MsScenario extends MsTestElement { return true; } } catch (Exception ex) { - ex.printStackTrace(); + LoggerUtil.error(ex); } return false; } - public static JSONObject setRefEnable(MsTestElement targetElement, JSONObject orgElement) { - if (JSONObject.NULL.equals(orgElement) || targetElement == null) { - return orgElement; - } - if (!orgElement.optBoolean(MsHashTreeService.ENABLE)) { - orgElement.put(MsHashTreeService.ENABLE, false); - } else { - orgElement.put(MsHashTreeService.ENABLE, targetElement.isEnable()); - } - try { - if (orgElement.has(MsHashTreeService.HASH_TREE)) { - JSONArray orgJSONArray = orgElement.optJSONArray(MsHashTreeService.HASH_TREE); - LinkedList hashTree = targetElement.getHashTree(); - if (orgJSONArray != null && CollectionUtils.isNotEmpty(hashTree)) { - orgJSONArray.forEach(obj -> { - JSONObject orgJsonObject = (JSONObject) obj; - hashTree.forEach(targetObj -> { - if (StringUtils.equals(orgJsonObject.optString(MsHashTreeService.ID), targetObj.getId()) - && StringUtils.equals(orgJsonObject.optString(MsHashTreeService.INDEX), targetObj.getIndex())) { - setRefEnable(targetObj, orgJsonObject); - } - }); - }); - } - } - } catch (Exception ex) { - LogUtil.error(ex, ex.getMessage()); - return orgElement; - } - return orgElement; - } - private void setNewConfig(Map envConfig, ParameterConfig newConfig) { if (this.isEnvironmentEnable()) { ApiScenarioMapper apiScenarioMapper = CommonBeanFactory.getBean(ApiScenarioMapper.class); diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java index c240a89e7b..5757b6797d 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java @@ -102,6 +102,10 @@ public class ParameterConfig extends MsParameter { private List excludeScenarioIds = new ArrayList<>(); private List csvFilePaths = new ArrayList<>(); + /** + * 启用或禁用记录 + */ + private Map keyMap = new HashMap<>(); public boolean isEffective(String projectId) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDebugSampler.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDebugSampler.java index 563b223a5f..dcaa06ac8d 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDebugSampler.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDebugSampler.java @@ -1,5 +1,6 @@ package io.metersphere.api.dto.definition.request.sampler; +import io.metersphere.api.dto.definition.request.ElementUtil; import io.metersphere.api.dto.definition.request.ParameterConfig; import io.metersphere.commons.constants.ElementConstants; import io.metersphere.plugin.core.MsParameter; @@ -37,6 +38,9 @@ public class MsDebugSampler extends MsTestElement { if (!config.isOperating() && !this.isEnable()) { return; } + if (!ElementUtil.isEnable(this, config)) { + return; + } final HashTree groupTree = tree.add(debugSampler()); if (CollectionUtils.isNotEmpty(hashTree)) { hashTree.forEach(el -> { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDubboSampler.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDubboSampler.java index 62022dc873..88d43bc1f5 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDubboSampler.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsDubboSampler.java @@ -71,6 +71,9 @@ public class MsDubboSampler extends MsTestElement { if (this.getReferenced() != null && "Deleted".equals(this.getReferenced())) { return; } + if (!ElementUtil.isEnable(this, config)) { + return; + } if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { boolean ref = this.setRefElement(); if (!ref) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java index e3a0c5d333..47b9dc8ec0 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsHTTPSamplerProxy.java @@ -96,12 +96,16 @@ public class MsHTTPSamplerProxy extends MsTestElement { if (StringUtils.isEmpty(this.getEnvironmentId())) { this.setEnvironmentId(this.useEnvironment); } + // 非导出操作,且不是启用状态则跳过执行Ms if (!config.isOperating() && !this.isEnable()) { return; } else if (config.isOperating() && StringUtils.isNotEmpty(config.getOperatingSampleTestName())) { this.setName(config.getOperatingSampleTestName()); } + if (!ElementUtil.isEnable(this, config)) { + return; + } if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { boolean ref = this.setRefElement(); if (!ref) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java index acd5b0ee50..a9e6727135 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsJDBCSampler.java @@ -66,6 +66,9 @@ public class MsJDBCSampler extends MsTestElement { } else if (config.isOperating() && StringUtils.isNotEmpty(config.getOperatingSampleTestName())) { this.setName(config.getOperatingSampleTestName()); } + if (!ElementUtil.isEnable(this, config)) { + return; + } if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { boolean ref = this.setRefElement(); if (!ref) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java index d16b6d67d0..d6f9e3f884 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/definition/request/sampler/MsTCPSampler.java @@ -90,6 +90,9 @@ public class MsTCPSampler extends MsTestElement { } else if (config.isOperating() && StringUtils.isNotEmpty(config.getOperatingSampleTestName())) { this.setName(config.getOperatingSampleTestName()); } + if (!ElementUtil.isEnable(this, config)) { + return; + } if (this.getReferenced() != null && MsTestElementConstants.REF.name().equals(this.getReferenced())) { boolean ref = this.setRefElement(); if (!ref) { diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java index 6f082832a2..79bba25f94 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java @@ -34,10 +34,7 @@ import io.metersphere.dto.*; import io.metersphere.environment.service.BaseEnvGroupProjectService; import io.metersphere.i18n.Translator; import io.metersphere.plugin.core.MsTestElement; -import io.metersphere.service.ApiExecutionQueueService; -import io.metersphere.service.RedisTemplateService; -import io.metersphere.service.ServiceUtils; -import io.metersphere.service.SystemParameterService; +import io.metersphere.service.*; import io.metersphere.service.definition.TcpApiParamService; import io.metersphere.service.scenario.ApiScenarioReportService; import io.metersphere.service.scenario.ApiScenarioReportStructureService; @@ -451,6 +448,9 @@ public class ApiScenarioExecuteService { uploadBodyFiles(request.getBodyFileRequestIds(), bodyFiles); FileUtils.createBodyFiles(request.getScenarioFileIds(), scenarioFiles); this.testElement(request); + Map keyMap = MsHashTreeService.getIndexKeyMap(request.getTestElement(), ""); + config.setKeyMap(keyMap); + HashTree hashTree = request.getTestElement().generateHashTree(config); String runMode = StringUtils.isEmpty(request.getRunMode()) ? ApiRunMode.SCENARIO.name() : request.getRunMode(); JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(request.getId(), request.getId(), runMode, hashTree); diff --git a/api-test/backend/src/main/java/io/metersphere/commons/constants/ElementConstants.java b/api-test/backend/src/main/java/io/metersphere/commons/constants/ElementConstants.java index 3552237fc5..9ecdcf8366 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/constants/ElementConstants.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/constants/ElementConstants.java @@ -31,6 +31,10 @@ public class ElementConstants { public static final String ASSERTIONS = "Assertions"; public static final String EXTRACT = "Extract"; public static final String STEP_CREATED = "Created"; + public static final String INDEX = "index"; + public static final String ID = "id"; + public static final String REF_ENABLE = "refEnable"; + public final static List REQUESTS = new ArrayList() {{ this.add(ElementConstants.HTTP_SAMPLER); this.add(ElementConstants.DUBBO_SAMPLER); diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java index b749f942f9..dfd2863f27 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/GenerateHashTreeUtil.java @@ -20,6 +20,7 @@ import io.metersphere.dto.ProjectJarConfig; import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.environment.service.BaseEnvGroupProjectService; import io.metersphere.plugin.core.MsTestElement; +import io.metersphere.service.MsHashTreeService; import io.metersphere.utils.LoggerUtil; import io.metersphere.vo.BooleanPool; import org.apache.commons.collections.MapUtils; @@ -159,6 +160,9 @@ public class GenerateHashTreeUtil { if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) { config.setRetryNum(runRequest.getRetryNum()); } + + Map keyMap = MsHashTreeService.getIndexKeyMap(element, ""); + config.setKeyMap(keyMap); testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config); LoggerUtil.info("场景资源:" + item.getName() + ", 生成执行脚本JMX成功", runRequest.getReportId()); diff --git a/api-test/backend/src/main/java/io/metersphere/service/MsHashTreeService.java b/api-test/backend/src/main/java/io/metersphere/service/MsHashTreeService.java index 8d82a88a78..9a926a6fd6 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/MsHashTreeService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/MsHashTreeService.java @@ -19,15 +19,18 @@ import io.metersphere.commons.utils.JSON; import io.metersphere.commons.utils.JSONUtil; import io.metersphere.commons.utils.LogUtil; import io.metersphere.dto.ProjectConfig; +import io.metersphere.plugin.core.MsTestElement; import io.metersphere.service.definition.ApiDefinitionService; import io.metersphere.service.definition.ApiTestCaseService; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.stereotype.Service; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -97,6 +100,8 @@ public class MsHashTreeService { private static final String DATASOURCEID = "dataSourceId"; private static final String RESULT_VARIABLE = "resultVariable"; private static final String ENV_Id = "environmentId"; + private static final String PARENT_INDEX = "parentIndex"; + private final static String JSON_PATH="jsonPath"; private final static String JSR223="jsr223"; @@ -310,7 +315,7 @@ public class MsHashTreeService { } } - private JSONObject setRefScenario(JSONObject element) { + private JSONObject setRefScenario(JSONObject element, Map keyMap) { boolean enable = element.has(ENABLE) ? element.optBoolean(ENABLE) : true; if (!element.has(MIX_ENABLE)) { element.put(MIX_ENABLE, false); @@ -327,7 +332,21 @@ public class MsHashTreeService { element.put(ENV_MAP, JSON.parseObject(scenarioWithBLOBs.getEnvironmentJson(), Map.class)); } if (StringUtils.equalsIgnoreCase(element.optString(REFERENCED), REF)) { - element = setRefEnable(element, JSONUtil.parseObject(scenarioWithBLOBs.getScenarioDefinition())); + JSONObject object = JSONUtil.parseObject(scenarioWithBLOBs.getScenarioDefinition()); + object.put(PARENT_INDEX, element.optString(PARENT_INDEX)); + object.put(INDEX, element.optString(INDEX)); + if (object.has(ENABLE) && BooleanUtils.isFalse(object.optBoolean(ENABLE))) { + enable = false; + object.put(REF_ENABLE, true); + } else { + String indexStr = object.has(PARENT_INDEX) && StringUtils.isNotBlank(object.optString(PARENT_INDEX)) ? + StringUtils.join(object.optString(PARENT_INDEX), "_", object.optString(INDEX)) : object.optString(INDEX); + if (keyMap.containsKey(element.optString(ID) + indexStr)) { + enable = keyMap.get(element.optString(ID) + indexStr); + object.put(ENABLE, enable); + } + } + element = object; element.put(REFERENCED, REF); element.put(NAME, scenarioWithBLOBs.getName()); } @@ -354,69 +373,76 @@ public class MsHashTreeService { return element; } - public static JSONObject setRefEnable(JSONObject targetElement, JSONObject orgElement) { - if (orgElement == null || targetElement == null) { - return orgElement; + public static Map getIndexKeyMap(JSONObject element, String parentIndex) { + Map indexKeyMap = new HashMap<>(); + StringBuilder builder = new StringBuilder(parentIndex); + if (element.has(ENABLE) && element.has(ID) && element.has(INDEX)) { + builder.append("_").append(element.getString(INDEX)); + String key = StringUtils.join(element.optString(ID), builder.toString()); + indexKeyMap.put(key, element.optBoolean(ENABLE)); } - if (!orgElement.optBoolean(ENABLE)) { - orgElement.put(ENABLE, false); - orgElement.put(REF_ENABLE, true); - } else { - orgElement.put(ENABLE, targetElement.optBoolean(ENABLE)); + if (element.has(HASH_TREE)) { + element.getJSONArray(HASH_TREE).forEach(item -> { + JSONObject obj = (JSONObject) item; + indexKeyMap.putAll(getIndexKeyMap(obj, builder.toString())); + }); } - if (targetElement.optBoolean(REF_ENABLE)) { - orgElement.put(REF_ENABLE, targetElement.optBoolean(REF_ENABLE)); - } - try { - if (orgElement.has(HASH_TREE)) { - JSONArray org = orgElement.optJSONArray(HASH_TREE); - JSONArray target = targetElement.optJSONArray(HASH_TREE); - if (org != null && target != null) { - org.forEach(obj -> { - JSONObject childOrg = (JSONObject) obj; - target.forEach(targetObj -> { - JSONObject childTarget = (JSONObject) targetObj; - if (StringUtils.equals(childOrg.optString(ID), childTarget.optString(ID)) - && StringUtils.equals(childOrg.optString(INDEX), childTarget.optString(INDEX))) { - setRefEnable(childTarget, childOrg); - } - }); - }); - } - } - } catch (Exception e) { - LogUtil.error(e, e.getMessage()); - return orgElement; - } - return orgElement; + return indexKeyMap; } - public void dataFormatting(JSONArray hashTree, List caseIds) { + public void dataFormatting(JSONArray hashTree, List caseIds, Map keyMap, String parentIndex) { for (int i = 0; i < hashTree.length(); i++) { JSONObject element = hashTree.optJSONObject(i); + // 设置父级索引 + element.put(PARENT_INDEX, parentIndex); + if (element != null && StringUtils.equalsIgnoreCase(element.optString(TYPE), SCENARIO)) { - element = this.setRefScenario(element); + element = this.setRefScenario(element, keyMap); hashTree.put(i, element); } else if (element != null && ElementConstants.REQUESTS.contains(element.optString(TYPE))) { + setCaseEnable(element, keyMap, parentIndex); this.getCaseIds(element, caseIds); hashTree.put(i, element); } if (element.has(HASH_TREE)) { JSONArray elementJSONArray = element.optJSONArray(HASH_TREE); - dataFormatting(elementJSONArray, caseIds); + String indexStr = StringUtils.join(parentIndex, "_", element.optString(INDEX)); + dataFormatting(elementJSONArray, caseIds, keyMap, indexStr); } } } - public void dataFormatting(JSONObject element, List caseIds) { - if (element != null && StringUtils.equalsIgnoreCase(element.optString(TYPE), SCENARIO)) { - element = this.setRefScenario(element); - } else if (element != null && ElementConstants.REQUESTS.contains(element.optString(TYPE))) { + public void dataFormatting(JSONObject element, List caseIds, Map keyMap) { + if (element == null) { + return; + } + // 设置父级索引 + String parentIndex = element.has(PARENT_INDEX) ? + StringUtils.join(element.optString(PARENT_INDEX), "_", element.optString(INDEX)) + : element.optString(INDEX); + + element.put(PARENT_INDEX, parentIndex); + if (StringUtils.equalsIgnoreCase(element.optString(TYPE), SCENARIO)) { + element = this.setRefScenario(element, keyMap); + } else if (ElementConstants.REQUESTS.contains(element.optString(TYPE))) { + setCaseEnable(element, keyMap, parentIndex); this.getCaseIds(element, caseIds); } - if (element != null && element.has(HASH_TREE)) { + if (element.has(HASH_TREE)) { JSONArray elementJSONArray = element.optJSONArray(HASH_TREE); - dataFormatting(elementJSONArray, caseIds); + dataFormatting(elementJSONArray, caseIds, keyMap, parentIndex); + } + } + + private void setCaseEnable(JSONObject element, Map keyMap, String parentIndex) { + if (element.has(ENABLE) && BooleanUtils.isFalse(element.optBoolean(ENABLE))) { + element.put(ENABLE, false); + element.put(REF_ENABLE, true); + } else { + String indexStr = StringUtils.join(element.optString(ID), parentIndex, "_", element.optString(INDEX)); + if (keyMap.containsKey(indexStr)) { + element.put(ENABLE, keyMap.get(indexStr)); + } } } @@ -447,4 +473,19 @@ public class MsHashTreeService { } } + public static Map getIndexKeyMap(MsTestElement element, String parentIndex) { + Map indexKeyMap = new HashMap<>(); + StringBuilder builder = new StringBuilder(parentIndex); + if (StringUtils.isNotBlank(element.getId()) && StringUtils.isNotBlank(element.getIndex())) { + builder.append("_").append(element.getIndex()); + String key = StringUtils.join(element.getId(), builder.toString()); + indexKeyMap.put(key, element.isEnable()); + } + if (CollectionUtils.isNotEmpty(element.getHashTree())) { + element.getHashTree().forEach(item -> { + indexKeyMap.putAll(getIndexKeyMap(item, builder.toString())); + }); + } + return indexKeyMap; + } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java index 75bec28e4d..ee171a534c 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioReportStructureService.java @@ -168,7 +168,9 @@ public class ApiScenarioReportStructureService { MsHashTreeService hashTreeService = CommonBeanFactory.getBean(MsHashTreeService.class); assert hashTreeService != null; List caseIds = new ArrayList<>(); - hashTreeService.dataFormatting(element, caseIds); + Map keyMap = MsHashTreeService.getIndexKeyMap(element,element.optString(ElementConstants.INDEX)); + + hashTreeService.dataFormatting(element, caseIds, keyMap); // 处理用例 hashTreeService.caseFormatting(element, caseIds, null); diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java index 47649f6777..a293c21b1d 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java @@ -757,7 +757,8 @@ public class ApiScenarioService { if (StringUtils.isNotEmpty(scenarioWithBLOBs.getScenarioDefinition())) { JSONObject element = JSONUtil.parseObject(scenarioWithBLOBs.getScenarioDefinition()); List caseIds = new ArrayList<>(); - hashTreeService.dataFormatting(element, caseIds); + Map keyMap = MsHashTreeService.getIndexKeyMap(element, element.optString(ElementConstants.INDEX)); + hashTreeService.dataFormatting(element, caseIds, keyMap); // 处理用例 hashTreeService.caseFormatting(element, caseIds, getConfig(scenarioWithBLOBs)); ElementUtil.dataFormatting(element); @@ -885,7 +886,8 @@ public class ApiScenarioService { JSONObject element = JSONUtil.parseObject(dto.getScenarioDefinition()); // 获取所有case List caseIds = new ArrayList<>(); - hashTreeService.dataFormatting(element, caseIds); + Map keyMap = MsHashTreeService.getIndexKeyMap(element, element.optString(ElementConstants.INDEX)); + hashTreeService.dataFormatting(element, caseIds, keyMap); // 处理用例 hashTreeService.caseFormatting(element, caseIds, null); diff --git a/api-test/frontend/src/business/automation/scenario/common/ApiBaseComponent.vue b/api-test/frontend/src/business/automation/scenario/common/ApiBaseComponent.vue index b815c9bec6..c852824374 100644 --- a/api-test/frontend/src/business/automation/scenario/common/ApiBaseComponent.vue +++ b/api-test/frontend/src/business/automation/scenario/common/ApiBaseComponent.vue @@ -81,7 +81,7 @@ v-model="data.enable" class="enable-switch" size="mini" - :disabled="data.refEnable || !showVersion || isDeleted" /> + :disabled="data.refEnable || !showVersion || isDeleted || isEnabled()" /> @@ -16,6 +17,7 @@ diff --git a/api-test/frontend/src/business/definition/components/step/JmxStep.vue b/api-test/frontend/src/business/definition/components/step/JmxStep.vue index 01600d447d..d9c78cf6be 100644 --- a/api-test/frontend/src/business/definition/components/step/JmxStep.vue +++ b/api-test/frontend/src/business/definition/components/step/JmxStep.vue @@ -10,6 +10,7 @@