From e3e4af29889cac8dc322a2cf72dd8b13c2ae8eeb Mon Sep 17 00:00:00 2001
From: AgAngle <1323481023@qq.com>
Date: Fri, 19 Jan 2024 17:43:18 +0800
Subject: [PATCH] =?UTF-8?q?feat(=E9=A1=B9=E7=9B=AE=E8=AE=BE=E7=BD=AE):=20?=
=?UTF-8?q?=E5=85=AC=E5=85=B1=E8=84=9A=E6=9C=AC=E6=89=A7=E8=A1=8C=E6=8E=A5?=
=?UTF-8?q?=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../migration/3.0.0/dml/V3.0.0_11_1__data.sql | 7 +
.../sdk/constants/PermissionConstants.java | 1 +
.../sdk/dto/api/task/TaskRequestDTO.java | 2 +-
.../main/resources/i18n/project.properties | 3 +-
.../resources/i18n/project_en_US.properties | 2 +
.../resources/i18n/project_zh_CN.properties | 2 +
.../resources/i18n/project_zh_TW.properties | 2 +
.../resources/i18n/system_zh_CN.properties | 2 +-
backend/services/api-test/pom.xml | 5 +
.../api/controller/ApiTestController.java | 19 ++-
.../java/io/metersphere/api/dto/NodeDTO.java | 31 -----
.../controller/MsCommentScriptElement.java | 30 ++++
.../request/processors/ScriptProcessor.java | 19 +--
.../MsCommentScriptElementConverter.java | 82 +++++++++++
.../parser/jmeter/constants/JmeterAlias.java | 1 +
.../parser/jmeter/processor/ScriptFilter.java | 6 +-
.../processor/ScriptProcessorConverter.java | 5 +-
.../assertion/VariableAssertionConverter.java | 3 +-
.../api/service/ApiExecuteService.java | 121 +++++++++++++---
.../api/service/RoundRobinService.java | 12 +-
.../utils/JmeterElementConverterRegister.java | 2 +
.../controller/ApiDebugControllerTests.java | 108 +--------------
.../controller/ApiTestControllerTests.java | 37 +++++
.../api/controller/MsHTTPElementTest.java | 5 +-
.../service/BaseResourcePoolTestService.java | 131 ++++++++++++++++++
.../api/service/RoundRobinServiceTests.java | 26 ++--
.../project/constants/ScriptLanguageType.java | 23 +++
.../controller/CustomFunctionController.java | 2 -
.../request/CustomFunctionRunRequest.java | 34 +++++
.../processors/ScriptProcessor.java | 20 +--
.../src/main/resources/permission.json | 22 +++
.../system/dto/pool/TestResourceNodeDTO.java | 4 +
.../controller/PluginControllerTests.java | 22 +--
33 files changed, 557 insertions(+), 234 deletions(-)
delete mode 100644 backend/services/api-test/src/main/java/io/metersphere/api/dto/NodeDTO.java
create mode 100644 backend/services/api-test/src/main/java/io/metersphere/api/dto/request/controller/MsCommentScriptElement.java
create mode 100644 backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsCommentScriptElementConverter.java
create mode 100644 backend/services/api-test/src/test/java/io/metersphere/api/service/BaseResourcePoolTestService.java
create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/constants/ScriptLanguageType.java
create mode 100644 backend/services/project-management/src/main/java/io/metersphere/project/dto/customfunction/request/CustomFunctionRunRequest.java
diff --git a/backend/framework/domain/src/main/resources/migration/3.0.0/dml/V3.0.0_11_1__data.sql b/backend/framework/domain/src/main/resources/migration/3.0.0/dml/V3.0.0_11_1__data.sql
index d3b613838c..5394ad1609 100644
--- a/backend/framework/domain/src/main/resources/migration/3.0.0/dml/V3.0.0_11_1__data.sql
+++ b/backend/framework/domain/src/main/resources/migration/3.0.0/dml/V3.0.0_11_1__data.sql
@@ -200,6 +200,11 @@ INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+UPDATE');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_TEST_PLAN:READ+EXECUTE');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_CUSTOM_FUNCTION:READ');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_CUSTOM_FUNCTION:READ+ADD');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_CUSTOM_FUNCTION:READ+UPDATE');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_CUSTOM_FUNCTION:READ+DELETE');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_CUSTOM_FUNCTION:READ+EXECUTE');
-- 项目成员权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_BASE_INFO:READ');
@@ -255,6 +260,8 @@ INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_BUG:READ+DELETE');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_BUG:READ+EXPORT');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_BASE_INFO:READ+UPDATE');
+INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_CUSTOM_FUNCTION:READ');
+
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_API_DEBUG:READ');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_API_DEBUG:READ+ADD');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_member', 'PROJECT_API_DEBUG:READ+UPDATE');
diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java
index 46f1eac0da..3b3c6eae43 100644
--- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java
+++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/constants/PermissionConstants.java
@@ -203,6 +203,7 @@ public class PermissionConstants {
public static final String PROJECT_CUSTOM_FUNCTION_ADD = "PROJECT_CUSTOM_FUNCTION:READ+ADD";
public static final String PROJECT_CUSTOM_FUNCTION_UPDATE = "PROJECT_CUSTOM_FUNCTION:READ+UPDATE";
public static final String PROJECT_CUSTOM_FUNCTION_DELETE = "PROJECT_CUSTOM_FUNCTION:READ+DELETE";
+ public static final String PROJECT_CUSTOM_FUNCTION_EXECUTE = "PROJECT_CUSTOM_FUNCTION:READ+EXECUTE";
/*------ end: PROJECT_CUSTOM_FUNCTION ------*/
/*------ start: PROJECT_TEMPLATE ------*/
diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java
index eefa7b5739..7adbb72657 100644
--- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java
+++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/dto/api/task/TaskRequestDTO.java
@@ -39,7 +39,7 @@ public class TaskRequestDTO implements Serializable {
/**
* 资源类型
- * ApiResourceType
+ * @see io.metersphere.sdk.constants.ApiExecuteResourceType
*/
private String resourceType;
diff --git a/backend/framework/sdk/src/main/resources/i18n/project.properties b/backend/framework/sdk/src/main/resources/i18n/project.properties
index a416da056f..de667b38f6 100644
--- a/backend/framework/sdk/src/main/resources/i18n/project.properties
+++ b/backend/framework/sdk/src/main/resources/i18n/project.properties
@@ -475,4 +475,5 @@ env_info_all=环境信息(总).json
# custom_function
custom_function_already_exist= 脚本名称已存在
-
+permission.project_custom_function.name=公共脚本
+permission.project_custom_function.execute=测试
\ No newline at end of file
diff --git a/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties
index 98e3749ff2..e9196e8b45 100644
--- a/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties
+++ b/backend/framework/sdk/src/main/resources/i18n/project_en_US.properties
@@ -513,3 +513,5 @@ env_info_all=All environment info.json
# custom_function
custom_function_already_exist= custom function name already exist
+permission.project_custom_function.name=Common script
+permission.project_custom_function.execute=Test
\ No newline at end of file
diff --git a/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties
index 72eb47f37d..b81a64c834 100644
--- a/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties
+++ b/backend/framework/sdk/src/main/resources/i18n/project_zh_CN.properties
@@ -512,3 +512,5 @@ env_info_all=环境信息(总).json
# custom_function
custom_function_already_exist= 脚本名称已存在
+permission.project_custom_function.name=公共脚本
+permission.project_custom_function.execute=测试
\ No newline at end of file
diff --git a/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties
index 7566d88424..e15c646e3a 100644
--- a/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties
+++ b/backend/framework/sdk/src/main/resources/i18n/project_zh_TW.properties
@@ -513,3 +513,5 @@ env_info_all=環境信息(总).json
# custom_function
custom_function_already_exist= 腳本名稱已存在
+permission.project_custom_function.name=公共腳本
+permission.project_custom_function.execute=測試
\ No newline at end of file
diff --git a/backend/framework/sdk/src/main/resources/i18n/system_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/system_zh_CN.properties
index ba7b82f5af..7a4b72b91a 100644
--- a/backend/framework/sdk/src/main/resources/i18n/system_zh_CN.properties
+++ b/backend/framework/sdk/src/main/resources/i18n/system_zh_CN.properties
@@ -309,4 +309,4 @@ operation_history.type.not_blank=变更记录操作类型不能为空
operation_history.type.length_range=变更记录操作类型长度必须在{min}和{max}之间
operation_history.source_id.not_blank=变更记录资源 ID 不能为空
operation_history.version_id.not_blank=变更记录版本 ID 不能为空
-operation_history.version_id.length_range=变更记录版本 ID 长度必须在{min}和{max}之间
\ No newline at end of file
+operation_history.version_id.length_range=变更记录版本 ID 长度必须在{min}和{max}之间
diff --git a/backend/services/api-test/pom.xml b/backend/services/api-test/pom.xml
index 922129290b..4af1e0e26e 100644
--- a/backend/services/api-test/pom.xml
+++ b/backend/services/api-test/pom.xml
@@ -57,6 +57,11 @@
ApacheJMeter_http
${jmeter.version}
+
+ org.apache.jmeter
+ ApacheJMeter_java
+ ${jmeter.version}
+
io.metersphere
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
index f45be2bdff..c9399dba26 100644
--- a/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/controller/ApiTestController.java
@@ -1,15 +1,17 @@
package io.metersphere.api.controller;
+import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.ApiTestService;
import io.metersphere.jmeter.mock.Mock;
+import io.metersphere.project.dto.customfunction.request.CustomFunctionRunRequest;
+import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.ProtocolDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
import java.util.List;
@@ -24,6 +26,8 @@ public class ApiTestController {
@Resource
private ApiTestService apiTestService;
+ @Resource
+ private ApiExecuteService apiExecuteService;
@GetMapping("/protocol/{organizationId}")
@Operation(summary = "获取协议插件的的协议列表")
@@ -37,4 +41,11 @@ public class ApiTestController {
public String mock(@PathVariable String key) {
return Mock.calculate(key).toString();
}
+
+ @PostMapping("/custom/func/run")
+ @Operation(summary = "项目管理-公共脚本-脚本测试")
+ @RequiresPermissions(PermissionConstants.PROJECT_CUSTOM_FUNCTION_EXECUTE)
+ public String run(@Validated @RequestBody CustomFunctionRunRequest runRequest) {
+ return apiExecuteService.runScript(runRequest);
+ }
}
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/NodeDTO.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/NodeDTO.java
deleted file mode 100644
index 808f48d1a9..0000000000
--- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/NodeDTO.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package io.metersphere.api.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-import java.io.Serial;
-import java.io.Serializable;
-
-@Data
-@AllArgsConstructor
-public class NodeDTO implements Serializable {
-
- @Serial
- private static final long serialVersionUID = 1L;
-
- /**
- * 接口测试 性能测试 node节点ip
- */
- private String ip;
-
- /**
- * 接口测试 性能测试 node节点端口
- */
- private String port;
-
- /**
- * 资源池最大并发数
- */
- private int podThreads;
-
-}
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/controller/MsCommentScriptElement.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/controller/MsCommentScriptElement.java
new file mode 100644
index 0000000000..f67086ad75
--- /dev/null
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/controller/MsCommentScriptElement.java
@@ -0,0 +1,30 @@
+package io.metersphere.api.dto.request.controller;
+
+import io.metersphere.api.dto.request.processors.ScriptProcessor;
+import io.metersphere.plugin.api.spi.AbstractMsTestElement;
+import io.metersphere.project.dto.environment.KeyValueParam;
+import lombok.Data;
+
+import java.util.List;
+
+
+/**
+ * 公共脚本组件
+ * 主要用于公共脚本测试执行时,生成jmx
+ */
+@Data
+public class MsCommentScriptElement extends AbstractMsTestElement {
+ /**
+ * 脚本内容
+ */
+ private String script;
+ /**
+ * 脚本语言
+ * @see ScriptProcessor.ScriptLanguageType
+ */
+ private String scriptLanguage;
+ /**
+ * 公共脚本入参
+ */
+ private List params;
+}
\ No newline at end of file
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/processors/ScriptProcessor.java b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/processors/ScriptProcessor.java
index b0349c7c13..7807899d82 100644
--- a/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/processors/ScriptProcessor.java
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/dto/request/processors/ScriptProcessor.java
@@ -2,6 +2,7 @@ package io.metersphere.api.dto.request.processors;
import com.fasterxml.jackson.annotation.JsonTypeName;
import io.metersphere.api.dto.request.http.KeyValueParam;
+import io.metersphere.project.constants.ScriptLanguageType;
import lombok.Data;
import java.util.List;
@@ -34,22 +35,4 @@ public class ScriptProcessor extends MsProcessor {
* 公共脚本入参
*/
private List params;
-
- public enum ScriptLanguageType {
- BEANSHELL("beanshell"),
- BEANSHELL_JSR233("beanshell-JSR233"),
- GROOVY("groovy"),
- JAVASCRIPT("javascript"),
- PYTHON("python");
-
- private String value;
-
- ScriptLanguageType(String value) {
- this.value = value;
- }
-
- public String getValue() {
- return value;
- }
- }
}
diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsCommentScriptElementConverter.java b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsCommentScriptElementConverter.java
new file mode 100644
index 0000000000..69438165fd
--- /dev/null
+++ b/backend/services/api-test/src/main/java/io/metersphere/api/parser/jmeter/MsCommentScriptElementConverter.java
@@ -0,0 +1,82 @@
+package io.metersphere.api.parser.jmeter;
+
+import io.metersphere.api.dto.request.controller.MsCommentScriptElement;
+import io.metersphere.api.dto.request.processors.ScriptProcessor;
+import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter;
+import io.metersphere.plugin.api.dto.ParameterConfig;
+import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
+import io.metersphere.project.dto.environment.KeyValueParam;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.jmeter.extractor.BeanShellPostProcessor;
+import org.apache.jmeter.extractor.JSR223PostProcessor;
+import org.apache.jmeter.modifiers.UserParameters;
+import org.apache.jmeter.save.SaveService;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jorphan.collections.HashTree;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static io.metersphere.api.parser.jmeter.constants.JmeterAlias.USER_PARAMETERS_GUI;
+
+/**
+ * @Author: jianxing
+ * @CreateTime: 2024-01-18 22:04
+ */
+public class MsCommentScriptElementConverter extends AbstractJmeterElementConverter {
+
+ @Override
+ public void toHashTree(HashTree hashTree, MsCommentScriptElement msElement, ParameterConfig config) {
+
+ if (CollectionUtils.isNotEmpty(msElement.getParams())) {
+ // 添加变量
+ List params = msElement.getParams()
+ .stream()
+ .filter(KeyValueParam::isValid)
+ .collect(Collectors.toList());
+
+ if (CollectionUtils.isNotEmpty(params)) {
+ UserParameters userParameters = getUserParameters(params);
+ hashTree.add(userParameters);
+ }
+ }
+
+ // 添加脚本
+ ScriptProcessor scriptProcessor = new ScriptProcessor();
+ scriptProcessor.setScriptLanguage(msElement.getScriptLanguage());
+ scriptProcessor.setScript(msElement.getScript());
+ TestElement scriptElement;
+ if (ScriptProcessorConverter.isJSR233(scriptProcessor)) {
+ scriptElement = new JSR223PostProcessor();
+ } else {
+ scriptElement = new BeanShellPostProcessor();
+ }
+ ScriptProcessorConverter.parse(scriptElement, scriptProcessor);
+ hashTree.add(scriptElement);
+ }
+
+ public static UserParameters getUserParameters(List params) {
+ UserParameters processor = new UserParameters();
+ processor.setEnabled(true);
+ processor.setName("User Defined Variables");
+ processor.setPerIteration(true);
+ processor.setProperty(TestElement.TEST_CLASS, UserParameters.class.getName());
+ processor.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass(USER_PARAMETERS_GUI));
+ if (CollectionUtils.isNotEmpty(params)) {
+ List names = new LinkedList<>();
+ List