性能测试-定时任务

This commit is contained in:
chenjianxing 2020-06-24 17:33:42 +08:00
parent 6c4dbedf36
commit fdfac7f038
13 changed files with 191 additions and 64 deletions

View File

@ -20,6 +20,7 @@ import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.job.QuartzManager;
import io.metersphere.job.sechedule.ApiTestJob;
import io.metersphere.job.sechedule.PerformanceTestJob;
import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService;
import org.apache.commons.lang3.StringUtils;
@ -40,6 +41,8 @@ import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@ -231,44 +234,23 @@ public class APITestService {
public void updateSchedule(Schedule request) {
scheduleService.editSchedule(request);
updateApiTestCronJob(request);
addOrUpdateApiTestCronJob(request);
}
public void createSchedule(Schedule request) {
scheduleService.addSchedule(buildApiTestSchedule(request));
updateApiTestCronJob(request);
addOrUpdateApiTestCronJob(request);
}
private Schedule buildApiTestSchedule(Schedule request) {
Schedule schedule = new Schedule();
schedule.setResourceId(request.getResourceId());
schedule.setEnable(request.getEnable());
Schedule schedule = scheduleService.buildApiTestSchedule(request);
schedule.setJob(ApiTestJob.class.getName());
schedule.setValue(request.getValue().trim());
schedule.setGroup(ScheduleGroup.API_TEST.name());
schedule.setKey(request.getResourceId());
schedule.setType(ScheduleType.CRON.name());
schedule.setUserId(SessionUtils.getUser().getId());
return schedule;
}
private void updateApiTestCronJob(Schedule request) {
Boolean enable = request.getEnable();
String cronExpression = request.getValue();
if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) {
try {
QuartzManager.addOrUpdateCronJob(ApiTestJob.getJobKey(request.getResourceId()),
ApiTestJob.getTriggerKey(request.getResourceId()), ApiTestJob.class, cronExpression, QuartzManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
} catch (SchedulerException e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException("定时任务开启异常");
}
} else {
try {
QuartzManager.removeJob(ApiTestJob.getJobKey(request.getResourceId()), ApiTestJob.getTriggerKey(request.getResourceId()));
} catch (Exception e) {
MSException.throwException("定时任务关闭异常");
}
}
private void addOrUpdateApiTestCronJob(Schedule request) {
scheduleService.addOrUpdateCronJob(request, ApiTestJob.getJobKey(request.getResourceId()), ApiTestJob.getTriggerKey(request.getResourceId()), ApiTestJob.class);
}
}

View File

@ -1,6 +1,7 @@
package io.metersphere.dto;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule;
import lombok.Getter;
import lombok.Setter;
@ -9,4 +10,5 @@ import lombok.Setter;
public class LoadTestDTO extends LoadTest {
private String projectName;
private String userName;
private Schedule schedule;
}

View File

@ -20,7 +20,7 @@ public class ApiTestJob extends MsScheduleJob {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
if (StringUtils.isBlank(resourceId)) {
QuartzManager.removeJob(new JobKey(resourceId), new TriggerKey(resourceId));
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
}
LogUtil.info("ApiTestSchedule Running: " + resourceId);
LogUtil.info("CronExpression: " + expression);

View File

@ -1,12 +1,45 @@
package io.metersphere.job.sechedule;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.job.QuartzManager;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.track.request.testplan.RunTestPlanRequest;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
public class PerformanceTestJob extends MsScheduleJob {
private PerformanceTestService performanceTestService;
public PerformanceTestJob() {
this.performanceTestService = CommonBeanFactory.getBean(PerformanceTestService.class);
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
if (StringUtils.isBlank(resourceId)) {
QuartzManager.removeJob(getJobKey(resourceId), getTriggerKey(resourceId));
}
LogUtil.info("PerformanceTestSchedule Running: " + resourceId);
LogUtil.info("CronExpression: " + expression);
RunTestPlanRequest request = new RunTestPlanRequest();
request.setId(resourceId);
request.setUserId(userId);
performanceTestService.run(request);
}
public static JobKey getJobKey(String testId) {
return new JobKey(testId, ScheduleGroup.PERFORMANCE_TEST.name());
}
public static TriggerKey getTriggerKey(String testId) {
return new TriggerKey(testId, ScheduleGroup.PERFORMANCE_TEST.name());
}
}

View File

@ -1,4 +1,4 @@
package io.metersphere.listeners;
package io.metersphere.listener;
import io.metersphere.service.ScheduleService;
import org.springframework.boot.context.event.ApplicationReadyEvent;

View File

@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.FileMetadata;
import io.metersphere.base.domain.LoadTest;
import io.metersphere.base.domain.Schedule;
import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
@ -117,4 +118,15 @@ public class PerformanceTestController {
public void copy(@RequestBody SaveTestPlanRequest request) {
performanceTestService.copy(request);
}
@PostMapping(value = "/schedule/create")
public void createSchedule(@RequestBody Schedule request) {
performanceTestService.createSchedule(request);
}
@PostMapping(value = "/schedule/update")
public void updateSchedule(@RequestBody Schedule request) {
performanceTestService.updateSchedule(request);
}
}

View File

@ -7,6 +7,8 @@ import io.metersphere.base.mapper.ext.ExtLoadTestReportDetailMapper;
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
import io.metersphere.commons.constants.APITestStatus;
import io.metersphere.commons.constants.PerformanceTestStatus;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
@ -16,9 +18,11 @@ import io.metersphere.controller.request.OrderRequest;
import io.metersphere.dto.DashboardTestDTO;
import io.metersphere.dto.LoadTestDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.job.sechedule.PerformanceTestJob;
import io.metersphere.performance.engine.Engine;
import io.metersphere.performance.engine.EngineFactory;
import io.metersphere.service.FileService;
import io.metersphere.service.ScheduleService;
import io.metersphere.service.TestResourceService;
import io.metersphere.track.request.testplan.*;
import org.apache.commons.collections4.ListUtils;
@ -68,6 +72,8 @@ public class PerformanceTestService {
private ReportService reportService;
@Resource
private KafkaProperties kafkaProperties;
@Resource
private ScheduleService scheduleService;
public List<LoadTestDTO> list(QueryTestPlanRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
@ -196,6 +202,9 @@ public class PerformanceTestService {
@Transactional(noRollbackFor = MSException.class)// 保存失败的信息
public String run(RunTestPlanRequest request) {
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
if (request.getUserId() != null) {
loadTest.setUserId(request.getUserId());
}
if (loadTest == null) {
MSException.throwException(Translator.get("run_load_test_not_found") + request.getId());
}
@ -252,7 +261,7 @@ public class PerformanceTestService {
testReport.setUpdateTime(engine.getStartTime());
testReport.setTestId(loadTest.getId());
testReport.setName(loadTest.getName());
testReport.setUserId(SessionUtils.getUser().getId());
testReport.setUserId(Optional.ofNullable(SessionUtils.getUser().getId()).orElse(loadTest.getUserId()));
// 启动测试
try {
@ -296,7 +305,10 @@ public class PerformanceTestService {
request.setId(testId);
List<LoadTestDTO> testDTOS = extLoadTestMapper.list(request);
if (!CollectionUtils.isEmpty(testDTOS)) {
return testDTOS.get(0);
LoadTestDTO loadTestDTO = testDTOS.get(0);
Schedule schedule = scheduleService.getScheduleByResource(loadTestDTO.getId(), ScheduleGroup.PERFORMANCE_TEST.name());
loadTestDTO.setSchedule(schedule);
return loadTestDTO;
}
return null;
}
@ -350,4 +362,26 @@ public class PerformanceTestService {
});
}
}
public void updateSchedule(Schedule request) {
scheduleService.editSchedule(request);
addOrUpdatePerformanceTestCronJob(request);
}
public void createSchedule(Schedule request) {
scheduleService.addSchedule(buildPerformanceTestSchedule(request));
addOrUpdatePerformanceTestCronJob(request);
}
private Schedule buildPerformanceTestSchedule(Schedule request) {
Schedule schedule = scheduleService.buildApiTestSchedule(request);
schedule.setJob(PerformanceTestJob.class.getName());
schedule.setGroup(ScheduleGroup.PERFORMANCE_TEST.name());
schedule.setType(ScheduleType.CRON.name());
return schedule;
}
private void addOrUpdatePerformanceTestCronJob(Schedule request) {
scheduleService.addOrUpdateCronJob(request, PerformanceTestJob.getJobKey(request.getResourceId()), PerformanceTestJob.getTriggerKey(request.getResourceId()), PerformanceTestJob.class);
}
}

View File

@ -4,9 +4,16 @@ import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.Schedule;
import io.metersphere.base.domain.ScheduleExample;
import io.metersphere.base.mapper.ScheduleMapper;
import io.metersphere.commons.constants.ScheduleGroup;
import io.metersphere.commons.constants.ScheduleType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.job.QuartzManager;
import io.metersphere.job.sechedule.ApiTestJob;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -77,4 +84,33 @@ public class ScheduleService {
}
});
}
public Schedule buildApiTestSchedule(Schedule request) {
Schedule schedule = new Schedule();
schedule.setResourceId(request.getResourceId());
schedule.setEnable(request.getEnable());
schedule.setValue(request.getValue().trim());
schedule.setKey(request.getResourceId());
schedule.setUserId(SessionUtils.getUser().getId());
return schedule;
}
public void addOrUpdateCronJob(Schedule request, JobKey jobKey, TriggerKey triggerKey, Class clazz) {
Boolean enable = request.getEnable();
String cronExpression = request.getValue();
if (enable != null && enable && StringUtils.isNotBlank(cronExpression)) {
try {
QuartzManager.addOrUpdateCronJob(jobKey, triggerKey, clazz, cronExpression, QuartzManager.getDefaultJobDataMap(request.getResourceId(), cronExpression, SessionUtils.getUser().getId()));
} catch (SchedulerException e) {
LogUtil.error(e.getMessage(), e);
MSException.throwException("定时任务开启异常");
}
} else {
try {
QuartzManager.removeJob(jobKey, triggerKey);
} catch (Exception e) {
MSException.throwException("定时任务关闭异常");
}
}
}
}

