feat(接口测试): 解析sql前后置

This commit is contained in:
AgAngle 2024-02-29 20:02:51 +08:00 committed by Craftsman
parent d82a2a1bab
commit 61f477576d
12 changed files with 198 additions and 38 deletions

View File

@ -97,11 +97,13 @@ public class RequestResult {
/** /**
* 子请求结果 * 子请求结果
* {@link RequestResult}
*/ */
private List<RequestResult> subRequestResults = new ArrayList<>(); private List<RequestResult> subRequestResults = new ArrayList<>();
/** /**
* 响应结果 * 响应结果
* {@link ResponseResult}
*/ */
private ResponseResult responseResult = new ResponseResult(); private ResponseResult responseResult = new ResponseResult();

View File

@ -15,6 +15,7 @@ public class TaskResultDTO implements Serializable {
/** /**
* 任务执行结果数据结构 * 任务执行结果数据结构
* {@link RequestResult}
*/ */
private List<RequestResult> requestResults; private List<RequestResult> requestResults;
/** /**
@ -31,11 +32,13 @@ public class TaskResultDTO implements Serializable {
private Boolean hasEnded; private Boolean hasEnded;
/** /**
* 执行过程状态 * 执行过程状态
* {@link ProcessResultDTO}
*/ */
private ProcessResultDTO processResultDTO; private ProcessResultDTO processResultDTO;
/** /**
* 请求参数 * 请求参数
* {@link TaskRequestDTO}
*/ */
private TaskRequestDTO request; private TaskRequestDTO request;
} }

View File

@ -62,6 +62,11 @@
<artifactId>ApacheJMeter_java</artifactId> <artifactId>ApacheJMeter_java</artifactId>
<version>${jmeter.version}</version> <version>${jmeter.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_jdbc</artifactId>
<version>${jmeter.version}</version>
</dependency>
<!-- 自定义jmeter 断言插件 --> <!-- 自定义jmeter 断言插件 -->
<dependency> <dependency>
<groupId>io.metersphere</groupId> <groupId>io.metersphere</groupId>

View File

@ -1,7 +1,8 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.project.api.processor.SQLProcessor;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.processor.SQLProcessor;
import org.apache.jmeter.protocol.jdbc.processor.JDBCPostProcessor;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
/** /**
@ -10,10 +11,7 @@ import org.apache.jorphan.collections.HashTree;
*/ */
public class SqlPostProcessorConverter extends SqlProcessorConverter { public class SqlPostProcessorConverter extends SqlProcessorConverter {
@Override @Override
public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) { public void parse(HashTree hashTree, SQLProcessor sqlProcessor, ParameterConfig config) {
if (!needParse(scriptProcessor, config)) { parse(hashTree, sqlProcessor, config, JDBCPostProcessor.class);
return;
}
// todo 等环境开发完之后补充
} }
} }

View File

@ -1,7 +1,8 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.project.api.processor.SQLProcessor;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.processor.SQLProcessor;
import org.apache.jmeter.protocol.jdbc.processor.JDBCPreProcessor;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
/** /**
@ -10,10 +11,7 @@ import org.apache.jorphan.collections.HashTree;
*/ */
public class SqlPreProcessorConverter extends SqlProcessorConverter { public class SqlPreProcessorConverter extends SqlProcessorConverter {
@Override @Override
public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) { public void parse(HashTree hashTree, SQLProcessor sqlProcessor, ParameterConfig config) {
if (!needParse(scriptProcessor, config)) { parse(hashTree, sqlProcessor, config, JDBCPreProcessor.class);
return;
}
// todo 等环境开发完之后补充
} }
} }

View File

