fix (接口自动化): 并发执行优化
This commit is contained in:
parent
59b1faec6e
commit
4443a88dca
|
@ -1,10 +1,13 @@
|
|||
package io.metersphere.api.dto;
|
||||
|
||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class RunModeDataDTO {
|
||||
|
@ -17,6 +20,11 @@ public class RunModeDataDTO {
|
|||
//
|
||||
private String apiCaseId;
|
||||
|
||||
private ApiScenarioWithBLOBs scenario;
|
||||
private Map<String, String> planEnvMap;
|
||||
public RunModeDataDTO(){
|
||||
|
||||
}
|
||||
public RunModeDataDTO(String testId, String apiCaseId) {
|
||||
this.testId = testId;
|
||||
this.apiCaseId = apiCaseId;
|
||||
|
@ -36,4 +44,10 @@ public class RunModeDataDTO {
|
|||
this.hashTree = hashTree;
|
||||
this.report = report;
|
||||
}
|
||||
|
||||
public RunModeDataDTO(HashTree hashTree, APIScenarioReportResult report, String testId) {
|
||||
this.hashTree = hashTree;
|
||||
this.report = report;
|
||||
this.testId = testId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import io.metersphere.api.service.MsResultService;
|
|||
import io.metersphere.api.service.TestResultService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Comparator;
|
||||
|
@ -18,6 +20,8 @@ import java.util.Map;
|
|||
* 获取结果和数据库操作分离
|
||||
* 减少占用的数据库连接
|
||||
*/
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class APIBackendListenerHandler {
|
||||
|
||||
@Resource
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
package io.metersphere.api.jmeter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import io.metersphere.api.dto.JvmInfoDTO;
|
||||
import io.metersphere.api.dto.RunRequest;
|
||||
import io.metersphere.api.dto.automation.ExecuteType;
|
||||
import io.metersphere.api.dto.automation.RunModeConfig;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.service.ApiScenarioReportService;
|
||||
import io.metersphere.base.domain.TestResource;
|
||||
import io.metersphere.base.domain.TestResourcePool;
|
||||
import io.metersphere.base.mapper.TestResourcePoolMapper;
|
||||
import io.metersphere.commons.constants.ApiRunMode;
|
||||
import io.metersphere.commons.constants.ResourcePoolTypeEnum;
|
||||
import io.metersphere.commons.constants.TriggerMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.*;
|
||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.config.JmeterProperties;
|
||||
import io.metersphere.dto.BaseSystemConfigDTO;
|
||||
import io.metersphere.dto.NodeDTO;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import io.metersphere.performance.engine.Engine;
|
||||
import io.metersphere.performance.engine.EngineFactory;
|
||||
import io.metersphere.service.SystemParameterService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
|
@ -37,16 +35,16 @@ import org.apache.jmeter.util.JMeterUtils;
|
|||
import org.apache.jmeter.visualizers.backend.BackendListener;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -55,11 +53,9 @@ public class JMeterService {
|
|||
@Resource
|
||||
private JmeterProperties jmeterProperties;
|
||||
@Resource
|
||||
ResourcePoolCalculation resourcePoolCalculation;
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
@Resource
|
||||
private TestResourcePoolMapper testResourcePoolMapper;
|
||||
@Resource
|
||||
private KafkaTemplate<String, Object> kafkaTemplate;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
@ -145,7 +141,7 @@ public class JMeterService {
|
|||
}
|
||||
|
||||
public void runTest(String testId, String reportId, String runMode,
|
||||
String testPlanScenarioId, RunModeConfig config) {
|
||||
String testPlanScenarioId, RunModeConfig config, HashTree hashTree) {
|
||||
// 获取可以执行的资源池
|
||||
String resourcePoolId = config.getResourcePoolId();
|
||||
BaseSystemConfigDTO baseInfo = config.getBaseInfo();
|
||||
|
@ -179,33 +175,8 @@ public class JMeterService {
|
|||
MSException.throwException(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
TestResource testResource = null;
|
||||
List<JvmInfoDTO> testResources = config.getTestResources();
|
||||
if (CollectionUtils.isEmpty(testResources)) {
|
||||
testResource = resourcePoolCalculation.getPool(resourcePoolId);
|
||||
} else {
|
||||
int index = (int) (Math.random() * testResources.size());
|
||||
JvmInfoDTO jvmInfoDTO = testResources.get(index);
|
||||
testResource = testResources.get(index).getTestResource();
|
||||
}
|
||||
String configuration = testResource.getConfiguration();
|
||||
NodeDTO node = JSON.parseObject(configuration, NodeDTO.class);
|
||||
String nodeIp = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
try {
|
||||
String uri = String.format(BASE_URL + "/jmeter/api/start", nodeIp, port);
|
||||
ResponseEntity<String> resultEntity = restTemplate.postForEntity(uri, runRequest, String.class);
|
||||
String result = resultEntity.getBody(); // this.send(uri, runRequest);
|
||||
if (StringUtils.isEmpty(result) || !StringUtils.equals("SUCCESS", result)) {
|
||||
// 清理零时报告
|
||||
ApiScenarioReportService apiScenarioReportService = CommonBeanFactory.getBean(ApiScenarioReportService.class);
|
||||
apiScenarioReportService.delete(reportId);
|
||||
MSException.throwException("执行失败:" + result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
MSException.throwException(runRequest.getReportId() + ":" + e.getMessage());
|
||||
}
|
||||
runRequest.setJmx(new MsTestPlan().getJmx(hashTree));
|
||||
kafkaTemplate.send(MsKafkaListener.EXEC_TOPIC, JSON.toJSONString(runRequest));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ import javax.annotation.Resource;
|
|||
@Service
|
||||
public class MsKafkaListener {
|
||||
public static final String TOPICS = "ms-api-exec-topic";
|
||||
public final static String EXEC_TOPIC = "ms-automation-exec-topic";
|
||||
|
||||
public static final String CONSUME_ID = "ms-api-exec-consume";
|
||||
|
||||
@KafkaListener(id = CONSUME_ID, topics = TOPICS, groupId = "${spring.kafka.consumer.group-id}")
|
||||
|
|
|
@ -25,7 +25,6 @@ import io.metersphere.api.jmeter.MessageCache;
|
|||
import io.metersphere.api.jmeter.ReportCounter;
|
||||
import io.metersphere.api.jmeter.ResourcePoolCalculation;
|
||||
import io.metersphere.api.parse.ApiImportParser;
|
||||
import io.metersphere.api.service.task.ParallelScenarioExecTask;
|
||||
import io.metersphere.api.service.task.SerialScenarioExecTask;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.*;
|
||||
|
@ -1052,7 +1051,11 @@ public class ApiAutomationService {
|
|||
}
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
executeQueue.put(report.getId(), new RunModeDataDTO(item.getId(), report));
|
||||
RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
|
||||
runModeDataDTO.setPlanEnvMap(planEnvMap);
|
||||
runModeDataDTO.setReport(report);
|
||||
runModeDataDTO.setScenario(item);
|
||||
executeQueue.put(report.getId(), runModeDataDTO);
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(item, reportId, planEnvMap);
|
||||
|
@ -1088,108 +1091,130 @@ public class ApiAutomationService {
|
|||
}
|
||||
}
|
||||
// 开始执行
|
||||
this.run(executeQueue, request, serialReportId);
|
||||
if (executeQueue != null && executeQueue.size() > 0) {
|
||||
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
|
||||
this.serial(executeQueue, request, serialReportId);
|
||||
} else {
|
||||
this.parallel(executeQueue, request);
|
||||
}
|
||||
}
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
private void run(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId) {
|
||||
// 开始选择执行模式
|
||||
if (executeQueue != null && executeQueue.size() > 0) {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(6);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
||||
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
|
||||
// 非集合报告,先生成执行队列
|
||||
if (StringUtils.isEmpty(serialReportId)) {
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
|
||||
report.setStatus(APITestStatus.Waiting.name());
|
||||
batchMapper.insert(report);
|
||||
/**
|
||||
* 串行
|
||||
*
|
||||
* @param executeQueue
|
||||
* @param request
|
||||
* @param serialReportId
|
||||
*/
|
||||
private void serial(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request, String serialReportId) {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(executeQueue.size());
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
||||
// 非集合报告,先生成执行队列
|
||||
if (StringUtils.isEmpty(serialReportId)) {
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
|
||||
report.setStatus(APITestStatus.Waiting.name());
|
||||
batchMapper.insert(report);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
// 开始串行执行
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<String> reportIds = new LinkedList<>();
|
||||
//记录串行执行中的环境参数,供下一个场景执行时使用。 <envId,<key,data>>
|
||||
Map<String, Map<String, String>> execute_env_param_datas = new LinkedHashMap<>();
|
||||
ApiTestEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||
HashTreeUtil hashTreeUtil = new HashTreeUtil();
|
||||
for (String key : executeQueue.keySet()) {
|
||||
reportIds.add(key);
|
||||
APIScenarioReportResult report = executeQueue.get(key).getReport();
|
||||
if (StringUtils.isNotEmpty(serialReportId)) {
|
||||
report.setExecuteType(ExecuteType.Marge.name());
|
||||
apiScenarioReportMapper.insert(report);
|
||||
} else {
|
||||
report.setStatus(APITestStatus.Running.name());
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
apiScenarioReportMapper.updateByPrimaryKey(report);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
// 开始串行执行
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<String> reportIds = new LinkedList<>();
|
||||
//记录串行执行中的环境参数,供下一个场景执行时使用。 <envId,<key,data>>
|
||||
Map<String, Map<String, String>> execute_env_param_datas = new LinkedHashMap<>();
|
||||
ApiTestEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
|
||||
HashTreeUtil hashTreeUtil = new HashTreeUtil();
|
||||
for (String key : executeQueue.keySet()) {
|
||||
reportIds.add(key);
|
||||
APIScenarioReportResult report = executeQueue.get(key).getReport();
|
||||
if (StringUtils.isNotEmpty(serialReportId)) {
|
||||
report.setExecuteType(ExecuteType.Marge.name());
|
||||
apiScenarioReportMapper.insert(report);
|
||||
} else {
|
||||
report.setStatus(APITestStatus.Running.name());
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
apiScenarioReportMapper.updateByPrimaryKey(report);
|
||||
}
|
||||
try {
|
||||
if (!execute_env_param_datas.isEmpty()) {
|
||||
try {
|
||||
HashTree hashTree = executeQueue.get(key).getHashTree();
|
||||
hashTreeUtil.setEnvParamsMapToHashTree(hashTree, execute_env_param_datas);
|
||||
executeQueue.get(key).setHashTree(hashTree);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
Future<ApiScenarioReport> future = executorService.submit(new SerialScenarioExecTask(jMeterService, apiScenarioReportMapper, executeQueue.get(key), request));
|
||||
ApiScenarioReport scenarioReport = future.get();
|
||||
// 如果开启失败结束执行,则判断返回结果状态
|
||||
if (request.getConfig().isOnSampleError()) {
|
||||
if (scenarioReport == null || !scenarioReport.getStatus().equals("Success")) {
|
||||
reportIds.remove(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!execute_env_param_datas.isEmpty()) {
|
||||
HashTree hashTree = executeQueue.get(key).getHashTree();
|
||||
hashTreeUtil.setEnvParamsMapToHashTree(hashTree, execute_env_param_datas);
|
||||
executeQueue.get(key).setHashTree(hashTree);
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Map<String, String>> envParamsMap = hashTreeUtil.getEnvParamsDataByHashTree(executeQueue.get(key).getHashTree(), apiTestEnvironmentService);
|
||||
execute_env_param_datas = hashTreeUtil.mergeParamDataMap(execute_env_param_datas, envParamsMap);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
HashTree hashTree = generateHashTree(executeQueue.get(key).getScenario(), key, executeQueue.get(key).getPlanEnvMap());
|
||||
executeQueue.get(key).setHashTree(hashTree);
|
||||
}
|
||||
Future<ApiScenarioReport> future = executorService.submit(new SerialScenarioExecTask(jMeterService, apiScenarioReportMapper, executeQueue.get(key), request));
|
||||
ApiScenarioReport scenarioReport = future.get();
|
||||
// 如果开启失败结束执行,则判断返回结果状态
|
||||
if (request.getConfig().isOnSampleError()) {
|
||||
if (scenarioReport == null || !scenarioReport.getStatus().equals("Success")) {
|
||||
reportIds.remove(key);
|
||||
LogUtil.error("执行终止:" + e.getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 清理未执行的队列
|
||||
if (reportIds.size() < executeQueue.size()) {
|
||||
List<String> removeList = executeQueue.entrySet().stream()
|
||||
.filter(map -> !reportIds.contains(map.getKey()))
|
||||
.map(map -> map.getKey()).collect(Collectors.toList());
|
||||
ApiScenarioReportExample example = new ApiScenarioReportExample();
|
||||
example.createCriteria().andIdIn(removeList);
|
||||
apiScenarioReportMapper.deleteByExample(example);
|
||||
}
|
||||
// 更新集成报告
|
||||
if (StringUtils.isNotEmpty(serialReportId)) {
|
||||
apiScenarioReportService.margeReport(serialReportId, reportIds);
|
||||
executeQueue.clear();
|
||||
}
|
||||
|
||||
Map<String, Map<String, String>> envParamsMap = hashTreeUtil.getEnvParamsDataByHashTree(executeQueue.get(key).getHashTree(), apiTestEnvironmentService);
|
||||
execute_env_param_datas = hashTreeUtil.mergeParamDataMap(execute_env_param_datas, envParamsMap);
|
||||
} catch (Exception e) {
|
||||
reportIds.remove(key);
|
||||
LogUtil.error("执行终止:" + e.getMessage());
|
||||
break;
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
} else {
|
||||
// 开始并发执行
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
//存储报告
|
||||
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
|
||||
batchMapper.insert(report);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
executorService.submit(new ParallelScenarioExecTask(jMeterService, executeQueue.get(reportId), request));
|
||||
// 清理未执行的队列
|
||||
if (reportIds.size() < executeQueue.size()) {
|
||||
List<String> removeList = executeQueue.entrySet().stream().filter(map -> !reportIds.contains(map.getKey()))
|
||||
.map(map -> map.getKey()).collect(Collectors.toList());
|
||||
ApiScenarioReportExample example = new ApiScenarioReportExample();
|
||||
example.createCriteria().andIdIn(removeList);
|
||||
apiScenarioReportMapper.deleteByExample(example);
|
||||
}
|
||||
// 更新集成报告
|
||||
if (StringUtils.isNotEmpty(serialReportId)) {
|
||||
apiScenarioReportService.margeReport(serialReportId, reportIds);
|
||||
executeQueue.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 并行
|
||||
*
|
||||
* @param executeQueue
|
||||
* @param request
|
||||
*/
|
||||
private void parallel(Map<String, RunModeDataDTO> executeQueue, RunScenarioRequest request) {
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioReportMapper batchMapper = sqlSession.getMapper(ApiScenarioReportMapper.class);
|
||||
// 开始并发执行
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
//存储报告
|
||||
APIScenarioReportResult report = executeQueue.get(reportId).getReport();
|
||||
batchMapper.insert(report);
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
for (String reportId : executeQueue.keySet()) {
|
||||
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
|
||||
HashTree hashTree = generateHashTree(executeQueue.get(reportId).getScenario(), reportId, executeQueue.get(reportId).getPlanEnvMap());
|
||||
jMeterService.runTest(executeQueue.get(reportId).getScenario().getId(), reportId, request.getRunMode(), request.getPlanScenarioId(), request.getConfig(), hashTree);
|
||||
} else {
|
||||
jMeterService.runLocal(reportId, executeQueue.get(reportId).getHashTree(),
|
||||
TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
|
||||
}
|
||||
}
|
||||
executeQueue.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -689,7 +689,7 @@ public class ApiDefinitionService {
|
|||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
RunModeConfig configs = request.getConfig();
|
||||
configs.setBaseInfo(CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo());
|
||||
jMeterService.runTest(request.getId(), request.getId(), runMode, null, configs);
|
||||
jMeterService.runTest(request.getId(), request.getId(), runMode, null, configs, hashTree);
|
||||
} else {
|
||||
jMeterService.runLocal(request.getId(), hashTree, request.getReportId(), runMode);
|
||||
}
|
||||
|
|
|
@ -443,47 +443,50 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
|
||||
public void margeReport(String reportId, List<String> reportIds) {
|
||||
// 合并生成一份报告
|
||||
if (CollectionUtils.isNotEmpty(reportIds)) {
|
||||
TestResult testResult = new TestResult();
|
||||
testResult.setTestId(UUID.randomUUID().toString());
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
|
||||
// 要合并的报告已经被删除
|
||||
if (report == null) {
|
||||
MessageCache.cache.remove(reportId);
|
||||
} else {
|
||||
// 合并生成一份报告
|
||||
if (CollectionUtils.isNotEmpty(reportIds)) {
|
||||
TestResult testResult = new TestResult();
|
||||
testResult.setTestId(UUID.randomUUID().toString());
|
||||
|
||||
StringBuilder idStr = new StringBuilder();
|
||||
reportIds.forEach(item -> {
|
||||
idStr.append("\"").append(item).append("\"").append(",");
|
||||
});
|
||||
List<ApiScenarioReportDetail> details = extApiScenarioReportDetailMapper.selectByIds(idStr.toString().substring(0, idStr.toString().length() - 1), "\"" + StringUtils.join(reportIds, ",") + "\"");
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// 记录单场景通过率
|
||||
Map<String, String> passRateMap = new HashMap<>();
|
||||
for (ApiScenarioReportDetail detail : details) {
|
||||
try {
|
||||
String content = new String(detail.getContent(), StandardCharsets.UTF_8);
|
||||
TestResult scenarioResult = mapper.readValue(content, new TypeReference<TestResult>() {
|
||||
});
|
||||
testResult.getScenarios().addAll(scenarioResult.getScenarios());
|
||||
testResult.setTotal(testResult.getTotal() + scenarioResult.getTotal());
|
||||
testResult.setError(testResult.getError() + scenarioResult.getError());
|
||||
testResult.setPassAssertions(testResult.getPassAssertions() + scenarioResult.getPassAssertions());
|
||||
testResult.setSuccess(testResult.getSuccess() + scenarioResult.getSuccess());
|
||||
testResult.setTotalAssertions(scenarioResult.getTotalAssertions() + testResult.getTotalAssertions());
|
||||
testResult.setScenarioTotal(testResult.getScenarioTotal() + scenarioResult.getScenarioTotal());
|
||||
testResult.setScenarioSuccess(testResult.getScenarioSuccess() + scenarioResult.getScenarioSuccess());
|
||||
testResult.setScenarioError(testResult.getScenarioError() + scenarioResult.getScenarioError());
|
||||
testResult.setConsole(scenarioResult.getConsole());
|
||||
testResult.setScenarioStepError(scenarioResult.getScenarioStepError() + testResult.getScenarioStepError());
|
||||
testResult.setScenarioStepSuccess(scenarioResult.getScenarioStepSuccess() + testResult.getScenarioStepSuccess());
|
||||
testResult.setScenarioStepTotal(scenarioResult.getScenarioStepTotal() + testResult.getScenarioStepTotal());
|
||||
String passRate = new DecimalFormat("0%").format((float) scenarioResult.getSuccess() / (scenarioResult.getSuccess() + scenarioResult.getError()));
|
||||
passRateMap.put(detail.getReportId(), passRate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
StringBuilder idStr = new StringBuilder();
|
||||
reportIds.forEach(item -> {
|
||||
idStr.append("\"").append(item).append("\"").append(",");
|
||||
});
|
||||
List<ApiScenarioReportDetail> details = extApiScenarioReportDetailMapper.selectByIds(idStr.toString().substring(0, idStr.toString().length() - 1), "\"" + StringUtils.join(reportIds, ",") + "\"");
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
// 记录单场景通过率
|
||||
Map<String, String> passRateMap = new HashMap<>();
|
||||
for (ApiScenarioReportDetail detail : details) {
|
||||
try {
|
||||
String content = new String(detail.getContent(), StandardCharsets.UTF_8);
|
||||
TestResult scenarioResult = mapper.readValue(content, new TypeReference<TestResult>() {
|
||||
});
|
||||
testResult.getScenarios().addAll(scenarioResult.getScenarios());
|
||||
testResult.setTotal(testResult.getTotal() + scenarioResult.getTotal());
|
||||
testResult.setError(testResult.getError() + scenarioResult.getError());
|
||||
testResult.setPassAssertions(testResult.getPassAssertions() + scenarioResult.getPassAssertions());
|
||||
testResult.setSuccess(testResult.getSuccess() + scenarioResult.getSuccess());
|
||||
testResult.setTotalAssertions(scenarioResult.getTotalAssertions() + testResult.getTotalAssertions());
|
||||
testResult.setScenarioTotal(testResult.getScenarioTotal() + scenarioResult.getScenarioTotal());
|
||||
testResult.setScenarioSuccess(testResult.getScenarioSuccess() + scenarioResult.getScenarioSuccess());
|
||||
testResult.setScenarioError(testResult.getScenarioError() + scenarioResult.getScenarioError());
|
||||
testResult.setConsole(scenarioResult.getConsole());
|
||||
testResult.setScenarioStepError(scenarioResult.getScenarioStepError() + testResult.getScenarioStepError());
|
||||
testResult.setScenarioStepSuccess(scenarioResult.getScenarioStepSuccess() + testResult.getScenarioStepSuccess());
|
||||
testResult.setScenarioStepTotal(scenarioResult.getScenarioStepTotal() + testResult.getScenarioStepTotal());
|
||||
String passRate = new DecimalFormat("0%").format((float) scenarioResult.getSuccess() / (scenarioResult.getSuccess() + scenarioResult.getError()));
|
||||
passRateMap.put(detail.getReportId(), passRate);
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
|
||||
if (report != null) {
|
||||
report.setExecuteType(ExecuteType.Saved.name());
|
||||
report.setStatus(testResult.getError() > 0 ? "Error" : "Success");
|
||||
if (StringUtils.isNotEmpty(report.getTriggerMode()) && report.getTriggerMode().equals("CASE")) {
|
||||
|
@ -497,28 +500,28 @@ public class ApiScenarioReportService {
|
|||
detail.setReportId(report.getId());
|
||||
detail.setProjectId(report.getProjectId());
|
||||
apiScenarioReportDetailMapper.insert(detail);
|
||||
// 更新场景状态
|
||||
if (CollectionUtils.isNotEmpty(reportIds)) {
|
||||
ApiScenarioReportExample scenarioReportExample = new ApiScenarioReportExample();
|
||||
scenarioReportExample.createCriteria().andIdIn(reportIds);
|
||||
List<ApiScenarioReport> reports = apiScenarioReportMapper.selectByExampleWithBLOBs(scenarioReportExample);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioMapper scenarioReportMapper = sqlSession.getMapper(ApiScenarioMapper.class);
|
||||
reports.forEach(apiScenarioReport -> {
|
||||
ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs();
|
||||
scenario.setId(apiScenarioReport.getDescription());
|
||||
scenario.setLastResult(StringUtils.equals("Error", apiScenarioReport.getStatus()) ? "Fail" : apiScenarioReport.getStatus());
|
||||
scenario.setPassRate(passRateMap.get(apiScenarioReport.getId()));
|
||||
scenario.setReportId(report.getId());
|
||||
scenarioReportMapper.updateByPrimaryKeySelective(scenario);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
passRateMap.clear();
|
||||
}
|
||||
// 更新场景状态
|
||||
if (CollectionUtils.isNotEmpty(reportIds)) {
|
||||
ApiScenarioReportExample scenarioReportExample = new ApiScenarioReportExample();
|
||||
scenarioReportExample.createCriteria().andIdIn(reportIds);
|
||||
List<ApiScenarioReport> reports = apiScenarioReportMapper.selectByExampleWithBLOBs(scenarioReportExample);
|
||||
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
|
||||
ApiScenarioMapper scenarioReportMapper = sqlSession.getMapper(ApiScenarioMapper.class);
|
||||
reports.forEach(apiScenarioReport -> {
|
||||
ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs();
|
||||
scenario.setId(apiScenarioReport.getDescription());
|
||||
scenario.setLastResult(StringUtils.equals("Error", apiScenarioReport.getStatus()) ? "Fail" : apiScenarioReport.getStatus());
|
||||
scenario.setPassRate(passRateMap.get(apiScenarioReport.getId()));
|
||||
scenario.setReportId(report.getId());
|
||||
scenarioReportMapper.updateByPrimaryKeySelective(scenario);
|
||||
});
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
// 清理其他报告保留一份合并后的报告
|
||||
passRateMap.clear();
|
||||
deleteByIds(reportIds);
|
||||
}
|
||||
// 清理其他报告保留一份合并后的报告
|
||||
deleteByIds(reportIds);
|
||||
}
|
||||
|
||||
private void counter(TestResult result) {
|
||||
|
@ -592,14 +595,14 @@ public class ApiScenarioReportService {
|
|||
sendNotice(scenario);
|
||||
}
|
||||
lastReport = report;
|
||||
}
|
||||
if (report.getExecuteType().equals(ExecuteType.Marge.name())) {
|
||||
Object obj = MessageCache.cache.get(report.getScenarioId());
|
||||
if (obj != null) {
|
||||
ReportCounter counter = (ReportCounter) obj;
|
||||
counter.setNumber(counter.getNumber() + 1);
|
||||
System.out.println("得到统计数量:" + counter.getNumber());
|
||||
MessageCache.cache.put(report.getScenarioId(), counter);
|
||||
if (report.getExecuteType().equals(ExecuteType.Marge.name())) {
|
||||
Object obj = MessageCache.cache.get(report.getScenarioId());
|
||||
if (obj != null) {
|
||||
ReportCounter counter = (ReportCounter) obj;
|
||||
counter.setNumber(counter.getNumber() + 1);
|
||||
System.out.println("得到统计数量:" + counter.getNumber());
|
||||
MessageCache.cache.put(report.getScenarioId(), counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,43 +98,44 @@ public class TestResultService {
|
|||
testResult.setTestId(testId);
|
||||
ApiScenarioReport scenarioReport = apiScenarioReportService.complete(testResult, runMode);
|
||||
//环境
|
||||
ApiScenarioWithBLOBs apiScenario = apiAutomationService.getDto(scenarioReport.getScenarioId());
|
||||
String name = "";
|
||||
//执行人
|
||||
String userName = "";
|
||||
//负责人
|
||||
String principal = "";
|
||||
if (apiScenario != null) {
|
||||
String executionEnvironment = apiScenario.getScenarioDefinition();
|
||||
JSONObject json = JSONObject.parseObject(executionEnvironment);
|
||||
if (json != null && json.getString("environmentMap") != null && json.getString("environmentMap").length() > 2) {
|
||||
JSONObject environment = JSONObject.parseObject(json.getString("environmentMap"));
|
||||
String environmentId = environment.get(apiScenario.getProjectId()).toString();
|
||||
name = apiAutomationService.get(environmentId).getName();
|
||||
if (scenarioReport != null) {
|
||||
ApiScenarioWithBLOBs apiScenario = apiAutomationService.getDto(scenarioReport.getScenarioId());
|
||||
String name = "";
|
||||
//执行人
|
||||
String userName = "";
|
||||
//负责人
|
||||
String principal = "";
|
||||
if (apiScenario != null) {
|
||||
String executionEnvironment = apiScenario.getScenarioDefinition();
|
||||
JSONObject json = JSONObject.parseObject(executionEnvironment);
|
||||
if (json != null && json.getString("environmentMap") != null && json.getString("environmentMap").length() > 2) {
|
||||
JSONObject environment = JSONObject.parseObject(json.getString("environmentMap"));
|
||||
String environmentId = environment.get(apiScenario.getProjectId()).toString();
|
||||
name = apiAutomationService.get(environmentId).getName();
|
||||
}
|
||||
userName = apiAutomationService.getUser(apiScenario.getUserId());
|
||||
principal = apiAutomationService.getUser(apiScenario.getPrincipal());
|
||||
}
|
||||
userName = apiAutomationService.getUser(apiScenario.getUserId());
|
||||
principal = apiAutomationService.getUser(apiScenario.getPrincipal());
|
||||
}
|
||||
|
||||
//报告内容
|
||||
reportTask = new ApiTestReportVariable();
|
||||
if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_SCENARIO.name())) {
|
||||
reportTask.setStatus(scenarioReport.getStatus());
|
||||
reportTask.setId(scenarioReport.getId());
|
||||
reportTask.setTriggerMode(scenarioReport.getTriggerMode());
|
||||
reportTask.setName(scenarioReport.getName());
|
||||
reportTask.setExecutor(userName);
|
||||
reportTask.setPrincipal(principal);
|
||||
reportTask.setExecutionTime(DateUtils.getTimeString(scenarioReport.getUpdateTime()));
|
||||
reportTask.setExecutionEnvironment(name);
|
||||
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
assert systemParameterService != null;
|
||||
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
|
||||
reportUrl = baseSystemConfigDTO.getUrl() + "/#/api/automation/report";
|
||||
//报告内容
|
||||
reportTask = new ApiTestReportVariable();
|
||||
if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_SCENARIO.name())) {
|
||||
reportTask.setStatus(scenarioReport.getStatus());
|
||||
reportTask.setId(scenarioReport.getId());
|
||||
reportTask.setTriggerMode(scenarioReport.getTriggerMode());
|
||||
reportTask.setName(scenarioReport.getName());
|
||||
reportTask.setExecutor(userName);
|
||||
reportTask.setPrincipal(principal);
|
||||
reportTask.setExecutionTime(DateUtils.getTimeString(scenarioReport.getUpdateTime()));
|
||||
reportTask.setExecutionEnvironment(name);
|
||||
SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class);
|
||||
assert systemParameterService != null;
|
||||
BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo();
|
||||
reportUrl = baseSystemConfigDTO.getUrl() + "/#/api/automation/report";
|
||||
|
||||
}
|
||||
testResult.setTestId(scenarioReport.getScenarioId());
|
||||
planScenarioId = scenarioReport.getTestPlanScenarioId();
|
||||
}
|
||||
testResult.setTestId(scenarioReport.getScenarioId());
|
||||
planScenarioId = scenarioReport.getTestPlanScenarioId();
|
||||
} else {
|
||||
apiTestService.changeStatus(testId, APITestStatus.Completed);
|
||||
report = apiReportService.getRunningReport(testResult.getTestId());
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package io.metersphere.api.service.task;
|
||||
|
||||
import io.metersphere.api.dto.RunModeDataDTO;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.commons.constants.TriggerMode;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class ParallelScenarioExecTask<T> implements Callable<T> {
|
||||
private RunScenarioRequest request;
|
||||
private JMeterService jMeterService;
|
||||
private RunModeDataDTO runModeDataDTO;
|
||||
|
||||
public ParallelScenarioExecTask(JMeterService jMeterService, RunModeDataDTO runModeDataDTO, RunScenarioRequest request) {
|
||||
this.jMeterService = jMeterService;
|
||||
this.request = request;
|
||||
this.runModeDataDTO = runModeDataDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() {
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReport().getId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
|
||||
}
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
LogUtil.error(ex);
|
||||
MSException.throwException(ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ public class SerialScenarioExecTask<T> implements Callable<T> {
|
|||
public T call() {
|
||||
try {
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReport().getId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig());
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getReport().getId(), request.getRunMode(), request.getPlanScenarioId(), request.getConfig(), runModeDataDTO.getHashTree());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getReport().getId(), runModeDataDTO.getHashTree(), TriggerMode.BATCH.name().equals(request.getTriggerMode()) ? TriggerMode.BATCH.name() : request.getReportId(), request.getRunMode());
|
||||
}
|
||||
|
|
|
@ -401,11 +401,12 @@ public class TestPlanApiCaseService {
|
|||
mapper.updateByPrimaryKey(execResult);
|
||||
reportIds.add(execResult.getId());
|
||||
RunModeDataDTO modeDataDTO;
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(testPlanApiCase.getId());
|
||||
if (request.getConfig() != null && StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
modeDataDTO = new RunModeDataDTO(testPlanApiCase.getId(), UUID.randomUUID().toString());
|
||||
modeDataDTO.setHashTree(hashTree);
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(testPlanApiCase.getId());
|
||||
modeDataDTO = new RunModeDataDTO(hashTree, UUID.randomUUID().toString());
|
||||
}
|
||||
modeDataDTO.setApiCaseId(execResult.getId());
|
||||
|
@ -440,16 +441,21 @@ public class TestPlanApiCaseService {
|
|||
// 开始并发执行
|
||||
for (TestPlanApiCase key : planApiCases) {
|
||||
RunModeDataDTO modeDataDTO = null;
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(key.getId());
|
||||
if (StringUtils.isNotBlank(request.getConfig().getResourcePoolId())) {
|
||||
modeDataDTO = new RunModeDataDTO(key.getId(), UUID.randomUUID().toString());
|
||||
} else {
|
||||
// 生成报告和HashTree
|
||||
HashTree hashTree = generateHashTree(key.getId());
|
||||
modeDataDTO = new RunModeDataDTO(hashTree, UUID.randomUUID().toString());
|
||||
}
|
||||
ApiDefinitionExecResult report = addResult(request, key, APITestStatus.Running.name(), batchMapper);
|
||||
modeDataDTO.setApiCaseId(report.getId());
|
||||
executorService.submit(new ParallelApiExecTask(jMeterService, mapper, modeDataDTO, request.getConfig(), ApiRunMode.API_PLAN.name()));
|
||||
if (request.getConfig() != null && StringUtils.isNotEmpty(request.getConfig().getResourcePoolId())) {
|
||||
jMeterService.runTest(modeDataDTO.getTestId(), modeDataDTO.getApiCaseId(), ApiRunMode.API_PLAN.name(), null, request.getConfig(), hashTree);
|
||||
} else {
|
||||
jMeterService.runLocal(modeDataDTO.getTestId(), hashTree, TriggerMode.BATCH.name() , ApiRunMode.API_PLAN.name());
|
||||
}
|
||||
}
|
||||
sqlSession.flushStatements();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class ParallelApiExecTask<T> implements Callable<T> {
|
|||
public T call() {
|
||||
try {
|
||||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config);
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config, runModeDataDTO.getHashTree());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null, runMode);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public class SerialApiExecTask<T> implements Callable<T> {
|
|||
public T call() {
|
||||
try {
|
||||
if (config != null && StringUtils.isNotBlank(config.getResourcePoolId())) {
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config);
|
||||
jMeterService.runTest(runModeDataDTO.getTestId(), runModeDataDTO.getApiCaseId(), runMode, null, config, runModeDataDTO.getHashTree());
|
||||
} else {
|
||||
jMeterService.runLocal(runModeDataDTO.getApiCaseId(), runModeDataDTO.getHashTree(), runModeDataDTO.getReport() != null ? runModeDataDTO.getReport().getTriggerMode() : null, runMode);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ spring.flyway.baseline-version=0
|
|||
spring.flyway.encoding=UTF-8
|
||||
spring.flyway.validate-on-migrate=false
|
||||
spring.kafka.listener.missing-topics-fatal=false
|
||||
|
||||
spring.kafka.producer.properties.max.request.size=32428800
|
||||
spring.messages.basename=i18n/messages
|
||||
|
||||
# kafka
|
||||
|
@ -76,7 +76,6 @@ kafka.ssl.keystore-type=JKS
|
|||
kafka.ssl.protocol=TLS
|
||||
kafka.ssl.provider=
|
||||
kafka.ssl.truststore-type=
|
||||
|
||||
# jmeter
|
||||
jmeter.home=/opt/jmeter
|
||||
|
||||
|
|
Loading…
Reference in New Issue