diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index e1859be01d..7b7ac7c1cc 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -29,6 +29,7 @@ import io.metersphere.service.EnvironmentGroupProjectService; import lombok.Data; import lombok.EqualsAndHashCode; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Arguments; import org.apache.jmeter.protocol.http.control.Header; @@ -78,6 +79,9 @@ public class MsScenario extends MsTestElement { @JSONField(ordinal = 30) private Boolean variableEnable; + @JSONField(ordinal = 31) + private Boolean mixEnable; + private static final String BODY_FILE_DIR = FileUtils.BODY_FILE_DIR; public MsScenario() { @@ -127,7 +131,8 @@ public class MsScenario extends MsTestElement { } } } - if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) { + + if (CollectionUtils.isNotEmpty(this.getVariables()) && (this.variableEnable == null || this.variableEnable)) { config.setVariables(this.variables); } HashTree scenarioTree = tree; @@ -144,12 +149,19 @@ public class MsScenario extends MsTestElement { if (config != null && !config.getExcludeScenarioIds().contains(this.getId())) { scenarioTree = MsCriticalSectionController.createHashTree(tree, this.getName(), this.isEnable()); } + // 启用当前场景变量优先选择 + if ((mixEnable == null || BooleanUtils.isTrue(mixEnable)) + && (this.variableEnable == null || BooleanUtils.isFalse(this.variableEnable))) { + config.margeVariables(this.variables, config.getTransferVariables()); + } + // 环境变量 Arguments arguments = arguments(this.isEnvironmentEnable() ? newConfig : config); - if (arguments != null && (this.variableEnable == null || this.variableEnable)) { + if (arguments != null && ((this.variableEnable == null || this.variableEnable) + || (this.mixEnable == null || this.mixEnable))) { Arguments valueSupposeMock = ParameterConfig.valueSupposeMock(arguments); // 这里加入自定义变量解决ForEach循环控制器取值问题,循环控制器无法从vars中取值 - if (this.variableEnable != null && this.variableEnable) { + if ((this.variableEnable == null || this.variableEnable) || (this.mixEnable == null || this.mixEnable)) { scenarioTree.add(ElementUtil.argumentsToUserParameters(valueSupposeMock)); } else { scenarioTree.add(valueSupposeMock); @@ -167,6 +179,7 @@ public class MsScenario extends MsTestElement { } } } + // 添加全局前置 this.setGlobProcessor(this.isEnvironmentEnable() ? newConfig : config, scenarioTree, true); diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java index e52a7c406e..dd80c18f0f 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/ParameterConfig.java @@ -21,10 +21,12 @@ import io.metersphere.plugin.core.MsTestElement; import io.metersphere.track.service.TestPlanApiCaseService; import lombok.Data; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.config.Arguments; import java.util.*; +import java.util.stream.Collectors; @Data public class ParameterConfig extends MsParameter { @@ -138,7 +140,7 @@ public class ParameterConfig extends MsParameter { } else { apiDefinition = apiDefinitionService.get(samplerProxy.getId()); // 兼容导入数据 - if(apiDefinition == null ){ + if (apiDefinition == null) { apiDefinition = apiDefinitionService.get(samplerProxy.getName()); } ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(samplerProxy.getId()); @@ -249,4 +251,45 @@ public class ParameterConfig extends MsParameter { } return null; } + + public void margeVariables(List variables, List transferVariables) { + if (CollectionUtils.isNotEmpty(transferVariables)) { + List constants = variables.stream().filter(ScenarioVariable::isConstantValid).collect(Collectors.toList()); + Map> transferVariableGroup = + transferVariables.stream().collect(Collectors.groupingBy(ScenarioVariable::getName, LinkedHashMap::new, Collectors.toList())); + Map> constantsGroup = + constants.stream().collect(Collectors.groupingBy(ScenarioVariable::getName, LinkedHashMap::new, Collectors.toList())); + // 更新相同名称的值 + for (ScenarioVariable constant : constants) { + if (transferVariableGroup.containsKey(constant.getName()) + && CollectionUtils.isNotEmpty(transferVariableGroup.get(constant.getName()))) { + constant.setValue(transferVariableGroup.get(constant.getName()).get(0).getValue()); + } + } + // 添加当前没有的值 + transferVariables.forEach(item -> { + if (!constantsGroup.containsKey(item.getName())) { + variables.add(item); + } + }); + } + } + + public void margeParentVariables(List variables, MsTestElement parent) { + // 取出父级场景且父场景不是顶级场景 + MsScenario scenario = getScenario(parent); + if (scenario == null || BooleanUtils.isFalse(scenario.getMixEnable()) || CollectionUtils.isEmpty(scenario.getVariables())) { + return; + } + this.margeVariables(variables, scenario.getVariables()); + } + + private MsScenario getScenario(MsTestElement parent) { + if (parent != null && parent instanceof MsScenario) { + return parent.getParent() != null ? (MsScenario) parent : null; + } else if (parent != null && parent.getParent() != null) { + getScenario(parent.getParent()); + } + return null; + } } diff --git a/backend/src/main/java/io/metersphere/api/service/MsHashTreeService.java b/backend/src/main/java/io/metersphere/api/service/MsHashTreeService.java index 7b384e3d08..879bce2946 100644 --- a/backend/src/main/java/io/metersphere/api/service/MsHashTreeService.java +++ b/backend/src/main/java/io/metersphere/api/service/MsHashTreeService.java @@ -51,6 +51,7 @@ public class MsHashTreeService { public static final String NUM = "num"; public static final String ENV_ENABLE = "environmentEnable"; public static final String VARIABLE_ENABLE = "variableEnable"; + public static final String MIX_ENABLE = "mixEnable"; public static final String DISABLED = "disabled"; public static final String VERSION_NAME = "versionName"; public static final String VERSION_ENABLE = "versionEnable"; @@ -245,8 +246,8 @@ public class MsHashTreeService { private JSONObject setRefScenario(JSONObject element) { boolean enable = element.containsKey(ENABLE) ? element.getBoolean(ENABLE) : true; - if (!element.containsKey(VARIABLE_ENABLE)) { - element.put(VARIABLE_ENABLE, true); + if (!element.containsKey(MIX_ENABLE)) { + element.put(MIX_ENABLE, true); } ApiScenarioDTO scenarioWithBLOBs = extApiScenarioMapper.selectById(element.getString(ID)); @@ -254,7 +255,9 @@ public class MsHashTreeService { boolean environmentEnable = element.containsKey(ENV_ENABLE) ? element.getBoolean(ENV_ENABLE) : false; boolean variableEnable = element.containsKey(VARIABLE_ENABLE) - ? element.getBoolean(VARIABLE_ENABLE) : true; + ? element.getBoolean(VARIABLE_ENABLE) : false; + boolean mixEnable = element.containsKey(MIX_ENABLE) + ? element.getBoolean(MIX_ENABLE) : true; if (environmentEnable && StringUtils.isNotEmpty(scenarioWithBLOBs.getEnvironmentJson())) { element.put(ENV_MAP, JSON.parseObject(scenarioWithBLOBs.getEnvironmentJson(), Map.class)); @@ -269,6 +272,9 @@ public class MsHashTreeService { if (!element.containsKey(VARIABLE_ENABLE)) { element.put(VARIABLE_ENABLE, variableEnable); } + if (!element.containsKey(MIX_ENABLE) && !variableEnable) { + element.put(MIX_ENABLE, mixEnable); + } this.setElement(element, scenarioWithBLOBs.getNum(), enable, scenarioWithBLOBs.getVersionName(), scenarioWithBLOBs.getVersionEnable()); } else { if (StringUtils.equalsIgnoreCase(element.getString(REFERENCED), REF)) { diff --git a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue index b4809cb7bb..8ab832c517 100644 --- a/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue +++ b/frontend/src/business/components/api/automation/scenario/EditApiScenario.vue @@ -1271,7 +1271,7 @@ export default { } this.resetResourceId(item.hashTree); item.enable === undefined ? item.enable = true : item.enable; - item.variableEnable = item.variableEnable === undefined ? true : item.variableEnable; + item.mixEnable = item.mixEnable === undefined && !item.variableEnable ? true : item.mixEnable; if (this.selectedTreeNode !== undefined) { if (this.stepFilter.get("SpecialSteps").indexOf(this.selectedTreeNode.type) !== -1) { this.scenarioDefinition.splice(this.selectedTreeNode.index, 0, item); diff --git a/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue b/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue index d0470c88ec..2d14a8f564 100644 --- a/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue +++ b/frontend/src/business/components/api/automation/scenario/component/StepExtendBtns.vue @@ -6,17 +6,27 @@ {{ this.$t('commons.copy') }} - {{ this.$t('ui.disable') }} - {{ this.$t('ui.enable') }} + {{ + this.$t('ui.disable') + }} + + {{ + this.$t('ui.enable') + }} + {{ this.$t('api_test.automation.delete_step') }} - {{ this.$t('test_track.module.rename') }} + {{ + this.$t('test_track.module.rename') + }} + {{ this.$t("api_test.automation.view_scene_variables") }} {{ this.$t("api_test.automation.open_scene") }} - + {{ this.$t("api_test.automation.save_as_api") }} @@ -30,16 +40,21 @@ + :visible.sync="dialogVisible" width="700px">
    - + {{ $t('commons.enable_scene') }} - +
    + {{ $t('commons.variable_scene') }} +
    + + {{ $t('commons.mix_enable') }} +
@@ -85,6 +100,16 @@ export default { this.allSamplers = this.filter.get('DEFINITION'); }, methods: { + variableChange() { + if (this.data.variableEnable) { + this.data.mixEnable = false; + } + }, + mixChange() { + if (this.data.mixEnable) { + this.data.variableEnable = false; + } + }, handleCommand(cmd) { switch (cmd) { case "copy": diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 2f6c2c9c0b..bef6162413 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -242,6 +242,7 @@ export default { testing: "Testing", enable_scene: "Original scene environment", variable_scene: "Original scene variable", + mix_enable: "The current scene variable is used first, and the original scene variable is used if there is no", reference_settings: "Reference settings", enable_scene_info: "Enable scene environment: the current step uses the original environment configuration of the scene to run", edit_info: "Edit details", diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index a1a3e6e7fd..4d79b0cc39 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -244,6 +244,7 @@ export default { edit_info: "编辑详情", enable_scene: "原场景环境", variable_scene: "原场景变量", + mix_enable: "优先使用当前场景变量,没有则使用原场景变量", reference_settings: "场景设置", enable_scene_info: "启用场景环境:当前步骤使用场景原始环境配置运行", environment: "运行环境", diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 2845d0b847..ae3aa1e586 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -244,6 +244,7 @@ export default { edit_info: "編輯詳情", enable_scene: "原場景環境", variable_scene: "原場景变量", + mix_enable: "優先使用當前場景變量,沒有則使用原場景變量", reference_settings: "场景设置", enable_scene_info: "啟用場景環境:當前步驟使用場景原始環境配置運行", environment: "運行環境",