feat(接口测试): 统一执行方式增加失败停止和用例集合报告

--story=1005727 --user=赵勇 接口测试用例支持批量执行后生成聚合报告 https://www.tapd.cn/55049933/s/1104083
This commit is contained in:
fit2-zhao 2022-02-15 15:07:07 +08:00 committed by fit2-zhao
parent 1e4a3e9c60
commit 861ebc2e37
34 changed files with 790 additions and 142 deletions

View File

@ -8,6 +8,7 @@ import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.base.domain.ApiScenarioReport;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
@ -61,7 +62,7 @@ public class APIScenarioReportController {
}
@PostMapping("/reName")
public void reName(@RequestBody QueryAPIReportRequest reportRequest) {
public void reName(@RequestBody ApiScenarioReport reportRequest) {
apiReportService.reName(reportRequest);
}
}

View File

@ -2,6 +2,8 @@ package io.metersphere.api.exec.api;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiCaseRunRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
import io.metersphere.api.dto.definition.BatchRunDefinitionRequest;
import io.metersphere.api.exec.queue.DBTestQueue;
@ -9,13 +11,16 @@ import io.metersphere.api.exec.scenario.ApiScenarioSerialService;
import io.metersphere.api.exec.utils.ApiDefinitionExecResultUtil;
import io.metersphere.api.service.ApiCaseResultService;
import io.metersphere.api.service.ApiExecutionQueueService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.api.service.ApiScenarioReportStructureService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioReportMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
import io.metersphere.base.mapper.TestPlanMapper;
import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.TriggerMode;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.MsExecResponseDTO;
@ -49,6 +54,12 @@ public class ApiCaseExecuteService {
private EnvironmentGroupProjectService environmentGroupProjectService;
@Resource
private ApiCaseResultService apiCaseResultService;
@Resource
private ApiScenarioReportService apiScenarioReportService;
@Resource
private ApiScenarioReportMapper apiScenarioReportMapper;
@Resource
ApiScenarioReportStructureService apiScenarioReportStructureService;
/**
* 测试计划case执行
@ -80,8 +91,18 @@ public class ApiCaseExecuteService {
Map<String, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
Map<String, String> planProjects = new HashMap<>();
planApiCases.forEach(testPlanApiCase -> {
ApiDefinitionExecResult report = ApiDefinitionExecResultUtil.addResult(request, testPlanApiCase, status);
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()));
});
@ -135,6 +156,26 @@ public class ApiCaseExecuteService {
List<ApiTestCaseWithBLOBs> list = apiTestCaseMapper.selectByExampleWithBLOBs(example);
LoggerUtil.debug("查询到执行数据:" + list.size());
// 集合报告设置
String serialReportId = null;
if (StringUtils.equals(request.getConfig().getReportType(), RunModeConstants.SET_REPORT.toString())
&& StringUtils.isNotEmpty(request.getConfig().getReportName())) {
serialReportId = UUID.randomUUID().toString();
APIScenarioReportResult report = apiScenarioReportService.init(request.getConfig().getReportId(), null, request.getConfig().getReportName(),
ReportTriggerMode.MANUAL.name(), ExecuteType.Saved.name(), request.getProjectId(),
null, request.getConfig());
report.setVersionId(list.get(0).getVersionId());
report.setName(request.getConfig().getReportName());
report.setTestName(request.getConfig().getReportName());
report.setId(serialReportId);
report.setReportType(ReportTypeConstants.API_INTEGRATED.name());
request.getConfig().setAmassReport(serialReportId);
report.setStatus(APITestStatus.Running.name());
apiScenarioReportMapper.insert(report);
apiScenarioReportStructureService.save(serialReportId, new ArrayList<>());
}
if (request.getConfig() != null && request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
if (request.getCondition() == null || !request.getCondition().isSelectAll()) {
// 按照id指定顺序排序
@ -152,11 +193,15 @@ public class ApiCaseExecuteService {
List<MsExecResponseDTO> responseDTOS = new LinkedList<>();
Map<String, ApiDefinitionExecResult> executeQueue = new LinkedHashMap<>();
String status = request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString()) ? APITestStatus.Waiting.name() : APITestStatus.Running.name();
String finalSerialReportId = serialReportId;
list.forEach(caseWithBLOBs -> {
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.setIntegratedReportId(finalSerialReportId);
executeQueue.put(caseWithBLOBs.getId(), report);
responseDTOS.add(new MsExecResponseDTO(caseWithBLOBs.getId(), report.getId(), request.getTriggerMode()));
});
@ -165,7 +210,7 @@ public class ApiCaseExecuteService {
String reportType = request.getConfig().getReportType();
String poolId = request.getConfig().getResourcePoolId();
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.DEFINITION.name(), null, reportType, ApiRunMode.DEFINITION.name(), request.getConfig());
DBTestQueue deQueue = apiExecutionQueueService.add(executeQueue, poolId, ApiRunMode.DEFINITION.name(), finalSerialReportId, reportType, ApiRunMode.DEFINITION.name(), request.getConfig());
// 开始选择执行模式
if (request.getConfig().getMode().equals(RunModeConstants.SERIAL.toString())) {
LoggerUtil.debug("开始串行执行");

View File

@ -83,6 +83,7 @@ public class ApiExecuteService {
report.setName(caseWithBLOBs.getName());
report.setTriggerMode(ApiRunMode.JENKINS.name());
report.setType(ApiRunMode.JENKINS.name());
report.setProjectId(caseWithBLOBs.getProjectId());
apiDefinitionExecResultMapper.insert(report);
//更新接口案例的最后执行状态等信息
caseWithBLOBs.setLastResultId(report.getId());

View File

@ -25,6 +25,7 @@ import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ReportTriggerMode;
import io.metersphere.commons.constants.ReportTypeConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.LogUtil;
@ -154,6 +155,7 @@ public class ApiScenarioExecuteService {
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);

View File

@ -61,25 +61,28 @@ public class ApiScenarioSerialService {
public void serial(ApiExecutionQueue executionQueue, ApiExecutionQueueDetail queue) {
LoggerUtil.debug("Scenario run-执行脚本装载-进入串行准备");
if (!StringUtils.equals(executionQueue.getReportType(), RunModeConstants.SET_REPORT.toString())) {
if (!StringUtils.equals(executionQueue.getReportType(), RunModeConstants.SET_REPORT.toString())
|| StringUtils.equalsIgnoreCase(executionQueue.getRunMode(), ApiRunMode.DEFINITION.name())) {
if (StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name(), ApiRunMode.SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO_PLAN.name(), ApiRunMode.SCHEDULE_SCENARIO.name(), ApiRunMode.JENKINS_SCENARIO_PLAN.name())) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(queue.getReportId());
report.setStatus(APITestStatus.Running.name());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
apiScenarioReportMapper.updateByPrimaryKey(report);
if (report != null) {
report.setStatus(APITestStatus.Running.name());
report.setCreateTime(System.currentTimeMillis());
report.setUpdateTime(System.currentTimeMillis());
apiScenarioReportMapper.updateByPrimaryKey(report);
}
} else {
ApiDefinitionExecResult execResult = apiDefinitionExecResultMapper.selectByPrimaryKey(queue.getReportId());
if (execResult != null) {
execResult.setStatus(APITestStatus.Running.name());
apiDefinitionExecResultMapper.updateByPrimaryKey(execResult);
apiDefinitionExecResultMapper.updateByPrimaryKeySelective(execResult);
}
}
}
LoggerUtil.info("Scenario run-开始执行队列ID" + executionQueue.getReportId() + "");
String reportId = StringUtils.isNotEmpty(executionQueue.getReportId()) ? executionQueue.getReportId() : queue.getReportId();
if (!StringUtils.equals(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
if (!StringUtils.equalsAny(executionQueue.getRunMode(), ApiRunMode.SCENARIO.name())) {
reportId = queue.getReportId();
}
HashTree hashTree = null;

View File

@ -48,6 +48,7 @@ public class ApiDefinitionExecResultUtil {
ApiTestCaseWithBLOBs caseWithBLOBs = CommonBeanFactory.getBean(ApiTestCaseMapper.class).selectByPrimaryKey(key.getApiCaseId());
if (caseWithBLOBs != null) {
apiResult.setName(caseWithBLOBs.getName());
apiResult.setProjectId(caseWithBLOBs.getProjectId());
}
apiResult.setTriggerMode(request.getTriggerMode());
apiResult.setActuator("LOCAL");

View File

@ -10,6 +10,7 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.config.JmeterProperties;
import io.metersphere.config.KafkaConfig;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.*;
import io.metersphere.jmeter.JMeterBase;
import io.metersphere.jmeter.LocalRunner;
@ -79,7 +80,11 @@ public class JMeterService {
if (!FixedCapacityUtils.jmeterLogTask.containsKey(request.getReportId())) {
FixedCapacityUtils.jmeterLogTask.put(request.getReportId(), System.currentTimeMillis());
}
if (StringUtils.isNotEmpty(request.getTestPlanReportId())
&& !FixedCapacityUtils.jmeterLogTask.containsKey(request.getTestPlanReportId())
&& StringUtils.equals(request.getReportType(), RunModeConstants.SET_REPORT.toString())) {
FixedCapacityUtils.jmeterLogTask.put(request.getTestPlanReportId(), System.currentTimeMillis());
}
LoggerUtil.debug("监听MessageCache.tasks当前容量" + FixedCapacityUtils.jmeterLogTask.size());
if (request.isDebug() && !StringUtils.equalsAny(request.getRunMode(), ApiRunMode.DEFINITION.name())) {
LoggerUtil.debug("为请求 [ " + request.getReportId() + " ] 添加同步接收结果 Listener");

View File

@ -136,6 +136,7 @@ public class ApiDefinitionExecResultService {
public void editStatus(ApiDefinitionExecResult saveResult, String type, String status, Long time, String reportId, String testId) {
String name = testId;
String version = "";
String projectId = "";
if (StringUtils.equalsAnyIgnoreCase(type, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name(), ApiRunMode.JENKINS_API_PLAN.name(), ApiRunMode.MANUAL_PLAN.name())) {
TestPlanApiCase testPlanApiCase = testPlanApiCaseMapper.selectByPrimaryKey(testId);
ApiTestCaseWithBLOBs caseWithBLOBs = null;
@ -164,11 +165,13 @@ public class ApiDefinitionExecResultService {
if (caseWithBLOBs != null) {
name = caseWithBLOBs.getName();
version = caseWithBLOBs.getVersionId();
projectId = caseWithBLOBs.getProjectId();
}
} else {
ApiDefinition apiDefinition = apiDefinitionMapper.selectByPrimaryKey(testId);
if (apiDefinition != null) {
name = apiDefinition.getName();
projectId = apiDefinition.getProjectId();
} else {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(testId);
if (caseWithBLOBs != null) {
@ -183,9 +186,13 @@ public class ApiDefinitionExecResultService {
}
name = caseWithBLOBs.getName();
version = caseWithBLOBs.getVersionId();
projectId = caseWithBLOBs.getProjectId();
}
}
}
if (StringUtils.isEmpty(saveResult.getProjectId()) && StringUtils.isNotEmpty(projectId)) {
saveResult.setProjectId(projectId);
}
saveResult.setVersionId(version);
saveResult.setName(name);
}

View File

@ -1040,6 +1040,7 @@ public class ApiDefinitionService {
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());
result.setProjectId(request.getProjectId());
result.setTriggerMode(TriggerMode.MANUAL.name());
apiDefinitionExecResultMapper.insert(result);
}

View File

@ -237,7 +237,11 @@ public class ApiExecutionQueueService {
if (count == 0) {
queueMapper.deleteByPrimaryKey(dto.getQueueId());
if (StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportService.margeReport(dto.getReportId());
String reportId = dto.getReportId();
if (StringUtils.equalsIgnoreCase(dto.getRunMode(), ApiRunMode.DEFINITION.name())) {
reportId = dto.getTestPlanReportId();
}
apiScenarioReportService.margeReport(reportId, dto.getRunMode());
}
}
return;
@ -259,7 +263,11 @@ public class ApiExecutionQueueService {
}
} else {
if (StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())) {
apiScenarioReportService.margeReport(dto.getReportId());
String reportId = dto.getReportId();
if (StringUtils.equalsIgnoreCase(dto.getRunMode(), ApiRunMode.DEFINITION.name())) {
reportId = dto.getTestPlanReportId();
}
apiScenarioReportService.margeReport(reportId, dto.getRunMode());
}
queueMapper.deleteByPrimaryKey(dto.getQueueId());
LoggerUtil.info("Queue execution ends" + dto.getQueueId());

View File

@ -32,7 +32,6 @@ import io.metersphere.utils.LoggerUtil;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -78,7 +77,7 @@ public class ApiScenarioReportService {
@Resource
private ApiScenarioReportStructureMapper apiScenarioReportStructureMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
private ApiDefinitionExecResultMapper definitionExecResultMapper;
public void saveResult(List<RequestResult> requestResults, ResultDTO dto) {
// 报告详情内容
@ -118,7 +117,7 @@ public class ApiScenarioReportService {
APIScenarioReportResult reportResult = extApiScenarioReportMapper.get(reportId);
if (reportResult != null) {
if (reportResult.getReportVersion() != null && reportResult.getReportVersion() > 1) {
reportResult.setContent(JSON.toJSONString(apiScenarioReportStructureService.getReport(reportId)));
reportResult.setContent(JSON.toJSONString(apiScenarioReportStructureService.assembleReport(reportId)));
} else {
ApiScenarioReportDetail detail = apiScenarioReportDetailMapper.selectByPrimaryKey(reportId);
if (detail != null && reportResult != null) {
@ -319,17 +318,25 @@ public class ApiScenarioReportService {
return report;
}
public void margeReport(String reportId) {
public void margeReport(String reportId, String runMode) {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
if (report != null) {
// 更新场景状态
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());
if (StringUtils.equalsIgnoreCase(runMode, ApiRunMode.DEFINITION.name())) {
ApiDefinitionExecResultExample execResultExample = new ApiDefinitionExecResultExample();
execResultExample.createCriteria().andIntegratedReportIdEqualTo(reportId).andStatusEqualTo("Error");
long size = definitionExecResultMapper.countByExample(execResultExample);
report.setStatus(size > 0 ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name());
} else {
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());
}
// 更新控制台信息
apiScenarioReportStructureService.update(reportId, FixedCapacityUtils.getJmeterLogger(reportId));
report.setEndTime(System.currentTimeMillis());
// 更新报告
apiScenarioReportMapper.updateByPrimaryKey(report);
}
@ -695,6 +702,7 @@ public class ApiScenarioReportService {
report.setProjectId(projectId);
report.setScenarioName(scenarioName);
report.setScenarioId(scenarioId);
report.setReportType(ReportTypeConstants.SCENARIO_INDEPENDENT.name());
return report;
}
@ -753,11 +761,19 @@ public class ApiScenarioReportService {
}
}
public void reName(QueryAPIReportRequest reportRequest) {
ApiScenarioReport apiTestReport = apiScenarioReportMapper.selectByPrimaryKey(reportRequest.getId());
if (apiTestReport != null) {
apiTestReport.setName(reportRequest.getName());
apiScenarioReportMapper.updateByPrimaryKey(apiTestReport);
public void reName(ApiScenarioReport reportRequest) {
if (StringUtils.equalsIgnoreCase(reportRequest.getReportType(), ReportTypeConstants.API_INDEPENDENT.name())) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportRequest.getId());
if (result != null) {
result.setName(reportRequest.getName());
definitionExecResultMapper.updateByPrimaryKeySelective(result);
}
} else {
ApiScenarioReport apiTestReport = apiScenarioReportMapper.selectByPrimaryKey(reportRequest.getId());
if (apiTestReport != null) {
apiTestReport.setName(reportRequest.getName());
apiScenarioReportMapper.updateByPrimaryKey(apiTestReport);
}
}
}
}

View File

@ -6,11 +6,12 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ApiScenarioReportDTO;
import io.metersphere.api.dto.RequestResultExpandDTO;
import io.metersphere.api.dto.StepTreeDTO;
import io.metersphere.api.service.vo.ApiDefinitionExecResultVo;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiScenarioMapper;
import io.metersphere.base.mapper.ApiScenarioReportResultMapper;
import io.metersphere.base.mapper.ApiScenarioReportStructureMapper;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.constants.ReportTypeConstants;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RequestResult;
@ -34,6 +35,10 @@ public class ApiScenarioReportStructureService {
private ApiScenarioReportStructureMapper mapper;
@Resource
private ApiScenarioReportResultMapper reportResultMapper;
@Resource
private ApiScenarioReportMapper scenarioReportMapper;
@Resource
private ApiDefinitionExecResultMapper definitionExecResultMapper;
private static final List<String> requests = Arrays.asList("HTTPSamplerProxy", "DubboSampler", "JDBCSampler", "TCPSampler", "JSR223Processor", "AbstractSampler");
@ -56,7 +61,7 @@ public class ApiScenarioReportStructureService {
this.save(reportId, dtoList);
}
private void save(String reportId, List<StepTreeDTO> dtoList) {
public void save(String reportId, List<StepTreeDTO> dtoList) {
ApiScenarioReportStructureWithBLOBs structure = new ApiScenarioReportStructureWithBLOBs();
structure.setId(UUID.randomUUID().toString());
structure.setCreateTime(System.currentTimeMillis());
@ -271,7 +276,90 @@ public class ApiScenarioReportStructureService {
}
}
public ApiScenarioReportDTO getReport(String reportId) {
private List<ApiDefinitionExecResultVo> formatApiReport(String reportId, List<StepTreeDTO> stepList) {
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
example.createCriteria().andIntegratedReportIdEqualTo(reportId);
List<ApiDefinitionExecResult> reportResults = definitionExecResultMapper.selectByExampleWithBLOBs(example);
List<ApiDefinitionExecResultVo> resultVos = new LinkedList<>();
for (int i = 0; i < reportResults.size(); i++) {
ApiDefinitionExecResult item = reportResults.get(i);
if (StringUtils.equalsIgnoreCase(item.getErrorCode(), "null")) {
item.setErrorCode(null);
}
ApiDefinitionExecResultVo vo = new ApiDefinitionExecResultVo();
BeanUtils.copyBean(vo, item);
if (StringUtils.isNotEmpty(item.getContent())) {
vo.setRequestResult(JSON.parseObject(item.getContent(), RequestResult.class));
if (vo.getRequestResult() != null) {
vo.setPassAssertions(vo.getRequestResult().getPassAssertions());
vo.setTotalAssertions(vo.getRequestResult().getTotalAssertions());
vo.getRequestResult().setName(item.getName());
}
}
if (vo.getRequestResult() == null) {
RequestResult requestResult = new RequestResult();
BeanUtils.copyBean(requestResult, item);
vo.setRequestResult(requestResult);
}
StepTreeDTO treeDTO = new StepTreeDTO(item.getName(), item.getResourceId(), "API", (i + 1));
treeDTO.setValue(vo.getRequestResult());
stepList.add(treeDTO);
resultVos.add(vo);
}
return resultVos;
}
private ApiScenarioReportDTO apiIntegratedReport(String reportId) {
List<StepTreeDTO> stepList = new LinkedList<>();
List<ApiDefinitionExecResultVo> reportResults = this.formatApiReport(reportId, stepList);
ApiScenarioReportDTO reportDTO = new ApiScenarioReportDTO();
// 组装报告
if (CollectionUtils.isNotEmpty(reportResults)) {
reportDTO.setTotal(reportResults.size());
reportDTO.setError(reportResults.stream().filter(e -> StringUtils.equalsIgnoreCase(e.getStatus(), "Error")).collect(Collectors.toList()).size());
reportDTO.setErrorCode(reportResults.stream().filter(e -> StringUtils.isNotEmpty(e.getErrorCode())).collect(Collectors.toList()).size());
reportDTO.setPassAssertions(reportResults.stream().mapToLong(ApiDefinitionExecResultVo::getPassAssertions).sum());
reportDTO.setTotalAssertions(reportResults.stream().mapToLong(ApiDefinitionExecResultVo::getTotalAssertions).sum());
// 统计场景数据
AtomicLong totalScenario = new AtomicLong();
AtomicLong scenarioError = new AtomicLong();
AtomicLong totalTime = new AtomicLong();
AtomicLong errorReport = new AtomicLong();
calculate(stepList, totalScenario, scenarioError, totalTime, errorReport, true);
reportDTO.setTotalTime(totalTime.longValue());
reportDTO.setScenarioTotal(totalScenario.longValue());
reportDTO.setScenarioError(scenarioError.longValue());
reportDTO.setScenarioErrorReport(errorReport.longValue());
//统计步骤数据
reportDTO.setScenarioStepSuccess((reportResults.size() - reportDTO.getError()));
reportDTO.setScenarioStepTotal(reportResults.size());
reportDTO.setScenarioStepError(reportDTO.getError());
reportDTO.setScenarioStepErrorReport(0);
ApiScenarioReportStructureExample structureExample = new ApiScenarioReportStructureExample();
structureExample.createCriteria().andReportIdEqualTo(reportId);
List<ApiScenarioReportStructureWithBLOBs> reportStructureWithBLOBs = mapper.selectByExampleWithBLOBs(structureExample);
if (CollectionUtils.isNotEmpty(reportStructureWithBLOBs)) {
reportDTO.setConsole(reportStructureWithBLOBs.get(0).getConsole());
}
reportDTO.setSteps(stepList);
}
return reportDTO;
}
public ApiScenarioReportDTO assembleReport(String reportId) {
ApiScenarioReport report = scenarioReportMapper.selectByPrimaryKey(reportId);
if (report != null && report.getReportType().equals(ReportTypeConstants.API_INTEGRATED.name())) {
return this.apiIntegratedReport(reportId);
} else {
return this.getReport(reportId);
}
}
private ApiScenarioReportDTO getReport(String reportId) {
ApiScenarioReportResultExample example = new ApiScenarioReportResultExample();
example.createCriteria().andReportIdEqualTo(reportId);
List<ApiScenarioReportResult> reportResults = reportResultMapper.selectByExampleWithBLOBs(example);

View File

@ -0,0 +1,43 @@
package io.metersphere.api.service.vo;
import io.metersphere.dto.RequestResult;
import lombok.Data;
@Data
public class ApiDefinitionExecResultVo {
private String id;
private String name;
private String resourceId;
private String status;
private String userId;
private Long startTime;
private Long endTime;
private Long createTime;
private String type;
private String actuator;
private String triggerMode;
private String errorCode;
private String versionId;
private String projectId;
private String integratedReportId;
private long totalAssertions = 0;
private long passAssertions = 0;
private RequestResult requestResult;
}

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 ApiDefinitionExecResult implements Serializable {
private String id;
@ -27,9 +28,13 @@ public class ApiDefinitionExecResult implements Serializable {
private String triggerMode;
private String errorCode;
private String versionId;
private String errorCode;
private String projectId;
private String integratedReportId;
private String content;

View File

@ -844,6 +844,76 @@ public class ApiDefinitionExecResultExample {
return (Criteria) this;
}
public Criteria andErrorCodeIsNull() {
addCriterion("error_code is null");
return (Criteria) this;
}
public Criteria andErrorCodeIsNotNull() {
addCriterion("error_code is not null");
return (Criteria) this;
}
public Criteria andErrorCodeEqualTo(String value) {
addCriterion("error_code =", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeNotEqualTo(String value) {
addCriterion("error_code <>", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeGreaterThan(String value) {
addCriterion("error_code >", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeGreaterThanOrEqualTo(String value) {
addCriterion("error_code >=", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeLessThan(String value) {
addCriterion("error_code <", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeLessThanOrEqualTo(String value) {
addCriterion("error_code <=", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeLike(String value) {
addCriterion("error_code like", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeNotLike(String value) {
addCriterion("error_code not like", value, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeIn(List<String> values) {
addCriterion("error_code in", values, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeNotIn(List<String> values) {
addCriterion("error_code not in", values, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeBetween(String value1, String value2) {
addCriterion("error_code between", value1, value2, "errorCode");
return (Criteria) this;
}
public Criteria andErrorCodeNotBetween(String value1, String value2) {
addCriterion("error_code not between", value1, value2, "errorCode");
return (Criteria) this;
}
public Criteria andVersionIdIsNull() {
addCriterion("version_id is null");
return (Criteria) this;
@ -914,73 +984,143 @@ public class ApiDefinitionExecResultExample {
return (Criteria) this;
}
public Criteria andErrorCodeIsNull() {
addCriterion("error_code is null");
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andErrorCodeIsNotNull() {
addCriterion("error_code is not null");
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andErrorCodeEqualTo(String value) {
addCriterion("error_code =", value, "errorCode");
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeNotEqualTo(String value) {
addCriterion("error_code <>", value, "errorCode");
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeGreaterThan(String value) {
addCriterion("error_code >", value, "errorCode");
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeGreaterThanOrEqualTo(String value) {
addCriterion("error_code >=", value, "errorCode");
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeLessThan(String value) {
addCriterion("error_code <", value, "errorCode");
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeLessThanOrEqualTo(String value) {
addCriterion("error_code <=", value, "errorCode");
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeLike(String value) {
addCriterion("error_code like", value, "errorCode");
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeNotLike(String value) {
addCriterion("error_code not like", value, "errorCode");
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeIn(List<String> values) {
addCriterion("error_code in", values, "errorCode");
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeNotIn(List<String> values) {
addCriterion("error_code not in", values, "errorCode");
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeBetween(String value1, String value2) {
addCriterion("error_code between", value1, value2, "errorCode");
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andErrorCodeNotBetween(String value1, String value2) {
addCriterion("error_code not between", value1, value2, "errorCode");
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdIsNull() {
addCriterion("integrated_report_id is null");
return (Criteria) this;
}
public Criteria andIntegratedReportIdIsNotNull() {
addCriterion("integrated_report_id is not null");
return (Criteria) this;
}
public Criteria andIntegratedReportIdEqualTo(String value) {
addCriterion("integrated_report_id =", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdNotEqualTo(String value) {
addCriterion("integrated_report_id <>", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdGreaterThan(String value) {
addCriterion("integrated_report_id >", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdGreaterThanOrEqualTo(String value) {
addCriterion("integrated_report_id >=", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdLessThan(String value) {
addCriterion("integrated_report_id <", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdLessThanOrEqualTo(String value) {
addCriterion("integrated_report_id <=", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdLike(String value) {
addCriterion("integrated_report_id like", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdNotLike(String value) {
addCriterion("integrated_report_id not like", value, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdIn(List<String> values) {
addCriterion("integrated_report_id in", values, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdNotIn(List<String> values) {
addCriterion("integrated_report_id not in", values, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdBetween(String value1, String value2) {
addCriterion("integrated_report_id between", value1, value2, "integratedReportId");
return (Criteria) this;
}
public Criteria andIntegratedReportIdNotBetween(String value1, String value2) {
addCriterion("integrated_report_id not between", value1, value2, "integratedReportId");
return (Criteria) this;
}
}

View File

@ -38,6 +38,8 @@ public class ApiScenarioReport implements Serializable {
private String versionId;
private String reportType;
private String description;
private static final long serialVersionUID = 1L;

View File

@ -1183,6 +1183,76 @@ public class ApiScenarioReportExample {
addCriterion("version_id not between", value1, value2, "versionId");
return (Criteria) this;
}
public Criteria andReportTypeIsNull() {
addCriterion("report_type is null");
return (Criteria) this;
}
public Criteria andReportTypeIsNotNull() {
addCriterion("report_type is not null");
return (Criteria) this;
}
public Criteria andReportTypeEqualTo(String value) {
addCriterion("report_type =", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeNotEqualTo(String value) {
addCriterion("report_type <>", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeGreaterThan(String value) {
addCriterion("report_type >", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeGreaterThanOrEqualTo(String value) {
addCriterion("report_type >=", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeLessThan(String value) {
addCriterion("report_type <", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeLessThanOrEqualTo(String value) {
addCriterion("report_type <=", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeLike(String value) {
addCriterion("report_type like", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeNotLike(String value) {
addCriterion("report_type not like", value, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeIn(List<String> values) {
addCriterion("report_type in", values, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeNotIn(List<String> values) {
addCriterion("report_type not in", values, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeBetween(String value1, String value2) {
addCriterion("report_type between", value1, value2, "reportType");
return (Criteria) this;
}
public Criteria andReportTypeNotBetween(String value1, String value2) {
addCriterion("report_type not between", value1, value2, "reportType");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -13,8 +13,10 @@
<result column="type" jdbcType="VARCHAR" property="type" />
<result column="actuator" jdbcType="VARCHAR" property="actuator" />
<result column="trigger_mode" jdbcType="VARCHAR" property="triggerMode" />
<result column="version_id" jdbcType="VARCHAR" property="versionId" />
<result column="error_code" jdbcType="VARCHAR" property="errorCode" />
<result column="version_id" jdbcType="VARCHAR" property="versionId" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
<result column="integrated_report_id" jdbcType="VARCHAR" property="integratedReportId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiDefinitionExecResult">
<result column="content" jdbcType="LONGVARCHAR" property="content" />
@ -79,7 +81,7 @@
</sql>
<sql id="Base_Column_List">
id, `name`, resource_id, `status`, user_id, start_time, end_time, create_time, `type`,
actuator, trigger_mode, version_id, error_code
actuator, trigger_mode, error_code, version_id, project_id, integrated_report_id
</sql>
<sql id="Blob_Column_List">
content
@ -136,13 +138,15 @@
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, content)
actuator, trigger_mode, error_code,
version_id, project_id, integrated_report_id,
content)
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}, #{versionId,jdbcType=VARCHAR},
#{errorCode,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARCHAR})
#{actuator,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}, #{errorCode,jdbcType=VARCHAR},
#{versionId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{integratedReportId,jdbcType=VARCHAR},
#{content,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiDefinitionExecResult">
insert into api_definition_exec_result
@ -180,11 +184,17 @@
<if test="triggerMode != null">
trigger_mode,
</if>
<if test="errorCode != null">
error_code,
</if>
<if test="versionId != null">
version_id,
</if>
<if test="errorCode != null">
error_code,
<if test="projectId != null">
project_id,
</if>
<if test="integratedReportId != null">
integrated_report_id,
</if>
<if test="content != null">
content,
@ -224,11 +234,17 @@
<if test="triggerMode != null">
#{triggerMode,jdbcType=VARCHAR},
</if>
<if test="errorCode != null">
#{errorCode,jdbcType=VARCHAR},
</if>
<if test="versionId != null">
#{versionId,jdbcType=VARCHAR},
</if>
<if test="errorCode != null">
#{errorCode,jdbcType=VARCHAR},
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="integratedReportId != null">
#{integratedReportId,jdbcType=VARCHAR},
</if>
<if test="content != null">
#{content,jdbcType=LONGVARCHAR},
@ -277,11 +293,17 @@
<if test="record.triggerMode != null">
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
</if>
<if test="record.errorCode != null">
error_code = #{record.errorCode,jdbcType=VARCHAR},
</if>
<if test="record.versionId != null">
version_id = #{record.versionId,jdbcType=VARCHAR},
</if>
<if test="record.errorCode != null">
error_code = #{record.errorCode,jdbcType=VARCHAR},
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.integratedReportId != null">
integrated_report_id = #{record.integratedReportId,jdbcType=VARCHAR},
</if>
<if test="record.content != null">
content = #{record.content,jdbcType=LONGVARCHAR},
@ -304,8 +326,10 @@
`type` = #{record.type,jdbcType=VARCHAR},
actuator = #{record.actuator,jdbcType=VARCHAR},
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
version_id = #{record.versionId,jdbcType=VARCHAR},
error_code = #{record.errorCode,jdbcType=VARCHAR},
version_id = #{record.versionId,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
integrated_report_id = #{record.integratedReportId,jdbcType=VARCHAR},
content = #{record.content,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -324,8 +348,10 @@
`type` = #{record.type,jdbcType=VARCHAR},
actuator = #{record.actuator,jdbcType=VARCHAR},
trigger_mode = #{record.triggerMode,jdbcType=VARCHAR},
error_code = #{record.errorCode,jdbcType=VARCHAR},
version_id = #{record.versionId,jdbcType=VARCHAR},
error_code = #{record.errorCode,jdbcType=VARCHAR}
project_id = #{record.projectId,jdbcType=VARCHAR},
integrated_report_id = #{record.integratedReportId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -363,11 +389,17 @@
<if test="triggerMode != null">
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
</if>
<if test="errorCode != null">
error_code = #{errorCode,jdbcType=VARCHAR},
</if>
<if test="versionId != null">
version_id = #{versionId,jdbcType=VARCHAR},
</if>
<if test="errorCode != null">
error_code = #{errorCode,jdbcType=VARCHAR},
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="integratedReportId != null">
integrated_report_id = #{integratedReportId,jdbcType=VARCHAR},
</if>
<if test="content != null">
content = #{content,jdbcType=LONGVARCHAR},
@ -387,8 +419,10 @@
`type` = #{type,jdbcType=VARCHAR},
actuator = #{actuator,jdbcType=VARCHAR},
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
version_id = #{versionId,jdbcType=VARCHAR},
error_code = #{errorCode,jdbcType=VARCHAR},
version_id = #{versionId,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
integrated_report_id = #{integratedReportId,jdbcType=VARCHAR},
content = #{content,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -404,8 +438,10 @@
`type` = #{type,jdbcType=VARCHAR},
actuator = #{actuator,jdbcType=VARCHAR},
trigger_mode = #{triggerMode,jdbcType=VARCHAR},
error_code = #{errorCode,jdbcType=VARCHAR},
version_id = #{versionId,jdbcType=VARCHAR},
error_code = #{errorCode,jdbcType=VARCHAR}
project_id = #{projectId,jdbcType=VARCHAR},
integrated_report_id = #{integratedReportId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -18,6 +18,7 @@
<result column="end_time" jdbcType="BIGINT" property="endTime" />
<result column="report_version" jdbcType="INTEGER" property="reportVersion" />
<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">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
@ -83,7 +84,7 @@
<sql id="Base_Column_List">
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
version_id, report_type
</sql>
<sql id="Blob_Column_List">
description
@ -137,18 +138,20 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport">
INSERT INTO api_scenario_report (id, project_id, `name`,
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)
VALUES (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
version_id, report_type, description
)
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}, #{description,jdbcType=LONGVARCHAR})
#{versionId,jdbcType=VARCHAR}, #{reportType,jdbcType=VARCHAR}, #{description,jdbcType=LONGVARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
insert into api_scenario_report
@ -201,6 +204,9 @@
<if test="versionId != null">
version_id,
</if>
<if test="reportType != null">
report_type,
</if>
<if test="description != null">
description,
</if>
@ -254,6 +260,9 @@
<if test="versionId != null">
#{versionId,jdbcType=VARCHAR},
</if>
<if test="reportType != null">
#{reportType,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
@ -316,6 +325,9 @@
<if test="record.versionId != null">
version_id = #{record.versionId,jdbcType=VARCHAR},
</if>
<if test="record.reportType != null">
report_type = #{record.reportType,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
@ -342,6 +354,7 @@
end_time = #{record.endTime,jdbcType=BIGINT},
report_version = #{record.reportVersion,jdbcType=INTEGER},
version_id = #{record.versionId,jdbcType=VARCHAR},
report_type = #{record.reportType,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -364,7 +377,8 @@
actuator = #{record.actuator,jdbcType=VARCHAR},
end_time = #{record.endTime,jdbcType=BIGINT},
report_version = #{record.reportVersion,jdbcType=INTEGER},
version_id = #{record.versionId,jdbcType=VARCHAR}
version_id = #{record.versionId,jdbcType=VARCHAR},
report_type = #{record.reportType,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -417,6 +431,9 @@
<if test="versionId != null">
version_id = #{versionId,jdbcType=VARCHAR},
</if>
<if test="reportType != null">
report_type = #{reportType,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
@ -440,6 +457,7 @@
end_time = #{endTime,jdbcType=BIGINT},
report_version = #{reportVersion,jdbcType=INTEGER},
version_id = #{versionId,jdbcType=VARCHAR},
report_type = #{reportType,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -459,7 +477,8 @@
actuator = #{actuator,jdbcType=VARCHAR},
end_time = #{endTime,jdbcType=BIGINT},
report_version = #{reportVersion,jdbcType=INTEGER},
version_id = #{versionId,jdbcType=VARCHAR}
version_id = #{versionId,jdbcType=VARCHAR},
report_type = #{reportType,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -8,7 +8,7 @@ public class ExtApiDefinitionExecResultProvider {
public String insertListSql(List<ApiDefinitionExecResult> 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, content) values ");
" create_time, `type`, actuator, trigger_mode, version_id, error_code,project_id,integrated_report_id, content) values ");
for (int i = 0; i < list.size(); i++) {
ApiDefinitionExecResult result = list.get(i);
sqlList.append(" (")
@ -39,6 +39,10 @@ public class ExtApiDefinitionExecResultProvider {
.append("','")
.append(result.getErrorCode())
.append("','")
.append(result.getProjectId())
.append("','")
.append(result.getIntegratedReportId())
.append("','")
.append(result.getContent())
.append("'")
.append(")");

View File

@ -99,10 +99,36 @@
</sql>
<select id="list" resultMap="BaseResultMap">
SELECT r.name AS test_name,r.end_time, r.user_id,
r.name, r.description, r.id, r.project_id, r.create_time, r.update_time, r.status, r.trigger_mode,IfNULL(s.name,r.scenario_name) as scenario_name
FROM api_scenario_report r
LEFT JOIN api_scenario s on r.scenario_id = s.id
select * from (
SELECT s_r.name AS test_name,
s_r.end_time,
s_r.user_id,
s_r.name,
s_r.id,
s_r.project_id,
s_r.create_time,
s_r.update_time,
s_r.status,
s_r.trigger_mode,
s_r.execute_type,
s_r.report_type
FROM api_scenario_report s_r
union
select a_r.name as test_name,
a_r.end_time,
a_r.user_id,
a_r.name,
a_r.id,
a_r.project_id,
a_r.create_time,
a_r.create_time as update_time,
a_r.status,
a_r.trigger_mode,
'Saved' as execute_type,
'API_INDEPENDENT' as report_type
from api_definition_exec_result a_r
where a_r.integrated_report_id is null
) r
<where>
<if test="request.combine != null">
<include refid="combine">
@ -130,6 +156,12 @@
#{value}
</foreach>
</when>
<when test="key=='report_type'">
and r.report_type in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<otherwise>
and r.trigger_mode in
<foreach collection="values" item="value" separator="," open="(" close=")">

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) VALUES ");
" execute_type, scenario_name, scenario_id, create_user, actuator, end_time, report_version, version_id, description,report_type) VALUES ");
for (int i = 0; i < list.size(); i++) {
APIScenarioReportResult result = list.get(i);
sqlList.append(" (")
@ -46,6 +46,8 @@ public class ExtApiScenarioReportProvider {
.append(result.getVersionId())
.append("','")
.append(result.getDescription())
.append("','")
.append(result.getReportType())
.append("'")
.append(")");
if (i < list.size() - 1) {

View File

@ -33,7 +33,8 @@
<if test="request.executor != null and request.executor != ''">
and t.user_id = #{request.executor}
</if>
)
and t.integrated_report_id is null
)
UNION ALL
(select t.id,t.name,'PERFORMANCE' as executionModule, ifnull(t2.name,'LOCAL') as actuator, t1.`name` as executor,t.create_time as executionTime, t.trigger_mode as triggerMode ,t.`status` as executionStatus
from load_test_report t left join `user` t1 ON t.user_id = t1.id left join test_resource_pool t2 on t.test_resource_pool_id = t2.id
@ -79,7 +80,7 @@
from api_definition_exec_result t left join `user` t1 ON t.user_id = t1.id left join test_resource_pool t2 on t.actuator = t2.id
left join api_definition t3 on t.resource_id = t3.id left join api_test_case t4 on t4.id = t.resource_id
left join test_plan_api_case t5 on t.resource_id = t5.id left join test_plan t6 on t5.test_plan_id = t6.id
where to_days(FROM_UNIXTIME(t.create_time/1000))= to_days(now()) and (t3.project_id =#{request.projectId} OR t4.project_id =#{request.projectId} OR t6.project_id = #{request.projectId}) and t.status not in ("saved","completed","success","error","STOP")
where to_days(FROM_UNIXTIME(t.create_time/1000))= to_days(now()) and t.integrated_report_id is null and (t3.project_id =#{request.projectId} OR t4.project_id =#{request.projectId} OR t6.project_id = #{request.projectId}) and t.status not in ("saved","completed","success","error","STOP")
)
UNION ALL
(select t.id,t.create_time as executionTime

View File

@ -0,0 +1,8 @@
package io.metersphere.commons.constants;
public enum ReportTypeConstants {
SCENARIO_INTEGRATED,
SCENARIO_INDEPENDENT,
API_INTEGRATED,
API_INDEPENDENT
}

View File

@ -51,3 +51,23 @@ DELIMITER ;
CALL test_personal();
DROP PROCEDURE IF EXISTS test_personal;
ALTER TABLE api_definition_exec_result
ADD project_id varchar(50);
ALTER TABLE api_definition_exec_result
ADD integrated_report_id varchar(50);
ALTER TABLE `api_definition_exec_result`
ADD INDEX project_id_index ( `project_id` );
ALTER TABLE api_scenario_report
ADD report_type varchar(100);
update api_definition_exec_result t
INNER JOIN
(select id,project_id from api_test_case) atc on t.resource_id = atc.id
set t.project_id = atc.project_id where atc.id = t.resource_id;
update api_scenario_report set report_type = 'SCENARIO_INTEGRATED' where scenario_id like '[%';
update api_scenario_report set report_type = 'SCENARIO_INDEPENDENT' where report_type is null;

View File

@ -43,8 +43,36 @@
min-width="200px">
</ms-table-column>
<el-table-column prop="scenarioName" :label="$t('api_test.automation.scenario_name')" width="150"
show-overflow-tooltip/>
<el-table-column prop="reportType" :label="$t('load_test.report_type')" width="150"
column-key="reportType"
:filters="reportTypeFilters">
<template v-slot:default="scope">
<div v-if="scope.row.reportType === 'SCENARIO_INTEGRATED'">
<el-tag size="mini" type="primary">
{{ $t('api_test.scenario.integrated') }}
</el-tag>
{{ $t('commons.scenario') }}
</div>
<div v-else-if="scope.row.reportType === 'API_INDEPENDENT'">
<el-tag size="mini" type="primary">
{{ $t('api_test.scenario.independent') }}
</el-tag>
case
</div>
<div v-else-if="scope.row.reportType === 'API_INTEGRATED'">
<el-tag size="mini" type="primary">
{{ $t('api_test.scenario.integrated') }}
</el-tag>
case
</div>
<div v-else>
<el-tag size="mini" type="primary">
{{ $t('api_test.scenario.independent') }}
</el-tag>
{{ $t('commons.scenario') }}
</div>
</template>
</el-table-column>
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
<el-table-column prop="createTime" min-width="120" :label="$t('commons.create_time')" sortable>
<template v-slot:default="scope">
@ -85,7 +113,10 @@
:total="total"/>
</el-card>
<ms-rename-report-dialog ref="renameDialog" @submit="rename($event)"></ms-rename-report-dialog>
<el-dialog :close-on-click-modal="false" :title="$t('test_track.plan_view.test_result')" width="60%"
:visible.sync="resVisible" class="api-import" destroy-on-close @close="resVisible=false">
<ms-request-result-tail :response="response" ref="debugResult"/>
</el-dialog>
</ms-main-container>
</ms-container>
</template>
@ -96,6 +127,8 @@ import {REPORT_CONFIGS} from "../../../common/components/search/search-component
import {_filter, _sort} from "@/common/js/tableUtils";
import MsRenameReportDialog from "@/business/components/common/components/report/MsRenameReportDialog";
import MsTableColumn from "@/business/components/common/components/table/MsTableColumn";
import MsRequestResultTail from "../../../api/definition/components/response/RequestResultTail";
export default {
components: {
ReportTriggerModeItem: () => import("../../../common/tableItem/ReportTriggerModeItem"),
@ -108,10 +141,13 @@ export default {
ShowMoreBtn: () => import("../../../track/case/components/ShowMoreBtn"),
MsRenameReportDialog,
MsTableColumn,
MsRequestResultTail,
},
data() {
return {
result: {},
resVisible: false,
response: {},
reportId: "",
debugVisible: false,
condition: {
@ -134,6 +170,12 @@ export default {
{text: 'Success', value: 'Success'},
{text: this.$t('error_report_library.option.name'), value: 'errorReportResult'},
],
reportTypeFilters: [
{text: this.$t('api_test.scenario.independent') + this.$t('commons.scenario'), value: 'SCENARIO_INDEPENDENT'},
{text: this.$t('api_test.scenario.integrated') + this.$t('commons.scenario'), value: 'SCENARIO_INTEGRATED'},
{text: this.$t('api_test.scenario.independent') + 'case', value: 'API_INDEPENDENT'},
{text: this.$t('api_test.scenario.integrated') + 'case', value: 'API_INTEGRATED'},
],
triggerFilters: [
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
{text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
@ -180,17 +222,36 @@ export default {
handleSelectionChange(val) {
this.multipleSelection = val;
},
getExecResult(apiCase) {
if (apiCase.id) {
let url = "/api/definition/report/get/" + apiCase.id;
this.$get(url, response => {
if (response.data) {
try {
let data = JSON.parse(response.data.content);
this.response = data;
this.resVisible = true;
} catch (error) {
this.resVisible = true;
}
}
});
}
},
handleView(report) {
this.reportId = report.id;
if (report.status === 'Running') {
this.$warning(this.$t('commons.run_warning'))
return;
}
this.currentProjectId = report.projectId;
this.$router.push({
path: 'report/view/' + report.id,
})
if (report.reportType.indexOf('SCENARIO') !== -1 || report.reportType === 'API_INTEGRATED') {
this.currentProjectId = report.projectId;
this.$router.push({
path: 'report/view/' + report.id,
})
} else {
this.getExecResult(report);
}
},
handleDelete(report) {
this.$alert(this.$t('api_report.delete_confirm') + report.name + "", '', {

View File

@ -1,25 +1,25 @@
<template>
<div>
<el-tag size="mini" type="info" v-if="row.status === 'Starting'">
{{ row.status }}
{{ getStatus(row.status) }}
</el-tag>
<el-tag size="mini" type="primary" effect="plain" v-else-if="row.status === 'Running'">
{{ row.status }}
{{ getStatus(row.status) }}
</el-tag>
<el-tag size="mini" type="success" v-else-if="row.status === 'Success'">
{{ row.status }}
<el-tag size="mini" type="success" v-else-if="getStatus(row.status) === 'success'">
{{ getStatus(row.status) }}
</el-tag>
<el-tag size="mini" type="warning" v-else-if="row.status === 'Reporting'">
{{ row.status }}
{{ getStatus(row.status) }}
</el-tag>
<el-tag size="mini" type="danger" v-else-if="row.status === 'Error'">
{{ row.status }}
<el-tag size="mini" type="danger" v-else-if="getStatus(row.status) === 'error'">
{{ getStatus(row.status) }}
</el-tag>
<el-tag size="mini" type="danger" style="background-color: #F6972A; color: #FFFFFF" v-else-if="row.status === 'errorReportResult'">
{{ $t('error_report_library.option.name') }}
</el-tag>
<el-tag v-else size="mini" type="info">
{{ row.status }}
{{ getStatus(row.status) }}
</el-tag>
</div>
</template>
@ -30,6 +30,11 @@
props: {
row: Object
},
methods:{
getStatus(status){
return status.toLowerCase();
}
}
}
</script>

View File

@ -9,7 +9,7 @@
<div class="el-step__icon is-text ms-api-col-create">
<div class="el-step__icon-inner"> {{ indexNumber }}</div>
</div>
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}" @click="active" @click.stop/>
<i class="icon el-icon-arrow-right" :class="{'is-active': showActive}" @click="active" @click.stop/>
<span>{{ getName(request.name) }}</span>
</div>
</el-tooltip>
@ -68,13 +68,13 @@
</div>
<el-collapse-transition>
<div v-show="isActive && !request.unexecute" style="width: 99%">
<div v-show="showActive && !request.unexecute" style="width: 99%">
<ms-request-result-tail
:scenario-name="scenarioName"
:request-type="requestType"
:request="request"
:console="console"
v-if="isActive"/>
v-if="showActive"/>
</div>
</el-collapse-transition>
</div>
@ -103,7 +103,13 @@ export default {
indexNumber: Number,
console: String,
errorCode: String,
isActive: Boolean,
isActive: {
type: Boolean,
default: false
}
},
created() {
this.showActive = this.isActive;
},
data() {
return {
@ -120,6 +126,7 @@ export default {
return "#F9F1EA";
}
},
showActive: false,
}
},
watch: {
@ -139,9 +146,9 @@ export default {
methods: {
active() {
if (this.request.unexecute) {
this.isActive = false;
this.showActive = false;
} else {
this.isActive = !this.isActive;
this.showActive = !this.showActive;
}
},
getName(name) {

View File

@ -23,7 +23,7 @@ export function STEP() {
['CustomizeReq', getDefaultSamplerMenu()],
['MaxSamplerProxy', getDefaultSamplerMenu()],
['GenericController', getAll()],
['AllSamplerProxy', ['HTTPSamplerProxy', 'DubboSampler', 'JDBCSampler', 'TCPSampler', 'Sampler', 'AbstractSampler', 'JSR223Processor']],
['AllSamplerProxy', ['HTTPSamplerProxy', 'DubboSampler', 'JDBCSampler', 'TCPSampler', 'Sampler', 'AbstractSampler', 'JSR223Processor','API']],
['DEFINITION', ['HTTPSamplerProxy', 'DubboSampler', 'JDBCSampler', 'TCPSampler']],
['AllCanExecType', ['HTTPSamplerProxy', 'DubboSampler', 'JDBCSampler', 'TCPSampler', 'JSR223Processor', 'AbstractSampler']]]);
return map

View File

@ -55,6 +55,13 @@
</el-row>
</div>
<!--- 失败停止 -->
<div style="margin-top: 10px" v-if="runConfig.mode === 'serial'">
<el-checkbox v-model="runConfig.onSampleError" style="margin-left: 127px">
{{ $t("api_test.fail_to_stop") }}
</el-checkbox>
</div>
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
<span class="ms-mode-span">{{ $t("run_mode.report_name") }}</span>
<el-input

View File

@ -25,14 +25,18 @@
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
</el-radio-group>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'serial'">
<div class="ms-mode-div">
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<div>
<el-checkbox v-model="runConfig.onSampleError">{{ $t("api_test.fail_to_stop") }}</el-checkbox>
<el-radio-group v-model="runConfig.reportType">
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
</el-radio-group>
</div>
<div style="padding-top: 10px">
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
@ -43,6 +47,7 @@
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.api"
:value="item.id">
</el-option>
</el-select>
@ -50,26 +55,20 @@
</el-col>
</el-row>
</div>
<div class="ms-mode-div" v-if="runConfig.mode === 'parallel'">
<el-row>
<el-col :span="6">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
</el-col>
<el-col :span="18">
<el-checkbox v-model="runConfig.runWithinResourcePool" style="padding-right: 10px;">
{{ $t('run_mode.run_with_resource_pool') }}
</el-checkbox>
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.api"
:value="item.id">
</el-option>
</el-select>
</el-col>
</el-row>
<!--- 失败停止 -->
<div style="margin-top: 10px" v-if="runConfig.mode === 'serial'">
<el-checkbox v-model="runConfig.onSampleError" style="margin-left: 127px">
{{ $t("api_test.fail_to_stop") }}
</el-checkbox>
</div>
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
<span class="ms-mode-span">{{ $t("run_mode.report_name") }}</span>
<el-input
v-model="runConfig.reportName"
:placeholder="$t('commons.input_content')"
size="small"
style="width: 300px"/>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>

View File

@ -1036,6 +1036,7 @@ export default {
delete_threadgroup_confirm: 'Confirm delete scenario',
scenario_list: 'Scenario List',
scenario_name: 'Scenario Name',
report_type: 'Report type',
upload_jmx: 'Upload JMX',
exist_jmx: 'Existed Files',
other_resource: 'Resource Files',
@ -1441,6 +1442,8 @@ export default {
scenario_warning: "No other steps can be added to the referenced scenario steps and sub-steps",
scenario_step_warning: "No other steps can be added under the current step",
scenario_error: "Cannot reference or copy itself",
integrated: "Integrated",
independent: "Independent",
},
request: {
debug: "Debug",

View File

@ -1042,6 +1042,7 @@ export default {
delete_threadgroup_confirm: '确认删除场景',
scenario_list: '场景列表',
scenario_name: "场景名称",
report_type: "报告类型",
upload_jmx: '上传 JMX 文件',
exist_jmx: '已存在的文件',
other_resource: '资源文件',
@ -1445,6 +1446,8 @@ export default {
scenario_warning: "引用的场景步骤及子步骤都无法添加其他步骤",
scenario_step_warning: "当前步骤下不能添加其他步骤",
scenario_error: "不能引用或复制自身!",
integrated: "集合",
independent: "独立",
},
request: {
debug: "调试",

View File

@ -1042,6 +1042,7 @@ export default {
delete_threadgroup_confirm: '確認刪除場景',
scenario_list: '場景列表',
scenario_name: "場景名稱",
report_type: "报告类型",
upload_jmx: '上傳 JMX 文件',
exist_jmx: '已存在的文件',
other_resource: '資源文件',
@ -1445,6 +1446,8 @@ export default {
scenario_warning: "引用的場景步驟及子步驟都無法添加其他步驟",
scenario_step_warning: "當前步驟下不能添加其他步驟",
scenario_error: "不能引用或復製自身!",
integrated: "集合",
independent: "獨立",
},
request: {
debug: "調試",