feat(接口测试): 接口测试支持禁用本地执行
--story=1009842 --user=赵勇 接口测试支持禁用本地执行 https://www.tapd.cn/55049933/s/1291450
This commit is contained in:
parent
3a1992cfb0
commit
e765433d40
|
@ -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<BodyFile> bodyFiles;
|
||||
}
|
|
@ -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()));
|
||||
|
|
|
@ -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<String, Object>() {{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<MsExecResponseDTO> 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();
|
||||
}
|
||||
|
|
|
@ -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<String, Object> 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<TestResource> 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<String> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<?, String> 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)
|
||||
|
|
|
@ -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<String, Object> getKafka() {
|
||||
KafkaProperties kafkaProperties = CommonBeanFactory.getBean(KafkaProperties.class);
|
||||
Map<String, Object> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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<byte[]> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, byte[]> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Long> currentApiOrder = new ThreadLocal<>();
|
||||
private final ThreadLocal<Long> currentApiCaseOrder = new ThreadLocal<>();
|
||||
|
@ -2838,6 +2840,11 @@ public class ApiDefinitionService {
|
|||
* @return
|
||||
*/
|
||||
public MsExecResponseDTO run(RunDefinitionRequest request, List<MultipartFile> 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);
|
||||
|
|
|
@ -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<String, Object> extendedParameters = new HashMap<>();
|
||||
extendedParameters.put("SYN_RES", true);
|
||||
extendedParameters.put(ExtendedParameter.SYNC_STATUS, true);
|
||||
apiExecuteService.exec(request, extendedParameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Long> currentScenarioOrder = new ThreadLocal<>();
|
||||
|
||||
|
@ -915,6 +919,8 @@ public class ApiScenarioService {
|
|||
* @return
|
||||
*/
|
||||
public String debugRun(RunDefinitionRequest request, List<MultipartFile> bodyFiles, List<MultipartFile> scenarioFiles) {
|
||||
request.setConfig(new RunModeConfigDTO());
|
||||
jMeterService.verifyPool(request.getProjectId(), request.getConfig());
|
||||
return apiScenarioExecuteService.debug(request, bodyFiles, scenarioFiles);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,73 +4,73 @@
|
|||
:title="$t('load_test.runtime_config')"
|
||||
width="550px"
|
||||
@close="close"
|
||||
:visible.sync="runModeVisible"
|
||||
>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span class="ms-mode-span">{{ $t("commons.environment") }}:</span>
|
||||
<env-popover :project-ids="projectIds"
|
||||
:placement="'bottom-start'"
|
||||
:project-list="projectList"
|
||||
:project-env-map="projectEnvListMap"
|
||||
:environment-type.sync="runConfig.environmentType"
|
||||
:group-id="runConfig.environmentGroupId"
|
||||
:has-option-group="true"
|
||||
@setEnvGroup="setEnvGroup"
|
||||
@setProjectEnvMap="setProjectEnvMap"
|
||||
@showPopover="showPopover"
|
||||
ref="envPopover" class="env-popover"/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="ms-mode-span">{{ $t("run_mode.title") }}:</span>
|
||||
<el-radio-group v-model="runConfig.mode" @change="changeMode">
|
||||
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
|
||||
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div class="ms-mode-div">
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}:</span>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<div>
|
||||
<el-radio-group v-model="runConfig.reportType">
|
||||
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
|
||||
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div style="padding-top: 10px">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="!item.api"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
:visible.sync="runModeVisible">
|
||||
<div v-loading="loading">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span class="ms-mode-span"> {{ $t("commons.environment") }}: </span>
|
||||
<env-popover
|
||||
:project-ids="projectIds"
|
||||
:placement="'bottom-start'"
|
||||
:project-list="projectList"
|
||||
:project-env-map="projectEnvListMap"
|
||||
:environment-type.sync="runConfig.environmentType"
|
||||
:group-id="runConfig.environmentGroupId"
|
||||
:has-option-group="true"
|
||||
:show-env-group="isScenario"
|
||||
@setEnvGroup="setEnvGroup"
|
||||
@setProjectEnvMap="setProjectEnvMap"
|
||||
@showPopover="showPopover"
|
||||
ref="envPopover" class="env-popover"/>
|
||||
</div>
|
||||
|
||||
<!--- 失败停止 -->
|
||||
<div style="margin-top: 10px" v-if="runConfig.mode === 'serial'">
|
||||
<el-checkbox v-model="runConfig.onSampleError" style="margin-left: 127px">
|
||||
{{ $t("api_test.fail_to_stop") }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ $t("run_mode.title") }}:</span>
|
||||
<el-radio-group v-model="runConfig.mode" @change="changeMode">
|
||||
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
|
||||
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<!-- 资源池 -->
|
||||
<div class="ms-mode-div">
|
||||
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}:</span>
|
||||
<span>
|
||||
<el-radio-group v-model="runConfig.reportType">
|
||||
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
|
||||
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</span>
|
||||
<div style="padding:10px 90px">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool"
|
||||
style="padding-right: 10px;" :disabled="runMode === 'POOL'">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="!item.api"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
|
||||
<span class="ms-mode-span-label">{{ $t("run_mode.report_name") }}:</span>
|
||||
<el-input
|
||||
v-model="runConfig.reportName"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
size="small"
|
||||
style="width: 300px"/>
|
||||
<!--- 失败停止 -->
|
||||
<div style="padding:0px 90px" v-if="runConfig.mode === 'serial'">
|
||||
<el-checkbox v-model="runConfig.onSampleError">
|
||||
{{ $t("api_test.fail_to_stop") }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
|
||||
<span class="ms-mode-span-label">{{ $t("run_mode.report_name") }}:</span>
|
||||
<el-input
|
||||
v-model="runConfig.reportName"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
size="small"
|
||||
style="width: 300px"/>
|
||||
</div>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
|
||||
|
@ -78,20 +78,25 @@
|
|||
</el-dialog>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import {apiScenarioEnv} from "@/api/scenario";
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||
import {strMapToObj} from "metersphere-frontend/src/utils";
|
||||
import EnvPopover from "@/business/automation/scenario/EnvPopover";
|
||||
import {getOwnerProjects} from "@/api/project";
|
||||
import {getOwnerProjects, getProjectConfig} from "@/api/project";
|
||||
import {getTestResourcePools} from "@/api/test-resource-pool";
|
||||
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
|
||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||
|
||||
export default {
|
||||
name: "RunMode",
|
||||
components: {MsDialogFooter, EnvPopover},
|
||||
data() {
|
||||
return {
|
||||
runMode: "",
|
||||
loading: false,
|
||||
runModeVisible: false,
|
||||
testType: null,
|
||||
resourcePools: [],
|
||||
|
@ -111,8 +116,13 @@ export default {
|
|||
projectIds: new Set(),
|
||||
};
|
||||
},
|
||||
props: ['request'],
|
||||
|
||||
props: {
|
||||
request: Object,
|
||||
isScenario: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'runConfig.runWithinResourcePool'() {
|
||||
if (!this.runConfig.runWithinResourcePool) {
|
||||
|
@ -131,11 +141,10 @@ export default {
|
|||
this.runModeVisible = true;
|
||||
this.getResourcePools();
|
||||
this.getWsProjects();
|
||||
this.query();
|
||||
this.runConfig.environmentType = ENV_TYPE.JSON;
|
||||
},
|
||||
changeMode() {
|
||||
this.runConfig.runWithinResourcePool = false;
|
||||
this.runConfig.resourcePoolId = null;
|
||||
this.runConfig.reportType = "iddReport";
|
||||
this.runConfig.reportName = "";
|
||||
},
|
||||
|
@ -173,6 +182,29 @@ export default {
|
|||
this.resourcePools = response.data;
|
||||
});
|
||||
},
|
||||
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;
|
||||
});
|
||||
},
|
||||
setEnvGroup(id) {
|
||||
this.runConfig.environmentGroupId = id;
|
||||
},
|
||||
|
@ -180,6 +212,18 @@ export default {
|
|||
this.runConfig.envMap = strMapToObj(projectEnvMap);
|
||||
},
|
||||
showPopover() {
|
||||
if (this.isScenario) {
|
||||
this.showScenarioPopover();
|
||||
} else {
|
||||
this.showApiPopover();
|
||||
}
|
||||
},
|
||||
showApiPopover() {
|
||||
this.projectIds.clear();
|
||||
this.projectIds.add(getCurrentProjectID());
|
||||
this.$refs.envPopover.openEnvSelect();
|
||||
},
|
||||
showScenarioPopover() {
|
||||
this.projectIds.clear();
|
||||
apiScenarioEnv(this.request).then(res => {
|
||||
let data = res.data;
|
||||
|
@ -198,6 +242,9 @@ export default {
|
|||
<style scoped>
|
||||
.ms-mode-span {
|
||||
margin-right: 10px;
|
||||
display: -moz-inline-box;
|
||||
display: inline-block;
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.ms-mode-div {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
:append-to-body='true'
|
||||
@close="close">
|
||||
<template>
|
||||
<div>
|
||||
<div v-loading="loading">
|
||||
<el-tabs v-model="activeName">
|
||||
<el-tab-pane :label="$t('schedule.task_config')" name="first">
|
||||
<div class="el-step__icon is-text" style="margin-right: 10px;">
|
||||
|
@ -60,7 +60,7 @@
|
|||
</div>
|
||||
<div class="ms-mode-div">
|
||||
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}:</span>
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" :disabled="runMode === 'POOL'">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select style="margin-left: 10px" :disabled="!runConfig.runWithinResourcePool"
|
||||
|
@ -106,8 +106,9 @@ import MsScheduleNotification from "./ScheduleNotification";
|
|||
import ScheduleSwitch from "@/business/automation/schedule/ScheduleSwitch";
|
||||
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||
import EnvPopover from "@/business/automation/scenario/EnvPopover";
|
||||
import {getMaintainer, getOwnerProjects} from "@/api/project";
|
||||
import {getMaintainer, getOwnerProjects, getProjectConfig} from "@/api/project";
|
||||
import {getTestResourcePools} from "@/api/test-resource-pool";
|
||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
|
@ -162,6 +163,8 @@ export default {
|
|||
}
|
||||
};
|
||||
return {
|
||||
runMode: "",
|
||||
loading: false,
|
||||
scheduleReceiverOptions: [],
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
|
@ -198,6 +201,29 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
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;
|
||||
});
|
||||
},
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
|
@ -208,8 +234,6 @@ export default {
|
|||
return true;
|
||||
},
|
||||
changeMode() {
|
||||
this.runConfig.runWithinResourcePool = false;
|
||||
this.runConfig.resourcePoolId = null;
|
||||
this.runConfig.reportType = "iddReport";
|
||||
this.runConfig.reportName = "";
|
||||
},
|
||||
|
@ -293,6 +317,7 @@ export default {
|
|||
this.activeName = 'first';
|
||||
this.getResourcePools();
|
||||
this.getWsProjects();
|
||||
this.query();
|
||||
this.runConfig.environmentType = ENV_TYPE.JSON;
|
||||
},
|
||||
findSchedule() {
|
||||
|
|
|
@ -1,213 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
destroy-on-close
|
||||
:title="$t('load_test.runtime_config')"
|
||||
width="550px"
|
||||
@close="close"
|
||||
:visible.sync="runModeVisible"
|
||||
>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span class="ms-mode-span">{{ $t("commons.environment") }}:</span>
|
||||
<env-popover :project-ids="projectIds"
|
||||
:placement="'bottom-start'"
|
||||
:project-list="projectList"
|
||||
:project-env-map="projectEnvListMap"
|
||||
:environment-type.sync="runConfig.environmentType"
|
||||
:group-id="runConfig.environmentGroupId"
|
||||
@setEnvGroup="setEnvGroup"
|
||||
@setProjectEnvMap="setProjectEnvMap"
|
||||
@showPopover="showPopover"
|
||||
:show-env-group="false"
|
||||
ref="envPopover" class="env-popover"/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="ms-mode-span">{{ $t("run_mode.title") }}:</span>
|
||||
<el-radio-group v-model="runConfig.mode" @change="changeMode">
|
||||
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
|
||||
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="ms-mode-div">
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}:</span>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<div>
|
||||
<el-radio-group v-model="runConfig.reportType">
|
||||
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
|
||||
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div style="padding-top: 10px">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="!item.api"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!--- 失败停止 -->
|
||||
<div style="margin-top: 10px" v-if="runConfig.mode === 'serial'">
|
||||
<el-checkbox v-model="runConfig.onSampleError" style="margin-left: 127px">
|
||||
{{ $t("api_test.fail_to_stop") }}
|
||||
</el-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
|
||||
<span class="ms-mode-span-label">{{ $t("run_mode.report_name") }}:</span>
|
||||
<el-input
|
||||
v-model="runConfig.reportName"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
size="small"
|
||||
style="width: 300px"/>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import EnvPopover from "@/business/automation/scenario/EnvPopover";
|
||||
import {strMapToObj} from "metersphere-frontend/src/utils";
|
||||
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||
import {parseEnvironment} from "@/business/environment/model/EnvironmentModel";
|
||||
import {getOwnerProjects} from "@/api/project";
|
||||
import {getEnvironmentByProjectId} from "metersphere-frontend/src/api/environment";
|
||||
import {getTestResourcePools} from "@/api/test-resource-pool";
|
||||
|
||||
export default {
|
||||
name: "MsApiCaseRunModeWithEnv",
|
||||
components: {EnvPopover, MsDialogFooter},
|
||||
data() {
|
||||
return {
|
||||
runModeVisible: false,
|
||||
resourcePools: [],
|
||||
runConfig: {
|
||||
reportName: "",
|
||||
mode: "serial",
|
||||
reportType: "iddReport",
|
||||
onSampleError: false,
|
||||
runWithinResourcePool: false,
|
||||
resourcePoolId: null,
|
||||
envMap: new Map(),
|
||||
environmentGroupId: "",
|
||||
environmentType: ENV_TYPE.JSON
|
||||
},
|
||||
projectEnvListMap: {},
|
||||
projectList: [],
|
||||
projectIds: new Set(),
|
||||
};
|
||||
},
|
||||
props: ['projectId'],
|
||||
methods: {
|
||||
open() {
|
||||
this.runModeVisible = true;
|
||||
this.getResourcePools();
|
||||
this.getWsProjects();
|
||||
},
|
||||
changeMode() {
|
||||
this.runConfig.onSampleError = false;
|
||||
this.runConfig.runWithinResourcePool = false;
|
||||
this.runConfig.resourcePoolId = null;
|
||||
this.runConfig.reportName = "";
|
||||
},
|
||||
close() {
|
||||
this.runConfig = {
|
||||
mode: "serial",
|
||||
reportType: "iddReport",
|
||||
onSampleError: false,
|
||||
reportName: "",
|
||||
runWithinResourcePool: false,
|
||||
resourcePoolId: null,
|
||||
envMap: new Map(),
|
||||
environmentGroupId: "",
|
||||
environmentType: ENV_TYPE.JSON
|
||||
};
|
||||
this.runModeVisible = false;
|
||||
this.$emit('close');
|
||||
},
|
||||
handleRunBatch() {
|
||||
if ((this.runConfig.mode === 'serial' || this.runConfig.mode === 'parallel') && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
|
||||
this.$warning(this.$t('commons.input_name'));
|
||||
return;
|
||||
}
|
||||
if (this.runConfig.runWithinResourcePool && this.runConfig.resourcePoolId == null) {
|
||||
this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool'));
|
||||
return;
|
||||
}
|
||||
this.$emit("handleRunBatch", this.runConfig);
|
||||
this.close();
|
||||
},
|
||||
getResourcePools() {
|
||||
this.result = getTestResourcePools().then(response => {
|
||||
this.resourcePools = response.data;
|
||||
});
|
||||
},
|
||||
setProjectEnvMap(projectEnvMap) {
|
||||
this.runConfig.envMap = strMapToObj(projectEnvMap);
|
||||
},
|
||||
setEnvGroup(id) {
|
||||
this.runConfig.environmentGroupId = id;
|
||||
},
|
||||
getWsProjects() {
|
||||
getOwnerProjects().then(res => {
|
||||
this.projectList = res.data;
|
||||
})
|
||||
},
|
||||
getEnvironments() {
|
||||
return new Promise((resolve) => {
|
||||
if (this.projectId) {
|
||||
getEnvironmentByProjectId(this.projectId).then(response => {
|
||||
this.environments = response.data;
|
||||
this.environments.forEach(environment => {
|
||||
parseEnvironment(environment);
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
showPopover() {
|
||||
this.projectIds.clear();
|
||||
this.projectIds.add(this.projectId);
|
||||
this.$refs.envPopover.openEnvSelect();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-mode-span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ms-mode-div {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.ms-mode-span {
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.ms-mode-span-label:before {
|
||||
content: '*';
|
||||
color: #F56C6C;
|
||||
margin-right: 4px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -247,6 +247,7 @@
|
|||
<ms-task-center ref="taskCenter" :show-menu="false"/>
|
||||
|
||||
<ms-api-case-run-mode-with-env
|
||||
:is-scenario="false"
|
||||
:project-id="projectId"
|
||||
@handleRunBatch="runBatch"
|
||||
@close="initTable"
|
||||
|
@ -304,7 +305,7 @@ import MsContainer from "metersphere-frontend/src/components/MsContainer";
|
|||
import MsBottomContainer from "../BottomContainer";
|
||||
import ShowMoreBtn from "@/business/commons/ShowMoreBtn";
|
||||
import MsBatchEdit from "../basis/BatchEdit";
|
||||
import MsApiCaseRunModeWithEnv from "./ApiCaseRunModeWithEnv";
|
||||
import MsApiCaseRunModeWithEnv from "@/business/automation/scenario/common/RunMode";
|
||||
import {getUUID, operationConfirm} from "metersphere-frontend/src/utils";
|
||||
|
||||
import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData";
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import {get} from "../plugins/request";
|
||||
|
||||
export function getSystemBaseSetting() {
|
||||
return get('/system/base/info');
|
||||
}
|
||||
|
||||
export function getTestResourcePools() {
|
||||
let url = '/testresourcepool/list/quota/valid';
|
||||
return get(url);
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
package io.metersphere.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.type.CollectionType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -13,6 +16,11 @@ public class JsonUtils {
|
|||
|
||||
static {
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// 自动检测所有类的全部属性
|
||||
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||
// 如果一个对象中没有任何的属性,那么在序列化的时候就会报错
|
||||
objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
|
||||
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
}
|
||||
|
||||
public static String toJSONString(Object value) {
|
||||
|
|
|
@ -7,6 +7,7 @@ public interface KafkaTopicConstants {
|
|||
String CLEAN_UP_REPORT_SCHEDULE = "CLEAN_UP_REPORT_SCHEDULE";
|
||||
// 原接口执行结果TOPIC
|
||||
String API_REPORT_TOPIC = "ms-api-exec-topic";
|
||||
String DEBUG_TOPICS = "MS-API-DEBUG-TOPIC";
|
||||
// 测试计划接收执行结果TOPIC
|
||||
String TEST_PLAN_REPORT_TOPIC = "TEST_PLAN_REPORT_TOPIC";
|
||||
// 保存当前站点时检查MOCK环境
|
||||
|
|
|
@ -115,7 +115,8 @@ public interface ParamConstants {
|
|||
CONCURRENCY("base.concurrency"),
|
||||
GRID_CONCURRENCY("base.grid.concurrency"),
|
||||
PROMETHEUS_HOST("base.prometheus.host"),
|
||||
SELENIUM_DOCKER_URL("base.selenium.docker.url");
|
||||
SELENIUM_DOCKER_URL("base.selenium.docker.url"),
|
||||
RUN_MODE("base.run.mode");
|
||||
|
||||
private String value;
|
||||
|
||||
|
|
|
@ -98,5 +98,13 @@ public enum ProjectApplicationType {
|
|||
/**
|
||||
* 我的工作台-开启待更新规则
|
||||
*/
|
||||
OPEN_UPDATE_RULE
|
||||
OPEN_UPDATE_RULE,
|
||||
/**
|
||||
* 开启接口测试默认资源池
|
||||
*/
|
||||
POOL_ENABLE,
|
||||
/**
|
||||
* 资源池ID
|
||||
*/
|
||||
RESOURCE_POOL_ID,
|
||||
}
|
||||
|
|
|
@ -33,4 +33,6 @@ public class ProjectConfig {
|
|||
private Boolean openUpdateTime = false;
|
||||
private String openUpdateRuleTime;
|
||||
private Boolean openUpdateRule;
|
||||
private String resourcePoolId;
|
||||
private Boolean poolEnable = false;
|
||||
}
|
||||
|
|
|
@ -236,6 +236,9 @@ public class SystemParameterService {
|
|||
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASE.SELENIUM_DOCKER_URL.getValue())) {
|
||||
baseSystemConfigDTO.setSeleniumDockerUrl(param.getParamValue());
|
||||
}
|
||||
if (StringUtils.equals(param.getParamKey(), ParamConstants.BASE.RUN_MODE.getValue())) {
|
||||
baseSystemConfigDTO.setRunMode(param.getParamValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
return baseSystemConfigDTO;
|
||||
|
|
|
@ -22,6 +22,7 @@ spring.datasource.quartz.hikari.connection-test-query=SELECT 1
|
|||
#kafka
|
||||
spring.kafka.bootstrap-servers=${kafka.bootstrap-servers}
|
||||
spring.kafka.consumer.group-id=metersphere_group_id
|
||||
spring.kafka.consumer.debug.group-id=metersphere_group_id_${random.uuid}
|
||||
# mybatis
|
||||
mybatis.configuration.cache-enabled=true
|
||||
mybatis.configuration.lazy-loading-enabled=false
|
||||
|
|
|
@ -94,6 +94,29 @@
|
|||
:unit-options="applyUnitOptions"
|
||||
@chooseChange="switchChange('API_SHARE_REPORT_TIME', config.apiShareReportTime, config.shareReport)"
|
||||
:title="$t('report.report_sharing_link')"/>
|
||||
|
||||
<!-- 接口测试资源池 -->
|
||||
<app-manage-item :title="$t('pj.api_run_pool_title')" :prepend-span="8" :middle-span="12"
|
||||
:append-span="4" v-if="isPool">
|
||||
<template #middle>
|
||||
<el-select v-model="config.resourcePoolId"
|
||||
size="mini"
|
||||
@change="runModeChange(true, ['RESOURCE_POOL_ID', config.resourcePoolId])">
|
||||
<el-option
|
||||
v-for="item in resourcePools"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="!item.api"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-switch v-model="config.poolEnable"
|
||||
@change="runModeChange($event, ['RESOURCE_POOL_ID', config.resourcePoolId])"></el-switch>
|
||||
</template>
|
||||
</app-manage-item>
|
||||
|
||||
</el-row>
|
||||
</el-col>
|
||||
<el-col :span="8" class="commons-view-setting">
|
||||
|
@ -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 => {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -6,6 +6,7 @@ const message = {
|
|||
pj: {
|
||||
environment_import_repeat_tip: "(已过滤同名称的环境配置 {0})",
|
||||
check_third_project_success: "检查通过",
|
||||
api_run_pool_title: '接口执行资源池',
|
||||
},
|
||||
file_manage: {
|
||||
my_file: '我的文件',
|
||||
|
|
|
@ -6,6 +6,7 @@ const message = {
|
|||
pj: {
|
||||
environment_import_repeat_tip: "(已過濾同名稱的環境配置 {0})",
|
||||
check_third_project_success: "檢查通過",
|
||||
api_run_pool_title: '接口執行資源池',
|
||||
},
|
||||
file_manage: {
|
||||
my_file: '我的文件',
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
<el-input v-model="formInline.seleniumDockerUrl" :placeholder="$t('system_config.selenium_docker.url_tip')"/>
|
||||
<i>({{ $t('commons.examples') }}:http://localhost:4444)</i>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('system.api_default_run')" prop="seleniumDockerUrl">
|
||||
<el-switch active-value="LOCAL" inactive-value="POOL" v-model="formInline.runMode" @change="modeChange"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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: '显示设置',
|
||||
|
|
|
@ -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: '顯示設置',
|
||||
|
|
|
@ -147,6 +147,12 @@ public class TestPlanService {
|
|||
private KafkaTemplate<String, String> 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转化为性能测试中辨别更明确的值
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
@close="close"
|
||||
:visible.sync="runModeVisible"
|
||||
>
|
||||
<div class="env-container">
|
||||
<div class="env-container" v-loading="loading">
|
||||
<div class="run-env-row wrap">
|
||||
<div class="title">{{ $t("commons.environment") }}:</div>
|
||||
<div class="content">
|
||||
|
@ -68,6 +68,7 @@
|
|||
<el-checkbox
|
||||
v-model="runConfig.runWithinResourcePool"
|
||||
style="padding-right: 10px"
|
||||
:disabled="runMode === 'POOL'"
|
||||
>
|
||||
{{ $t("run_mode.run_with_resource_pool") }}
|
||||
</el-checkbox>
|
||||
|
@ -94,6 +95,7 @@
|
|||
<el-checkbox
|
||||
v-model="runConfig.runWithinResourcePool"
|
||||
style="padding-right: 10px"
|
||||
:disabled="runMode === 'POOL'"
|
||||
>
|
||||
{{ $t("run_mode.run_with_resource_pool") }}
|
||||
</el-checkbox>
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -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") }}
|
||||
</el-checkbox><br/>
|
||||
|
@ -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") }}
|
||||
</el-checkbox><br/>
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
</el-col>
|
||||
<el-col :span="18">
|
||||
<div v-if="testType === 'API'">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;" :disabled="runMode === 'POOL'">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId"
|
||||
|
@ -99,7 +99,7 @@
|
|||
</el-col>
|
||||
<el-col :span="18">
|
||||
<div v-if="testType === 'API'">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
|
||||
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;" :disabled="runMode === 'POOL'">
|
||||
{{ $t('run_mode.run_with_resource_pool') }}
|
||||
</el-checkbox>
|
||||
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId"
|
||||
|
@ -203,6 +203,8 @@ import {
|
|||
import {saveNotice} from "@/api/notice";
|
||||
import {getProjectMember} from "@/api/user";
|
||||
import {getQuotaValidResourcePools} from "@/api/remote/resource-pool";
|
||||
import {getProjectConfig} from "@/api/project";
|
||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
|
@ -266,6 +268,7 @@ export default {
|
|||
}
|
||||
};
|
||||
return {
|
||||
runMode: "",
|
||||
isHasLicense: hasLicense(),
|
||||
result: {},
|
||||
scheduleReceiverOptions: [],
|
||||
|
@ -314,6 +317,29 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
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;
|
||||
});
|
||||
},
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
<el-checkbox
|
||||
v-model="runConfig.runWithinResourcePool"
|
||||
style="padding-right: 10px"
|
||||
:disabled="runMode === 'POOL'"
|
||||
>
|
||||
{{ $t("run_mode.run_with_resource_pool") }}
|
||||
</el-checkbox>
|
||||
|
@ -94,6 +95,7 @@
|
|||
<el-checkbox
|
||||
v-model="runConfig.runWithinResourcePool"
|
||||
style="padding-right: 10px"
|
||||
:disabled="runMode === 'POOL'"
|
||||
>
|
||||
{{ $t("run_mode.run_with_resource_pool") }}
|
||||
</el-checkbox>
|
||||
|
@ -186,16 +188,19 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import {getOwnerProjects, hasLicense} from "@/business/utils/sdk-utils";
|
||||
import {getCurrentProjectID, getOwnerProjects, hasLicense} from "@/business/utils/sdk-utils";
|
||||
import {BODY_TYPE as ENV_TYPE} from "@/business/plan/env/ApiTestModel";
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import EnvPopover from "@/business/plan/env/EnvPopover";
|
||||
import {getProjectConfig} from "@/api/project";
|
||||
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
|
||||
|
||||
export default {
|
||||
name: "MsPlanRunModeWithEnv",
|
||||
components: {EnvPopover, MsDialogFooter},
|
||||
data() {
|
||||
return {
|
||||
runMode: "",
|
||||
btnStyle: {
|
||||
width: "260px",
|
||||
},
|
||||
|
@ -269,11 +274,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 = {
|
||||
|
|
Loading…
Reference in New Issue