feat(测试跟踪): 测试计划中性能测试用例支持串行和并行

--story=1008149 --user=赵勇 定时任务、jenkins、页面执行测试计划的性能测试不支持串行模式运行 https://www.tapd.cn/55049933/s/1195943
This commit is contained in:
fit2-zhao 2022-07-06 15:15:30 +08:00 committed by f2c-ci-robot[bot]
parent 7495be1c9b
commit b459e4736c
12 changed files with 349 additions and 200 deletions

View File

@ -0,0 +1,76 @@
package io.metersphere.api.exec.perf;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RunModeConfigDTO;
import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
@Service
public class PerfExecService {
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private PerfModeExecService perfModeExecService;
@Resource
private ExtLoadTestReportMapper extLoadTestReportMapper;
public Map<String, String> run(String planReportId, RunModeConfigDTO config, String triggerMode, Map<String, String> perfMap) {
LoggerUtil.info("开始生成测试计划性能测试队列");
List<RunTestPlanRequest> requests = new LinkedList<>();
Map<String, String> responseMap = new LinkedHashMap<>();
perfMap.forEach((k, v) -> {
String reportId = null;
// 执行中的性能测试资源
List<String> reportIds = extLoadTestReportMapper.selectReportIdByTestId(v);
if (CollectionUtils.isNotEmpty(reportIds)) {
reportId = reportIds.get(0);
}
// 过滤掉执行中的性能测试资源
if (StringUtils.isEmpty(reportId)) {
RunTestPlanRequest request = new RunTestPlanRequest();
reportId = UUID.randomUUID().toString();
request.setId(v);
request.setTestPlanLoadId(k);
request.setReportId(reportId);
request.setTriggerMode(triggerMode);
if (StringUtils.isNotBlank(config.getResourcePoolId())) {
request.setTestResourcePoolId(config.getResourcePoolId());
}
if (StringUtils.isEmpty(triggerMode)) {
request.setTriggerMode(ReportTriggerMode.TEST_PLAN_SCHEDULE.name());
}
requests.add(request);
}
responseMap.put(k, reportId);
});
//将性能测试加入到队列中
if (MapUtils.isNotEmpty(responseMap)) {
apiExecutionQueueService.add(responseMap, config.getResourcePoolId(), ApiRunMode.TEST_PLAN_PERFORMANCE_TEST.name(),
planReportId, config.getReportType(), config.getMode(), config);
}
if (CollectionUtils.isEmpty(requests) && StringUtils.isNotEmpty(planReportId)) {
apiExecutionQueueService.testPlanReportTestEnded(planReportId);
return responseMap;
}
LoggerUtil.info("开始执行性能测试任务");
if (config != null && config.getMode().equals(RunModeConstants.SERIAL.toString())) {
perfModeExecService.serial(requests.get(0));
} else {
perfModeExecService.parallel(requests);
}
return responseMap;
}
}

View File

@ -0,0 +1,43 @@
package io.metersphere.api.exec.perf;
import io.metersphere.base.domain.TestPlanLoadCaseWithBLOBs;
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
import io.metersphere.commons.constants.TestPlanLoadCaseStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.performance.service.PerformanceTestService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class PerfModeExecService {
@Resource
private PerformanceTestService performanceTestService;
@Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
public void serial(RunTestPlanRequest request) {
TestPlanLoadCaseWithBLOBs loadCase = testPlanLoadCaseMapper.selectByPrimaryKey(request.getTestPlanLoadId());
if (loadCase != null) {
loadCase.setLoadReportId(request.getReportId());
loadCase.setStatus(TestPlanLoadCaseStatus.run.name());
request.setId(loadCase.getLoadCaseId());
try {
performanceTestService.run(request);
} catch (Exception e) {
loadCase.setStatus(TestPlanLoadCaseStatus.error.name());
MSException.throwException(e);
}
//更新关联处的报告
testPlanLoadCaseMapper.updateByPrimaryKeySelective(loadCase);
}
}
public void parallel(List<RunTestPlanRequest> requests) {
for (RunTestPlanRequest request : requests) {
this.serial(request);
}
}
}

