From 61f477576d3184e00e0d7d5a510cedf483667002 Mon Sep 17 00:00:00 2001 From: AgAngle <1323481023@qq.com> Date: Thu, 29 Feb 2024 20:02:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95):=20?= =?UTF-8?q?=E8=A7=A3=E6=9E=90sql=E5=89=8D=E5=90=8E=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sdk/dto/api/result/RequestResult.java | 2 + .../sdk/dto/api/result/TaskResultDTO.java | 3 + backend/services/api-test/pom.xml | 5 + .../processor/SqlPostProcessorConverter.java | 10 +- .../processor/SqlPreProcessorConverter.java | 10 +- .../processor/SqlProcessorConverter.java | 133 +++++++++++++++++- .../assertion/ScriptAssertionConverter.java | 17 ++- .../ApiScenarioControllerTests.java | 15 ++ .../api/controller/MsHTTPElementTest.java | 18 ++- .../project/api/processor/SQLProcessor.java | 18 +-- .../environment/datasource/DataSource.java | 4 +- .../EnvironmentControllerTests.java | 1 - 12 files changed, 198 insertions(+), 38 deletions(-) diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/RequestResult.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/RequestResult.java index 34f3173ed7..5ffb6c466c 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/RequestResult.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/RequestResult.java @@ -97,11 +97,13 @@ public class RequestResult { /** * 子请求结果 + * {@link RequestResult} */ private List subRequestResults = new ArrayList<>(); /** * 响应结果 + * {@link ResponseResult} */ private ResponseResult responseResult = new ResponseResult(); diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/TaskResultDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/TaskResultDTO.java index f530470de8..7c135292ac 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/TaskResultDTO.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/result/TaskResultDTO.java @@ -15,6 +15,7 @@ public class TaskResultDTO implements Serializable { /** * 任务执行结果数据结构 + * {@link RequestResult} */ private List requestResults; /** @@ -31,11 +32,13 @@ public class TaskResultDTO implements Serializable { private Boolean hasEnded; /** * 执行过程状态 + * {@link ProcessResultDTO} */ private ProcessResultDTO processResultDTO; /** * 请求参数 + * {@link TaskRequestDTO} */ private TaskRequestDTO request; } diff --git a/backend/services/api-test/pom.xml b/backend/services/api-test/pom.xml index 2e82269a19..47ad14d867 100644 --- a/backend/services/api-test/pom.xml +++ b/backend/services/api-test/pom.xml @@ -62,6 +62,11 @@ ApacheJMeter_java ${jmeter.version} + + org.apache.jmeter + ApacheJMeter_jdbc + ${jmeter.version} + io.metersphere diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPostProcessorConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPostProcessorConverter.java index ccd3fe5b1a..f19da95843 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPostProcessorConverter.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPostProcessorConverter.java @@ -1,7 +1,8 @@ package io.metersphere.api.parser.jmeter.processor; -import io.metersphere.project.api.processor.SQLProcessor; 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; /** @@ -10,10 +11,7 @@ import org.apache.jorphan.collections.HashTree; */ public class SqlPostProcessorConverter extends SqlProcessorConverter { @Override - public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) { - if (!needParse(scriptProcessor, config)) { - return; - } - // todo 等环境开发完之后,补充 + public void parse(HashTree hashTree, SQLProcessor sqlProcessor, ParameterConfig config) { + parse(hashTree, sqlProcessor, config, JDBCPostProcessor.class); } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPreProcessorConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPreProcessorConverter.java index dff5f7d68b..a315e1fe42 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPreProcessorConverter.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlPreProcessorConverter.java @@ -1,7 +1,8 @@ package io.metersphere.api.parser.jmeter.processor; -import io.metersphere.project.api.processor.SQLProcessor; 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; /** @@ -10,10 +11,7 @@ import org.apache.jorphan.collections.HashTree; */ public class SqlPreProcessorConverter extends SqlProcessorConverter { @Override - public void parse(HashTree hashTree, SQLProcessor scriptProcessor, ParameterConfig config) { - if (!needParse(scriptProcessor, config)) { - return; - } - // todo 等环境开发完之后,补充 + public void parse(HashTree hashTree, SQLProcessor sqlProcessor, ParameterConfig config) { + parse(hashTree, sqlProcessor, config, JDBCPreProcessor.class); } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlProcessorConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlProcessorConverter.java index 200fac6740..83cfdff5fb 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlProcessorConverter.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/SqlProcessorConverter.java @@ -1,8 +1,25 @@ 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.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.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 { - protected void parse(TestElement testElement, ScriptProcessor scriptProcessor) { - // todo 等环境开发完之后,补充 + public void parse(HashTree hashTree, + SQLProcessor sqlProcessor, + ParameterConfig config, + Class 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 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 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 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; } } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/assertion/ScriptAssertionConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/assertion/ScriptAssertionConverter.java index dcc2a9f17c..c2d5e82e7e 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/assertion/ScriptAssertionConverter.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/processor/assertion/ScriptAssertionConverter.java @@ -4,8 +4,12 @@ import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter; import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.project.api.assertion.MsScriptAssertion; import io.metersphere.project.api.processor.ScriptProcessor; +import io.metersphere.project.constants.ScriptLanguageType; 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.testelement.TestElement; import org.apache.jorphan.collections.HashTree; import java.util.Optional; @@ -21,14 +25,21 @@ public class ScriptAssertionConverter extends AssertionConverter preProcessors = preProcessorConfig.getApiProcessorConfig().getScenarioProcessorConfig().getProcessors(); @@ -1118,6 +1122,17 @@ public class ApiScenarioControllerTests extends BaseTest { 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 @Order(7) public void get() throws Exception { diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java index 5abdd18106..1557450974 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/MsHTTPElementTest.java @@ -16,6 +16,7 @@ import io.metersphere.api.utils.ApiDataUtils; import io.metersphere.plugin.api.dto.ParameterConfig; import io.metersphere.plugin.api.spi.AbstractMsTestElement; import io.metersphere.project.api.KeyValueEnableParam; +import io.metersphere.project.api.KeyValueParam; import io.metersphere.project.api.assertion.*; import io.metersphere.project.api.assertion.body.*; import io.metersphere.project.api.processor.ExtractPostProcessor; @@ -141,17 +142,22 @@ public class MsHTTPElementTest { processors.add(beanShellScriptProcessor); 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.setDataSourceId("dataSourceId"); - KeyValueEnableParam keyValueParam = new KeyValueEnableParam(); - keyValueParam.setKey("key"); - keyValueParam.setValue("value"); - sqlProcessor.setVariables(List.of(keyValueParam)); + sqlProcessor.setExtractParams(List.of(keyValueParam)); sqlProcessor.setResultVariable("ddd"); sqlProcessor.setQueryTimeout(1111); - sqlProcessor.setVariableNames("test"); + sqlProcessor.setVariableNames("id,name"); + sqlProcessor.setDataSourceName("test"); processors.add(sqlProcessor); + SQLProcessor sqlProcessor1 = BeanUtils.copyBean(new SQLProcessor(), sqlProcessor); + sqlProcessor1.setDataSourceId("1111"); + processors.add(sqlProcessor1); TimeWaitingProcessor timeWaitingProcessor = new TimeWaitingProcessor(); timeWaitingProcessor.setDelay(1000); diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/api/processor/SQLProcessor.java b/backend/services/project-management/src/main/java/io/metersphere/project/api/processor/SQLProcessor.java index fb53c21544..2aa18cf11d 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/api/processor/SQLProcessor.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/api/processor/SQLProcessor.java @@ -1,7 +1,6 @@ package io.metersphere.project.api.processor; import com.fasterxml.jackson.annotation.JsonTypeName; -import io.metersphere.project.api.KeyValueEnableParam; import io.metersphere.project.api.KeyValueParam; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; @@ -36,22 +35,19 @@ public class SQLProcessor extends MsProcessor { */ @Size(max = 200) private String variableNames; - /** - * 变量列表 - */ - @Valid - private List variables; - /** - * 环境ID - */ - @Size(max = 50) - private String environmentId; /** * 数据源ID */ @NotBlank @Size(max = 50) private String dataSourceId; + /** + * 数据源名称 + * 用于匹配不同环境数据源 + */ + @NotBlank + @Size(max = 255) + private String dataSourceName; /** * 提取参数 */ diff --git a/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/datasource/DataSource.java b/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/datasource/DataSource.java index 97ec343640..338d86334b 100644 --- a/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/datasource/DataSource.java +++ b/backend/services/project-management/src/main/java/io/metersphere/project/dto/environment/datasource/DataSource.java @@ -27,7 +27,7 @@ public class DataSource implements Serializable { @Schema(description = "密码") private String password; @Schema(description = "最大连接数") - private Long poolMax; + private Long poolMax = 1L; @Schema(description = "超时时间") - private Long timeout; + private Long timeout = 10000L; } diff --git a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java index 8ac40034d8..0ddefc821c 100644 --- a/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java +++ b/backend/services/project-management/src/test/java/io/metersphere/project/controller/EnvironmentControllerTests.java @@ -316,7 +316,6 @@ public class EnvironmentControllerTests extends BaseTest { scriptProcessor.setScript("script"); scriptProcessor.setName("测试计划级别脚本"); SQLProcessor sqlProcessor = new SQLProcessor(); - sqlProcessor.setEnvironmentId("environmentId"); sqlProcessor.setDataSourceId("dataSourceId"); sqlProcessor.setQueryTimeout(1000L); ApiEnvPlanProcessorConfig apiEnvPlanProcessorConfig = new ApiEnvPlanProcessorConfig();