@ -1,8 +1,25 @@
package io.metersphere.api.parser.jmeter.processor; package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.api.dto.ApiParamConfig;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.api.processor.SQLProcessor; import io.metersphere.project.api.processor.SQLProcessor;
import io.metersphere.project.api.processor.ScriptProcessor; import io.metersphere.project.dto.environment.EnvironmentInfoDTO;
import io.metersphere.project.dto.environment.datasource.DataSource;
import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.jdbc.config.DataSourceElement;
import org.apache.jmeter.protocol.jdbc.processor.AbstractJDBCProcessor;
import org.apache.jmeter.save.SaveService;
import org.apache.jmeter.testelement.TestElement; import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree;
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;
/** /**
@ -11,7 +28,117 @@ import org.apache.jmeter.testelement.TestElement;
*/ */
public abstract class SqlProcessorConverter extends MsProcessorConverter<SQLProcessor> { public abstract class SqlProcessorConverter extends MsProcessorConverter<SQLProcessor> {
protected void parse(TestElement testElement, ScriptProcessor scriptProcessor) { public <T extends AbstractJDBCProcessor> void parse(HashTree hashTree,
// todo 等环境开发完之后补充 SQLProcessor sqlProcessor,
ParameterConfig config,
Class<T> jdbcProcessorClass) {
if (!needParse(sqlProcessor, config)) {
return;
}
ApiParamConfig apiParamConfig = (ApiParamConfig) config;
EnvironmentInfoDTO envConfig = apiParamConfig.getEnvConfig(sqlProcessor.getProjectId());
DataSource dataSource = getDataSource(sqlProcessor, envConfig);
if (dataSource == null) {
return;
}
// 添加数据源
DataSourceElement dataSourceElement = getDataSourceElement(dataSource);
hashTree.add(dataSourceElement);
try {
// 添加前后置处理器
T jdbcProcessor = jdbcProcessorClass.getDeclaredConstructor().newInstance();
getJdbcProcessor(sqlProcessor, jdbcProcessor, dataSource);
hashTree.add(jdbcProcessor);
} catch (Exception e) {
LogUtils.error(e);
}
List<KeyValueParam> extractParams = sqlProcessor.getExtractParams()
.stream()
.filter(KeyValueParam::isValid)
.toList();
// 添加提取的变量
Arguments jdbcArguments = getJdbcArguments(sqlProcessor.getName(), extractParams);
if (jdbcArguments != null && !jdbcArguments.getArguments().isEmpty()) {
hashTree.add(jdbcArguments);
}
}
public Arguments getJdbcArguments(String name, List<KeyValueParam> extractParams) {
if (CollectionUtils.isNotEmpty(extractParams)) {
Arguments arguments = new Arguments();
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)
.forEach(keyValue ->
arguments.addArgument(keyValue.getKey(), String.format("vars.get(\"%s\")", keyValue.getValue()), "=")
);
return arguments;
}
return null;
}
protected DataSource getDataSource(SQLProcessor sqlProcessor, EnvironmentInfoDTO envConfig) {
if (envConfig == null) {
return null;
}
List<DataSource> dataSources = envConfig.getConfig().getDataSources();
// 先按ID匹配
dataSources = dataSources.stream()
.filter(item -> StringUtils.equals(item.getId(), sqlProcessor.getDataSourceId()))
.toList();
// 再按名称匹配
if (CollectionUtils.isEmpty(dataSources)) {
dataSources = dataSources.stream()
.filter(item -> StringUtils.equals(item.getDataSource(), sqlProcessor.getDataSourceName()))
.toList();
}
return CollectionUtils.isEmpty(dataSources) ? null : dataSources.get(0);
}
protected AbstractJDBCProcessor getJdbcProcessor(SQLProcessor sqlProcessor, AbstractJDBCProcessor jdbcProcessor, DataSource dataSource) {
jdbcProcessor.setEnabled(sqlProcessor.getEnable());
jdbcProcessor.setName(sqlProcessor.getName() == null ? jdbcProcessor.getClass().getSimpleName() : sqlProcessor.getName());
jdbcProcessor.setProperty(TestElement.TEST_CLASS, jdbcProcessor.getClass().getSimpleName());
jdbcProcessor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(TEST_BEAN_GUI));
jdbcProcessor.setDataSource(sqlProcessor.getName());
jdbcProcessor.setProperty("dataSource", dataSource.getDataSource());
jdbcProcessor.setProperty("query", sqlProcessor.getScript());
jdbcProcessor.setProperty("queryTimeout", String.valueOf(sqlProcessor.getQueryTimeout()));
jdbcProcessor.setProperty("resultVariable", sqlProcessor.getResultVariable());
jdbcProcessor.setProperty("variableNames", sqlProcessor.getVariableNames());
jdbcProcessor.setProperty("resultSetHandler", "Store as String");
jdbcProcessor.setProperty("queryType", "Callable Statement");
return jdbcProcessor;
}
public DataSourceElement getDataSourceElement(DataSource dataSource) {
DataSourceElement dataSourceElement = new DataSourceElement();
dataSourceElement.setEnabled(true);
dataSourceElement.setName(dataSource.getDataSource() + "_JDBCDataSource");
dataSourceElement.setProperty(TestElement.TEST_CLASS, DataSourceElement.class.getName());
dataSourceElement.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(TEST_BEAN_GUI));
dataSourceElement.setProperty("autocommit", true);
dataSourceElement.setProperty("keepAlive", true);
dataSourceElement.setProperty("preinit", false);
dataSourceElement.setProperty("dataSource", dataSource.getDataSource());
dataSourceElement.setProperty("dbUrl", dataSource.getDbUrl());
dataSourceElement.setProperty("driver", dataSource.getDriver());
dataSourceElement.setProperty("username", dataSource.getUsername());
dataSourceElement.setProperty("password", dataSource.getPassword());
dataSourceElement.setProperty("poolMax", dataSource.getPoolMax());
dataSourceElement.setProperty("timeout", String.valueOf(dataSource.getTimeout()));
dataSourceElement.setProperty("connectionAge", 5000);
dataSourceElement.setProperty("trimInterval", 6000);
dataSourceElement.setProperty("transactionIsolation", "DEFAULT");
return dataSourceElement;
} }
} }

