feat(接口测试): 支持场景接口用例批量执行选择环境

--story=1004209 --user=赵勇 3.case列表和场景列表批量执行支持选择环境 和测试计划保持一致 https://www.tapd.cn/55049933/s/1088817
This commit is contained in:
fit2-zhao 2021-12-30 19:19:10 +08:00 committed by fit2-zhao
parent a1700ece0c
commit a29e9951f8
24 changed files with 731 additions and 360 deletions

View File

@ -396,5 +396,10 @@ public class ApiAutomationController {
public void deleteApiScenario(@PathVariable String version, @PathVariable String refId) { public void deleteApiScenario(@PathVariable String version, @PathVariable String refId) {
apiAutomationService.deleteApiScenarioByVersion(refId, version); apiAutomationService.deleteApiScenarioByVersion(refId, version);
} }
@PostMapping(value = "/env")
public List<String> getEnvProjects(@RequestBody RunScenarioRequest request) {
return apiAutomationService.getProjects(request);
}
} }

View File

@ -47,8 +47,9 @@ public class ApiJmeterFileController {
} }
@GetMapping("download") @GetMapping("download")
public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId, @RequestParam("runMode") String runMode, @RequestParam("reportType") String reportType) { public ResponseEntity<byte[]> downloadJmeterFiles(@RequestParam("testId") String testId, @RequestParam("reportId") String reportId,
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode, testId, reportId, reportType); @RequestParam("runMode") String runMode, @RequestParam("reportType") String reportType, @RequestParam("queueId") String queueId) {
byte[] bytes = apiJmeterFileService.downloadJmeterFiles(runMode, testId, reportId, reportType, queueId);
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("application/octet-stream")) .contentType(MediaType.parseMediaType("application/octet-stream"))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + "_" + testId + ".zip\"") .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + "_" + testId + ".zip\"")

View File

@ -6,6 +6,8 @@ import io.metersphere.api.dto.ApiCaseEditRequest;
import io.metersphere.api.dto.ApiCaseRunRequest; import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.DeleteCheckResult; import io.metersphere.api.dto.DeleteCheckResult;
import io.metersphere.api.dto.definition.*; import io.metersphere.api.dto.definition.*;
import io.metersphere.api.exec.api.ApiCaseExecuteService;
import io.metersphere.api.exec.api.ApiExecuteService;
import io.metersphere.api.service.ApiTestCaseService; import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.ApiTestCase; import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
@ -36,6 +38,10 @@ public class ApiTestCaseController {
private ApiTestCaseService apiTestCaseService; private ApiTestCaseService apiTestCaseService;
@Resource @Resource
private TestPlanApiCaseService testPlanApiCaseService; private TestPlanApiCaseService testPlanApiCaseService;
@Resource
private ApiCaseExecuteService apiCaseExecuteService;
@Resource
private ApiExecuteService apiExecuteService;
@PostMapping("/list") @PostMapping("/list")
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) { public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
@ -194,13 +200,13 @@ public class ApiTestCaseController {
@MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class) @MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public void batchRun(@RequestBody ApiCaseRunRequest request) { public void batchRun(@RequestBody ApiCaseRunRequest request) {
request.setTriggerMode(ReportTriggerMode.BATCH.name()); request.setTriggerMode(ReportTriggerMode.BATCH.name());
apiTestCaseService.batchRun(request); apiCaseExecuteService.run(request);
} }
@PostMapping(value = "/jenkins/run") @PostMapping(value = "/jenkins/run")
@MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class) @MsAuditLog(module = "api_definition_case", type = OperLogConstants.EXECUTE, content = "#msClass.getLogDetails(#request.caseId)", msClass = ApiTestCaseService.class)
public MsExecResponseDTO jenkinsRun(@RequestBody RunCaseRequest request) { public MsExecResponseDTO jenkinsRun(@RequestBody RunCaseRequest request) {
return apiTestCaseService.jenkinsRun(request); return apiExecuteService.jenkinsRun(request);
} }
@GetMapping(value = "/jenkins/exec/result/{id}") @GetMapping(value = "/jenkins/exec/result/{id}")

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.ApiTestCaseRequest; import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.OrderRequest;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -17,5 +18,6 @@ public class ApiCaseRunRequest {
private List<OrderRequest> orders; private List<OrderRequest> orders;
private String projectId; private String projectId;
private String environmentId; private String environmentId;
private RunModeConfigDTO config;
private ApiTestCaseRequest condition; private ApiTestCaseRequest condition;
} }

View File

@ -0,0 +1,196 @@
package io.metersphere.api.exec.api;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiCaseExecuteService {
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private ApiCaseParallelExecuteService apiCaseParallelExecuteService;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private EnvironmentGroupProjectService environmentGroupProjectService;
/**
* 测试计划case执行
*
* @param request
* @return
*/
public List<MsExecResponseDTO> run(BatchRunDefinitionRequest request) {
List<String> ids = request.getPlanIds();
if (CollectionUtils.isEmpty(ids)) {
return new LinkedList<>();
}
if (request.getConfig() == null) {
request.setConfig(new RunModeConfigDTO());
}
if (StringUtils.equals("GROUP", request.getConfig().getEnvironmentType()) && StringUtils.isNotEmpty(request.getConfig().getEnvironmentGroupId())) {
request.getConfig().setEnvMap(environmentGroupProjectService.getEnvMap(request.getConfig().getEnvironmentGroupId()));
}
LoggerUtil.debug("开始查询测试计划用例");
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
example.createCriteria().andIdIn(ids);
example.setOrderByClause("`order` DESC");
List<TestPlanApiCase> planApiCases = testPlanApiCaseMapper.selectByExample(example);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ApiRunMode.API_PLAN.name());
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>();
//记录案例线程结果以及执行失败的案例ID
Map<String, String> executeThreadIdMap = new HashMap<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
planApiCases.forEach(testPlanApiCase -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status, batchMapper);
executeQueue.put(testPlanApiCase.getId(), report);
executeThreadIdMap.put(testPlanApiCase.getId(), report.getId());
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
});
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
LoggerUtil.debug("开始生成测试计划队列");
String reportType = request.getConfig().getReportType();
String poolId = request.getConfig().getResourcePoolId();
String runMode = StringUtils.equals(request.getTriggerMode(), TriggerMode.MANUAL.name()) ? ApiRunMode.API_PLAN.name() : ApiRunMode.SCHEDULE_API_PLAN.name();
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.API_PLAN.name(), request.getPlanReportId(), reportType, runMode, request.getConfig().getEnvMap());
//如果是测试计划生成报告的执行则更新执行信息执行线程信息
if (TestPlanReportExecuteCatch.containsReport(request.getPlanReportId())) {
if (!executeThreadIdMap.isEmpty()) {
TestPlanReportExecuteCatch.updateTestPlanThreadInfo(request.getPlanReportId(), executeThreadIdMap, null, null);
}
}
// 开始选择执行模式
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
LoggerUtil.debug("开始串行执行");
if (deQueue != null && deQueue.getQueue() != null) {
apiScenarioSerialService.serial(deQueue, deQueue.getQueue());
}
} else {
LoggerUtil.debug("开始并发执行");
if (deQueue != null && deQueue.getQueue() != null) {
apiCaseParallelExecuteService.parallel(executeQueue, request.getConfig(), deQueue, runMode);
}
}
return responseDTOS;
}
/**
* 接口定义case执行
*
* @param request
* @return
*/
public List<MsExecResponseDTO> run(ApiCaseRunRequest request) {
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("进入执行方法,接收到参数:" + JSON.toJSONString(request));
}
if (request.getConfig() == null) {
request.setConfig(new RunModeConfigDTO());
}
if (StringUtils.equals("GROUP", request.getConfig().getEnvironmentType()) && StringUtils.isNotEmpty(request.getConfig().getEnvironmentGroupId())) {
request.getConfig().setEnvMap(environmentGroupProjectService.getEnvMap(request.getConfig().getEnvironmentGroupId()));
}
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest) query));
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdIn(request.getIds());
List<ApiTestCaseWithBLOBs> list = apiTestCaseMapper.selectByExampleWithBLOBs(example);
LoggerUtil.debug("查询到执行数据:" + list.size());
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ApiRunMode.DEFINITION.name());
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
Map<String, ApiDefinitionExecResult> executeQueue = new HashMap<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
list.forEach(caseWithBLOBs -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.initBase(caseWithBLOBs.getId(), APITestStatus.Running.name(), null, request.getConfig());
report.setStatus(status);
batchMapper.insert(report);
executeQueue.put(caseWithBLOBs.getId(), report);
responseDTOS.add(new MsExecResponseDTO(caseWithBLOBs.getId(), report.getId(), request.getTriggerMode()));
});
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
String reportType = request.getConfig().getReportType();
String poolId = request.getConfig().getResourcePoolId();
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.DEFINITION.name(), null, reportType, ApiRunMode.DEFINITION.name(), request.getConfig().getEnvMap());
// 开始选择执行模式
if (request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
LoggerUtil.debug("开始串行执行");
if (deQueue != null && deQueue.getQueue() != null) {
apiScenarioSerialService.serial(deQueue, deQueue.getQueue());
}
} else {
LoggerUtil.debug("开始并发执行");
if (deQueue != null && deQueue.getQueue() != null) {
apiCaseParallelExecuteService.parallel(executeQueue, request.getConfig(), deQueue, ApiRunMode.DEFINITION.name());
}
}
return responseDTOS;
}
}

