Merge remote-tracking branch 'origin/master'

This commit is contained in:
song.tianyang 2021-01-25 13:58:39 +08:00
commit a71f75967d
16 changed files with 217 additions and 27 deletions

View File

@ -7,4 +7,6 @@ public class CountController {
private int loops;
private int interval;
private boolean proceed;
private Object requestResult;
}

View File

@ -7,4 +7,6 @@ public class MsForEachController {
private String inputVal;
private String returnVal;
private String interval;
private Object requestResult;
}

View File

@ -8,4 +8,5 @@ public class MsWhileController {
private String operator;
private String value;
private int timeout;
private Object requestResult;
}

View File

@ -275,7 +275,6 @@ public class Swagger2Parser extends SwaggerAbstractParser {
} else {
propertyList.add(new JSONObject());
}
jsonObject.put(key, propertyList);
} else {
jsonObject.put(key, new ArrayList<>());

View File

@ -40,6 +40,26 @@
<if test="request.name != null">
and (lt.name like CONCAT('%', #{request.name},'%') or lt.num like CONCAT('%', #{request.name},'%'))
</if>
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key=='status'">
and lt.status in
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
</choose>
</if>
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
tplc.${order.name} ${order.type}
</foreach>
</if>
</select>
</mapper>

View File

@ -1,10 +1,12 @@
package io.metersphere.track.request.testplan;
import io.metersphere.base.domain.TestPlanLoadCase;
import io.metersphere.controller.request.OrderRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@ -12,4 +14,6 @@ public class LoadCaseRequest extends TestPlanLoadCase {
private String projectId;
private List<String> caseIds;
private String name;
private Map<String, List<String>> filters;
private List<OrderRequest> orders;
}

View File

@ -5,6 +5,7 @@ import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanLoadCaseMapper;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.track.dto.TestPlanLoadCaseDTO;
import io.metersphere.track.request.testplan.LoadCaseReportRequest;
@ -50,6 +51,15 @@ public class TestPlanLoadCaseService {
}
public List<TestPlanLoadCaseDTO> list(LoadCaseRequest request) {
List<OrderRequest> orders = request.getOrders();
if (orders == null || orders.size() < 1) {
OrderRequest orderRequest = new OrderRequest();
orderRequest.setName("create_time");
orderRequest.setType("desc");
orders = new ArrayList<>();
orders.add(orderRequest);
}
request.setOrders(orders);
return extTestPlanLoadCaseMapper.selectTestPlanLoadCaseList(request);
}

@ -1 +1 @@
Subproject commit 77a4db3ee59003d88aed53601d0d2bfa09ec272f
Subproject commit e4521190f0f1be113c8b84fbdcdf8ff273bf274e

View File

@ -110,7 +110,6 @@
if (this.isNotRunning) {
try {
this.content = JSON.parse(this.report.content);
console.log(this.content)
if (!this.content) {
this.content = {scenarios: []};
}

View File

@ -24,6 +24,7 @@
</span>
<div class="header-right" @click.stop>
<slot name="message"></slot>
<el-switch v-model="data.enable" class="enable-switch"/>
<slot name="button"></slot>
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow"/>

View File

@ -7,7 +7,7 @@
:draggable="true"
color="#02A7F0"
background-color="#F4F4F5"
:title="$t('api_test.automation.loop_controller')">
:title="$t('api_test.automation.loop_controller')" v-loading="loading">
<template v-slot:headerLeft>
<i class="icon el-icon-arrow-right" :class="{'is-active': controller.active}" @click="active(controller)" style="margin-right: 10px"/>
@ -16,6 +16,15 @@
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="WHILE">{{$t('loop.while')}}</el-radio>
</template>
<template v-slot:message>
<span v-if="requestResult && requestResult.scenarios && requestResult.scenarios.length > 0 " style="color: #8c939d;margin-right: 10px">
循环{{requestResult.scenarios.length}} 成功{{success}} 失败{{error}}
</span>
</template>
<template v-slot:button>
<el-button @click="runDebug" :tip="$t('api_test.run')" icon="el-icon-video-play" style="background-color: #409EFF;color: white;" size="mini" circle/>
</template>
<div v-if="controller.loopType==='LOOP_COUNT'" draggable>
<el-row>
<el-col :span="8">
@ -69,17 +78,34 @@
<span class="ms-span ms-radio">ms</span>
</div>
<p class="tip">{{$t('api_test.definition.request.res_param')}} </p>
<el-tabs v-model="activeName">
<el-tab-pane :label="item.name" :name="item.name" v-for="(item,index) in requestResult.scenarios" :key="index">
<div v-for="(result,i) in item.requestResults" :key="i" style="margin-bottom: 5px">
<api-response-component :result="result"/>
</div>
</el-tab-pane>
</el-tabs>
<ms-run :debug="true" :environment="currentEnvironmentId" :reportId="reportId" :run-data="debugData"
@runRefresh="runRefresh" ref="runTest"/>
</api-base-component>
</template>
<script>
import ApiBaseComponent from "../common/ApiBaseComponent";
import ApiResponseComponent from "./ApiResponseComponent";
import MsRun from "../DebugRun";
import {getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "MsLoopController",
components: {ApiBaseComponent},
components: {ApiBaseComponent, ApiResponseComponent, MsRun},
props: {
controller: {},
currentEnvironmentId: String,
currentScenario: {},
node: {},
index: Object,
draggable: {
@ -87,9 +113,19 @@
default: false,
},
},
created() {
this.initResult();
},
data() {
return {
loading: false,
activeName: "first",
requestResult: {responseResult: {}},
success: 0,
error: 0,
debugData: {},
report: [],
reportId: "",
operators: {
EQ: {
label: "commons.adv_search.operators.equals",
@ -127,6 +163,25 @@
}
},
methods: {
initResult() {
if (this.controller) {
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.requestResult = this.controller.countController && this.controller.countController.requestResult ? this.controller.countController.requestResult : {};
break;
case "FOREACH":
this.requestResult = this.controller.forEachController && this.controller.forEachController.requestResult ? this.controller.forEachController.requestResult : {};
break;
case "WHILE":
this.requestResult = this.controller.whileController && this.controller.whileController.requestResult ? this.controller.whileController.requestResult : {};
break;
default:
break;
}
}
this.getFails();
this.activeName = this.requestResult && this.requestResult.scenarios && this.requestResult.scenarios.length > 0 ? this.requestResult.scenarios[0].name : "";
},
switchChange() {
if (this.controller.hashTree && this.controller.hashTree.length > 1) {
this.$warning("当前循环下超过一个请求,不能关闭状态")
@ -134,6 +189,26 @@
return;
}
},
runDebug() {
/*触发执行操作*/
if (!this.currentEnvironmentId) {
this.$error(this.$t('api_test.environment.select_environment'));
return;
}
if (!this.controller.hashTree || this.controller.hashTree.length < 1) {
this.$warning("当前循环下没有请求,不能执行")
return;
}
this.loading = true;
this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,
environmentId: this.currentEnvironmentId, hashTree: [this.controller]
};
this.reportId = getUUID().substring(0, 8);
},
remove() {
this.$emit('remove', this.controller, this.node);
},
@ -146,6 +221,7 @@
},
changeRadio() {
this.controller.active = true;
this.initResult();
this.reload();
},
change(value) {
@ -159,11 +235,77 @@
this.loading = false
})
},
runRefresh() {
this.getReport();
},
getFails() {
this.error = 0;
this.success = 0;
if (this.requestResult.scenarios) {
this.requestResult.scenarios.forEach((scenario) => {
if (scenario.requestResults) {
scenario.requestResults.forEach(item => {
if (item.error > 0) {
this.error++;
return;
}
})
}
})
this.success = this.requestResult.scenarios.length - this.error;
}
},
getReport() {
if (this.reportId) {
let url = "/api/scenario/report/get/" + this.reportId;
this.$get(url, response => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.requestResult = JSON.parse(this.report.content);
this.controller.requestResult = this.requestResult;
switch (this.controller.loopType) {
case "LOOP_COUNT":
this.controller.countController.requestResult = this.requestResult;
break;
case "FOREACH":
this.controller.forEachController.requestResult = this.requestResult;
break;
case "WHILE":
this.controller.whileController.requestResult = this.requestResult;
break;
default:
break;
}
this.getFails();
if (!this.requestResult) {
this.requestResult = {scenarios: []};
}
} catch (e) {
throw e;
}
this.loading = false;
this.activeName = this.requestResult && this.requestResult.scenarios ? this.requestResult.scenarios[0].name : "";
} else {
setTimeout(this.getReport, 2000)
}
} else {
this.loading = false;
this.$error(this.$t('api_report.not_exist'));
}
});
}
},
},
computed: {
hasEmptyOperator() {
return !!this.controller.operator && this.controller.operator.indexOf("empty") > 0;
},
isNotRunning() {
return "Running" !== this.report.status;
}
}
}
</script>
@ -180,6 +322,14 @@
font-weight: normal;
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
.icon.is-active {
transform: rotate(90deg);
}

