refactor(接口测试): 接口测试执行相关代码整理优化

This commit is contained in:
fit2-zhao 2022-07-11 17:59:54 +08:00 committed by fit2-zhao
parent def44a3326
commit 59b6e5e556
10 changed files with 370 additions and 260 deletions

View File

@ -8,7 +8,6 @@ import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.scenario.DatabaseConfig;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.service.ApiCaseResultService;
@ -51,7 +50,7 @@ public class ApiCaseExecuteService {
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
private ApiCaseSerialService apiCaseSerialService;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
@ -149,13 +148,13 @@ public class ApiCaseExecuteService {
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.API_PLAN.name(), request.getPlanReportId(), reportType, runMode, request.getConfig());
// 开始选择执行模式
if (deQueue != null && deQueue.getQueue() != null) {
if (deQueue != null && deQueue.getDetail() != null) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().setName("PLAN-CASE" + request.getPlanReportId());
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
apiScenarioSerialService.serial(deQueue, deQueue.getQueue());
apiCaseSerialService.serial(deQueue);
} else {
apiCaseParallelExecuteService.parallel(executeQueue, request.getConfig(), deQueue, runMode);
}
@ -277,7 +276,7 @@ public class ApiCaseExecuteService {
if (MapUtils.isEmpty(config.getEnvMap())) {
RunModeConfigWithEnvironmentDTO runModeConfig = new RunModeConfigWithEnvironmentDTO();
BeanUtils.copyBean(runModeConfig, request.getConfig());
this.setExecutionEnvironmen(runModeConfig, testCaseEnvMap);
this.setExecutionEnvironment(runModeConfig, testCaseEnvMap);
config = runModeConfig;
}
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.initBase(null, APITestStatus.Running.name(), serialReportId, config);
@ -341,17 +340,17 @@ public class ApiCaseExecuteService {
String reportType = request.getConfig().getReportType();
String poolId = request.getConfig().getResourcePoolId();
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.DEFINITION.name(), serialReportId, reportType, ApiRunMode.DEFINITION.name(), request.getConfig());
DBTestQueue queue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.DEFINITION.name(), serialReportId, reportType, ApiRunMode.DEFINITION.name(), request.getConfig());
// 开始选择执行模式
if (deQueue != null && deQueue.getQueue() != null) {
if (queue != null && queue.getDetail() != null) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Thread.currentThread().setName("API-CASE-RUN");
if (request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
apiScenarioSerialService.serial(deQueue, deQueue.getQueue());
apiCaseSerialService.serial(queue);
} else {
apiCaseParallelExecuteService.parallel(executeQueue, request.getConfig(), deQueue, ApiRunMode.DEFINITION.name());
apiCaseParallelExecuteService.parallel(executeQueue, request.getConfig(), queue, ApiRunMode.DEFINITION.name());
}
}
});
@ -360,7 +359,7 @@ public class ApiCaseExecuteService {
return responseDTOS;
}
public void setExecutionEnvironmen(RunModeConfigWithEnvironmentDTO config, Map<String, List<String>> projectEnvMap) {
public void setExecutionEnvironment(RunModeConfigWithEnvironmentDTO config, Map<String, List<String>> projectEnvMap) {
if (MapUtils.isNotEmpty(projectEnvMap) && config != null) {
config.setExecutionEnvironmentMap(projectEnvMap);
}

View File

@ -1,7 +1,6 @@
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.api.jmeter.utils.SmoothWeighted;
@ -26,7 +25,7 @@ import java.util.Map;
@Service
public class ApiCaseParallelExecuteService {
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
private ApiCaseSerialService apiCaseSerialService;
@Resource
private JMeterService jMeterService;
@Resource
@ -64,7 +63,7 @@ public class ApiCaseParallelExecuteService {
runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, executionQueue.getDetailMap().get(result.getId())));
}
if (!pool.isPool()) {
HashTree hashTree = apiScenarioSerialService.generateHashTree(testId, config.getEnvMap(), runRequest);
HashTree hashTree = apiCaseSerialService.generateHashTree(testId, config.getEnvMap(), runRequest);
runRequest.setHashTree(hashTree);
}

View File

@ -0,0 +1,239 @@
package io.metersphere.api.exec.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.exec.utils.RequestParamsUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.utils.SmoothWeighted;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.RemakeReportService;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.base.domain.ApiExecutionQueueDetail;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.xpack.api.dto.MsRetryLoopController;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiCaseSerialService {
@Resource
private JMeterService jMeterService;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private ObjectMapper mapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void serial(DBTestQueue executionQueue) {
ApiExecutionQueueDetail queue = executionQueue.getDetail();
JmeterRunRequestDTO runRequest = RequestParamsUtil.init(executionQueue, queue, queue.getReportId());
// 判断触发资源对象是用例
if (!GenerateHashTreeUtil.isSetReport(executionQueue.getReportType())
|| StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiRunMode.DEFINITION.name())) {
updateDefinitionExecResultToRunning(queue, runRequest);
}
try {
if (StringUtils.isEmpty(executionQueue.getPoolId())) {
Map<String, String> map = new LinkedHashMap<>();
if (StringUtils.isNotEmpty(queue.getEvnMap())) {
map = JSON.parseObject(queue.getEvnMap(), Map.class);
}
runRequest.setHashTree(generateHashTree(queue.getTestId(), map, runRequest));
// 更新环境变量
if (runRequest.getHashTree() != null) {
this.initEnv(runRequest.getHashTree());
}
}
if (runRequest.getPool().isPool()) {
SmoothWeighted.setServerConfig(runRequest.getPoolId(), redisTemplate);
}
// 开始执行
jMeterService.run(runRequest);
} catch (Exception e) {
RequestParamsUtil.rollback(runRequest, e);
}
}
protected void updateDefinitionExecResultToRunning(ApiExecutionQueueDetail queue, JmeterRunRequestDTO runRequest) {
ApiDefinitionExecResultWithBLOBs execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (execResult != null) {
runRequest.setExtendedParameters(new HashMap<String, Object>() {{
this.put("userId", execResult.getUserId());
}});
execResult.setStartTime(System.currentTimeMillis());
execResult.setStatus(APITestStatus.Running.name());
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(execResult);
LoggerUtil.info("进入串行模式,准备执行资源:[" + execResult.getName() + " ]", execResult.getId());
}
}
private void initEnv(HashTree hashTree) {
ApiTestEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
HashTreeUtil hashTreeUtil = new HashTreeUtil();
Map<String, Map<String, String>> envParamsMap = hashTreeUtil.getEnvParamsDataByHashTree(hashTree, apiTestEnvironmentService);
hashTreeUtil.mergeParamDataMap(null, envParamsMap);
}
public HashTree generateHashTree(String testId, Map<String, String> envMap, JmeterRunRequestDTO runRequest) {
try {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testId);
String envId = null;
if (caseWithBLOBs == null) {
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) {
String data = caseWithBLOBs.getRequest();
// 失败重试
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
ApiRetryOnFailureService apiRetryOnFailureService = CommonBeanFactory.getBean(ApiRetryOnFailureService.class);
String retryData = apiRetryOnFailureService.retry(data, runRequest.getRetryNum(), true);
data = StringUtils.isNotEmpty(retryData) ? retryData : data;
}
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
MsThreadGroup group = new MsThreadGroup();
group.setLabel(caseWithBLOBs.getName());
group.setName(runRequest.getReportId());
group.setProjectId(caseWithBLOBs.getProjectId());
MsTestElement testElement = null;
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
MsRetryLoopController controller = JSON.parseObject(data, MsRetryLoopController.class);
GenerateHashTreeUtil.parse(data, controller);
MsTestElement element = parse(JSON.toJSONString(controller.getHashTree().get(0)), testId, envId, caseWithBLOBs.getProjectId());
controller.setHashTree(new LinkedList<>() {{
this.add(element);
}});
testElement = controller;
} else {
testElement = parse(data, testId, envId, caseWithBLOBs.getProjectId());
}
group.setHashTree(new LinkedList<>());
group.getHashTree().add(testElement);
testPlan.getHashTree().add(group);
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
LoggerUtil.info("用例资源:" + caseWithBLOBs.getName() + ", 生成执行脚本JMX成功", runRequest.getReportId());
return jmeterHashTree;
}
} catch (Exception ex) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest);
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, runRequest);
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
LoggerUtil.error("用例资源:" + testId + ", 生成执行脚本失败", runRequest.getReportId(), ex);
}
return null;
}
private MsTestElement parse(String api, String planId, String envId, String projectId) {
try {
JSONObject element = JSON.parseObject(api, Feature.DisableSpecialKeyDetect);
ElementUtil.dataFormatting(element);
LinkedList<MsTestElement> list = new LinkedList<>();
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
list.addAll(elements);
}
if (element.getString("type").equals("HTTPSamplerProxy")) {
MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class, Feature.DisableSpecialKeyDetect);
httpSamplerProxy.setHashTree(list);
httpSamplerProxy.setName(planId);
if (StringUtils.isNotEmpty(envId)) {
httpSamplerProxy.setUseEnvironment(envId);
}
return httpSamplerProxy;
}
if (element.getString("type").equals("TCPSampler")) {
MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class, Feature.DisableSpecialKeyDetect);
if (StringUtils.isEmpty(msTCPSampler.getProjectId())) {
msTCPSampler.setProjectId(projectId);
}
if (StringUtils.isNotEmpty(envId)) {
msTCPSampler.setUseEnvironment(envId);
}
msTCPSampler.setHashTree(list);
msTCPSampler.setName(planId);
return msTCPSampler;
}
if (element.getString("type").equals("DubboSampler")) {
MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class, Feature.DisableSpecialKeyDetect);
if (StringUtils.isNotEmpty(envId)) {
dubboSampler.setUseEnvironment(envId);
}
dubboSampler.setHashTree(list);
dubboSampler.setName(planId);
return dubboSampler;
}
if (element.getString("type").equals("JDBCSampler")) {
MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class);
if (StringUtils.isNotEmpty(envId)) {
jDBCSampler.setUseEnvironment(envId);
}
jDBCSampler.setHashTree(list);
jDBCSampler.setName(planId);
return jDBCSampler;
}
} catch (Exception e) {
LogUtil.error(e);
}
return null;
}
}