View File

@ -0,0 +1,108 @@
package io.metersphere.api.exec.perf;
import io.metersphere.api.exec.queue.DBTestQueue;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiExecutionQueueDetailMapper;
import io.metersphere.base.mapper.ApiExecutionQueueMapper;
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
import io.metersphere.commons.constants.TestPlanLoadCaseStatus;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class PerfQueueService {
@Resource
private ApiExecutionQueueDetailMapper executionQueueDetailMapper;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private PerfModeExecService perfModeExecService;
@Resource
protected ApiExecutionQueueMapper queueMapper;
@Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
/**
* 性能测试监听检查
*
* @param loadTestReport
*/
public void queueNext(LoadTestReport loadTestReport) {
LoggerUtil.info("进入结果处理监听", loadTestReport.getId());
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
detailExample.createCriteria().andReportIdEqualTo(loadTestReport.getId());
List<ApiExecutionQueueDetail> details = executionQueueDetailMapper.selectByExample(detailExample);
executionQueueDetailMapper.deleteByExample(detailExample);
if (CollectionUtils.isEmpty(details)) {
return;
}
List<String> ids = details.stream().map(ApiExecutionQueueDetail::getQueueId).collect(Collectors.toList());
ApiExecutionQueueExample queueExample = new ApiExecutionQueueExample();
queueExample.createCriteria().andIdIn(ids);
List<ApiExecutionQueue> queues = queueMapper.selectByExample(queueExample);
List<String> testPlanReportIds = queues.stream().map(ApiExecutionQueue::getReportId).collect(Collectors.toList());
for (String testPlanReportId : testPlanReportIds) {
LoggerUtil.info("处理测试计划报告状态", loadTestReport.getId());
apiExecutionQueueService.testPlanReportTestEnded(testPlanReportId);
}
for (ApiExecutionQueueDetail detail : details) {
// 更新测试计划关联数据状态
TestPlanLoadCaseWithBLOBs loadCase = new TestPlanLoadCaseWithBLOBs();
loadCase.setId(loadTestReport.getTestId());
loadCase.setStatus(TestPlanLoadCaseStatus.success.name());
testPlanLoadCaseMapper.updateByPrimaryKeySelective(loadCase);
// 检查队列是否已空
ApiExecutionQueueDetailExample queueDetailExample = new ApiExecutionQueueDetailExample();
queueDetailExample.createCriteria().andQueueIdEqualTo(detail.getQueueId());
long count = executionQueueDetailMapper.countByExample(queueDetailExample);
// 最后一个执行节点删除执行链
if (count == 0) {
queueMapper.deleteByPrimaryKey(detail.getQueueId());
continue;
}
// 获取串行下一个执行节点
DBTestQueue executionQueue = apiExecutionQueueService.handleQueue(detail.getQueueId(), detail.getTestId());
if (executionQueue != null && executionQueue.getQueue() != null
&& StringUtils.isNotEmpty(executionQueue.getQueue().getTestId()) &&
StringUtils.equals(executionQueue.getRunMode(), RunModeConstants.SERIAL.toString())) {
LoggerUtil.info("获取下一个执行资源:" + executionQueue.getQueue().getTestId(), loadTestReport.getId());
RunTestPlanRequest request = new RunTestPlanRequest();
request.setTestPlanLoadId(executionQueue.getQueue().getTestId());
request.setReportId(executionQueue.getQueue().getReportId());
try {
perfModeExecService.serial(request);
} catch (Exception e) {
if (BooleanUtils.isTrue(executionQueue.getFailure()) && StringUtils.isNotEmpty(executionQueue.getCompletedReportId())) {
LoggerUtil.info("失败停止处理:" + request.getId(), request.getReportId());
continue;
}
LoggerUtil.error("执行异常", executionQueue.getQueue().getTestId(), e);
executionQueueDetailMapper.deleteByExample(detailExample);
// 异常执行下一个
DBTestQueue next = apiExecutionQueueService.handleQueue(executionQueue.getId(), executionQueue.getQueue().getTestId());
if (next != null) {
LoadTestReport report = new LoadTestReport();
report.setId(next.getReportId());
this.queueNext(report);
}
}
}
}
}
}