View File

@ -4,8 +4,12 @@ import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.project.api.assertion.MsScriptAssertion; import io.metersphere.project.api.assertion.MsScriptAssertion;
import io.metersphere.project.api.processor.ScriptProcessor; import io.metersphere.project.api.processor.ScriptProcessor;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.sdk.util.BeanUtils; import io.metersphere.sdk.util.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.assertions.BeanShellAssertion;
import org.apache.jmeter.assertions.JSR223Assertion; import org.apache.jmeter.assertions.JSR223Assertion;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.Optional; import java.util.Optional;
@ -21,14 +25,21 @@ public class ScriptAssertionConverter extends AssertionConverter<MsScriptAsserti
return; return;
} }
JSR223Assertion jsr223Assertion = new JSR223Assertion(); TestElement assertion = new JSR223Assertion();
if (isJSR233(msAssertion)) {
assertion = new BeanShellAssertion();
}
ScriptProcessor scriptProcessor = BeanUtils.copyBean(new ScriptProcessor(), msAssertion); ScriptProcessor scriptProcessor = BeanUtils.copyBean(new ScriptProcessor(), msAssertion);
ScriptProcessorConverter.parse(jsr223Assertion, scriptProcessor); ScriptProcessorConverter.parse(assertion, scriptProcessor);
// 添加公共脚本的参数 // 添加公共脚本的参数
Optional.ofNullable(ScriptProcessorConverter.getScriptArguments(scriptProcessor)) Optional.ofNullable(ScriptProcessorConverter.getScriptArguments(scriptProcessor))
.ifPresent(hashTree::add); .ifPresent(hashTree::add);
hashTree.add(jsr223Assertion); hashTree.add(assertion);
}
public static boolean isJSR233(MsScriptAssertion msScriptAssertion) {
return !StringUtils.equals(msScriptAssertion.getScriptLanguage(), ScriptLanguageType.BEANSHELL.name());
} }
} }

View File