View File

@ -77,14 +77,14 @@ public class PerfQueueService {
}
// 获取串行下一个执行节点
DBTestQueue executionQueue = apiExecutionQueueService.handleQueue(detail.getQueueId(), detail.getTestId());
if (executionQueue != null && executionQueue.getQueue() != null
&& StringUtils.isNotEmpty(executionQueue.getQueue().getTestId()) &&
if (executionQueue != null && executionQueue.getDetail() != null
&& StringUtils.isNotEmpty(executionQueue.getDetail().getTestId()) &&
StringUtils.equals(executionQueue.getRunMode(), RunModeConstants.SERIAL.toString())) {
LoggerUtil.info("获取下一个执行资源:" + executionQueue.getQueue().getTestId(), loadTestReport.getId());
LoggerUtil.info("获取下一个执行资源:" + executionQueue.getDetail().getTestId(), loadTestReport.getId());
RunTestPlanRequest request = new RunTestPlanRequest();
request.setTestPlanLoadId(executionQueue.getQueue().getTestId());
request.setReportId(executionQueue.getQueue().getReportId());
request.setTestPlanLoadId(executionQueue.getDetail().getTestId());
request.setReportId(executionQueue.getDetail().getReportId());
try {
perfModeExecService.serial(request);
} catch (Exception e) {
@ -92,10 +92,10 @@ public class PerfQueueService {
LoggerUtil.info("失败停止处理:" + request.getId(), request.getReportId());
continue;
}
LoggerUtil.error("执行异常", executionQueue.getQueue().getTestId(), e);
LoggerUtil.error("执行异常", executionQueue.getDetail().getTestId(), e);
executionQueueDetailMapper.deleteByExample(detailExample);
// 异常执行下一个
DBTestQueue next = apiExecutionQueueService.handleQueue(executionQueue.getId(), executionQueue.getQueue().getTestId());
DBTestQueue next = apiExecutionQueueService.handleQueue(executionQueue.getId(), executionQueue.getDetail().getTestId());
if (next != null) {
LoadTestReport report = new LoadTestReport();
report.setId(next.getReportId());

View File

@ -10,6 +10,6 @@ import java.util.Map;
@Data
public class DBTestQueue extends ApiExecutionQueue {
private String completedReportId;
private ApiExecutionQueueDetail queue;
private ApiExecutionQueueDetail detail;
private Map<String, String> detailMap = new HashMap<>();
}

View File

@ -165,7 +165,7 @@ public class ApiScenarioExecuteService {
RunModeConfigWithEnvironmentDTO runModeConfig = new RunModeConfigWithEnvironmentDTO();
BeanUtils.copyBean(runModeConfig, request.getConfig());
Map<String, List<String>> projectEnvMap = apiScenarioEnvService.selectApiScenarioEnv(apiScenarios);
apiCaseExecuteService.setExecutionEnvironmen(runModeConfig, projectEnvMap);
apiCaseExecuteService.setExecutionEnvironment(runModeConfig, projectEnvMap);
request.setConfig(runModeConfig);
}
APIScenarioReportResult report = getApiScenarioReportResult(request, serialReportId, scenarioNames, reportScenarioIds);
@ -199,7 +199,7 @@ public class ApiScenarioExecuteService {
{
Thread.currentThread().setName("SCENARIO-THREAD");
if (isSerial(request)) {
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
apiScenarioSerialService.serial(executionQueue);
} else {
apiScenarioParallelService.parallel(executeQueue, request, finalSerialReportId, executionQueue);
}

View File

@ -1,41 +1,21 @@
package io.metersphere.api.exec.scenario;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.definition.request.MsThreadGroup;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.sampler.MsDubboSampler;
import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy;
import io.metersphere.api.dto.definition.request.sampler.MsJDBCSampler;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.exec.api.ApiRetryOnFailureService;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.api.exec.utils.RequestParamsUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.utils.SmoothWeighted;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.api.service.RemakeReportService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.service.SystemParameterService;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.xpack.api.dto.MsRetryLoopController;
import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree;
import org.springframework.data.redis.core.RedisTemplate;
@ -45,7 +25,6 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@Service
@ -58,48 +37,24 @@ public class ApiScenarioSerialService {
@Resource
private ApiScenarioMapper apiScenarioMapper;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private TestPlanApiCaseMapper testPlanApiCaseMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
private ApiScenarioEnvService apiScenarioEnvService;
@Resource
private ObjectMapper mapper;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Resource
private ApiTestEnvironmentService apiTestEnvironmentService;
public void serial(ApiExecutionQueue executionQueue, ApiExecutionQueueDetail queue) {
public void serial(DBTestQueue executionQueue) {
ApiExecutionQueueDetail queue = executionQueue.getDetail();
String reportId = StringUtils.isNotEmpty(executionQueue.getReportId()) ? executionQueue.getReportId() : queue.getReportId();
if (!StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
reportId = queue.getReportId();
}
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(queue.getTestId(), reportId, executionQueue.getRunMode(), null);
// 获取可以执行的资源池
BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
runRequest.setRetryEnable(queue.getRetryEnable() == null ? false : queue.getRetryEnable());
runRequest.setRetryNum(queue.getRetryNumber());
// 判断触发资源对象是用例/场景更新对应报告状态
if (!GenerateHashTreeUtil.isSetReport(executionQueue.getReportType())
|| StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiRunMode.DEFINITION.name())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
updateReportToRunning(queue, runRequest);
} else {
updateDefinitionExecResultToRunning(queue, runRequest);
}
}
JmeterRunRequestDTO runRequest = RequestParamsUtil.init(executionQueue, queue, reportId);
// 更新报告状态
updateReportToRunning(queue, runRequest);
try {
runRequest.setReportType(executionQueue.getReportType());
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(executionQueue.getPoolId()));
runRequest.setTestPlanReportId(executionQueue.getReportId());
runRequest.setRunType(RunModeConstants.SERIAL.toString());
runRequest.setQueueId(executionQueue.getId());
runRequest.setPoolId(executionQueue.getPoolId());
if (StringUtils.isEmpty(executionQueue.getPoolId())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioWithBLOBs scenario = null;
@ -118,12 +73,6 @@ public class ApiScenarioSerialService {
planEnvMap = JSON.parseObject(queue.getEvnMap(), Map.class);
}
runRequest.setHashTree(GenerateHashTreeUtil.generateHashTree(scenario, planEnvMap, runRequest));
} else {
Map<String, String> map = new LinkedHashMap<>();
if (StringUtils.isNotEmpty(queue.getEvnMap())) {
map = JSON.parseObject(queue.getEvnMap(), Map.class);
}
runRequest.setHashTree(generateHashTree(queue.getTestId(), map, runRequest));
}
// 更新环境变量
@ -131,175 +80,47 @@ public class ApiScenarioSerialService {
this.initEnv(runRequest.getHashTree());
}
}
if (queue != null) {
runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, queue.getId()));
}
if (runRequest.getPool().isPool()) {
SmoothWeighted.setServerConfig(runRequest.getPoolId(), redisTemplate);
}
// 开始执行
jMeterService.run(runRequest);
} catch (Exception e) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest);
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, runRequest);
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
LoggerUtil.error("执行队列[" + queue.getId() + "]入队列失败:", queue.getReportId(), e);
}
}
protected void updateDefinitionExecResultToRunning(ApiExecutionQueueDetail queue, JmeterRunRequestDTO runRequest) {
ApiDefinitionExecResultWithBLOBs execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (execResult != null) {
runRequest.setExtendedParameters(new HashMap<String, Object>() {{
this.put("userId", execResult.getUserId());
}});
execResult.setStartTime(System.currentTimeMillis());
execResult.setStatus(APITestStatus.Running.name());
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(execResult);
LoggerUtil.info("进入串行模式,准备执行资源:[" + execResult.getName() + " ]", execResult.getId());
RequestParamsUtil.rollback(runRequest, e);
}
}
/**
* 更新报告状态
*
* @param queue
* @param runRequest
*/
public void updateReportToRunning(ApiExecutionQueueDetail queue, JmeterRunRequestDTO runRequest) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(queue.getReportId());
if (report != null) {
report.setStatus(APITestStatus.Running.name());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
runRequest.setExtendedParameters(new HashMap<String, Object>() {{
this.put("userId", report.getCreateUser());
}});
apiScenarioReportMapper.updateByPrimaryKey(report);
LoggerUtil.info("进入串行模式,准备执行资源:[ " + report.getName() + " ]", report.getId());
if (!GenerateHashTreeUtil.isSetReport(runRequest.getReportType()) &&
StringUtils.equalsAny(runRequest.getRunMode(),
ApiRunMode.SCENARIO.name(),
ApiRunMode.SCENARIO_PLAN.name(),
ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(),
ApiRunMode.SCHEDULE_SCENARIO.name(),
ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(queue.getReportId());
if (report != null) {
report.setStatus(APITestStatus.Running.name());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
runRequest.setExtendedParameters(new HashMap<String, Object>() {{
this.put("userId", report.getCreateUser());
}});
apiScenarioReportMapper.updateByPrimaryKey(report);
LoggerUtil.info("进入串行模式,准备执行资源:[ " + report.getName() + " ]", report.getId());
}
}
}
private void initEnv(HashTree hashTree) {
ApiTestEnvironmentService apiTestEnvironmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
HashTreeUtil hashTreeUtil = new HashTreeUtil();
Map<String, Map<String, String>> envParamsMap = hashTreeUtil.getEnvParamsDataByHashTree(hashTree, apiTestEnvironmentService);
hashTreeUtil.mergeParamDataMap(null, envParamsMap);
}
public HashTree generateHashTree(String testId, Map<String, String> envMap, JmeterRunRequestDTO runRequest) {
try {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testId);
String envId = null;
if (caseWithBLOBs == null) {
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) {
String data = caseWithBLOBs.getRequest();
// 失败重试
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
ApiRetryOnFailureService apiRetryOnFailureService = CommonBeanFactory.getBean(ApiRetryOnFailureService.class);
String retryData = apiRetryOnFailureService.retry(data, runRequest.getRetryNum(), true);
data = StringUtils.isNotEmpty(retryData) ? retryData : data;
}
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
MsThreadGroup group = new MsThreadGroup();
group.setLabel(caseWithBLOBs.getName());
group.setName(runRequest.getReportId());
group.setProjectId(caseWithBLOBs.getProjectId());
MsTestElement testElement = null;
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
MsRetryLoopController controller = JSON.parseObject(data, MsRetryLoopController.class);
GenerateHashTreeUtil.parse(data, controller);
MsTestElement element = parse(JSON.toJSONString(controller.getHashTree().get(0)), testId, envId, caseWithBLOBs.getProjectId());
controller.setHashTree(new LinkedList<>() {{
this.add(element);
}});
testElement = controller;
} else {
testElement = parse(data, testId, envId, caseWithBLOBs.getProjectId());
}
group.setHashTree(new LinkedList<>());
group.getHashTree().add(testElement);
testPlan.getHashTree().add(group);
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
LoggerUtil.info("用例资源:" + caseWithBLOBs.getName() + ", 生成执行脚本JMX成功", runRequest.getReportId());
return jmeterHashTree;
}
} catch (Exception ex) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest);
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, runRequest);
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
LoggerUtil.error("用例资源:" + testId + ", 生成执行脚本失败", runRequest.getReportId(), ex);
}
return null;
}
private MsTestElement parse(String api, String planId, String envId, String projectId) {
try {
JSONObject element = JSON.parseObject(api, Feature.DisableSpecialKeyDetect);
ElementUtil.dataFormatting(element);
LinkedList<MsTestElement> list = new LinkedList<>();
if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) {
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"),
new TypeReference<LinkedList<MsTestElement>>() {
});
list.addAll(elements);
}
if (element.getString("type").equals("HTTPSamplerProxy")) {
MsHTTPSamplerProxy httpSamplerProxy = JSON.parseObject(api, MsHTTPSamplerProxy.class, Feature.DisableSpecialKeyDetect);
httpSamplerProxy.setHashTree(list);
httpSamplerProxy.setName(planId);
if (StringUtils.isNotEmpty(envId)) {
httpSamplerProxy.setUseEnvironment(envId);
}
return httpSamplerProxy;
}
if (element.getString("type").equals("TCPSampler")) {
MsTCPSampler msTCPSampler = JSON.parseObject(api, MsTCPSampler.class, Feature.DisableSpecialKeyDetect);
if (StringUtils.isEmpty(msTCPSampler.getProjectId())) {
msTCPSampler.setProjectId(projectId);
}
if (StringUtils.isNotEmpty(envId)) {
msTCPSampler.setUseEnvironment(envId);
}
msTCPSampler.setHashTree(list);
msTCPSampler.setName(planId);
return msTCPSampler;
}
if (element.getString("type").equals("DubboSampler")) {
MsDubboSampler dubboSampler = JSON.parseObject(api, MsDubboSampler.class, Feature.DisableSpecialKeyDetect);
if (StringUtils.isNotEmpty(envId)) {
dubboSampler.setUseEnvironment(envId);
}
dubboSampler.setHashTree(list);
dubboSampler.setName(planId);
return dubboSampler;
}
if (element.getString("type").equals("JDBCSampler")) {
MsJDBCSampler jDBCSampler = JSON.parseObject(api, MsJDBCSampler.class);
if (StringUtils.isNotEmpty(envId)) {
jDBCSampler.setUseEnvironment(envId);
}
jDBCSampler.setHashTree(list);
jDBCSampler.setName(planId);
return jDBCSampler;
}
} catch (Exception e) {
LogUtil.error(e);
}
return null;
}
}

