feat(误报库): 接口测试增加误报筛选功能

接口测试增加误报筛选功能
This commit is contained in:
song-tianyang 2022-01-13 10:24:53 +08:00 committed by song-tianyang
parent f143e68b32
commit ff8dccbc7a
18 changed files with 260 additions and 93 deletions

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Setter
@Getter

View File

@ -0,0 +1,14 @@
package io.metersphere.api.dto;
import io.metersphere.dto.RequestResult;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
@Getter
@Setter
public class RequestResultExpandDTO extends RequestResult {
private String status;
private Map<String,String> attachInfoMap;
}

View File

@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import io.metersphere.api.dto.definition.parse.JMeterScriptUtil;
import io.metersphere.api.dto.definition.request.ElementUtil;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.assertions.MsAssertions;
import io.metersphere.api.dto.definition.request.auth.MsAuthManager;
import io.metersphere.api.dto.definition.request.dns.MsDNSCacheManager;
import io.metersphere.api.dto.definition.request.processors.post.MsJSR223PostProcessor;
@ -37,6 +38,7 @@ import io.metersphere.commons.constants.MsTestElementConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.FileUtils;
import io.metersphere.commons.utils.HashTreeUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.constants.RunModeConstants;
import io.metersphere.jmeter.utils.ScriptEngineUtils;
@ -281,6 +283,20 @@ public class MsHTTPSamplerProxy extends MsTestElement {
this.setScript(httpConfig, httpSamplerTree, config, false);
}
HashTreeUtil hashTreeUtil = new HashTreeUtil();
//增加误报断言
if (httpConfig != null) {
if (CollectionUtils.isNotEmpty(httpConfig.getErrorReportAssertions())) {
for (MsAssertions assertion : httpConfig.getErrorReportAssertions()) {
assertion.toHashTree(httpSamplerTree, assertion.getHashTree(), config);
}
}
if (CollectionUtils.isNotEmpty(httpConfig.getAssertions())) {
for (MsAssertions assertion : httpConfig.getAssertions()) {
assertion.toHashTree(httpSamplerTree, assertion.getHashTree(), config);
}
}
}
if (CollectionUtils.isNotEmpty(hashTree)) {
for (MsTestElement el : hashTree) {
if (el.getEnvironmentId() == null) {
@ -290,6 +306,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
el.setEnvironmentId(this.getEnvironmentId());
}
}
if (el instanceof MsAssertions) {
//断言设置需要和全局断言误报进行去重
el = hashTreeUtil.duplicateRegexInAssertions(httpConfig.getAssertions(), (MsAssertions) el);
}
el.toHashTree(httpSamplerTree, el.getHashTree(), config);
}
}
@ -387,6 +407,10 @@ public class MsHTTPSamplerProxy extends MsTestElement {
httpConfig.setPreProcessor(environmentConfig.getPreProcessor());
httpConfig.setPostProcessor(environmentConfig.getPostProcessor());
httpConfig.setGlobalScriptConfig(environmentConfig.getGlobalScriptConfig());
httpConfig.setAssertions(environmentConfig.getAssertions());
if (environmentConfig.isUseErrorCode()) {
httpConfig.setErrorReportAssertions(HashTreeUtil.getErrorReportByProjectId(this.getProjectId()));
}
return httpConfig;
}
}
@ -407,11 +431,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
String url = httpConfig.getProtocol() + "://" + httpConfig.getSocket();
// 补充如果是完整URL 则用自身URL
if (StringUtils.isNotEmpty(this.getUrl()) && ElementUtil.isURL(this.getUrl())) {
url = this.getUrl();
}
if (isUrl()) {
// 补充如果是完整URL 则用自身URL
if (StringUtils.isNotEmpty(this.getUrl()) && ElementUtil.isURL(this.getUrl())) {
url = this.getUrl();
}
if (this.isCustomizeReq()) {
url = this.getUrl();
sampler.setProperty("HTTPSampler.path", url);
@ -633,6 +657,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
return true;
}
if (StringUtils.isNotEmpty(this.getUrl()) && ElementUtil.isURL(this.getUrl())) {
return true;
}
return false;
}
@ -722,22 +749,22 @@ public class MsHTTPSamplerProxy extends MsTestElement {
list.stream().
filter(KeyValue::isValid).
filter(KeyValue::isEnable).forEach(keyValue -> {
try {
String value = StringUtils.isNotEmpty(keyValue.getValue()) && keyValue.getValue().startsWith("@") ? ScriptEngineUtils.buildFunctionCallString(keyValue.getValue()) : keyValue.getValue();
HTTPArgument httpArgument = new HTTPArgument(keyValue.getName(), value);
if (keyValue.getValue() == null) {
httpArgument.setValue("");
}
httpArgument.setAlwaysEncoded(keyValue.isUrlEncode());
if (StringUtils.isNotBlank(keyValue.getContentType())) {
httpArgument.setContentType(keyValue.getContentType());
}
arguments.addArgument(httpArgument);
} catch (Exception e) {
try {
String value = StringUtils.isNotEmpty(keyValue.getValue()) && keyValue.getValue().startsWith("@") ? ScriptEngineUtils.buildFunctionCallString(keyValue.getValue()) : keyValue.getValue();
HTTPArgument httpArgument = new HTTPArgument(keyValue.getName(), value);
if (keyValue.getValue() == null) {
httpArgument.setValue("");
}
httpArgument.setAlwaysEncoded(keyValue.isUrlEncode());
if (StringUtils.isNotBlank(keyValue.getContentType())) {
httpArgument.setContentType(keyValue.getContentType());
}
arguments.addArgument(httpArgument);
} catch (Exception e) {
}
}
);
}
}
);
return arguments;
}
@ -809,23 +836,19 @@ public class MsHTTPSamplerProxy extends MsTestElement {
}
} else {
apiDefinition = apiDefinitionService.get(this.getId());
apiDefinition = apiDefinition == null ? apiDefinitionService.get(this.getName()) : apiDefinition;
if (apiDefinition == null) {
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(this.getId());
if (apiTestCaseWithBLOBs == null) {
apiTestCaseWithBLOBs = apiTestCaseService.get(this.getName());
}
if (apiTestCaseWithBLOBs != null) {
apiDefinition = apiDefinitionService.get(apiTestCaseWithBLOBs.getApiDefinitionId());
} else {
TestPlanApiCaseService testPlanApiCaseService = CommonBeanFactory.getBean(TestPlanApiCaseService.class);
TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(this.getId());
testPlanApiCase = testPlanApiCase == null ? testPlanApiCaseService.getById(this.getName()) : testPlanApiCase;
if (testPlanApiCase != null) {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseService.get(testPlanApiCase.getApiCaseId());
if (caseWithBLOBs != null) {
apiDefinition = apiDefinitionService.get(caseWithBLOBs.getApiDefinitionId());
}
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = apiTestCaseService.get(this.getId());
if (apiTestCaseWithBLOBs == null) {
apiTestCaseWithBLOBs = apiTestCaseService.get(this.getName());
}
if (apiTestCaseWithBLOBs != null) {
apiDefinition = apiDefinitionService.get(apiTestCaseWithBLOBs.getApiDefinitionId());
} else {
TestPlanApiCaseService testPlanApiCaseService = CommonBeanFactory.getBean(TestPlanApiCaseService.class);
TestPlanApiCase testPlanApiCase = testPlanApiCaseService.getById(this.getId());
if (testPlanApiCase != null) {
ApiTestCaseWithBLOBs caseWithBLOBs = apiTestCaseService.get(testPlanApiCase.getApiCaseId());
if (caseWithBLOBs != null) {
apiDefinition = apiDefinitionService.get(caseWithBLOBs.getApiDefinitionId());
}
}
}

View File

@ -18,10 +18,13 @@
package io.metersphere.api.jmeter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ErrorReportLibraryParseDTO;
import io.metersphere.api.dto.RunningParamKeys;
import io.metersphere.api.exec.queue.PoolExecBlockingQueueUtil;
import io.metersphere.api.service.MsResultService;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.ErrorReportLibraryUtil;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.RequestResult;
import io.metersphere.jmeter.JMeterBase;
@ -149,10 +152,12 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
if (isSampleWanted(result.isSuccessful()) && !StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) {
RequestResult requestResult = JMeterBase.getRequestResult(result);
if (requestResult != null) {
MsgDto dto = new MsgDto();
dto.setExecEnd(false);
dto.setReportId("send." + this.getName());
dto.setToReport(this.getName());
String console = CommonBeanFactory.getBean(MsResultService.class).getJmeterLogger(this.getName());
if (StringUtils.isNotEmpty(requestResult.getName()) && requestResult.getName().startsWith("Transaction=")) {
requestResult.getSubRequestResults().forEach(transactionResult -> {
@ -161,8 +166,15 @@ public class MsDebugListener extends AbstractListenerElement implements SampleLi
WebSocketUtils.sendMessageSingle(dto);
});
} else {
//解析误报内容
JSONObject requestResultObject = JSONObject.parseObject(JSON.toJSONString(requestResult));
ErrorReportLibraryParseDTO errorCodeDTO = ErrorReportLibraryUtil.parseAssertions(requestResult);
if(CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())){
requestResultObject.put("errorReportResult",errorCodeDTO.getErrorCodeStr());
}
requestResult.getResponseResult().setConsole(console);
dto.setContent("result_" + JSON.toJSONString(requestResult));
dto.setContent("result_" + JSON.toJSONString(requestResultObject));
WebSocketUtils.sendMessageSingle(dto);
}
LoggerUtil.debug("send. " + this.getName());

View File

@ -2,6 +2,8 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.ErrorReportLibraryParseDTO;
import io.metersphere.api.dto.RequestResultExpandDTO;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
@ -10,9 +12,7 @@ import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.TestCaseReviewApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.commons.utils.*;
import io.metersphere.dto.RequestResult;
import io.metersphere.dto.ResultDTO;
import io.metersphere.notice.sender.NoticeModel;
@ -28,6 +28,7 @@ import io.metersphere.track.service.TestPlanTestCaseService;
import io.metersphere.utils.LoggerUtil;
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;
@ -329,14 +330,24 @@ public class ApiDefinitionExecResultService {
if (StringUtils.isEmpty(saveResult.getActuator())) {
saveResult.setActuator("LOCAL");
}
String status = item.isSuccess() ? ExecuteResult.success.name() : ExecuteResult.error.name();
//对响应内容进行进一步解析如果有附加信息比如误报库信息则根据附加信息内的数据进行其他判读
RequestResultExpandDTO expandDTO = ResponseUtil.parseByRequestResult(item);
if(MapUtils.isNotEmpty(expandDTO.getAttachInfoMap())){
status = expandDTO.getStatus();
saveResult.setContent(JSON.toJSONString(expandDTO));
}else {
saveResult.setContent(JSON.toJSONString(item));
}
saveResult.setName(item.getName());
saveResult.setType(type);
saveResult.setCreateTime(item.getStartTime());
String status = item.isSuccess() ? ExecuteResult.success.name() : ExecuteResult.error.name();
saveResult.setName(editStatus(type, status, saveResult.getCreateTime(), saveResult.getId(), testId));
saveResult.setStatus(status);
saveResult.setResourceId(item.getName());
saveResult.setContent(JSON.toJSONString(item));
saveResult.setStartTime(item.getStartTime());
saveResult.setEndTime(item.getResponseResult().getResponseTime());
// 清空上次执行结果的内容只保留近五条结果

View File

@ -59,7 +59,7 @@ public class ApiScenarioReportResultService {
report.setCreateTime(System.currentTimeMillis());
String status = result.getError() == 0 ? ExecuteResult.Success.name() : ExecuteResult.Error.name();
if(CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())){
status = ExecuteResult.errorCode.name();
status = ExecuteResult.errorReportResult.name();
report.setErrorCode(errorCodeDTO.getErrorCodeStr());
}
report.setStatus(status);

View File

@ -720,8 +720,22 @@ public class ApiScenarioReportService {
}
private String getStatus(List<ApiScenarioReportResult> requestResults, ResultDTO dto) {
long errorSize = requestResults.stream().filter(requestResult -> StringUtils.equalsIgnoreCase(requestResult.getStatus(), ScenarioStatus.Error.name())).count();
String status = errorSize > 0 || requestResults.isEmpty() ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name();
long errorSize = 0;
long errorReportResultSize = 0;
for (ApiScenarioReportResult result : requestResults) {
if (StringUtils.equalsIgnoreCase(result.getStatus(), ScenarioStatus.Error.name())) {
errorSize++;
} else if (StringUtils.equalsIgnoreCase(result.getStatus(), ExecuteResult.errorReportResult.name())) {
errorReportResultSize++;
}
}
String status;//增加误报状态判断
if(errorReportResultSize > 0){
status = ExecuteResult.errorReportResult.name();
}else {
status =errorSize > 0 || requestResults.isEmpty() ? ScenarioStatus.Error.name() : ScenarioStatus.Success.name();
}
if (dto != null && dto.getArbitraryData() != null && dto.getArbitraryData().containsKey("TIMEOUT") && (Boolean) dto.getArbitraryData().get("TIMEOUT")) {
LoggerUtil.info("报告 【 " + dto.getReportId() + " 】资源 " + dto.getTestId() + " 执行超时");
status = ScenarioStatus.Timeout.name();

View File

@ -138,11 +138,17 @@ public class ApiScenarioReportStructureService {
}
}
private void scenarioCalculate(List<StepTreeDTO> dtoList, AtomicLong isErrorReport) {
private void scenarioCalculate(List<StepTreeDTO> dtoList, AtomicLong isError, AtomicLong isErrorReport) {
for (StepTreeDTO step : dtoList) {
if (step.getValue() != null && StringUtils.isNotEmpty(step.getErrorCode())) {
isErrorReport.set(isErrorReport.longValue() + 1);
if (step.getValue() != null) {
if (StringUtils.isNotEmpty(step.getErrorCode())) {
isErrorReport.set(isErrorReport.longValue() + 1);
} else if (step.getValue().getError() > 0) {
isError.set(isError.longValue() + 1);
}
break;
} else if (CollectionUtils.isNotEmpty(step.getChildren())) {
scenarioCalculate(step.getChildren(), isError, isErrorReport);
}
}
}
@ -153,12 +159,12 @@ public class ApiScenarioReportStructureService {
totalScenario.set((totalScenario.longValue() + 1));
// 失败结果数量
AtomicLong error = new AtomicLong();
AtomicLong errorCode = new AtomicLong();
scenarioCalculate(step.getChildren(), errorCode);
AtomicLong errorReportCode = new AtomicLong();
scenarioCalculate(step.getChildren(), error, errorReportCode);
if (error.longValue() > 0) {
scenarioError.set((scenarioError.longValue() + 1));
}
if (errorCode.longValue() > 0) {
if (errorReportCode.longValue() > 0) {
errorReport.set((errorReport.longValue() + 1));
}
} else if (step.getValue() != null) {
@ -177,13 +183,8 @@ public class ApiScenarioReportStructureService {
private void calculateStep(List<StepTreeDTO> dtoList, AtomicLong stepError, AtomicLong stepTotal, AtomicLong stepErrorCode) {
for (StepTreeDTO step : dtoList) {
// 失败结果数量
stepErrorCalculate(step.getChildren(), stepError);
AtomicLong errorReport = new AtomicLong();
scenarioCalculate(step.getChildren(), errorReport);
if (errorReport.longValue() > 0) {
stepErrorCode.set((stepErrorCode.longValue() + 1));
}
// stepErrorCalculate(step.getChildren(), stepError);
scenarioCalculate(step.getChildren(), stepError, stepErrorCode);
if (CollectionUtils.isNotEmpty(step.getChildren())) {
stepTotal.set((stepTotal.longValue() + step.getChildren().size()));
}
@ -286,8 +287,7 @@ public class ApiScenarioReportStructureService {
//统计步骤数据
AtomicLong stepErrorCode = new AtomicLong();
calculateStep(stepList, stepError, stepTotal, stepErrorCode);
reportDTO.setScenarioStepSuccess((stepTotal.longValue() - stepError.longValue()));
reportDTO.setScenarioStepSuccess((stepTotal.longValue() - stepError.longValue() - stepErrorCode.longValue()));
reportDTO.setScenarioStepTotal(stepTotal.longValue());
reportDTO.setScenarioStepError(stepError.longValue());
reportDTO.setScenarioStepErrorReport(stepErrorCode.longValue());

View File

@ -2,11 +2,14 @@ package io.metersphere.commons.constants;
public enum ExecuteResult {
//误报状态
errorCode,
errorReportResult,
//接口执行状态(兼容旧数据)
success,error,
//场景执行状态(兼容旧数据)
Success,Error,
//测试计划执行状态(兼容旧数据)
PREPARE,RUNNING,SUCCESS,FAILD
}

View File

@ -0,0 +1,31 @@
package io.metersphere.commons.utils;
import io.metersphere.api.dto.ErrorReportLibraryParseDTO;
import io.metersphere.api.dto.RequestResultExpandDTO;
import io.metersphere.commons.constants.ExecuteResult;
import io.metersphere.dto.RequestResult;
import org.apache.commons.collections4.CollectionUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 请求返回解析工具
*/
public class ResponseUtil {
public static RequestResultExpandDTO parseByRequestResult(RequestResult requestResult) {
RequestResultExpandDTO expandDTO = new RequestResultExpandDTO();
BeanUtils.copyBean(expandDTO, requestResult);
//解析是否含有误报库信息
ErrorReportLibraryParseDTO errorCodeDTO = ErrorReportLibraryUtil.parseAssertions(requestResult);
if(CollectionUtils.isNotEmpty(errorCodeDTO.getErrorCodeList())){
Map<String, String> expandMap = new HashMap<>();
expandDTO.setStatus(ExecuteResult.errorReportResult.name());
expandMap.put(ExecuteResult.errorReportResult.name(), errorCodeDTO.getErrorCodeStr());
expandDTO.setAttachInfoMap(expandMap);
}
return expandDTO;
}
}

View File

@ -118,6 +118,7 @@ export default {
{text: 'Completed', value: 'Completed'},
{text: 'Error', value: 'Error'},
{text: 'Success', value: 'Success'},
{text: this.$t('error_report_library.option.name'), value: 'errorReportResult'},
],
triggerFilters: [
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},

View File

@ -15,6 +15,9 @@
<el-tag size="mini" type="danger" v-else-if="row.status === 'Error'">
{{ row.status }}
</el-tag>
<el-tag size="mini" type="danger" v-else-if="row.status === 'errorReportResult'">
{{ $t('error_report_library.option.name') }}
</el-tag>
<el-tag v-else size="mini" type="info">
{{ row.status }}
</el-tag>

View File

@ -284,7 +284,6 @@ export default {
this.totalTime = this.content.totalTime;
this.fullTreeNodes = this.content.steps;
this.recursiveSorting(this.fullTreeNodes);
console.info(this.fullTreeNodes);
this.reload();
}
});

View File

@ -17,28 +17,27 @@
<span class="ms-req-span"> {{content.success? content.success+content.error :0}} 请求</span>
</span>
</div>
<ms-chart id="chart" ref="chart" :options="options" :height="220" :autoresize="true" v-else/>
<el-row type="flex" justify="center" align="middle">
<ms-chart id="chart" ref="chart" :options="options" :height="220" style="margin-right: 10px" :autoresize="true" v-else/>
<el-row type="flex" justify="center" align="middle" style="width: 150px">
<div>
<div class="metric-icon-box" style="height: 26px">
<span class="ms-point-success" style="margin: 7px"/>
<div class="metric-box">
<div class="value">{{ content.success }} {{ $t('api_report.success') }}</div>
<div class="value" style="font-size: 12px">{{ content.success }} {{ $t('api_report.success') }}</div>
</div>
</div>
<el-divider></el-divider>
<div class="metric-icon-box" style="height: 26px">
<span class="ms-point-error" style="margin: 7px"/>
<div class="metric-box">
<div class="value">{{ content.error }} {{ $t('api_report.fail') }}</div>
<div class="value" style="font-size: 12px">{{ content.error }} {{ $t('api_report.fail') }}</div>
</div>
</div>
<el-divider v-if="content.errorCode > 0"></el-divider>
<div class="metric-icon-box" style="height: 26px">
<span class="ms-point-error-code" v-if="content.errorCode > 0" style="margin: 7px"/>
<div class="metric-box" v-if="content.errorCode > 0">
<div class="value">{{ content.errorCode }} {{ $t('error_report_library.option.name') }}</div>
<div class="value" style="font-size: 12px">{{ content.errorCode }} {{ $t('error_report_library.option.name') }}</div>
</div>
</div>
</div>

View File

@ -49,7 +49,7 @@
<i class="el-icon-loading" style="font-size: 16px"/>
{{ $t('commons.testing') }}
</el-tag>
<el-tag v-if="errorCode" class="ms-test-running" size="mini">
<el-tag v-else-if="errorCode" class="ms-test-running" size="mini">
{{ $t('error_report_library.option.name') }}
</el-tag>
<el-tag size="mini" v-else-if="request.unexecute">{{
@ -66,11 +66,11 @@
<el-collapse-transition>
<div v-show="isActive && !request.unexecute" style="width: 99%">
<ms-request-result-tail
:scenario-name="scenarioName"
:request-type="requestType"
:request="request"
:console="console"
v-if="isActive"/>
:scenario-name="scenarioName"
:request-type="requestType"
:request="request"
:console="console"
v-if="isActive"/>
</div>
</el-collapse-transition>
</div>
@ -118,7 +118,15 @@ export default {
},
}
},
created() {
watch:{
request:{
deep: true,
handler(n) {
if(this.request.errorCode){
this.errorCode = this.request.errorCode;
}
},
}
},
methods: {
active() {

View File

@ -132,7 +132,8 @@
<ms-table-column v-if="item.id=='tags'" prop="tags" width="120px" :label="$t('commons.tag')">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :show-tooltip="scope.row.tags.length===1&&itemName.length*12<=120"
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:show-tooltip="scope.row.tags.length===1&&itemName.length*12<=120"
:content="itemName" style="margin-left: 0px; margin-right: 2px"/>
<span/>
</template>
@ -320,13 +321,33 @@ export default {
buttons: [],
enableOrderDrag: true,
simpleButtons: [
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteToGcBatch, permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE']},
{name: this.$t('api_test.definition.request.batch_edit'), handleClick: this.handleEditBatch, permissions: ['PROJECT_API_DEFINITION:READ+EDIT_CASE']},
{name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleRunBatch, permissions: ['PROJECT_API_DEFINITION:READ+RUN']},
{
name: this.$t('api_test.definition.request.batch_delete'),
handleClick: this.handleDeleteToGcBatch,
permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE']
},
{
name: this.$t('api_test.definition.request.batch_edit'),
handleClick: this.handleEditBatch,
permissions: ['PROJECT_API_DEFINITION:READ+EDIT_CASE']
},
{
name: this.$t('api_test.automation.batch_execute'),
handleClick: this.handleRunBatch,
permissions: ['PROJECT_API_DEFINITION:READ+RUN']
},
],
trashButtons: [
{name: this.$t('commons.reduction'), handleClick: this.handleBatchRestore, permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE']},
{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch, permissions: ['PROJECT_API_DEFINITION:READ+EDIT_CASE']},
{
name: this.$t('commons.reduction'),
handleClick: this.handleBatchRestore,
permissions: ['PROJECT_API_DEFINITION:READ+DELETE_CASE']
},
{
name: this.$t('api_test.definition.request.batch_delete'),
handleClick: this.handleDeleteBatch,
permissions: ['PROJECT_API_DEFINITION:READ+EDIT_CASE']
},
],
operators: [],
simpleOperators: [
@ -548,6 +569,8 @@ export default {
return "ms-error";
case "Running":
return "ms-running";
case "errorReportResult":
return "ms-error-report-result";
default:
return "ms-unexecute";
}
@ -560,6 +583,8 @@ export default {
return this.$t('api_test.automation.fail');
case "Running":
return this.$t('commons.testing');
case "errorReportResult":
return this.$t('error_report_library.option.name');
default:
return this.$t('api_test.home_page.detail_card.unexecute');
}
@ -1081,7 +1106,10 @@ export default {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
stepArray[i].document = {type: "JSON", data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}};
stepArray[i].document = {
type: "JSON",
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
if (stepArray[i] && stepArray[i].authManager && !stepArray[i].authManager.clazzName) {
stepArray[i].authManager.clazzName = TYPE_TO_C.get(stepArray[i].authManager.type);
@ -1226,6 +1254,10 @@ export default {
color: #F56C6C;
}
.ms-error-report-result {
color: #F6972A;
}
.ms-running {
color: #6D317C;
}

View File

@ -14,6 +14,11 @@
<div v-else class="node-title" :class="response && response.success ?'ms-req-success':'ms-req-error'">
{{ responseResult && responseResult.responseCode ? responseResult.responseCode : '0' }}
</div>
<div v-if="response.attachInfoMap && response.attachInfoMap.errorReportResult">
<div class="ms-req-error-report-result">
{{ response.attachInfoMap.errorReportResult }}
</div>
</div>
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{ $t('api_report.response_time') }} :</div>
@ -39,8 +44,6 @@ export default {
}
}
},
computed: {
responseResult() {
return this.response && this.response.responseResult ? this.response.responseResult : {};
@ -58,7 +61,7 @@ export default {
}
.node-title {
width: 150px;
/*width: 150px;*/
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
@ -68,6 +71,7 @@ export default {
color: #61C550;
margin-top: 2px;
margin-left: 10px;
margin-right: 10px;
float: left
}
@ -75,6 +79,10 @@ export default {
color: #F56C6C;
}
.ms-req-error-report-result {
color: #F6972A;
}
.ms-req-success {
color: #67C23A;
}

View File

@ -109,15 +109,20 @@
<el-progress :percentage="getPercentage(item.executionStatus)" :format="format"/>
</el-col>
<el-col :span="4">
<span v-if="item.executionStatus && item.executionStatus.toLowerCase() === 'error'" class="ms-task-error">
<span v-if="item.executionStatus && item.executionStatus.toLowerCase() === 'error'"
class="ms-task-error">
error
</span>
<span v-else-if="item.executionStatus && item.executionStatus.toLowerCase() === 'success'" class="ms-task-success">
<span v-else-if="item.executionStatus && item.executionStatus.toLowerCase() === 'success'"
class="ms-task-success">
success
</span>
<span v-else-if="item.executionStatus && item.executionStatus.toLowerCase() === 'stop'">
stopped
</span>
<span v-else-if="item.executionStatus && item.executionStatus.toLowerCase() === 'errorreportresult'" class="ms-task-error-report-status">
{{ $t('error_report_library.option.name') }}
</span>
<span v-else>
{{ item.executionStatus ? item.executionStatus.toLowerCase() : item.executionStatus }}
</span>
@ -127,7 +132,8 @@
</div>
</div>
<div class="report-bottom">
<ms-table-pagination :change="init" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total" small/>
<ms-table-pagination :change="init" :current-page.sync="currentPage" :page-size.sync="pageSize" :total="total"
small/>
</div>
</el-card>
@ -308,7 +314,7 @@ export default {
if (status === "waiting" || status === 'stop') {
return 0;
}
if (status === 'saved' || status === 'completed' || status === 'success' || status === 'error') {
if (status === 'saved' || status === 'completed' || status === 'success' || status === 'error'|| status === 'errorreportresult') {
return 100;
}
}
@ -317,7 +323,7 @@ export default {
showStop(status) {
if (status) {
status = status.toLowerCase();
if (status === "stop" || status === 'saved' || status === 'completed' || status === 'success' || status === 'error') {
if (status === "stop" || status === 'saved' || status === 'completed' || status === 'success' || status === 'error' || status === 'errorreportresult') {
return false;
}
}
@ -341,7 +347,7 @@ export default {
let status = row.executionStatus;
if (status) {
status = row.executionStatus.toLowerCase();
if (status === 'saved' || status === 'completed' || status === 'success' || status === 'error') {
if (status === 'saved' || status === 'completed' || status === 'success' || status === 'error' || status === 'errorreportresult') {
this.size = 1400;
this.reportId = row.id;
this.reportType = row.executionModule;
@ -527,8 +533,6 @@ export default {
}
.item {
margin-right: 10px;
}
@ -537,6 +541,10 @@ export default {
color: #F56C6C;
}
.ms-task-error-report-status {
color: #F6972A;
}
.ms-task-stop {
color: #F56C6C;
float: right;