diff --git a/api-test/backend/src/main/java/io/metersphere/api/dto/BodyFileRequest.java b/api-test/backend/src/main/java/io/metersphere/api/dto/BodyFileRequest.java new file mode 100644 index 0000000000..6b7a6dcfee --- /dev/null +++ b/api-test/backend/src/main/java/io/metersphere/api/dto/BodyFileRequest.java @@ -0,0 +1,11 @@ +package io.metersphere.api.dto; +import io.metersphere.request.BodyFile; +import lombok.Data; + +import java.util.List; + +@Data +public class BodyFileRequest { + private String reportId; + private List bodyFiles; +} diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseExecuteService.java index cc64b00090..9cc0f2153b 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiCaseExecuteService.java @@ -9,6 +9,7 @@ import io.metersphere.api.dto.definition.BatchRunDefinitionRequest; import io.metersphere.api.dto.scenario.DatabaseConfig; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.exec.queue.DBTestQueue; +import io.metersphere.api.jmeter.JMeterService; import io.metersphere.service.definition.ApiCaseResultService; import io.metersphere.service.ApiExecutionQueueService; import io.metersphere.service.scenario.ApiScenarioReportStructureService; @@ -66,7 +67,8 @@ public class ApiCaseExecuteService { private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper; @Resource private TestPlanApiCaseMapper testPlanApiCaseMapper; - + @Resource + private JMeterService jMeterService; /** * 测试计划case执行 @@ -275,6 +277,7 @@ public class ApiCaseExecuteService { if (request.getConfig() == null) { request.setConfig(new RunModeConfigDTO()); } + jMeterService.verifyPool(request.getProjectId(), request.getConfig()); if (StringUtils.equals(EnvironmentType.GROUP.toString(), request.getConfig().getEnvironmentType()) && StringUtils.isNotEmpty(request.getConfig().getEnvironmentGroupId())) { request.getConfig().setEnvMap(environmentGroupProjectService.getEnvMap(request.getConfig().getEnvironmentGroupId())); diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java index 2b0b1c9b97..25aeae20a1 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/api/ApiExecuteService.java @@ -23,12 +23,16 @@ import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper; import io.metersphere.base.mapper.plan.TestPlanApiCaseMapper; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ElementConstants; +import io.metersphere.commons.constants.ExtendedParameter; import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.commons.utils.*; +import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.dto.JmeterRunRequestDTO; import io.metersphere.dto.MsExecResponseDTO; +import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.environment.service.BaseEnvironmentService; import io.metersphere.plugin.core.MsTestElement; +import io.metersphere.service.SystemParameterService; import io.metersphere.service.definition.TcpApiParamService; import io.metersphere.utils.LoggerUtil; import org.apache.commons.collections.CollectionUtils; @@ -65,6 +69,8 @@ public class ApiExecuteService { private ObjectMapper mapper; @Resource private TestPlanApiCaseMapper testPlanApiCaseMapper; + @Resource + private SystemParameterService systemParameterService; public MsExecResponseDTO jenkinsRun(RunCaseRequest request) { ApiTestCaseWithBLOBs caseWithBLOBs = null; @@ -80,6 +86,8 @@ public class ApiExecuteService { if (caseWithBLOBs == null) { return null; } + jMeterService.verifyPool(caseWithBLOBs.getProjectId(), new RunModeConfigDTO()); + if (StringUtils.isBlank(request.getEnvironmentId())) { request.setEnvironmentId(extApiTestCaseMapper.getApiCaseEnvironment(request.getCaseId())); } @@ -232,10 +240,17 @@ public class ApiExecuteService { runRequest.setDebug(request.isDebug()); runRequest.setRunMode(runMode); runRequest.setExtendedParameters(new HashMap() {{ - this.put("SYN_RES", request.isSyncResult()); + this.put(ExtendedParameter.SYNC_STATUS, request.isSyncResult()); this.put("userId", SessionUtils.getUser().getId()); this.put("userName", SessionUtils.getUser().getName()); }}); + // 开始执行 + if (StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) { + runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId())); + runRequest.setPoolId(request.getConfig().getResourcePoolId()); + BaseSystemConfigDTO baseInfo = systemParameterService.getBaseInfo(); + runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, null)); + } return runRequest; } diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/engine/KubernetesTestEngine.java b/api-test/backend/src/main/java/io/metersphere/api/exec/engine/KubernetesTestEngine.java index fc736ce8d6..c519757304 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/engine/KubernetesTestEngine.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/engine/KubernetesTestEngine.java @@ -2,7 +2,9 @@ package io.metersphere.api.exec.engine; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.client.KubernetesClient; +import io.metersphere.api.dto.definition.request.MsTestPlan; import io.metersphere.base.domain.TestResource; +import io.metersphere.commons.constants.ExtendedParameter; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.JSON; import io.metersphere.commons.utils.LogUtil; @@ -55,13 +57,20 @@ public class KubernetesTestEngine extends AbstractEngine { .append(StringUtils.LF).append("Pod信息:【 ") .append(JSON.toJSONString(pod.getMetadata())).append(" 】"); LoggerUtil.info(logMsg); + String path = "api/start"; + if (runRequest.getHashTree() != null) { + path = "debug"; + runRequest.getExtendedParameters().put(ExtendedParameter.JMX, new MsTestPlan().getJmx(runRequest.getHashTree())); + runRequest.setHashTree(null); + LoggerUtil.info("进入DEBUG执行模式", runRequest.getReportId()); + } // 拼接CURL执行命令 StringBuffer command = new StringBuffer("curl -H \"Accept: application/json\" -H \"Content-type: application/json\" -X POST -d").append(StringUtils.SPACE); command.append("'").append(JSON.toJSONString(runRequest)).append("'"); // 请求参数 command.append(StringUtils.SPACE).append("--connect-timeout 30"); // 设置连接超时时间为30S command.append(StringUtils.SPACE).append("--max-time 120"); // 设置请求超时时间为120S command.append(StringUtils.SPACE).append("--retry 3"); // 设置重试次数3次 - command.append(StringUtils.SPACE).append("http://127.0.0.1:8082/jmeter/api/start"); + command.append(StringUtils.SPACE).append("http://127.0.0.1:8082/jmeter/").append(path); KubernetesApiExec.newExecWatch(client, clientCredential.getNamespace(), pod.getMetadata().getName(), command.toString()); } catch (Exception e) { LoggerUtil.error("当前报告:【" + runRequest.getReportId() + "】资源:【" + runRequest.getTestId() + "】CURL失败:", e); diff --git a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java index cee886f39c..79b27f8a80 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/exec/scenario/ApiScenarioExecuteService.java @@ -13,7 +13,9 @@ import io.metersphere.api.exec.api.ApiCaseExecuteService; import io.metersphere.api.exec.queue.DBTestQueue; import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.NewDriverManager; +import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.service.ApiExecutionQueueService; +import io.metersphere.service.SystemParameterService; import io.metersphere.service.scenario.ApiScenarioReportService; import io.metersphere.service.scenario.ApiScenarioReportStructureService; import io.metersphere.service.definition.TcpApiParamService; @@ -99,7 +101,9 @@ public class ApiScenarioExecuteService { @Resource protected TestPlanApiScenarioMapper testPlanApiScenarioMapper; @Resource - ExtTestPlanScenarioCaseMapper extTestPlanScenarioCaseMapper; + private ExtTestPlanScenarioCaseMapper extTestPlanScenarioCaseMapper; + @Resource + private SystemParameterService systemParameterService; public List run(RunScenarioRequest request) { if (LoggerUtil.getLogger().isDebugEnabled()) { @@ -417,6 +421,12 @@ public class ApiScenarioExecuteService { JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(request.getId(), request.getId(), runMode, hashTree); LoggerUtil.info(new MsTestPlan().getJmx(hashTree)); runRequest.setDebug(true); + if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) { + runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId())); + runRequest.setPoolId(request.getConfig().getResourcePoolId()); + BaseSystemConfigDTO baseInfo = systemParameterService.getBaseInfo(); + runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, null)); + } jMeterService.run(runRequest); return request.getId(); } diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java index 15490ea465..6a5984dbab 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/JMeterService.java @@ -1,6 +1,7 @@ package io.metersphere.api.jmeter; +import io.metersphere.api.dto.definition.request.MsTestPlan; import io.metersphere.api.exec.engine.EngineFactory; import io.metersphere.api.exec.queue.ExecThreadPoolExecutor; import io.metersphere.api.jmeter.utils.ServerConfig; @@ -8,16 +9,19 @@ import io.metersphere.api.jmeter.utils.SmoothWeighted; import io.metersphere.base.domain.TestResource; import io.metersphere.commons.config.KafkaConfig; import io.metersphere.commons.constants.ApiRunMode; +import io.metersphere.commons.constants.ExtendedParameter; +import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.*; import io.metersphere.config.JmeterProperties; import io.metersphere.constants.BackendListenerConstants; import io.metersphere.constants.RunModeConstants; -import io.metersphere.dto.JmeterRunRequestDTO; -import io.metersphere.dto.NodeDTO; +import io.metersphere.dto.*; import io.metersphere.engine.Engine; import io.metersphere.jmeter.JMeterBase; import io.metersphere.jmeter.LocalRunner; +import io.metersphere.service.BaseProjectApplicationService; import io.metersphere.service.RemakeReportService; +import io.metersphere.service.SystemParameterService; import io.metersphere.utils.LoggerUtil; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -42,12 +46,18 @@ import java.util.List; @Service public class JMeterService { public static final String BASE_URL = "http://%s:%d"; + public static final String POOL = "POOL"; + @Resource private JmeterProperties jmeterProperties; @Resource private RestTemplate restTemplate; @Resource private RedisTemplate redisTemplate; + @Resource + private SystemParameterService systemParameterService; + @Resource + private BaseProjectApplicationService projectApplicationService; @PostConstruct private void init() { @@ -112,8 +122,8 @@ public class JMeterService { } if (MapUtils.isNotEmpty(request.getExtendedParameters()) - && request.getExtendedParameters().containsKey("SYN_RES") - && (Boolean) request.getExtendedParameters().get("SYN_RES")) { + && request.getExtendedParameters().containsKey(ExtendedParameter.SYNC_STATUS) + && (Boolean) request.getExtendedParameters().get(ExtendedParameter.SYNC_STATUS)) { LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加Debug Listener"); addDebugListener(request.getReportId(), request.getHashTree()); } @@ -144,11 +154,52 @@ public class JMeterService { apiScenarioReportService.testEnded(request, e.getMessage()); LoggerUtil.error("调用K8S执行请求[ " + request.getTestId() + " ]失败:", request.getReportId(), e); } + } else if ((MapUtils.isNotEmpty(request.getExtendedParameters()) + && request.getExtendedParameters().containsKey(ExtendedParameter.SYNC_STATUS) + && (Boolean) request.getExtendedParameters().get(ExtendedParameter.SYNC_STATUS)) + || request.isDebug()) { + this.nodeDebug(request); } else { this.send(request); } } + private synchronized void nodeDebug(JmeterRunRequestDTO request) { + try { + if (request.isDebug() && !StringUtils.equalsAny(request.getRunMode(), ApiRunMode.DEFINITION.name())) { + request.getExtendedParameters().put(ExtendedParameter.SAVE_RESULT, true); + } else if (!request.isDebug()) { + request.getExtendedParameters().put(ExtendedParameter.SAVE_RESULT, true); + } + List resources = GenerateHashTreeUtil.setPoolResource(request.getPoolId()); + String uri = null; + int index = (int) (Math.random() * resources.size()); + String configuration = resources.get(index).getConfiguration(); + if (StringUtils.isNotEmpty(configuration)) { + NodeDTO node = com.alibaba.fastjson.JSON.parseObject(configuration, NodeDTO.class); + uri = String.format(BASE_URL + "/jmeter/debug", node.getIp(), node.getPort()); + } + if (StringUtils.isEmpty(uri)) { + LoggerUtil.info("未获取到资源池,请检查配置【系统设置-系统-测试资源池】", request.getReportId()); + MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常"); + } + request.getExtendedParameters().put(ExtendedParameter.JMX, new MsTestPlan().getJmx(request.getHashTree())); + request.setHashTree(null); + LoggerUtil.info("开始发送请求【 " + request.getTestId() + " 】到 " + uri + " 节点执行", request.getReportId()); + ResponseEntity result = restTemplate.postForEntity(uri, request, String.class); + if (result == null || !StringUtils.equals("SUCCESS", result.getBody())) { + LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 到" + uri + " 节点执行失败", request.getReportId()); + LoggerUtil.info(result); + MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常"); + } + } catch (Exception e) { + RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class); + remakeReportService.remake(request); + LoggerUtil.error("发送请求[ " + request.getTestId() + " ] 执行失败,进行数据回滚:", request.getReportId(), e); + MSException.throwException("调用资源池执行失败,请检查资源池是否配置正常"); + } + } + private synchronized void send(JmeterRunRequestDTO request) { try { if (redisTemplate.opsForValue().get(SmoothWeighted.EXEC_INDEX + request.getPoolId()) != null) { @@ -221,4 +272,19 @@ public class JMeterService { return false; } } + + public void verifyPool(String projectId, RunModeConfigDTO runConfig) { + // 检查是否禁用了本地执行 + if (runConfig != null && StringUtils.isEmpty(runConfig.getResourcePoolId())) { + BaseSystemConfigDTO configDTO = systemParameterService.getBaseInfo(); + if (StringUtils.equals(configDTO.getRunMode(), POOL)) { + ProjectConfig config = projectApplicationService.getProjectConfig(projectId); + if (config == null || !config.getPoolEnable() || StringUtils.isEmpty(config.getResourcePoolId())) { + MSException.throwException("请在【项目设置-应用管理-接口测试】中选择资源池"); + } + runConfig = runConfig == null ? new RunModeConfigDTO() : runConfig; + runConfig.setResourcePoolId(config.getResourcePoolId()); + } + } + } } diff --git a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsKafkaListener.java b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsKafkaListener.java index 269a36bddc..eafe37a7f0 100644 --- a/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsKafkaListener.java +++ b/api-test/backend/src/main/java/io/metersphere/api/jmeter/MsKafkaListener.java @@ -1,11 +1,15 @@ package io.metersphere.api.jmeter; +import com.alibaba.fastjson.JSON; import com.fasterxml.jackson.databind.ObjectMapper; +import io.metersphere.api.dto.MsgDTO; import io.metersphere.commons.constants.KafkaTopicConstants; import io.metersphere.commons.utils.NamedThreadFactory; +import io.metersphere.commons.utils.WebSocketUtil; import io.metersphere.service.ApiExecutionQueueService; import io.metersphere.service.TestResultService; import io.metersphere.utils.LoggerUtil; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.springframework.context.annotation.Configuration; @@ -21,6 +25,7 @@ import java.util.concurrent.TimeUnit; @Configuration public class MsKafkaListener { public static final String CONSUME_ID = "ms-api-exec-consume"; + public static final String DEBUG_CONSUME_ID = "ms-api-debug-consume"; @Resource private ApiExecutionQueueService apiExecutionQueueService; @Resource @@ -64,6 +69,19 @@ public class MsKafkaListener { } } + @KafkaListener(id = DEBUG_CONSUME_ID, topics = KafkaTopicConstants.DEBUG_TOPICS, groupId = "${spring.kafka.consumer.debug.group-id}") + public void debugConsume(ConsumerRecord record) { + try { + LoggerUtil.info("接收到执行结果:", record.key()); + if (ObjectUtils.isNotEmpty(record.value()) && WebSocketUtil.has(record.key().toString())) { + MsgDTO dto = JSON.parseObject(record.value(), MsgDTO.class); + WebSocketUtil.sendMessageSingle(dto); + } + } catch (Exception e) { + LoggerUtil.error("KAFKA消费失败:", e); + } + } + public void outKafkaPoolLogger() { StringBuffer buffer = new StringBuffer() .append(StringUtils.LF) diff --git a/api-test/backend/src/main/java/io/metersphere/commons/config/KafkaConfig.java b/api-test/backend/src/main/java/io/metersphere/commons/config/KafkaConfig.java index 37e3071577..7abb4da876 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/config/KafkaConfig.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/config/KafkaConfig.java @@ -22,6 +22,7 @@ import java.util.Map; @Configuration public class KafkaConfig { + public static final String DEBUG_TOPICS_KEY = "MS-API-DEBUG-KEY"; @Resource private KafkaProperties kafkaProperties; @@ -38,11 +39,18 @@ public class KafkaConfig { .build(); } + @Bean + public NewTopic debugTopic() { + return TopicBuilder.name(KafkaTopicConstants.DEBUG_TOPICS) + .build(); + } + public static Map getKafka() { KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class); Map producerProps = new HashMap<>(); producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapServers()); producerProps.put(ProducerConfig.MAX_REQUEST_SIZE_CONFIG, kafkaProperties.getMaxRequestSize()); + producerProps.put(DEBUG_TOPICS_KEY, KafkaTopicConstants.DEBUG_TOPICS); return producerProps; } diff --git a/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java b/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java new file mode 100644 index 0000000000..6c1e39a4bb --- /dev/null +++ b/api-test/backend/src/main/java/io/metersphere/commons/constants/ExtendedParameter.java @@ -0,0 +1,7 @@ +package io.metersphere.commons.constants; + +public class ExtendedParameter { + public static final String JMX = "JMX"; + public static final String SYNC_STATUS = "SYN_RES"; + public static final String SAVE_RESULT = "SAVE_RESULT"; +} diff --git a/api-test/backend/src/main/java/io/metersphere/commons/utils/WebSocketUtil.java b/api-test/backend/src/main/java/io/metersphere/commons/utils/WebSocketUtil.java index 1b0f8a49c9..692d2c30cc 100644 --- a/api-test/backend/src/main/java/io/metersphere/commons/utils/WebSocketUtil.java +++ b/api-test/backend/src/main/java/io/metersphere/commons/utils/WebSocketUtil.java @@ -40,6 +40,10 @@ public class WebSocketUtil { }); } + public static boolean has(String key) { + return StringUtils.isNotEmpty(key) && ONLINE_USER_SESSIONS.containsKey(key); + } + //当前的Session 移除 public static void onClose(String reportId) { try { diff --git a/api-test/backend/src/main/java/io/metersphere/controller/ApiJMeterFileController.java b/api-test/backend/src/main/java/io/metersphere/controller/ApiJMeterFileController.java index 9499c28f73..8d52eb4849 100644 --- a/api-test/backend/src/main/java/io/metersphere/controller/ApiJMeterFileController.java +++ b/api-test/backend/src/main/java/io/metersphere/controller/ApiJMeterFileController.java @@ -1,5 +1,6 @@ package io.metersphere.controller; +import io.metersphere.api.dto.BodyFileRequest; import io.metersphere.api.jmeter.JMeterThreadUtils; import io.metersphere.service.ApiJMeterFileService; import org.springframework.http.HttpHeaders; @@ -58,4 +59,13 @@ public class ApiJMeterFileController { .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + UUID.randomUUID().toString() + ".zip\"") .body(bytes); } + + @PostMapping("download/files") + public ResponseEntity downloadJmeterFiles(@RequestBody BodyFileRequest request) { + byte[] bytes = apiJmeterFileService.zipFilesToByteArray(request); + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType("application/octet-stream")) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + request.getReportId() + ".zip\"") + .body(bytes); + } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java b/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java index f337739d15..579875d951 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/ApiJMeterFileService.java @@ -1,5 +1,6 @@ package io.metersphere.service; +import io.metersphere.api.dto.BodyFileRequest; import io.metersphere.api.dto.EnvironmentType; import io.metersphere.api.dto.definition.request.MsTestPlan; import io.metersphere.api.exec.api.ApiCaseSerialService; @@ -308,4 +309,21 @@ public class ApiJMeterFileService { return null; } } + + public byte[] zipFilesToByteArray(BodyFileRequest request) { + Map files = new LinkedHashMap<>(); + if (CollectionUtils.isNotEmpty(request.getBodyFiles())) { + for (BodyFile bodyFile : request.getBodyFiles()) { + File file = new File(bodyFile.getName()); + if (file != null && file.exists()) { + byte[] fileByte = FileUtils.fileToByte(file); + if (fileByte != null) { + files.put(file.getAbsolutePath(), fileByte); + } + } + } + } + return listBytesToZip(files); + } + } diff --git a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionService.java b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionService.java index 6403125754..94ca019b4c 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/definition/ApiDefinitionService.java @@ -22,6 +22,7 @@ import io.metersphere.api.dto.mock.config.MockConfigImportDTO; import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult; import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest; import io.metersphere.api.exec.api.ApiExecuteService; +import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.parse.ApiImportParser; import io.metersphere.api.parse.api.ApiDefinitionImport; import io.metersphere.api.parse.api.ApiDefinitionImportParserFactory; @@ -166,7 +167,8 @@ public class ApiDefinitionService { private ApiCustomFieldService customFieldApiService; @Resource private ApiScenarioMapper apiScenarioMapper; - + @Resource + private JMeterService jMeterService; private final ThreadLocal currentApiOrder = new ThreadLocal<>(); private final ThreadLocal currentApiCaseOrder = new ThreadLocal<>(); @@ -2838,6 +2840,11 @@ public class ApiDefinitionService { * @return */ public MsExecResponseDTO run(RunDefinitionRequest request, List bodyFiles) { + if(request.getConfig() == null ) { + request.setConfig(new RunModeConfigDTO()); + } + // 验证是否本地执行 + jMeterService.verifyPool(request.getProjectId(), request.getConfig()); if (!request.isDebug()) { String testId = request.getTestElement() != null && CollectionUtils.isNotEmpty(request.getTestElement().getHashTree()) && CollectionUtils.isNotEmpty(request.getTestElement().getHashTree().get(0).getHashTree()) ? request.getTestElement().getHashTree().get(0).getHashTree().get(0).getName() : request.getId(); String reportName = this.getReportNameByTestId(testId); diff --git a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java index e15b05702e..51ca448679 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/plan/TestPlanApiCaseService.java @@ -24,6 +24,7 @@ import io.metersphere.base.mapper.plan.TestPlanApiCaseMapper; import io.metersphere.base.mapper.plan.ext.ExtTestPlanApiCaseMapper; import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.CommonConstants; +import io.metersphere.commons.constants.ExtendedParameter; import io.metersphere.commons.constants.TriggerMode; import io.metersphere.commons.enums.ApiReportStatus; import io.metersphere.commons.exception.MSException; @@ -773,7 +774,7 @@ public class TestPlanApiCaseService { request.setBloBs(apiCase); request.setReportId(reportId); Map extendedParameters = new HashMap<>(); - extendedParameters.put("SYN_RES", true); + extendedParameters.put(ExtendedParameter.SYNC_STATUS, true); apiExecuteService.exec(request, extendedParameters); } } diff --git a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java index 7339cfd3ae..283f26e63c 100644 --- a/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java +++ b/api-test/backend/src/main/java/io/metersphere/service/scenario/ApiScenarioService.java @@ -12,6 +12,7 @@ import io.metersphere.api.dto.definition.request.unknown.MsJmeterElement; import io.metersphere.api.dto.export.ScenarioToPerformanceInfoDTO; import io.metersphere.api.exec.scenario.ApiScenarioEnvService; import io.metersphere.api.exec.scenario.ApiScenarioExecuteService; +import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.NewDriverManager; import io.metersphere.api.parse.ApiImportParser; import io.metersphere.api.parse.scenario.ApiScenarioImportUtil; @@ -35,6 +36,7 @@ import io.metersphere.commons.utils.mock.MockApiUtils; import io.metersphere.dto.BaseCase; import io.metersphere.dto.MsExecResponseDTO; import io.metersphere.dto.ProjectConfig; +import io.metersphere.dto.RunModeConfigDTO; import io.metersphere.environment.service.BaseEnvGroupProjectService; import io.metersphere.i18n.Translator; import io.metersphere.log.utils.ReflexObjectUtil; @@ -148,6 +150,8 @@ public class ApiScenarioService { private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper; @Resource private ExtTestPlanScenarioCaseMapper extTestPlanScenarioCaseMapper; + @Resource + private JMeterService jMeterService; private ThreadLocal currentScenarioOrder = new ThreadLocal<>(); @@ -915,6 +919,8 @@ public class ApiScenarioService { * @return */ public String debugRun(RunDefinitionRequest request, List bodyFiles, List scenarioFiles) { + request.setConfig(new RunModeConfigDTO()); + jMeterService.verifyPool(request.getProjectId(), request.getConfig()); return apiScenarioExecuteService.debug(request, bodyFiles, scenarioFiles); } diff --git a/api-test/frontend/src/business/automation/scenario/common/RunMode.vue b/api-test/frontend/src/business/automation/scenario/common/RunMode.vue index 6e5824b05b..a504ae62bd 100644 --- a/api-test/frontend/src/business/automation/scenario/common/RunMode.vue +++ b/api-test/frontend/src/business/automation/scenario/common/RunMode.vue @@ -4,73 +4,73 @@ :title="$t('load_test.runtime_config')" width="550px" @close="close" - :visible.sync="runModeVisible" - > -
- {{ $t("commons.environment") }}: - -
-
- {{ $t("run_mode.title") }}: - - {{ $t("run_mode.serial") }} - {{ $t("run_mode.parallel") }} - -
-
- - - {{ $t("run_mode.other_config") }}: - - -
- - {{ $t("run_mode.idd_report") }} - {{ $t("run_mode.set_report") }} - -
-
- - {{ $t('run_mode.run_with_resource_pool') }} - - - - - -
-
-
-
+ :visible.sync="runModeVisible"> +
+
+ {{ $t("commons.environment") }}: + +
- -
- - {{ $t("api_test.fail_to_stop") }} - -
+
+ {{ $t("run_mode.title") }}: + + {{ $t("run_mode.serial") }} + {{ $t("run_mode.parallel") }} + +
+ +
+ {{ $t("run_mode.other_config") }}: + + + {{ $t("run_mode.idd_report") }} + {{ $t("run_mode.set_report") }} + + +
+ + {{ $t('run_mode.run_with_resource_pool') }} + + + + + +
+
-
- {{ $t("run_mode.report_name") }}: - + +
+ + {{ $t("api_test.fail_to_stop") }} + +
+ +
+ {{ $t("run_mode.report_name") }}: + +
+ - - diff --git a/api-test/frontend/src/business/definition/components/list/ApiCaseSimpleList.vue b/api-test/frontend/src/business/definition/components/list/ApiCaseSimpleList.vue index 34a0e0dfa7..e99a2f27db 100644 --- a/api-test/frontend/src/business/definition/components/list/ApiCaseSimpleList.vue +++ b/api-test/frontend/src/business/definition/components/list/ApiCaseSimpleList.vue @@ -247,6 +247,7 @@ + + + + + + + @@ -301,6 +324,7 @@ import TimingItem from "./TimingItem"; import {genTcpMockPort} from "../../../api/project"; import {batchModifyAppSetting, getProjectAppSetting} from "../../../api/app-setting"; import {PROJECT_APP_SETTING} from "../../../common/js/constants"; +import {getSystemBaseSetting, getTestResourcePools} from "metersphere-frontend/src/api/system"; export default { name: "appManage", @@ -313,6 +337,8 @@ export default { data() { return { activeName: 'test_track', + resourcePools: [], + isPool: false, form: { cleanTrackReport: false, cleanTrackReportExpr: "", @@ -381,6 +407,8 @@ export default { }, created() { this.init(); + this.getBase(); + this.getResourcePools(); this.isXpack = !!hasLicense(); }, computed: { @@ -389,6 +417,24 @@ export default { }, }, methods: { + getBase() { + this.result = getSystemBaseSetting().then(response => { + this.isPool = response.data.runMode === 'POOL'; + }) + }, + getResourcePools() { + this.result = getTestResourcePools().then(response => { + this.resourcePools = response.data; + }); + }, + runModeChange(value, other) { + if (value && !this.config.resourcePoolId) { + this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool')); + this.config.poolEnable = false; + } else { + this.switchChange("POOL_ENABLE", value, other); + } + }, tcpMockSwitchChange(value, other) { if (value && this.config.mockTcpPort === 0) { genTcpMockPort(this.projectId).then(res => { diff --git a/project-management/frontend/src/i18n/lang/en-US.js b/project-management/frontend/src/i18n/lang/en-US.js index fc57e54dc9..1cd0cc03e8 100644 --- a/project-management/frontend/src/i18n/lang/en-US.js +++ b/project-management/frontend/src/i18n/lang/en-US.js @@ -6,6 +6,7 @@ const message = { pj: { environment_import_repeat_tip: "(Environment configuration with the same name filtered {0})", check_third_project_success: "inspection passed", + api_run_pool_title: 'Interface execution resource pool', }, file_manage: { my_file: 'My File', diff --git a/project-management/frontend/src/i18n/lang/zh-CN.js b/project-management/frontend/src/i18n/lang/zh-CN.js index ab3ea1a1c3..c082d710f1 100644 --- a/project-management/frontend/src/i18n/lang/zh-CN.js +++ b/project-management/frontend/src/i18n/lang/zh-CN.js @@ -6,6 +6,7 @@ const message = { pj: { environment_import_repeat_tip: "(已过滤同名称的环境配置 {0})", check_third_project_success: "检查通过", + api_run_pool_title: '接口执行资源池', }, file_manage: { my_file: '我的文件', diff --git a/project-management/frontend/src/i18n/lang/zh-TW.js b/project-management/frontend/src/i18n/lang/zh-TW.js index 386e173f82..5130a81e33 100644 --- a/project-management/frontend/src/i18n/lang/zh-TW.js +++ b/project-management/frontend/src/i18n/lang/zh-TW.js @@ -6,6 +6,7 @@ const message = { pj: { environment_import_repeat_tip: "(已過濾同名稱的環境配置 {0})", check_third_project_success: "檢查通過", + api_run_pool_title: '接口執行資源池', }, file_manage: { my_file: '我的文件', diff --git a/system-setting/frontend/src/business/system/setting/BaseSetting.vue b/system-setting/frontend/src/business/system/setting/BaseSetting.vue index 7d4d2e913f..c1241dacff 100644 --- a/system-setting/frontend/src/business/system/setting/BaseSetting.vue +++ b/system-setting/frontend/src/business/system/setting/BaseSetting.vue @@ -19,6 +19,9 @@ ({{ $t('commons.examples') }}:http://localhost:4444) + + + @@ -40,7 +43,7 @@ export default { name: "BaseSetting", data() { return { - formInline: {}, + formInline: {runMode: true}, input: '', visible: true, showEdit: true, @@ -75,12 +78,29 @@ export default { methods: { query() { this.loading = getSystemBaseSetting().then(res => { + if(!res.data.runMode) { + res.data.runMode = 'LOCAL' + } this.formInline = res.data; this.$nextTick(() => { this.$refs.formInline.clearValidate(); }) }); }, + modeChange(v){ + if(v === 'POOL'){ + this.formInline.runMode = 'LOCAL'; + this.$alert(this.$t('system.api_default_run_message'), '', { + confirmButtonText: this.$t('commons.confirm'), + cancelButtonText: this.$t('commons.cancel'), + callback: (action) => { + if (action === 'confirm') { + this.formInline.runMode = v; + } + } + }); + } + }, edit() { this.showEdit = false; this.showSave = true; @@ -101,6 +121,7 @@ export default { {paramKey: "base.concurrency", paramValue: this.formInline.concurrency, type: "text", sort: 2}, {paramKey: "base.prometheus.host", paramValue: this.formInline.prometheusHost, type: "text", sort: 1}, {paramKey: "base.selenium.docker.url", paramValue: this.formInline.seleniumDockerUrl, type: "text", sort: 1}, + {paramKey: "base.run.mode", paramValue: this.formInline.runMode, type: "text", sort: 5} ]; this.loading = saveSystemBaseSetting(param).then(res => { if (res.success) { diff --git a/system-setting/frontend/src/i18n/lang/en-US.js b/system-setting/frontend/src/i18n/lang/en-US.js index 40ee127f9d..240c6c5166 100644 --- a/system-setting/frontend/src/i18n/lang/en-US.js +++ b/system-setting/frontend/src/i18n/lang/en-US.js @@ -9,7 +9,9 @@ const message = { system: { environment_import_repeat_tip: "(Environment configuration with the same name filtered {0})", search_by_environment_name: "search by environment name", - check_third_project_success: "inspection passed" + check_third_project_success: "inspection passed", + api_default_run_message: 'In order not to affect the normal execution of the interface, please configure the resource pool for interface execution in [Project Settings - Application Management - Interface Test]', + api_default_run: 'The interface is executed locally by default', }, display: { title: 'Theme', diff --git a/system-setting/frontend/src/i18n/lang/zh-CN.js b/system-setting/frontend/src/i18n/lang/zh-CN.js index e67f157917..a007df1909 100644 --- a/system-setting/frontend/src/i18n/lang/zh-CN.js +++ b/system-setting/frontend/src/i18n/lang/zh-CN.js @@ -9,7 +9,9 @@ const message = { system: { environment_import_repeat_tip: "(已过滤同名称的环境配置 {0})", search_by_environment_name: "根据环境的名称搜索", - check_third_project_success: "检查通过" + check_third_project_success: "检查通过", + api_default_run_message: '为了不影响接口正常执行,请在【 项目设置-应用管理-接口测试 】中配置接口执行的资源池', + api_default_run: '接口默认本地执行', }, display: { title: '显示设置', diff --git a/system-setting/frontend/src/i18n/lang/zh-TW.js b/system-setting/frontend/src/i18n/lang/zh-TW.js index f0121d92bb..f1767abf25 100644 --- a/system-setting/frontend/src/i18n/lang/zh-TW.js +++ b/system-setting/frontend/src/i18n/lang/zh-TW.js @@ -9,7 +9,9 @@ const message = { system: { environment_import_repeat_tip: "(已過濾同名稱的環境配置 {0})", search_by_environment_name: "根據環境的名稱搜索", - check_third_project_success: "檢查通過" + check_third_project_success: "檢查通過", + api_default_run_message: '為了不影響接口正常執行,請在【 項目設置-應用管理-接口測試 】中配置接口執行的資源池', + api_default_run: '接口默認本地執行', }, display: { title: '顯示設置', diff --git a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java index 9c40f6dee0..c46839013e 100644 --- a/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java +++ b/test-track/backend/src/main/java/io/metersphere/plan/service/TestPlanService.java @@ -147,6 +147,12 @@ public class TestPlanService { private KafkaTemplate kafkaTemplate; @Resource private ObjectMapper objectMapper; + @Resource + private SystemParameterService systemParameterService; + @Resource + private BaseProjectApplicationService projectApplicationService; + public static final String POOL = "POOL"; + public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) { if (getTestPlanByName(testPlan.getName()).size() > 0) { MSException.throwException(Translator.get("plan_name_already_exists")); @@ -847,7 +853,7 @@ public class TestPlanService { if (planReportId == null) { planReportId = UUID.randomUUID().toString(); } - + this.verifyPool(projectId, runModeConfig); //创建测试报告,然后返回的ID重新赋值为resourceID,作为后续的参数 TestPlanScheduleReportInfoDTO reportInfoDTO = this.genTestPlanReport(planReportId, testPlanId, userId, triggerMode, runModeConfig); //测试计划准备执行,取消测试计划的实际结束时间 @@ -888,6 +894,20 @@ public class TestPlanService { return planReportId; } + public void verifyPool(String projectId, RunModeConfigDTO runConfig) { + // 检查是否禁用了本地执行 + if (runConfig != null && StringUtils.isEmpty(runConfig.getResourcePoolId())) { + BaseSystemConfigDTO configDTO = systemParameterService.getBaseInfo(); + if (StringUtils.equals(configDTO.getRunMode(), POOL)) { + ProjectConfig config = projectApplicationService.getProjectConfig(projectId); + if (config == null || !config.getPoolEnable() || StringUtils.isEmpty(config.getResourcePoolId())) { + MSException.throwException("请在【项目设置-应用管理-接口测试】中选择资源池"); + } + runConfig = runConfig == null ? new RunModeConfigDTO() : runConfig; + runConfig.setResourcePoolId(config.getResourcePoolId()); + } + } + } /** * 将测试计划运行时的triggerMode转化为性能测试中辨别更明确的值 * diff --git a/test-track/frontend/src/business/plan/common/PlanRunModeWithEnv.vue b/test-track/frontend/src/business/plan/common/PlanRunModeWithEnv.vue index dba8c95feb..cc5195f216 100644 --- a/test-track/frontend/src/business/plan/common/PlanRunModeWithEnv.vue +++ b/test-track/frontend/src/business/plan/common/PlanRunModeWithEnv.vue @@ -6,7 +6,7 @@ @close="close" :visible.sync="runModeVisible" > -
+
{{ $t("commons.environment") }}:
@@ -68,6 +68,7 @@ {{ $t("run_mode.run_with_resource_pool") }} @@ -94,6 +95,7 @@ {{ $t("run_mode.run_with_resource_pool") }} @@ -191,17 +193,21 @@ import {hasLicense} from "metersphere-frontend/src/utils/permission"; import {strMapToObj} from "metersphere-frontend/src/utils"; import {ENV_TYPE} from "metersphere-frontend/src/utils/constants"; -import {getOwnerProjects} from "@/business/utils/sdk-utils"; +import {getCurrentProjectID, getOwnerProjects} from "@/business/utils/sdk-utils"; import {getQuotaValidResourcePools} from "@/api/remote/resource-pool"; import EnvGroupPopover from "@/business/plan/env/EnvGroupPopover"; import {getApiCaseEnv} from "@/api/remote/plan/test-plan-api-case"; import {getApiScenarioEnv, getPlanCaseEnv} from "@/api/remote/plan/test-plan"; +import {getSystemBaseSetting} from "metersphere-frontend/src/api/system"; +import {getProjectConfig} from "@/api/project"; export default { name: "MsPlanRunModeWithEnv", components: {EnvGroupPopover, MsDialogFooter}, data() { return { + loading: false, + runMode: "", btnStyle: { width: "260px", }, @@ -275,11 +281,33 @@ export default { this.testType = testType; this.getResourcePools(); this.getWsProjects(); + this.query(); + }, + query() { + this.loading = true; + this.result = getSystemBaseSetting().then(response => { + if (!response.data.runMode) { + response.data.runMode = 'LOCAL' + } + this.runMode = response.data.runMode; + if (this.runMode === 'POOL') { + this.runConfig.runWithinResourcePool = true; + this.getProjectApplication(); + } else { + this.loading = false; + } + }) + }, + getProjectApplication() { + getProjectConfig(getCurrentProjectID(), "").then(res => { + if (res.data && res.data.poolEnable && res.data.resourcePoolId) { + this.runConfig.resourcePoolId = res.data.resourcePoolId; + } + this.loading = false; + }); }, changeMode() { this.runConfig.onSampleError = false; - this.runConfig.runWithinResourcePool = false; - this.runConfig.resourcePoolId = null; }, close() { this.runConfig = { diff --git a/test-track/frontend/src/business/plan/common/TestPlanRunModeWithEnv.vue b/test-track/frontend/src/business/plan/common/TestPlanRunModeWithEnv.vue index 695bfa2894..cda31adf5f 100644 --- a/test-track/frontend/src/business/plan/common/TestPlanRunModeWithEnv.vue +++ b/test-track/frontend/src/business/plan/common/TestPlanRunModeWithEnv.vue @@ -64,6 +64,7 @@ v-model="runConfig.runWithinResourcePool" style="padding-right: 10px" class="radio-change" + :disabled="runMode === 'POOL'" > {{ $t("run_mode.run_with_resource_pool") }}
@@ -91,6 +92,7 @@ v-model="runConfig.runWithinResourcePool" style="padding-right: 10px" class="radio-change" + :disabled="runMode === 'POOL'" > {{ $t("run_mode.run_with_resource_pool") }}
@@ -192,7 +194,7 @@ import {hasLicense} from "metersphere-frontend/src/utils/permission"; import {strMapToObj} from "metersphere-frontend/src/utils"; import MsTag from "metersphere-frontend/src/components/MsTag"; import {ENV_TYPE} from "metersphere-frontend/src/utils/constants"; -import {getOwnerProjects} from "@/business/utils/sdk-utils"; +import {getCurrentProjectID, getOwnerProjects} from "@/business/utils/sdk-utils"; import {getQuotaValidResourcePools} from "@/api/remote/resource-pool"; import EnvGroupPopover from "@/business/plan/env/EnvGroupPopover"; import {getApiCaseEnv} from "@/api/remote/plan/test-plan-api-case"; @@ -200,6 +202,8 @@ import {getApiScenarioEnv, getPlanCaseEnv} from "@/api/remote/plan/test-plan"; import EnvGroupWithOption from "../env/EnvGroupWithOption"; import EnvironmentGroup from "@/business/plan/env/EnvironmentGroupList"; import EnvSelectPopover from "@/business/plan/env/EnvSelectPopover"; +import {getSystemBaseSetting} from "metersphere-frontend/src/api/system"; +import {getProjectConfig} from "@/api/project"; export default { name: "MsTestPlanRunModeWithEnv", @@ -211,6 +215,7 @@ export default { }, data() { return { + runMode: "", btnStyle: { width: "260px", }, @@ -287,11 +292,33 @@ export default { this.getResourcePools(); this.getWsProjects(); this.showPopover(); + this.query(); + }, + query() { + this.loading = true; + this.result = getSystemBaseSetting().then(response => { + if (!response.data.runMode) { + response.data.runMode = 'LOCAL' + } + this.runMode = response.data.runMode; + if (this.runMode === 'POOL') { + this.runConfig.runWithinResourcePool = true; + this.getProjectApplication(); + } else { + this.loading = false; + } + }) + }, + getProjectApplication() { + getProjectConfig(getCurrentProjectID(), "").then(res => { + if (res.data && res.data.poolEnable && res.data.resourcePoolId) { + this.runConfig.resourcePoolId = res.data.resourcePoolId; + } + this.loading = false; + }); }, changeMode() { this.runConfig.onSampleError = false; - this.runConfig.runWithinResourcePool = false; - this.runConfig.resourcePoolId = null; }, close() { this.runConfig = { diff --git a/test-track/frontend/src/business/plan/components/ScheduleMaintain.vue b/test-track/frontend/src/business/plan/components/ScheduleMaintain.vue index dd1dd9755c..288310ce90 100644 --- a/test-track/frontend/src/business/plan/components/ScheduleMaintain.vue +++ b/test-track/frontend/src/business/plan/components/ScheduleMaintain.vue @@ -76,7 +76,7 @@
- + {{ $t('run_mode.run_with_resource_pool') }}
- + {{ $t('run_mode.run_with_resource_pool') }} { + if (!response.data.runMode) { + response.data.runMode = 'LOCAL' + } + this.runMode = response.data.runMode; + if (this.runMode === 'POOL') { + this.runConfig.runWithinResourcePool = true; + this.getProjectApplication(); + } else { + this.loading = false; + } + }) + }, + getProjectApplication() { + getProjectConfig(getCurrentProjectID(), "").then(res => { + if (res.data && res.data.poolEnable && res.data.resourcePoolId) { + this.runConfig.resourcePoolId = res.data.resourcePoolId; + } + this.loading = false; + }); + }, currentUser: () => { return getCurrentUser(); }, diff --git a/test-track/frontend/src/business/plan/view/comonents/api/PlanRunModeWithEnv.vue b/test-track/frontend/src/business/plan/view/comonents/api/PlanRunModeWithEnv.vue index 3bbc490e4b..24b43af279 100644 --- a/test-track/frontend/src/business/plan/view/comonents/api/PlanRunModeWithEnv.vue +++ b/test-track/frontend/src/business/plan/view/comonents/api/PlanRunModeWithEnv.vue @@ -68,6 +68,7 @@ {{ $t("run_mode.run_with_resource_pool") }} @@ -94,6 +95,7 @@ {{ $t("run_mode.run_with_resource_pool") }} @@ -186,16 +188,19 @@