fix(接口测试): 引用原场景参数,变量优先级有误

--bug=1039759 --user=陈建星 【场景】-引用的场景配置使用原场景参数并优先原场景参数时,当前场景步骤参数优先级高于原场景参数 https://www.tapd.cn/55049933/s/1502253
This commit is contained in:
AgAngle 2024-04-21 13:35:47 +08:00 committed by Craftsman
parent 820862bcaf
commit da8d506311
6 changed files with 93 additions and 69 deletions

View File

@ -1,61 +1,63 @@
package io.metersphere.api.parser.jmeter; package io.metersphere.api.parser.jmeter;
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
import io.metersphere.jmeter.mock.Mock; import io.metersphere.jmeter.mock.Mock;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.dto.environment.variables.CommonVariables; import io.metersphere.project.dto.environment.variables.CommonVariables;
import org.apache.commons.lang3.BooleanUtils; import io.metersphere.sdk.util.BeanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Argument; import org.apache.jmeter.modifiers.UserParameters;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.ARGUMENTS_PANEL;
/** /**
* @Author: jianxing * @Author: jianxing
* @CreateTime: 2024-03-05 21:06 * @CreateTime: 2024-03-05 21:06
*/ */
public class JmeterTestElementParserHelper { public class JmeterTestElementParserHelper {
public static Arguments getArguments(String name) { public static UserParameters getUserParameters(String name) {
Arguments arguments = new Arguments(); UserParameters userParameters = new UserParameters();
arguments.setEnabled(true); userParameters.setEnabled(true);
arguments.setName(name + "_Arguments"); userParameters.setName(name + "_User Parameters");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName()); userParameters.setPerIteration(true);
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(ARGUMENTS_PANEL)); userParameters.setProperty(TestElement.TEST_CLASS, UserParameters.class.getName());
userParameters.setProperty(TestElement.GUI_CLASS, JmeterAlias.USER_PARAMETERS_GUI);
return userParameters;
}
public static UserParameters getUserParameters(String name, List<? extends KeyValueParam> argumentList) {
UserParameters arguments = getUserParameters(name);
List<String> names = new LinkedList<>();
List<Object> values = new LinkedList<>();
List<Object> threadValues = new LinkedList<>();
for (int i = 0; i < argumentList.size(); ++i) {
String value = argumentList.get(i).getValue();
String key = argumentList.get(i).getKey();
names.add(key);
values.add(Mock.buildFunctionCallString(value).replaceAll("[\r\n]", ""));
}
arguments.setNames(names);
threadValues.add(values);
arguments.setThreadLists(threadValues);
return arguments; return arguments;
} }
public static Arguments getArguments(String name, List<CommonVariables> argumentList) { public static UserParameters getUserParameters(List<CommonVariables> constantVariables, List<CommonVariables> listVariables) {
Arguments arguments = getArguments(name); List<CommonVariables> variableResults = new ArrayList<>();
parse2ArgumentList(argumentList).forEach(arguments::addArgument); listVariables.forEach(listVariable -> {
return arguments; String[] arrays = listVariable.getValue().replaceAll("[\r\n]", "").split(",");
} for (int i = 0; i < arrays.length; i++) {
CommonVariables commonVariables = BeanUtils.copyBean(new CommonVariables(), listVariable);
public static List<Argument> parse2ArgumentList(List<CommonVariables> variables) { commonVariables.setKey(listVariable.getKey() + "_" + (i + 1));
List<Argument> arguments = new ArrayList<>(variables.size()); commonVariables.setValue(arrays[i]);
variables.forEach(variable -> { variableResults.add(commonVariables);
if (BooleanUtils.isFalse(variable.getEnable())) {
return;
}
if (variable.isConstantValid()) {
// 处理常量
String value = StringUtils.isBlank(variable.getValue()) ? variable.getValue()
: Mock.buildFunctionCallString(variable.getValue()).replaceAll("[\r\n]", "");
arguments.add(new Argument(variable.getKey(), value, "="));
} else if (variable.isListValid()) {
// 处理 List 变量
String[] arrays = variable.getValue().replaceAll("[\r\n]", "").split(",");
for (int i = 0; i < arrays.length; i++) {
arguments.add(new Argument(variable.getKey() + "_" + (i + 1), arrays[i], "="));
}
} }
}); });
return arguments; variableResults.addAll(constantVariables);
return getUserParameters(StringUtils.EMPTY, variableResults);
} }
} }

View File

