This commit is contained in:
chenjianxing 2021-01-25 16:39:56 +08:00
commit 28fa069390
11 changed files with 161 additions and 110 deletions

View File

@ -121,6 +121,14 @@ public class MsScenario extends MsTestElement {
variables.stream().filter(ScenarioVariable::isConstantValid).forEach(keyValue ->
arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=")
);
List<ScenarioVariable> variableList = variables.stream().filter(ScenarioVariable::isListValid).collect(Collectors.toList());
variableList.forEach(item -> {
String[] arrays = item.getValue().split(",");
for (int i = 0; i < arrays.length; i++) {
arguments.addArgument(item.getName() + "_" + (i + 1), arrays[i], "=");
}
});
}
if (config != null && config.getConfig() != null && config.getConfig().getCommonConfig() != null
&& CollectionUtils.isNotEmpty(config.getConfig().getCommonConfig().getVariables())) {

View File

@ -41,8 +41,7 @@ public class ScenarioVariable {
private String maxNumber;
public boolean isConstantValid() {
if ((StringUtils.equals(this.type, VariableTypeConstants.CONSTANT.name())
|| StringUtils.equals(this.type, VariableTypeConstants.LIST.name())) && StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
if (StringUtils.equals(this.type, VariableTypeConstants.CONSTANT.name()) && StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
return true;
}
return false;
@ -55,6 +54,13 @@ public class ScenarioVariable {
return false;
}
public boolean isListValid() {
if (StringUtils.equals(this.type, VariableTypeConstants.LIST.name()) && StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value) && value.indexOf(",") != -1) {
return true;
}
return false;
}
public boolean isCounterValid() {
if (StringUtils.equals(this.type, VariableTypeConstants.COUNTER.name()) && StringUtils.isNotEmpty(name)) {
return true;

View File

@ -11,4 +11,5 @@ public interface ExtTestPlanLoadCaseMapper {
List<String> selectIdsNotInPlan(@Param("projectId") String projectId, @Param("planId") String planId);
List<TestPlanLoadCaseDTO> selectTestPlanLoadCaseList(@Param("request") LoadCaseRequest request);
void updateCaseStatus(@Param("reportId") String reportId, @Param("status") String status);
List<String> getStatusByTestPlanId(@Param("planId") String planId);
}

View File

@ -62,4 +62,7 @@
</foreach>
</if>
</select>
<select id="getStatusByTestPlanId" resultType="java.lang.String">
select status from test_plan_load_case tplc where tplc.test_plan_id = #{planId}
</select>
</mapper>

View File

@ -19,10 +19,7 @@ import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
@ -103,6 +100,10 @@ public class TestPlanService {
private JMeterService jMeterService;
@Resource
private ApiAutomationService apiAutomationService;
@Resource
private ExtTestPlanApiCaseMapper extTestPlanApiCaseMapper;
@Resource
private ExtTestPlanLoadCaseMapper extTestPlanLoadCaseMapper;
public synchronized void addTestPlan(AddTestPlanRequest testPlan) {
if (getTestPlanByName(testPlan.getName()).size() > 0) {
@ -550,18 +551,10 @@ public class TestPlanService {
}
public void editTestPlanStatus(String planId) {
List<String> statusList = extTestPlanTestCaseMapper.getStatusByPlanId(planId);
TestPlan testPlan = new TestPlan();
testPlan.setId(planId);
for (String status : statusList) {
if (StringUtils.equals(status, TestPlanTestCaseStatus.Prepare.name())
|| StringUtils.equals(status, TestPlanTestCaseStatus.Underway.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlanMapper.updateByPrimaryKeySelective(testPlan);
return;
}
}
testPlan.setStatus(TestPlanStatus.Completed.name());
String status = calcTestPlanStatus(planId);
testPlan.setStatus(status);
testPlanMapper.updateByPrimaryKeySelective(testPlan);
TestPlan testPlans = getTestPlan(planId);
List<String> userIds = new ArrayList<>();
@ -590,6 +583,36 @@ public class TestPlanService {
}
private String calcTestPlanStatus(String planId) {
// test-plan-functional-case status
List<String> funcStatusList = extTestPlanTestCaseMapper.getStatusByPlanId(planId);
for (String funcStatus : funcStatusList) {
if (StringUtils.equals(funcStatus, TestPlanTestCaseStatus.Prepare.name())
|| StringUtils.equals(funcStatus, TestPlanTestCaseStatus.Underway.name())) {
return TestPlanStatus.Underway.name();
}
}
// test-plan-api-case status
List<String> apiStatusList = extTestPlanApiCaseMapper.getStatusByTestPlanId(planId);
for (String apiStatus : apiStatusList) {
if (apiStatus == null) {
return TestPlanStatus.Underway.name();
}
}
// test-plan-load-case status
List<String> loadStatusList = extTestPlanLoadCaseMapper.getStatusByTestPlanId(planId);
for (String loadStatus : loadStatusList) {
if (loadStatus == null) {
return TestPlanStatus.Underway.name();
}
}
return TestPlanStatus.Completed.name();
}
public String getProjectNameByPlanId(String testPlanId) {
List<String> projectIds = testPlanProjectService.getProjectIdsByPlanId(testPlanId);
ProjectExample projectExample = new ProjectExample();

View File

@ -143,7 +143,7 @@
highlight-current
@node-expand="nodeExpand"
@node-collapse="nodeCollapse"
:allow-drop="allowDrop" @node-drag-end="allowDrag" @node-click="nodeClick" v-if="!loading" draggable>
:allow-drop="allowDrop" @node-drag-end="allowDrag" @node-click="nodeClick" v-if="!loading" draggable class="ms-is-leaf">
<span class="custom-tree-node father" slot-scope="{ node, data}" style="width: 96%">
<!-- 步骤组件-->
<ms-component-config :type="data.type" :scenario="data" :response="response" :currentScenario="currentScenario"
@ -1035,7 +1035,7 @@
color: #7C3985;
}
/deep/ .is-leaf {
.ms-is-leaf >>> .is-leaf {
color: transparent;
}
</style>

View File

@ -1,96 +1,97 @@
<template>
<div>
<ms-run :debug="true" :environment="currentEnvironmentId" :reportId="reportId" :run-data="debugData"
@runRefresh="runRefresh" ref="runTest"/>
<api-base-component
@copy="copyRow"
@remove="remove"
:data="controller"
:draggable="true"
color="#02A7F0"
background-color="#F4F4F5"
:title="$t('api_test.automation.loop_controller')" v-loading="loading">
<api-base-component
@copy="copyRow"
@remove="remove"
:data="controller"
:draggable="true"
color="#02A7F0"
background-color="#F4F4F5"
: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"/>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="LOOP_COUNT">{{$t('loop.loops_title')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="FOREACH">{{$t('loop.foreach')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="WHILE">{{$t('loop.while')}}</el-radio>
</template>
<template v-slot:headerLeft>
<i class="icon el-icon-arrow-right" :class="{'is-active': controller.active}" @click="active(controller)" style="margin-right: 10px"/>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="LOOP_COUNT">{{$t('loop.loops_title')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="FOREACH">{{$t('loop.foreach')}}</el-radio>
<el-radio @change="changeRadio" class="ms-radio" v-model="controller.loopType" label="WHILE">{{$t('loop.while')}}</el-radio>
</template>
<template v-slot:message>
<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>
<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">
<span class="ms-span ms-radio">{{$t('loop.loops')}}</span>
<el-input-number size="small" v-model="controller.countController.loops" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
<span class="ms-span ms-radio"></span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<el-input-number size="small" v-model="controller.countController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.proceed')}}</span>
<el-tooltip class="item" effect="dark" content="默认为开启,当循环下只有一个请求时,可以开启/关闭;当循环下超过一个请求时,则只能开启。" placement="top">>
<el-switch v-model="controller.countController.proceed" @change="switchChange"/>
<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">
<span class="ms-span ms-radio">{{$t('loop.loops')}}</span>
<el-input-number size="small" v-model="controller.countController.loops" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0"/>
<span class="ms-span ms-radio"></span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<el-input-number size="small" v-model="controller.countController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
<el-col :span="8">
<span class="ms-span ms-radio">{{$t('loop.proceed')}}</span>
<el-tooltip class="item" effect="dark" content="默认为开启,当循环下只有一个请求时,可以开启/关闭;当循环下超过一个请求时,则只能开启。" placement="top">>
<el-switch v-model="controller.countController.proceed" @change="switchChange"/>
</el-tooltip>
</el-col>
</el-row>
</div>
</el-tooltip>
</el-col>
</el-row>
</div>
<div v-else-if="controller.loopType==='FOREACH'" draggable>
<el-row>
<el-col :span="8">
<el-input :placeholder="$t('api_test.request.condition_variable')" v-model="controller.forEachController.inputVal" size="small"/>
</el-col>
<el-col :span="1" style="margin-top: 6px">
<span style="margin:10px 10px 10px">in</span>
</el-col>
<el-col :span="8">
<el-input :placeholder="$t('api_test.request.condition_variable')" v-model="controller.forEachController.returnVal" size="small"/>
</el-col>
<el-col :span="7">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<el-input-number size="small" v-model="controller.forEachController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
</el-row>
</div>
<div v-else draggable>
<el-input size="small" v-model="controller.whileController.variable" style="width: 20%" :placeholder="$t('api_test.request.condition_variable')"/>
<div v-else-if="controller.loopType==='FOREACH'" draggable>
<el-row>
<el-col :span="8">
<el-input placeholder="输出变量名称" v-model="controller.forEachController.returnVal" size="small"/>
</el-col>
<el-col :span="1" style="margin-top: 6px">
<span style="margin:10px 10px 10px">in</span>
</el-col>
<el-col :span="8">
<el-input placeholder="输入变量前缀" v-model="controller.forEachController.inputVal" size="small"/>
</el-col>
<el-col :span="7">
<span class="ms-span ms-radio">{{$t('loop.interval')}}</span>
<el-input-number size="small" v-model="controller.forEachController.interval" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="0" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</el-col>
</el-row>
</div>
<div v-else draggable>
<el-input size="small" v-model="controller.whileController.variable" style="width: 20%" :placeholder="$t('api_test.request.condition_variable')"/>
<el-select v-model="controller.whileController.operator" :placeholder="$t('commons.please_select')" size="small"
@change="change" style="width: 10%;margin-left: 10px">
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
<el-input size="small" v-model="controller.whileController.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" style="width: 20%;margin-left: 20px"/>
<span class="ms-span ms-radio">{{$t('loop.timeout')}}</span>
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="1" :step="1000"/>
<span class="ms-span ms-radio">ms</span>
</div>
<el-select v-model="controller.whileController.operator" :placeholder="$t('commons.please_select')" size="small"
@change="change" style="width: 10%;margin-left: 10px">
<el-option v-for="o in operators" :key="o.value" :label="$t(o.label)" :value="o.value"/>
</el-select>
<el-input size="small" v-model="controller.whileController.value" :placeholder="$t('api_test.value')" v-if="!hasEmptyOperator" style="width: 20%;margin-left: 20px"/>
<span class="ms-span ms-radio">{{$t('loop.timeout')}}</span>
<el-input-number size="small" v-model="controller.whileController.timeout" :placeholder="$t('commons.millisecond')" :max="1000*10000000" :min="1" :step="1000"/>
<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>
<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>
</api-base-component>
</div>
</template>
<script>
@ -199,8 +200,8 @@
this.$warning("当前循环下没有请求,不能执行")
return;
}
this.controller.active = true;
this.loading = true;
this.debugData = {
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,

View File

@ -29,7 +29,7 @@
<el-col :span="20">
<el-autocomplete
size="small"
class="inline-input"
style="width: 100%"
v-model="editData.encoding"
:fetch-suggestions="querySearch"
:placeholder="$t('commons.input_content')"
@ -110,7 +110,7 @@
},
handleClick() {
let config = {complete: this.complete, step: this.step};
let config = {complete: this.complete, step: this.step, delimiter: this.editData.delimiter ? this.editData.delimiter : ","};
this.allDatas = [];
//
if (this.editData.files && this.editData.files.length > 0 && this.editData.files[0].file) {
@ -152,5 +152,7 @@
</script>
<style scoped>
ms-is-leaf >>> .is-leaf {
color: red;
}
</style>

View File

@ -107,6 +107,9 @@
},
addParameters(v) {
v.id = getUUID();
if (v.type === 'CSV') {
v.delimiter = ",";
}
this.variables.push(v);
let index = 1;
this.variables.forEach(item => {

View File

@ -1,10 +1,6 @@
<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

@ -75,6 +75,9 @@
<el-tag size="mini" type="success" v-else-if="row.caseStatus === 'success'">
{{ row.caseStatus }}
</el-tag>
<el-tag size="mini" v-else-if="row.caseStatus === 'run'">
{{ row.caseStatus }}
</el-tag>
<span v-else>-</span>
</template>
</el-table-column>
@ -264,17 +267,22 @@ export default {
title: loadCase.caseName,
message: this.$t('test_track.plan.load_case.exec').toString()
});
this.initTable();
this.updateStatus(loadCase, 'run');
}).catch(() => {
this.$post('/test/plan/load/case/update', {id: loadCase.id, status: "error"}, () => {
this.initTable();
});
this.updateStatus(loadCase, 'error');
this.$notify.error({
title: loadCase.caseName,
message: this.$t('test_track.plan.load_case.error').toString()
});
})
},
updateStatus(loadCase, status) {
this.$post('/test/plan/load/case/update', {id: loadCase.id, status: status}, () => {
this.$post('/test/plan/edit/status/' + loadCase.testPlanId, {},() => {
this.initTable();
});
});
},
handleDelete(loadCase) {
this.result = this.$get('/test/plan/load/case/delete/' + loadCase.id, () => {
this.$success(this.$t('test_track.cancel_relevance_success'));