feat(项目设置): 公共脚本执行接口
This commit is contained in:
parent
46d1d3f43f
commit
e3e4af2988
|
@ -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');
|
||||
|
|
|
@ -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 ------*/
|
||||
|
|
|
@ -39,7 +39,7 @@ public class TaskRequestDTO implements Serializable {
|
|||
|
||||
/**
|
||||
* 资源类型
|
||||
* ApiResourceType
|
||||
* @see io.metersphere.sdk.constants.ApiExecuteResourceType
|
||||
*/
|
||||
private String resourceType;
|
||||
|
||||
|
|
|
@ -475,4 +475,5 @@ env_info_all=环境信息(总).json
|
|||
|
||||
# custom_function
|
||||
custom_function_already_exist= 脚本名称已存在
|
||||
|
||||
permission.project_custom_function.name=公共脚本
|
||||
permission.project_custom_function.execute=测试
|
|
@ -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
|
|
@ -512,3 +512,5 @@ env_info_all=环境信息(总).json
|
|||
|
||||
# custom_function
|
||||
custom_function_already_exist= 脚本名称已存在
|
||||
permission.project_custom_function.name=公共脚本
|
||||
permission.project_custom_function.execute=测试
|
|
@ -513,3 +513,5 @@ env_info_all=環境信息(总).json
|
|||
|
||||
# custom_function
|
||||
custom_function_already_exist= 腳本名稱已存在
|
||||
permission.project_custom_function.name=公共腳本
|
||||
permission.project_custom_function.execute=測試
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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))) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -91,6 +91,4 @@ public class CustomFunctionController {
|
|||
public void delete(@PathVariable String id) {
|
||||
customFunctionService.delete(id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 {
|
||||
|
||||
/**
|
||||
|
|
|
@ -136,18 +136,22 @@ public class PluginControllerTests extends BaseTest {
|
|||
Assertions.assertEquals(Arrays.asList("connect", "disconnect", "pub", "sub"), getScriptIdsByPlugId(plugin.getId()));
|
||||
addPlugin = plugin;
|
||||
|
||||
// 模拟其他节点加载插件
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.handlePluginAddNotified(plugin.getId(), jarFile.getName());
|
||||
try {
|
||||
// 模拟其他节点加载插件
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.handlePluginAddNotified(plugin.getId(), jarFile.getName());
|
||||
|
||||
// 增加覆盖率
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.loadPlugin(jarFile.getName());
|
||||
// 增加覆盖率
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.loadPlugin(jarFile.getName());
|
||||
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.loadPlugins();
|
||||
unloadAndDeletePlugin(jarFile, plugin);
|
||||
pluginLoadService.loadPlugins();
|
||||
|
||||
pluginLoadService.getExtensions(Platform.class);
|
||||
pluginLoadService.getExtensions(Platform.class);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 增加覆盖率
|
||||
this.requestGetWithOkAndReturn(DEFAULT_LIST);
|
||||
|
|
Loading…
Reference in New Issue