From be8784d3b5cf60cf8a646584a8008f128f7e7024 Mon Sep 17 00:00:00 2001 From: song-tianyang Date: Sun, 24 Apr 2022 16:39:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B5=8B=E8=AF=95=E8=B7=9F=E8=B8=AA):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B5=8B=E8=AF=95=E8=AE=A1=E5=88=92=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=80=9A=E7=9F=A5=E7=9A=84=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E4=B8=8D=E8=AE=BA=E5=87=BA=E7=8E=B0=E4=BB=80=E4=B9=88=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E9=83=BD=E4=B8=8D=E4=BC=9A=E5=BD=B1=E5=93=8D=E5=88=B0?= =?UTF-8?q?=E4=B8=8A=E4=B8=80=E5=B1=82=E7=9A=84=E4=BA=8B=E7=89=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化测试计划发送通知的方法,不论出现什么异常都不会影响到上一层的事物 --- .../controller/TestPlanReportController.java | 17 --- .../track/service/TestPlanMessageService.java | 125 ++++++++++++++++ .../track/service/TestPlanReportService.java | 134 ++++-------------- 3 files changed, 150 insertions(+), 126 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/track/service/TestPlanMessageService.java diff --git a/backend/src/main/java/io/metersphere/track/controller/TestPlanReportController.java b/backend/src/main/java/io/metersphere/track/controller/TestPlanReportController.java index b617fec4a0..383abc6ea3 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestPlanReportController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestPlanReportController.java @@ -6,7 +6,6 @@ import io.metersphere.base.domain.TestPlanReport; import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogModule; -import io.metersphere.commons.constants.ReportTriggerMode; import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.Pager; import io.metersphere.commons.utils.SessionUtils; @@ -52,13 +51,6 @@ public class TestPlanReportController { return testPlanReportService.getReport(reportId); } - @GetMapping("/sendTask/{planId}") - public String sendTask(@PathVariable String planId) { - TestPlanReport report = testPlanReportService.getTestPlanReport(planId); - testPlanReportService.update(report); - return "sucess"; - } - @GetMapping("/status/{planId}") public String getStatus(@PathVariable String planId) { TestPlanReport report = testPlanReportService.getTestPlanReport(planId); @@ -79,15 +71,6 @@ public class TestPlanReportController { testPlanReportService.delete(request); } - - @GetMapping("/apiExecuteFinish/{planId}/{userId}") - public void apiExecuteFinish(@PathVariable String planId, @PathVariable String userId) { - String reportId = UUID.randomUUID().toString(); - TestPlanReportSaveRequest saveRequest = new TestPlanReportSaveRequest(reportId, planId, userId, ReportTriggerMode.API.name()); - TestPlanScheduleReportInfoDTO report = testPlanReportService.genTestPlanReport(saveRequest); - testPlanReportService.countReportByTestPlanReportId(report.getTestPlanReport().getId(), null, ReportTriggerMode.API.name()); - } - @GetMapping("/saveTestPlanReport/{planId}/{triggerMode}") public String saveTestPlanReport(@PathVariable String planId, @PathVariable String triggerMode) { String userId = SessionUtils.getUser().getId(); diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanMessageService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanMessageService.java new file mode 100644 index 0000000000..dc2d6f36dd --- /dev/null +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanMessageService.java @@ -0,0 +1,125 @@ +package io.metersphere.track.service; + +import io.metersphere.api.service.ShareInfoService; +import io.metersphere.base.domain.TestPlan; +import io.metersphere.base.domain.TestPlanReport; +import io.metersphere.commons.constants.NoticeConstants; +import io.metersphere.commons.constants.ReportTriggerMode; +import io.metersphere.commons.constants.TestPlanReportStatus; +import io.metersphere.commons.utils.BeanUtils; +import io.metersphere.commons.utils.CommonBeanFactory; +import io.metersphere.dto.BaseSystemConfigDTO; +import io.metersphere.dto.UserDTO; +import io.metersphere.i18n.Translator; +import io.metersphere.notice.sender.NoticeModel; +import io.metersphere.notice.service.NoticeSendService; +import io.metersphere.service.ProjectService; +import io.metersphere.service.SystemParameterService; +import io.metersphere.service.UserService; +import io.metersphere.track.dto.TestPlanDTOWithMetric; +import org.apache.commons.beanutils.BeanMap; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +@Service +@Transactional +public class TestPlanMessageService { + @Resource + private ProjectService projectService; + @Lazy + @Resource + private TestPlanService testPlanService; + @Resource + private UserService userService; + @Resource + private ShareInfoService shareInfoService; + + @Async + public void sendMessage(TestPlan testPlan, TestPlanReport testPlanReport, String projectId) { + assert testPlan != null; + SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class); + NoticeSendService noticeSendService = CommonBeanFactory.getBean(NoticeSendService.class); + assert systemParameterService != null; + assert noticeSendService != null; + BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo(); + String url = baseSystemConfigDTO.getUrl() + "/#/track/testPlan/reportList"; + String subject = ""; + String successContext = "${operator}执行的 ${name} 测试计划运行成功, 报告: ${planShareUrl}"; + String failedContext = "${operator}执行的 ${name} 测试计划运行失败, 报告: ${planShareUrl}"; + String context = "${operator}完成了测试计划: ${name}, 报告: ${planShareUrl}"; + if (StringUtils.equals(testPlanReport.getTriggerMode(), ReportTriggerMode.API.name())) { + subject = Translator.get("task_notification_jenkins"); + } else { + subject = Translator.get("task_notification"); + } + // 计算通过率 + TestPlanDTOWithMetric testPlanDTOWithMetric = BeanUtils.copyBean(new TestPlanDTOWithMetric(), testPlan); + testPlanService.calcTestPlanRate(Collections.singletonList(testPlanDTOWithMetric)); + + String creator = testPlanReport.getCreator(); + UserDTO userDTO = userService.getUserDTO(creator); + + Map paramMap = new HashMap(); + paramMap.put("type", "testPlan"); + paramMap.put("url", url); + paramMap.put("projectId", projectId); + if (userDTO != null) { + paramMap.put("operator", userDTO.getName()); + } + paramMap.putAll(new BeanMap(testPlanDTOWithMetric)); + + String successfulMailTemplate = "TestPlanSuccessfulNotification"; + String errfoMailTemplate = "TestPlanFailedNotification"; + + String testPlanShareUrl = shareInfoService.getTestPlanShareUrl(testPlanReport.getId(), creator); + paramMap.put("planShareUrl", baseSystemConfigDTO.getUrl() + "/sharePlanReport" + testPlanShareUrl); + + /** + * 测试计划的消息通知配置包括 完成、成功、失败 + * 所以发送通知时必定会有"完成"状态的通知 + */ + Map execStatusEventMap = new HashMap<>(); + execStatusEventMap.put(TestPlanReportStatus.COMPLETED.name(), NoticeConstants.Event.COMPLETE); + if (StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.SUCCESS.name())) { + execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.EXECUTE_SUCCESSFUL); + } else if (StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.FAILED.name())) { + execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.EXECUTE_FAILED); + } else if (!StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name())) { + execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.COMPLETE); + } + for (Map.Entry entry : execStatusEventMap.entrySet()) { + String status = entry.getKey(); + String event = entry.getValue(); + NoticeModel noticeModel = NoticeModel.builder() + .operator(creator) + .context(context) + .successContext(successContext) + .successMailTemplate(successfulMailTemplate) + .failedContext(failedContext) + .failedMailTemplate(errfoMailTemplate) + .mailTemplate("track/TestPlanComplete") + .testId(testPlan.getId()) + .status(status) + .event(event) + .subject(subject) + .paramMap(paramMap) + .build(); + + if (StringUtils.equals(testPlanReport.getTriggerMode(), ReportTriggerMode.MANUAL.name())) { + noticeSendService.send(projectService.getProjectById(projectId), NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); + } + + if (StringUtils.equalsAny(testPlanReport.getTriggerMode(), ReportTriggerMode.SCHEDULE.name(), ReportTriggerMode.API.name())) { + noticeSendService.send(testPlanReport.getTriggerMode(), NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); + } + } + } +} diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java index 5863f68bf8..3092a0461f 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanReportService.java @@ -102,6 +102,8 @@ public class TestPlanReportService { private ApiScenarioReportService apiScenarioReportService; @Resource private TestPlanExecutionQueueMapper testPlanExecutionQueueMapper; + @Resource + private TestPlanMessageService testPlanMessageService; public List list(QueryTestPlanReportRequest request) { List list = new ArrayList<>(); @@ -418,12 +420,6 @@ public class TestPlanReportService { return principalName; } - public void updateReport(List testPlanReportIdList, String runMode, String triggerMode) { - for (String planReportId : testPlanReportIdList) { - this.countReportByTestPlanReportId(planReportId, runMode, triggerMode); - } - } - public TestPlanReportContentWithBLOBs updateReport(TestPlanReport testPlanReport, TestPlanReportContentWithBLOBs reportContent) { if (testPlanReport == null) { return null; @@ -441,6 +437,10 @@ public class TestPlanReportService { return testPlanReport; } if (testPlanReport != null) { + boolean isSendMessage = false; + if(StringUtils.equalsIgnoreCase(testPlanReport.getStatus(),ExecuteResult.RUNNING.name())){ + isSendMessage = true; + } //初始化测试计划包含组件信息 int[] componentIndexArr = new int[]{1, 3, 4}; testPlanReport.setComponents(JSONArray.toJSONString(componentIndexArr)); @@ -494,7 +494,7 @@ public class TestPlanReportService { } content.setPlanApiCaseReportStruct(JSONObject.toJSONString(apiTestCases)); } catch (Exception e) { - LogUtil.error("update test plan api error! ", e.getMessage()); + LogUtil.error("update test plan api error! ", e); } } if (StringUtils.isNotEmpty(content.getPlanScenarioReportStruct())) { @@ -529,7 +529,7 @@ public class TestPlanReportService { } content.setPlanScenarioReportStruct(JSONObject.toJSONString(scenarioCases)); } catch (Exception e) { - LogUtil.error("update test plan api error! ", e.getMessage()); + LogUtil.error("update test plan api error! ", e); } } //更新content表对结束日期 @@ -551,7 +551,7 @@ public class TestPlanReportService { testPlanReport.setIsApiCaseExecuting(false); testPlanReport.setIsScenarioExecuting(false); testPlanReport.setIsPerformanceExecuting(false); - testPlanReport = this.update(testPlanReport); + TestPlanExecutionQueueExample testPlanExecutionQueueExample = new TestPlanExecutionQueueExample(); testPlanExecutionQueueExample.createCriteria().andReportIdEqualTo(testPlanReportId); List planExecutionQueues = testPlanExecutionQueueMapper.selectByExample(testPlanExecutionQueueExample); @@ -577,6 +577,9 @@ public class TestPlanReportService { runRequest.setReportId(testPlanExecutionQueue.getReportId()); testPlanService.runPlan(runRequest); } + testPlanReportMapper.updateByPrimaryKey(testPlanReport); + //发送通知 + this.checkTestPlanStatusAndSendMessage(testPlanReport, isSendMessage); } return testPlanReport; } @@ -633,7 +636,8 @@ public class TestPlanReportService { String testPlanStatus = this.getTestPlanReportStatus(testPlanReport, reportDTO); testPlanReport.setStatus(testPlanStatus); - this.update(testPlanReport); + testPlanReportMapper.updateByPrimaryKey(testPlanReport); + this.checkTestPlanStatusAndSendMessage(testPlanReport, false); } public TestPlanReportContentWithBLOBs parseReportDaoToReportContent(TestPlanSimpleReportDTO reportDTO, TestPlanReportContentWithBLOBs testPlanReportContentWithBLOBs) { @@ -737,113 +741,25 @@ public class TestPlanReportService { return status; } - public TestPlanReport update(TestPlanReport report) { - testPlanReportMapper.updateByPrimaryKey(report); + public void checkTestPlanStatusAndSendMessage(TestPlanReport report, boolean sendMessage) { if (!report.getIsApiCaseExecuting() && !report.getIsPerformanceExecuting() && !report.getIsScenarioExecuting()) { + //更新TestPlan状态为完成 + TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(report.getTestPlanId()); + if (testPlan != null && !StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) { + testPlan.setStatus(TestPlanStatus.Completed.name()); + testPlanService.editTestPlan(testPlan); + } try { - //更新TestPlan状态为完成 - TestPlanWithBLOBs testPlan = testPlanMapper.selectByPrimaryKey(report.getTestPlanId()); - if (testPlan != null && !StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) { - testPlan.setStatus(TestPlanStatus.Completed.name()); - testPlanService.editTestPlan(testPlan); - } - if (testPlan != null && StringUtils.equalsAny(report.getTriggerMode(), + if (sendMessage && testPlan != null && StringUtils.equalsAny(report.getTriggerMode(), ReportTriggerMode.MANUAL.name(), ReportTriggerMode.API.name(), ReportTriggerMode.SCHEDULE.name()) && !StringUtils.equalsIgnoreCase(report.getStatus(), ExecuteResult.RUNNING.name()) ) { - try { - //发送通知 - sendMessage(report, testPlan.getProjectId()); - } catch (Exception e) { - LogUtil.error("Send message error: " + e.getMessage()); - } - + //发送通知 + testPlanMessageService.sendMessage(testPlan, report, testPlan.getProjectId()); } } catch (Exception e) { - LogUtil.error(e.getMessage()); - } - } - return report; - } - - public void sendMessage(TestPlanReport testPlanReport, String projectId) { - TestPlan testPlan = testPlanMapper.selectByPrimaryKey(testPlanReport.getTestPlanId()); - assert testPlan != null; - SystemParameterService systemParameterService = CommonBeanFactory.getBean(SystemParameterService.class); - NoticeSendService noticeSendService = CommonBeanFactory.getBean(NoticeSendService.class); - assert systemParameterService != null; - assert noticeSendService != null; - BaseSystemConfigDTO baseSystemConfigDTO = systemParameterService.getBaseInfo(); - String url = baseSystemConfigDTO.getUrl() + "/#/track/testPlan/reportList"; - String subject = ""; - String successContext = "${operator}执行的 ${name} 测试计划运行成功, 报告: ${planShareUrl}"; - String failedContext = "${operator}执行的 ${name} 测试计划运行失败, 报告: ${planShareUrl}"; - String context = "${operator}完成了测试计划: ${name}, 报告: ${planShareUrl}"; - if (StringUtils.equals(testPlanReport.getTriggerMode(), ReportTriggerMode.API.name())) { - subject = Translator.get("task_notification_jenkins"); - } else { - subject = Translator.get("task_notification"); - } - // 计算通过率 - TestPlanDTOWithMetric testPlanDTOWithMetric = BeanUtils.copyBean(new TestPlanDTOWithMetric(), testPlan); - testPlanService.calcTestPlanRate(Collections.singletonList(testPlanDTOWithMetric)); - - String creator = testPlanReport.getCreator(); - UserDTO userDTO = userService.getUserDTO(creator); - - Map paramMap = new HashMap(); - paramMap.put("type", "testPlan"); - paramMap.put("url", url); - paramMap.put("projectId", projectId); - if (userDTO != null) { - paramMap.put("operator", userDTO.getName()); - } - paramMap.putAll(new BeanMap(testPlanDTOWithMetric)); - - String successfulMailTemplate = "TestPlanSuccessfulNotification"; - String errfoMailTemplate = "TestPlanFailedNotification"; - - String testPlanShareUrl = shareInfoService.getTestPlanShareUrl(testPlanReport.getId(), creator); - paramMap.put("planShareUrl", baseSystemConfigDTO.getUrl() + "/sharePlanReport" + testPlanShareUrl); - - /** - * 测试计划的消息通知配置包括 完成、成功、失败 - * 所以发送通知时必定会有"完成"状态的通知 - */ - Map execStatusEventMap = new HashMap<>(); - execStatusEventMap.put(TestPlanReportStatus.COMPLETED.name(), NoticeConstants.Event.COMPLETE); - if (StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.SUCCESS.name())) { - execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.EXECUTE_SUCCESSFUL); - } else if (StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.FAILED.name())) { - execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.EXECUTE_FAILED); - } else if (!StringUtils.equalsIgnoreCase(testPlanReport.getStatus(), TestPlanReportStatus.COMPLETED.name())) { - execStatusEventMap.put(testPlanReport.getStatus(), NoticeConstants.Event.COMPLETE); - } - for (Map.Entry entry : execStatusEventMap.entrySet()) { - String status = entry.getKey(); - String event = entry.getValue(); - NoticeModel noticeModel = NoticeModel.builder() - .operator(creator) - .context(context) - .successContext(successContext) - .successMailTemplate(successfulMailTemplate) - .failedContext(failedContext) - .failedMailTemplate(errfoMailTemplate) - .mailTemplate("track/TestPlanComplete") - .testId(testPlan.getId()) - .status(status) - .event(event) - .subject(subject) - .paramMap(paramMap) - .build(); - - if (StringUtils.equals(testPlanReport.getTriggerMode(), ReportTriggerMode.MANUAL.name())) { - noticeSendService.send(projectService.getProjectById(projectId), NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); - } - - if (StringUtils.equalsAny(testPlanReport.getTriggerMode(), ReportTriggerMode.SCHEDULE.name(), ReportTriggerMode.API.name())) { - noticeSendService.send(testPlanReport.getTriggerMode(), NoticeConstants.TaskType.TEST_PLAN_TASK, noticeModel); + LogUtil.error(e); } } }