View File

@ -0,0 +1,57 @@
package io.metersphere.api.exec.api;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.jorphan.collections.HashTree;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
@Service
public class ApiCaseParallelExecuteService {
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private JMeterService jMeterService;
public void parallel(Map<String, ApiDefinitionExecResult> executeQueue, RunModeConfigDTO config, DBTestQueue executionQueue, String runMode) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
Thread.currentThread().setName("API-CASE-THREAD");
for (String testId : executeQueue.keySet()) {
ApiDefinitionExecResult result = executeQueue.get(testId);
String reportId = result.getId();
HashTree hashTree = null;
if (!GenerateHashTreeUtil.isResourcePool(config.getResourcePoolId()).isPool()) {
hashTree = apiScenarioSerialService.generateHashTree(testId, executionQueue.getRunMode(), config.getEnvMap());
}
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testId, reportId, runMode, hashTree);
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(config.getResourcePoolId()));
runRequest.setPoolId(config.getResourcePoolId());
runRequest.setReportType(executionQueue.getReportType());
runRequest.setRunType(RunModeConstants.PARALLEL.toString());
runRequest.setQueueId(executionQueue.getId());
if (executionQueue.getQueue() != null) {
runRequest.setPlatformUrl(executionQueue.getQueue().getId());
}
jMeterService.run(runRequest);
}
} catch (Exception e) {
LoggerUtil.error("并发执行用例失败:" + e.getMessage());
}
}
});
thread.start();
}
}

View File