View File

@ -0,0 +1,42 @@
package io.metersphere.api.exec.utils;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.RemakeReportService;
import io.metersphere.base.domain.ApiExecutionQueue;
import io.metersphere.base.domain.ApiExecutionQueueDetail;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.dto.ResultDTO;
import io.metersphere.service.SystemParameterService;
import io.metersphere.utils.LoggerUtil;
public class RequestParamsUtil {
public static JmeterRunRequestDTO init(ApiExecutionQueue executionQueue, ApiExecutionQueueDetail queue, String reportId) {
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(queue.getTestId(), reportId, executionQueue.getRunMode(), null);
runRequest.setRetryEnable(queue.getRetryEnable() == null ? false : queue.getRetryEnable());
runRequest.setRetryNum(queue.getRetryNumber());
runRequest.setReportType(executionQueue.getReportType());
runRequest.setPool(GenerateHashTreeUtil.isResourcePool(executionQueue.getPoolId()));
runRequest.setTestPlanReportId(executionQueue.getReportId());
runRequest.setRunType(RunModeConstants.SERIAL.toString());
runRequest.setQueueId(executionQueue.getId());
runRequest.setPoolId(executionQueue.getPoolId());
// 获取可以执行的资源池
BaseSystemConfigDTO baseInfo = CommonBeanFactory.getBean(SystemParameterService.class).getBaseInfo();
runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, queue.getId()));
return runRequest;
}
public static void rollback(JmeterRunRequestDTO runRequest, Exception e) {
RemakeReportService remakeReportService = CommonBeanFactory.getBean(RemakeReportService.class);
remakeReportService.remake(runRequest);
ResultDTO dto = new ResultDTO();
BeanUtils.copyBean(dto, runRequest);
CommonBeanFactory.getBean(ApiExecutionQueueService.class).queueNext(dto);
LoggerUtil.error("执行队列[" + runRequest.getQueueId() + "]入队列失败:", runRequest.getReportId(), e);
}
}

