feat(项目设置): 公共脚本执行接口

This commit is contained in:
AgAngle 2024-01-19 17:43:18 +08:00 committed by Craftsman
parent 46d1d3f43f
commit e3e4af2988
33 changed files with 557 additions and 234 deletions

View File

@ -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');

View File

@ -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 ------*/

View File

@ -39,7 +39,7 @@ public class TaskRequestDTO implements Serializable {
/**
* 资源类型
* ApiResourceType
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
*/
private String resourceType;

View File

@ -475,4 +475,5 @@ env_info_all=环境信息(总).json
# custom_function
custom_function_already_exist= 脚本名称已存在
permission.project_custom_function.name=公共脚本
permission.project_custom_function.execute=测试

View File

@ -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

View File

@ -512,3 +512,5 @@ env_info_all=环境信息(总).json
# custom_function
custom_function_already_exist= 脚本名称已存在
permission.project_custom_function.name=公共脚本
permission.project_custom_function.execute=测试

View File

@ -513,3 +513,5 @@ env_info_all=環境信息(总).json
# custom_function
custom_function_already_exist= 腳本名稱已存在
permission.project_custom_function.name=公共腳本
permission.project_custom_function.execute=測試

View File

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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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<KeyValueParam> params;
}

View File

@ -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<KeyValueParam> 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;
}
}
}

View File

@ -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<MsCommentScriptElement> {
@Override
public void toHashTree(HashTree hashTree, MsCommentScriptElement msElement, ParameterConfig config) {
if (CollectionUtils.isNotEmpty(msElement.getParams())) {
// 添加变量
List<KeyValueParam> 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<KeyValueParam> 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<String> names = new LinkedList<>();
List<Object> values = new LinkedList<>();
List<Object> threadValues = new LinkedList<>();
for (KeyValueParam param : params) {
String name = param.getKey();
String value = param.getValue();
names.add(name);
values.add(value);
}
processor.setNames(names);
threadValues.add(values);
processor.setThreadLists(threadValues);
}
return processor;
}
}

View File