@ -5,8 +5,6 @@ import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.RunCaseRequest; import io.metersphere.api.dto.definition.RunCaseRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.dto.definition.request.ElementUtil; import io.metersphere.api.dto.definition.request.ElementUtil;
@ -30,19 +28,14 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils; import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.dto.JmeterRunRequestDTO; import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO; import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.plugin.core.MsTestElement; import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree; import org.apache.jorphan.collections.ListedHashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -56,10 +49,6 @@ public class ApiExecuteService {
@Resource @Resource
private ApiTestCaseMapper apiTestCaseMapper; private ApiTestCaseMapper apiTestCaseMapper;
@Resource @Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
@Resource
private JMeterService jMeterService; private JMeterService jMeterService;
@Resource @Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper; private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@ -69,68 +58,45 @@ public class ApiExecuteService {
private ApiTestEnvironmentService environmentService; private ApiTestEnvironmentService environmentService;
@Resource @Resource
private TcpApiParamService tcpApiParamService; private TcpApiParamService tcpApiParamService;
@Resource
private ExtApiTestCaseMapper extApiTestCaseMapper;
public List<MsExecResponseDTO> run(ApiCaseRunRequest request) { public MsExecResponseDTO jenkinsRun(RunCaseRequest request) {
if (LoggerUtil.getLogger().isDebugEnabled()) { ApiTestCaseWithBLOBs caseWithBLOBs = null;
LoggerUtil.debug("进入执行方法,接收到参数:" + JSON.toJSONString(request)); if (request.getBloBs() == null) {
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
if (caseWithBLOBs == null) {
return null;
}
request.setBloBs(caseWithBLOBs);
} else {
caseWithBLOBs = request.getBloBs();
} }
if (caseWithBLOBs == null) {
ServiceUtils.getSelectAllIds(request, request.getCondition(), return null;
(query) -> extApiTestCaseMapper.selectIdsByQuery((ApiTestCaseRequest) query));
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiTestCaseExample example = new ApiTestCaseExample();
example.createCriteria().andIdIn(request.getIds());
List<ApiTestCaseWithBLOBs> list = apiTestCaseMapper.selectByExampleWithBLOBs(example);
LoggerUtil.debug("查询到执行数据:" + list.size());
ApiTestCaseMapper sqlSessionMapper = sqlSession.getMapper(ApiTestCaseMapper.class);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
List<RunCaseRequest> executeQueue = new LinkedList<>();
for (ApiTestCaseWithBLOBs caseWithBLOBs : list) {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.initBase(caseWithBLOBs.getId(), APITestStatus.Running.name(), null);
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(request.getTriggerMode());
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
sqlSessionMapper.updateByPrimaryKey(caseWithBLOBs);
// 执行对象
RunCaseRequest runCaseRequest = new RunCaseRequest();
runCaseRequest.setRunMode(ApiRunMode.DEFINITION.name());
runCaseRequest.setCaseId(caseWithBLOBs.getId());
runCaseRequest.setReportId(report.getId());
runCaseRequest.setEnvironmentId(request.getEnvironmentId());
runCaseRequest.setBloBs(caseWithBLOBs);
runCaseRequest.setReport(report);
batchMapper.insert(report);
executeQueue.add(runCaseRequest);
} }
sqlSession.flushStatements(); if (StringUtils.isBlank(request.getEnvironmentId())) {
if (sqlSession != null && sqlSessionFactory != null) { request.setEnvironmentId(extApiTestCaseMapper.getApiCaseEnvironment(request.getCaseId()));
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
} }
//提前生成报告
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.add(caseWithBLOBs.getId(), APITestStatus.Running.name(), request.getReportId());
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(ApiRunMode.JENKINS.name());
report.setType(ApiRunMode.JENKINS.name());
apiDefinitionExecResultMapper.insert(report);
//更新接口案例的最后执行状态等信息
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
request.setReport(report);
LoggerUtil.info("生成执行队列:" + executeQueue.size()); if (StringUtils.isEmpty(request.getRunMode())) {
if (LoggerUtil.getLogger().isDebugEnabled()) { request.setRunMode(ApiRunMode.DEFINITION.name());
LoggerUtil.debug("生成执行队列:" + JSON.toJSONString(executeQueue));
} }
List<MsExecResponseDTO> responseDTOS = new LinkedList<>(); return this.exec(request);
for (RunCaseRequest runCaseRequest : executeQueue) {
responseDTOS.add(exec(runCaseRequest));
}
return responseDTOS;
} }
/**
* 单条执行
*
* @param request
* @return
*/
public MsExecResponseDTO exec(RunCaseRequest request) { public MsExecResponseDTO exec(RunCaseRequest request) {
ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs(); ApiTestCaseWithBLOBs testCaseWithBLOBs = request.getBloBs();
if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) { if (StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())) {

View File

@ -1,146 +0,0 @@
package io.metersphere.api.exec.api;
import io.metersphere.api.cache.TestPlanReportExecuteCatch;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.domain.TestPlanApiCaseExample;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.jorphan.collections.HashTree;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanApiExecuteService {
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private JMeterService jMeterService;
public List<MsExecResponseDTO> run(BatchRunDefinitionRequest request) {
List<String> ids = request.getPlanIds();
if (CollectionUtils.isEmpty(ids)) {
return new LinkedList<>();
}
LoggerUtil.debug("开始查询测试计划用例");
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
example.createCriteria().andIdIn(ids);
example.setOrderByClause("`order` DESC");
List<TestPlanApiCase> planApiCases = testPlanApiCaseMapper.selectByExample(example);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiDefinitionExecResultMapper batchMapper = sqlSession.getMapper(ApiDefinitionExecResultMapper.class);
if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ApiRunMode.API_PLAN.name());
}
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
Map<TestPlanApiCase, ApiDefinitionExecResult> executeQueue = new HashMap<>();
//记录案例线程结果以及执行失败的案例ID
Map<String, String> executeThreadIdMap = new HashMap<>();
String status = request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
planApiCases.forEach(testPlanApiCase -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status, batchMapper);
executeQueue.put(testPlanApiCase, report);
executeThreadIdMap.put(testPlanApiCase.getId(), report.getId());
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
});
sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
LoggerUtil.debug("开始生成测试计划队列");
String reportType = request.getConfig() != null ? request.getConfig().getReportType() : null;
String poolId = request.getConfig() != null ? request.getConfig().getResourcePoolId() : null;
String runMode = StringUtils.equals(request.getTriggerMode(), TriggerMode.MANUAL.name()) ? ApiRunMode.API_PLAN.name() : ApiRunMode.SCHEDULE_API_PLAN.name();
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.API_PLAN.name(), request.getPlanReportId(), reportType, runMode);
//如果是测试计划生成报告的执行则更新执行信息执行线程信息
if (TestPlanReportExecuteCatch.containsReport(request.getPlanReportId())) {
if (!executeThreadIdMap.isEmpty()) {
TestPlanReportExecuteCatch.updateTestPlanThreadInfo(request.getPlanReportId(), executeThreadIdMap, null, null);
}
}
// 开始选择执行模式
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
LoggerUtil.debug("开始串行执行");
if (deQueue != null && deQueue.getQueue() != null) {
apiScenarioSerialService.serial(deQueue, deQueue.getQueue());
}
} else {
LoggerUtil.debug("开始并发执行");
if (deQueue != null && deQueue.getQueue() != null) {
parallel(executeQueue, request, deQueue);
}
}
return responseDTOS;
}
private void parallel(Map<TestPlanApiCase, ApiDefinitionExecResult> executeQueue, BatchRunDefinitionRequest request, DBTestQueue executionQueue) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
Thread.currentThread().setName("测试计划入列线程");
for (TestPlanApiCase testPlanApiCase : executeQueue.keySet()) {
ApiDefinitionExecResult result = executeQueue.get(testPlanApiCase);
String reportId = result.getId();
HashTree hashTree = null;
if (request.getConfig() == null || !GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()).isPool()) {
hashTree = apiScenarioSerialService.generateHashTree(testPlanApiCase.getId());
}
String runMode = StringUtils.equals(request.getTriggerMode(), TriggerMode.MANUAL.name()) ? ApiRunMode.API_PLAN.name() : ApiRunMode.SCHEDULE_API_PLAN.name();
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testPlanApiCase.getId(), reportId, runMode, hashTree);
if (request.getConfig() != null) {
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()));
runRequest.setPoolId(request.getConfig().getResourcePoolId());
}
runRequest.setTestPlanReportId(request.getPlanReportId());
runRequest.setReportType(executionQueue.getReportType());
runRequest.setTestPlanReportId(request.getPlanReportId());
runRequest.setRunType(RunModeConstants.PARALLEL.toString());
runRequest.setQueueId(executionQueue.getId());
jMeterService.run(runRequest);
}
} catch (Exception e) {
LoggerUtil.error("并发执行测试计划用例失败:" + e.getMessage());
}
}
});
thread.start();
}
}

View File

@ -4,7 +4,11 @@ import io.metersphere.base.domain.ApiExecutionQueue;
import io.metersphere.base.domain.ApiExecutionQueueDetail; import io.metersphere.base.domain.ApiExecutionQueueDetail;
import lombok.Data; import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data @Data
public class DBTestQueue extends ApiExecutionQueue { public class DBTestQueue extends ApiExecutionQueue {
private ApiExecutionQueueDetail queue; private ApiExecutionQueueDetail queue;
private Map<String, String> detailMap = new HashMap<>();
} }

View File

