feat(接口测试): 完善失败重试相关功能

This commit is contained in:
fit2-zhao 2022-06-29 14:40:12 +08:00 committed by fit2-zhao
parent 53dc397e51
commit 97e4fca7ff
11 changed files with 156 additions and 235 deletions

View File

@ -22,10 +22,15 @@ public class RequestResultExpandDTO extends RequestResult {
public RequestResultExpandDTO() {
}
public RequestResultExpandDTO(String name, String status) {
this.setName(name);
this.setStatus(status);
}
public RequestResultExpandDTO(ApiScenarioReportResultWithBLOBs requestResult) {
if(requestResult.getBaseInfo() != null){
if (requestResult.getBaseInfo() != null) {
try {
ApiScenarioReportBaseInfoDTO dto = JSONObject.parseObject(requestResult.getBaseInfo(),ApiScenarioReportBaseInfoDTO.class);
ApiScenarioReportBaseInfoDTO dto = JSONObject.parseObject(requestResult.getBaseInfo(), ApiScenarioReportBaseInfoDTO.class);
this.setName(dto.getReqName());
this.setSuccess(dto.isReqSuccess());
this.setError(dto.getReqError());
@ -39,8 +44,8 @@ public class RequestResultExpandDTO extends RequestResult {
responseResult.setResponseCode(dto.getRspCode());
responseResult.setResponseTime(dto.getRspTime());
this.setResponseResult(responseResult);
}catch (Exception e){
LogUtil.error("Parse report base-info error :"+ e.getMessage());
} catch (Exception e) {
LogUtil.error("Parse report base-info error :" + e.getMessage());
}
}
}

View File

@ -11,16 +11,16 @@ 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 io.metersphere.utils.RetryResultUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.samplers.SampleResult;
import java.util.*;
import java.util.stream.Collectors;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class APISingleResultListener implements MsExecListener {
private ApiExecutionQueueService apiExecutionQueueService;
private final static String RETRY = "MsRetry_";
private List<SampleResult> queues;
/**
@ -35,11 +35,8 @@ public class APISingleResultListener implements MsExecListener {
@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);
this.clearLoops(results);
// 清理过程步骤
results = RetryResultUtil.clearLoops(results);
queues.addAll(results);
}
@ -47,22 +44,20 @@ public class APISingleResultListener implements MsExecListener {
public void testEnded(ResultDTO dto, Map<String, Object> kafkaConfig) {
try {
if (dto.isRetryEnable()) {
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + " 】,进入重试结果处理");
mergeRetryResults(queues);
LoggerUtil.info("重试结果处理【" + dto.getReportId() + " 】开始");
RetryResultUtil.mergeRetryResults(queues);
LoggerUtil.info("重试结果处理【" + dto.getReportId() + " 】结束");
}
JMeterBase.resultFormatting(queues, dto);
dto.setConsole(FixedCapacityUtils.getJmeterLogger(dto.getReportId(), !StringUtils.equals(dto.getReportType(), RunModeConstants.SET_REPORT.toString())));
// 入库存储
CommonBeanFactory.getBean(TestResultService.class).saveResults(dto);
LoggerUtil.info("进入TEST-END处理报告【" + dto.getReportId() + "" + dto.getRunMode() + " 整体执行完成");
// 全局并发队列
PoolExecBlockingQueueUtil.offer(dto.getReportId());
// 整体执行结束更新资源状态
CommonBeanFactory.getBean(TestResultService.class).testEnded(dto);
if (apiExecutionQueueService == null) {
apiExecutionQueueService = CommonBeanFactory.getBean(ApiExecutionQueueService.class);
}
@ -83,43 +78,4 @@ public class APISingleResultListener implements MsExecListener {
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);
}
}
private void clearLoops(List<SampleResult> results) {
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(results)) {
results = results.stream().filter(sampleResult ->
StringUtils.isNotEmpty(sampleResult.getSampleLabel())
&& !sampleResult.getSampleLabel().startsWith("MS_CLEAR_LOOPS_VAR_"))
.collect(Collectors.toList());
}
}
}

View File

@ -11,7 +11,6 @@ import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.*;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.ResultDTO;
import io.metersphere.notice.sender.NoticeModel;
@ -499,21 +498,6 @@ public class ApiDefinitionExecResultService {
return extApiDefinitionExecResultMapper.selectForPlanReport(apiReportIds);
}
private static List<OrderRequest> getDefaultOrderByField(String prefix, List<OrderRequest> orders, String field) {
if (orders == null || orders.size() < 1) {
OrderRequest orderRequest = new OrderRequest();
orderRequest.setName(field);
orderRequest.setType("desc");
if (StringUtils.isNotBlank(prefix)) {
orderRequest.setPrefix(prefix);
}
orders = new ArrayList<>();
orders.add(orderRequest);
return orders;
}
return orders;
}
public List<ApiDefinitionExecResultExpand> apiReportList(QueryAPIReportRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders(), "end_time"));
List<ApiDefinitionExecResultExpand> list = extApiDefinitionExecResultMapper.list(request);

View File

@ -1,7 +1,6 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import io.metersphere.api.dto.*;
@ -36,8 +35,6 @@ import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ -52,7 +49,6 @@ import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiScenarioReportService {
Logger testPlanLog = LoggerFactory.getLogger("testPlanExecuteLog");
@Resource
private ExtApiScenarioReportMapper extApiScenarioReportMapper;
@Resource
@ -116,14 +112,6 @@ public class ApiScenarioReportService {
example.createCriteria().andReportIdEqualTo(dto.getReportId());
List<ApiScenarioReportResult> requestResults = apiScenarioReportResultMapper.selectByExample(example);
if (StringUtils.isNotEmpty(dto.getTestPlanReportId())) {
String status = getStatus(requestResults, dto);
Map<String, String> reportMap = new HashMap<String, String>() {{
this.put(dto.getReportId(), status);
}};
testPlanLog.info("TestPlanReportId" + JSONArray.toJSONString(dto.getReportId()) + " EXECUTE OVER. SCENARIO STATUS : " + JSONObject.toJSONString(reportMap));
}
ApiScenarioReport scenarioReport;
if (StringUtils.equals(dto.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
scenarioReport = updatePlanCase(requestResults, dto);
@ -139,16 +127,6 @@ public class ApiScenarioReportService {
}
public APIScenarioReportResult get(String reportId, boolean selectReportContent) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportId);
if (result != null) {
APIScenarioReportResult reportResult = new APIScenarioReportResult();
BeanUtils.copyBean(reportResult, result);
reportResult.setReportVersion(2);
reportResult.setTestId(reportId);
ApiScenarioReportDTO dto = apiScenarioReportStructureService.apiIntegratedReport(reportId);
reportResult.setContent(JSON.toJSONString(dto));
return reportResult;
}
APIScenarioReportResult reportResult = extApiScenarioReportMapper.get(reportId);
if (reportResult != null) {
if (reportResult.getReportVersion() != null && reportResult.getReportVersion() > 1) {
@ -159,8 +137,31 @@ public class ApiScenarioReportService {
reportResult.setContent(new String(detail.getContent(), StandardCharsets.UTF_8));
}
}
return reportResult;
}
return reportResult;
// case 集成报告
APIScenarioReportResult result = this.getApiIntegrated(reportId);
return result;
}
/**
* CASE集成报告
*
* @param reportId
* @return
*/
public APIScenarioReportResult getApiIntegrated(String reportId) {
ApiDefinitionExecResult result = definitionExecResultMapper.selectByPrimaryKey(reportId);
if (result != null) {
APIScenarioReportResult reportResult = new APIScenarioReportResult();
BeanUtils.copyBean(reportResult, result);
reportResult.setReportVersion(2);
reportResult.setTestId(reportId);
ApiScenarioReportDTO dto = apiScenarioReportStructureService.apiIntegratedReport(reportId);
reportResult.setContent(JSON.toJSONString(dto));
return reportResult;
}
return null;
}
public List<APIScenarioReportResult> list(QueryAPIReportRequest request) {
@ -178,12 +179,12 @@ public class ApiScenarioReportService {
return list;
}
public QueryAPIReportRequest initRequest(QueryAPIReportRequest request){
if(request != null){
public QueryAPIReportRequest initRequest(QueryAPIReportRequest request) {
if (request != null) {
//初始化triggerMode的查询条件 如果查询API的话增加 JENKINS_RUN_TEST_PLAN(jenkins调用测试计划时执行的场景) 查询条件
if(MapUtils.isNotEmpty(request.getFilters()) && request.getFilters().containsKey("trigger_mode")
if (MapUtils.isNotEmpty(request.getFilters()) && request.getFilters().containsKey("trigger_mode")
&& CollectionUtils.isNotEmpty(request.getFilters().get("trigger_mode"))
&& request.getFilters().get("trigger_mode").contains("API") && !request.getFilters().get("trigger_mode").contains(ReportTriggerMode.JENKINS_RUN_TEST_PLAN.name())){
&& request.getFilters().get("trigger_mode").contains("API") && !request.getFilters().get("trigger_mode").contains(ReportTriggerMode.JENKINS_RUN_TEST_PLAN.name())) {
request.getFilters().get("trigger_mode").add(ReportTriggerMode.JENKINS_RUN_TEST_PLAN.name());
}
}
@ -251,8 +252,8 @@ public class ApiScenarioReportService {
report.setTriggerMode(TriggerMode.MANUAL.name());
}
// UI 调试类型报告不记录更新状态
if(report.getExecuteType().equals(ExecuteType.Debug.name()) &&
report.getReportType().equals(ReportTypeConstants.UI_INDEPENDENT.name())){
if (report.getExecuteType().equals(ExecuteType.Debug.name()) &&
report.getReportType().equals(ReportTypeConstants.UI_INDEPENDENT.name())) {
return report;
}
apiScenarioReportMapper.updateByPrimaryKeySelective(report);
@ -378,7 +379,7 @@ public class ApiScenarioReportService {
if (CollectionUtils.isEmpty(reportStatus)) {
//查不到任何结果按照未执行来处理
hasUnExecute = true;
}else {
} else {
for (String status : reportStatus) {
if (StringUtils.equalsIgnoreCase(status, ExecuteResult.SCENARIO_ERROR.toString())) {
hasError = true;
@ -407,15 +408,13 @@ public class ApiScenarioReportService {
public void margeReport(String reportId, String runMode, String console) {
// 更新场景状态
List<String> statusList = null;
if (StringUtils.equalsIgnoreCase(runMode, ApiRunMode.DEFINITION.name())) {
ApiDefinitionExecResultWithBLOBs result = definitionExecResultMapper.selectByPrimaryKey(reportId);
if (!StringUtils.equalsAnyIgnoreCase(result.getStatus(), APITestStatus.Rerunning.name())) {
result.setEndTime(System.currentTimeMillis());
}
statusList = extApiDefinitionExecResultMapper.selectDistinctStatusByReportId(reportId);
List<String> statusList = extApiDefinitionExecResultMapper.selectDistinctStatusByReportId(reportId);
result.setStatus(this.getIntegrationReportStatus(statusList));
result.setEndTime(System.currentTimeMillis());
definitionExecResultMapper.updateByPrimaryKeySelective(result);
} else {
ApiScenarioReport report = apiScenarioReportMapper.selectByPrimaryKey(reportId);
@ -423,9 +422,8 @@ public class ApiScenarioReportService {
if (!StringUtils.equalsAnyIgnoreCase(report.getStatus(), APITestStatus.Rerunning.name())) {
report.setEndTime(System.currentTimeMillis());
}
statusList = extApiScenarioReportResultMapper.selectDistinctStatusByReportId(reportId);
List<String> statusList = extApiScenarioReportResultMapper.selectDistinctStatusByReportId(reportId);
report.setStatus(this.getIntegrationReportStatus(statusList));
report.setEndTime(System.currentTimeMillis());
// 更新报告
apiScenarioReportMapper.updateByPrimaryKey(report);
}
@ -509,8 +507,8 @@ public class ApiScenarioReportService {
}
scenario.setExecuteTimes(executeTimes + 1);
// 针对 UI 调试类型的不需要更新
if(report.getExecuteType().equals(ExecuteType.Debug.name()) &&
report.getReportType().equals(ReportTypeConstants.UI_INDEPENDENT.name())){
if (report.getExecuteType().equals(ExecuteType.Debug.name()) &&
report.getReportType().equals(ReportTypeConstants.UI_INDEPENDENT.name())) {
return report;
}
uiScenarioMapper.updateByPrimaryKey(scenario);

View File

@ -215,11 +215,11 @@ public class ApiScenarioReportStructureService {
AtomicLong totalScenario, AtomicLong scenarioError, AtomicLong errorReport, AtomicLong unExecute) {
for (StepTreeDTO step : dtoList) {
totalScenario.set(totalScenario.longValue() + 1);
if (StringUtils.equalsIgnoreCase(step.getTotalStatus(), "fail")) {
if (StringUtils.equalsIgnoreCase(step.getTotalStatus(), ExecuteResult.FAIL.getValue())) {
scenarioError.set(scenarioError.longValue() + 1);
} else if (StringUtils.equalsAnyIgnoreCase(step.getTotalStatus(), "errorCode", ExecuteResult.ERROR_REPORT_RESULT.toString())) {
errorReport.set(errorReport.longValue() + 1);
} else if (!StringUtils.equalsIgnoreCase(step.getTotalStatus(), "success")) {
} else if (!StringUtils.equalsIgnoreCase(step.getTotalStatus(), ExecuteResult.API_SUCCESS.getValue())) {
unExecute.set(unExecute.longValue() + 1);
}
}
@ -249,11 +249,11 @@ public class ApiScenarioReportStructureService {
if (CollectionUtils.isNotEmpty(root.getChildren())) {
stepTotal.set((stepTotal.longValue() + root.getChildren().size()));
for (StepTreeDTO step : root.getChildren()) {
if (StringUtils.equalsAnyIgnoreCase(step.getTotalStatus(), "fail", "error")) {
if (StringUtils.equalsAnyIgnoreCase(step.getTotalStatus(), ExecuteResult.FAIL.getValue(), "error")) {
stepError.set(stepError.longValue() + 1);
} else if (StringUtils.equalsAnyIgnoreCase(step.getTotalStatus(), "errorCode", "errorReportResult")) {
stepErrorCode.set(stepErrorCode.longValue() + 1);
} else if (!StringUtils.equalsIgnoreCase(step.getTotalStatus(), "success")) {
} else if (!StringUtils.equalsIgnoreCase(step.getTotalStatus(), ExecuteResult.API_SUCCESS.getValue())) {
stepUnExecute.set(stepUnExecute.longValue() + 1);
unExecSize++;
}
@ -263,78 +263,44 @@ public class ApiScenarioReportStructureService {
}
}
public void reportFormatting(List<StepTreeDTO> dtoList, Map<String, List<ApiScenarioReportResultWithBLOBs>> maps, boolean isLoops) {
public void reportFormatting(List<StepTreeDTO> dtoList, Map<String, List<ApiScenarioReportResultWithBLOBs>> maps) {
// 按照创建时间排序
for (int index = 0; index < dtoList.size(); index++) {
StepTreeDTO dto = dtoList.get(index);
dto.setIndex((index + 1));
List<ApiScenarioReportResultWithBLOBs> reportResults = maps.get(dto.getResourceId());
if (CollectionUtils.isNotEmpty(reportResults)) {
if (reportResults.size() > 1) {
for (int i = 0; i < reportResults.size(); i++) {
ApiScenarioReportResultWithBLOBs reportResult = reportResults.get(i);
//来自报告导出的数据
if (i == 0) {
if (reportResult.getContent() != null) {
dto.setValue(JSON.parseObject(new String(reportResults.get(i).getContent(), StandardCharsets.UTF_8), RequestResult.class));
dto.setErrorCode(reportResults.get(0).getErrorCode());
} else {
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO(reportResult);
dto.setStepId(reportResults.get(i).getId());
dto.setValue(requestResultExpandDTO);
dto.setErrorCode(reportResults.get(0).getErrorCode());
}
} else {
if (reportResult.getContent() != null) {
StepTreeDTO step = new StepTreeDTO(dto.getLabel(), UUID.randomUUID().toString(), dto.getType(), reportResults.get(i).getId(), (i + 1));
step.setValue(JSON.parseObject(new String(reportResults.get(i).getContent(), StandardCharsets.UTF_8), RequestResult.class));
step.setErrorCode(reportResults.get(i).getErrorCode());
dtoList.add(step);
} else {
StepTreeDTO step = new StepTreeDTO(dto.getLabel(), UUID.randomUUID().toString(), dto.getType(), reportResults.get(i).getId(), (i + 1));
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO(reportResult);
step.setValue(requestResultExpandDTO);
step.setErrorCode(reportResults.get(i).getErrorCode());
dtoList.add(step);
}
}
}
} else {
ApiScenarioReportResultWithBLOBs reportResult = reportResults.get(0);
for (int i = 0; i < reportResults.size(); i++) {
ApiScenarioReportResultWithBLOBs reportResult = reportResults.get(i);
StepTreeDTO step = i == 0 ? dto :
new StepTreeDTO(dto.getLabel(), UUID.randomUUID().toString(), dto.getType(), reportResults.get(i).getId(), (i + 1));
step.setStepId(reportResults.get(i).getId());
RequestResult result = new RequestResultExpandDTO(reportResult);
if (reportResult.getContent() != null) {
String content = new String(reportResults.get(0).getContent(), StandardCharsets.UTF_8);
dto.setValue(JSON.parseObject(content, RequestResult.class));
dto.setErrorCode(reportResults.get(0).getErrorCode());
} else {
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO(reportResult);
dto.setStepId(reportResults.get(0).getId());
dto.setValue(requestResultExpandDTO);
dto.setErrorCode(reportResults.get(0).getErrorCode());
dto.setTotalStatus(requestResultExpandDTO.getStatus());
result = JSON.parseObject(new String(reportResults.get(i).getContent(), StandardCharsets.UTF_8), RequestResult.class);
}
step.setValue(result);
step.setErrorCode(reportResults.get(i).getErrorCode());
if (i > 0) {
dtoList.add(step);
}
}
}
// 未执行请求
if (StringUtils.isNotEmpty(dto.getType()) && requests.contains(dto.getType()) && dto.getValue() == null || isUiUnExecuteCommand(dto)) {
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO();
requestResultExpandDTO.setStatus("unexecute");
requestResultExpandDTO.setName(dto.getLabel());
dto.setTotalStatus("unexecute");
dto.setValue(requestResultExpandDTO);
dto.setTotalStatus(ExecuteResult.UN_EXECUTE.getValue());
dto.setValue(new RequestResultExpandDTO(dto.getLabel(), ExecuteResult.UN_EXECUTE.getValue()));
} else if (StringUtils.isNotEmpty(dto.getType()) && controls.contains(dto.getType()) && dto.getValue() == null) {
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO();
requestResultExpandDTO.setStatus("success");
requestResultExpandDTO.setName(dto.getLabel());
dto.setTotalStatus("success");
dto.setValue(requestResultExpandDTO);
} else {
if (dto.getValue() instanceof RequestResultExpandDTO && StringUtils.isNotEmpty(((RequestResultExpandDTO) dto.getValue()).getStatus())) {
dto.setTotalStatus(((RequestResultExpandDTO) dto.getValue()).getStatus());
} else if (dto.getValue() != null) {
if (dto.getValue().getError() > 0 || BooleanUtils.isNotTrue(dto.getValue().isSuccess())) {
dto.setTotalStatus("fail");
} else {
dto.setTotalStatus("success");
}
// 条件控制步骤
dto.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
dto.setValue(new RequestResultExpandDTO(dto.getLabel(), ExecuteResult.API_SUCCESS.getValue()));
} else if (dto.getValue() instanceof RequestResultExpandDTO && StringUtils.isNotEmpty(((RequestResultExpandDTO) dto.getValue()).getStatus())) {
dto.setTotalStatus(((RequestResultExpandDTO) dto.getValue()).getStatus());
} else if (dto.getValue() != null) {
if (dto.getValue().getError() > 0 || BooleanUtils.isNotTrue(dto.getValue().isSuccess())) {
dto.setTotalStatus(ExecuteResult.FAIL.getValue());
} else {
dto.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
}
}
if (StringUtils.isNotEmpty(dto.getErrorCode()) && StringUtils.isEmpty(dto.getTotalStatus())) {
@ -342,7 +308,7 @@ public class ApiScenarioReportStructureService {
}
if (CollectionUtils.isNotEmpty(dto.getChildren())) {
reportFormatting(dto.getChildren(), maps, StringUtils.equalsIgnoreCase(dto.getType(), "LoopController"));
reportFormatting(dto.getChildren(), maps);
if (StringUtils.isEmpty(dto.getErrorCode())) {
//统计child的errorCode合并到parent中
@ -361,9 +327,9 @@ public class ApiScenarioReportStructureService {
int errorReportCount = 0;
int successCount = 0;
for (StepTreeDTO child : dto.getChildren()) {
if (StringUtils.equalsIgnoreCase(child.getTotalStatus(), "fail")) {
if (StringUtils.equalsIgnoreCase(child.getTotalStatus(), ExecuteResult.FAIL.getValue())) {
failCount++;
} else if (StringUtils.equalsIgnoreCase(child.getTotalStatus(), "success")) {
} else if (StringUtils.equalsIgnoreCase(child.getTotalStatus(), ExecuteResult.API_SUCCESS.getValue())) {
successCount++;
} else if (StringUtils.equalsAnyIgnoreCase(child.getTotalStatus(), "errorCode", "errorReportResult")) {
errorReportCount++;
@ -374,23 +340,23 @@ public class ApiScenarioReportStructureService {
if (failCount == 0 && errorReportCount == 0 && successCount == 0) {
dto.setTotalStatus(ExecuteResult.UN_EXECUTE.toString());
} else if (successCount == dto.getChildren().size() || (successCount > 0 && errorReportCount == 0 && failCount == 0)) {
dto.setTotalStatus("success");
dto.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
} else {
if (StringUtils.equalsIgnoreCase(dto.getType(), "scenario")) {
if (failCount > 0) {
dto.setTotalStatus("fail");
dto.setTotalStatus(ExecuteResult.FAIL.getValue());
} else if (errorReportCount > 0) {
dto.setTotalStatus("errorCode");
} else {
dto.setTotalStatus("success");
dto.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
}
} else {
if (failCount > 0) {
dto.setTotalStatus("fail");
dto.setTotalStatus(ExecuteResult.FAIL.getValue());
} else if (errorReportCount > 0) {
dto.setTotalStatus("errorCode");
} else {
dto.setTotalStatus("success");
dto.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
}
}
}
@ -398,12 +364,10 @@ public class ApiScenarioReportStructureService {
if (StringUtils.isEmpty(dto.getTotalStatus())) {
dto.setTotalStatus(ExecuteResult.UN_EXECUTE.toString());
} else if (StringUtils.equalsAnyIgnoreCase(dto.getTotalStatus(), "error")) {
dto.setTotalStatus("fail");
dto.setTotalStatus(ExecuteResult.FAIL.getValue());
}
}
if (isLoops) {
this.orderLoops(dtoList);
}
this.orderLoops(dtoList);
}
/**
@ -411,7 +375,7 @@ public class ApiScenarioReportStructureService {
*/
private void orderLoops(List<StepTreeDTO> dtoList) {
try {
List<StepTreeDTO> steps = dtoList.stream().filter(e -> e.getValue() == null || StringUtils.isEmpty(e.getValue().getId()))
List<StepTreeDTO> steps = dtoList.stream().filter(e -> e.getValue() == null || e.getValue().getStartTime() == 0)
.collect(Collectors.toList());
// 都是没有结果的步骤不需要再次排序
if (dtoList.size() == steps.size()) {
@ -503,9 +467,9 @@ public class ApiScenarioReportStructureService {
treeDTO.setTotalStatus(expandDTO.getStatus());
} else {
if (expandDTO.isSuccess()) {
treeDTO.setTotalStatus("success");
treeDTO.setTotalStatus(ExecuteResult.API_SUCCESS.getValue());
} else {
treeDTO.setTotalStatus("fail");
treeDTO.setTotalStatus(ExecuteResult.FAIL.getValue());
}
}
}
@ -613,7 +577,7 @@ public class ApiScenarioReportStructureService {
// 匹配结果
Map<String, List<ApiScenarioReportResultWithBLOBs>> maps = reportResults.stream().collect(Collectors.groupingBy(ApiScenarioReportResult::getResourceId));
this.reportFormatting(stepList, maps, false);
this.reportFormatting(stepList, maps);
reportDTO = this.countReportNum(stepList, reportDTO);
// 统计场景数据
@ -637,7 +601,7 @@ public class ApiScenarioReportStructureService {
//统计未执行的请求数量
AtomicLong allUnExecute = new AtomicLong();
this.countAllUnexecute(stepList, allUnExecute);
this.countAllUnexpected(stepList, allUnExecute);
reportDTO.setUnExecute(allUnExecute.longValue());
//之前的total中请求数是按照获得报告的响应数来算的这里要加上未执行的数量
reportDTO.setTotal(reportDTO.getTotal() + allUnExecute.longValue());
@ -688,7 +652,7 @@ public class ApiScenarioReportStructureService {
}
}
private void countAllUnexecute(List<StepTreeDTO> stepList, AtomicLong allUnExecute) {
private void countAllUnexpected(List<StepTreeDTO> stepList, AtomicLong allUnExecute) {
for (StepTreeDTO step : stepList) {
if (step.getValue() != null) {
if (step.getValue() instanceof RequestResultExpandDTO
@ -697,7 +661,7 @@ public class ApiScenarioReportStructureService {
}
}
if (CollectionUtils.isNotEmpty(step.getChildren())) {
this.countAllUnexecute(step.getChildren(), allUnExecute);
this.countAllUnexpected(step.getChildren(), allUnExecute);
}
}
}

View File

@ -12,7 +12,10 @@ public enum ExecuteResult {
//场景执行状态(兼容旧数据)
SCENARIO_SUCCESS("Success"), SCENARIO_ERROR("Error"),
//测试计划执行状态(兼容旧数据)
TEST_PLAN_PREPARE("PREPARE"), TEST_PLAN_RUNNING("RUNNING");
TEST_PLAN_PREPARE("PREPARE"), TEST_PLAN_RUNNING("RUNNING"),
FAIL("fail");
private String value;
ExecuteResult(String value) {
@ -24,4 +27,7 @@ public enum ExecuteResult {
return this.value;
}
public String getValue() {
return this.value;
}
}

View File

@ -20,6 +20,7 @@
<span style="margin-left: 10px">{{$t('report.test_end_time')}}</span>
<span class="time"> {{ report.endTime | timestampFormatDate }}</span>
</span>
<div style="float: right">
<el-button v-if="!isPlan && (!debug || exportFlag) && !isTemplate && !isUi" v-permission="['PROJECT_API_REPORT:READ+EXPORT']" :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
{{ $t('test_track.plan_view.export_report') }}
</el-button>
@ -52,7 +53,7 @@
<el-button v-if="showCancelButton" class="export-button" plain size="mini" @click="returnView" >
{{$t('commons.cancel')}}
</el-button>
</div>
</el-col>
</el-row>
</header>
@ -136,6 +137,7 @@ export default {
this.$error(res.data);
}else{
this.$success("已经开始重跑,稍后刷新结果查看");
this.returnView();
}
});
},

View File

@ -10,8 +10,8 @@
</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 class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
<el-tab-pane style="min-height: 500px" name="third" v-if="errorReportEnable">
@ -20,8 +20,8 @@
</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 class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
@ -32,8 +32,8 @@
<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 class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
@ -43,8 +43,8 @@
</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 class="rerun-button" plain size="mini" v-if="showRerunBtn && (failureSize > 0 || unExecuteSize > 0) && isRerun" @click="rerun">
{{ $t('api_test.automation.rerun') }}
</el-button>
</el-tab-pane>
@ -69,12 +69,12 @@ export default {
activeName: 'first',
failureSize: 0,
errorReportSize: 0,
unExecuteSize:0,
unExecuteSize: 0,
allSize: 0,
showRerunBtn: true,
};
},
created(){
created() {
this.showRerunBtn = hasLicense();
},
props: [
@ -101,6 +101,13 @@ export default {
let disable = this.report.config && this.report.config.api.children.all.enable === false;
return !disable;
},
isRerun() {
return ((this.report && this.report.apiFailureCases)
|| (this.report && this.report.unExecuteCases)
|| (this.report && this.report.scenarioFailureCases)
|| (this.report && this.report.unExecuteScenarios)
|| (this.report && this.report.loadFailureCases));
}
},
watch: {
resultEnable() {
@ -137,7 +144,7 @@ export default {
setErrorReportSize(size) {
this.errorReportSize = size;
},
setUnExecuteSize(size){
setUnExecuteSize(size) {
this.unExecuteSize = size;
},
setAllSize(size) {
@ -145,7 +152,7 @@ export default {
},
handleClick(tab, event) {
},
rerun(){
rerun() {
let type = "TEST_PLAN";
let scenarios = [];
let cases = [];
@ -158,24 +165,23 @@ export default {
performanceCases: performanceCases
}
//
if(this.report && this.report.apiFailureCases){
this.format(cases,this.report.apiFailureCases);
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.unExecuteCases) {
this.format(cases, this.report.unExecuteCases);
}
//
if(this.report && this.report.scenarioFailureCases){
this.format(scenarios,this.report.scenarioFailureCases);
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.unExecuteScenarios) {
this.format(scenarios, this.report.unExecuteScenarios);
}
//
if(this.report && this.report.loadFailureCases){
this.format(performanceCases,this.report.loadFailureCases);
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);
@ -184,11 +190,11 @@ export default {
}
});
},
format(cases, datas){
if(this.report && datas){
datas.forEach(item=>{
if(item){
let obj = {id: item.id, reportId: item.reportId,userId:item.createUser};
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);
}
});
@ -199,13 +205,13 @@ export default {
</script>
<style scoped>
.rerun-button {
position: absolute;
top: 10px;
right: 10px;
margin-right: 10px;
z-index: 1100;
background-color: #F2F9EF;
color: #87C45D;
}
.rerun-button {
position: absolute;
top: 10px;
right: 10px;
margin-right: 10px;
z-index: 1100;
background-color: #F2F9EF;
color: #87C45D;
}
</style>

View File

@ -2750,7 +2750,7 @@ export default {
report_name: "Report name",
run_with_resource_pool: "Run Within Resource pool",
retry_on_failure: "retry on failure",
retry_message: "Retry the interface/UI use case, if it still fails after retries n times, use the failed use case",
retry_message: "Retry the interface/UI use case, if it still fails after retries n times, the use case failed",
retry: "Retry",
retry_frequency: "Frequency"
},

View File

@ -2758,7 +2758,7 @@ export default {
report_name: "报告名称",
run_with_resource_pool: "资源池运行",
retry_on_failure: "失败重试",
retry_message: "重试接口/UI用例重试n次后仍然失败则用失败用例",
retry_message: "重试接口/UI用例重试n次后仍然失败则用失败",
retry: "重试",
retry_frequency: "次"
},

View File

@ -2752,7 +2752,7 @@ export default {
report_name: "報告名稱",
run_with_resource_pool: "資源池運行",
retry_on_failure: "失敗重試",
retry_message: "重試接口/UI用例重試n次後仍然失敗則用失敗用例",
retry_message: "重試接口/UI用例重試n次後仍然失敗則用失敗",
retry: "重試",
retry_frequency: "次"
},