feat(测试计划): 完成失败重跑和失败重试功能

This commit is contained in:
fit2-zhao 2022-05-17 17:46:09 +08:00 committed by f2c-ci-robot[bot]
parent 00e5395faa
commit c0744ce789
62 changed files with 1637 additions and 926 deletions

View File

@ -1,12 +1,14 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@ -20,4 +22,7 @@ public class ApiCaseRunRequest {
private String environmentId;
private RunModeConfigDTO config;
private ApiTestCaseRequest condition;
// 失败重跑
private boolean isRerun;
private Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue;
}

View File

@ -32,4 +32,9 @@ public class ApiScenarioReportDTO {
private long totalAssertions = 0;
private long passAssertions = 0;
private long errorCodeAssertions = 0;
private String actuator;
private String name;
private String envConfig;
}

View File

@ -18,6 +18,8 @@ public class StepTreeDTO {
private RequestResult value;
private String allIndex;
private String stepId;
// 某个场景未执行总量
private int unExecuteTotal;
//误报库编码
private String errorCode;

View File

@ -1,6 +1,6 @@
package io.metersphere.api.dto.automation;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.base.domain.ApiScenarioReportWithBLOBs;
import lombok.Getter;
import lombok.Setter;
@ -8,7 +8,7 @@ import java.util.List;
@Setter
@Getter
public class APIScenarioReportResult extends ApiScenarioReport {
public class APIScenarioReportResult extends ApiScenarioReportWithBLOBs {
private String testName;

View File

@ -47,4 +47,10 @@ public class RunScenarioRequest {
private String testPlanReportId;
private String requestOriginator;
// 失败重跑
private boolean isRerun;
private String serialReportId;
private Map<String, APIScenarioReportResult> reportMap;
}

View File

@ -1,10 +1,12 @@
package io.metersphere.api.dto.definition;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.dto.RunModeConfigDTO;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Setter
@Getter
@ -21,5 +23,8 @@ public class BatchRunDefinitionRequest {
//测试计划报告ID 测试计划执行时使用
private String planReportId;
// 失败重跑
private boolean rerun;
private Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue;
}

View File

@ -579,6 +579,10 @@ public class ElementUtil {
if (StringUtils.isNotEmpty(config.getScenarioId()) && StringUtils.equals(config.getReportType(), RunModeConstants.SET_REPORT.toString())) {
resourceId = config.getScenarioId() + "=" + resourceId;
}
// 跳过失败重试层
if (parent != null && StringUtils.equalsAnyIgnoreCase("RetryLoopController", parent.getType())) {
parent = parent.getParent();
}
return resourceId + "_" + ElementUtil.getFullIndexPath(parent, indexPath);
}

View File

@ -15,6 +15,7 @@ import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiScenarioReportStructureService;
import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.base.mapper.TestPlanMapper;
@ -63,6 +64,8 @@ public class ApiCaseExecuteService {
private ApiCaseResultService apiCaseResultService;
@Resource
private ApiScenarioReportStructureService apiScenarioReportStructureService;
@Resource
private ApiDefinitionExecResultMapper apiDefinitionExecResultMapper;
/**
* 测试计划case执行
@ -91,7 +94,7 @@ public class ApiCaseExecuteService {
}
LoggerUtil.debug("查询到测试计划用例 " + planApiCases.size());
Map<String, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue = request.isRerun() ? request.getExecuteQueue() : new LinkedHashMap<>();
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
@ -106,26 +109,26 @@ public class ApiCaseExecuteService {
if (request.getConfig() != null && GenerateHashTreeUtil.isResourcePool(request.getConfig().getResourcePoolId()).isPool()) {
resourcePoolId = request.getConfig().getResourcePoolId();
}
Map<String, String> planProjects = new HashMap<>();
for (TestPlanApiCase testPlanApiCase : planApiCases) {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status, caseMap, resourcePoolId);
if (planProjects.containsKey(testPlanApiCase.getTestPlanId())) {
report.setProjectId(planProjects.get(testPlanApiCase.getTestPlanId()));
} else {
TestPlan plan = CommonBeanFactory.getBean(TestPlanMapper.class).selectByPrimaryKey(testPlanApiCase.getTestPlanId());
if (plan != null) {
planProjects.put(plan.getId(), plan.getProjectId());
report.setProjectId(plan.getProjectId());
if (!request.isRerun()) {
Map<String, String> planProjects = new HashMap<>();
for (TestPlanApiCase testPlanApiCase : planApiCases) {
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status, caseMap, resourcePoolId);
if (planProjects.containsKey(testPlanApiCase.getTestPlanId())) {
report.setProjectId(planProjects.get(testPlanApiCase.getTestPlanId()));
} else {
TestPlan plan = CommonBeanFactory.getBean(TestPlanMapper.class).selectByPrimaryKey(testPlanApiCase.getTestPlanId());
if (plan != null) {
planProjects.put(plan.getId(), plan.getProjectId());
report.setProjectId(plan.getProjectId());
}
}
executeQueue.put(testPlanApiCase.getId(), report);
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
LoggerUtil.debug("预生成测试用例结果报告:" + report.getName() + ", ID " + report.getId());
}
executeQueue.put(testPlanApiCase.getId(), report);
responseDTOS.add(new MsExecResponseDTO(testPlanApiCase.getId(), report.getId(), request.getTriggerMode()));
LoggerUtil.debug("预生成测试用例结果报告:" + report.getName() + ", ID " + report.getId());
apiCaseResultService.batchSave(executeQueue);
}
apiCaseResultService.batchSave(executeQueue);
LoggerUtil.debug("开始生成测试计划队列");
String reportType = request.getConfig().getReportType();
String poolId = request.getConfig().getResourcePoolId();
@ -227,22 +230,30 @@ public class ApiCaseExecuteService {
this.checkEnv(caseList);
}
// 集合报告设置
String serialReportId = null;
if (StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
String serialReportId = request.isRerun() ? request.getReportId() : null;
if (!request.isRerun() && StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
&& StringUtils.isNotEmpty(request.getConfig().getReportName())) {
serialReportId = UUID.randomUUID().toString();
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.initBase(null, APITestStatus.Running.name(), serialReportId, request.getConfig());
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.initBase(null, APITestStatus.Running.name(), serialReportId, request.getConfig());
report.setName(request.getConfig().getReportName());
report.setProjectId(request.getProjectId());
report.setReportType(ReportTypeConstants.API_INTEGRATED.name());
report.setVersionId(caseList.get(0).getVersionId());
Map<String, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue = new LinkedHashMap<>();
executeQueue.put(serialReportId, report);
apiScenarioReportStructureService.save(serialReportId, new ArrayList<>());
apiCaseResultService.batchSave(executeQueue);
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(request.getIds()), report.getId(), request.getTriggerMode()));
}
// 失败重跑报告状态更新
if (request.isRerun()) {
ApiDefinitionExecResultWithBLOBs result = new ApiDefinitionExecResultWithBLOBs();
result.setId(serialReportId);
result.setStatus(APITestStatus.Rerunning.name());
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
}
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (request.getCondition() == null || !request.getCondition().isSelectAll()) {
@ -258,28 +269,30 @@ public class ApiCaseExecuteService {
request.setTriggerMode(ApiRunMode.DEFINITION.name());
}
Map<String, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue = request.isRerun() ? request.getExecuteQueue() : new LinkedHashMap<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
for (int i = 0; i < caseList.size(); i++) {
ApiTestCaseWithBLOBs caseWithBLOBs = caseList.get(i);
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.initBase(caseWithBLOBs.getId(), APITestStatus.Running.name(), null, request.getConfig());
report.setStatus(status);
report.setName(caseWithBLOBs.getName());
report.setProjectId(caseWithBLOBs.getProjectId());
report.setVersionId(caseWithBLOBs.getVersionId());
report.setCreateTime(System.currentTimeMillis() + i);
if (StringUtils.isNotEmpty(serialReportId)) {
report.setIntegratedReportId(serialReportId);
}
executeQueue.put(caseWithBLOBs.getId(), report);
if (!StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
responseDTOS.add(new MsExecResponseDTO(caseWithBLOBs.getId(), report.getId(), request.getTriggerMode()));
// 第一次执行非重跑的报告处理
if (!request.isRerun()) {
for (int i = 0; i < caseList.size(); i++) {
ApiTestCaseWithBLOBs caseWithBLOBs = caseList.get(i);
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.initBase(caseWithBLOBs.getId(), APITestStatus.Running.name(), null, request.getConfig());
report.setStatus(status);
report.setName(caseWithBLOBs.getName());
report.setProjectId(caseWithBLOBs.getProjectId());
report.setVersionId(caseWithBLOBs.getVersionId());
report.setCreateTime(System.currentTimeMillis() + i);
if (StringUtils.isNotEmpty(serialReportId)) {
report.setIntegratedReportId(serialReportId);
}
executeQueue.put(caseWithBLOBs.getId(), report);
if (!StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
responseDTOS.add(new MsExecResponseDTO(caseWithBLOBs.getId(), report.getId(), request.getTriggerMode()));
}
}
apiCaseResultService.batchSave(executeQueue);
}
apiCaseResultService.batchSave(executeQueue);
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());

View File

@ -5,7 +5,7 @@ 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;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.BaseSystemConfigDTO;
@ -32,7 +32,7 @@ public class ApiCaseParallelExecuteService {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public void parallel(Map<String, ApiDefinitionExecResult> executeQueue, RunModeConfigDTO config, DBTestQueue executionQueue, String runMode) {
public void parallel(Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue, RunModeConfigDTO config, DBTestQueue executionQueue, String runMode) {
BooleanPool pool = GenerateHashTreeUtil.isResourcePool(config.getResourcePoolId());
// 初始化分配策略
if (pool.isPool()) {
@ -44,7 +44,7 @@ public class ApiCaseParallelExecuteService {
if (Thread.currentThread().isInterrupted()) {
break;
}
ApiDefinitionExecResult result = executeQueue.get(testId);
ApiDefinitionExecResultWithBLOBs result = executeQueue.get(testId);
String reportId = result.getId();
JmeterRunRequestDTO runRequest = new JmeterRunRequestDTO(testId, reportId, runMode, null);
runRequest.setPool(pool);
@ -53,6 +53,10 @@ public class ApiCaseParallelExecuteService {
runRequest.setReportType(executionQueue.getReportType());
runRequest.setRunType(RunModeConstants.PARALLEL.toString());
runRequest.setQueueId(executionQueue.getId());
runRequest.setRetryNum(config.getRetryNum());
runRequest.setRetryEnable(config.isRetryEnable());
Map<String, Object> extendedParameters = new HashMap<>();
extendedParameters.put("userId", result.getUserId());
runRequest.setExtendedParameters(extendedParameters);

View File

@ -82,7 +82,7 @@ public class ApiExecuteService {
request.setEnvironmentId(extApiTestCaseMapper.getApiCaseEnvironment(request.getCaseId()));
}
//提前生成报告
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.add(caseWithBLOBs.getId(), APITestStatus.Running.name(), request.getReportId(),Objects.requireNonNull(SessionUtils.getUser()).getId());
ApiDefinitionExecResultWithBLOBs report = ApiDefinitionExecResultUtil.add(caseWithBLOBs.getId(), APITestStatus.Running.name(), request.getReportId(),Objects.requireNonNull(SessionUtils.getUser()).getId());
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(ApiRunMode.JENKINS.name());
report.setType(ApiRunMode.JENKINS.name());

View File

@ -0,0 +1,5 @@
package io.metersphere.api.exec.api;
public interface ApiRetryOnFailureService {
public String retry(String data, long retryNum);
}

View File

@ -15,9 +15,7 @@ import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiScenarioReportStructureService;
import io.metersphere.api.service.TcpApiParamService;
import io.metersphere.base.domain.ApiScenarioExample;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
@ -103,7 +101,7 @@ public class ApiScenarioExecuteService {
}
// 生成集成报告
String serialReportId = null;
String serialReportId = request.isRerun() && GenerateHashTreeUtil.isSetReport(request.getConfig()) ? request.getSerialReportId() : null;
LoggerUtil.info("Scenario run-执行脚本装载-根据条件查询所有场景 ");
List<ApiScenarioWithBLOBs> apiScenarios = this.get(request);
// 只有一个场景且没有测试步骤则提示
@ -114,7 +112,7 @@ public class ApiScenarioExecuteService {
LoggerUtil.info("Scenario run-执行脚本装载-开始针对所有执行场景进行环境检查");
apiScenarioEnvService.checkEnv(request, apiScenarios);
// 集合报告设置
if (StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
if (!request.isRerun() && StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
&& StringUtils.isNotEmpty(request.getConfig().getReportName())) {
if (request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
request.setExecuteType(ExecuteType.Completed.name());
@ -144,25 +142,37 @@ public class ApiScenarioExecuteService {
return responseDTOS;
}
if (GenerateHashTreeUtil.isSetReport(request.getConfig())) {
LoggerUtil.info("Scenario run-执行脚本装载-初始化集成报告:" + serialReportId);
request.getConfig().setReportId(UUID.randomUUID().toString());
// 失败重跑更新报告状态
if (request.isRerun()) {
ApiScenarioReportWithBLOBs report = new ApiScenarioReportWithBLOBs();
report.setId(serialReportId);
report.setStatus(APITestStatus.Rerunning.name());
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
} else {
LoggerUtil.info("Scenario run-执行脚本装载-初始化集成报告:" + serialReportId);
request.getConfig().setReportId(UUID.randomUUID().toString());
String reportScenarioIds = JSON.toJSONString(CollectionUtils.isNotEmpty(scenarioIds) && scenarioIds.size() > 50 ? scenarioIds.subList(0, 50) : scenarioIds);
APIScenarioReportResult report = apiScenarioReportService.init(request.getConfig().getReportId(), reportScenarioIds,
scenarioNames.toString(), request.getTriggerMode(), ExecuteType.Saved.name(), request.getProjectId(),
request.getReportUserID(), request.getConfig());
String reportScenarioIds = JSON.toJSONString(CollectionUtils.isNotEmpty(scenarioIds) && scenarioIds.size() > 50 ? scenarioIds.subList(0, 50) : scenarioIds);
APIScenarioReportResult report = apiScenarioReportService.init(request.getConfig().getReportId(), reportScenarioIds,
scenarioNames.toString(), request.getTriggerMode(), ExecuteType.Saved.name(), request.getProjectId(),
request.getReportUserID(), request.getConfig());
report.setVersionId(apiScenarios.get(0).getVersionId());
report.setName(request.getConfig().getReportName());
report.setId(serialReportId);
report.setReportType(ReportTypeConstants.SCENARIO_INTEGRATED.name());
request.getConfig().setAmassReport(serialReportId);
report.setStatus(APITestStatus.Running.name());
apiScenarioReportMapper.insert(report);
report.setVersionId(apiScenarios.get(0).getVersionId());
report.setName(request.getConfig().getReportName());
report.setId(serialReportId);
report.setReportType(ReportTypeConstants.SCENARIO_INTEGRATED.name());
request.getConfig().setAmassReport(serialReportId);
if (request.getConfig() != null) {
report.setEnvConfig(JSON.toJSONString(request.getConfig()));
}
report.setStatus(APITestStatus.Running.name());
apiScenarioReportMapper.insert(report);
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(scenarioIds), serialReportId, request.getRunMode()));
reportStructureService.save(apiScenarios, serialReportId, request.getConfig().getReportType());
responseDTOS.add(new MsExecResponseDTO(JSON.toJSONString(scenarioIds), serialReportId, request.getRunMode()));
reportStructureService.save(apiScenarios, serialReportId, request.getConfig().getReportType());
}
}
String reportType = request.getConfig().getReportType();
String planReportId = StringUtils.isNotEmpty(request.getTestPlanReportId()) ? request.getTestPlanReportId() : serialReportId;
// 生成执行队列
@ -170,8 +180,9 @@ public class ApiScenarioExecuteService {
, ApiRunMode.SCENARIO.name(), planReportId, reportType, request.getRunMode(), request.getConfig());
// 预生成报告
apiScenarioReportService.batchSave(executeQueue, serialReportId, request.getRunMode(), responseDTOS);
if (!request.isRerun() && !GenerateHashTreeUtil.isSetReport(request.getConfig())) {
apiScenarioReportService.batchSave(executeQueue, serialReportId, request.getRunMode(), responseDTOS);
}
// 开始执行
String finalSerialReportId = serialReportId;
Thread thread = new Thread(new Runnable() {
@ -190,7 +201,7 @@ public class ApiScenarioExecuteService {
return responseDTOS;
}
private List<ApiScenarioWithBLOBs> get(RunScenarioRequest request) {
public List<ApiScenarioWithBLOBs> get(RunScenarioRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(),
(query) -> extApiScenarioMapper.selectIdsByQuery(query));
List<String> ids = request.getIds();
@ -248,9 +259,15 @@ public class ApiScenarioExecuteService {
projectId = scenario.getProjectId();
}
APIScenarioReportResult report = apiScenarioReportService.init(reportId, testPlanScenarioId, scenario.getName(), request.getTriggerMode(),
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig());
APIScenarioReportResult report = request.isRerun() ? request.getReportMap().get(scenarioId) :
apiScenarioReportService.init(reportId, testPlanScenarioId, scenario.getName(), request.getTriggerMode(),
request.getExecuteType(), projectId, request.getReportUserID(), request.getConfig());
if (report == null) {
report = request.getReportMap().get(testPlanScenarioId);
}
if (report == null) {
return;
}
report.setVersionId(scenario.getVersionId());
scenarioIds.add(scenario.getId());
RunModeDataDTO runModeDataDTO = new RunModeDataDTO();
@ -261,6 +278,9 @@ public class ApiScenarioExecuteService {
runModeDataDTO.setScenario(scenario);
executeQueue.put(report.getId(), runModeDataDTO);
scenarioNames.append(scenario.getName()).append(",");
if (request.getConfig() != null) {
report.setEnvConfig(JSON.toJSONString(request.getConfig()));
}
// 生成文档结构
if (!StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())) {
reportStructureService.save(scenario, report.getId(), request.getConfig() != null ? request.getConfig().getReportType() : null);

View File

@ -50,6 +50,8 @@ public class ApiScenarioParallelService {
runRequest.setTestPlanReportId(request.getTestPlanReportId());
runRequest.setPlatformUrl(GenerateHashTreeUtil.getPlatformUrl(baseInfo, runRequest, executionQueue.getDetailMap().get(reportId)));
runRequest.setRunType(RunModeConstants.PARALLEL.toString());
runRequest.setRetryNum(request.getConfig().getRetryNum());
runRequest.setRetryEnable(request.getConfig().isRetryEnable());
// 本地执行生成hashTree
if (!pool.isPool()) {
runRequest.setHashTree(GenerateHashTreeUtil.generateHashTree(dataDTO.getScenario(), dataDTO.getPlanEnvMap(), runRequest));

View File

@ -13,6 +13,7 @@ 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.utils.GenerateHashTreeUtil;
import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.jmeter.utils.SmoothWeighted;
@ -23,7 +24,10 @@ import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.*;
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;
@ -37,7 +41,10 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@Service
public class ApiScenarioSerialService {
@ -70,7 +77,8 @@ public class ApiScenarioSerialService {
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 (!StringUtils.equals(executionQueue.getReportType(), RunModeConstants.SET_REPORT.toString())
|| StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiRunMode.DEFINITION.name())) {
@ -87,7 +95,7 @@ public class ApiScenarioSerialService {
LoggerUtil.info("进入串行模式,准备执行资源:[ " + report.getName() + " ], 报告ID [ " + report.getId() + " ]");
}
} else {
ApiDefinitionExecResult execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
ApiDefinitionExecResultWithBLOBs execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (execResult != null) {
runRequest.setExtendedParameters(new HashMap<String, Object>() {{
this.put("userId", execResult.getUserId());
@ -180,6 +188,14 @@ public class ApiScenarioSerialService {
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());
data = StringUtils.isNotEmpty(retryData) ? retryData : data;
}
HashTree jmeterHashTree = new HashTree();
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
@ -189,7 +205,7 @@ public class ApiScenarioSerialService {
group.setName(runRequest.getReportId());
group.setProjectId(caseWithBLOBs.getProjectId());
MsTestElement testElement = parse(caseWithBLOBs, testId, envId);
MsTestElement testElement = parse(data, testId, envId);
group.setHashTree(new LinkedList<>());
group.getHashTree().add(testElement);
testPlan.getHashTree().add(group);
@ -209,9 +225,8 @@ public class ApiScenarioSerialService {
return null;
}
private MsTestElement parse(ApiTestCaseWithBLOBs caseWithBLOBs, String planId, String envId) {
private MsTestElement parse(String api, String planId, String envId) {
try {
String api = caseWithBLOBs.getRequest();
JSONObject element = JSON.parseObject(api, Feature.DisableSpecialKeyDetect);
ElementUtil.dataFormatting(element);

View File

@ -1,7 +1,8 @@
package io.metersphere.api.exec.utils;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.base.domain.ApiTestCase;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.commons.constants.ApiRunMode;
@ -16,8 +17,8 @@ import java.util.Objects;
import java.util.UUID;
public class ApiDefinitionExecResultUtil {
public static ApiDefinitionExecResult initBase(String resourceId, String status, String reportId, RunModeConfigDTO config) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
public static ApiDefinitionExecResultWithBLOBs initBase(String resourceId, String status, String reportId, RunModeConfigDTO config) {
ApiDefinitionExecResultWithBLOBs apiResult = new ApiDefinitionExecResultWithBLOBs();
if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString());
} else {
@ -37,12 +38,14 @@ public class ApiDefinitionExecResultUtil {
apiResult.setStartTime(System.currentTimeMillis());
apiResult.setType(ApiRunMode.DEFINITION.name());
apiResult.setStatus(status);
apiResult.setEnvConfig(JSON.toJSONString(config));
return apiResult;
}
public static ApiDefinitionExecResult addResult(BatchRunDefinitionRequest request, TestPlanApiCase key, String status,
Map<String, ApiTestCase> caseMap, String poolId) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
public static ApiDefinitionExecResultWithBLOBs addResult(BatchRunDefinitionRequest request, TestPlanApiCase key, String status,
Map<String, ApiTestCase> caseMap, String poolId) {
ApiDefinitionExecResultWithBLOBs apiResult = new ApiDefinitionExecResultWithBLOBs();
apiResult.setId(UUID.randomUUID().toString());
apiResult.setCreateTime(System.currentTimeMillis());
apiResult.setStartTime(System.currentTimeMillis());
@ -72,11 +75,13 @@ public class ApiDefinitionExecResultUtil {
apiResult.setType(ApiRunMode.API_PLAN.name());
apiResult.setStatus(status);
apiResult.setContent(request.getPlanReportId());
apiResult.setEnvConfig(JSON.toJSONString(request.getConfig()));
return apiResult;
}
public static ApiDefinitionExecResult add(String resourceId, String status, String reportId, String userId) {
ApiDefinitionExecResult apiResult = new ApiDefinitionExecResult();
public static ApiDefinitionExecResultWithBLOBs add(String resourceId, String status, String reportId, String userId) {
ApiDefinitionExecResultWithBLOBs apiResult = new ApiDefinitionExecResultWithBLOBs();
if (StringUtils.isEmpty(reportId)) {
apiResult.setId(UUID.randomUUID().toString());
} else {

View File

@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.EnvironmentType;
import io.metersphere.api.dto.definition.request.*;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.exec.api.ApiRetryOnFailureService;
import io.metersphere.api.jmeter.ResourcePoolCalculation;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.RemakeReportService;
@ -134,7 +135,15 @@ public class GenerateHashTreeUtil {
} else {
setScenarioEnv(scenario, item);
}
GenerateHashTreeUtil.parse(item.getScenarioDefinition(), scenario);
String data = item.getScenarioDefinition();
// 失败重试
if (runRequest.isRetryEnable() && runRequest.getRetryNum() > 0) {
ApiRetryOnFailureService apiRetryOnFailureService = CommonBeanFactory.getBean(ApiRetryOnFailureService.class);
String retryData = apiRetryOnFailureService.retry(data, runRequest.getRetryNum());
data = StringUtils.isNotEmpty(retryData) ? retryData : data;
}
GenerateHashTreeUtil.parse(data, scenario);
group.setEnableCookieShare(scenario.isEnableCookieShare());
LinkedList<MsTestElement> scenarios = new LinkedList<>();
@ -156,6 +165,8 @@ public class GenerateHashTreeUtil {
config.setScenarioId(item.getId());
config.setReportType(runRequest.getReportType());
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), config);
LogUtil.info(testPlan.getJmx(jmeterHashTree));
return jmeterHashTree;
}

View File

@ -10,38 +10,49 @@ import io.metersphere.dto.ResultDTO;
import io.metersphere.jmeter.JMeterBase;
import io.metersphere.jmeter.MsExecListener;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.samplers.SampleResult;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
public class APISingleResultListener implements MsExecListener {
private ApiExecutionQueueService apiExecutionQueueService;
private final static String RETRY = "MsRetry_";
private List<SampleResult> queues;
/**
* 参数初始化方法
*/
@Override
public void setupTest() {
queues = new ArrayList<>();
LoggerUtil.info("初始化监听");
}
@Override
public void handleTeardownTest(List<SampleResult> results, ResultDTO dto, Map<String, Object> kafkaConfig) {
LoggerUtil.info("接收到执行结果开始处理报告【" + dto.getReportId() + " 】,资源【 " + dto.getTestId() + "");
dto.setConsole(FixedCapacityUtils.getJmeterLogger(dto.getReportId()));
JMeterBase.resultFormatting(results, dto);
CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
// 暂时保留
// dto.setConsole(FixedCapacityUtils.getJmeterLogger(dto.getReportId()));
// JMeterBase.resultFormatting(results, dto);
// CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
queues.addAll(results);
}
@Override
public void testEnded(ResultDTO dto, Map<String, Object> kafkaConfig) {
try {
if (JMeterEngineCache.runningEngine.containsKey(dto.getReportId())) {
JMeterEngineCache.runningEngine.remove(dto.getReportId());
if (dto.isRetryEnable()) {
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + " 】,进入重试结果处理");
mergeRetryResults(queues);
}
JMeterBase.resultFormatting(queues, dto);
// 入库存储
CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + "" + dto.getRunMode() + " 整体执行完成");
// 全局并发队列
PoolExecBlockingQueueUtil.offer(dto.getReportId());
@ -66,6 +77,40 @@ public class APISingleResultListener implements MsExecListener {
if (FixedCapacityUtils.jmeterLogTask.containsKey(dto.getReportId())) {
FixedCapacityUtils.jmeterLogTask.remove(dto.getReportId());
}
if (JMeterEngineCache.runningEngine.containsKey(dto.getReportId())) {
JMeterEngineCache.runningEngine.remove(dto.getReportId());
}
queues.clear();
}
}
/**
* 合并掉重试结果保留最后一次重试结果
*
* @param results
*/
public void mergeRetryResults(List<SampleResult> results) {
if (CollectionUtils.isNotEmpty(results)) {
Map<String, List<SampleResult>> resultMap = results.stream().collect(Collectors.groupingBy(SampleResult::getResourceId));
List<SampleResult> list = new LinkedList<>();
resultMap.forEach((k, v) -> {
// 校验是否含重试结果
List<SampleResult> isRetryResults = v
.stream()
.filter(c -> StringUtils.isNotEmpty(c.getSampleLabel()) && c.getSampleLabel().startsWith(RETRY))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(isRetryResults) && v.size() > 1) {
Collections.sort(v, Comparator.comparing(SampleResult::getResourceId));
SampleResult sampleResult = v.get(v.size() - 1);
sampleResult.setSampleLabel(v.get(0).getSampleLabel());
list.add(sampleResult);
} else {
list.addAll(v);
}
});
results.clear();
results.addAll(list);
}
}
}

View File

@ -1,6 +1,6 @@
package io.metersphere.api.service;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
@ -16,7 +16,7 @@ public class ApiCaseResultService {
private ExtApiDefinitionExecResultMapper resultMapper;
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void batchSave(Map<String, ApiDefinitionExecResult> executeQueue) {
public void batchSave(Map<String, ApiDefinitionExecResultWithBLOBs> executeQueue) {
if (!executeQueue.isEmpty()) {
resultMapper.sqlInsert(new LinkedList<>(executeQueue.values()));
}

View File

@ -436,7 +436,7 @@ public class ApiDefinitionExecResultService {
private ApiDefinitionExecResult editResult(RequestResult item, String reportId, String console, String type, String testId, ApiDefinitionExecResultMapper batchMapper) {
if (!StringUtils.startsWithAny(item.getName(), "PRE_PROCESSOR_ENV_", "POST_PROCESSOR_ENV_")) {
ApiDefinitionExecResult saveResult = new ApiDefinitionExecResult();
ApiDefinitionExecResultWithBLOBs saveResult = new ApiDefinitionExecResultWithBLOBs();
item.getResponseResult().setConsole(console);
saveResult.setId(reportId);
//对响应内容进行进一步解析如果有附加信息比如误报库信息则根据附加信息内的数据进行其他判读

View File

@ -1107,7 +1107,7 @@ public class ApiDefinitionService {
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree()) &&
CollectionUtils.isNotEmpty(request.getTestElement().getHashTree().get(0).getHashTree()) ?
request.getTestElement().getHashTree().get(0).getHashTree().get(0).getName() : request.getId();
ApiDefinitionExecResult result = ApiDefinitionExecResultUtil.add(testId, APITestStatus.Running.name(), request.getId(), Objects.requireNonNull(SessionUtils.getUser()).getId());
ApiDefinitionExecResultWithBLOBs result = ApiDefinitionExecResultUtil.add(testId, APITestStatus.Running.name(), request.getId(), Objects.requireNonNull(SessionUtils.getUser()).getId());
result.setProjectId(request.getProjectId());
result.setTriggerMode(TriggerMode.MANUAL.name());
apiDefinitionExecResultMapper.insert(result);
@ -1129,21 +1129,21 @@ public class ApiDefinitionService {
* @return
*/
public APIReportResult getDbResult(String testId) {
ApiDefinitionExecResult result = extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId);
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectMaxResultByResourceId(testId);
return buildAPIReportResult(result);
}
public APIReportResult getByResultId(String reportId) {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(reportId);
ApiDefinitionExecResultWithBLOBs result = apiDefinitionExecResultMapper.selectByPrimaryKey(reportId);
return buildAPIReportResult(result);
}
public APIReportResult getReportById(String testId) {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(testId);
ApiDefinitionExecResultWithBLOBs result = apiDefinitionExecResultMapper.selectByPrimaryKey(testId);
return buildAPIReportResult(result);
}
public APIReportResult buildAPIReportResult(ApiDefinitionExecResult result) {
public APIReportResult buildAPIReportResult(ApiDefinitionExecResultWithBLOBs result) {
if (result == null) {
return null;
}
@ -1154,7 +1154,7 @@ public class ApiDefinitionService {
}
public APIReportResult getDbResult(String testId, String type) {
ApiDefinitionExecResult result = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(testId, type);
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(testId, type);
return buildAPIReportResult(result);
}
@ -1842,7 +1842,7 @@ public class ApiDefinitionService {
}
public APIReportResult getTestPlanApiCaseReport(String testId, String type) {
ApiDefinitionExecResult result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(testId, type);
ApiDefinitionExecResultWithBLOBs result = extApiDefinitionExecResultMapper.selectPlanApiMaxResultByTestIdAndType(testId, type);
return buildAPIReportResult(result);
}

View File

@ -98,6 +98,8 @@ public class ApiExecutionQueueService {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
@ -114,6 +116,8 @@ public class ApiExecutionQueueService {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
@ -127,6 +131,8 @@ public class ApiExecutionQueueService {
resQueue.setQueue(queue);
}
sort[0]++;
queue.setRetryEnable(config.isRetryEnable());
queue.setRetryNumber(config.getRetryNum());
queueDetails.add(queue);
detailMap.put(k, queue.getId());
});
@ -362,7 +368,7 @@ public class ApiExecutionQueueService {
ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(),
ApiRunMode.SCHEDULE_SCENARIO.name(),
ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
// 报告已经被删除则队列也删除
if (report == null) {
executionQueueDetailMapper.deleteByPrimaryKey(item.getId());
@ -394,7 +400,7 @@ public class ApiExecutionQueueService {
}
} else {
// 用例/接口超时结果处理
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(item.getReportId());
ApiDefinitionExecResultWithBLOBs result = apiDefinitionExecResultMapper.selectByPrimaryKey(item.getReportId());
if (result != null && StringUtils.equalsAnyIgnoreCase(result.getStatus(), TestPlanReportStatus.RUNNING.name())) {
result.setStatus(ScenarioStatus.Timeout.name());
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
@ -408,7 +414,7 @@ public class ApiExecutionQueueService {
List<ApiExecutionQueue> executionQueues = queueMapper.selectByExample(queueDetailExample);
if (CollectionUtils.isNotEmpty(executionQueues)) {
executionQueues.forEach(item -> {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(item.getReportId());
if (report != null && StringUtils.equalsAnyIgnoreCase(report.getStatus(), TestPlanReportStatus.RUNNING.name(), APITestStatus.Waiting.name())
&& (report.getUpdateTime() < timeout)) {
report.setStatus(ScenarioStatus.Timeout.name());

View File

@ -209,10 +209,10 @@ public class ApiScenarioReportService {
return report;
}
public ApiScenarioReport editReport(String reportType, String reportId, String status, String runMode) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
public ApiScenarioReportWithBLOBs editReport(String reportType, String reportId, String status, String runMode) {
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
if (report == null) {
report = new ApiScenarioReport();
report = new ApiScenarioReportWithBLOBs();
report.setId(reportId);
}
if (StringUtils.equals(reportType, RunModeConstants.SET_REPORT.toString())) {
@ -234,7 +234,7 @@ public class ApiScenarioReportService {
public ApiScenarioReport updateReport(APIScenarioReportResult test) {
checkNameExist(test);
ApiScenarioReport report = new ApiScenarioReport();
ApiScenarioReportWithBLOBs report = new ApiScenarioReportWithBLOBs();
report.setId(test.getId());
report.setProjectId(test.getProjectId());
report.setName(test.getName());
@ -301,7 +301,7 @@ public class ApiScenarioReportService {
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
String status = getStatus(requestResults, dto);
ApiScenarioReport report = editReport(dto.getReportType(), dto.getReportId(), status, dto.getRunMode());
ApiScenarioReportWithBLOBs report = editReport(dto.getReportType(), dto.getReportId(), status, dto.getRunMode());
if (report != null) {
if (StringUtils.isNotEmpty(dto.getTestPlanReportId()) && !testPlanReportIdList.contains(dto.getTestPlanReportId())) {
testPlanReportIdList.add(dto.getTestPlanReportId());
@ -348,21 +348,25 @@ public class ApiScenarioReportService {
public void margeReport(String reportId, String runMode) {
// 更新场景状态
if (StringUtils.equalsIgnoreCase(runMode, ApiRunMode.DEFINITION.name())) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportId);
ApiDefinitionExecResultWithBLOBs result = definitionExecResultMapper.selectByPrimaryKey(reportId);
if (!StringUtils.equalsAnyIgnoreCase(result.getStatus(), APITestStatus.Rerunning.name())) {
result.setEndTime(System.currentTimeMillis());
}
ApiDefinitionExecResultExample execResultExample = new ApiDefinitionExecResultExample();
execResultExample.createCriteria().andIntegratedReportIdEqualTo(reportId).andStatusEqualTo("Error");
long size = definitionExecResultMapper.countByExample(execResultExample);
result.setStatus(size > 0 ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name());
result.setEndTime(System.currentTimeMillis());
definitionExecResultMapper.updateByPrimaryKeySelective(result);
} else {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
if (report != null) {
if (!StringUtils.equalsAnyIgnoreCase(report.getStatus(), APITestStatus.Rerunning.name())) {
report.setEndTime(System.currentTimeMillis());
}
ApiScenarioReportResultExample example = new ApiScenarioReportResultExample();
example.createCriteria().andReportIdEqualTo(reportId).andStatusEqualTo(ScenarioStatus.Error.name());
long size = apiScenarioReportResultMapper.countByExample(example);
report.setStatus(size > 0 ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name());
report.setEndTime(System.currentTimeMillis());
// 更新报告
apiScenarioReportMapper.updateByPrimaryKey(report);
}
@ -828,6 +832,9 @@ public class ApiScenarioReportService {
report.setProjectId(projectId);
report.setScenarioName(scenarioName);
report.setScenarioId(scenarioId);
if (config != null) {
report.setEnvConfig(JSON.toJSONString(config));
}
report.setReportType(ReportTypeConstants.SCENARIO_INDEPENDENT.name());
return report;
}
@ -899,7 +906,7 @@ public class ApiScenarioReportService {
public void reName(ApiScenarioReport reportRequest) {
if (StringUtils.equalsIgnoreCase(reportRequest.getReportType(), ReportTypeConstants.API_INDEPENDENT.name())) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportRequest.getId());
ApiDefinitionExecResultWithBLOBs result = definitionExecResultMapper.selectByPrimaryKey(reportRequest.getId());
if (result != null) {
result.setName(reportRequest.getName());
definitionExecResultMapper.updateByPrimaryKeySelective(result);

View File

@ -69,6 +69,18 @@ public class ApiScenarioReportStructureService {
this.save(reportId, dtoList);
}
public List<StepTreeDTO> get(List<ApiScenarioWithBLOBs> apiScenarios, String reportType) {
List<StepTreeDTO> dtoList = new LinkedList<>();
for (ApiScenarioWithBLOBs bos : apiScenarios) {
StepTreeDTO dto = dataFormatting(bos, reportType);
dtoList.add(dto);
}
if (LoggerUtil.getLogger().isDebugEnabled()) {
LoggerUtil.debug("Scenario run-执行脚本装载-生成场景报告结构:" + JSON.toJSONString(dtoList));
}
return dtoList;
}
public void saveUi(List<UiScenarioWithBLOBs> uiScenarios, String reportId, String reportType) {
List<StepTreeDTO> dtoList = new LinkedList<>();
for (UiScenarioWithBLOBs bos : uiScenarios) {
@ -104,6 +116,17 @@ public class ApiScenarioReportStructureService {
mapper.insert(structure);
}
public void update(String reportId, List<StepTreeDTO> dtoList) {
ApiScenarioReportStructureExample example = new ApiScenarioReportStructureExample();
example.createCriteria().andReportIdEqualTo(reportId);
List<ApiScenarioReportStructureWithBLOBs> structures = mapper.selectByExampleWithBLOBs(example);
if (CollectionUtils.isNotEmpty(structures)) {
ApiScenarioReportStructureWithBLOBs structure = structures.get(0);
structure.setResourceTree(JSON.toJSONString(dtoList).getBytes(StandardCharsets.UTF_8));
mapper.updateByPrimaryKeySelective(structure);
}
}
public void update(String reportId, String console) {
ApiScenarioReportStructureExample example = new ApiScenarioReportStructureExample();
example.createCriteria().andReportIdEqualTo(reportId);
@ -225,6 +248,7 @@ public class ApiScenarioReportStructureService {
private void calculateStep(List<StepTreeDTO> dtoList, AtomicLong stepTotal, AtomicLong stepError, AtomicLong stepErrorCode, AtomicLong stepUnExecute) {
for (StepTreeDTO root : dtoList) {
int unExecSize = 0;
if (CollectionUtils.isNotEmpty(root.getChildren())) {
stepTotal.set((stepTotal.longValue() + root.getChildren().size()));
for (StepTreeDTO step : root.getChildren()) {
@ -234,9 +258,11 @@ public class ApiScenarioReportStructureService {
stepErrorCode.set(stepErrorCode.longValue() + 1);
} else if (!StringUtils.equalsIgnoreCase(step.getTotalStatus(), "success")) {
stepUnExecute.set(stepUnExecute.longValue() + 1);
unExecSize++;
}
}
}
root.setUnExecuteTotal(unExecSize);
}
}
@ -413,10 +439,10 @@ public class ApiScenarioReportStructureService {
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
example.createCriteria().andIntegratedReportIdEqualTo(reportId);
example.setOrderByClause("create_time asc");
List<ApiDefinitionExecResult> reportResults = definitionExecResultMapper.selectByExampleWithBLOBs(example);
List<ApiDefinitionExecResultWithBLOBs> reportResults = definitionExecResultMapper.selectByExampleWithBLOBs(example);
List<ApiDefinitionExecResultVo> resultVos = new LinkedList<>();
for (int i = 0; i < reportResults.size(); i++) {
ApiDefinitionExecResult item = reportResults.get(i);
ApiDefinitionExecResultWithBLOBs item = reportResults.get(i);
if (StringUtils.equalsIgnoreCase(item.getErrorCode(), "null")) {
item.setErrorCode(null);
}
@ -502,11 +528,15 @@ public class ApiScenarioReportStructureService {
}
public ApiScenarioReportDTO assembleReport(String reportId, boolean selectReportContent) {
ApiScenarioReport report = scenarioReportMapper.selectByPrimaryKey(reportId);
ApiScenarioReportWithBLOBs report = scenarioReportMapper.selectByPrimaryKey(reportId);
if (report != null && report.getReportType().equals(ReportTypeConstants.API_INTEGRATED.name())) {
return this.apiIntegratedReport(reportId);
} else {
return this.getReport(reportId, selectReportContent);
ApiScenarioReportDTO dto = this.getReport(reportId, selectReportContent);
dto.setActuator(report.getActuator());
dto.setName(report.getName());
dto.setEnvConfig(report.getEnvConfig());
return dto;
}
}

View File

@ -40,7 +40,7 @@ public class RemakeReportService {
try {
// 清理零时报告
if (StringUtils.equalsAnyIgnoreCase(request.getRunMode(), ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name())) {
ApiDefinitionExecResult result = execResultMapper.selectByPrimaryKey(request.getReportId());
ApiDefinitionExecResultWithBLOBs result = execResultMapper.selectByPrimaryKey(request.getReportId());
if (result != null) {
result.setStatus("error");
result.setEndTime(System.currentTimeMillis());
@ -60,7 +60,7 @@ public class RemakeReportService {
}
}
} else if (StringUtils.equals(request.getRunMode(), ApiRunMode.DEFINITION.name())) {
ApiDefinitionExecResult result = execResultMapper.selectByPrimaryKey(request.getReportId());
ApiDefinitionExecResultWithBLOBs result = execResultMapper.selectByPrimaryKey(request.getReportId());
if (result != null) {
result.setStatus("error");
result.setEndTime(System.currentTimeMillis());
@ -89,7 +89,7 @@ public class RemakeReportService {
apiScenarioReportMapper.updateByPrimaryKey(report);
}
} else if (StringUtils.equalsAny(request.getRunMode(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
if (report != null) {
report.setEndTime(System.currentTimeMillis());
report.setStatus(APITestStatus.Error.name());
@ -108,7 +108,7 @@ public class RemakeReportService {
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
}
} else {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
if (report != null) {
report.setStatus(APITestStatus.Error.name());
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
@ -135,7 +135,7 @@ public class RemakeReportService {
}
}
public void remakeScenario(String runMode, String scenarioId, ApiScenarioWithBLOBs scenarioWithBLOBs, ApiScenarioReport report) {
public void remakeScenario(String runMode, String scenarioId, ApiScenarioWithBLOBs scenarioWithBLOBs, ApiScenarioReportWithBLOBs report) {
// 生成失败报告
if (StringUtils.equalsAny(runMode, ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name(), ApiRunMode.SCENARIO_PLAN.name())) {
TestPlanApiScenario testPlanApiScenario = testPlanApiScenarioMapper.selectByPrimaryKey(scenarioId);

View File

@ -209,7 +209,7 @@ public class TestResultService {
}
}
} else if (StringUtils.equals(dto.getRunMode(), ApiRunMode.DEFINITION.name())) {
ApiDefinitionExecResult record = new ApiDefinitionExecResult();
ApiDefinitionExecResultWithBLOBs record = new ApiDefinitionExecResultWithBLOBs();
record.setId(dto.getReportId());
record.setStatus("STOP");

View File

@ -38,7 +38,5 @@ public class ApiDefinitionExecResult implements Serializable {
private String reportType;
private String content;
private static final long serialVersionUID = 1L;
}

View File

@ -1,17 +1,18 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ApiDefinitionExecResultWithBLOBs extends ApiDefinitionExecResult implements Serializable {
private String content;
private String errorCode;
private String envConfig;
private static final long serialVersionUID = 1L;
}

View File

@ -1,8 +1,9 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiExecutionQueueDetail implements Serializable {
private String id;
@ -19,6 +20,10 @@ public class ApiExecutionQueueDetail implements Serializable {
private Long createTime;
private Boolean retryEnable;
private Long retryNumber;
private String evnMap;
private static final long serialVersionUID = 1L;

View File

@ -573,6 +573,126 @@ public class ApiExecutionQueueDetailExample {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andRetryEnableIsNull() {
addCriterion("retry_enable is null");
return (Criteria) this;
}
public Criteria andRetryEnableIsNotNull() {
addCriterion("retry_enable is not null");
return (Criteria) this;
}
public Criteria andRetryEnableEqualTo(Boolean value) {
addCriterion("retry_enable =", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableNotEqualTo(Boolean value) {
addCriterion("retry_enable <>", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableGreaterThan(Boolean value) {
addCriterion("retry_enable >", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableGreaterThanOrEqualTo(Boolean value) {
addCriterion("retry_enable >=", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableLessThan(Boolean value) {
addCriterion("retry_enable <", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableLessThanOrEqualTo(Boolean value) {
addCriterion("retry_enable <=", value, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableIn(List<Boolean> values) {
addCriterion("retry_enable in", values, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableNotIn(List<Boolean> values) {
addCriterion("retry_enable not in", values, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableBetween(Boolean value1, Boolean value2) {
addCriterion("retry_enable between", value1, value2, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryEnableNotBetween(Boolean value1, Boolean value2) {
addCriterion("retry_enable not between", value1, value2, "retryEnable");
return (Criteria) this;
}
public Criteria andRetryNumberIsNull() {
addCriterion("retry_number is null");
return (Criteria) this;
}
public Criteria andRetryNumberIsNotNull() {
addCriterion("retry_number is not null");
return (Criteria) this;
}
public Criteria andRetryNumberEqualTo(Long value) {
addCriterion("retry_number =", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberNotEqualTo(Long value) {
addCriterion("retry_number <>", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberGreaterThan(Long value) {
addCriterion("retry_number >", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberGreaterThanOrEqualTo(Long value) {
addCriterion("retry_number >=", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberLessThan(Long value) {
addCriterion("retry_number <", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberLessThanOrEqualTo(Long value) {
addCriterion("retry_number <=", value, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberIn(List<Long> values) {
addCriterion("retry_number in", values, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberNotIn(List<Long> values) {
addCriterion("retry_number not in", values, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberBetween(Long value1, Long value2) {
addCriterion("retry_number between", value1, value2, "retryNumber");
return (Criteria) this;
}
public Criteria andRetryNumberNotBetween(Long value1, Long value2) {
addCriterion("retry_number not between", value1, value2, "retryNumber");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -40,7 +40,5 @@ public class ApiScenarioReport implements Serializable {
private String reportType;
private String description;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,18 @@
package io.metersphere.base.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ApiScenarioReportWithBLOBs extends ApiScenarioReport implements Serializable {
private String description;
private String envConfig;
private static final long serialVersionUID = 1L;
}

View File

@ -2,9 +2,11 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultExample;
import java.util.List;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ApiDefinitionExecResultMapper {
long countByExample(ApiDefinitionExecResultExample example);
@ -12,25 +14,25 @@ public interface ApiDefinitionExecResultMapper {
int deleteByPrimaryKey(String id);
int insert(ApiDefinitionExecResult record);
int insert(ApiDefinitionExecResultWithBLOBs record);
int insertSelective(ApiDefinitionExecResult record);
int insertSelective(ApiDefinitionExecResultWithBLOBs record);
List<ApiDefinitionExecResult> selectByExampleWithBLOBs(ApiDefinitionExecResultExample example);
List<ApiDefinitionExecResultWithBLOBs> selectByExampleWithBLOBs(ApiDefinitionExecResultExample example);
List<ApiDefinitionExecResult> selectByExample(ApiDefinitionExecResultExample example);
ApiDefinitionExecResult selectByPrimaryKey(String id);
ApiDefinitionExecResultWithBLOBs selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiDefinitionExecResult record, @Param("example") ApiDefinitionExecResultExample example);
int updateByExampleSelective(@Param("record") ApiDefinitionExecResultWithBLOBs record, @Param("example") ApiDefinitionExecResultExample example);
int updateByExampleWithBLOBs(@Param("record") ApiDefinitionExecResult record, @Param("example") ApiDefinitionExecResultExample example);
int updateByExampleWithBLOBs(@Param("record") ApiDefinitionExecResultWithBLOBs record, @Param("example") ApiDefinitionExecResultExample example);
int updateByExample(@Param("record") ApiDefinitionExecResult record, @Param("example") ApiDefinitionExecResultExample example);
int updateByPrimaryKeySelective(ApiDefinitionExecResult record);
int updateByPrimaryKeySelective(ApiDefinitionExecResultWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(ApiDefinitionExecResult record);
int updateByPrimaryKeyWithBLOBs(ApiDefinitionExecResultWithBLOBs record);
int updateByPrimaryKey(ApiDefinitionExecResult record);
}

View File

@ -19,8 +19,9 @@
<result column="integrated_report_id" jdbcType="VARCHAR" property="integratedReportId" />
<result column="report_type" jdbcType="VARCHAR" property="reportType" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDefinitionExecResult">
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
<result column="content" jdbcType="LONGVARCHAR" property="content" />
<result column="env_config" jdbcType="LONGVARCHAR" property="envConfig" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -86,7 +87,7 @@
report_type
</sql>
<sql id="Blob_Column_List">
content
content, env_config
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultExample" resultMap="ResultMapWithBLOBs">
select
@ -136,21 +137,23 @@
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">
<insert id="insert" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
insert into api_definition_exec_result (id, `name`, resource_id,
`status`, user_id, start_time,
end_time, create_time, `type`,
actuator, trigger_mode, error_code,
version_id, project_id, integrated_report_id,
report_type, content)
report_type, content, env_config
)
values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, #{resourceId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{startTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{createTime,jdbcType=BIGINT}, #{type,jdbcType=VARCHAR},
#{actuator,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{errorCode,jdbcType=VARCHAR},
#{versionId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{integratedReportId,jdbcType=VARCHAR},
#{reportType,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARCHAR})
#{reportType,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARCHAR}, #{envConfig,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
insert into api_definition_exec_result
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -204,6 +207,9 @@
<if test="content != null">
content,
</if>
<if test="envConfig != null">
env_config,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -257,6 +263,9 @@
<if test="content != null">
#{content,jdbcType=LONGVARCHAR},
</if>
<if test="envConfig != null">
#{envConfig,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultExample" resultType="java.lang.Long">
@ -319,6 +328,9 @@
<if test="record.content != null">
content = #{record.content,jdbcType=LONGVARCHAR},
</if>
<if test="record.envConfig != null">
env_config = #{record.envConfig,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -342,7 +354,8 @@
project_id = #{record.projectId,jdbcType=VARCHAR},
integrated_report_id = #{record.integratedReportId,jdbcType=VARCHAR},
report_type = #{record.reportType,jdbcType=VARCHAR},
content = #{record.content,jdbcType=LONGVARCHAR}
content = #{record.content,jdbcType=LONGVARCHAR},
env_config = #{record.envConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -369,7 +382,7 @@
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
update api_definition_exec_result
<set>
<if test="name != null">
@ -420,10 +433,13 @@
<if test="content != null">
content = #{content,jdbcType=LONGVARCHAR},
</if>
<if test="envConfig != null">
env_config = #{envConfig,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
update api_definition_exec_result
set `name` = #{name,jdbcType=VARCHAR},
resource_id = #{resourceId,jdbcType=VARCHAR},
@ -440,7 +456,8 @@
project_id = #{projectId,jdbcType=VARCHAR},
integrated_report_id = #{integratedReportId,jdbcType=VARCHAR},
report_type = #{reportType,jdbcType=VARCHAR},
content = #{content,jdbcType=LONGVARCHAR}
content = #{content,jdbcType=LONGVARCHAR},
env_config = #{envConfig,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">

View File

@ -9,6 +9,8 @@
<result column="test_id" jdbcType="VARCHAR" property="testId" />
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="retry_enable" jdbcType="BIT" property="retryEnable" />
<result column="retry_number" jdbcType="BIGINT" property="retryNumber" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiExecutionQueueDetail">
<result column="evn_map" jdbcType="LONGVARCHAR" property="evnMap" />
@ -72,7 +74,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, queue_id, sort, report_id, test_id, `type`, create_time
id, queue_id, sort, report_id, test_id, `type`, create_time, retry_enable, retry_number
</sql>
<sql id="Blob_Column_List">
evn_map
@ -128,10 +130,12 @@
<insert id="insert" parameterType="io.metersphere.base.domain.ApiExecutionQueueDetail">
insert into api_execution_queue_detail (id, queue_id, sort,
report_id, test_id, `type`,
create_time, evn_map)
create_time, retry_enable, retry_number,
evn_map)
values (#{id,jdbcType=VARCHAR}, #{queueId,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER},
#{reportId,jdbcType=VARCHAR}, #{testId,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{evnMap,jdbcType=LONGVARCHAR})
#{createTime,jdbcType=BIGINT}, #{retryEnable,jdbcType=BIT}, #{retryNumber,jdbcType=BIGINT},
#{evnMap,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiExecutionQueueDetail">
insert into api_execution_queue_detail
@ -157,6 +161,12 @@
<if test="createTime != null">
create_time,
</if>
<if test="retryEnable != null">
retry_enable,
</if>
<if test="retryNumber != null">
retry_number,
</if>
<if test="evnMap != null">
evn_map,
</if>
@ -183,6 +193,12 @@
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="retryEnable != null">
#{retryEnable,jdbcType=BIT},
</if>
<if test="retryNumber != null">
#{retryNumber,jdbcType=BIGINT},
</if>
<if test="evnMap != null">
#{evnMap,jdbcType=LONGVARCHAR},
</if>
@ -218,6 +234,12 @@
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.retryEnable != null">
retry_enable = #{record.retryEnable,jdbcType=BIT},
</if>
<if test="record.retryNumber != null">
retry_number = #{record.retryNumber,jdbcType=BIGINT},
</if>
<if test="record.evnMap != null">
evn_map = #{record.evnMap,jdbcType=LONGVARCHAR},
</if>
@ -235,6 +257,8 @@
test_id = #{record.testId,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
retry_enable = #{record.retryEnable,jdbcType=BIT},
retry_number = #{record.retryNumber,jdbcType=BIGINT},
evn_map = #{record.evnMap,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -248,7 +272,9 @@
report_id = #{record.reportId,jdbcType=VARCHAR},
test_id = #{record.testId,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}
create_time = #{record.createTime,jdbcType=BIGINT},
retry_enable = #{record.retryEnable,jdbcType=BIT},
retry_number = #{record.retryNumber,jdbcType=BIGINT}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -274,6 +300,12 @@
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="retryEnable != null">
retry_enable = #{retryEnable,jdbcType=BIT},
</if>
<if test="retryNumber != null">
retry_number = #{retryNumber,jdbcType=BIGINT},
</if>
<if test="evnMap != null">
evn_map = #{evnMap,jdbcType=LONGVARCHAR},
</if>
@ -288,6 +320,8 @@
test_id = #{testId,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
retry_enable = #{retryEnable,jdbcType=BIT},
retry_number = #{retryNumber,jdbcType=BIGINT},
evn_map = #{evnMap,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -298,7 +332,9 @@
report_id = #{reportId,jdbcType=VARCHAR},
test_id = #{testId,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}
create_time = #{createTime,jdbcType=BIGINT},
retry_enable = #{retryEnable,jdbcType=BIT},
retry_number = #{retryNumber,jdbcType=BIGINT}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -2,9 +2,11 @@ package io.metersphere.base.mapper;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.base.domain.ApiScenarioReportExample;
import java.util.List;
import io.metersphere.base.domain.ApiScenarioReportWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ApiScenarioReportMapper {
long countByExample(ApiScenarioReportExample example);
@ -12,25 +14,25 @@ public interface ApiScenarioReportMapper {
int deleteByPrimaryKey(String id);
int insert(ApiScenarioReport record);
int insert(ApiScenarioReportWithBLOBs record);
int insertSelective(ApiScenarioReport record);
int insertSelective(ApiScenarioReportWithBLOBs record);
List<ApiScenarioReport> selectByExampleWithBLOBs(ApiScenarioReportExample example);
List<ApiScenarioReportWithBLOBs> selectByExampleWithBLOBs(ApiScenarioReportExample example);
List<ApiScenarioReport> selectByExample(ApiScenarioReportExample example);
ApiScenarioReport selectByPrimaryKey(String id);
ApiScenarioReportWithBLOBs selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") ApiScenarioReport record, @Param("example") ApiScenarioReportExample example);
int updateByExampleSelective(@Param("record") ApiScenarioReportWithBLOBs record, @Param("example") ApiScenarioReportExample example);
int updateByExampleWithBLOBs(@Param("record") ApiScenarioReport record, @Param("example") ApiScenarioReportExample example);
int updateByExampleWithBLOBs(@Param("record") ApiScenarioReportWithBLOBs record, @Param("example") ApiScenarioReportExample example);
int updateByExample(@Param("record") ApiScenarioReport record, @Param("example") ApiScenarioReportExample example);
int updateByPrimaryKeySelective(ApiScenarioReport record);
int updateByPrimaryKeySelective(ApiScenarioReportWithBLOBs record);
int updateByPrimaryKeyWithBLOBs(ApiScenarioReport record);
int updateByPrimaryKeyWithBLOBs(ApiScenarioReportWithBLOBs record);
int updateByPrimaryKey(ApiScenarioReport record);
}

View File

@ -20,8 +20,9 @@
<result column="version_id" jdbcType="VARCHAR" property="versionId" />
<result column="report_type" jdbcType="VARCHAR" property="reportType" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReport">
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportWithBLOBs">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
<result column="env_config" jdbcType="LONGVARCHAR" property="envConfig" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -87,7 +88,7 @@
version_id, report_type
</sql>
<sql id="Blob_Column_List">
description
description, env_config
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="ResultMapWithBLOBs">
select
@ -137,23 +138,23 @@
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport">
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReportWithBLOBs">
insert into api_scenario_report (id, project_id, `name`,
create_time, update_time, `status`,
user_id, trigger_mode, execute_type,
scenario_name, scenario_id, create_user,
actuator, end_time, report_version,
version_id, report_type, description
)
version_id, report_type, description,
env_config)
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR},
#{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{executeType,jdbcType=VARCHAR},
#{scenarioName,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{createUser,jdbcType=VARCHAR},
#{actuator,jdbcType=VARCHAR}, #{endTime,jdbcType=BIGINT}, #{reportVersion,jdbcType=INTEGER},
#{versionId,jdbcType=VARCHAR}, #{reportType,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}
)
#{versionId,jdbcType=VARCHAR}, #{reportType,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR},
#{envConfig,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportWithBLOBs">
insert into api_scenario_report
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -210,6 +211,9 @@
<if test="description != null">
description,
</if>
<if test="envConfig != null">
env_config,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -266,6 +270,9 @@
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
<if test="envConfig != null">
#{envConfig,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultType="java.lang.Long">
@ -331,6 +338,9 @@
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
<if test="record.envConfig != null">
env_config = #{record.envConfig,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -355,7 +365,8 @@
report_version = #{record.reportVersion,jdbcType=INTEGER},
version_id = #{record.versionId,jdbcType=VARCHAR},
report_type = #{record.reportType,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
description = #{record.description,jdbcType=LONGVARCHAR},
env_config = #{record.envConfig,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -383,7 +394,7 @@
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportWithBLOBs">
update api_scenario_report
<set>
<if test="projectId != null">
@ -437,10 +448,13 @@
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
<if test="envConfig != null">
env_config = #{envConfig,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReport">
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportWithBLOBs">
update api_scenario_report
set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR},
@ -458,7 +472,8 @@
report_version = #{reportVersion,jdbcType=INTEGER},
version_id = #{versionId,jdbcType=VARCHAR},
report_type = #{reportType,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
description = #{description,jdbcType=LONGVARCHAR},
env_config = #{envConfig,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport">

View File

@ -4,6 +4,7 @@ import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultExpand;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import io.metersphere.task.dto.TaskCenterRequest;
import io.metersphere.track.dto.PlanReportCaseDTO;
import org.apache.ibatis.annotations.InsertProvider;
@ -18,9 +19,9 @@ public interface ExtApiDefinitionExecResultMapper {
void deleteByResourceId(String id);
ApiDefinitionExecResult selectMaxResultByResourceId(String resourceId);
ApiDefinitionExecResultWithBLOBs selectMaxResultByResourceId(String resourceId);
ApiDefinitionExecResult selectMaxResultByResourceIdAndType(String resourceId, String type);
ApiDefinitionExecResultWithBLOBs selectMaxResultByResourceIdAndType(String resourceId, String type);
long countByProjectIDAndCreateInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
@ -31,7 +32,7 @@ public interface ExtApiDefinitionExecResultMapper {
String selectExecResult(String resourceId);
ApiDefinitionExecResult selectPlanApiMaxResultByTestIdAndType(String resourceId, String type);
ApiDefinitionExecResultWithBLOBs selectPlanApiMaxResultByTestIdAndType(String resourceId, String type);
List<ApiDefinitionExecResult> selectStatusByIdList(@Param("ids") Collection<String> values);

View File

@ -6,12 +6,12 @@
from api_definition_exec_result where resource_id = #{id,jdbcType=VARCHAR}
</delete>
<select id="selectMaxResultByResourceId" parameterType="java.lang.String" resultType="io.metersphere.base.domain.ApiDefinitionExecResult">
<select id="selectMaxResultByResourceId" parameterType="java.lang.String" resultType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
select * from api_definition_exec_result
where resource_id = #{resourceId,jdbcType=VARCHAR} ORDER BY create_time DESC LIMIT 1
</select>
<select id="selectMaxResultByResourceIdAndType"
resultType="io.metersphere.base.domain.ApiDefinitionExecResult">
resultType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
select * from api_definition_exec_result
where resource_id = #{resourceId,jdbcType=VARCHAR} and `type` = #{type, jdbcType=VARCHAR}
ORDER BY start_time DESC LIMIT 5, 1
@ -86,7 +86,7 @@
select ader.status from api_definition_exec_result ader where ader.resource_id=#{resourceId}
</select>
<select id="selectPlanApiMaxResultByTestIdAndType"
resultType="io.metersphere.base.domain.ApiDefinitionExecResult">
resultType="io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs">
select * from api_definition_exec_result
where resource_id = #{resourceId,jdbcType=VARCHAR} and `type` = #{type, jdbcType=VARCHAR}
ORDER BY start_time DESC LIMIT 1

View File

@ -1,16 +1,16 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultWithBLOBs;
import java.util.List;
public class ExtApiDefinitionExecResultProvider {
public String insertListSql(List<ApiDefinitionExecResult> list) {
public String insertListSql(List<ApiDefinitionExecResultWithBLOBs> list) {
StringBuffer sqlList = new StringBuffer();
sqlList.append("insert into api_definition_exec_result (id, `name`, resource_id, `status`, user_id, start_time, end_time," +
" create_time, `type`, actuator, trigger_mode, version_id, error_code,project_id,integrated_report_id,report_type, content) values ");
" create_time, `type`, actuator, trigger_mode, version_id, error_code,project_id,integrated_report_id,report_type, content,env_config) values ");
for (int i = 0; i < list.size(); i++) {
ApiDefinitionExecResult result = list.get(i);
ApiDefinitionExecResultWithBLOBs result = list.get(i);
sqlList.append(" (")
.append("'")
.append(result.getId())
@ -46,6 +46,8 @@ public class ExtApiDefinitionExecResultProvider {
.append(result.getReportType())
.append("','")
.append(result.getContent())
.append("','")
.append(result.getEnvConfig())
.append("'")
.append(")");
if (i < list.size() - 1) {

View File

@ -7,7 +7,7 @@ import java.util.List;
public class ExtApiExecutionQueueProvider {
public String insertListSql(List<ApiExecutionQueueDetail> list) {
StringBuffer sqlList = new StringBuffer();
sqlList.append("insert into api_execution_queue_detail (id, queue_id, sort, report_id, test_id, `type`, create_time, evn_map) values ");
sqlList.append("insert into api_execution_queue_detail (id, queue_id, sort, report_id, test_id, `type`, create_time, evn_map,retry_enable,retry_number) values ");
for (int i = 0; i < list.size(); i++) {
ApiExecutionQueueDetail result = list.get(i);
sqlList.append(" (")
@ -27,7 +27,10 @@ public class ExtApiExecutionQueueProvider {
.append(result.getCreateTime())
.append(",'")
.append(result.getEvnMap())
.append("'")
.append("',")
.append(result.getRetryEnable())
.append(",")
.append(result.getRetryNumber())
.append(")");
if (i < list.size() - 1) {
sqlList.append(",");

View File

@ -8,7 +8,7 @@ public class ExtApiScenarioReportProvider {
public String insertListSql(List<APIScenarioReportResult> list) {
StringBuffer sqlList = new StringBuffer();
sqlList.append("INSERT INTO api_scenario_report (id, project_id, `name`, create_time, update_time, `status`, user_id, trigger_mode," +
" execute_type, scenario_name, scenario_id, create_user, actuator, end_time, report_version, version_id, description,report_type) VALUES ");
" execute_type, scenario_name, scenario_id, create_user, actuator, end_time, report_version, version_id, description,report_type,env_config) VALUES ");
for (int i = 0; i < list.size(); i++) {
APIScenarioReportResult result = list.get(i);
sqlList.append(" (")
@ -48,6 +48,8 @@ public class ExtApiScenarioReportProvider {
.append(result.getDescription())
.append("','")
.append(result.getReportType())
.append("','")
.append(result.getEnvConfig())
.append("'")
.append(")");
if (i < list.size() - 1) {

View File

@ -1,9 +1,15 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ApiScenarioReportResultWithBLOBs;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtApiScenarioReportResultMapper {
List<ApiScenarioReportResultWithBLOBs> selectBaseInfoResultByReportId(String reportId);
void deleteHisReportResult(@Param("scenarioIds") List<String> scenarioIds, @Param("reportId") String reportId);
List<String> getReportIds(@Param("ids") List<String> ids);
}

View File

@ -15,4 +15,19 @@
FROM api_scenario_report_result
WHERE report_id = #{0}
</select>
<delete id="deleteHisReportResult">
DELETE from api_scenario_report_result where report_id = #{reportId,jdbcType=VARCHAR} and
<foreach collection="scenarioIds" item="id" separator="or" open="(" close=")">
resource_id like CONCAT('%',#{id},'%')
</foreach>
</delete>
<select id="getReportIds" resultType="java.lang.String">
SELECT t.id FROM api_scenario_report t left JOIN api_scenario t1 on t.scenario_id = t1.id
where t1.id is not null and t.id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants;
public enum APITestStatus {
Saved, Starting, Running, Reporting, Completed, Debug, Error, Success,Underway,Waiting
Saved, Starting, Running, Reporting, Completed, Debug, Error, Success,Underway,Waiting,Rerunning
}

View File

@ -6,5 +6,6 @@ public enum ReportTypeConstants {
API_INTEGRATED,
API_INDEPENDENT,
UI_INTEGRATED,
UI_INDEPENDENT
UI_INDEPENDENT,
TEST_PLAN
}

View File

@ -148,7 +148,7 @@ public class TaskService {
apiExecutionQueueService.stop(request.getReportId());
PoolExecBlockingQueueUtil.offer(request.getReportId());
if (StringUtils.equals(request.getType(), "API")) {
ApiDefinitionExecResult result = apiDefinitionExecResultMapper.selectByPrimaryKey(request.getReportId());
ApiDefinitionExecResultWithBLOBs result = apiDefinitionExecResultMapper.selectByPrimaryKey(request.getReportId());
if (result != null) {
result.setStatus("STOP");
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(result);
@ -156,7 +156,7 @@ public class TaskService {
}
}
if (StringUtils.equals(request.getType(), "SCENARIO")) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
ApiScenarioReportWithBLOBs report = apiScenarioReportMapper.selectByPrimaryKey(request.getReportId());
if (report != null) {
report.setStatus("STOP");
apiScenarioReportMapper.updateByPrimaryKeySelective(report);

View File

@ -24,7 +24,11 @@ public class TestplanRunRequest {
private String environmentGroupId;
private List<String> testPlanIds;
private Boolean isAll;
private String reportId;
private String reportId;
private QueryTestPlanRequest queryTestPlanRequest;
// 失败重试
private boolean retryEnable;
private long retryNum;
}

View File

@ -1913,8 +1913,6 @@ public class TestCaseService {
testCaseMap = testCaseWithBLOBs.stream().collect(Collectors.toMap(TestCaseWithBLOBs::getId, t -> t));
}
String lastAddId = null;
for (TestCaseMinderEditRequest.TestCaseMinderEditItem item : data) {
if (StringUtils.isBlank(item.getNodeId()) || item.getNodeId().equals("root")) {
item.setNodeId("");

View File

@ -3,7 +3,6 @@ package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.esotericsoftware.minlog.Log;
import io.metersphere.api.dto.automation.TestPlanFailureApiDTO;
import io.metersphere.api.dto.automation.TestPlanFailureScenarioDTO;
import io.metersphere.api.service.ApiDefinitionExecResultService;
@ -15,15 +14,9 @@ import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.*;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.TestPlanExecuteReportDTO;
import io.metersphere.dto.UserDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.notice.sender.NoticeModel;
import io.metersphere.notice.service.NoticeSendService;
import io.metersphere.service.ProjectService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.service.UserService;
import io.metersphere.track.dto.*;
import io.metersphere.track.request.report.QueryTestPlanReportRequest;
@ -31,7 +24,6 @@ import io.metersphere.track.request.report.TestPlanReportSaveRequest;
import io.metersphere.track.request.testcase.QueryTestPlanRequest;
import io.metersphere.track.request.testplan.LoadCaseRequest;
import io.metersphere.track.request.testplan.TestplanRunRequest;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
@ -438,7 +430,7 @@ public class TestPlanReportService {
}
if (testPlanReport != null) {
boolean isSendMessage = false;
if(StringUtils.equalsIgnoreCase(testPlanReport.getStatus(),ExecuteResult.RUNNING.name())){
if (StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), ExecuteResult.RUNNING.name())) {
isSendMessage = true;
}
//初始化测试计划包含组件信息
@ -451,7 +443,7 @@ public class TestPlanReportService {
long endTime = System.currentTimeMillis();
long testCaseCount = testPlanTestCaseMapper.countByExample(testPlanTestCaseExample);
boolean updateTestPlanTime = testCaseCount > 0;
if (updateTestPlanTime) {
if (updateTestPlanTime && !StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), APITestStatus.Rerunning.name())) {
testPlanReport.setEndTime(endTime);
testPlanReport.setUpdateTime(endTime);
}
@ -533,8 +525,10 @@ public class TestPlanReportService {
}
}
//更新content表对结束日期
content.setStartTime(testPlanReport.getStartTime());
content.setEndTime(endTime);
if (!StringUtils.equalsAnyIgnoreCase(testPlanReport.getStatus(), APITestStatus.Rerunning.name())) {
content.setStartTime(testPlanReport.getStartTime());
content.setEndTime(endTime);
}
testPlanReportContentMapper.updateByExampleSelective(content, contentExample);
}
//计算测试计划状态

View File

@ -471,7 +471,7 @@ public class TestPlanService {
statusList.addAll(testPlanLoadCaseService.getStatus(testPlanId));
TestPlanWithBLOBs testPlanWithBLOBs = testPlanMapper.selectByPrimaryKey(testPlanId);
//如果测试计划是已归档状态不处理
if(testPlanWithBLOBs.getStatus().equals(TestPlanStatus.Archived.name())){
if (testPlanWithBLOBs.getStatus().equals(TestPlanStatus.Archived.name())) {
return;
}
testPlanWithBLOBs.setId(testPlanId);
@ -1936,6 +1936,8 @@ public class TestPlanService {
} else {
runModeConfig.setReportType(testplanRunRequest.getReportType());
}
runModeConfig.setRetryEnable(testplanRunRequest.isRetryEnable());
runModeConfig.setRetryNum(testplanRunRequest.getRetryNum());
return runModeConfig;
}

View File

@ -197,6 +197,7 @@ export default {
{text: 'Error', value: 'Error'},
{text: 'Success', value: 'Success'},
{text: 'stopped', value: 'stop'},
{text: 'Rerunning', value: 'Rerunning'},
{text: this.$t('error_report_library.option.name'), value: 'errorReportResult'},
],
reportTypeFilters:[],
@ -300,7 +301,7 @@ export default {
},
handleView(report) {
this.reportId = report.id;
if (report.status === 'Running') {
if (report.status === 'Running' || report.status ==='Rerunning') {
this.$warning(this.$t('commons.run_warning'))
return;
}

View File

@ -45,7 +45,11 @@
</el-button>
</el-popover>
<el-button v-if="showCancelButton" class="export-button" plain size="mini" @click="returnView()" >
<el-button v-if="showRerunButton" class="rerun-button" plain size="mini" @click="rerun" >
{{$t('api_test.automation.rerun')}}
</el-button>
<el-button v-if="showCancelButton" class="export-button" plain size="mini" @click="returnView" >
{{$t('commons.cancel')}}
</el-button>
@ -68,6 +72,10 @@ export default {
type: Boolean,
default: true,
},
showRerunButton: {
type: Boolean,
default: false,
},
isTemplate: Boolean,
exportFlag: {
type: Boolean,
@ -120,6 +128,17 @@ export default {
handleSaveKeyUp($event) {
$event.target.blur();
},
rerun(){
let type = this.report.reportType;
let rerunObj = {type :type,reportId:this.report.id}
this.$post('/api/test/exec/rerun',rerunObj, res => {
if (res.data !=='SUCCESS') {
this.$error(res.data);
}else{
this.$success("已经开始重跑,稍后刷新结果查看");
}
});
},
returnView(){
if (this.isUi) {
this.$router.push('/ui/report');
@ -169,4 +188,10 @@ export default {
margin-right: 10px;
}
.rerun-button{
float: right;
margin-right: 10px;
background-color: #F2F9EF;
color: #87C45D;
}
</style>

View File

@ -10,7 +10,10 @@
<div class="el-step__icon-inner"> {{ indexNumber }}</div>
</div>
<i class="icon el-icon-arrow-right" :class="{'is-active': showActive}" @click="active" @click.stop/>
<span>{{ getName(request.name) }}</span>
<el-link class="report-label-req" @click="isLink" v-if="redirect && resourceId">
{{ request.name }}
</el-link>
<span v-else>{{ getName(request.name) }}</span>
</div>
</el-tooltip>
</el-col>
@ -168,11 +171,13 @@ export default {
},
props: {
request: Object,
resourceId: String,
scenarioName: String,
stepId: String,
indexNumber: Number,
console: String,
totalStatus: String,
redirect: Boolean,
errorCode: {
type: String,
default: ""
@ -233,6 +238,27 @@ export default {
}
},
methods: {
isLink() {
let uri = "/#/api/definition?caseId=" + this.resourceId;
this.clickResource(uri)
},
clickResource(uri) {
this.$get('/user/update/currentByResourceId/' + this.resourceId, () => {
this.toPage(uri);
});
},
toPage(uri) {
let id = "new_a";
let a = document.createElement("a");
a.setAttribute("href", uri);
a.setAttribute("target", "_blank");
a.setAttribute("id", id);
document.body.appendChild(a);
a.click();
let element = document.getElementById(id);
element.parentNode.removeChild(element);
},
loadRequestInfoExpand() {
if (!this.requestInfo.hasData) {
if (this.request.responseResult && this.request.responseResult.body) {
@ -406,4 +432,9 @@ export default {
.ms-req-name-col {
overflow-x: hidden;
}
.report-label-req {
height: 20px;
border-bottom: 1px solid #303133;
}
</style>

View File

@ -9,7 +9,10 @@
</div>
</div>
<el-tooltip effect="dark" :content="node.label" placement="top">
<span>{{ node.label }}</span>
<el-link v-if="node.redirect" class="report-label-head" @click="isLink">
{{ node.label }}
</el-link>
<span v-else>{{ node.label }}</span>
</el-tooltip>
</el-card>
</div>
@ -25,9 +28,11 @@
<ms-request-result
:step-id="node.stepId"
:request="node.value"
:redirect="node.redirect"
:indexNumber="node.index"
:error-code="node.errorCode"
:scenarioName="node.label"
:resourceId="node.resourceId"
:total-status="node.totalStatus"
:console="console"
:isActive="isActive"
@ -55,13 +60,33 @@ export default {
console: String,
isActive: Boolean,
},
data() {
return {
stepFilter: new STEP,
}
},
methods: {
isLink() {
let uri = "/#/api/automation?resourceId=" + this.node.resourceId;
this.clickResource(uri)
},
clickResource(uri) {
this.$get('/user/update/currentByResourceId/' + this.node.resourceId, () => {
this.toPage(uri);
});
},
toPage(uri) {
let id = "new_a";
let a = document.createElement("a");
a.setAttribute("href", uri);
a.setAttribute("target", "_blank");
a.setAttribute("id", id);
document.body.appendChild(a);
a.click();
let element = document.getElementById(id);
element.parentNode.removeChild(element);
},
active() {
this.isActive = !this.isActive;
},
@ -127,6 +152,12 @@ export default {
color: #008080;
}
.report-label-head {
border-bottom: 1px solid #303133;
color: #303133;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
font-size: 13px;
}
/deep/ .el-step__icon {
width: 20px;

View File

@ -74,11 +74,32 @@
</el-col>
</el-row>
</div>
<!-- 失败重试 -->
<div class="ms-failure-div" v-if="isHasLicense">
<el-row>
<el-col :span="6">
<span class="ms-mode-span">&nbsp;</span>
</el-col>
<el-col :span="18">
<el-checkbox v-model="runConfig.retryEnable" class="ms-failure-div-right">
{{ $t('run_mode.retry_on_failure') }}
</el-checkbox>
<span v-if="runConfig.retryEnable">
<el-tooltip placement="top">
<div slot="content">重试接口/UI用例重试n次后仍然失败则用失败用例</div>
<i class="el-icon-question" style="cursor: pointer"/>
</el-tooltip>
<span>重试 <el-input-number v-model="runConfig.retryNum" :min="1" size="mini"/> &nbsp;</span>
</span>
</el-col>
</el-row>
</div>
<template v-slot:footer>
<div class="dialog-footer" v-if="showSave">
<el-button @click="close" >{{$t('commons.cancel')}}</el-button>
<el-dropdown @command="handleCommand" style="margin-left: 5px">
<el-button type="primary" >
<el-button @click="close">{{$t('commons.cancel')}}</el-button>
<el-dropdown @command="handleCommand" style="margin-left: 5px">
<el-button type="primary">
{{$t('load_test.save_and_run')}}<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
@ -93,148 +114,158 @@
</template>
<script>
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
import {strMapToObj} from "@/common/js/utils";
import {ENV_TYPE} from "@/common/js/constants";
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
import {strMapToObj} from "@/common/js/utils";
import {ENV_TYPE} from "@/common/js/constants";
import {hasLicense} from "@/common/js/utils";
export default {
name: "MsPlanRunModeWithEnv",
components: {EnvPopover, MsDialogFooter},
data() {
return {
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
},
projectEnvListMap: {},
projectList: [],
projectIds: new Set(),
options: [{
value: 'confirmAndRun',
label: this.$t('load_test.save_and_run')
}, {
value: 'save',
label: this.$t('commons.save')
}],
value: 'confirmAndRun'
};
},
props: {
planCaseIds: {
type: Array,
},
type: String,
planId: String,
showSave: {
type: Boolean,
default: false
},
},
methods: {
open(testType) {
this.runModeVisible = true;
this.testType = testType;
this.getResourcePools();
this.getWsProjects();
},
changeMode() {
this.runConfig.onSampleError = false;
this.runConfig.runWithinResourcePool = false;
this.runConfig.resourcePoolId = null;
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
export default {
name: "MsPlanRunModeWithEnv",
components: {EnvPopover, MsDialogFooter},
data() {
return {
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
},
isHasLicense: hasLicense(),
projectEnvListMap: {},
projectList: [],
projectIds: new Set(),
options: [{
value: 'confirmAndRun',
label: this.$t('load_test.save_and_run')
}, {
value: 'save',
label: this.$t('commons.save')
}],
value: 'confirmAndRun'
};
this.runModeVisible = false;
this.$emit('close');
},
handleRunBatch() {
this.$emit("handleRunBatch", this.runConfig);
this.close();
props: {
planCaseIds: {
type: Array,
},
type: String,
planId: String,
showSave: {
type: Boolean,
default: false
},
},
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
getWsProjects() {
this.$get("/project/getOwnerProjects", res => {
this.projectList = res.data;
})
},
showPopover() {
this.projectIds.clear();
let param = undefined;
let url = "";
if (this.type === 'apiCase') {
url = '/test/plan/api/case/env';
param = this.planCaseIds;
} else if (this.type === 'apiScenario') {
url = '/test/plan/api/scenario/env';
param = this.planCaseIds;
} else if (this.type === 'plan') {
url = '/test/plan/case/env';
param = {id: this.planId};
}
this.$post(url, param, res => {
let data = res.data;
if (data) {
this.projectEnvListMap = data;
for (let d in data) {
this.projectIds.add(d);
}
methods: {
open(testType) {
this.runModeVisible = true;
this.testType = testType;
this.getResourcePools();
this.getWsProjects();
},
changeMode() {
this.runConfig.onSampleError = false;
this.runConfig.runWithinResourcePool = false;
this.runConfig.resourcePoolId = null;
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
};
this.runModeVisible = false;
this.$emit('close');
},
handleRunBatch() {
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
});
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
getWsProjects() {
this.$get("/project/getOwnerProjects", res => {
this.projectList = res.data;
})
},
showPopover() {
this.projectIds.clear();
let param = undefined;
let url = "";
if (this.type === 'apiCase') {
url = '/test/plan/api/case/env';
param = this.planCaseIds;
} else if (this.type === 'apiScenario') {
url = '/test/plan/api/scenario/env';
param = this.planCaseIds;
} else if (this.type === 'plan') {
url = '/test/plan/case/env';
param = {id: this.planId};
}
this.$refs.envPopover.openEnvSelect();
});
this.$post(url, param, res => {
let data = res.data;
if (data) {
this.projectEnvListMap = data;
for (let d in data) {
this.projectIds.add(d);
}
}
this.$refs.envPopover.openEnvSelect();
});
},
handleCommand(command) {
if (this.runConfig.runWithinResourcePool && this.runConfig.resourcePoolId == null) {
this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool'));
return;
}
if (command === 'run') {
this.runConfig.isRun = true
this.handleRunBatch();
} else {
this.runConfig.isRun = false
this.handleRunBatch();
}
}
},
handleCommand(command){
if (this.runConfig.runWithinResourcePool && this.runConfig.resourcePoolId == null) {
this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool'));
return;
}
if (command === 'run') {
this.runConfig.isRun = true
this.handleRunBatch();
} else {
this.runConfig.isRun = false
this.handleRunBatch();
}
}
},
};
};
</script>
<style scoped>
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-span {
margin-right: 10px;
}
.ms-mode-div {
margin-top: 20px;
}
.ms-mode-div {
margin-top: 20px;
}
.ms-failure-div {
margin-top: 10px;
}
.ms-failure-div-right {
padding-right: 10px;
}
</style>

View File

@ -103,6 +103,29 @@
</el-col>
</el-row>
</div>
<!-- 失败重试 -->
<div class="ms-mode-div" v-if="isHasLicense">
<el-row>
<el-col :span="3">
<span class="ms-mode-span">&nbsp;</span>
</el-col>
<el-col :span="18">
<el-checkbox v-model="runConfig.retryEnable" class="ms-failure-div-right">
{{ $t('run_mode.retry_on_failure') }}
</el-checkbox>
<span v-if="runConfig.retryEnable">
<el-tooltip placement="top">
<div slot="content">重试接口/UI用例重试n次后仍然失败则用失败用例</div>
<i class="el-icon-question" style="cursor: pointer"/>
</el-tooltip>
<span>重试 <el-input-number v-model="runConfig.retryNum" :min="1" size="mini"/> &nbsp;</span>
</span>
</el-col>
</el-row>
</div>
<el-dialog width="60%" :title="$t('schedule.generate_expression')" :visible.sync="showCron"
:modal="false">
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"
@ -121,6 +144,7 @@
<script>
import {
hasLicense,
getCurrentProjectID,
getCurrentUser,
getCurrentWorkspaceId,
@ -196,6 +220,7 @@ export default {
}
};
return {
isHasLicense: hasLicense(),
result: {},
scheduleReceiverOptions: [],
operation: true,
@ -310,6 +335,9 @@ export default {
listenGoBack(this.close);
this.activeName = 'first';
this.getResourcePools();
this.runConfig.environmentType = ENV_TYPE.JSON;
this.runConfig.retryEnable = false;
this.runConfig.retryNum = 0;
},
findSchedule() {
let scheduleResourceID = this.testId;
@ -502,5 +530,7 @@ export default {
left: -42px;
padding-top: 0px;
}
.ms-failure-div-right {
padding-right: 10px;
}
</style>

View File

@ -779,6 +779,8 @@ export default {
param.environmentType = environmentType;
param.environmentGroupId = environmentGroupId;
param.requestOriginator = "TEST_PLAN";
param.retryEnable = config.retryEnable;
param.retryNum = config.retryNum;
if(config.isRun === true){
this.$refs.taskCenter.open();
this.result = this.$post('test/plan/run/', param, () => {

View File

@ -10,6 +10,9 @@
</template>
<api-cases :is-db="isDb" :share-id="shareId" :is-share="isShare" :report="report" :is-template="isTemplate"
:plan-id="planId" @setSize="setFailureSize"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0)" @click="rerun">
{{$t('api_test.automation.rerun')}}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="third" v-if="errorReportEnable">
<template v-slot:label>
@ -17,6 +20,10 @@
</template>
<api-cases :is-db="isDb" :is-error-report="true" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :plan-id="planId" @setSize="setErrorReportSize"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0)" @click="rerun">
{{$t('api_test.automation.rerun')}}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="fourth" v-if="unExecuteEnable">
<template v-slot:label>
@ -24,6 +31,10 @@
</template>
<api-cases :is-db="isDb" :is-un-execute="true" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :plan-id="planId" @setSize="setUnExecuteSize"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0)" @click="rerun">
{{$t('api_test.automation.rerun')}}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="fifth" v-if="allEnable">
@ -32,6 +43,10 @@
</template>
<api-cases :is-db="isDb" :is-all="true" :share-id="shareId" :is-share="isShare" :report="report"
:is-template="isTemplate" :plan-id="planId" @setSize="setAllSize"/>
<el-button class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0)" @click="rerun">
{{$t('api_test.automation.rerun')}}
</el-button>
</el-tab-pane>
</el-tabs>
</test-plan-report-container>
@ -44,6 +59,7 @@ import TestPlanReportContainer
from "@/business/components/track/plan/view/comonents/report/detail/TestPlanReportContainer";
import ApiCases from "@/business/components/track/plan/view/comonents/report/detail/component/ApiCases";
import TabPaneCount from "@/business/components/track/plan/view/comonents/report/detail/component/TabPaneCount";
import {hasLicense} from "@/common/js/utils";
export default {
name: "TestPlanApiReport",
@ -55,8 +71,12 @@ export default {
errorReportSize: 0,
unExecuteSize:0,
allSize: 0,
showRerunBtn: true,
};
},
created(){
this.showRerunBtn = hasLicense();
},
props: [
'report', 'planId', 'isTemplate', 'isShare', 'shareId', 'isDb'
],
@ -124,12 +144,68 @@ export default {
this.allSize = size;
},
handleClick(tab, event) {
},
rerun(){
let type = "TEST_PLAN";
let scenarios = [];
let cases = [];
let performanceCases = [];
let rerunObj = {
type: type,
reportId: this.report.id,
scenarios: scenarios,
cases: cases,
performanceCases: performanceCases
}
//
if(this.report && this.report.apiFailureCases){
this.format(cases,this.report.apiFailureCases);
}
if(this.report && this.report.unExecuteCases){
this.format(cases,this.report.unExecuteCases);
}
//
if(this.report && this.report.scenarioFailureCases){
this.format(scenarios,this.report.scenarioFailureCases);
}
if(this.report && this.report.unExecuteScenarios){
this.format(scenarios,this.report.unExecuteScenarios);
}
//
if(this.report && this.report.loadFailureCases){
this.format(performanceCases,this.report.loadFailureCases);
}
this.$post('/api/test/exec/rerun', rerunObj, res => {
if (res.data !== 'SUCCESS') {
this.$error(res.data);
} else {
this.$success("已经开始重跑,稍后刷新结果查看");
}
});
},
format(cases, datas){
if(this.report && datas){
datas.forEach(item=>{
if(item){
let obj = {id: item.id, reportId: item.reportId,userId:item.createUser};
cases.push(obj);
}
});
}
}
}
}
</script>
<style scoped>
.rerun-button {
position: absolute;
top: 10px;
right: 10px;
margin-right: 10px;
z-index: 1100;
background-color: #F2F9EF;
color: #87C45D;
}
</style>

View File

@ -1421,6 +1421,7 @@ export default {
request_success: "success",
request_error: "error",
generate_report: "Generate report",
rerun: "fail and rerun",
},
environment: {
id: 'Environment ID',
@ -2692,6 +2693,7 @@ export default {
set_report: "Set report",
report_name: "Report name",
run_with_resource_pool: "Run Within Resource pool",
retry_on_failure: "retry on failure",
},
operating_log: {
title: "Operating Log",

View File

@ -1426,6 +1426,7 @@ export default {
request_success: "成功",
request_error: "失败",
generate_report: "生成报告",
rerun: "失败重跑",
},
environment: {
id: '环境ID',
@ -2696,6 +2697,7 @@ export default {
set_report: "集合报告",
report_name: "报告名称",
run_with_resource_pool: "资源池运行",
retry_on_failure: "失败重试",
},
operating_log: {
title: "操作日志",

View File

@ -1426,6 +1426,7 @@ export default {
request_success: "成功",
request_error: "失敗",
generate_report: "生成報告",
rerun: "失敗重跑",
},
environment: {
id: '環境ID',
@ -2695,6 +2696,7 @@ export default {
set_report: "集合報告",
report_name: "報告名稱",
run_with_resource_pool: "資源池運行",
retry_on_failure: "失敗重試",
},
operating_log: {
title: "操作日誌",