parent
dfb9890af4
commit
ad85f0814f
|
@ -131,11 +131,11 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
LogUtil.error("testPlanApiCaseService is required");
|
LogUtil.error("testPlanApiCaseService is required");
|
||||||
}
|
}
|
||||||
apiEnvironmentRunningParamService = CommonBeanFactory.getBean(ApiEnvironmentRunningParamService.class);
|
apiEnvironmentRunningParamService = CommonBeanFactory.getBean(ApiEnvironmentRunningParamService.class);
|
||||||
if (apiEnvironmentRunningParamService == null) {
|
if(apiEnvironmentRunningParamService == null){
|
||||||
LogUtil.error("apiEnvironmentRunningParamService is required");
|
LogUtil.error("apiEnvironmentRunningParamService is required");
|
||||||
}
|
}
|
||||||
testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
testPlanTestCaseService = CommonBeanFactory.getBean(TestPlanTestCaseService.class);
|
||||||
if (testPlanTestCaseService == null) {
|
if(testPlanTestCaseService == null){
|
||||||
LogUtil.error("testPlanTestCaseService is required");
|
LogUtil.error("testPlanTestCaseService is required");
|
||||||
}
|
}
|
||||||
super.setupTest(context);
|
super.setupTest(context);
|
||||||
|
@ -151,17 +151,16 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
public void teardownTest(BackendListenerContext context) throws Exception {
|
public void teardownTest(BackendListenerContext context) throws Exception {
|
||||||
TestResult testResult = new TestResult();
|
TestResult testResult = new TestResult();
|
||||||
testResult.setTestId(testId);
|
testResult.setTestId(testId);
|
||||||
testResult.setTotal(queue.size());
|
|
||||||
testResult.setConsole(getConsole());
|
testResult.setConsole(getConsole());
|
||||||
|
testResult.setTotal(0);
|
||||||
// 一个脚本里可能包含多个场景(ThreadGroup),所以要区分开,key: 场景Id
|
// 一个脚本里可能包含多个场景(ThreadGroup),所以要区分开,key: 场景Id
|
||||||
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
final Map<String, ScenarioResult> scenarios = new LinkedHashMap<>();
|
||||||
queue.forEach(result -> {
|
queue.forEach(result -> {
|
||||||
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
// 线程名称: <场景名> <场景Index>-<请求Index>, 例如:Scenario 2-1
|
||||||
if (StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)) {
|
if(StringUtils.equals(result.getSampleLabel(), RunningParamKeys.RUNNING_DEBUG_SAMPLER_NAME)){
|
||||||
String evnStr = result.getResponseDataAsString();
|
String evnStr = result.getResponseDataAsString();
|
||||||
apiEnvironmentRunningParamService.parseEvn(evnStr);
|
apiEnvironmentRunningParamService.parseEvn(evnStr);
|
||||||
} else {
|
}else {
|
||||||
String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT);
|
String scenarioName = StringUtils.substringBeforeLast(result.getThreadName(), THREAD_SPLIT);
|
||||||
String index = StringUtils.substringAfterLast(result.getThreadName(), THREAD_SPLIT);
|
String index = StringUtils.substringAfterLast(result.getThreadName(), THREAD_SPLIT);
|
||||||
String scenarioId = StringUtils.substringBefore(index, ID_SPLIT);
|
String scenarioId = StringUtils.substringBefore(index, ID_SPLIT);
|
||||||
|
@ -193,11 +192,12 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
testResult.addPassAssertions(requestResult.getPassAssertions());
|
testResult.addPassAssertions(requestResult.getPassAssertions());
|
||||||
testResult.addTotalAssertions(requestResult.getTotalAssertions());
|
testResult.addTotalAssertions(requestResult.getTotalAssertions());
|
||||||
|
testResult.setTotal(testResult.getTotal()+1);
|
||||||
scenarioResult.addPassAssertions(requestResult.getPassAssertions());
|
scenarioResult.addPassAssertions(requestResult.getPassAssertions());
|
||||||
scenarioResult.addTotalAssertions(requestResult.getTotalAssertions());
|
scenarioResult.addTotalAssertions(requestResult.getTotalAssertions());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
testResult.getScenarios().addAll(scenarios.values());
|
testResult.getScenarios().addAll(scenarios.values());
|
||||||
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
testResult.getScenarios().sort(Comparator.comparing(ScenarioResult::getId));
|
||||||
ApiTestReport report = null;
|
ApiTestReport report = null;
|
||||||
|
@ -297,7 +297,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
//环境
|
//环境
|
||||||
ApiScenarioWithBLOBs apiScenario = apiAutomationService.getDto(scenarioReport.getScenarioId());
|
ApiScenarioWithBLOBs apiScenario = apiAutomationService.getDto(scenarioReport.getScenarioId());
|
||||||
String name = "";
|
String name = "";
|
||||||
if (apiScenario != null) {
|
if(apiScenario!= null ) {
|
||||||
String executionEnvironment = apiScenario.getScenarioDefinition();
|
String executionEnvironment = apiScenario.getScenarioDefinition();
|
||||||
JSONObject json = JSONObject.parseObject(executionEnvironment);
|
JSONObject json = JSONObject.parseObject(executionEnvironment);
|
||||||
if (json != null && json.getString("environmentMap") != null && json.getString("environmentMap").length() > 2) {
|
if (json != null && json.getString("environmentMap") != null && json.getString("environmentMap").length() > 2) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.metersphere.api.jmeter;
|
package io.metersphere.api.jmeter;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import io.metersphere.commons.constants.DelimiterConstants;
|
import io.metersphere.commons.constants.DelimiterConstants;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
@ -40,12 +41,15 @@ public class TestResult {
|
||||||
|
|
||||||
private String console;
|
private String console;
|
||||||
|
|
||||||
private String runningDebugSampler;
|
|
||||||
|
|
||||||
private List<ScenarioResult> scenarios = new ArrayList<>();
|
private List<ScenarioResult> scenarios = new ArrayList<>();
|
||||||
|
|
||||||
private Map<String, Boolean> margeScenariMap = new HashMap<>();
|
private Map<String, Boolean> margeScenariMap = new HashMap<>();
|
||||||
|
|
||||||
|
private Map<String, Boolean> scenarioStepMap = new HashMap<>();
|
||||||
|
|
||||||
|
private int scenarioStepSuccess = 0;
|
||||||
|
private int scenarioStepError = 0;
|
||||||
|
private int scenarioStepTotal = 0;
|
||||||
public void addError(int count) {
|
public void addError(int count) {
|
||||||
this.error += count;
|
this.error += count;
|
||||||
}
|
}
|
||||||
|
@ -74,12 +78,33 @@ public class TestResult {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setStepStatus(String step_names, boolean status) {
|
||||||
|
if (!scenarioStepMap.containsKey(step_names) || status) {
|
||||||
|
scenarioStepMap.put(step_names, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addScenario(ScenarioResult result) {
|
public void addScenario(ScenarioResult result) {
|
||||||
if (result != null && CollectionUtils.isNotEmpty(result.getRequestResults())) {
|
if (result != null && CollectionUtils.isNotEmpty(result.getRequestResults())) {
|
||||||
result.getRequestResults().forEach(item -> {
|
result.getRequestResults().forEach(item -> {
|
||||||
|
String itemScenarioName = "";
|
||||||
if (StringUtils.isNotEmpty(item.getScenario())) {
|
if (StringUtils.isNotEmpty(item.getScenario())) {
|
||||||
List<String> id_names = JSON.parseObject(item.getScenario(), List.class);
|
List<String> all_id_names = JSON.parseObject(item.getScenario(), List.class);
|
||||||
|
if(all_id_names.size()>1){
|
||||||
|
List<String> id_names = new ArrayList<>();
|
||||||
|
all_id_names.forEach(name -> {
|
||||||
|
if(!name.endsWith(result.getName())){
|
||||||
|
id_names.add(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
this.setStatus(id_names, item.getError() > 0);
|
this.setStatus(id_names, item.getError() > 0);
|
||||||
|
itemScenarioName = JSONArray.toJSONString(id_names);
|
||||||
|
}else{
|
||||||
|
this.setStatus(all_id_names, item.getError() > 0);
|
||||||
|
itemScenarioName = JSONArray.toJSONString(all_id_names);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
|
if (StringUtils.isNotEmpty(item.getName()) && item.getName().indexOf(SEPARATOR) != -1) {
|
||||||
String array[] = item.getName().split(SEPARATOR);
|
String array[] = item.getName().split(SEPARATOR);
|
||||||
|
@ -102,17 +127,38 @@ public class TestResult {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.setStepStatus(item.getName()+itemScenarioName,item.getError()>0);
|
||||||
});
|
});
|
||||||
scenarios.add(result);
|
scenarios.add(result);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 1.10.2 场景成功/失败统计,不再按照请求为纬度,按照场景为纬度,
|
||||||
|
*/
|
||||||
|
for (String key : scenarioStepMap.keySet()) {
|
||||||
|
if (scenarioStepMap .get(key)) {
|
||||||
|
this.scenarioStepError++;
|
||||||
|
} else {
|
||||||
|
this.scenarioStepSuccess++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean hasError = false;
|
||||||
for (String key : margeScenariMap.keySet()) {
|
for (String key : margeScenariMap.keySet()) {
|
||||||
if (margeScenariMap.get(key)) {
|
if (margeScenariMap.get(key)) {
|
||||||
this.scenarioError++;
|
hasError = true;
|
||||||
} else {
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!margeScenariMap.isEmpty()){
|
||||||
|
if(hasError){
|
||||||
|
this.scenarioError ++;
|
||||||
|
}else {
|
||||||
this.scenarioSuccess++;
|
this.scenarioSuccess++;
|
||||||
}
|
}
|
||||||
|
this.scenarioTotal++;
|
||||||
}
|
}
|
||||||
this.setScenarioTotal(this.margeScenariMap.size());
|
|
||||||
|
|
||||||
|
this.setScenarioStepTotal(this.scenarioStepMap.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -384,6 +384,9 @@ public class ApiScenarioReportService {
|
||||||
testResult.setScenarioSuccess(testResult.getScenarioSuccess() + scenarioResult.getScenarioSuccess());
|
testResult.setScenarioSuccess(testResult.getScenarioSuccess() + scenarioResult.getScenarioSuccess());
|
||||||
testResult.setScenarioError(testResult.getScenarioError() + scenarioResult.getScenarioError());
|
testResult.setScenarioError(testResult.getScenarioError() + scenarioResult.getScenarioError());
|
||||||
testResult.setConsole(scenarioResult.getConsole());
|
testResult.setConsole(scenarioResult.getConsole());
|
||||||
|
testResult.setScenarioStepError(scenarioResult.getScenarioStepError()+testResult.getScenarioStepError());
|
||||||
|
testResult.setScenarioStepSuccess(scenarioResult.getScenarioStepSuccess()+testResult.getScenarioStepSuccess());
|
||||||
|
testResult.setScenarioStepTotal(scenarioResult.getScenarioStepTotal()+testResult.getScenarioStepTotal());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LogUtil.error(e.getMessage());
|
LogUtil.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,19 @@
|
||||||
<header class="report-header">
|
<header class="report-header">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col>
|
<el-col>
|
||||||
<span v-if="!debug"><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
|
<!-- <span v-if="!debug"><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>-->
|
||||||
|
<span v-if="!debug">
|
||||||
|
<el-input v-if="nameIsEdit" size="mini" @blur="nameIsEdit = false" style="width: 200px" v-model="report.name"/>
|
||||||
|
<span v-else>
|
||||||
|
<router-link v-if="isSingleScenario" :to="{name: 'ApiAutomation', params: { dataSelectRange: 'edit:' + scenarioId }}">
|
||||||
|
{{ report.name }}
|
||||||
|
</router-link>
|
||||||
|
<span v-else>
|
||||||
|
{{ report.name }}
|
||||||
|
</span>
|
||||||
|
<i class="el-icon-edit" style="cursor:pointer" @click="nameIsEdit = true" @click.stop/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
<span class="time"> {{ report.createTime | timestampFormatDate }}</span>
|
<span class="time"> {{ report.createTime | timestampFormatDate }}</span>
|
||||||
|
|
||||||
<el-button v-if="!debug" 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">
|
<el-button v-if="!debug" 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">
|
||||||
|
@ -30,10 +42,26 @@
|
||||||
path() {
|
path() {
|
||||||
return "/api/test/edit?id=" + this.report.testId;
|
return "/api/test/edit?id=" + this.report.testId;
|
||||||
},
|
},
|
||||||
|
scenarioId(){
|
||||||
|
if(typeof this.report.scenarioId === 'string'){
|
||||||
|
return this.report.scenarioId;
|
||||||
|
}else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isSingleScenario(){
|
||||||
|
try {
|
||||||
|
JSON.parse(this.report.scenarioId);
|
||||||
|
return false;
|
||||||
|
} catch(e){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isReadOnly: false,
|
isReadOnly: false,
|
||||||
|
nameIsEdit:false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|
|
@ -38,22 +38,43 @@
|
||||||
<div style="width: 50%">
|
<div style="width: 50%">
|
||||||
<el-row type="flex" justify="center" align="middle">
|
<el-row type="flex" justify="center" align="middle">
|
||||||
<el-row type="flex" justify="center" align="middle">
|
<el-row type="flex" justify="center" align="middle">
|
||||||
<div class="metric-box" style="margin-right: 50px">
|
<!-- <div class="metric-box" style="margin-right: 50px">-->
|
||||||
|
<div class="metric-box">
|
||||||
<div class="value">{{ content.scenarioTotal ? content.scenarioTotal : 0}}</div>
|
<div class="value">{{ content.scenarioTotal ? content.scenarioTotal : 0}}</div>
|
||||||
<div class="name">{{ $t('api_test.scenario.scenario') }}</div>
|
<div class="name">{{ $t('api_test.scenario.scenario') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<i class="circle success"/>
|
<i class="circle success" style="margin-left: 20px;margin-right: 20px"/>
|
||||||
<div class="metric-box">
|
<div class="metric-box">
|
||||||
<div class="value">{{ content.scenarioSuccess ? content.scenarioSuccess: 0 }}</div>
|
<div class="value">{{ content.scenarioSuccess ? content.scenarioSuccess: 0 }}</div>
|
||||||
<div class="name">{{ $t('api_report.success') }}</div>
|
<div class="name">{{ $t('api_report.success') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 40px"></div>
|
<!-- <div style="width: 40px"></div>-->
|
||||||
<i class="circle fail"/>
|
<i class="circle fail" style="margin-left: 20px;margin-right: 20px"/>
|
||||||
<div class="metric-box">
|
<div class="metric-box">
|
||||||
<div class="value">{{ content.scenarioError ? content.scenarioError : 0 }}</div>
|
<div class="value">{{ content.scenarioError ? content.scenarioError : 0 }}</div>
|
||||||
<div class="name">{{ $t('api_report.fail') }}</div>
|
<div class="name">{{ $t('api_report.fail') }}</div>
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-divider></el-divider>
|
||||||
|
<el-row type="flex" justify="center" align="middle">
|
||||||
|
<el-row type="flex" justify="center" align="middle">
|
||||||
|
<div class="metric-box">
|
||||||
|
<div class="value">{{ content.scenarioStepTotal ? content.scenarioStepTotal : 0}}</div>
|
||||||
|
<div class="name">{{ $t('test_track.plan_view.step') }}</div>
|
||||||
|
</div>
|
||||||
|
<i class="circle success" style="margin-left: 20px;margin-right: 20px"/>
|
||||||
|
<div class="metric-box">
|
||||||
|
<div class="value">{{ content.scenarioStepSuccess ? content.scenarioStepSuccess: 0 }}</div>
|
||||||
|
<div class="name">{{ $t('api_report.success') }}</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div style="width: 40px"></div>-->
|
||||||
|
<i class="circle fail" style="margin-left: 20px;margin-right: 20px"/>
|
||||||
|
<div class="metric-box">
|
||||||
|
<div class="value">{{ content.scenarioStepError ? content.scenarioStepError : 0 }}</div>
|
||||||
|
<div class="name">{{ $t('api_report.fail') }}</div>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
</el-row>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="split"></div>
|
<div class="split"></div>
|
||||||
|
|
|
@ -318,6 +318,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
onSampleError: false,
|
onSampleError: false,
|
||||||
|
showConfigButtonWithOutPermission:false,
|
||||||
props: {
|
props: {
|
||||||
label: "label",
|
label: "label",
|
||||||
children: "hashTree"
|
children: "hashTree"
|
||||||
|
|
Loading…
Reference in New Issue