View File

@ -28,7 +28,6 @@ import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
@ -67,88 +66,99 @@ public class ApiExecutionQueueService {
protected ExtApiExecutionQueueMapper extApiExecutionQueueMapper;
@Resource
private ApiScenarioReportResultMapper apiScenarioReportResultMapper;
@Lazy
@Resource
private TestPlanReportService testPlanReportService;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public DBTestQueue add(Object runObj, String poolId, String type, String reportId, String reportType, String runMode, RunModeConfigDTO config) {
LoggerUtil.info("开始生成执行链", reportId);
LoggerUtil.info("报告【" + reportId + "】开始生成执行链");
if (config.getEnvMap() == null) {
config.setEnvMap(new LinkedHashMap<>());
}
ApiExecutionQueue executionQueue = getApiExecutionQueue(poolId, reportId, reportType, runMode, config);
queueMapper.insert(executionQueue);
DBTestQueue resQueue = new DBTestQueue();
BeanUtils.copyBean(resQueue, executionQueue);
Map<String, String> detailMap = new HashMap<>();
List<ApiExecutionQueueDetail> queueDetails = new LinkedList<>();
// 初始化API/用例队列
if (StringUtils.equalsAnyIgnoreCase(type, ApiRunMode.DEFINITION.name(), ApiRunMode.API_PLAN.name())) {
final int[] sort = {0};
Map<String, ApiDefinitionExecResult> runMap = (Map<String, ApiDefinitionExecResult>) runObj;
if (config.getEnvMap() == null) {
config.setEnvMap(new LinkedHashMap<>());
}
String envStr = JSON.toJSONString(config.getEnvMap());
runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(v.getId(), k, config.getMode(), sort[0], executionQueue.getId(), envStr);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
} else if (StringUtils.equalsIgnoreCase(type, ApiRunMode.TEST_PLAN_PERFORMANCE_TEST.name())) {
final int[] sort = {0};
Map<String, String> runMap = (Map<String, String>) runObj;
if (config.getEnvMap() == null) {
config.setEnvMap(new LinkedHashMap<>());
}
String envStr = JSON.toJSONString(config.getEnvMap());
runMap.forEach((k, v) -> {
ApiExecutionQueueDetail queue = detail(v, k, "loadTest", sort[0], executionQueue.getId(), envStr);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
} else {
initApi(runMap, resQueue, config, detailMap, queueDetails);
}
// 初始化性能测试执行链
else if (StringUtils.equalsIgnoreCase(type, ApiRunMode.TEST_PLAN_PERFORMANCE_TEST.name())) {
Map<String, String> requests = (Map<String, String>) runObj;
initPerf(requests, resQueue, config, detailMap, queueDetails);
}
// 初始化场景/UI执行链
else {
Map<String, RunModeDataDTO> runMap = (Map<String, RunModeDataDTO>) runObj;
final int[] sort = {0};
runMap.forEach((k, v) -> {
String envMap = JSON.toJSONString(v.getPlanEnvMap());
if (StringUtils.startsWith(type, "UI_")) {
UiExecutionQueueParam param = new UiExecutionQueueParam();
BeanUtils.copyBean(param, config);
envMap = JSONObject.toJSONString(param);
}
ApiExecutionQueueDetail queue = detail(k, v.getTestId(), config.getMode(), sort[0], executionQueue.getId(), envMap);
queue.setSort(sort[0]);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
initScenario(runMap, resQueue, config, type, detailMap, queueDetails);
}
if (CollectionUtils.isNotEmpty(queueDetails)) {
extApiExecutionQueueMapper.sqlInsert(queueDetails);
}
resQueue.setDetailMap(detailMap);
LoggerUtil.info("生成执行链结束", reportId);
LoggerUtil.info("报告【" + reportId + "】生成执行链结束");
return resQueue;
}
private void initScenario(Map<String, RunModeDataDTO> runMap, DBTestQueue resQueue,
RunModeConfigDTO config, String type, Map<String, String> detailMap, List<ApiExecutionQueueDetail> queueDetails) {
final int[] sort = {0};
runMap.forEach((k, v) -> {
String envMap = JSON.toJSONString(v.getPlanEnvMap());
if (StringUtils.startsWith(type, "UI_")) {
UiExecutionQueueParam param = new UiExecutionQueueParam();
BeanUtils.copyBean(param, config);
envMap = JSONObject.toJSONString(param);
}
ApiExecutionQueueDetail queue = detail(k, v.getTestId(), config.getMode(), sort[0], resQueue.getId(), envMap);
queue.setSort(sort[0]);
if (sort[0] == 0) {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
}
private void initApi(Map<String, ApiDefinitionExecResult> runMap,
DBTestQueue resQueue, RunModeConfigDTO config, Map<String, String> detailMap, List<ApiExecutionQueueDetail> queueDetails) {
int sort = 0;
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);
}
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
}
resQueue.setDetailMap(detailMap);
}
private void initPerf(Map<String, String> requests,
DBTestQueue resQueue, RunModeConfigDTO config, Map<String, String> detailMap, List<ApiExecutionQueueDetail> queueDetails) {
String envStr = JSON.toJSONString(config.getEnvMap());
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);
}
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(testId, queue.getId());
}
}
protected ApiExecutionQueue getApiExecutionQueue(String poolId, String reportId, String reportType, String runMode, RunModeConfigDTO config) {
ApiExecutionQueue executionQueue = new ApiExecutionQueue();
executionQueue.setId(UUID.randomUUID().toString());
@ -175,7 +185,7 @@ public class ApiExecutionQueueService {
}
private boolean failure(DBTestQueue executionQueue, ResultDTO dto) {
LoggerUtil.info("进入失败停止处理:" + executionQueue.getId(), dto.getReportId());
LoggerUtil.info("进入失败停止处理:" + executionQueue.getId());
boolean isError = false;
if (StringUtils.contains(dto.getRunMode(), ApiRunMode.SCENARIO.name())) {
if (StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
@ -250,15 +260,15 @@ public class ApiExecutionQueueService {
if (CollectionUtils.isNotEmpty(queues)) {
queue.setQueue(queues.get(0));
} else {
LoggerUtil.info("execution complete,clear queue" + id + "", queue.getReportId());
LoggerUtil.info("execution complete,clear queue" + id + "");
queueMapper.deleteByPrimaryKey(id);
}
} else {
LoggerUtil.info("execution complete,clear queue" + id + "", queue.getReportId());
LoggerUtil.info("execution complete,clear queue" + id + "");
queueMapper.deleteByPrimaryKey(id);
}
} else {
LoggerUtil.info("The queue was accidentally deleted" + id + "", queue.getReportId());
LoggerUtil.info("The queue was accidentally deleted" + id + "");
}
return queue;
}
@ -289,7 +299,7 @@ public class ApiExecutionQueueService {
}
public void queueNext(ResultDTO dto) {
LoggerUtil.info("开始处理队列:" + dto.getQueueId(), dto.getReportId());
LoggerUtil.info("开始处理队列:" + dto.getReportId() + "QID" + dto.getQueueId());
if (StringUtils.equals(dto.getRunType(), RunModeConstants.PARALLEL.toString())) {
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andQueueIdEqualTo(dto.getQueueId()).andTestIdEqualTo(dto.getTestId());
@ -320,7 +330,7 @@ public class ApiExecutionQueueService {
return;
}
}
LoggerUtil.info("开始处理执行队列:" + executionQueue.getId() + " 当前资源是:" + dto.getTestId(), dto.getReportId());
LoggerUtil.info("开始处理执行队列:" + executionQueue.getId() + " 当前资源是:" + dto.getTestId() + "报告ID" + dto.getReportId());
if (executionQueue.getQueue() != null && StringUtils.isNotEmpty(executionQueue.getQueue().getTestId())) {
if (StringUtils.equals(dto.getRunType(), RunModeConstants.SERIAL.toString())) {
LoggerUtil.info("当前执行队列是:" + JSON.toJSONString(executionQueue.getQueue()));
@ -344,14 +354,14 @@ public class ApiExecutionQueueService {
apiScenarioReportService.margeReport(reportId, dto.getRunMode(), dto.getConsole());
}
queueMapper.deleteByPrimaryKey(dto.getQueueId());
LoggerUtil.info("Queue execution ends" + dto.getQueueId(), dto.getReportId());
LoggerUtil.info("Queue execution ends" + dto.getQueueId());
}
ApiExecutionQueueDetailExample example = new ApiExecutionQueueDetailExample();
example.createCriteria().andQueueIdEqualTo(dto.getQueueId()).andTestIdEqualTo(dto.getTestId());
executionQueueDetailMapper.deleteByExample(example);
}
LoggerUtil.info("处理队列结束:" + dto.getQueueId(), dto.getReportId());
LoggerUtil.info("处理队列结束:" + dto.getReportId() + "QID" + dto.getQueueId());
}
public void defendQueue() {
@ -404,7 +414,7 @@ public class ApiExecutionQueueService {
// 删除串行资源锁
redisTemplate.delete(RunModeConstants.SERIAL.name() + "_" + dto.getReportId());
LoggerUtil.info("超时处理报告处理,进入下一个执行", report.getId());
LoggerUtil.info("超时处理报告:【" + report.getId() + "】进入下一个执行");
dto.setTestPlanReportId(queue.getReportId());
dto.setReportId(queue.getReportId());
dto.setRunMode(queue.getRunMode());
@ -507,20 +517,4 @@ public class ApiExecutionQueueService {
}
}
}
/**
* 性能测试监听检查
*
* @param loadTestReport
*/
public void checkExecutionQueueByLoadTest(LoadTestReport loadTestReport) {
ApiExecutionQueueDetailExample detailExample = new ApiExecutionQueueDetailExample();
detailExample.createCriteria().andReportIdEqualTo(loadTestReport.getId());
executionQueueDetailMapper.deleteByExample(detailExample);
List<String> testPlanReportIdList = testPlanReportService.getTestPlanReportIdsByLoadTestReportId(loadTestReport.getId());
for (String testPlanReportId : testPlanReportIdList) {
this.testPlanReportTestEnded(testPlanReportId);
}
}
}

View File

@ -27,7 +27,10 @@ public interface ExtLoadTestReportMapper {
List<PlanReportCaseDTO> selectForPlanReport(@Param("ids") List<String> reportIds);
int updateReportVumStatus(String reportId,String reportKey ,String nextStatus, String preStatus);
int updateReportVumStatus(String reportId, String reportKey, String nextStatus, String preStatus);
List<FileMetadata> getFileMetadataById(@Param("reportId") String reportId);
List<String> selectReportIdByTestId(@Param("testId") String testId);
}

View File

@ -201,4 +201,8 @@
WHERE report_id = #{reportId}
ORDER BY sort
</select>
<select id="selectReportIdByTestId" resultType="string">
SELECT id FROM load_test_report WHERE test_id = #{testId} AND `status` !='Completed'
</select>
</mapper>

View File

@ -1,7 +1,7 @@
package io.metersphere.performance.notice;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.exec.perf.PerfQueueService;
import io.metersphere.base.domain.LoadTestReport;
import io.metersphere.commons.consumer.LoadTestFinishEvent;
import io.metersphere.commons.utils.LogUtil;
@ -13,12 +13,12 @@ import javax.annotation.Resource;
@Component
public class PerformanceQueueEvent implements LoadTestFinishEvent {
@Resource
ApiExecutionQueueService apiExecutionQueueService;
private PerfQueueService perfQueueService;
public void sendNotice(LoadTestReport loadTestReport) {
//删除性能测试在执行队列中的数据 在测试计划执行中会将性能测试执行添加到执行队列用于判断整个测试计划到执行进度
try {
apiExecutionQueueService.checkExecutionQueueByLoadTest(loadTestReport);
perfQueueService.queueNext(loadTestReport);
} catch (Exception e) {
LogUtil.error("PerformanceQueueEvent error. id:" + loadTestReport.getId());
}

View File

@ -20,4 +20,8 @@ public class RunTestPlanRequest extends TestPlanRequest {
* 资源池ID
*/
private String ownTestPoolId;
/**
* 测试计划中生成的报告ID
*/
private String reportId;
}

View File

@ -445,7 +445,7 @@ public class PerformanceTestService {
LoadTestReportWithBLOBs testReport = new LoadTestReportWithBLOBs();
testReport.setId(UUID.randomUUID().toString());
testReport.setId(StringUtils.isNotEmpty(request.getReportId()) ? request.getReportId() : UUID.randomUUID().toString());
testReport.setCreateTime(System.currentTimeMillis());
testReport.setUpdateTime(System.currentTimeMillis());
testReport.setTestId(loadTest.getId());

View File

@ -3,7 +3,7 @@ package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.api.exec.utils.NamedThreadFactory;
import io.metersphere.api.exec.perf.PerfExecService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
@ -13,11 +13,10 @@ import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanLoadCaseMapper;
import io.metersphere.commons.constants.PerformanceTestStatus;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.TestPlanLoadCaseStatus;
import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.controller.request.ResetOrderRequest;
import io.metersphere.dto.LoadTestDTO;
@ -30,8 +29,6 @@ import io.metersphere.track.request.testplan.LoadCaseReportBatchRequest;
import io.metersphere.track.request.testplan.LoadCaseReportRequest;
import io.metersphere.track.request.testplan.LoadCaseRequest;
import io.metersphere.track.request.testplan.RunBatchTestPlanRequest;
import io.metersphere.track.service.utils.ParallelExecTask;
import io.metersphere.track.service.utils.SerialExecTask;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
@ -44,9 +41,6 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
@Service
@ -73,6 +67,8 @@ public class TestPlanLoadCaseService {
private TestPlanService testPlanService;
@Resource
private ExtLoadTestMapper extLoadTestMapper;
@Resource
private PerfExecService perfExecService;
public Pager<List<LoadTestDTO>> relevanceList(LoadCaseRequest request, int goPage, int pageSize) {
List<OrderRequest> orders = ServiceUtils.getDefaultSortOrder(request.getOrders());
@ -83,7 +79,7 @@ public class TestPlanLoadCaseService {
}
List<String> ids = extTestPlanLoadCaseMapper.selectIdsNotInPlan(request);
if (CollectionUtils.isEmpty(ids)) {
return PageUtils.setPageInfo(PageHelper.startPage(goPage, pageSize, true), new ArrayList <>());
return PageUtils.setPageInfo(PageHelper.startPage(goPage, pageSize, true), new ArrayList<>());
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
QueryTestPlanRequest newRequest = new QueryTestPlanRequest();
@ -172,38 +168,9 @@ public class TestPlanLoadCaseService {
}
public void runBatch(RunBatchTestPlanRequest request) {
try {
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
serialRun(request);
} else {
ExecutorService executorService = Executors.newFixedThreadPool(request.getRequests().size(), new NamedThreadFactory("TestPlanLoadCaseService"));
request.getRequests().forEach(item -> {
executorService.submit(new ParallelExecTask(performanceTestService, testPlanLoadCaseMapper, item));
});
}
} catch (Exception e) {
if (StringUtils.isNotEmpty(e.getMessage())) {
MSException.throwException("测试正在运行, 请等待!");
} else {
MSException.throwException("请求参数错误,请刷新后执行!");
}
}
}
private void serialRun(RunBatchTestPlanRequest request) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(request.getRequests().size(), new NamedThreadFactory("TestPlanLoadCaseService-serial"));
for (RunTestPlanRequest runTestPlanRequest : request.getRequests()) {
Future<LoadTestReportWithBLOBs> future = executorService.submit(new SerialExecTask(performanceTestService, testPlanLoadCaseMapper, loadTestReportMapper, runTestPlanRequest));
LoadTestReportWithBLOBs report = future.get();
// 如果开启失败结束执行则判断返回结果状态
if (request.getConfig().isOnSampleError()) {
TestPlanLoadCaseExample example = new TestPlanLoadCaseExample();
example.createCriteria().andLoadReportIdEqualTo(report.getId());
List<TestPlanLoadCase> cases = testPlanLoadCaseMapper.selectByExample(example);
if (CollectionUtils.isEmpty(cases) || !cases.get(0).getStatus().equals(TestPlanLoadCaseStatus.success.name())) {
break;
}
}
if (request != null && CollectionUtils.isNotEmpty(request.getRequests())) {
Map<String, String> reqMap = request.getRequests().stream().collect(Collectors.toMap(RunTestPlanRequest::getTestPlanLoadId, a -> a.getId(), (k1, k2) -> k1));
perfExecService.run(null, request.getConfig(), ReportTriggerMode.BATCH.name(), reqMap);
}
}
@ -429,12 +396,9 @@ public class TestPlanLoadCaseService {
}
public List<TestPlanLoadCaseDTO> buildCases(List<TestPlanLoadCaseDTO> cases) {
// Map<String, Project> projectMap = ServiceUtils.getProjectMap(
// failureCases.stream().map(TestPlanCaseDTO::getProjectId).collect(Collectors.toList()));
Map<String, String> userNameMap = ServiceUtils.getUserNameMap(
cases.stream().map(TestPlanLoadCaseDTO::getCreateUser).collect(Collectors.toList()));
cases.forEach(item -> {
// item.setProjectName(projectMap.get(item.getProjectId()).getName());
item.setUserName(userNameMap.get(item.getCreateUser()));
});
return cases;

View File

@ -12,7 +12,11 @@ import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.dto.definition.ParamsDTO;
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
import io.metersphere.api.service.*;
import io.metersphere.api.exec.perf.PerfExecService;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiDefinitionService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
@ -30,7 +34,6 @@ import io.metersphere.performance.base.*;
import io.metersphere.performance.dto.LoadTestExportJmx;
import io.metersphere.performance.dto.MetricData;
import io.metersphere.performance.dto.Monitor;
import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.performance.service.MetricQueryService;
import io.metersphere.performance.service.PerformanceReportService;
import io.metersphere.performance.service.PerformanceTestService;
@ -58,8 +61,6 @@ import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.TriggerBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
@ -80,8 +81,6 @@ import java.util.stream.Stream;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanService {
Logger testPlanLog = LoggerFactory.getLogger("testPlanExecuteLog");
@Resource
ExtScheduleMapper extScheduleMapper;
@Resource
@ -132,8 +131,6 @@ public class TestPlanService {
@Resource
private ExtTestPlanScenarioCaseMapper extTestPlanScenarioCaseMapper;
@Resource
private ApiExecutionQueueService apiExecutionQueueService;
@Resource
private PerformanceTestService performanceTestService;
@Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
@ -157,7 +154,7 @@ public class TestPlanService {
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ApiDefinitionService apiDefinitionService;
private PerfExecService perfExecService;
@Resource
private PerformanceReportService performanceReportService;
@Resource
@ -184,6 +181,8 @@ public class TestPlanService {
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
@Resource
private ExtApiDefinitionExecResultMapper extApiDefinitionExecResultMapper;
@Resource
private ApiDefinitionService apiDefinitionService;
public synchronized TestPlan addTestPlan(AddTestPlanRequest testPlan) {
if (getTestPlanByName(testPlan.getName()).size() > 0) {
@ -1002,7 +1001,7 @@ public class TestPlanService {
if (reportInfoDTO.getPerformanceIdMap() != null) {
//执行性能测试任务
LoggerUtil.info("开始执行测试计划性能用例 " + planReportId);
loadCaseReportMap = this.executeLoadCaseTask(planReportId, runModeConfig, triggerMode, reportInfoDTO.getPerformanceIdMap());
loadCaseReportMap = perfExecService.run(planReportId, runModeConfig, triggerMode, reportInfoDTO.getPerformanceIdMap());
}
if (apiCaseReportMap != null && scenarioReportMap != null && loadCaseReportMap != null) {
LoggerUtil.info("开始生成测试计划报告内容 " + planReportId);
@ -1067,54 +1066,6 @@ public class TestPlanService {
return returnMap;
}
private Map<String, String> executeLoadCaseTask(String planReportId, RunModeConfigDTO runModeConfig, String triggerMode, Map<String, String> performanceIdMap) {
Map<String, String> loadCaseReportMap = new HashMap<>();
for (Map.Entry<String, String> entry : performanceIdMap.entrySet()) {
String id = entry.getKey();
String caseID = entry.getValue();
RunTestPlanRequest performanceRequest = new RunTestPlanRequest();
performanceRequest.setId(caseID);
performanceRequest.setTestPlanLoadId(id);
if (StringUtils.isNotBlank(runModeConfig.getResourcePoolId())) {
performanceRequest.setTestResourcePoolId(runModeConfig.getResourcePoolId());
}
if (StringUtils.equals(ReportTriggerMode.API.name(), triggerMode)) {
performanceRequest.setTriggerMode(ReportTriggerMode.TEST_PLAN_API.name());
} else {
performanceRequest.setTriggerMode(ReportTriggerMode.TEST_PLAN_SCHEDULE.name());
}
String reportId = null;
try {
reportId = performanceTestService.run(performanceRequest);
if (reportId != null) {
loadCaseReportMap.put(id, reportId);
//更新关联处的报告
TestPlanLoadCaseWithBLOBs loadCase = new TestPlanLoadCaseDTO();
loadCase.setId(id);
loadCase.setLoadReportId(reportId);
loadCase.setStatus(TestPlanLoadCaseStatus.run.name());
testPlanLoadCaseService.update(loadCase);
}
} catch (Exception e) {
TestPlanLoadCaseWithBLOBs testPlanLoadCase = new TestPlanLoadCaseWithBLOBs();
testPlanLoadCase.setId(id);
testPlanLoadCase.setLoadReportId(reportId);
testPlanLoadCase.setStatus(TestPlanLoadCaseStatus.error.name());
testPlanLoadCaseService.update(testPlanLoadCase);
LogUtil.error(e);
}
}
if (MapUtils.isNotEmpty(loadCaseReportMap)) {
//将性能测试加入到队列中
apiExecutionQueueService.add(loadCaseReportMap, null, ApiRunMode.TEST_PLAN_PERFORMANCE_TEST.name(),
planReportId, null, null, new RunModeConfigDTO());
}
return loadCaseReportMap;
}
public String getLogDetails(String id) {
TestPlan plan = testPlanMapper.selectByPrimaryKey(id);
if (plan != null) {

View File

@ -370,11 +370,13 @@ export default {
});
},
refreshStatus() {
this.refreshScheduler = setInterval(() => {
//
let arr = this.tableData.filter(data => data.status !== 'Completed' && data.status !== 'Error' && data.status !== 'Saved');
arr.length > 0 ? this.initTable() : clearInterval(this.refreshScheduler);
}, 8000);
//
// this.refreshScheduler = setInterval(() => {
// //
// let arr = this.tableData.filter(data => data.status !== 'Completed' && data.status !== 'Error' && data.status !== 'Saved');
// arr.length > 0 ? this.initTable() : clearInterval(this.refreshScheduler);
// }, 8000);
this.initTable();
},
handleDeleteBatch() {
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + "", '', {