View File

@ -1,4 +1,10 @@
package io.metersphere.track.request.testplan;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class RunTestPlanRequest extends TestPlanRequest {
private String userId;
}

View File

@ -219,10 +219,7 @@
this.saveSchedule();
},
saveSchedule() {
if (this.create) {
this.$message('请先保存测试,在设置定时任务');
return;
}
this.checkScheduleEdit();
let param = {};
param = this.test.schedule;
param.resourceId = this.test.id;
@ -278,8 +275,4 @@
.test-container .more {
margin-left: 10px;
}
.schedule-config {
float: right;
}
</style>

View File

@ -32,7 +32,9 @@
checkOpen: {
type: Function,
default() {
return new Function()
return {
checkOpen() {return true;}
}
}
},
},

View File

@ -1,7 +1,7 @@
<template>
<el-dialog width="30%" class="schedule-edit" :title="'编辑定时任务'" :visible.sync="dialogVisible" @close="close">
<div id="app">
<el-form :model="schedule" :rules="rules" ref="from">
<el-form :model="form" :rules="rules" ref="from">
<el-form-item
:placeholder="'请输入 Cron 表达式'"
prop="cronValue">
@ -9,7 +9,7 @@
<el-button type="primary" @click="showCronDialog">生成 Cron</el-button>
<el-button type="primary" @click="saveCron">保存</el-button>
</el-form-item>
<crontab-result :ex="schedule.value" ref="crontabResult"/>
<crontab-result :ex="form.cronValue" ref="crontabResult"/>
</el-form>
<el-dialog title="生成 cron" :visible.sync="showCron" :modal="false">
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.value"/>
@ -41,7 +41,6 @@
if (!cronValidate(cronValue)) {
callback(new Error('Cron 表达式格式错误'));
} else {
this.schedule.value = cronValue;
callback();
}
};
@ -62,7 +61,6 @@
},
crontabFill(value) {
//
this.schedule.value = value;
this.form.cronValue = value;
this.$refs['from'].validate();
},
@ -80,12 +78,14 @@
});
},
close() {
this.form.cronValue = '';
this.$refs['from'].resetFields();
this.form.cronValue = this.schedule.value;
if (!this.schedule.value) {
this.$refs.crontabResult.resultList = [];
}
}
}
}
</script>
<style scoped>

