feat(接口测试): 处理环境和场景变量

This commit is contained in:
AgAngle 2024-03-06 10:56:36 +08:00 committed by Craftsman
parent f6fcfe98ca
commit d2dd6e5829
7 changed files with 223 additions and 32 deletions

View File

@ -82,7 +82,6 @@ public class ApiTestController {
@RequiresPermissions(value = { @RequiresPermissions(value = {
PermissionConstants.PROJECT_API_DEFINITION_READ, PermissionConstants.PROJECT_API_DEFINITION_READ,
PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, PermissionConstants.PROJECT_API_DEFINITION_CASE_READ,
PermissionConstants.PROJECT_API_DEBUG_READ,
PermissionConstants.PROJECT_API_SCENARIO_READ PermissionConstants.PROJECT_API_SCENARIO_READ
}, logical = Logical.OR) }, logical = Logical.OR)
public List<Environment> getEnvList(@PathVariable String projectId) { public List<Environment> getEnvList(@PathVariable String projectId) {

View File

@ -0,0 +1,61 @@
package io.metersphere.api.parser.jmeter;
import io.metersphere.jmeter.mock.Mock;
import io.metersphere.project.dto.environment.variables.CommonVariables;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Argument;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement;
import java.util.ArrayList;
import java.util.List;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.ARGUMENTS_PANEL;
/**
* @Author: jianxing
* @CreateTime: 2024-03-05 21:06
*/
public class JmeterTestElementParserHelper {
public static Arguments getArguments(String name) {
Arguments arguments = new Arguments();
arguments.setEnabled(true);
arguments.setName(name + "_Arguments");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(ARGUMENTS_PANEL));
return arguments;
}
public static Arguments getArguments(String name, List<CommonVariables> argumentList) {
Arguments arguments = getArguments(name);
parse2ArgumentList(argumentList).forEach(arguments::addArgument);
return arguments;
}
public static List<Argument> parse2ArgumentList(List<CommonVariables> variables) {
List<Argument> arguments = new ArrayList<>(variables.size());
variables.forEach(variable -> {
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;
}
}

View File

@ -25,11 +25,13 @@ import io.metersphere.project.dto.environment.GlobalParams;
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;
import io.metersphere.project.dto.environment.http.SelectModule; import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.project.dto.environment.variables.CommonVariables;
import io.metersphere.sdk.util.EnumValidator; import io.metersphere.sdk.util.EnumValidator;
import io.metersphere.sdk.util.LogUtils; 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.protocol.http.control.AuthManager; import org.apache.jmeter.protocol.http.control.AuthManager;
import org.apache.jmeter.protocol.http.control.Authorization; import org.apache.jmeter.protocol.http.control.Authorization;
import org.apache.jmeter.protocol.http.control.Header; import org.apache.jmeter.protocol.http.control.Header;
@ -68,6 +70,7 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
ApiParamConfig apiParamConfig = (ApiParamConfig) config; ApiParamConfig apiParamConfig = (ApiParamConfig) config;
HttpConfig httpConfig = getHttpConfig(msHTTPElement, apiParamConfig); HttpConfig httpConfig = getHttpConfig(msHTTPElement, apiParamConfig);
EnvironmentInfoDTO envConfig = apiParamConfig.getEnvConfig(msHTTPElement.getProjectId());
HTTPSamplerProxy sampler = new HTTPSamplerProxy(); HTTPSamplerProxy sampler = new HTTPSamplerProxy();
sampler.setName(msHTTPElement.getName()); sampler.setName(msHTTPElement.getName());
@ -87,19 +90,19 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
HashTree httpTree = tree.add(sampler); HashTree httpTree = tree.add(sampler);
// 处理环境变量
Arguments envArguments = getEnvArguments(msHTTPElement, envConfig);
Optional.ofNullable(envArguments).ifPresent(httpTree::add);
// 处理请求头 // 处理请求头
HeaderManager httpHeader = getHttpHeader(msHTTPElement, apiParamConfig, httpConfig); HeaderManager httpHeader = getHttpHeader(msHTTPElement, apiParamConfig, httpConfig);
if (httpHeader != null) { Optional.ofNullable(httpHeader).ifPresent(httpTree::add);
httpTree.add(httpHeader);
}
HTTPAuthConfig authConfig = msHTTPElement.getAuthConfig(); HTTPAuthConfig authConfig = msHTTPElement.getAuthConfig();
// 处理认证信息 // 处理认证信息
AuthManager authManager = getAuthManager(authConfig); AuthManager authManager = getAuthManager(authConfig);
if (authManager != null) { Optional.ofNullable(authManager).ifPresent(httpTree::add);
httpTree.add(authManager);
}
parseChild(httpTree, msHTTPElement, config); parseChild(httpTree, msHTTPElement, config);
} }
@ -160,6 +163,24 @@ public class MsHTTPElementConverter extends AbstractJmeterElementConverter<MsHTT
return authManager; return authManager;
} }
/**
* 添加场景和环境变量
* @param msHTTPElement
* @param envInfo
*/
private Arguments getEnvArguments(MsHTTPElement msHTTPElement, EnvironmentInfoDTO envInfo) {
if (envInfo == null) {
return null;
}
List<CommonVariables> envVariables = envInfo.getConfig().getCommonVariables();
if (CollectionUtils.isEmpty(envVariables)) {
return null;
}
return JmeterTestElementParserHelper.getArguments(msHTTPElement.getName(), envVariables);
}
/** /**
* 设置步骤标识 * 设置步骤标识
* 当前步骤唯一标识结果和步骤匹配的关键 * 当前步骤唯一标识结果和步骤匹配的关键

View File

@ -7,6 +7,7 @@ import io.metersphere.api.dto.request.MsScenario;
import io.metersphere.api.dto.request.processors.MsProcessorConfig; 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.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;
@ -17,10 +18,12 @@ import io.metersphere.project.api.processor.MsProcessor;
import io.metersphere.project.dto.environment.EnvironmentConfig; import io.metersphere.project.dto.environment.EnvironmentConfig;
import io.metersphere.project.dto.environment.EnvironmentInfoDTO; import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.processors.EnvProcessorConfig; import io.metersphere.project.dto.environment.processors.EnvProcessorConfig;
import io.metersphere.project.dto.environment.variables.CommonVariables;
import io.metersphere.sdk.util.BeanUtils; 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.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;
@ -29,6 +32,8 @@ 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.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.COOKIE_PANEL; import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.COOKIE_PANEL;
@ -50,6 +55,9 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
tree.add(getCookieManager()); tree.add(getCookieManager());
} }
// 添加场景和环境变量
addArguments(tree, msScenario, envInfo);
// 添加环境的前置 // 添加环境的前置
addEnvScenarioProcessor(tree, msScenario, config, envInfo, true); addEnvScenarioProcessor(tree, msScenario, config, envInfo, true);
// 添加场景前置 // 添加场景前置
@ -68,6 +76,72 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
addScenarioAssertions(tree, msScenario, config); addScenarioAssertions(tree, msScenario, config);
} }
/**
* 添加场景和环境变量
* @param tree
* @param msScenario
* @param envInfo
*/
private void addArguments(HashTree tree, MsScenario msScenario, EnvironmentInfoDTO envInfo) {
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
ScenarioVariable scenarioVariable = scenarioConfig == null ? new ScenarioVariable() : scenarioConfig.getVariable();
List<CommonVariables> commonVariables = scenarioVariable.getCommonVariables();
List<CommonVariables> envCommonVariables = List.of();
if (needParseEnv(msScenario) && envInfo.getConfig() != null) {
// 获取环境变量
envCommonVariables = envInfo.getConfig().getCommonVariables();
// 获取后将环境变量置空避免请求重复设置
envInfo.getConfig().setCommonVariables(List.of());
}
List<CommonVariables> constantVariables = mergeEnvVariables(commonVariables, envCommonVariables, CommonVariables::isConstantValid);
List<CommonVariables> listVariables = mergeEnvVariables(commonVariables, envCommonVariables, CommonVariables::isListValid);
if (CollectionUtils.isEmpty(commonVariables) && CollectionUtils.isEmpty(envCommonVariables)) {
return;
}
Arguments arguments = JmeterTestElementParserHelper.getArguments(msScenario.getName());
JmeterTestElementParserHelper.parse2ArgumentList(constantVariables).forEach(arguments::addArgument);
JmeterTestElementParserHelper.parse2ArgumentList(listVariables).forEach(arguments::addArgument);
tree.add(arguments);
}
/**
* 合并环境变量和场景变量
* @param scenarioVariables
* @param envCommonVariables
* @param filter
* @return
*/
private List<CommonVariables> mergeEnvVariables(List<CommonVariables> scenarioVariables, List<CommonVariables> envCommonVariables, Predicate<CommonVariables> filter) {
List<CommonVariables> variables = scenarioVariables
.stream()
.filter(CommonVariables::getEnable)
.filter(filter::test)
.collect(Collectors.toList());
List<CommonVariables> envConstantVariables = envCommonVariables
.stream()
.filter(CommonVariables::getEnable)
.filter(filter::test)
.collect(Collectors.toList());
Map<String, String> scenarioVariableMap = variables
.stream()
.collect(Collectors.toMap(CommonVariables::getKey, CommonVariables::getValue));
for (CommonVariables globalConstantVariable : envConstantVariables) {
String key = globalConstantVariable.getKey();
if (!scenarioVariableMap.containsKey(key)) {
variables.add(globalConstantVariable);
}
}
return variables;
}
/** /**
* 添加场景断言 * 添加场景断言
* *
@ -105,18 +179,8 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
EnvironmentInfoDTO envInfo, EnvironmentInfoDTO envInfo,
boolean isPre) { boolean isPre) {
if (isRef(msScenario.getRefType())) { if (!needParseEnv(msScenario)) {
ScenarioStepConfig scenarioStepConfig = msScenario.getScenarioStepConfig();
if (scenarioStepConfig == null || BooleanUtils.isFalse(scenarioStepConfig.getEnableScenarioEnv())) {
// 引用的场景如果没有开启源场景环境不添加环境的前后置
return;
}
} else if (isCopy(msScenario.getRefType())) {
// 复制场景不添加环境的前后置
return; return;
} else {
// 当前场景添加环境的前后置
// do nothing
} }
ScenarioConfig scenarioConfig = msScenario.getScenarioConfig(); ScenarioConfig scenarioConfig = msScenario.getScenarioConfig();
@ -147,6 +211,28 @@ public class MsScenarioConverter extends AbstractJmeterElementConverter<MsScenar
}); });
} }
/**
* 是否需要解析环境
* @param msScenario
* @return
*/
private boolean needParseEnv(MsScenario msScenario) {
if (isRef(msScenario.getRefType())) {
ScenarioStepConfig scenarioStepConfig = msScenario.getScenarioStepConfig();
if (scenarioStepConfig == null || BooleanUtils.isFalse(scenarioStepConfig.getEnableScenarioEnv())) {
// 引用的场景如果没有开启源场景环境不解析环境
return false;
}
return true;
} else if (isCopy(msScenario.getRefType())) {
// 复制场景不解析环境
return false;
} else {
// 当前场景解析环境
return true;
}
}
private void addScenarioProcessor(HashTree tree, MsScenario msScenario, ParameterConfig config, boolean isPre) { private void addScenarioProcessor(HashTree tree, MsScenario msScenario, ParameterConfig config, boolean isPre) {
if (isCopy(msScenario.getRefType())) { if (isCopy(msScenario.getRefType())) {
// 复制的场景没有前后置 // 复制的场景没有前后置

View File

@ -1,5 +1,6 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
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.plugin.api.constants.ElementProperty; import io.metersphere.plugin.api.constants.ElementProperty;
@ -15,8 +16,6 @@ import org.apache.jmeter.testelement.TestElement;
import java.util.List; import java.util.List;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.ARGUMENTS_PANEL;
/** /**
* @Author: jianxing * @Author: jianxing
@ -79,11 +78,7 @@ public abstract class ScriptProcessorConverter extends MsProcessorConverter<Scri
return null; return null;
} }
Arguments arguments = new Arguments(); Arguments arguments = JmeterTestElementParserHelper.getArguments(scriptProcessor.getName());
arguments.setEnabled(true);
arguments.setName(scriptProcessor.getName() + "_Arguments");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(ARGUMENTS_PANEL));
for (KeyValueParam param : params) { for (KeyValueParam param : params) {
arguments.addArgument(param.getKey(), param.getValue(), "="); arguments.addArgument(param.getKey(), param.getValue(), "=");
} }

View File

@ -1,6 +1,7 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.api.dto.ApiParamConfig; import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.api.parser.jmeter.JmeterTestElementParserHelper;
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;
import io.metersphere.project.api.processor.SQLProcessor; import io.metersphere.project.api.processor.SQLProcessor;
@ -18,7 +19,6 @@ import org.apache.jorphan.collections.HashTree;
import java.util.List; import java.util.List;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.ARGUMENTS_PANEL;
import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.TEST_BEAN_GUI; import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.TEST_BEAN_GUI;
@ -68,12 +68,7 @@ public abstract class SqlProcessorConverter extends MsProcessorConverter<SQLProc
public Arguments getJdbcArguments(String name, List<KeyValueParam> extractParams) { public Arguments getJdbcArguments(String name, List<KeyValueParam> extractParams) {
if (CollectionUtils.isNotEmpty(extractParams)) { if (CollectionUtils.isNotEmpty(extractParams)) {
Arguments arguments = new Arguments(); Arguments arguments = JmeterTestElementParserHelper.getArguments(name);
arguments.setEnabled(true);
name = StringUtils.isNotEmpty(name) ? name : "Arguments";
arguments.setName(name + "_JDBC_Argument");
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
arguments.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(ARGUMENTS_PANEL));
extractParams.stream().filter(KeyValueParam::isValid) extractParams.stream().filter(KeyValueParam::isValid)
.forEach(keyValue -> .forEach(keyValue ->
arguments.addArgument(keyValue.getKey(), String.format("vars.get(\"%s\")", keyValue.getValue()), "=") arguments.addArgument(keyValue.getKey(), String.format("vars.get(\"%s\")", keyValue.getValue()), "=")

View File

@ -45,6 +45,7 @@ import io.metersphere.project.dto.environment.http.SelectModule;
import io.metersphere.project.dto.environment.processors.EnvProcessorConfig; import io.metersphere.project.dto.environment.processors.EnvProcessorConfig;
import io.metersphere.project.dto.environment.processors.EnvRequestScriptProcessor; import io.metersphere.project.dto.environment.processors.EnvRequestScriptProcessor;
import io.metersphere.project.dto.environment.processors.EnvScenarioScriptProcessor; import io.metersphere.project.dto.environment.processors.EnvScenarioScriptProcessor;
import io.metersphere.project.dto.environment.variables.CommonVariables;
import io.metersphere.project.dto.filemanagement.request.FileUploadRequest; import io.metersphere.project.dto.filemanagement.request.FileUploadRequest;
import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper;
import io.metersphere.project.mapper.ProjectVersionMapper; import io.metersphere.project.mapper.ProjectVersionMapper;
@ -760,6 +761,7 @@ public class ApiScenarioControllerTests extends BaseTest {
request.getStepDetails().put(pluginStep.getId(), pluginStepDetail); request.getStepDetails().put(pluginStep.getId(), pluginStepDetail);
request.getScenarioConfig().getOtherConfig().setEnableCookieShare(true); request.getScenarioConfig().getOtherConfig().setEnableCookieShare(true);
request.getScenarioConfig().getOtherConfig().setEnableGlobalCookie(false); request.getScenarioConfig().getOtherConfig().setEnableGlobalCookie(false);
request.getScenarioConfig().setVariable(getScenarioVariable());
Plugin plugin = addEnvTestPlugin(); Plugin plugin = addEnvTestPlugin();
this.requestPostWithOk(DEBUG, request); this.requestPostWithOk(DEBUG, request);
@ -769,6 +771,24 @@ public class ApiScenarioControllerTests extends BaseTest {
requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, DEBUG, request); requestPostPermissionTest(PermissionConstants.PROJECT_API_SCENARIO_EXECUTE, DEBUG, request);
} }
private ScenarioVariable getScenarioVariable() {
ScenarioVariable scenarioVariable = new ScenarioVariable();
CommonVariables commonVariables1 = new CommonVariables();
commonVariables1.setType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setKey("a");
commonVariables1.setValue("b");
CommonVariables commonVariables2 = new CommonVariables();
commonVariables2.setType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setKey("b");
commonVariables2.setValue("c");
CommonVariables commonVariables3 = new CommonVariables();
commonVariables3.setType(VariableTypeConstants.LIST.name());
commonVariables3.setKey("list1");
commonVariables3.setValue("1,2,3");
scenarioVariable.setCommonVariables(List.of(commonVariables1, commonVariables2, commonVariables3));
return scenarioVariable;
}
@Test @Test
@Order(7) @Order(7)
public void testTransfer() throws Exception { public void testTransfer() throws Exception {
@ -1051,6 +1071,20 @@ public class ApiScenarioControllerTests extends BaseTest {
DataSource dataSource = getDataSource(); DataSource dataSource = getDataSource();
environmentConfig.setDataSources(List.of(dataSource)); environmentConfig.setDataSources(List.of(dataSource));
CommonVariables commonVariables1 = new CommonVariables();
commonVariables1.setType(VariableTypeConstants.CONSTANT.name());
commonVariables1.setKey("a");
commonVariables1.setValue("c");
CommonVariables commonVariables2 = new CommonVariables();
commonVariables2.setType(VariableTypeConstants.CONSTANT.name());
commonVariables2.setKey("q");
commonVariables2.setValue("qq");
CommonVariables commonVariables3 = new CommonVariables();
commonVariables3.setType(VariableTypeConstants.LIST.name());
commonVariables3.setKey("list1");
commonVariables3.setValue("1,2,3,5");
environmentConfig.setCommonVariables(List.of(commonVariables1, commonVariables2, commonVariables3));
EnvProcessorConfig preProcessorConfig = environmentConfig.getPreProcessorConfig(); EnvProcessorConfig preProcessorConfig = environmentConfig.getPreProcessorConfig();
EnvProcessorConfig postProcessorConfig = environmentConfig.getPostProcessorConfig(); EnvProcessorConfig postProcessorConfig = environmentConfig.getPostProcessorConfig();
List<MsProcessor> preProcessors = preProcessorConfig.getApiProcessorConfig().getScenarioProcessorConfig().getProcessors(); List<MsProcessor> preProcessors = preProcessorConfig.getApiProcessorConfig().getScenarioProcessorConfig().getProcessors();