@ -4,9 +4,6 @@ package io.metersphere.api.parser.jmeter;
import io.metersphere.api.constants.ApiConstants; import io.metersphere.api.constants.ApiConstants;
import io.metersphere.api.dto.ApiParamConfig; import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.dto.request.http.*; import io.metersphere.api.dto.request.http.*;
import io.metersphere.project.dto.environment.auth.BasicAuth;
import io.metersphere.project.dto.environment.auth.DigestAuth;
import io.metersphere.project.dto.environment.auth.HTTPAuthConfig;
import io.metersphere.api.dto.request.http.body.Body; import io.metersphere.api.dto.request.http.body.Body;
import io.metersphere.api.parser.jmeter.body.MsBodyConverter; import io.metersphere.api.parser.jmeter.body.MsBodyConverter;
import io.metersphere.api.parser.jmeter.body.MsBodyConverterFactory; import io.metersphere.api.parser.jmeter.body.MsBodyConverterFactory;
@ -19,6 +16,9 @@ import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.api.KeyValueParam; import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO; import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.GlobalParams; import io.metersphere.project.dto.environment.GlobalParams;
import io.metersphere.project.dto.environment.auth.BasicAuth;
import io.metersphere.project.dto.environment.auth.DigestAuth;
import io.metersphere.project.dto.environment.auth.HTTPAuthConfig;
import io.metersphere.project.dto.environment.host.Host; import io.metersphere.project.dto.environment.host.Host;
import io.metersphere.project.dto.environment.http.HttpConfig; import io.metersphere.project.dto.environment.http.HttpConfig;
import io.metersphere.project.dto.environment.http.HttpConfigPathMatchRule; import io.metersphere.project.dto.environment.http.HttpConfigPathMatchRule;
@ -29,8 +29,11 @@ import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments; import org.apache.jmeter.modifiers.UserParameters;
import org.apache.jmeter.protocol.http.control.*; import org.apache.jmeter.protocol.http.control.AuthManager;
import org.apache.jmeter.protocol.http.control.Authorization;
import org.apache.jmeter.protocol.http.control.DNSCacheManager;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy; import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
@ -89,8 +92,8 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
HashTree httpTree = tree.add(sampler); HashTree httpTree = tree.add(sampler);
// 处理环境变量 // 处理环境变量
Arguments envArguments = getEnvArguments(msHTTPElement, envConfig); UserParameters userParameters = getEnvUserParameters(msHTTPElement, envConfig);
Optional.ofNullable(envArguments).ifPresent(httpTree::add); Optional.ofNullable(userParameters).ifPresent(httpTree::add);
// 处理请求头 // 处理请求头
HeaderManager httpHeader = getHttpHeader(msHTTPElement, apiParamConfig, httpConfig); HeaderManager httpHeader = getHttpHeader(msHTTPElement, apiParamConfig, httpConfig);
@ -190,7 +193,7 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
* @param msHTTPElement * @param msHTTPElement
* @param envInfo * @param envInfo
*/ */
private Arguments getEnvArguments(MsHTTPElement msHTTPElement, EnvironmentInfoDTO envInfo) { private UserParameters getEnvUserParameters(MsHTTPElement msHTTPElement, EnvironmentInfoDTO envInfo) {
if (envInfo == null) { if (envInfo == null) {
return null; return null;
} }
@ -200,7 +203,7 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
return null; return null;
} }
return JmeterTestElementParserHelper.getArguments(msHTTPElement.getName(), envVariables); return JmeterTestElementParserHelper.getUserParameters(msHTTPElement.getName(), envVariables);
} }
private String getPath(MsHTTPElement msHTTPElement, HttpConfig httpConfig) { private String getPath(MsHTTPElement msHTTPElement, HttpConfig httpConfig) {

View File

@ -8,6 +8,7 @@ import io.metersphere.api.dto.request.processors.MsProcessorConfig;
import io.metersphere.api.dto.scenario.ScenarioConfig; import io.metersphere.api.dto.scenario.ScenarioConfig;
import io.metersphere.api.dto.scenario.ScenarioStepConfig; import io.metersphere.api.dto.scenario.ScenarioStepConfig;
import io.metersphere.api.dto.scenario.ScenarioVariable; import io.metersphere.api.dto.scenario.ScenarioVariable;
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
import io.metersphere.api.parser.jmeter.processor.MsProcessorConverter; import io.metersphere.api.parser.jmeter.processor.MsProcessorConverter;
import io.metersphere.api.parser.jmeter.processor.MsProcessorConverterFactory; import io.metersphere.api.parser.jmeter.processor.MsProcessorConverterFactory;
import io.metersphere.api.parser.jmeter.processor.assertion.AssertionConverterFactory; import io.metersphere.api.parser.jmeter.processor.assertion.AssertionConverterFactory;
@ -23,7 +24,8 @@ import io.metersphere.sdk.util.BeanUtils;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments; import org.apache.jmeter.control.CriticalSectionController;
import org.apache.jmeter.modifiers.UserParameters;
import org.apache.jmeter.protocol.http.control.CookieManager; import org.apache.jmeter.protocol.http.control.CookieManager;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
@ -32,6 +34,7 @@ import org.apache.jorphan.collections.HashTree;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -52,13 +55,18 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
ApiScenarioParamConfig config = getEnableConfig(msScenario, (ApiScenarioParamConfig) msParameter); ApiScenarioParamConfig config = getEnableConfig(msScenario, (ApiScenarioParamConfig) msParameter);
EnvironmentInfoDTO envInfo = config.getEnvConfig(msScenario.getProjectId()); EnvironmentInfoDTO envInfo = config.getEnvConfig(msScenario.getProjectId());
if (isRef(msScenario.getRefType())) {
// 引用的场景中可能包含变量场景包一层临界控制器解决变量冲突
tree = addCriticalSectionController(tree, msScenario);
}
if (isRootScenario(msScenario.getRefType()) && msScenario.getScenarioConfig().getOtherConfig().getEnableGlobalCookie()) { if (isRootScenario(msScenario.getRefType()) && msScenario.getScenarioConfig().getOtherConfig().getEnableGlobalCookie()) {
// 根场景设置共享cookie // 根场景设置共享cookie
tree.add(getCookieManager()); tree.add(getCookieManager());
} }
// 添加场景和环境变量 // 添加场景和环境变量
addArguments(tree, msScenario, envInfo, config); addUserParameters(tree, msScenario, envInfo, config);
// 添加环境的前置 // 添加环境的前置
addEnvScenarioProcessor(tree, msScenario, config, envInfo, true); addEnvScenarioProcessor(tree, msScenario, config, envInfo, true);
@ -77,6 +85,24 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
addScenarioAssertions(tree, msScenario, config); addScenarioAssertions(tree, msScenario, config);
} }
/**
* 添加临界控制器解决变量冲突
* @param tree
* @param msScenario
* @return
*/
public HashTree addCriticalSectionController(HashTree tree, MsScenario msScenario) {
String name = msScenario.getName();
boolean enable = msScenario.getEnable();
CriticalSectionController criticalSectionController = new CriticalSectionController();
criticalSectionController.setName(StringUtils.isNotEmpty(name) ? "Csc_" + name : "Scenario Critical Section Controller");
criticalSectionController.setLockName(UUID.randomUUID().toString());
criticalSectionController.setEnabled(enable);
criticalSectionController.setProperty(TestElement.TEST_CLASS, CriticalSectionController.class.getName());
criticalSectionController.setProperty(TestElement.GUI_CLASS, JmeterAlias.CRITICAL_SECTION_CONTROLLER_GUI);
return tree.add(criticalSectionController);
}
/** /**
* 添加场景和环境变量 * 添加场景和环境变量
* *
@ -84,7 +110,7 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
* @param msScenario * @param msScenario
* @param envInfo * @param envInfo
*/ */
private void addArguments(HashTree tree, MsScenario msScenario, EnvironmentInfoDTO envInfo, ApiScenarioParamConfig config) { private void addUserParameters(HashTree tree, MsScenario msScenario, EnvironmentInfoDTO envInfo, ApiScenarioParamConfig config) {
// 如果是根场景获取场景变量 // 如果是根场景获取场景变量
List<CommonVariables> commonVariables = getCommonVariables(msScenario.getScenarioConfig()); List<CommonVariables> commonVariables = getCommonVariables(msScenario.getScenarioConfig());
@ -132,9 +158,8 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
return; return;
} }
Arguments arguments = JmeterTestElementParserHelper.getArguments(msScenario.getName()); UserParameters arguments = JmeterTestElementParserHelper.getUserParameters(constantVariables, listVariables);
JmeterTestElementParserHelper.parse2ArgumentList(constantVariables).forEach(arguments::addArgument);
JmeterTestElementParserHelper.parse2ArgumentList(listVariables).forEach(arguments::addArgument);
tree.add(arguments); tree.add(arguments);
} }