View File

@ -23,6 +23,8 @@
<el-button :disabled="isReadOnly" type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
<el-button :disabled="isReadOnly" type="primary" plain @click="saveAndRun">{{$t('load_test.save_and_run')}}</el-button>
<el-button :disabled="isReadOnly" type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
<ms-schedule-config :schedule="testPlan.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit"/>
</el-col>
</el-row>
@ -50,10 +52,12 @@
import MsContainer from "../../common/components/MsContainer";
import MsMainContainer from "../../common/components/MsMainContainer";
import {checkoutTestManagerOrTestUser} from "../../../../common/js/utils";
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
export default {
name: "EditPerformanceTestPlan",
components: {
MsScheduleConfig,
PerformancePressureConfig,
PerformanceBasicConfig,
PerformanceAdvancedConfig,
@ -63,7 +67,7 @@
data() {
return {
result: {},
testPlan: {},
testPlan: {schedule:{}},
listProjectPath: "/project/listAll",
savePath: "/performance/save",
editPath: "/performance/edit",
@ -103,32 +107,16 @@
if (!checkoutTestManagerOrTestUser()) {
this.isReadOnly = true;
}
let testId = to.params.testId;
if (testId) {
this.testId = testId;
this.result = this.$get('/performance/get/' + testId, response => {
if (response.data) {
this.testPlan = response.data;
}
});
}
this.getTest(to.params.testId);
}
},
created() {
let testId = this.$route.params.testId;
this.isReadOnly = false;
if (!checkoutTestManagerOrTestUser()) {
this.isReadOnly = true;
}
if (testId) {
this.testId = testId;
this.result = this.$get('/performance/get/' + testId, response => {
this.testPlan = response.data;
});
}
this.getTest(this.$route.params.testId);
this.listProjects();
},
mounted() {
@ -148,6 +136,19 @@
this.$store.commit("clearTest");
}
},
getTest(testId) {
if (testId) {
this.testId = testId;
this.result = this.$get('/performance/get/' + testId, response => {
if (response.data) {
this.testPlan = response.data;
if (!this.testPlan.schedule) {
this.testPlan.schedule = {};
}
}
});
}
},
listProjects() {
this.result = this.$get(this.listProjectPath, response => {
this.projects = response.data;
@ -251,6 +252,32 @@
this.$nextTick(()=> {
this.active = activeName;
});
},
saveCronExpression(cronExpression) {
this.testPlan.schedule.enable = true;
this.testPlan.schedule.value = cronExpression;
this.saveSchedule();
},
saveSchedule() {
this.checkScheduleEdit();
let param = {};
param = this.testPlan.schedule;
param.resourceId = this.testPlan.id;
let url = '/performance/schedule/create';
if (param.id) {
url = '/performance/schedule/update';
}
this.$post(url, param, response => {
this.$success('保存成功');
this.getTest(this.testPlan.id);
});
},
checkScheduleEdit() {
if (!this.testPlan.id) {
this.$message('请先保存测试');
return false;
}
return true;
}
}
}