@ -38,6 +38,7 @@ import io.metersphere.project.dto.environment.EnvironmentConfig;
import io.metersphere.project.dto.environment.EnvironmentGroupProjectDTO; import io.metersphere.project.dto.environment.EnvironmentGroupProjectDTO;
import io.metersphere.project.dto.environment.EnvironmentGroupRequest; import io.metersphere.project.dto.environment.EnvironmentGroupRequest;
import io.metersphere.project.dto.environment.EnvironmentRequest; import io.metersphere.project.dto.environment.EnvironmentRequest;
import io.metersphere.project.dto.environment.datasource.DataSource;
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;
@ -1035,6 +1036,9 @@ public class ApiScenarioControllerTests extends BaseTest {
sqlProcessor.setName("select * from test"); sqlProcessor.setName("select * from test");
EnvironmentConfig environmentConfig = new EnvironmentConfig(); EnvironmentConfig environmentConfig = new EnvironmentConfig();
DataSource dataSource = getDataSource();
environmentConfig.setDataSources(List.of(dataSource));
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();
@ -1118,6 +1122,17 @@ public class ApiScenarioControllerTests extends BaseTest {
envGroupId = environmentGroupService.add(groupRequest, "admin").getId(); envGroupId = environmentGroupService.add(groupRequest, "admin").getId();
} }
private DataSource getDataSource() {
DataSource dataSource = new DataSource();
dataSource.setDataSource("test");
dataSource.setId("dataSourceId");
dataSource.setDriver("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("Password123@mysql");
dataSource.setDbUrl("jdbc:mysql://192.168.15.41:3306/metersphere");
return dataSource;
}
@Test @Test
@Order(7) @Order(7)
public void get() throws Exception { public void get() throws Exception {

View File

@ -16,6 +16,7 @@ import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.api.KeyValueEnableParam; import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.api.KeyValueParam;
import io.metersphere.project.api.assertion.*; import io.metersphere.project.api.assertion.*;
import io.metersphere.project.api.assertion.body.*; import io.metersphere.project.api.assertion.body.*;
import io.metersphere.project.api.processor.ExtractPostProcessor; import io.metersphere.project.api.processor.ExtractPostProcessor;
@ -141,17 +142,22 @@ public class MsHTTPElementTest {
processors.add(beanShellScriptProcessor); processors.add(beanShellScriptProcessor);
SQLProcessor sqlProcessor = new SQLProcessor(); SQLProcessor sqlProcessor = new SQLProcessor();
sqlProcessor.setScript("script"); sqlProcessor.setScript("select * from user;");
sqlProcessor.setName("sqlProcessor");
KeyValueParam keyValueParam = new KeyValueParam();
keyValueParam.setKey("id");
keyValueParam.setValue("id_1");
sqlProcessor.setEnable(true); sqlProcessor.setEnable(true);
sqlProcessor.setDataSourceId("dataSourceId"); sqlProcessor.setDataSourceId("dataSourceId");
KeyValueEnableParam keyValueParam = new KeyValueEnableParam(); sqlProcessor.setExtractParams(List.of(keyValueParam));
keyValueParam.setKey("key");
keyValueParam.setValue("value");
sqlProcessor.setVariables(List.of(keyValueParam));
sqlProcessor.setResultVariable("ddd"); sqlProcessor.setResultVariable("ddd");
sqlProcessor.setQueryTimeout(1111); sqlProcessor.setQueryTimeout(1111);
sqlProcessor.setVariableNames("test"); sqlProcessor.setVariableNames("id,name");
sqlProcessor.setDataSourceName("test");
processors.add(sqlProcessor); processors.add(sqlProcessor);
SQLProcessor sqlProcessor1 = BeanUtils.copyBean(new SQLProcessor(), sqlProcessor);
sqlProcessor1.setDataSourceId("1111");
processors.add(sqlProcessor1);
TimeWaitingProcessor timeWaitingProcessor = new TimeWaitingProcessor(); TimeWaitingProcessor timeWaitingProcessor = new TimeWaitingProcessor();
timeWaitingProcessor.setDelay(1000); timeWaitingProcessor.setDelay(1000);

View File

@ -1,7 +1,6 @@
package io.metersphere.project.api.processor; package io.metersphere.project.api.processor;
import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.project.api.KeyValueEnableParam;
import io.metersphere.project.api.KeyValueParam; import io.metersphere.project.api.KeyValueParam;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
@ -36,22 +35,19 @@ public class SQLProcessor extends MsProcessor {
*/ */
@Size(max = 200) @Size(max = 200)
private String variableNames; private String variableNames;
/**
* 变量列表
*/
@Valid
private List<KeyValueEnableParam> variables;
/**
* 环境ID
*/
@Size(max = 50)
private String environmentId;
/** /**
* 数据源ID * 数据源ID
*/ */
@NotBlank @NotBlank
@Size(max = 50) @Size(max = 50)
private String dataSourceId; private String dataSourceId;
/**
* 数据源名称
* 用于匹配不同环境数据源
*/
@NotBlank
@Size(max = 255)
private String dataSourceName;
/** /**
* 提取参数 * 提取参数
*/ */

View File

@ -27,7 +27,7 @@ public class DataSource implements Serializable {
@Schema(description = "密码") @Schema(description = "密码")
private String password; private String password;
@Schema(description = "最大连接数") @Schema(description = "最大连接数")
private Long poolMax; private Long poolMax = 1L;
@Schema(description = "超时时间") @Schema(description = "超时时间")
private Long timeout; private Long timeout = 10000L;
} }

View File

@ -316,7 +316,6 @@ public class EnvironmentControllerTests extends BaseTest {
scriptProcessor.setScript("script"); scriptProcessor.setScript("script");
scriptProcessor.setName("测试计划级别脚本"); scriptProcessor.setName("测试计划级别脚本");
SQLProcessor sqlProcessor = new SQLProcessor(); SQLProcessor sqlProcessor = new SQLProcessor();
sqlProcessor.setEnvironmentId("environmentId");
sqlProcessor.setDataSourceId("dataSourceId"); sqlProcessor.setDataSourceId("dataSourceId");
sqlProcessor.setQueryTimeout(1000L); sqlProcessor.setQueryTimeout(1000L);
ApiEnvPlanProcessorConfig apiEnvPlanProcessorConfig = new ApiEnvPlanProcessorConfig(); ApiEnvPlanProcessorConfig apiEnvPlanProcessorConfig = new ApiEnvPlanProcessorConfig();