@ -32,6 +32,7 @@ import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.constants.RunModeConstants; import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.JmeterRunRequestDTO; import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.MsExecResponseDTO; import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.service.EnvironmentGroupProjectService; import io.metersphere.service.EnvironmentGroupProjectService;
import io.metersphere.track.service.TestPlanScenarioCaseService; import io.metersphere.track.service.TestPlanScenarioCaseService;
@ -98,6 +99,14 @@ public class ApiScenarioExecuteService {
if (StringUtils.isEmpty(request.getTriggerMode())) { if (StringUtils.isEmpty(request.getTriggerMode())) {
request.setTriggerMode(ReportTriggerMode.MANUAL.name()); request.setTriggerMode(ReportTriggerMode.MANUAL.name());
} }
if (request.getConfig() == null) {
request.setConfig(new RunModeConfigDTO());
}
if (StringUtils.equals("GROUP", request.getConfig().getEnvironmentType()) && StringUtils.isNotEmpty(request.getConfig().getEnvironmentGroupId())) {
request.getConfig().setEnvMap(environmentGroupProjectService.getEnvMap(request.getConfig().getEnvironmentGroupId()));
}
// 生成集成报告 // 生成集成报告
String serialReportId = null; String serialReportId = null;
LoggerUtil.info("Scenario run-执行脚本装载-根据条件查询所有场景 "); LoggerUtil.info("Scenario run-执行脚本装载-根据条件查询所有场景 ");
@ -156,8 +165,7 @@ public class ApiScenarioExecuteService {
// 开始执行 // 开始执行
if (executeQueue != null && executeQueue.size() > 0) { if (executeQueue != null && executeQueue.size() > 0) {
String reportType = request.getConfig().getReportType(); String reportType = request.getConfig().getReportType();
DBTestQueue executionQueue = apiExecutionQueueService.add(executeQueue, request.getConfig().getResourcePoolId(), ApiRunMode.SCENARIO.name(), serialReportId, reportType, request.getRunMode(), request.getConfig().getEnvMap());
DBTestQueue executionQueue = apiExecutionQueueService.add(executeQueue, request.getConfig().getResourcePoolId(), ApiRunMode.SCENARIO.name(), serialReportId, reportType, request.getRunMode());
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) { if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (StringUtils.isNotEmpty(serialReportId)) { if (StringUtils.isNotEmpty(serialReportId)) {
apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null); apiScenarioReportStructureService.save(apiScenarios, serialReportId, request.getConfig() != null ? request.getConfig().getReportType() : null);
@ -181,7 +189,7 @@ public class ApiScenarioExecuteService {
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue()); apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
} }
} else { } else {
apiScenarioParallelService.parallel(executeQueue, request, serialReportId, responseDTOS, executionQueue.getId()); apiScenarioParallelService.parallel(executeQueue, request, serialReportId, responseDTOS, executionQueue);
} }
} }
return responseDTOS; return responseDTOS;
@ -309,6 +317,9 @@ public class ApiScenarioExecuteService {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(); RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
runModeDataDTO.setTestId(item.getId()); runModeDataDTO.setTestId(item.getId());
runModeDataDTO.setPlanEnvMap(new HashMap<>()); runModeDataDTO.setPlanEnvMap(new HashMap<>());
if (request.getConfig().getEnvMap() != null) {
runModeDataDTO.setPlanEnvMap(request.getConfig().getEnvMap());
}
runModeDataDTO.setReport(report); runModeDataDTO.setReport(report);
runModeDataDTO.setReportId(report.getId()); runModeDataDTO.setReportId(report.getId());
executeQueue.put(report.getId(), runModeDataDTO); executeQueue.put(report.getId(), runModeDataDTO);
@ -317,9 +328,10 @@ public class ApiScenarioExecuteService {
try { try {
RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, item.getId()); RunModeDataDTO runModeDataDTO = new RunModeDataDTO(report, item.getId());
if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) { if (request.getConfig() != null && !request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
HashTree hashTree = GenerateHashTreeUtil.generateHashTree(item, StringUtils.isNotEmpty(serialReportId) ? serialReportId + "-" + i : reportId, new HashMap<>(), request.getConfig().getReportType()); HashTree hashTree = GenerateHashTreeUtil.generateHashTree(item, StringUtils.isNotEmpty(serialReportId) ? serialReportId + "-" + i : reportId, request.getConfig().getEnvMap(), request.getConfig().getReportType());
runModeDataDTO.setHashTree(hashTree); runModeDataDTO.setHashTree(hashTree);
} }
runModeDataDTO.setPlanEnvMap(request.getConfig().getEnvMap());
executeQueue.put(report.getId(), runModeDataDTO); executeQueue.put(report.getId(), runModeDataDTO);
} catch (Exception ex) { } catch (Exception ex) {
scenarioIds.remove(item.getId()); scenarioIds.remove(item.getId());

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.RunModeDataDTO; import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.dto.automation.APIScenarioReportResult; import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.RunScenarioRequest; import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil; import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.mapper.ApiScenarioReportMapper; import io.metersphere.base.mapper.ApiScenarioReportMapper;
@ -30,7 +31,7 @@ public class ApiScenarioParallelService {
@Resource @Resource
private JMeterService jMeterService; private JMeterService jMeterService;
public void parallel(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId, List<MsExecResponseDTO> responseDTOS, String queueId) { public void parallel(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId, List<MsExecResponseDTO> responseDTOS, DBTestQueue executionQueue) {
if (StringUtils.isEmpty(serialReportId)) { if (StringUtils.isEmpty(serialReportId)) {
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class); ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
@ -49,13 +50,14 @@ public class ApiScenarioParallelService {
for (String reportId : executeQueue.keySet()) { for (String reportId : executeQueue.keySet()) {
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(executeQueue.get(reportId).getTestId(), StringUtils.isNotEmpty(serialReportId) ? serialReportId : reportId, request.getRunMode(), executeQueue.get(reportId).getHashTree()); JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(executeQueue.get(reportId).getTestId(), StringUtils.isNotEmpty(serialReportId) ? serialReportId : reportId, request.getRunMode(), executeQueue.get(reportId).getHashTree());
runRequest.setReportType(StringUtils.isNotEmpty(serialReportId) ? RunModeConstants.SET_REPORT.toString() : RunModeConstants.INDEPENDENCE.toString()); runRequest.setReportType(StringUtils.isNotEmpty(serialReportId) ? RunModeConstants.SET_REPORT.toString() : RunModeConstants.INDEPENDENCE.toString());
runRequest.setQueueId(queueId); runRequest.setQueueId(executionQueue.getId());
if (request.getConfig() != null) { if (request.getConfig() != null) {
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId())); runRequest.setPool(GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()));
runRequest.setPoolId(request.getConfig().getResourcePoolId()); runRequest.setPoolId(request.getConfig().getResourcePoolId());
} }
runRequest.setTestPlanReportId(request.getTestPlanReportId()); runRequest.setTestPlanReportId(request.getTestPlanReportId());
runRequest.setHashTree(executeQueue.get(reportId).getHashTree()); runRequest.setHashTree(executeQueue.get(reportId).getHashTree());
runRequest.setPlatformUrl(executionQueue.getDetailMap().get(reportId));
if (LoggerUtil.getLogger().isDebugEnabled()) { if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("Scenario run-开始并发执行:" + JSON.toJSONString(request)); LoggerUtil.debug("Scenario run-开始并发执行:" + JSON.toJSONString(request));
} }

View File

@ -100,7 +100,11 @@ public class ApiScenarioSerialService {
} }
hashTree = GenerateHashTreeUtil.generateHashTree(scenario, queue.getReportId(), planEnvMap, executionQueue.getReportType()); hashTree = GenerateHashTreeUtil.generateHashTree(scenario, queue.getReportId(), planEnvMap, executionQueue.getReportType());
} else { } else {
hashTree = generateHashTree(queue.getTestId()); Map<String, String> map = new LinkedHashMap<>();
if (StringUtils.isNotEmpty(queue.getEvnMap())) {
map = JSON.parseObject(queue.getEvnMap(), Map.class);
}
hashTree = generateHashTree(queue.getTestId(), queue.getType(), map);
} }
// 更新环境变量 // 更新环境变量
this.initEnv(hashTree); this.initEnv(hashTree);
@ -116,6 +120,9 @@ public class ApiScenarioSerialService {
runRequest.setRunType(RunModeConstants.SERIAL.toString()); runRequest.setRunType(RunModeConstants.SERIAL.toString());
runRequest.setQueueId(executionQueue.getId()); runRequest.setQueueId(executionQueue.getId());
runRequest.setPoolId(executionQueue.getPoolId()); runRequest.setPoolId(executionQueue.getPoolId());
if (queue != null) {
runRequest.setPlatformUrl(queue.getId());
}
// 开始执行 // 开始执行
jMeterService.run(runRequest); jMeterService.run(runRequest);
} catch (Exception e) { } catch (Exception e) {
@ -145,25 +152,36 @@ public class ApiScenarioSerialService {
hashTreeUtil.mergeParamDataMap(null, envParamsMap); hashTreeUtil.mergeParamDataMap(null, envParamsMap);
} }
public HashTree generateHashTree(String testId) { public HashTree generateHashTree(String testId, String type, Map<String, String> envMap) {
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(testId); ApiTestCaseWithBLOBs caseWithBLOBs = null;
if (apiCase != null) { String envId = null;
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(apiCase.getApiCaseId()); if (StringUtils.equals(type, ApiRunMode.DEFINITION.name())) {
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testId);
} else {
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(testId);
if (apiCase != null) {
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(apiCase.getApiCaseId());
envId = apiCase.getEnvironmentId();
}
}
if (envMap != null && envMap.containsKey(caseWithBLOBs.getProjectId())) {
envId = envMap.get(caseWithBLOBs.getProjectId());
}
if (caseWithBLOBs != null) {
HashTree jmeterHashTree = new HashTree(); HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan(); MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>()); testPlan.setHashTree(new LinkedList<>());
if (caseWithBLOBs != null) { try {
try { MsThreadGroup group = new MsThreadGroup();
MsThreadGroup group = new MsThreadGroup(); group.setLabel(caseWithBLOBs.getName());
group.setLabel(caseWithBLOBs.getName()); group.setName(caseWithBLOBs.getName());
group.setName(caseWithBLOBs.getName());
MsTestElement testElement = parse(caseWithBLOBs, testId); MsTestElement testElement = parse(caseWithBLOBs, testId, envId);
group.setHashTree(new LinkedList<>()); group.setHashTree(new LinkedList<>());
group.getHashTree().add(testElement); group.getHashTree().add(testElement);
testPlan.getHashTree().add(group); testPlan.getHashTree().add(group);
} catch (Exception ex) { } catch (Exception ex) {
MSException.throwException(ex.getMessage()); MSException.throwException(ex.getMessage());
}
} }
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig()); testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
return jmeterHashTree; return jmeterHashTree;
@ -171,7 +189,7 @@ public class ApiScenarioSerialService {
return null; return null;
} }
private MsTestElement parse(ApiTestCaseWithBLOBs caseWithBLOBs, String planId) { private MsTestElement parse(ApiTestCaseWithBLOBs caseWithBLOBs, String planId, String envId) {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try { try {
@ -186,31 +204,38 @@ public class ApiScenarioSerialService {
}); });
list.addAll(elements); list.addAll(elements);
} }
TestPlanApiCase apiCase = testPlanApiCaseMapper.selectByPrimaryKey(planId);
if (element.getString("type").equals("HTTPSamplerProxy")) { if (element.getString("type").equals("HTTPSamplerProxy")) {
MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class); MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class);
httpSamplerProxy.setHashTree(list); httpSamplerProxy.setHashTree(list);
httpSamplerProxy.setName(planId); httpSamplerProxy.setName(planId);
httpSamplerProxy.setUseEnvironment(apiCase.getEnvironmentId()); if (StringUtils.isNotEmpty(envId)) {
httpSamplerProxy.setUseEnvironment(envId);
}
return httpSamplerProxy; return httpSamplerProxy;
} }
if (element.getString("type").equals("TCPSampler")) { if (element.getString("type").equals("TCPSampler")) {
MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class); MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class);
msTCPSampler.setUseEnvironment(apiCase.getEnvironmentId()); if (StringUtils.isNotEmpty(envId)) {
msTCPSampler.setUseEnvironment(envId);
}
msTCPSampler.setHashTree(list); msTCPSampler.setHashTree(list);
msTCPSampler.setName(planId); msTCPSampler.setName(planId);
return msTCPSampler; return msTCPSampler;
} }
if (element.getString("type").equals("DubboSampler")) { if (element.getString("type").equals("DubboSampler")) {
MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class); MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class);
dubboSampler.setUseEnvironment(apiCase.getEnvironmentId()); if (StringUtils.isNotEmpty(envId)) {
dubboSampler.setUseEnvironment(envId);
}
dubboSampler.setHashTree(list); dubboSampler.setHashTree(list);
dubboSampler.setName(planId); dubboSampler.setName(planId);
return dubboSampler; return dubboSampler;
} }
if (element.getString("type").equals("JDBCSampler")) { if (element.getString("type").equals("JDBCSampler")) {
MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class); MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class);
jDBCSampler.setUseEnvironment(apiCase.getEnvironmentId()); if (StringUtils.isNotEmpty(envId)) {
jDBCSampler.setUseEnvironment(envId);
}
jDBCSampler.setHashTree(list); jDBCSampler.setHashTree(list);
jDBCSampler.setName(planId); jDBCSampler.setName(planId);
return jDBCSampler; return jDBCSampler;