@ -16,4 +16,5 @@ public class JmeterAlias {
public static final String HTTP_TEST_SAMPLE_GUI = "HttpTestSampleGui";
public static final String XPATH_ASSERTION_GUI = "XPathAssertionGui";
public static final String X_PATH_2_ASSERTION_GUI = "XPath2AssertionGui";
public static final String USER_PARAMETERS_GUI = "UserParametersGui";
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.api.dto.request.processors.ScriptProcessor;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.LogUtils;
import org.apache.commons.collections4.CollectionUtils;
@ -57,10 +57,10 @@ public class ScriptFilter {
public static void verify(String language, String label, String script) {
// 默认 groovy
ScriptProcessor.ScriptLanguageType scriptLanguageType = Arrays.stream(ScriptProcessor.ScriptLanguageType.values())
ScriptLanguageType scriptLanguageType = Arrays.stream(ScriptLanguageType.values())
.filter(item -> StringUtils.equals(item.getValue(), language))
.findFirst()
.orElse(ScriptProcessor.ScriptLanguageType.GROOVY);
.orElse(ScriptLanguageType.GROOVY);
if (StringUtils.isNotEmpty(script)) {
final StringBuffer buffer = new StringBuffer();

View File

@ -1,5 +1,6 @@
package io.metersphere.api.parser.jmeter.processor;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.api.dto.request.processors.ScriptProcessor;
import io.metersphere.api.parser.jmeter.constants.JmeterAlias;
import io.metersphere.api.parser.jmeter.constants.JmeterProperty;
@ -36,7 +37,7 @@ public abstract class ScriptProcessorConverter extends MsProcessorConverter<Scri
testElement.setProperty(JmeterProperty.SCRIPT, scriptProcessor.getScript());
}
protected boolean isJSR233(ScriptProcessor scriptProcessor) {
return !StringUtils.equals(scriptProcessor.getScriptLanguage(), ScriptProcessor.ScriptLanguageType.BEANSHELL.getValue());
public static boolean isJSR233(ScriptProcessor scriptProcessor) {
return !StringUtils.equals(scriptProcessor.getScriptLanguage(), ScriptLanguageType.BEANSHELL.getValue());
}
}

View File

@ -1,5 +1,6 @@
package io.metersphere.api.parser.jmeter.processor.assertion;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.api.dto.request.assertion.MsVariableAssertion;
import io.metersphere.api.dto.request.processors.ScriptProcessor;
import io.metersphere.api.parser.jmeter.processor.ScriptProcessorConverter;
@ -57,7 +58,7 @@ public class VariableAssertionConverter extends AssertionConverter<MsVariableAss
String name = String.format("Variable '%s' expect %s %s", variableName, condition.toLowerCase().replace("_", ""), expectedValue);
scriptProcessor.setName(name);
scriptProcessor.setScriptLanguage(ScriptProcessor.ScriptLanguageType.BEANSHELL_JSR233.getValue());
scriptProcessor.setScriptLanguage(ScriptLanguageType.BEANSHELL_JSR233.getValue());
JSR223Assertion jsr223Assertion = new JSR223Assertion();
ScriptProcessorConverter.parse(jsr223Assertion, scriptProcessor);
return jsr223Assertion;

View File

@ -4,19 +4,24 @@ import io.metersphere.api.config.JmeterProperties;
import io.metersphere.api.config.KafkaConfig;
import io.metersphere.api.controller.result.ApiResultCode;
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.request.controller.MsCommentScriptElement;
import io.metersphere.api.parser.TestElementParser;
import io.metersphere.api.parser.TestElementParserFactory;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.dto.customfunction.request.CustomFunctionRunRequest;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileManagementService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.project.service.ProjectApplicationService;
import io.metersphere.sdk.constants.ApiExecuteResourceType;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.StorageType;
import io.metersphere.sdk.dto.api.task.ApiExecuteFileInfo;
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.*;
@ -27,6 +32,7 @@ import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import io.metersphere.system.service.CommonProjectService;
import io.metersphere.system.service.SystemParameterService;
import io.metersphere.system.service.TestResourcePoolService;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.system.utils.TaskRunnerClient;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
@ -39,7 +45,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -66,6 +71,8 @@ public class ApiExecuteService {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RoundRobinService roundRobinService;
@Resource
private JmeterProperties jmeterProperties;
@Resource
private ApiFileResourceService apiFileResourceService;
@ -104,16 +111,14 @@ public class ApiExecuteService {
}
public void debug(ApiResourceRunRequest request) {
TestResourceDTO resourcePoolDTO = getAvailableResourcePoolDTO(request.getProjectId());
String reportId = request.getReportId();
String testId = request.getTestId();
TaskRequestDTO taskRequest = new TaskRequestDTO();
BeanUtils.copyBean(taskRequest, request);
taskRequest.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
taskRequest.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
taskRequest.setMsUrl(systemParameterService.getBaseInfo().getUrl());
taskRequest.setRealTime(true);
taskRequest.setResourceId(testId);
setServerInfoParam(taskRequest);
// 设置执行文件参数
setTaskFileParam(request, taskRequest);
@ -128,15 +133,30 @@ public class ApiExecuteService {
parameterConfig.setReportId(reportId);
String executeScript = parseExecuteScript(request.getRequest(), parameterConfig);
TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(request.getProjectId());
doDebug(reportId, testId, taskRequest, executeScript, testResourceNodeDTO);
}
/**
* 发送执行任务
* @param reportId 报告ID
* @param testId 资源ID
* @param taskRequest 执行参数
* @param executeScript 执行脚本
* @param testResourceNodeDTO 资源池
*/
private void doDebug(String reportId,
String testId,
TaskRequestDTO taskRequest,
String executeScript,
TestResourceNodeDTO testResourceNodeDTO) {
// 将测试脚本缓存到 redis
String scriptRedisKey = getScriptRedisKey(reportId, testId);
stringRedisTemplate.opsForValue().set(scriptRedisKey, executeScript);
List<TestResourceNodeDTO> nodesList = resourcePoolDTO.getNodesList();
int index = new SecureRandom().nextInt(nodesList.size());
TestResourceNodeDTO testResourceNodeDTO = nodesList.get(index);
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
try {
String endpoint = TaskRunnerClient.getEndpoint(testResourceNodeDTO.getIp(), testResourceNodeDTO.getPort());
LogUtils.info(String.format("开始发送请求【 %s 】到 %s 节点执行", testId, endpoint), reportId);
TaskRunnerClient.debugApi(endpoint, taskRequest);
} catch (Exception e) {
@ -147,6 +167,57 @@ public class ApiExecuteService {
}
}
private TestResourceNodeDTO getProjectExecuteNode(String projectId) {
String resourcePoolId = getProjectApiResourcePoolId(projectId);
TestResourceDTO resourcePoolDTO = getAvailableResourcePoolDTO(projectId, resourcePoolId);
roundRobinService.initializeNodes(resourcePoolId, resourcePoolDTO.getNodesList());
try {
return roundRobinService.getNextNode(resourcePoolId);
} catch (Exception e) {
LogUtils.error(e);
throw new MSException("get execute node error", e);
}
}
/**
* 设置minio kafka ms 等信息
*
* @param taskRequest
*/
private void setServerInfoParam(TaskRequestDTO taskRequest) {
taskRequest.setKafkaConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(KafkaConfig.getKafkaConfig())));
taskRequest.setMinioConfig(EncryptUtils.aesEncrypt(JSON.toJSONString(getMinio())));
taskRequest.setMsUrl(systemParameterService.getBaseInfo().getUrl());
}
/**
* 公共脚本执行
* @param runRequest
* @return
*/
public String runScript(CustomFunctionRunRequest runRequest) {
String reportId = IDGenerator.nextStr();
String testId = runRequest.getProjectId();
// 生成执行脚本
MsCommentScriptElement msCommentScriptElement = BeanUtils.copyBean(new MsCommentScriptElement(), runRequest);
String executeScript = parseExecuteScript(msCommentScriptElement, new ParameterConfig());
// 设置执行参数
TaskRequestDTO taskRequest = new TaskRequestDTO();
setServerInfoParam(taskRequest);
taskRequest.setRealTime(true);
taskRequest.setReportId(reportId);
taskRequest.setResourceId(testId);
taskRequest.setResourceType(ApiExecuteResourceType.API_DEBUG.name());
ApiRunModeConfigDTO apiRunModeConfig = new ApiRunModeConfigDTO();
apiRunModeConfig.setRunMode(ApiExecuteRunMode.BACKEND_DEBUG.name());
taskRequest.setRunModeConfig(apiRunModeConfig);
TestResourceNodeDTO testResourceNodeDTO = getProjectExecuteNode(runRequest.getProjectId());
doDebug(reportId, testId, taskRequest, executeScript, testResourceNodeDTO);
return reportId;
}
/**
* taskRequest 设置文件相关参数
*
@ -236,14 +307,18 @@ public class ApiExecuteService {
* 生成执行脚本
*
* @param testElementStr
* @param msParameter
* @param config
* @return
*/
private static String parseExecuteScript(String testElementStr, ParameterConfig msParameter) {
private static String parseExecuteScript(String testElementStr, ParameterConfig config) {
// 解析生成脚本
return parseExecuteScript(ApiDataUtils.parseObject(testElementStr, AbstractMsTestElement.class), config);
}
private static String parseExecuteScript(AbstractMsTestElement msTestElement, ParameterConfig config) {
// 解析生成脚本
TestElementParser defaultParser = TestElementParserFactory.getDefaultParser();
AbstractMsTestElement msTestElement = ApiDataUtils.parseObject(testElementStr, AbstractMsTestElement.class);
return defaultParser.parse(msTestElement, msParameter);
return defaultParser.parse(msTestElement, config);
}
@ -262,14 +337,7 @@ public class ApiExecuteService {
* @param projectId
* @param
*/
public TestResourceDTO getAvailableResourcePoolDTO(String projectId) {
// 查询接口默认资源池
ProjectApplication resourcePoolConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
// 没有配置接口默认资源池
if (resourcePoolConfig == null || StringUtils.isBlank(resourcePoolConfig.getTypeValue())) {
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
}
String resourcePoolId = StringUtils.isBlank(resourcePoolConfig.getTypeValue()) ? null : resourcePoolConfig.getTypeValue();
public TestResourceDTO getAvailableResourcePoolDTO(String projectId, String resourcePoolId) {
TestResourcePool testResourcePool = testResourcePoolService.getTestResourcePool(resourcePoolId);
if (testResourcePool == null ||
// 资源池禁用
@ -280,4 +348,15 @@ public class ApiExecuteService {
}
return testResourcePoolService.getTestResourceDTO(resourcePoolId);
}
private String getProjectApiResourcePoolId(String projectId) {
// 查询接口默认资源池
ProjectApplication resourcePoolConfig = projectApplicationService.getByType(projectId, ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
// 没有配置接口默认资源池
if (resourcePoolConfig == null || StringUtils.isBlank(resourcePoolConfig.getTypeValue())) {
throw new MSException(ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
}
String resourcePoolId = StringUtils.isBlank(resourcePoolConfig.getTypeValue()) ? null : resourcePoolConfig.getTypeValue();
return resourcePoolId;
}
}

View File

@ -1,7 +1,7 @@
package io.metersphere.api.service;
import io.metersphere.api.dto.NodeDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
@ -17,7 +17,7 @@ public class RoundRobinService {
/**
* 获取下一个节点
*/
public String getNextNode(String poolId) throws Exception {
public TestResourceNodeDTO getNextNode(String poolId) throws Exception {
// 从列表头部获取下一个节点
String node = redisTemplate.opsForList().leftPop(poolId);
@ -35,22 +35,24 @@ public class RoundRobinService {
if (StringUtils.isNotBlank(node)) {
// 将节点重新放回列表尾部实现轮询
redisTemplate.opsForList().rightPush(poolId, node);
} else {
return null;
}
return node;
return JSON.parseObject(node, TestResourceNodeDTO.class);
}
/**
* 初始化节点列表
*/
public void initializeNodes(String poolId, List<NodeDTO> nodes) {
public void initializeNodes(String poolId, List<TestResourceNodeDTO> nodes) {
// 检查节点是否有变更
Long poolSize = redisTemplate.opsForList().size(poolId);
int size = poolSize != null ? poolSize.intValue() : 0;
if (size == nodes.size()) {
// 对比redis中的节点列表和传入的节点列表是否一致
boolean isSame = true;
for (NodeDTO node : nodes) {
for (TestResourceNodeDTO node : nodes) {
boolean isExist = false;
for (int i = 0; i < size; i++) {
if (JSON.toJSONString(node).equals(redisTemplate.opsForList().index(poolId, i))) {

View File

@ -1,5 +1,6 @@
package io.metersphere.api.utils;
import io.metersphere.api.parser.jmeter.MsCommentScriptElementConverter;
import io.metersphere.api.parser.jmeter.MsCommonElementConverter;
import io.metersphere.api.parser.jmeter.MsHTTPElementConverter;
import io.metersphere.plugin.api.spi.AbstractJmeterElementConverter;
@ -28,6 +29,7 @@ public class JmeterElementConverterRegister {
// 注册默认的转换器 todo 注册插件的转换器
register(MsHTTPElementConverter.class);
register(MsCommonElementConverter.class);
register(MsCommentScriptElementConverter.class);
}
/**

View File

@ -16,22 +16,16 @@ import io.metersphere.api.parser.ImportParserFactory;
import io.metersphere.api.parser.TestElementParserFactory;
import io.metersphere.api.parser.jmeter.MsScenarioConverter;
import io.metersphere.api.service.ApiFileResourceService;
import io.metersphere.api.service.BaseResourcePoolTestService;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectTestResourcePool;
import io.metersphere.project.domain.ProjectTestResourcePoolExample;
import io.metersphere.project.dto.filemanagement.FileInfo;
import io.metersphere.project.dto.filemanagement.request.FileUploadRequest;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.project.mapper.ProjectTestResourcePoolMapper;
import io.metersphere.project.service.FileAssociationService;
import io.metersphere.project.service.FileMetadataService;
import io.metersphere.sdk.constants.DefaultRepositoryDir;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.ResourcePoolTypeEnum;
import io.metersphere.sdk.file.FileCenter;
import io.metersphere.sdk.file.FileRequest;
import io.metersphere.sdk.util.BeanUtils;
@ -40,28 +34,16 @@ import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.domain.TestResourcePool;
import io.metersphere.system.domain.TestResourcePoolBlob;
import io.metersphere.system.domain.TestResourcePoolOrganization;
import io.metersphere.system.domain.TestResourcePoolOrganizationExample;
import io.metersphere.system.dto.pool.TestResourceDTO;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import io.metersphere.system.dto.pool.TestResourcePoolDTO;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.mapper.TestResourcePoolBlobMapper;
import io.metersphere.system.mapper.TestResourcePoolMapper;
import io.metersphere.system.mapper.TestResourcePoolOrganizationMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.jorphan.collections.ListedHashTree;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MvcResult;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.util.LinkedList;
import java.util.List;
@ -92,19 +74,7 @@ public class ApiDebugControllerTests extends BaseTest {
@Resource
private FileMetadataService fileMetadataService;
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Resource
private TestResourcePoolOrganizationMapper testResourcePoolOrganizationMapper;
@Resource
private ProjectTestResourcePoolMapper projectTestResourcePoolMapper;
@Resource
private TestResourcePoolMapper testResourcePoolMapper;
@Resource
private TestResourcePoolBlobMapper testResourcePoolBlobMapper;
@Value("${embedded.mockserver.host}")
private String mockServerHost;
@Value("${embedded.mockserver.port}")
private int mockServerHostPort;
private BaseResourcePoolTestService baseResourcePoolTestService;
private static ApiDebug addApiDebug;
private static ApiDebug anotherAddApiDebug;
private static String fileMetadataId;
@ -397,13 +367,13 @@ public class ApiDebugControllerTests extends BaseTest {
// @校验组织没有资源池权限异常
assertErrorCode(this.requestPost(DEBUG, request), ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
TestResourcePool resourcePool = insertResourcePool();
insertResourcePoolOrg(resourcePool);
TestResourcePool resourcePool = baseResourcePoolTestService.insertResourcePool();
baseResourcePoolTestService.insertResourcePoolOrg(resourcePool);
// @校验项目没有资源池权限异常
assertErrorCode(this.requestPost(DEBUG, request), ApiResultCode.EXECUTE_RESOURCE_POOL_NOT_CONFIG);
insertResourcePoolProject(resourcePool);
insertProjectApplication(resourcePool);
baseResourcePoolTestService.insertResourcePoolProject(resourcePool);
baseResourcePoolTestService.insertProjectApplication(resourcePool);
// @校验资源池调用失败
assertErrorCode(this.requestPost(DEBUG, request), ApiResultCode.RESOURCE_POOL_EXECUTE_ERROR);
@ -485,71 +455,6 @@ public class ApiDebugControllerTests extends BaseTest {
this.requestPostWithOk(DEBUG, request);
}
private TestResourcePool insertResourcePool() {
String id = IDGenerator.nextStr();
TestResourcePoolDTO testResourcePool = new TestResourcePoolDTO();
testResourcePool.setId(id);
testResourcePool.setApiTest(true);
testResourcePool.setCreateTime(System.currentTimeMillis());
testResourcePool.setUpdateTime(System.currentTimeMillis());
testResourcePool.setDeleted(false);
testResourcePool.setName("api debug test");
testResourcePool.setCreateUser("admin");
testResourcePool.setAllOrg(false);
testResourcePool.setEnable(true);
testResourcePool.setType(ResourcePoolTypeEnum.NODE.name());
TestResourcePoolBlob testResourcePoolBlob = new TestResourcePoolBlob();
testResourcePoolBlob.setId(id);
TestResourceDTO testResourceDTO = new TestResourceDTO();
TestResourceNodeDTO testResourceNodeDTO = new TestResourceNodeDTO();
testResourceNodeDTO.setIp(mockServerHost);
testResourceNodeDTO.setPort(mockServerHostPort + StringUtils.EMPTY);
testResourceNodeDTO.setConcurrentNumber(10);
testResourceDTO.setNodesList(List.of(testResourceNodeDTO));
String configuration = JSON.toJSONString(testResourceDTO);
testResourcePoolBlob.setConfiguration(configuration.getBytes());
testResourcePool.setTestResourceDTO(testResourceDTO);
testResourcePoolMapper.insert(testResourcePool);
testResourcePoolBlobMapper.insert(testResourcePoolBlob);
return testResourcePool;
}
private void insertProjectApplication(TestResourcePool resourcePool) {
ProjectApplication projectApplication = new ProjectApplication();
projectApplication.setTypeValue(resourcePool.getId());
projectApplication.setType(ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
projectApplication.setProjectId(DEFAULT_PROJECT_ID);
projectApplicationMapper.insert(projectApplication);
}
private void insertResourcePoolProject(TestResourcePool resourcePool) {
ProjectTestResourcePoolExample example = new ProjectTestResourcePoolExample();
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID);
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePool.getId());
List<ProjectTestResourcePool> projectTestResourcePools = projectTestResourcePoolMapper.selectByExample(example);
if (CollectionUtils.isEmpty(projectTestResourcePools)) {
ProjectTestResourcePool projectTestResourcePool = new ProjectTestResourcePool();
projectTestResourcePool.setTestResourcePoolId(resourcePool.getId());
projectTestResourcePool.setProjectId(DEFAULT_PROJECT_ID);
projectTestResourcePoolMapper.insert(projectTestResourcePool);
}
}
private void insertResourcePoolOrg(TestResourcePool resourcePool) {
TestResourcePoolOrganizationExample example = new TestResourcePoolOrganizationExample();
example.createCriteria().andOrgIdEqualTo(DEFAULT_ORGANIZATION_ID);
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePool.getId());
List<TestResourcePoolOrganization> testResourcePoolOrganizations = testResourcePoolOrganizationMapper.selectByExample(example);
if (CollectionUtils.isEmpty(testResourcePoolOrganizations)) {
TestResourcePoolOrganization resourcePoolOrganization = new TestResourcePoolOrganization();
resourcePoolOrganization.setTestResourcePoolId(resourcePool.getId());
resourcePoolOrganization.setOrgId(DEFAULT_ORGANIZATION_ID);
resourcePoolOrganization.setId(IDGenerator.nextStr());
testResourcePoolOrganizationMapper.insert(resourcePoolOrganization);
}
}
@Test
@Order(7)
public void delete() throws Exception {
@ -568,4 +473,5 @@ public class ApiDebugControllerTests extends BaseTest {
// @@校验权限
requestGetPermissionTest(PermissionConstants.PROJECT_API_DEBUG_DELETE, DEFAULT_DELETE, addApiDebug.getId());
}
}

View File

@ -1,12 +1,20 @@
package io.metersphere.api.controller;
import io.metersphere.api.service.BaseResourcePoolTestService;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.project.dto.customfunction.request.CustomFunctionRunRequest;
import io.metersphere.project.dto.environment.KeyValueParam;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.base.BaseTest;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2023-11-07 17:07
@ -19,7 +27,10 @@ public class ApiTestControllerTests extends BaseTest {
private static final String BASE_PATH = "/api/test/";
protected static final String PROTOCOL_LIST = "protocol/{0}";
protected static final String MOCK = "mock/{0}";
protected static final String CUSTOM_FUNC_RUN = "custom/func/run";
@Resource
private BaseResourcePoolTestService baseResourcePoolTestService;
@Override
protected String getBasePath() {
return BASE_PATH;
@ -36,4 +47,30 @@ public class ApiTestControllerTests extends BaseTest {
// @@请求成功
this.requestGetWithOk(MOCK, "@integer").andReturn();
}
@Test
public void runCustomFunc() throws Exception {
mockPost("/api/debug", "");
// 初始化资源池
baseResourcePoolTestService.initProjectResourcePool();
CustomFunctionRunRequest request = new CustomFunctionRunRequest();
request.setProjectId(DEFAULT_PROJECT_ID);
request.setType(ScriptLanguageType.BEANSHELL.getValue());
request.setScript("""
log.info("========");
log.info("${test}");
""");
// @@请求成功
this.requestPostWithOk(CUSTOM_FUNC_RUN, request);
KeyValueParam keyValueParam = new KeyValueParam();
keyValueParam.setKey("test");
keyValueParam.setValue("value");
request.setParams(List.of(keyValueParam));
// @@请求成功
this.requestPostWithOk(CUSTOM_FUNC_RUN, request);
// @@校验权限
requestPostPermissionTest(PermissionConstants.PROJECT_CUSTOM_FUNCTION_EXECUTE, CUSTOM_FUNC_RUN, request);
}
}

View File

@ -22,6 +22,7 @@ import io.metersphere.api.parser.TestElementParserFactory;
import io.metersphere.api.utils.ApiDataUtils;
import io.metersphere.plugin.api.dto.ParameterConfig;
import io.metersphere.plugin.api.spi.AbstractMsTestElement;
import io.metersphere.project.constants.ScriptLanguageType;
import io.metersphere.sdk.constants.MsAssertionCondition;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -135,13 +136,13 @@ public class MsHTTPElementTest {
ScriptProcessor scriptProcessor = new ScriptProcessor();
scriptProcessor.setEnable(true);
scriptProcessor.setScript("script");
scriptProcessor.setScriptLanguage(ScriptProcessor.ScriptLanguageType.JAVASCRIPT.getValue());
scriptProcessor.setScriptLanguage(ScriptLanguageType.JAVASCRIPT.getValue());
processors.add(scriptProcessor);
ScriptProcessor beanShellScriptProcessor = new ScriptProcessor();
beanShellScriptProcessor.setEnable(true);
beanShellScriptProcessor.setScript("script");
beanShellScriptProcessor.setScriptLanguage(ScriptProcessor.ScriptLanguageType.BEANSHELL.getValue());
beanShellScriptProcessor.setScriptLanguage(ScriptLanguageType.BEANSHELL.getValue());
processors.add(beanShellScriptProcessor);
SQLProcessor sqlProcessor = new SQLProcessor();

View File

@ -0,0 +1,131 @@
package io.metersphere.api.service;
import io.metersphere.project.domain.ProjectApplication;
import io.metersphere.project.domain.ProjectApplicationExample;
import io.metersphere.project.domain.ProjectTestResourcePool;
import io.metersphere.project.domain.ProjectTestResourcePoolExample;
import io.metersphere.project.mapper.ProjectApplicationMapper;
import io.metersphere.project.mapper.ProjectTestResourcePoolMapper;
import io.metersphere.sdk.constants.ProjectApplicationType;
import io.metersphere.sdk.constants.ResourcePoolTypeEnum;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.TestResourcePool;
import io.metersphere.system.domain.TestResourcePoolBlob;
import io.metersphere.system.domain.TestResourcePoolOrganization;
import io.metersphere.system.domain.TestResourcePoolOrganizationExample;
import io.metersphere.system.dto.pool.TestResourceDTO;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import io.metersphere.system.dto.pool.TestResourcePoolDTO;
import io.metersphere.system.mapper.TestResourcePoolBlobMapper;
import io.metersphere.system.mapper.TestResourcePoolMapper;
import io.metersphere.system.mapper.TestResourcePoolOrganizationMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* @Author: jianxing
* @CreateTime: 2023-10-20 11:32
*/
@Service
public class BaseResourcePoolTestService {
@Resource
private ProjectApplicationMapper projectApplicationMapper;
@Resource
private TestResourcePoolOrganizationMapper testResourcePoolOrganizationMapper;
@Resource
private ProjectTestResourcePoolMapper projectTestResourcePoolMapper;
@Resource
private TestResourcePoolMapper testResourcePoolMapper;
@Resource
private TestResourcePoolBlobMapper testResourcePoolBlobMapper;
@Value("${embedded.mockserver.host}")
private String mockServerHost;
@Value("${embedded.mockserver.port}")
private int mockServerHostPort;
protected static final String DEFAULT_PROJECT_ID = "100001100001";
protected static final String DEFAULT_ORGANIZATION_ID = "100001";
public void initProjectResourcePool() {
TestResourcePool resourcePool = insertResourcePool();
insertResourcePoolOrg(resourcePool);
insertResourcePoolProject(resourcePool);
insertProjectApplication(resourcePool);
}
public TestResourcePool insertResourcePool() {
String id = IDGenerator.nextStr();
TestResourcePoolDTO testResourcePool = new TestResourcePoolDTO();
testResourcePool.setId(id);
testResourcePool.setApiTest(true);
testResourcePool.setCreateTime(System.currentTimeMillis());
testResourcePool.setUpdateTime(System.currentTimeMillis());
testResourcePool.setDeleted(false);
testResourcePool.setName("api debug test");
testResourcePool.setCreateUser("admin");
testResourcePool.setAllOrg(false);
testResourcePool.setEnable(true);
testResourcePool.setType(ResourcePoolTypeEnum.NODE.name());
TestResourcePoolBlob testResourcePoolBlob = new TestResourcePoolBlob();
testResourcePoolBlob.setId(id);
TestResourceDTO testResourceDTO = new TestResourceDTO();
TestResourceNodeDTO testResourceNodeDTO = new TestResourceNodeDTO();
testResourceNodeDTO.setIp(mockServerHost);
testResourceNodeDTO.setPort(mockServerHostPort + StringUtils.EMPTY);
testResourceNodeDTO.setConcurrentNumber(10);
testResourceDTO.setNodesList(List.of(testResourceNodeDTO));
String configuration = JSON.toJSONString(testResourceDTO);
testResourcePoolBlob.setConfiguration(configuration.getBytes());
testResourcePool.setTestResourceDTO(testResourceDTO);
testResourcePoolMapper.insert(testResourcePool);
testResourcePoolBlobMapper.insert(testResourcePoolBlob);
return testResourcePool;
}
public synchronized void insertProjectApplication(TestResourcePool resourcePool) {
ProjectApplicationExample example = new ProjectApplicationExample();
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID)
.andTypeEqualTo(ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
if (projectApplicationMapper.countByExample(example) > 0) {
return;
}
ProjectApplication projectApplication = new ProjectApplication();
projectApplication.setTypeValue(resourcePool.getId());
projectApplication.setType(ProjectApplicationType.API.API_RESOURCE_POOL_ID.name());
projectApplication.setProjectId(DEFAULT_PROJECT_ID);
projectApplicationMapper.insert(projectApplication);
}
public void insertResourcePoolProject(TestResourcePool resourcePool) {
ProjectTestResourcePoolExample example = new ProjectTestResourcePoolExample();
example.createCriteria().andProjectIdEqualTo(DEFAULT_PROJECT_ID);
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePool.getId());
List<ProjectTestResourcePool> projectTestResourcePools = projectTestResourcePoolMapper.selectByExample(example);
if (CollectionUtils.isEmpty(projectTestResourcePools)) {
ProjectTestResourcePool projectTestResourcePool = new ProjectTestResourcePool();
projectTestResourcePool.setTestResourcePoolId(resourcePool.getId());
projectTestResourcePool.setProjectId(DEFAULT_PROJECT_ID);
projectTestResourcePoolMapper.insert(projectTestResourcePool);
}
}
public void insertResourcePoolOrg(TestResourcePool resourcePool) {
TestResourcePoolOrganizationExample example = new TestResourcePoolOrganizationExample();
example.createCriteria().andOrgIdEqualTo(DEFAULT_ORGANIZATION_ID);
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePool.getId());
List<TestResourcePoolOrganization> testResourcePoolOrganizations = testResourcePoolOrganizationMapper.selectByExample(example);
if (CollectionUtils.isEmpty(testResourcePoolOrganizations)) {
TestResourcePoolOrganization resourcePoolOrganization = new TestResourcePoolOrganization();
resourcePoolOrganization.setTestResourcePoolId(resourcePool.getId());
resourcePoolOrganization.setOrgId(DEFAULT_ORGANIZATION_ID);
resourcePoolOrganization.setId(IDGenerator.nextStr());
testResourcePoolOrganizationMapper.insert(resourcePoolOrganization);
}
}
}

View File

@ -1,7 +1,7 @@
package io.metersphere.api.service;
import io.metersphere.api.dto.NodeDTO;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.dto.pool.TestResourceNodeDTO;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@ -24,11 +24,11 @@ public class RoundRobinServiceTests {
@Test
@Order(1)
public void testInit() throws Exception {
List<NodeDTO> nodes = new LinkedList<>();
nodes.add(new NodeDTO("172.0.0.1", "8080", 10));
nodes.add(new NodeDTO("172.0.0.2", "8080", 10));
nodes.add(new NodeDTO("172.0.0.3", "8080", 10));
nodes.add(new NodeDTO("172.0.0.4", "8080", 10));
List<TestResourceNodeDTO> nodes = new LinkedList<>();
nodes.add(new TestResourceNodeDTO("172.0.0.1", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.2", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.3", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.4", "8080", null, 10));
roundRobinService.initializeNodes("test", nodes);
}
@ -48,15 +48,15 @@ public class RoundRobinServiceTests {
@Test
@Order(3)
public void testInitAfter() throws Exception {
List<NodeDTO> nodes = new LinkedList<>();
nodes.add(new NodeDTO("172.0.0.1", "8080", 10));
nodes.add(new NodeDTO("172.0.0.2", "8080", 10));
nodes.add(new NodeDTO("172.0.0.3", "8080", 10));
List<TestResourceNodeDTO> nodes = new LinkedList<>();
nodes.add(new TestResourceNodeDTO("172.0.0.1", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.2", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.3", "8080", null, 10));
roundRobinService.initializeNodes("test", nodes);
nodes.add(new NodeDTO("172.0.0.3", "8080", 10));
nodes.add(new NodeDTO("172.0.0.7", "8080", 10));
nodes.add(new NodeDTO("172.0.0.6", "8080", 10));
nodes.add(new TestResourceNodeDTO("172.0.0.3", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.7", "8080", null, 10));
nodes.add(new TestResourceNodeDTO("172.0.0.6", "8080", null, 10));
roundRobinService.initializeNodes("test", nodes);
}

View File

@ -0,0 +1,23 @@
package io.metersphere.project.constants;
/**
* @Author: jianxing
* @CreateTime: 2024-01-19 18:19
*/
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;
}
}

View File

@ -91,6 +91,4 @@ public class CustomFunctionController {
public void delete(@PathVariable String id) {
customFunctionService.delete(id);
}
}

View File

@ -0,0 +1,34 @@
package io.metersphere.project.dto.customfunction.request;
import io.metersphere.project.dto.environment.KeyValueParam;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
@Data
public class CustomFunctionRunRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "脚本语言类型")
@NotBlank
@Size(max = 50)
private String type;
@Schema(description = "参数列表")
private List<KeyValueParam> params;
@Schema(description = "函数体")
@NotBlank
private String script;
@Schema(description = "项目ID")
@NotBlank
@Size(max = 50)
private String projectId;
}

View File

@ -16,7 +16,7 @@ public class ScriptProcessor extends MsProcessor {
/**
* 脚本语言
*
* @see ScriptLanguageType
* @see io.metersphere.project.constants.ScriptLanguageType
*/
private String scriptLanguage;
/**
@ -31,22 +31,4 @@ public class ScriptProcessor extends MsProcessor {
* 公共脚本入参
*/
private List<KeyValueParam> 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;
}
}
}

View File

@ -225,6 +225,28 @@
}
]
},
{
"id": "PROJECT_CUSTOM_FUNCTION",
"name": "permission.project_custom_function.name",
"permissions": [
{
"id": "PROJECT_CUSTOM_FUNCTION:READ"
},
{
"id": "PROJECT_CUSTOM_FUNCTION:READ+ADD"
},
{
"id": "PROJECT_CUSTOM_FUNCTION:READ+UPDATE"
},
{
"id": "PROJECT_CUSTOM_FUNCTION:READ+DELETE"
},
{
"id": "PROJECT_CUSTOM_FUNCTION:READ+EXECUTE",
"name": "permission.project_custom_function.execute"
}
]
},
{
"id": "PROJECT_LOG",
"name": "permission.project_log.name",

View File

@ -1,11 +1,15 @@
package io.metersphere.system.dto.pool;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TestResourceNodeDTO {
/**

View File

@ -136,6 +136,7 @@ public class PluginControllerTests extends BaseTest {
Assertions.assertEquals(Arrays.asList("connect", "disconnect", "pub", "sub"), getScriptIdsByPlugId(plugin.getId()));
addPlugin = plugin;
try {
// 模拟其他节点加载插件
unloadAndDeletePlugin(jarFile, plugin);
pluginLoadService.handlePluginAddNotified(plugin.getId(), jarFile.getName());
@ -148,6 +149,9 @@ public class PluginControllerTests extends BaseTest {
pluginLoadService.loadPlugins();
pluginLoadService.getExtensions(Platform.class);
} catch (Throwable e) {
e.printStackTrace();
}
// 增加覆盖率
this.requestGetWithOkAndReturn(DEFAULT_LIST);