接口测试 shcedule 业务逻辑
This commit is contained in:
parent
8c09d052f3
commit
f8cb40cb10
|
@ -18,6 +18,7 @@
|
||||||
<shiro.version>1.5.1</shiro.version>
|
<shiro.version>1.5.1</shiro.version>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<jmeter.version>5.2.1</jmeter.version>
|
<jmeter.version>5.2.1</jmeter.version>
|
||||||
|
<quartz-starter.version>0.0.4</quartz-starter.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -60,6 +61,7 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-mail</artifactId>
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
@ -75,6 +77,14 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fit2cloud</groupId>
|
||||||
|
<artifactId>quartz-spring-boot-starter</artifactId>
|
||||||
|
<version>${quartz-starter.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- flyway -->
|
<!-- flyway -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
|
|
|
@ -50,6 +50,11 @@ public class APITestController {
|
||||||
return apiTestService.getApiTestByProjectId(projectId);
|
return apiTestService.getApiTestByProjectId(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/schedule/update")
|
||||||
|
public void updateSchedule(@RequestBody SaveAPITestRequest request) {
|
||||||
|
apiTestService.updateSchedule(request);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
|
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
|
||||||
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> files) {
|
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> files) {
|
||||||
apiTestService.create(request, files);
|
apiTestService.create(request, files);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.metersphere.api.dto;
|
package io.metersphere.api.dto;
|
||||||
|
|
||||||
import io.metersphere.api.dto.scenario.Scenario;
|
import io.metersphere.api.dto.scenario.Scenario;
|
||||||
|
import io.metersphere.dto.ScheduleDTO;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@ -17,4 +18,6 @@ public class SaveAPITestRequest {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private List<Scenario> scenarioDefinition;
|
private List<Scenario> scenarioDefinition;
|
||||||
|
|
||||||
|
private ScheduleDTO schedule;
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,4 +207,14 @@ public class APITestService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updateSchedule(SaveAPITestRequest request) {
|
||||||
|
|
||||||
|
// todo 开启调度线程
|
||||||
|
|
||||||
|
ApiTestWithBLOBs apiTest = new ApiTestWithBLOBs();
|
||||||
|
apiTest.setId(request.getId());
|
||||||
|
apiTest.setSchedule(JSONObject.toJSONString(request.getSchedule()));
|
||||||
|
apiTest.setUpdateTime(System.currentTimeMillis());
|
||||||
|
apiTestMapper.updateByPrimaryKeySelective(apiTest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
package io.metersphere.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ScheduleDTO {
|
||||||
|
private Boolean enable;
|
||||||
|
private String cronExpression;
|
||||||
|
}
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
<ms-api-report-dialog :test-id="id" ref="reportDialog"/>
|
<ms-api-report-dialog :test-id="id" ref="reportDialog"/>
|
||||||
|
|
||||||
<ms-scheduler-config/>
|
<ms-schedule-config :schedule="test.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit"/>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-header>
|
</el-header>
|
||||||
<ms-api-scenario-config :is-read-only="isReadOnly" :scenarios="test.scenarioDefinition" ref="config"/>
|
<ms-api-scenario-config :is-read-only="isReadOnly" :scenarios="test.scenarioDefinition" ref="config"/>
|
||||||
|
@ -63,12 +63,12 @@
|
||||||
import MsApiReportStatus from "../report/ApiReportStatus";
|
import MsApiReportStatus from "../report/ApiReportStatus";
|
||||||
import MsApiReportDialog from "./ApiReportDialog";
|
import MsApiReportDialog from "./ApiReportDialog";
|
||||||
import {checkoutTestManagerOrTestUser, downloadFile} from "../../../../common/js/utils";
|
import {checkoutTestManagerOrTestUser, downloadFile} from "../../../../common/js/utils";
|
||||||
import MsSchedulerConfig from "../../common/components/MsSchedulerConfig";
|
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsApiTestConfig",
|
name: "MsApiTestConfig",
|
||||||
|
|
||||||
components: {MsSchedulerConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig},
|
components: {MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig},
|
||||||
|
|
||||||
props: ["id"],
|
props: ["id"],
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@
|
||||||
name: item.name,
|
name: item.name,
|
||||||
status: item.status,
|
status: item.status,
|
||||||
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
scenarioDefinition: JSON.parse(item.scenarioDefinition),
|
||||||
|
schedule: item.schedule ? JSON.parse(item.schedule) : {},
|
||||||
});
|
});
|
||||||
this.$refs.config.reset();
|
this.$refs.config.reset();
|
||||||
}
|
}
|
||||||
|
@ -211,6 +212,31 @@
|
||||||
downloadFile(this.test.name + ".json", this.test.export());
|
downloadFile(this.test.name + ".json", this.test.export());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
saveCronExpression(cronExpression) {
|
||||||
|
this.test.schedule.enable = true;
|
||||||
|
this.test.schedule.cronExpression = cronExpression;
|
||||||
|
this.saveSchedule();
|
||||||
|
},
|
||||||
|
saveSchedule() {
|
||||||
|
if (this.create) {
|
||||||
|
this.$message('请先保存测试,在设置定时任务');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let param = {};
|
||||||
|
param.id = this.test.id;
|
||||||
|
param.schedule = this.test.schedule;
|
||||||
|
this.$post('/api/schedule/update', param, response => {
|
||||||
|
this.$success('保存成功');
|
||||||
|
this.getTest(this.test.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
checkScheduleEdit() {
|
||||||
|
if (this.create) {
|
||||||
|
this.$message('请先保存测试');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -249,7 +275,7 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scheduler-config {
|
.schedule-config {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -100,6 +100,7 @@ export class Test extends BaseConfig {
|
||||||
this.name = undefined;
|
this.name = undefined;
|
||||||
this.projectId = undefined;
|
this.projectId = undefined;
|
||||||
this.scenarioDefinition = [];
|
this.scenarioDefinition = [];
|
||||||
|
this.schedule = {};
|
||||||
|
|
||||||
this.set(options);
|
this.set(options);
|
||||||
this.sets({scenarioDefinition: Scenario}, options);
|
this.sets({scenarioDefinition: Scenario}, options);
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
<template>
|
||||||
|
<div class="schedule-config">
|
||||||
|
<div>
|
||||||
|
<span class="cron-ico">
|
||||||
|
<i class="el-icon-date" size="small"></i>
|
||||||
|
<span class="character" @click="scheduleEdit">SCHEDULER</span>
|
||||||
|
</span>
|
||||||
|
<el-switch :disabled="!schedule.cronExpression" v-model="schedule.enable" @change="scheduleChange"/>
|
||||||
|
<ms-schedule-edit :schedule="schedule" :save="save" ref="scheduleEdit"/>
|
||||||
|
<crontab-result v-show="false" :ex="schedule.cronExpression" ref="crontabResult" @resultListChange="recentListChange"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span :class="{'disable-character': !schedule.enable}"> 下次执行时间:{{this.recentList.length > 0 ? this.recentList[0] : ''}} </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsScheduleEdit from "./MsScheduleEdit";
|
||||||
|
import CrontabResult from "../cron/CrontabResult";
|
||||||
|
export default {
|
||||||
|
name: "MsScheduleConfig",
|
||||||
|
components: {CrontabResult, MsScheduleEdit},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
recentList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
save: Function,
|
||||||
|
schedule: {},
|
||||||
|
checkOpen: {
|
||||||
|
type: Function,
|
||||||
|
default() {
|
||||||
|
return new Function()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// mounted() {
|
||||||
|
// console.log(this.schedule);
|
||||||
|
// // this.recentList = this.$refs.crontabResult.resultList;
|
||||||
|
// // console.log(this.recentList);
|
||||||
|
// console.log(this.recentList+ "====");
|
||||||
|
// },
|
||||||
|
// watch: {
|
||||||
|
// 'schedule.cronExpression'() {
|
||||||
|
// console.log(this.schedule);
|
||||||
|
// this.$refs.crontabResult.expressionChange();
|
||||||
|
// this.recentList = this.$refs.crontabResult.resultList;
|
||||||
|
// console.log(this.recentList);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
methods: {
|
||||||
|
scheduleEdit() {
|
||||||
|
if (!this.checkOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$refs.scheduleEdit.open();
|
||||||
|
},
|
||||||
|
scheduleChange() {
|
||||||
|
this.$emit('scheduleChange');
|
||||||
|
},
|
||||||
|
recentListChange(resultList) {
|
||||||
|
this.recentList = resultList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.schedule-config {
|
||||||
|
float: right;
|
||||||
|
width: 250px;
|
||||||
|
height: 15px;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon-date {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.character {
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disable-character {
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-switch {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cron-ico {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog width="30%" class="scheduler-edit" :title="'编辑定时任务'" :visible.sync="dialogVisible" @close="close">
|
<el-dialog width="30%" class="schedule-edit" :title="'编辑定时任务'" :visible.sync="dialogVisible" @close="close">
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<el-form :model="form" :rules="rules" ref="from">
|
<el-form :model="form" :rules="rules" ref="from">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
@ -7,12 +7,12 @@
|
||||||
prop="cronValue">
|
prop="cronValue">
|
||||||
<el-input v-model="form.cronValue" placeholder class="inp"/>
|
<el-input v-model="form.cronValue" placeholder class="inp"/>
|
||||||
<el-button type="primary" @click="showCronDialog">生成 Cron</el-button>
|
<el-button type="primary" @click="showCronDialog">生成 Cron</el-button>
|
||||||
<el-button type="primary" @click="save">保存</el-button>
|
<el-button type="primary" @click="saveCron">保存</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<crontab-result :ex="cronExpression"/>
|
<crontab-result :ex="schedule.cronExpression" ref="crontabResult"/>
|
||||||
</el-form>
|
</el-form>
|
||||||
<el-dialog title="生成 cron" :visible.sync="showCron" :modal="false">
|
<el-dialog title="生成 cron" :visible.sync="showCron" :modal="false">
|
||||||
<crontab @hide="showCron=false" @fill="crontabFill" :expression="cronExpression"/>
|
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.cronExpression"/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
@ -25,20 +25,28 @@
|
||||||
import {cronValidate} from "../../../../common/js/cron";
|
import {cronValidate} from "../../../../common/js/cron";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "MsSchedulerEdit",
|
name: "MsScheduleEdit",
|
||||||
components: {CrontabResult, Crontab},
|
components: {CrontabResult, Crontab},
|
||||||
|
props: {
|
||||||
|
save: Function,
|
||||||
|
schedule: {},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'schedule.cronExpression'() {
|
||||||
|
this.form.cronValue = this.schedule.cronExpression;
|
||||||
|
}
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
const validateCron = (rule, cronValue, callback) => {
|
const validateCron = (rule, cronValue, callback) => {
|
||||||
if (!cronValidate(cronValue)) {
|
if (!cronValidate(cronValue)) {
|
||||||
callback(new Error('Cron 表达式格式错误'));
|
callback(new Error('Cron 表达式格式错误'));
|
||||||
} else {
|
} else {
|
||||||
this.cronExpression = cronValue;
|
this.schedule.cronExpression = cronValue;
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
dialogVisible: false,
|
dialogVisible: false,
|
||||||
cronExpression: null,
|
|
||||||
showCron: false,
|
showCron: false,
|
||||||
form: {
|
form: {
|
||||||
cronValue: ""
|
cronValue: ""
|
||||||
|
@ -54,29 +62,26 @@
|
||||||
},
|
},
|
||||||
crontabFill(value) {
|
crontabFill(value) {
|
||||||
//确定后回传的值
|
//确定后回传的值
|
||||||
this.cronExpression = value;
|
this.schedule.cronExpression = value;
|
||||||
this.form.cronValue = value;
|
this.form.cronValue = value;
|
||||||
this.$refs['from'].validate();
|
this.$refs['from'].validate();
|
||||||
},
|
},
|
||||||
showCronDialog() {
|
showCronDialog() {
|
||||||
this.showCron = true;
|
this.showCron = true;
|
||||||
},
|
},
|
||||||
save () {
|
saveCron () {
|
||||||
if (!this.formValidate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("save");
|
|
||||||
},
|
|
||||||
formValidate() {
|
|
||||||
this.$refs['from'].validate((valid) => {
|
this.$refs['from'].validate((valid) => {
|
||||||
if (!valid) {
|
if (valid) {
|
||||||
|
this.save(this.form.cronValue);
|
||||||
|
this.dialogVisible = false;
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
this.cronExpression = null;
|
|
||||||
this.$refs['from'].resetFields();
|
this.$refs['from'].resetFields();
|
||||||
|
this.$refs.crontabResult.resultList = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="scheduler-config">
|
|
||||||
<div>
|
|
||||||
<span class="cron-ico">
|
|
||||||
<i class="el-icon-date" size="small"></i>
|
|
||||||
<span class="character" @click="schedulerEdit">SCHEDULER</span>
|
|
||||||
</span>
|
|
||||||
<el-switch v-model="isActive"/>
|
|
||||||
<!-- <el-button class="add-button" type="primary" size="mini" icon="el-icon-plus" plain @click="schedulerEdit"/>-->
|
|
||||||
<ms-scheduler-edit ref="schedulerEdit"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span :class="{'disable-character': !isActive}"> 下次执行时间:2020-06-19 12:07:09 </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import MsSchedulerEdit from "./MsSchedulerEdit";
|
|
||||||
export default {
|
|
||||||
name: "MsSchedulerConfig",
|
|
||||||
components: {MsSchedulerEdit},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isActive: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
schedulerEdit() {
|
|
||||||
this.$refs.schedulerEdit.open();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
.scheduler-config {
|
|
||||||
float: right;
|
|
||||||
width: 250px;
|
|
||||||
height: 15px;
|
|
||||||
line-height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-icon-date {
|
|
||||||
font-size: 20px;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.character {
|
|
||||||
font-weight: bold;
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disable-character {
|
|
||||||
color: #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*.scheduler-config >>> .el-switch__core::after {*/
|
|
||||||
/* height: 12px;*/
|
|
||||||
/* width: 12px;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.scheduler-config >>> .el-switch__core {*/
|
|
||||||
/* height: 15px;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
/*.scheduler-config >>> .el-switch.is-checked .el-switch__core::after {*/
|
|
||||||
/* margin-left: -13px;*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
.el-switch {
|
|
||||||
margin: 0 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cron-ico {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -344,10 +344,11 @@ export default {
|
||||||
this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
|
this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.$emit("resultListChange", this.resultList);
|
||||||
// 计算完成-显示结果
|
// 计算完成-显示结果
|
||||||
this.isShow = true;
|
this.isShow = true;
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
//用于计算某位数字在数组中的索引
|
//用于计算某位数字在数组中的索引
|
||||||
getIndex(arr, value) {
|
getIndex(arr, value) {
|
||||||
|
|
Loading…
Reference in New Issue