View File

@ -10,13 +10,14 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TriggerMode; import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.RunModeConfigDTO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
public class ApiDefinitionExecResultUtil { public class ApiDefinitionExecResultUtil {
public static ApiDefinitionExecResult initBase(String resourceId, String status, String reportId) { public static ApiDefinitionExecResult initBase(String resourceId, String status, String reportId, RunModeConfigDTO config) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult(); ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
if (StringUtils.isEmpty(reportId)) { if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString()); apiResult.setId(UUID.randomUUID().toString());
@ -28,6 +29,9 @@ public class ApiDefinitionExecResultUtil {
apiResult.setEndTime(System.currentTimeMillis()); apiResult.setEndTime(System.currentTimeMillis());
apiResult.setTriggerMode(TriggerMode.BATCH.name()); apiResult.setTriggerMode(TriggerMode.BATCH.name());
apiResult.setActuator("LOCAL"); apiResult.setActuator("LOCAL");
if (config != null && GenerateHashTreeUtil.isResourcePool(config.getResourcePoolId()).isPool()) {
apiResult.setActuator(config.getResourcePoolId());
}
apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId()); apiResult.setUserId(Objects.requireNonNull(SessionUtils.getUser()).getId());
apiResult.setResourceId(resourceId); apiResult.setResourceId(resourceId);
apiResult.setStartTime(System.currentTimeMillis()); apiResult.setStartTime(System.currentTimeMillis());

View File

@ -107,11 +107,15 @@ public class JMeterService {
if (baseInfo != null) { if (baseInfo != null) {
platformUrl = baseInfo.getUrl(); platformUrl = baseInfo.getUrl();
} }
// 临时存放
String queueDetailId = request.getPlatformUrl();
platformUrl += "/api/jmeter/download?testId=" platformUrl += "/api/jmeter/download?testId="
+ request.getTestId() + request.getTestId()
+ "&reportId=" + request.getReportId() + "&reportId=" + request.getReportId()
+ "&runMode=" + request.getRunMode() + "&runMode=" + request.getRunMode()
+ "&reportType=" + request.getReportType(); + "&reportType=" + request.getReportType()
+ "&queueId=" + queueDetailId;
request.setPlatformUrl(platformUrl); request.setPlatformUrl(platformUrl);
request.setKafkaConfig(KafkaConfig.getKafka()); request.setKafkaConfig(KafkaConfig.getKafka());

View File

@ -1948,4 +1948,20 @@ public class ApiAutomationService {
example.createCriteria().andRefIdEqualTo(refId).andVersionIdEqualTo(version); example.createCriteria().andRefIdEqualTo(refId).andVersionIdEqualTo(version);
apiScenarioMapper.deleteByExample(example); apiScenarioMapper.deleteByExample(example);
} }
public List<String> getProjects(RunScenarioRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiScenarioMapper.selectIdsByQuery(query));
List<String> ids = request.getIds();
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(ids);
List<ApiScenario> apiScenarios = apiScenarioMapper.selectByExample(example);
List<String> strings = new LinkedList<>();
apiScenarios.forEach(item -> {
if (!strings.contains(item.getProjectId())) {
strings.add(item.getProjectId());
}
});
return strings;
}
} }

View File

