feat(接口测试): 补充场景定时执行

This commit is contained in:
AgAngle 2024-04-07 10:57:09 +08:00 committed by 刘瑞斌
parent bc65305ed9
commit 9e1ebd5e2c
6 changed files with 91 additions and 163 deletions

View File

@ -208,11 +208,6 @@ public class ApiScenarioController {
@CheckOwner(resourceId = "#request.getScenarioId()", resourceType = "api_scenario") @CheckOwner(resourceId = "#request.getScenarioId()", resourceType = "api_scenario")
@SendNotice(taskType = NoticeConstants.TaskType.SCHEDULE_TASK, event = NoticeConstants.Event.UPDATE, target = "#targetClass.getScheduleNotice(#request)", targetClass = ApiScenarioNoticeService.class) @SendNotice(taskType = NoticeConstants.TaskType.SCHEDULE_TASK, event = NoticeConstants.Event.UPDATE, target = "#targetClass.getScheduleNotice(#request)", targetClass = ApiScenarioNoticeService.class)
public String scheduleConfig(@Validated @RequestBody ApiScenarioScheduleConfigRequest request) { public String scheduleConfig(@Validated @RequestBody ApiScenarioScheduleConfigRequest request) {
/*
TODO to Chen Jianxing:
request.configMap 中需要补充场景的执行信息比如环境资源池是否失败停止等配置
在触发定时任务的APIScenarioScheduleJob中会用到
*/
apiValidateService.validateApiMenuInProject(request.getScenarioId(), ApiResource.API_SCENARIO.name()); apiValidateService.validateApiMenuInProject(request.getScenarioId(), ApiResource.API_SCENARIO.name());
return apiScenarioService.scheduleConfig(request, SessionUtils.getUserId()); return apiScenarioService.scheduleConfig(request, SessionUtils.getUserId());
} }

View File

@ -1,6 +1,26 @@
package io.metersphere.api.job; package io.metersphere.api.job;
import io.metersphere.api.domain.ApiScenarioReport;
import io.metersphere.api.dto.ApiScenarioParamConfig;
import io.metersphere.api.dto.ApiScenarioParseTmpParam;
import io.metersphere.api.dto.debug.ApiResourceRunRequest;
import io.metersphere.api.dto.request.MsScenario;
import io.metersphere.api.dto.scenario.ApiScenarioDetail;
import io.metersphere.api.dto.scenario.ApiScenarioParseParam;
import io.metersphere.api.service.ApiExecuteService;
import io.metersphere.api.service.scenario.ApiScenarioService;
import io.metersphere.sdk.constants.ApiBatchRunMode;
import io.metersphere.sdk.constants.ApiExecuteRunMode;
import io.metersphere.sdk.constants.TaskTriggerMode;
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
import io.metersphere.sdk.dto.api.task.TaskRequestDTO;
import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.schedule.BaseScheduleJob; import io.metersphere.system.schedule.BaseScheduleJob;
import io.metersphere.system.uid.IDGenerator;
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
import org.quartz.JobKey; import org.quartz.JobKey;
import org.quartz.TriggerKey; import org.quartz.TriggerKey;
@ -8,11 +28,52 @@ import org.quartz.TriggerKey;
public class ApiScenarioScheduleJob extends BaseScheduleJob { public class ApiScenarioScheduleJob extends BaseScheduleJob {
@Override @Override
protected void businessExecute(JobExecutionContext context) { protected void businessExecute(JobExecutionContext context) {
/* ApiScenarioService apiScenarioService = CommonBeanFactory.getBean(ApiScenarioService.class);
TODO to Chen Jianxing: ApiExecuteService apiExecuteService = CommonBeanFactory.getBean(ApiExecuteService.class);
这里需要补充执行逻辑 ApiRunModeConfigDTO apiRunModeConfigDTO = JSON.parseObject(JSON.toJSONString(context.getJobDetail().getJobDataMap()), ApiRunModeConfigDTO.class);
记得执行信息环境资源池是否失败停止等配置在jobDataMap里面
*/ ApiScenarioDetail apiScenarioDetail = apiScenarioService.getForRun(resourceId);
if (apiScenarioDetail == null) {
LogUtils.info("当前定时任务的场景已删除 {}", resourceId);
return;
}
MsScenario msScenario = apiScenarioService.getMsScenario(apiScenarioDetail);
ApiScenarioParseParam parseParam = apiScenarioService.getApiScenarioParseParam(apiScenarioDetail);
parseParam.setEnvironmentId(apiRunModeConfigDTO.getEnvironmentId());
parseParam.setGrouped(apiRunModeConfigDTO.getGrouped());
if (StringUtils.isBlank(apiRunModeConfigDTO.getPoolId())) {
apiRunModeConfigDTO.setPoolId(apiExecuteService.getProjectApiResourcePoolId(apiScenarioDetail.getProjectId()));
}
// 解析生成场景树并保存临时变量
ApiScenarioParseTmpParam tmpParam = apiScenarioService.parse(msScenario, apiScenarioDetail.getSteps(), parseParam);
ApiResourceRunRequest runRequest = apiScenarioService.getApiResourceRunRequest(msScenario, tmpParam);
TaskRequestDTO taskRequest = apiScenarioService.getTaskRequest(IDGenerator.nextStr(), apiScenarioDetail.getId(), apiScenarioDetail.getProjectId(), ApiExecuteRunMode.SCENARIO.name());
taskRequest.getRunModeConfig().setPoolId(apiRunModeConfigDTO.getPoolId());
taskRequest.setSaveResult(true);
taskRequest.setRealTime(false);
taskRequest.getRunModeConfig().setEnvironmentId(parseParam.getEnvironmentId());
taskRequest.setRequestCount(tmpParam.getRequestCount().get());
ApiScenarioParamConfig parseConfig = apiScenarioService.getApiScenarioParamConfig(parseParam, tmpParam.getScenarioParseEnvInfo());
parseConfig.setReportId(taskRequest.getReportId());
// 初始化报告
ApiScenarioReport scenarioReport = apiScenarioService.getScenarioReport(userId);
scenarioReport.setId(taskRequest.getReportId());
scenarioReport.setTriggerMode(TaskTriggerMode.SCHEDULE.name());
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
scenarioReport.setPoolId(apiRunModeConfigDTO.getPoolId());
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
apiScenarioService.initApiReport(apiScenarioDetail, scenarioReport);
// 初始化报告步骤
apiScenarioService.initScenarioReportSteps(apiScenarioDetail.getSteps(), taskRequest.getReportId());
apiExecuteService.execute(runRequest, taskRequest, parseConfig);
} }
public static JobKey getJobKey(String scenarioId) { public static JobKey getJobKey(String scenarioId) {

View File

@ -301,14 +301,9 @@ public class ApiScenarioBatchRunService {
boolean envGroup = getEnvGroup(runModeConfig, apiScenarioDetail); boolean envGroup = getEnvGroup(runModeConfig, apiScenarioDetail);
// 解析生成待执行的场景树 // 解析生成待执行的场景树
MsScenario msScenario = new MsScenario(); MsScenario msScenario = apiScenarioService.getMsScenario(apiScenarioDetail);
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
msScenario.setProjectId(apiScenarioDetail.getProjectId());
ApiScenarioParseParam parseParam = new ApiScenarioParseParam(); ApiScenarioParseParam parseParam = apiScenarioService.getApiScenarioParseParam(apiScenarioDetail);
parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
parseParam.setStepDetails(Map.of());
parseParam.setEnvironmentId(envId); parseParam.setEnvironmentId(envId);
parseParam.setGrouped(envGroup); parseParam.setGrouped(envGroup);

View File

@ -84,7 +84,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.kafka.common.errors.ResourceNotFoundException;
import org.mybatis.spring.SqlSessionUtils; import org.mybatis.spring.SqlSessionUtils;
import org.quartz.CronExpression; import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder; import org.quartz.CronScheduleBuilder;
@ -1278,18 +1277,28 @@ public class ApiScenarioService extends MoveNodeService {
ApiScenarioDetail apiScenarioDetail = getForRun(id); ApiScenarioDetail apiScenarioDetail = getForRun(id);
// 解析生成待执行的场景树 // 解析生成待执行的场景树
MsScenario msScenario = new MsScenario(); MsScenario msScenario = getMsScenario(apiScenarioDetail);
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
msScenario.setProjectId(apiScenarioDetail.getProjectId());
ApiScenarioParseParam parseParam = getApiScenarioParseParam(apiScenarioDetail);
return executeRun(apiScenarioDetail, msScenario, apiScenarioDetail.getSteps(), parseParam, reportId, userId);
}
public ApiScenarioParseParam getApiScenarioParseParam(ApiScenarioDetail apiScenarioDetail) {
ApiScenarioParseParam parseParam = new ApiScenarioParseParam(); ApiScenarioParseParam parseParam = new ApiScenarioParseParam();
parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig()); parseParam.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
parseParam.setStepDetails(Map.of()); parseParam.setStepDetails(Map.of());
parseParam.setEnvironmentId(apiScenarioDetail.getEnvironmentId()); parseParam.setEnvironmentId(apiScenarioDetail.getEnvironmentId());
parseParam.setGrouped(apiScenarioDetail.getGrouped()); parseParam.setGrouped(apiScenarioDetail.getGrouped());
return parseParam;
}
return executeRun(apiScenarioDetail, msScenario, apiScenarioDetail.getSteps(), parseParam, reportId, userId); public MsScenario getMsScenario(ApiScenarioDetail apiScenarioDetail) {
MsScenario msScenario = new MsScenario();
msScenario.setRefType(ApiScenarioStepRefType.DIRECT.name());
msScenario.setScenarioConfig(apiScenarioDetail.getScenarioConfig());
msScenario.setProjectId(apiScenarioDetail.getProjectId());
return msScenario;
} }
public TaskRequestDTO run(ApiScenarioDebugRequest request, String userId) { public TaskRequestDTO run(ApiScenarioDebugRequest request, String userId) {
@ -1336,7 +1345,13 @@ public class ApiScenarioService extends MoveNodeService {
parseConfig.setReportId(reportId); parseConfig.setReportId(reportId);
// 初始化报告 // 初始化报告
initApiReport(apiScenario, parseParam.getEnvironmentId(), reportId, poolId, userId); ApiScenarioReport scenarioReport = getScenarioReport(userId);
scenarioReport.setId(reportId);
scenarioReport.setTriggerMode(TaskTriggerMode.MANUAL.name());
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
scenarioReport.setPoolId(poolId);
scenarioReport.setEnvironmentId(parseParam.getEnvironmentId());
initApiReport(apiScenario, scenarioReport);
// 初始化报告步骤 // 初始化报告步骤
initScenarioReportSteps(steps, taskRequest.getReportId()); initScenarioReportSteps(steps, taskRequest.getReportId());
@ -1352,20 +1367,11 @@ public class ApiScenarioService extends MoveNodeService {
* 预生成用例的执行报告 * 预生成用例的执行报告
* *
* @param apiScenario * @param apiScenario
* @param poolId
* @param userId
* @return * @return
*/ */
public ApiScenarioRecord initApiReport(ApiScenario apiScenario, String envId, String reportId, String poolId, String userId) { public ApiScenarioRecord initApiReport(ApiScenario apiScenario, ApiScenarioReport scenarioReport) {
// 初始化报告 // 初始化报告
ApiScenarioReport scenarioReport = getScenarioReport(userId);
scenarioReport.setId(reportId);
scenarioReport.setTriggerMode(TaskTriggerMode.MANUAL.name());
scenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis())); scenarioReport.setName(apiScenario.getName() + "_" + DateUtils.getTimeString(System.currentTimeMillis()));
scenarioReport.setRunMode(ApiBatchRunMode.PARALLEL.name());
scenarioReport.setPoolId(poolId);
scenarioReport.setEnvironmentId(apiScenario.getEnvironmentId());
scenarioReport.setEnvironmentId(envId);
scenarioReport.setProjectId(apiScenario.getProjectId()); scenarioReport.setProjectId(apiScenario.getProjectId());
// 创建报告和用例的关联关系 // 创建报告和用例的关联关系

View File

@ -1,104 +0,0 @@
package io.metersphere.system.controller;
import io.metersphere.sdk.constants.ScheduleResourceType;
import io.metersphere.sdk.constants.ScheduleType;
import io.metersphere.sdk.dto.api.task.ApiRunModeConfigDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.domain.Schedule;
import io.metersphere.system.dto.request.ScheduleConfig;
import io.metersphere.system.job.ApiScenarioScheduleJob;
import io.metersphere.system.schedule.ScheduleService;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ScheduleControllerTests extends BaseTest {
@Resource
private ScheduleService scheduleService;
@Test
public void test() {
Schedule schedule = new Schedule();
schedule.setName("test-schedule");
schedule.setResourceId("test-resource-id");
schedule.setEnable(true);
schedule.setValue("0 0/1 * * * ?");
schedule.setKey("test-resource-id");
schedule.setCreateUser("admin");
schedule.setProjectId(DEFAULT_PROJECT_ID);
schedule.setConfig("{}");
schedule.setJob(ApiScenarioScheduleJob.class.getName());
schedule.setType(ScheduleType.CRON.name());
schedule.setResourceType(ScheduleResourceType.API_IMPORT.name());
scheduleService.addSchedule(schedule);
scheduleService.getSchedule(schedule.getId());
scheduleService.editSchedule(schedule);
scheduleService.getScheduleByResource(schedule.getResourceId(), schedule.getJob());
scheduleService.deleteByResourceId(schedule.getResourceId(), schedule.getJob());
schedule = new Schedule();
schedule.setName("test-schedule-1");
schedule.setResourceId("test-resource-id-1");
schedule.setEnable(true);
schedule.setValue("0 0/1 * * * ?");
schedule.setKey("test-resource-id-1");
schedule.setCreateUser("admin");
schedule.setProjectId(DEFAULT_PROJECT_ID);
schedule.setConfig("{}");
schedule.setJob(ApiScenarioScheduleJob.class.getName());
schedule.setType(ScheduleType.CRON.name());
schedule.setResourceType(ScheduleResourceType.API_SCENARIO.name());
scheduleService.addSchedule(schedule);
scheduleService.deleteByResourceIds(List.of(schedule.getResourceId()), schedule.getJob());
schedule = new Schedule();
schedule.setName("test-schedule-2");
schedule.setResourceId("test-resource-id-2");
schedule.setEnable(true);
schedule.setValue("0 0/1 * * * ?");
schedule.setKey("test-resource-id-2");
schedule.setCreateUser("admin");
schedule.setProjectId(DEFAULT_PROJECT_ID);
schedule.setConfig("{}");
schedule.setJob("test-job");
schedule.setType(ScheduleType.CRON.name());
schedule.setResourceType(ScheduleResourceType.API_SCENARIO.name());
scheduleService.addSchedule(schedule);
scheduleService.addOrUpdateCronJob(schedule,
new JobKey(schedule.getResourceId(), ApiScenarioScheduleJob.class.getName()),
new TriggerKey(schedule.getResourceId(), ApiScenarioScheduleJob.class.getName()),
ApiScenarioScheduleJob.class);
scheduleService.deleteByProjectId(schedule.getProjectId());
ScheduleConfig scheduleConfig = ScheduleConfig.builder()
.resourceId("test-resource-id-3")
.key("test-resource-id-3")
.projectId(DEFAULT_PROJECT_ID)
.name("test-schedule-3")
.enable(true)
.cron("0 0/1 * * * ?")
.resourceType(ScheduleResourceType.API_SCENARIO.name())
.config(JSON.toJSONString(new ApiRunModeConfigDTO()))
.build();
scheduleService.scheduleConfig(
scheduleConfig,
new JobKey(scheduleConfig.getResourceId(), ApiScenarioScheduleJob.class.getName()),
new TriggerKey(scheduleConfig.getResourceId(), ApiScenarioScheduleJob.class.getName()),
ApiScenarioScheduleJob.class,
"admin");
}
}

View File

@ -1,25 +0,0 @@
package io.metersphere.system.job;
import io.metersphere.system.schedule.BaseScheduleJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
public class ApiScenarioScheduleJob extends BaseScheduleJob {
@Override
protected void businessExecute(JobExecutionContext context) {
/*
TODO to Chen Jianxing:
这里需要补充执行逻辑
记得执行信息环境资源池是否失败停止等配置在jobDataMap里面
*/
}
public static JobKey getJobKey(String scenarioId) {
return new JobKey(scenarioId, ApiScenarioScheduleJob.class.getName());
}
public static TriggerKey getTriggerKey(String scenarioId) {
return new TriggerKey(scenarioId, ApiScenarioScheduleJob.class.getName());
}
}