View File

@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.RunModeDataDTO;
import io.metersphere.api.dto.UiExecutionQueueParam;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.exec.api.ApiCaseSerialService;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.jmeter.JMeterService;
@ -66,6 +67,8 @@ public class ApiExecutionQueueService {
protected ExtApiExecutionQueueMapper extApiExecutionQueueMapper;
@Resource
private ApiScenarioReportResultMapper apiScenarioReportResultMapper;
@Resource
private ApiCaseSerialService apiCaseSerialService;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public DBTestQueue add(Object runObj, String poolId, String type, String reportId, String reportType, String runMode, RunModeConfigDTO config) {
@ -116,7 +119,7 @@ public class ApiExecutionQueueService {
ApiExecutionQueueDetail queue = detail(k, v.getTestId(), config.getMode(), sort[0], resQueue.getId(), envMap);
queue.setSort(sort[0]);
if (sort[0] == 0) {
resQueue.setQueue(queue);
resQueue.setDetail(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
@ -132,8 +135,8 @@ public class ApiExecutionQueueService {
String envStr = JSON.toJSONString(config.getEnvMap());
for (String k : runMap.keySet()) {
ApiExecutionQueueDetail queue = detail(runMap.get(k).getId(), k, config.getMode(), sort++, resQueue.getId(), envStr);
if (sort == 0) {
resQueue.setQueue(queue);
if (sort == 1) {
resQueue.setDetail(queue);
}
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
@ -149,8 +152,8 @@ public class ApiExecutionQueueService {
int i = 0;
for (String testId : requests.keySet()) {
ApiExecutionQueueDetail queue = detail(requests.get(testId), testId, config.getMode(), i++, resQueue.getId(), envStr);
if (i == 0) {
resQueue.setQueue(queue);
if (i == 1) {
resQueue.setDetail(queue);
}
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
@ -258,7 +261,7 @@ public class ApiExecutionQueueService {
}
// 取出下一个要执行的节点
if (CollectionUtils.isNotEmpty(queues)) {
queue.setQueue(queues.get(0));
queue.setDetail(queues.get(0));
} else {
LoggerUtil.info("execution complete,clear queue" + id + "");
queueMapper.deleteByPrimaryKey(id);
@ -331,22 +334,30 @@ public class ApiExecutionQueueService {
}
}
LoggerUtil.info("开始处理执行队列:" + executionQueue.getId() + " 当前资源是:" + dto.getTestId() + "报告ID" + dto.getReportId());
if (executionQueue.getQueue() != null && StringUtils.isNotEmpty(executionQueue.getQueue().getTestId())) {
if (executionQueue.getDetail() != null && StringUtils.isNotEmpty(executionQueue.getDetail().getTestId())) {
if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) {
LoggerUtil.info("当前执行队列是:" + JSON.toJSONString(executionQueue.getQueue()));
LoggerUtil.info("当前执行队列是:" + JSON.toJSONString(executionQueue.getDetail()));
// 防止重复执行
boolean isNext = redisTemplate.opsForValue().setIfAbsent(RunModeConstants.SERIAL.name() + "_" + executionQueue.getQueue().getReportId(), executionQueue.getQueue().getQueueId());
if (isNext) {
redisTemplate.expire(RunModeConstants.SERIAL.name() + "_" + executionQueue.getQueue().getReportId(), 60, TimeUnit.MINUTES);
if (StringUtils.startsWith(executionQueue.getRunMode(), "UI")) {
uiScenarioSerialServiceProxy.serial(executionQueue, executionQueue.getQueue());
} else {
apiScenarioSerialService.serial(executionQueue, executionQueue.getQueue());
}
boolean isNext = redisTemplate.opsForValue().setIfAbsent(RunModeConstants.SERIAL.name() + "_" + executionQueue.getDetail().getReportId(), executionQueue.getDetail().getQueueId());
if (!isNext) {
return;
}
redisTemplate.expire(RunModeConstants.SERIAL.name() + "_" + executionQueue.getDetail().getReportId(), 60, TimeUnit.MINUTES);
if (StringUtils.startsWith(executionQueue.getRunMode(), "UI")) {
uiScenarioSerialServiceProxy.serial(executionQueue, executionQueue.getDetail());
} else if (StringUtils.equalsAny(executionQueue.getRunMode(),
ApiRunMode.SCENARIO.name(),
ApiRunMode.SCENARIO_PLAN.name(),
ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(),
ApiRunMode.SCHEDULE_SCENARIO.name(),
ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
apiScenarioSerialService.serial(executionQueue);
} else {
apiCaseSerialService.serial(executionQueue);
}
}
} else {
if (StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
if (StringUtils.equalsIgnoreCase(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
String reportId = dto.getReportId();
if (StringUtils.equalsIgnoreCase(dto.getRunMode(), ApiRunMode.DEFINITION.name())) {
reportId = dto.getTestPlanReportId();

View File

@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.definition.request.MsTestPlan;
import io.metersphere.api.dto.scenario.request.BodyFile;
import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.api.ApiCaseSerialService;
import io.metersphere.api.exec.utils.GenerateHashTreeUtil;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
@ -36,9 +36,8 @@ import java.util.zip.ZipOutputStream;
@Service
public class ApiJmeterFileService {
@Resource
private ApiScenarioSerialService apiScenarioSerialService;
private ApiCaseSerialService apiCaseSerialService;
@Resource
private TestPlanApiScenarioMapper testPlanApiScenarioMapper;
@Resource
@ -90,7 +89,7 @@ public class ApiJmeterFileService {
}
HashTree hashTree = null;
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, envMap, runRequest);
hashTree = apiCaseSerialService.generateHashTree(remoteTestId, envMap, runRequest);
} else {
if (scenario == null) {
scenario = apiScenarioMapper.selectByPrimaryKey(remoteTestId);