@ -90,43 +90,47 @@ public class ApiDefinitionExecResultService {
} }
private void sendNotice(ApiDefinitionExecResult result) { private void sendNotice(ApiDefinitionExecResult result) {
String resourceId = result.getResourceId(); try {
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(resourceId); String resourceId = result.getResourceId();
// 接口定义直接执行不发通知 ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(resourceId);
if (apiTestCaseWithBLOBs == null) { // 接口定义直接执行不发通知
return; if (apiTestCaseWithBLOBs == null) {
} return;
BeanMap beanMap = new BeanMap(apiTestCaseWithBLOBs); }
BeanMap beanMap = new BeanMap(apiTestCaseWithBLOBs);
String event; String event;
String status; String status;
if (StringUtils.equals(result.getStatus(), "success")) { if (StringUtils.equals(result.getStatus(), "success")) {
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL; event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
status = "成功"; status = "成功";
} else { } else {
event = NoticeConstants.Event.EXECUTE_FAILED; event = NoticeConstants.Event.EXECUTE_FAILED;
status = "失败"; status = "失败";
} }
Map paramMap = new HashMap<>(beanMap); Map paramMap = new HashMap<>(beanMap);
paramMap.put("operator", SessionUtils.getUser().getName()); paramMap.put("operator", SessionUtils.getUser().getName());
paramMap.put("status", result.getStatus()); paramMap.put("status", result.getStatus());
String context = "${operator}执行接口用例" + status + ": ${name}"; String context = "${operator}执行接口用例" + status + ": ${name}";
NoticeModel noticeModel = NoticeModel.builder() NoticeModel noticeModel = NoticeModel.builder()
.operator(SessionUtils.getUserId()) .operator(SessionUtils.getUserId())
.context(context) .context(context)
.subject("接口用例通知") .subject("接口用例通知")
.successMailTemplate("api/CaseResultSuccess") .successMailTemplate("api/CaseResultSuccess")
.failedMailTemplate("api/CaseResultFailed") .failedMailTemplate("api/CaseResultFailed")
.paramMap(paramMap) .paramMap(paramMap)
.event(event) .event(event)
.build(); .build();
String taskType = NoticeConstants.TaskType.API_DEFINITION_TASK; String taskType = NoticeConstants.TaskType.API_DEFINITION_TASK;
if (StringUtils.equals(ReportTriggerMode.API.name(), result.getTriggerMode())) { if (StringUtils.equals(ReportTriggerMode.API.name(), result.getTriggerMode())) {
noticeSendService.send(ReportTriggerMode.API.name(), taskType, noticeModel); noticeSendService.send(ReportTriggerMode.API.name(), taskType, noticeModel);
} else { } else {
noticeSendService.send(taskType, noticeModel); noticeSendService.send(taskType, noticeModel);
}
} catch (Exception e) {
LogUtil.error(e);
} }
} }

View File