View File

@ -23,4 +23,5 @@ public class JmeterAlias {
public static final String ARGUMENTS_PANEL = "ArgumentsPanel"; public static final String ARGUMENTS_PANEL = "ArgumentsPanel";
public static final String BEAN_SHELL_ASSERTION_GUI = "BeanShellAssertionGui"; public static final String BEAN_SHELL_ASSERTION_GUI = "BeanShellAssertionGui";
public static final String BEAN_SHELL_SAMPLER_GUI = "BeanShellSamplerGui"; public static final String BEAN_SHELL_SAMPLER_GUI = "BeanShellSamplerGui";
public static final String CRITICAL_SECTION_CONTROLLER_GUI = "CriticalSectionControllerGui";
} }

View File

@ -4,7 +4,6 @@ import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.parser.jmeter.JmeterTestElementParserHelper; import io.metersphere.api.parser.jmeter.JmeterTestElementParserHelper;
import io.metersphere.api.parser.jmeter.constants.JmeterAlias; import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
import io.metersphere.api.parser.jmeter.constants.JmeterProperty; import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
import io.metersphere.jmeter.mock.Mock;
import io.metersphere.plugin.api.constants.ElementProperty; import io.metersphere.plugin.api.constants.ElementProperty;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.KeyValueParam; import io.metersphere.project.api.KeyValueParam;
@ -15,7 +14,7 @@ import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments; import org.apache.jmeter.modifiers.UserParameters;
import org.apache.jmeter.save.SaveService; import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
@ -72,7 +71,7 @@ public abstract class ScriptProcessorConverter extends MsProcessorConverter<Scri
testElement.setProperty(JmeterProperty.SCRIPT_LANGUAGE, scriptLanguage.toLowerCase()); testElement.setProperty(JmeterProperty.SCRIPT_LANGUAGE, scriptLanguage.toLowerCase());
} }
public static Arguments getScriptArguments(ScriptProcessor scriptProcessor) { public static UserParameters getScriptArguments(ScriptProcessor scriptProcessor) {
if (scriptProcessor == null || !scriptProcessor.isEnableCommonScript() || !scriptProcessor.isValid()) { if (scriptProcessor == null || !scriptProcessor.isEnableCommonScript() || !scriptProcessor.isValid()) {
return null; return null;
} }
@ -91,11 +90,7 @@ public abstract class ScriptProcessorConverter extends MsProcessorConverter<Scri
return null; return null;
} }
Arguments arguments = JmeterTestElementParserHelper.getArguments(scriptProcessor.getName()); return JmeterTestElementParserHelper.getUserParameters(scriptProcessor.getName(), params);
for (KeyValueParam param : params) {
arguments.addArgument(param.getKey(), Mock.buildFunctionCallString(param.getValue()), "=");
}
return arguments;
} }
public static boolean isJSR233(ScriptProcessor scriptProcessor) { public static boolean isJSR233(ScriptProcessor scriptProcessor) {

View File

@ -2,6 +2,7 @@ package io.metersphere.project.dto.environment.variables;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.sdk.constants.VariableTypeConstants; import io.metersphere.sdk.constants.VariableTypeConstants;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -11,17 +12,13 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
@Data @Data
public class CommonVariables implements Serializable { public class CommonVariables extends KeyValueParam implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Schema(description = "id") @Schema(description = "id")
private String id; private String id;
@Schema(description = "变量名")
private String key;
@Schema(description = "变量类型 CONSTANT LIST JSON") @Schema(description = "变量类型 CONSTANT LIST JSON")
private String paramType = VariableTypeConstants.CONSTANT.name(); private String paramType = VariableTypeConstants.CONSTANT.name();
@Schema(description = "变量值")
private String value;
@Schema(description = "状态") @Schema(description = "状态")
private Boolean enable = true; private Boolean enable = true;
@Schema(description = "描述") @Schema(description = "描述")
@ -32,17 +29,18 @@ public class CommonVariables implements Serializable {
@JsonIgnore @JsonIgnore
public boolean isConstantValid() { public boolean isConstantValid() {
return StringUtils.equals(this.paramType, VariableTypeConstants.CONSTANT.name()) && StringUtils.isNotEmpty(key); return (StringUtils.equals(this.paramType, VariableTypeConstants.CONSTANT.name()) || StringUtils.isBlank(paramType))
&& isValid();
} }
@JsonIgnore @JsonIgnore
public boolean isListValid() { public boolean isListValid() {
return StringUtils.equals(this.paramType, VariableTypeConstants.LIST.name()) && StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value) && value.indexOf(",") != -1; return StringUtils.equals(this.paramType, VariableTypeConstants.LIST.name()) && isValid() && isNotBlankValue() && getValue().indexOf(",") != -1;
} }
@JsonIgnore @JsonIgnore
public boolean isJsonValid() { public boolean isJsonValid() {
return StringUtils.equals(this.paramType, VariableTypeConstants.JSON.name()) && StringUtils.isNotEmpty(key); return StringUtils.equals(this.paramType, VariableTypeConstants.JSON.name()) && isValid();
} }
} }