From 151fe957222e3d0b9a434f74a04cc9a33d093cbc Mon Sep 17 00:00:00 2001 From: song-tianyang Date: Tue, 25 May 2021 19:27:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E4=B8=8D?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E7=9A=84=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复测试计划定时任务不执行的缺陷和导入出现的问题 --- .../dto/automation/RunScenarioRequest.java | 4 + .../SchedulePlanScenarioExecuteRequest.java | 2 + .../api/service/ApiAutomationService.java | 30 ++- .../api/service/ApiTestCaseService.java | 1 - .../excel/domain/TestCaseExcelData.java | 9 +- .../job/sechedule/TestPlanTestJob.java | 6 +- .../track/controller/TestCaseController.java | 1 - .../track/controller/TestPlanController.java | 2 +- .../track/service/TestPlanService.java | 174 ++++++++++++------ .../plan/components/ScheduleMaintain.vue | 4 +- 10 files changed, 156 insertions(+), 77 deletions(-) diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java index c1e130bf7b..700834f313 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java @@ -35,4 +35,8 @@ public class RunScenarioRequest extends ApiScenarioWithBLOBs { private ApiScenarioRequest condition; private RunModeConfig config; + + private boolean isTestPlanScheduleJob = false; + //生成测试报告:当isTestPlanScheduleJob为ture时使用 + private String testPlanReportId; } diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/SchedulePlanScenarioExecuteRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/SchedulePlanScenarioExecuteRequest.java index 293ca46f2f..7a6df6dce4 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/SchedulePlanScenarioExecuteRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/SchedulePlanScenarioExecuteRequest.java @@ -35,4 +35,6 @@ public class SchedulePlanScenarioExecuteRequest { private Map> testPlanScenarioIDMap; private String testPlanReportId; + + private RunModeConfig config; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 78b4748e97..e4544b648b 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -726,15 +726,17 @@ public class ApiAutomationService { report.setStatus(APITestStatus.Running.name()); if (StringUtils.isNotEmpty(userID)) { report.setUserId(userID); + report.setCreateUser(userID); } else { report.setUserId(SessionUtils.getUserId()); + report.setCreateUser(SessionUtils.getUserId()); } report.setTriggerMode(triggerMode); report.setExecuteType(execType); report.setProjectId(projectId); report.setScenarioName(scenarioName); report.setScenarioId(scenarioId); - report.setCreateUser(SessionUtils.getUserId()); + return report; } @@ -894,7 +896,7 @@ public class ApiAutomationService { APIScenarioReportResult report; Map planEnvMap = new HashMap<>(); //如果是测试计划页面触发的执行方式,生成报告时createScenarioReport第二个参数需要特殊处理 - if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) { + if (StringUtils.equalsAny(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name(),ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) { String testPlanScenarioId = item.getId(); if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(item.getId())) { testPlanScenarioId = request.getScenarioTestPlanIdMap().get(item.getId()); @@ -905,8 +907,15 @@ public class ApiAutomationService { planEnvMap = JSON.parseObject(environment, Map.class); } } - report = createScenarioReport(reportId, testPlanScenarioId, item.getName(), request.getTriggerMode(), - request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); + if(request.isTestPlanScheduleJob()){ + String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId(); + report = createScenarioReport(reportId, savedScenarioId, item.getName(), request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); + }else{ + report = createScenarioReport(reportId, testPlanScenarioId, item.getName(), request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); + } + } else { report = createScenarioReport(reportId, item.getId(), item.getName(), request.getTriggerMode(), request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); @@ -1049,7 +1058,8 @@ public class ApiAutomationService { if (reportIds != null) { //如果是测试计划页面触发的执行方式,生成报告时createScenarioReport第二个参数需要特殊处理 APIScenarioReportResult report = null; - if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) { +// if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) { + if (StringUtils.equalsAny(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name(),ApiRunMode.SCHEDULE_SCENARIO_PLAN.name())) { String testPlanScenarioId = item.getId(); if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(item.getId())) { testPlanScenarioId = request.getScenarioTestPlanIdMap().get(item.getId()); @@ -1060,8 +1070,14 @@ public class ApiAutomationService { scenario.setEnvironmentMap(JSON.parseObject(environment, Map.class)); } } - report = createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), - request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig()); + if(request.isTestPlanScheduleJob()){ + String savedScenarioId = testPlanScenarioId + ":" + request.getTestPlanReportId(); + report = createScenarioReport(group.getName(), savedScenarioId, item.getName(), request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); + }else{ + report = createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig()); + } } else { report = createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), request.getExecuteType(), item.getProjectId(), request.getReportUserID(), request.getConfig()); diff --git a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java index 2f83391fed..e12d719822 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiTestCaseService.java @@ -626,7 +626,6 @@ public class ApiTestCaseService { HashTree jmeterHashTree = this.generateHashTree(request, apiCaseBolbs); // 调用执行方法 jMeterService.runDefinition(id, jmeterHashTree, debugReportId, runMode); - } catch (Exception ex) { LogUtil.error(ex.getMessage()); } diff --git a/backend/src/main/java/io/metersphere/excel/domain/TestCaseExcelData.java b/backend/src/main/java/io/metersphere/excel/domain/TestCaseExcelData.java index 597e5c2966..bbbe5f60e1 100644 --- a/backend/src/main/java/io/metersphere/excel/domain/TestCaseExcelData.java +++ b/backend/src/main/java/io/metersphere/excel/domain/TestCaseExcelData.java @@ -10,9 +10,8 @@ import java.util.Set; @Getter @Setter public class TestCaseExcelData { - + @ExcelIgnore private String id; - @ExcelIgnore private Integer num; @ExcelIgnore @@ -41,10 +40,10 @@ public class TestCaseExcelData { public Set getExcludeColumnFiledNames(boolean needNum){ Set excludeColumnFiledNames = new HashSet<>(); if(!needNum){ - excludeColumnFiledNames.add("num"); + excludeColumnFiledNames.add("customNum"); } - excludeColumnFiledNames.add("customNum"); - + excludeColumnFiledNames.add("id"); + excludeColumnFiledNames.add("num"); return excludeColumnFiledNames; } } diff --git a/backend/src/main/java/io/metersphere/job/sechedule/TestPlanTestJob.java b/backend/src/main/java/io/metersphere/job/sechedule/TestPlanTestJob.java index 595c57d62d..1f03186e9c 100644 --- a/backend/src/main/java/io/metersphere/job/sechedule/TestPlanTestJob.java +++ b/backend/src/main/java/io/metersphere/job/sechedule/TestPlanTestJob.java @@ -59,7 +59,11 @@ public class TestPlanTestJob extends MsScheduleJob { @Override void businessExecute(JobExecutionContext context) { - testPlanService.run(this.resourceId, this.projectID, this.userId, ReportTriggerMode.SCHEDULE.name()); + + JobDataMap jobDataMap = context.getJobDetail().getJobDataMap(); + String config = jobDataMap.getString("config"); + + testPlanService.run(this.resourceId, this.projectID, this.userId, ReportTriggerMode.SCHEDULE.name(),config); } public static JobKey getJobKey(String testId) { diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java index 64c1e101fc..7008c13b9b 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseController.java @@ -161,7 +161,6 @@ public class TestCaseController { } @PostMapping("/importIgnoreError/{projectId}/{userId}") - @RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_IMPORT) @MsAuditLog(module = "track_test_case", type = OperLogConstants.IMPORT, project = "#projectId") public ExcelResponse testCaseImportIgnoreError(MultipartFile file, @PathVariable String projectId, @PathVariable String userId, @PathVariable String importType, HttpServletRequest request) { checkPermissionService.checkProjectOwner(projectId); diff --git a/backend/src/main/java/io/metersphere/track/controller/TestPlanController.java b/backend/src/main/java/io/metersphere/track/controller/TestPlanController.java index 7478acdfd5..86449f343f 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestPlanController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestPlanController.java @@ -157,6 +157,6 @@ public class TestPlanController { } @PostMapping("/testplan/jenkins") public void runJenkins(@RequestBody TestplanRunRequest testplanRunRequest){ - testPlanService.run(testplanRunRequest.getTestPlanID(),testplanRunRequest.getProjectID(),testplanRunRequest.getUserId(),testplanRunRequest.getTriggerMode()); + testPlanService.run(testplanRunRequest.getTestPlanID(),testplanRunRequest.getProjectID(),testplanRunRequest.getUserId(),testplanRunRequest.getTriggerMode(),null); } } diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index bbdfbeccd5..709fecc679 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -861,6 +861,50 @@ public class TestPlanService { return extTestPlanMapper.findScheduleCreateUserById(testPlanId); } + public String scenarioRunModeConfig(SchedulePlanScenarioExecuteRequest planScenarioExecuteRequest) { + Map> testPlanScenarioIdMap = planScenarioExecuteRequest.getTestPlanScenarioIDMap(); + + String returnStr = null; + for (Map.Entry> entry : testPlanScenarioIdMap.entrySet()) { +// String testPlanId = entry.getKey(); + Map scenarioMap = entry.getValue(); + + RunScenarioRequest request = new RunScenarioRequest(); + request.setReportId(planScenarioExecuteRequest.getReportId()); + request.setEnvironmentId(planScenarioExecuteRequest.getEnvironmentId()); + request.setTriggerMode(planScenarioExecuteRequest.getTriggerMode()); + request.setExecuteType(planScenarioExecuteRequest.getExecuteType()); + request.setRunMode(planScenarioExecuteRequest.getRunMode()); + request.setIds(new ArrayList<>(scenarioMap.keySet()));//场景IDS + request.setReportUserID(planScenarioExecuteRequest.getReportUserID()); + request.setScenarioTestPlanIdMap(scenarioMap);//未知 + request.setConfig(planScenarioExecuteRequest.getConfig()); + request.setTestPlanScheduleJob(true); + request.setTestPlanReportId(planScenarioExecuteRequest.getTestPlanReportId()); + request.setId(UUID.randomUUID().toString()); + + if (request.getConfig() != null) { + if (request.getConfig().getMode().equals(RunModeConstants.PARALLEL.toString())) { + // 校验并发数量 + int count = 50; + BaseSystemConfigDTO dto = systemParameterService.getBaseInfo(); + if (StringUtils.isNotEmpty(dto.getConcurrency())) { + count = Integer.parseInt(dto.getConcurrency()); + } + if (request.getIds().size() > count) { + MSException.throwException("并发数量过大,请重新选择!"); + } + returnStr = apiAutomationService.modeRun(request); + } else { + returnStr = apiAutomationService.modeRun(request); + } + } else { + returnStr = apiAutomationService.excute(request); + } + } + return returnStr; + } + /** * 测试计划的定时任务--执行场景案例 * @@ -876,64 +920,9 @@ public class TestPlanService { for (Map.Entry> entry : testPlanScenarioIdMap.entrySet()) { Map planScenarioIdMap = entry.getValue(); - List apiScenarios = extApiScenarioMapper.selectIds(new ArrayList<>(planScenarioIdMap.keySet())); + try { - boolean isFirst = true; - for (ApiScenarioWithBLOBs item : apiScenarios) { - String apiScenarioID = item.getId(); - String planScenarioID = planScenarioIdMap.get(apiScenarioID); - if (StringUtils.isEmpty(planScenarioID)) { - continue; - } - if (item.getStepTotal() == 0) { - // 只有一个场景且没有测试步骤,则提示 - if (apiScenarios.size() == 1) { - MSException.throwException((item.getName() + "," + Translator.get("automation_exec_info"))); - } - LogUtil.warn(item.getName() + "," + Translator.get("automation_exec_info")); - continue; - } - MsThreadGroup group = new MsThreadGroup(); - group.setLabel(item.getName()); - group.setName(UUID.randomUUID().toString()); - // 批量执行的结果直接存储为报告 - if (isFirst) { - group.setName(request.getId()); - isFirst = false; - } - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - JSONObject element = JSON.parseObject(item.getScenarioDefinition()); - MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); - - // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 - if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) { - LinkedList elements = mapper.readValue(element.getString("hashTree"), - new TypeReference>() { - }); - scenario.setHashTree(elements); - } - if (StringUtils.isNotEmpty(element.getString("variables"))) { - LinkedList variables = mapper.readValue(element.getString("variables"), - new TypeReference>() { - }); - scenario.setVariables(variables); - } - group.setEnableCookieShare(scenario.isEnableCookieShare()); - LinkedList scenarios = new LinkedList<>(); - scenarios.add(scenario); - // 创建场景报告 - //不同的运行模式,第二个参数入参不同 - APIScenarioReportResult report = apiAutomationService.createScenarioReport(group.getName(), - planScenarioID + ":" + request.getTestPlanReportId(), - item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), - request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); - apiScenarioReportMapper.insert(report); - group.setHashTree(scenarios); - testPlan.getHashTree().add(group); - returnId = request.getId(); - } - + returnId = this.generateHashTreeByScenarioList(testPlan,planScenarioIdMap,request); } catch (Exception ex) { MSException.throwException(ex.getMessage()); } @@ -947,11 +936,74 @@ public class TestPlanService { return returnId; } - public void run(String testPlanID, String projectID, String userId, String triggerMode) { + private String generateHashTreeByScenarioList(MsTestPlan testPlan, Map planScenarioIdMap,SchedulePlanScenarioExecuteRequest request) throws Exception { + String returnId = ""; + boolean isFirst = true; + List apiScenarios = extApiScenarioMapper.selectIds(new ArrayList<>(planScenarioIdMap.keySet())); + for (ApiScenarioWithBLOBs item : apiScenarios) { + String apiScenarioID = item.getId(); + String planScenarioID = planScenarioIdMap.get(apiScenarioID); + if (StringUtils.isEmpty(planScenarioID)) { + continue; + } + if (item.getStepTotal() == 0) { + // 只有一个场景且没有测试步骤,则提示 + if (apiScenarios.size() == 1) { + MSException.throwException((item.getName() + "," + Translator.get("automation_exec_info"))); + } + LogUtil.warn(item.getName() + "," + Translator.get("automation_exec_info")); + continue; + } + MsThreadGroup group = new MsThreadGroup(); + group.setLabel(item.getName()); + group.setName(UUID.randomUUID().toString()); + // 批量执行的结果直接存储为报告 + if (isFirst) { + group.setName(request.getId()); + isFirst = false; + } + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + JSONObject element = JSON.parseObject(item.getScenarioDefinition()); + MsScenario scenario = JSONObject.parseObject(item.getScenarioDefinition(), MsScenario.class); + + // 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取 + if (element != null && StringUtils.isNotEmpty(element.getString("hashTree"))) { + LinkedList elements = mapper.readValue(element.getString("hashTree"), + new TypeReference>() { + }); + scenario.setHashTree(elements); + } + if (StringUtils.isNotEmpty(element.getString("variables"))) { + LinkedList variables = mapper.readValue(element.getString("variables"), + new TypeReference>() { + }); + scenario.setVariables(variables); + } + group.setEnableCookieShare(scenario.isEnableCookieShare()); + LinkedList scenarios = new LinkedList<>(); + scenarios.add(scenario); + // 创建场景报告 + //不同的运行模式,第二个参数入参不同 + APIScenarioReportResult report = apiAutomationService.createScenarioReport(group.getName(), + planScenarioID + ":" + request.getTestPlanReportId(), + item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(), + request.getExecuteType(), item.getProjectId(), request.getReportUserID(), null); + apiScenarioReportMapper.insert(report); + group.setHashTree(scenarios); + testPlan.getHashTree().add(group); + returnId = request.getId(); + } + return returnId; + } + + public void run(String testPlanID, String projectID, String userId, String triggerMode,String apiRunConfig) { Map planScenarioIdMap; Map apiTestCaseIdMap; Map performanceIdMap; - + if(StringUtils.isEmpty(apiRunConfig)){ + apiRunConfig = "{\"mode\":\"parallel\",\"reportType\":\"iddReport\",\"onSampleError\":true,\"runWithinResourcePool\":true,\"resourcePoolId\":\"29773f4f-55e4-4bce-ad3d-b531b4eb59c2\"}"; + } planScenarioIdMap = new LinkedHashMap<>(); apiTestCaseIdMap = new LinkedHashMap<>(); performanceIdMap = new LinkedHashMap<>(); @@ -1064,7 +1116,9 @@ public class TestPlanService { scenarioRequest.setTestPlanID(testPlanID); scenarioRequest.setRunMode(ApiRunMode.SCHEDULE_SCENARIO_PLAN.name()); scenarioRequest.setTestPlanReportId(planReportId); - String scenarioReportID = this.runScenarioCase(scenarioRequest); + RunModeConfig runModeConfig = JSONObject.parseObject(apiRunConfig, RunModeConfig.class); + scenarioRequest.setConfig(runModeConfig); + String scenarioReportID = this.scenarioRunModeConfig(scenarioRequest); if (StringUtils.isNotEmpty(scenarioReportID)) { scenarioIsExcuting = true; scenarioCaseIdArray = JSONArray.toJSONString(new ArrayList<>(planScenarioIdMap.keySet())); diff --git a/frontend/src/business/components/track/plan/components/ScheduleMaintain.vue b/frontend/src/business/components/track/plan/components/ScheduleMaintain.vue index 0e0bb9b4f9..f3e8ee6aa1 100644 --- a/frontend/src/business/components/track/plan/components/ScheduleMaintain.vue +++ b/frontend/src/business/components/track/plan/components/ScheduleMaintain.vue @@ -264,7 +264,9 @@ export default { this.result = this.$get("/schedule/findOne/" + scheduleResourceID + "/" + taskType, response => { if (response.data != null) { this.schedule = response.data; - this.runConfig = JSON.parse(response.data.config); + if(response.data.config){ + this.runConfig = JSON.parse(response.data.config); + } } else { this.schedule = {}; }