@ -26,9 +26,7 @@ import org.mybatis.spring.SqlSessionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.*;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -50,7 +48,7 @@ public class ApiExecutionQueueService {
@Resource @Resource
private ExtApiExecutionQueueMapper extApiExecutionQueueMapper; private ExtApiExecutionQueueMapper extApiExecutionQueueMapper;
public DBTestQueue add(Object runObj, String poolId, String type, String reportId, String reportType, String runMode) { public DBTestQueue add(Object runObj, String poolId, String type, String reportId, String reportType, String runMode, Map<String, String> envMap) {
ApiExecutionQueue executionQueue = new ApiExecutionQueue(); ApiExecutionQueue executionQueue = new ApiExecutionQueue();
executionQueue.setId(UUID.randomUUID().toString()); executionQueue.setId(UUID.randomUUID().toString());
executionQueue.setCreateTime(System.currentTimeMillis()); executionQueue.setCreateTime(System.currentTimeMillis());
@ -61,19 +59,25 @@ public class ApiExecutionQueueService {
queueMapper.insert(executionQueue); queueMapper.insert(executionQueue);
DBTestQueue resQueue = new DBTestQueue(); DBTestQueue resQueue = new DBTestQueue();
BeanUtils.copyBean(resQueue, executionQueue); BeanUtils.copyBean(resQueue, executionQueue);
Map<String, String> detailMap = new HashMap<>();
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ApiExecutionQueueDetailMapper batchMapper = sqlSession.getMapper(ApiExecutionQueueDetailMapper.class); ApiExecutionQueueDetailMapper batchMapper = sqlSession.getMapper(ApiExecutionQueueDetailMapper.class);
if (StringUtils.equals(type, ApiRunMode.API_PLAN.name())) { if (StringUtils.equalsAny(type, ApiRunMode.DEFINITION.name(), ApiRunMode.API_PLAN.name())) {
final int[] sort = {0}; final int[] sort = {0};
Map<TestPlanApiCase, ApiDefinitionExecResult> runMap = (Map<TestPlanApiCase, ApiDefinitionExecResult>) runObj; Map<String, ApiDefinitionExecResult> runMap = (Map<String, ApiDefinitionExecResult>) runObj;
if (envMap == null) {
envMap = new LinkedHashMap<>();
}
String envStr = JSON.toJSONString(envMap);
runMap.forEach((k, v) -> { runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(v.getId(), k.getId(), type, sort[0], executionQueue.getId(), null); ApiExecutionQueueDetail queue = detail(v.getId(), k, type, sort[0], executionQueue.getId(), envStr);
if (sort[0] == 0) { if (sort[0] == 0) {
resQueue.setQueue(queue); resQueue.setQueue(queue);
} }
sort[0]++; sort[0]++;
batchMapper.insert(queue); batchMapper.insert(queue);
detailMap.put(k, queue.getId());
}); });
} else { } else {
Map<String, RunModeDataDTO> runMap = (Map<String, RunModeDataDTO>) runObj; Map<String, RunModeDataDTO> runMap = (Map<String, RunModeDataDTO>) runObj;
@ -86,12 +90,14 @@ public class ApiExecutionQueueService {
} }
sort[0]++; sort[0]++;
batchMapper.insert(queue); batchMapper.insert(queue);
detailMap.put(k, queue.getId());
}); });
} }
sqlSession.flushStatements(); sqlSession.flushStatements();
if (sqlSession != null && sqlSessionFactory != null) { if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
} }
resQueue.setDetailMap(detailMap);
return resQueue; return resQueue;
} }
@ -117,7 +123,7 @@ public class ApiExecutionQueueService {
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample(); ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.setOrderByClause("sort asc"); example.setOrderByClause("sort asc");
example.createCriteria().andQueueIdEqualTo(id); example.createCriteria().andQueueIdEqualTo(id);
List<ApiExecutionQueueDetail> queues = executionQueueDetailMapper.selectByExample(example); List<ApiExecutionQueueDetail> queues = executionQueueDetailMapper.selectByExampleWithBLOBs(example);
if (CollectionUtils.isNotEmpty(queues)) { if (CollectionUtils.isNotEmpty(queues)) {
List<ApiExecutionQueueDetail> list = queues.stream().filter(item -> StringUtils.equals(item.getTestId(), testId)).collect(Collectors.toList()); List<ApiExecutionQueueDetail> list = queues.stream().filter(item -> StringUtils.equals(item.getTestId(), testId)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(list)) { if (CollectionUtils.isNotEmpty(list)) {

View File

@ -6,10 +6,8 @@ import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.scenario.request.BodyFile; import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService; import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil; import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.*;
import io.metersphere.base.domain.JarConfig; import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.domain.Plugin;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper; import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.ApiRunMode; import io.metersphere.commons.constants.ApiRunMode;
@ -43,6 +41,9 @@ public class ApiJmeterFileService {
private TestPlanApiScenarioMapper testPlanApiScenarioMapper; private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource @Resource
private ApiScenarioMapper apiScenarioMapper; private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource @Resource
private EnvironmentGroupProjectService environmentGroupProjectService; private EnvironmentGroupProjectService environmentGroupProjectService;
@ -58,7 +59,7 @@ public class ApiJmeterFileService {
return listBytesToZip(files); return listBytesToZip(files);
} }
public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String reportType) { public byte[] downloadJmeterFiles(String runMode, String remoteTestId, String reportId, String reportType, String queueId) {
Map<String, String> planEnvMap = new HashMap<>(); Map<String, String> planEnvMap = new HashMap<>();
ApiScenarioWithBLOBs scenario = null; ApiScenarioWithBLOBs scenario = null;
if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) { if (StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
@ -76,9 +77,14 @@ public class ApiJmeterFileService {
scenario = apiScenarioMapper.selectByPrimaryKey(planApiScenario.getApiScenarioId()); scenario = apiScenarioMapper.selectByPrimaryKey(planApiScenario.getApiScenarioId());
} }
} }
ApiExecutionQueueDetail detail = executionQueueDetailMapper.selectByPrimaryKey(queueId);
Map<String, String> envMap = new LinkedHashMap<>();
if (detail != null && StringUtils.isNotEmpty(detail.getEvnMap())) {
envMap = JSON.parseObject(detail.getEvnMap(), Map.class);
}
HashTree hashTree; HashTree hashTree;
if (StringUtils.equalsAnyIgnoreCase(runMode, ApiRunMode.DEFINITION.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) { if (StringUtils.equalsAnyIgnoreCase(runMode, ApiRunMode.DEFINITION.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
hashTree = apiScenarioSerialService.generateHashTree(remoteTestId); hashTree = apiScenarioSerialService.generateHashTree(remoteTestId, runMode, envMap);
} else { } else {
if (scenario == null) { if (scenario == null) {
scenario = apiScenarioMapper.selectByPrimaryKey(remoteTestId); scenario = apiScenarioMapper.selectByPrimaryKey(remoteTestId);
@ -86,7 +92,9 @@ public class ApiJmeterFileService {
if (scenario == null) { if (scenario == null) {
MSException.throwException("未找到执行场景。"); MSException.throwException("未找到执行场景。");
} }
if (!StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) { if (envMap != null && !envMap.isEmpty()) {
planEnvMap = envMap;
} else if (!StringUtils.equalsAny(runMode, ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) {
String envType = scenario.getEnvironmentType(); String envType = scenario.getEnvironmentType();
String envJson = scenario.getEnvironmentJson(); String envJson = scenario.getEnvironmentJson();
String envGroupId = scenario.getEnvironmentGroupId(); String envGroupId = scenario.getEnvironmentGroupId();

View File

@ -6,7 +6,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.ApiCaseEditRequest; import io.metersphere.api.dto.ApiCaseEditRequest;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.DeleteCheckResult; import io.metersphere.api.dto.DeleteCheckResult;
import io.metersphere.api.dto.JmxInfoDTO; import io.metersphere.api.dto.JmxInfoDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.datacount.ApiDataCountResult;
@ -16,20 +15,16 @@ import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup; import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.scenario.request.RequestType; import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.exec.api.ApiExecuteService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*; import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.APITestStatus; import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.MsTestElementConstants; import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.TestPlanStatus; import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.OrderRequest; import io.metersphere.controller.request.OrderRequest;
import io.metersphere.controller.request.ResetOrderRequest; import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.dto.MsExecResponseDTO;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil; import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.DetailColumn;
@ -83,8 +78,6 @@ public class ApiTestCaseService {
@Resource @Resource
private ApiDefinitionMapper apiDefinitionMapper; private ApiDefinitionMapper apiDefinitionMapper;
@Resource @Resource
private ApiExecuteService apiCaseExecuteService;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper; private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource @Resource
private EsbApiParamService esbApiParamService; private EsbApiParamService esbApiParamService;
@ -746,47 +739,6 @@ public class ApiTestCaseService {
return ids; return ids;
} }
public void batchRun(ApiCaseRunRequest request) {
apiCaseExecuteService.run(request);
}
public MsExecResponseDTO jenkinsRun(RunCaseRequest request) {
ApiTestCaseWithBLOBs caseWithBLOBs = null;
if (request.getBloBs() == null) {
caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
if (caseWithBLOBs == null) {
return null;
}
request.setBloBs(caseWithBLOBs);
} else {
caseWithBLOBs = request.getBloBs();
}
if (caseWithBLOBs == null) {
return null;
}
if (StringUtils.isBlank(request.getEnvironmentId())) {
request.setEnvironmentId(extApiTestCaseMapper.getApiCaseEnvironment(request.getCaseId()));
}
//提前生成报告
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.add(caseWithBLOBs.getId(), APITestStatus.Running.name(), request.getReportId());
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(ApiRunMode.JENKINS.name());
report.setType(ApiRunMode.JENKINS.name());
apiDefinitionExecResultMapper.insert(report);
//更新接口案例的最后执行状态等信息
caseWithBLOBs.setLastResultId(report.getId());
caseWithBLOBs.setUpdateTime(System.currentTimeMillis());
caseWithBLOBs.setStatus(APITestStatus.Running.name());
apiTestCaseMapper.updateByPrimaryKey(caseWithBLOBs);
request.setReport(report);
if (StringUtils.isEmpty(request.getRunMode())) {
request.setRunMode(ApiRunMode.DEFINITION.name());
}
return apiCaseExecuteService.exec(request);
}
public String getExecResult(String id) { public String getExecResult(String id) {
String status = extApiDefinitionExecResultMapper.selectExecResult(id); String status = extApiDefinitionExecResultMapper.selectExecResult(id);
return status; return status;

View File

@ -9,7 +9,7 @@ import io.metersphere.api.dto.definition.ApiTestCaseDTO;
import io.metersphere.api.dto.definition.ApiTestCaseRequest; import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest; import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO; import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.exec.api.TestPlanApiExecuteService; import io.metersphere.api.exec.api.ApiCaseExecuteService;
import io.metersphere.api.service.ApiDefinitionExecResultService; import io.metersphere.api.service.ApiDefinitionExecResultService;
import io.metersphere.api.service.ApiTestCaseService; import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
@ -60,7 +60,7 @@ public class TestPlanApiCaseService {
@Resource @Resource
ApiTestCaseMapper apiTestCaseMapper; ApiTestCaseMapper apiTestCaseMapper;
@Resource @Resource
private TestPlanApiExecuteService testPlanApiCaseExecuteService; private ApiCaseExecuteService testPlanApiCaseExecuteService;
@Resource @Resource
SqlSessionFactory sqlSessionFactory; SqlSessionFactory sqlSessionFactory;
@Resource @Resource

View File

@ -282,7 +282,7 @@
<batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr" <batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"
:dialog-title="$t('test_track.case.batch_edit_case')"/> :dialog-title="$t('test_track.case.batch_edit_case')"/>
<batch-move @refresh="search" @moveSave="moveSave" ref="testBatchMove"/> <batch-move @refresh="search" @moveSave="moveSave" ref="testBatchMove"/>
<ms-run-mode @handleRunBatch="handleRunBatch" ref="runMode"/> <ms-run-mode @handleRunBatch="handleRunBatch" :request="runRequest" ref="runMode"/>
<ms-run :debug="true" :environment="projectEnvMap" @runRefresh="runRefresh" :reportId="reportId" :saved="true" <ms-run :debug="true" :environment="projectEnvMap" @runRefresh="runRefresh" :reportId="reportId" :saved="true"
:environment-type="environmentType" :environment-group-id="envGroupId" :environment-type="environmentType" :environment-group-id="envGroupId"
:run-data="debugData" ref="runTest"/> :run-data="debugData" ref="runTest"/>
@ -553,7 +553,8 @@ export default {
graphData: {}, graphData: {},
environmentType: "", environmentType: "",
envGroupId: "", envGroupId: "",
apiscenariofilters:{}, apiscenariofilters: {},
runRequest: {},
}; };
}, },
created() { created() {
@ -880,6 +881,14 @@ export default {
param.condition = this.condition; param.condition = this.condition;
}, },
handleBatchExecute() { handleBatchExecute() {
let run = {};
run.id = getUUID();
//
let ids = this.orderBySelectRows();
run.ids = ids;
run.projectId = this.projectId;
run.condition = this.condition;
this.runRequest = run;
this.$refs.runMode.open(); this.$refs.runMode.open();
}, },

View File

@ -2,9 +2,22 @@
<el-dialog <el-dialog
destroy-on-close destroy-on-close
:title="$t('load_test.runtime_config')" :title="$t('load_test.runtime_config')"
width="450px" width="550px"
:visible.sync="runModeVisible" :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"
ref="envPopover" class="env-popover"/>
</div>
<div> <div>
<span class="ms-mode-span">{{ $t("run_mode.title") }}</span> <span class="ms-mode-span">{{ $t("run_mode.title") }}</span>
<el-radio-group v-model="runConfig.mode" @change="changeMode"> <el-radio-group v-model="runConfig.mode" @change="changeMode">
@ -58,27 +71,39 @@
<script> <script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter"; import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import {ENV_TYPE} from "@/common/js/constants";
import {strMapToObj} from "@/common/js/utils";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
export default { export default {
name: "RunMode", name: "RunMode",
components: {MsDialogFooter}, components: {MsDialogFooter, EnvPopover},
data() { data() {
return { return {
runModeVisible: false, runModeVisible: false,
testType: null, testType: null,
resourcePools: [], resourcePools: [],
runConfig: { runConfig: {
reportName: "",
mode: "serial", mode: "serial",
reportType: "iddReport", reportType: "iddReport",
reportName: "", onSampleError: false,
runWithinResourcePool: false, runWithinResourcePool: false,
resourcePoolId: null, resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
}, },
projectEnvListMap: {},
projectList: [],
projectIds: new Set(),
}; };
}, },
watch:{ props: ['request'],
'runConfig.runWithinResourcePool'(){
if(!this.runConfig.runWithinResourcePool){ watch: {
'runConfig.runWithinResourcePool'() {
if (!this.runConfig.runWithinResourcePool) {
this.runConfig = { this.runConfig = {
mode: this.runConfig.mode, mode: this.runConfig.mode,
reportType: "iddReport", reportType: "iddReport",
@ -93,6 +118,7 @@ export default {
open() { open() {
this.runModeVisible = true; this.runModeVisible = true;
this.getResourcePools(); this.getResourcePools();
this.getWsProjects();
}, },
changeMode() { changeMode() {
this.runConfig.runWithinResourcePool = false; this.runConfig.runWithinResourcePool = false;
@ -110,6 +136,11 @@ export default {
}; };
this.runModeVisible = false; this.runModeVisible = false;
}, },
getWsProjects() {
this.$get("/project/listAll", res => {
this.projectList = res.data;
})
},
handleRunBatch() { handleRunBatch() {
if (this.runConfig.mode === 'serial' && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") { if (this.runConfig.mode === 'serial' && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
this.$warning(this.$t('commons.input_name')); this.$warning(this.$t('commons.input_name'));
@ -123,6 +154,25 @@ export default {
this.resourcePools = response.data; this.resourcePools = response.data;
}); });
}, },
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
showPopover() {
this.projectIds.clear();
let url = "/api/automation/env";
this.$post(url, this.request, res => {
let data = res.data;
if (data) {
for (let d in data) {
this.projectIds.add(data[d]);
}
}
this.$refs.envPopover.openEnvSelect();
});
},
}, },
}; };
</script> </script>

View File

@ -0,0 +1,185 @@
<template>
<el-dialog
destroy-on-close
:title="$t('load_test.runtime_config')"
width="550px"
: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"
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" v-if="runConfig.mode === 'serial'">
<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-checkbox v-model="runConfig.onSampleError">{{ $t("api_test.fail_to_stop") }}</el-checkbox>
</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"
:value="item.id">
</el-option>
</el-select>
</div>
</el-col>
</el-row>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'parallel'">
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<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>
</el-col>
</el-row>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
import {strMapToObj} from "@/common/js/utils";
import {ENV_TYPE} from "@/common/js/constants";
import {parseEnvironment} from "@/business/components/api/test/model/EnvironmentModel";
export default {
name: "MsApiCaseRunModeWithEnv",
components: {EnvPopover, MsDialogFooter},
data() {
return {
runModeVisible: false,
resourcePools: [],
runConfig: {
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;
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
};
this.runModeVisible = false;
},
handleRunBatch() {
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
getWsProjects() {
this.$get("/project/listAll", res => {
this.projectList = res.data;
})
},
getEnvironments() {
return new Promise((resolve) => {
if (this.projectId) {
this.$get('/api/environment/list/' + this.projectId, 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;
}
</style>

View File

@ -218,10 +218,10 @@
<!--高级搜索--> <!--高级搜索-->
<ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="initTable"/> <ms-table-adv-search-bar :condition.sync="condition" :showLink="false" ref="searchBar" @search="initTable"/>
<api-case-batch-run :project-id="projectId" @batchRun="runBatch" ref="batchRun"/>
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false"/>
<ms-api-case-run-mode-with-env @handleRunBatch="runBatch" ref="batchRun" :project-id="projectId"/>
<el-dialog :close-on-click-modal="false" :title="$t('test_track.plan_view.test_result')" width="60%" <el-dialog :close-on-click-modal="false" :title="$t('test_track.plan_view.test_result')" width="60%"
:visible.sync="resVisible" class="api-import" destroy-on-close @close="resVisible=false"> :visible.sync="resVisible" class="api-import" destroy-on-close @close="resVisible=false">
<ms-request-result-tail :response="response" ref="debugResult"/> <ms-request-result-tail :response="response" ref="debugResult"/>
@ -244,6 +244,8 @@ import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn"; import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit"; import MsBatchEdit from "../basis/BatchEdit";
import MsApiCaseRunModeWithEnv from "./ApiCaseRunModeWithEnv";
import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData"; import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData";
import {getBodyUploadFiles, getCurrentProjectID, getUUID, hasLicense, strMapToObj} from "@/common/js/utils"; import {getBodyUploadFiles, getCurrentProjectID, getUUID, hasLicense, strMapToObj} from "@/common/js/utils";
@ -297,8 +299,9 @@ export default {
MsTable, MsTable,
MsTableColumn, MsTableColumn,
MsRequestResultTail, MsRequestResultTail,
MsApiCaseRunModeWithEnv,
PlanStatusTableItem: () => import("../../../../track/common/tableItems/plan/PlanStatusTableItem"), PlanStatusTableItem: () => import("../../../../track/common/tableItems/plan/PlanStatusTableItem"),
MsTaskCenter: () => import("../../../../task/TaskCenter"), MsTaskCenter: () => import("@/business/components/task/TaskCenter"),
}, },
data() { data() {
return { return {
@ -405,6 +408,7 @@ export default {
timeoutIndex: 0, timeoutIndex: 0,
versionFilters: [], versionFilters: [],
versionName: '', versionName: '',
runCaseIds: []
}; };
}, },
props: { props: {
@ -559,17 +563,16 @@ export default {
return this.$t('api_test.home_page.detail_card.unexecute'); return this.$t('api_test.home_page.detail_card.unexecute');
} }
}, },
handleRunBatch() { handleRunBatch() {
this.$refs.batchRun.open(); this.$refs.batchRun.open();
}, },
runBatch(environment) { runBatch(config) {
let obj = {}; let obj = {};
obj.projectId = this.projectId; obj.projectId = this.projectId;
obj.selectAllDate = this.selectAll; obj.selectAllDate = this.selectAll;
obj.unSelectIds = this.unSelection; obj.unSelectIds = this.unSelection;
obj.ids = Array.from(this.selectRows).map(row => row.id); obj.ids = Array.from(this.selectRows).map(row => row.id);
obj.environmentId = environment.id; obj.config = config;
obj.condition = this.condition; obj.condition = this.condition;
obj.condition.status = ""; obj.condition.status = "";
this.$post('/api/testcase/batch/run', obj, () => { this.$post('/api/testcase/batch/run', obj, () => {
@ -580,7 +583,7 @@ export default {
} else { } else {
this.$store.state.currentApiCase = {case: true}; this.$store.state.currentApiCase = {case: true};
} }
this.search(); this.$refs.taskCenter.open();
}); });
}, },
customHeader() { customHeader() {