View File

@ -49,8 +49,13 @@
},
methods: {
validateSocket(socket) {
// if (!socket) return true;
if (socket !== ''){
if (!socket) {
this.httpConfig.domain = socket;
this.httpConfig.port = '';
this.httpConfig.socket = socket;
return true;
}
let urlStr = this.httpConfig.protocol + '://' + socket;
let url = {};
try {
@ -67,13 +72,6 @@
this.httpConfig.socket = this.httpConfig.domain + path;
}
return true;
}else {
this.httpConfig.domain = socket;
this.httpConfig.port = '';
this.httpConfig.socket = socket;
return true;
}
},
validate() {
let isValidate = false;

View File

@ -1,6 +1,10 @@
<template>
<div class="metric-container">
<el-row type="flex">
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">请求名称 :</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">{{response.name}}</div>
</el-col>
<el-col>
<div style="font-size: 14px;color: #AAAAAA;float: left">{{$t('api_report.response_code')}} :</div>
<div style="font-size: 14px;color:#61C550;margin-top:2px;margin-left:10px;float: left">{{response.responseResult.responseCode ? response.responseResult.responseCode :'0'}}</div>

View File

@ -1024,9 +1024,9 @@ export class LoopController extends Controller {
this.type = "LoopController";
this.active = false;
this.loopType = "LOOP_COUNT";
this.countController = {loops: 0, interval: 0, proceed: true};
this.forEachController = {inputVal: "", returnVal: "", interval: 0};
this.whileController = {variable: "", operator: "", value: "", timeout: 0};
this.countController = {loops: 0, interval: 0, proceed: true, requestResult: {}};
this.forEachController = {inputVal: "", returnVal: "", interval: 0, requestResult: {}};
this.whileController = {variable: "", operator: "", value: "", timeout: 0, requestResult: {}};
this.hashTree = [];
this.set(options);
}

View File

@ -64,11 +64,11 @@ export class HttpConfig extends BaseConfig {
constructor(options = {}) {
super();
this.socket = undefined;
this.domain = undefined;
this.socket = '';
this.domain = '';
this.headers = [];
this.protocol = 'https';
this.port = undefined;
this.port = '';
this.set(options);
this.sets({headers: KeyValue}, options);

View File

@ -284,15 +284,15 @@ export default {
},
sort(column) {
//
// if (this.condition.orders) {
// this.condition.orders = [];
// }
// _sort(column, this.condition);
// this.initTable();
if (this.condition.orders) {
this.condition.orders = [];
}
_sort(column, this.condition);
this.initTable();
},
filter(filters) {
// _filter(filters, this.condition);
// this.initTable();
_filter(filters, this.condition);
this.initTable();
},
getReport(data) {
const {loadReportId} = data;