feat: UI报告处理

This commit is contained in:
chenjianxing 2022-04-11 16:47:55 +08:00 committed by jianxing
parent a974dafb81
commit 9c222f0aea
9 changed files with 89 additions and 47 deletions

View File

@ -16,4 +16,5 @@ public class ApiScenarioReportBaseInfoDTO {
private long reqStartTime; private long reqStartTime;
private String rspCode; private String rspCode;
private long rspTime; private long rspTime;
private String uiImg;
} }

View File

@ -14,6 +14,8 @@ import java.util.Map;
@Setter @Setter
public class RequestResultExpandDTO extends RequestResult { public class RequestResultExpandDTO extends RequestResult {
private String status; private String status;
private String uiImg;
private long time;
private Map<String, String> attachInfoMap; private Map<String, String> attachInfoMap;
public RequestResultExpandDTO() { public RequestResultExpandDTO() {
@ -27,6 +29,9 @@ public class RequestResultExpandDTO extends RequestResult {
this.setSuccess(dto.isReqSuccess()); this.setSuccess(dto.isReqSuccess());
this.setError(dto.getReqError()); this.setError(dto.getReqError());
this.setStartTime(dto.getReqStartTime()); this.setStartTime(dto.getReqStartTime());
this.setTime(dto.getRspTime());
this.setEndTime(dto.getRspTime() - dto.getReqStartTime());
this.setUiImg(dto.getUiImg());
ResponseResult responseResult = this.getResponseResult(); ResponseResult responseResult = this.getResponseResult();
responseResult.setResponseCode(dto.getRspCode()); responseResult.setResponseCode(dto.getRspCode());
responseResult.setResponseTime(dto.getRspTime()); responseResult.setResponseTime(dto.getRspTime());

View File

@ -10,6 +10,8 @@ import java.util.List;
@Data @Data
public class StepTreeDTO { public class StepTreeDTO {
private String type; private String type;
// ui 指令的类型
private String cmdType;
private int index; private int index;
private String resourceId; private String resourceId;
private String label; private String label;

View File

@ -93,6 +93,19 @@ public class ApiScenarioReportResultService {
} }
private ApiScenarioReportResultWithBLOBs newUiScenarioReportResult(String reportId, String resourceId, JSONObject value) { private ApiScenarioReportResultWithBLOBs newUiScenarioReportResult(String reportId, String resourceId, JSONObject value) {
ApiScenarioReportResultWithBLOBs report = newScenarioReportResult(reportId, resourceId);
String status = value.getBooleanValue("success") ? ExecuteResult.Success.name() : ExecuteResult.Error.name();
report.setStatus(status);
RequestResult result = JSONObject.parseObject(value.toJSONString(), RequestResult.class);
ApiScenarioReportBaseInfoDTO baseInfo = getBaseInfo(result);
baseInfo.setRspTime(result.getEndTime() - result.getStartTime());
baseInfo.setUiImg(result.getUrl());
report.setBaseInfo(JSONObject.toJSONString(baseInfo));
report.setContent(value.toJSONString().getBytes(StandardCharsets.UTF_8));
return report;
}
private ApiScenarioReportResultWithBLOBs newScenarioReportResult(String reportId, String resourceId) {
ApiScenarioReportResultWithBLOBs report = new ApiScenarioReportResultWithBLOBs(); ApiScenarioReportResultWithBLOBs report = new ApiScenarioReportResultWithBLOBs();
report.setId(UUID.randomUUID().toString()); report.setId(UUID.randomUUID().toString());
report.setResourceId(resourceId); report.setResourceId(resourceId);
@ -100,33 +113,11 @@ public class ApiScenarioReportResultService {
report.setTotalAssertions(0L); report.setTotalAssertions(0L);
report.setPassAssertions(0L); report.setPassAssertions(0L);
report.setCreateTime(System.currentTimeMillis()); report.setCreateTime(System.currentTimeMillis());
String status = value.getBooleanValue("success") ? ExecuteResult.Success.name() : ExecuteResult.Error.name();
report.setStatus(status);
report.setContent(value.toJSONString().getBytes(StandardCharsets.UTF_8));
return report; return report;
} }
private ApiScenarioReportResultWithBLOBs newApiScenarioReportResult(String reportId, RequestResult baseResult) { //记录基础信息
ApiScenarioReportResultWithBLOBs report = new ApiScenarioReportResultWithBLOBs(); private ApiScenarioReportBaseInfoDTO getBaseInfo(RequestResult result) {
//解析误报内容
ErrorReportLibraryParseDTO errorCodeDTO = ErrorReportLibraryUtil.parseAssertions(baseResult);
RequestResult result = errorCodeDTO.getResult();
report.setId(UUID.randomUUID().toString());
String resourceId = result.getResourceId();
report.setResourceId(resourceId);
report.setReportId(reportId);
report.setTotalAssertions(Long.parseLong(result.getTotalAssertions() + ""));
report.setPassAssertions(Long.parseLong(result.getPassAssertions() + ""));
report.setCreateTime(System.currentTimeMillis());
String status = result.getError() == 0 ? ExecuteResult.Success.name() : ExecuteResult.Error.name();
if (CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())) {
status = ExecuteResult.errorReportResult.name();
report.setErrorCode(errorCodeDTO.getErrorCodeStr());
}
report.setStatus(status);
report.setRequestTime(result.getEndTime() - result.getStartTime());
//记录基础信息
ApiScenarioReportBaseInfoDTO baseInfoDTO = new ApiScenarioReportBaseInfoDTO(); ApiScenarioReportBaseInfoDTO baseInfoDTO = new ApiScenarioReportBaseInfoDTO();
baseInfoDTO.setReqName(result.getName()); baseInfoDTO.setReqName(result.getName());
baseInfoDTO.setReqSuccess(result.isSuccess()); baseInfoDTO.setReqSuccess(result.isSuccess());
@ -136,7 +127,27 @@ public class ApiScenarioReportResultService {
baseInfoDTO.setRspCode(result.getResponseResult().getResponseCode()); baseInfoDTO.setRspCode(result.getResponseResult().getResponseCode());
baseInfoDTO.setRspTime(result.getResponseResult().getResponseTime()); baseInfoDTO.setRspTime(result.getResponseResult().getResponseTime());
} }
report.setBaseInfo(JSONObject.toJSONString(baseInfoDTO)); return baseInfoDTO;
}
private ApiScenarioReportResultWithBLOBs newApiScenarioReportResult(String reportId, RequestResult baseResult) {
//解析误报内容
ErrorReportLibraryParseDTO errorCodeDTO = ErrorReportLibraryUtil.parseAssertions(baseResult);
RequestResult result = errorCodeDTO.getResult();
String resourceId = result.getResourceId();
ApiScenarioReportResultWithBLOBs report = newScenarioReportResult(reportId, resourceId);
report.setTotalAssertions(Long.parseLong(result.getTotalAssertions() + ""));
report.setPassAssertions(Long.parseLong(result.getPassAssertions() + ""));
String status = result.getError() == 0 ? ExecuteResult.Success.name() : ExecuteResult.Error.name();
if (CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())) {
status = ExecuteResult.errorReportResult.name();
report.setErrorCode(errorCodeDTO.getErrorCodeStr());
}
report.setStatus(status);
report.setRequestTime(result.getEndTime() - result.getStartTime());
report.setBaseInfo(JSONObject.toJSONString(getBaseInfo(result)));
report.setContent(JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8)); report.setContent(JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8));
return report; return report;
} }
@ -156,16 +167,7 @@ public class ApiScenarioReportResultService {
try { try {
RequestResult requestResult = JSON.parseObject(new String(baseResult.getContent(), StandardCharsets.UTF_8), RequestResult.class); RequestResult requestResult = JSON.parseObject(new String(baseResult.getContent(), StandardCharsets.UTF_8), RequestResult.class);
//记录基础信息 //记录基础信息
ApiScenarioReportBaseInfoDTO baseInfo = new ApiScenarioReportBaseInfoDTO(); baseResult.setBaseInfo(JSONObject.toJSONString(getBaseInfo(requestResult)));
baseInfo.setReqName(StringUtils.isEmpty(requestResult.getName()) ? "" : requestResult.getName());
baseInfo.setReqSuccess(requestResult.isSuccess());
baseInfo.setReqError(requestResult.getError());
baseInfo.setReqStartTime(requestResult.getStartTime());
if (requestResult.getResponseResult() != null) {
baseInfo.setRspCode(requestResult.getResponseResult().getResponseCode());
baseInfo.setRspTime(requestResult.getResponseResult().getResponseTime());
}
baseResult.setBaseInfo(JSONObject.toJSONString(baseInfo));
apiScenarioReportResultMapper.updateByPrimaryKeySelective(baseResult); apiScenarioReportResultMapper.updateByPrimaryKeySelective(baseResult);
return baseResult; return baseResult;
} catch (Exception e) { } catch (Exception e) {

View File

@ -20,6 +20,7 @@ import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants; import io.metersphere.constants.RunModeConstants;
import io.metersphere.dto.RequestResult; import io.metersphere.dto.RequestResult;
import io.metersphere.utils.LoggerUtil; import io.metersphere.utils.LoggerUtil;
import io.metersphere.commons.constants.CommandType;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -176,6 +177,7 @@ public class ApiScenarioReportStructureService {
children.setAllIndex("" + (children.getIndex() == 0 ? (i + 1) : children.getIndex())); children.setAllIndex("" + (children.getIndex() == 0 ? (i + 1) : children.getIndex()));
children.setResourceId(resourceId + "_" + children.getAllIndex()); children.setResourceId(resourceId + "_" + children.getAllIndex());
} }
children.setCmdType(element.getString("commandType"));
dto.getChildren().add(children); dto.getChildren().add(children);
if (element.containsKey("hashTree") && !requests.contains(children.getType())) { if (element.containsKey("hashTree") && !requests.contains(children.getType())) {
JSONArray elementJSONArray = element.getJSONArray("hashTree"); JSONArray elementJSONArray = element.getJSONArray("hashTree");
@ -307,7 +309,7 @@ public class ApiScenarioReportStructureService {
dto.setErrorCode(reportResults.get(0).getErrorCode()); dto.setErrorCode(reportResults.get(0).getErrorCode());
} }
} }
if (StringUtils.isNotEmpty(dto.getType()) && requests.contains(dto.getType()) && dto.getValue() == null) { if (StringUtils.isNotEmpty(dto.getType()) && requests.contains(dto.getType()) && dto.getValue() == null || isUiUnExecuteCommand(dto)) {
RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO(); RequestResultExpandDTO requestResultExpandDTO = new RequestResultExpandDTO();
requestResultExpandDTO.setStatus("unexecute"); requestResultExpandDTO.setStatus("unexecute");
requestResultExpandDTO.setName(dto.getLabel()); requestResultExpandDTO.setName(dto.getLabel());
@ -415,6 +417,14 @@ public class ApiScenarioReportStructureService {
} }
} }
private boolean isUiUnExecuteCommand(StepTreeDTO dto) {
if (dto.getType().equals("MsUiCommand") && dto.getValue() == null
&& (StringUtils.isBlank(dto.getCmdType()) || !dto.getCmdType().equalsIgnoreCase(CommandType.COMMAND_TYPE_COMBINATION))) {
return true;
}
return false;
}
private List<ApiDefinitionExecResultVo> formatApiReport(String reportId, List<StepTreeDTO> stepList) { private List<ApiDefinitionExecResultVo> formatApiReport(String reportId, List<StepTreeDTO> stepList) {
ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample(); ApiDefinitionExecResultExample example = new ApiDefinitionExecResultExample();
example.createCriteria().andIntegratedReportIdEqualTo(reportId); example.createCriteria().andIntegratedReportIdEqualTo(reportId);

View File

@ -0,0 +1,12 @@
package io.metersphere.commons.constants;
/**
* atomic 原子指令前端 后端 一对一
* combine 前端指令包含了多个指令实现 比如 IF 指令if 指令必须有 start end
* proxy 前端指令使用了代理模式 比如前端选择等待元素指令实际上还有一个子类别具体选择waitForElement 还是 waitForEditable
*/
public class CommandType {
public static final String COMMAND_TYPE_ATOM = "atom";
public static final String COMMAND_TYPE_COMBINATION = "combination";
public static final String COMMAND_TYPE_PROXY = "proxy";
}

View File

@ -13,14 +13,19 @@
<div> <div>
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label="$t('api_report.total')" name="total"> <el-tab-pane :label="$t('api_report.total')" name="total">
<ms-scenario-results :treeData="fullTreeNodes" :console="content.console" <ms-scenario-results :treeData="fullTreeNodes"
v-on:requestResult="requestResult" ref="resultsTree"/> :console="content.console"
:report="report"
v-on:requestResult="requestResult"
ref="resultsTree"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="fail"> <el-tab-pane name="fail">
<template slot="label"> <template slot="label">
<span class="fail">{{ $t('api_report.fail') }}</span> <span class="fail">{{ $t('api_report.fail') }}</span>
</template> </template>
<ms-scenario-results v-on:requestResult="requestResult" :console="content.console" <ms-scenario-results v-on:requestResult="requestResult"
:console="content.console"
:report="report"
:treeData="fullTreeNodes" ref="failsTree" :treeData="fullTreeNodes" ref="failsTree"
:errorReport="content.error"/> :errorReport="content.error"/>
</el-tab-pane> </el-tab-pane>
@ -28,14 +33,18 @@
<template slot="label"> <template slot="label">
<span class="fail" style="color: #F6972A">{{ $t('error_report_library.option.name') }}</span> <span class="fail" style="color: #F6972A">{{ $t('error_report_library.option.name') }}</span>
</template> </template>
<ms-scenario-results v-on:requestResult="requestResult" :console="content.console" <ms-scenario-results v-on:requestResult="requestResult"
:report="report"
:console="content.console"
:treeData="fullTreeNodes" ref="errorReportTree"/> :treeData="fullTreeNodes" ref="errorReportTree"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="unExecute" v-if="content.unExecute > 0"> <el-tab-pane name="unExecute" v-if="content.unExecute > 0">
<template slot="label"> <template slot="label">
<span class="fail" style="color: #9C9B9A">{{ $t('api_test.home_page.detail_card.unexecute') }}</span> <span class="fail" style="color: #9C9B9A">{{ $t('api_test.home_page.detail_card.unexecute') }}</span>
</template> </template>
<ms-scenario-results v-on:requestResult="requestResult" :console="content.console" <ms-scenario-results v-on:requestResult="requestResult"
:report="report"
:console="content.console"
:treeData="fullTreeNodes" ref="unExecuteTree"/> :treeData="fullTreeNodes" ref="unExecuteTree"/>
</el-tab-pane> </el-tab-pane>
<el-tab-pane name="console"> <el-tab-pane name="console">

View File

@ -33,6 +33,7 @@ export default {
treeData: Array, treeData: Array,
console: String, console: String,
errorReport: Number, errorReport: Number,
report: Object,
defaultExpand: { defaultExpand: {
default: false, default: false,
type: Boolean, type: Boolean,

View File

@ -13,8 +13,8 @@
</el-col> </el-col>
<el-col :span="3"> <el-col :span="3">
<span v-if="!isUnexecute" :style="!result.success ? 'color: #FE6F71' : ''"> <span v-if="!isUnexecute" :style="result && !result.success ? 'color: #FE6F71' : ''">
{{ result.endTime - result.startTime }} ms {{ result.time }} ms
</span> </span>
</el-col> </el-col>
@ -26,8 +26,8 @@
v-if="!isUnexecute"> v-if="!isUnexecute">
<el-image <el-image
style="width: 100px; height: 100px" style="width: 100px; height: 100px"
:src="'/resource/ui/get?fileName=' + result.url" :src="'/resource/ui/get?fileName=' + result.uiImg"
:preview-src-list="['/resource/ui/get?fileName=' + result.url]"> :preview-src-list="['/resource/ui/get?fileName=' + result.uiImg]">
</el-image> </el-image>
<el-button slot="reference" type="text">{{ $t('截图') }}</el-button> <el-button slot="reference" type="text">{{ $t('截图') }}</el-button>
</el-popover> </el-popover>
@ -38,7 +38,7 @@
<el-tag size="mini" v-if="isUnexecute"> <el-tag size="mini" v-if="isUnexecute">
{{ $t('api_test.home_page.detail_card.unexecute') }} {{ $t('api_test.home_page.detail_card.unexecute') }}
</el-tag> </el-tag>
<el-tag size="mini" type="success" v-else-if="result.success"> <el-tag size="mini" type="success" v-else-if="result && result.success">
{{ $t('api_report.success') }} {{ $t('api_report.success') }}
</el-tag> </el-tag>
<el-tooltip v-else :content="result.body" placement="top"> <el-tooltip v-else :content="result.body" placement="top">
@ -70,7 +70,7 @@ export default {
return this.command.label; return this.command.label;
}, },
isUnexecute() { isUnexecute() {
return this.result && this.result.status === 'unexecute'; return !this.result || this.result.status === 'unexecute';
} }
}, },
data() { data() {