diff options
author | Fabrice Bellingard <fabrice.bellingard@sonarsource.com> | 2013-01-24 16:07:51 +0100 |
---|---|---|
committer | Fabrice Bellingard <fabrice.bellingard@sonarsource.com> | 2013-01-24 16:08:35 +0100 |
commit | 30d668f520e3972de197ab1c8f5bfd4972a481b1 (patch) | |
tree | cfe84ec7f16908313b3635182a59668eaaf20362 /plugins | |
parent | aac947247b9e0754d4c52344fc2efc00cf40138f (diff) | |
download | sonarqube-30d668f520e3972de197ab1c8f5bfd4972a481b1.tar.gz sonarqube-30d668f520e3972de197ab1c8f5bfd4972a481b1.zip |
SONAR-2746 Email new alerts on favorite projects
Diffstat (limited to 'plugins')
8 files changed, 464 insertions, 13 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/GenerateAlertEvents.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/GenerateAlertEvents.java index 4abe16d4262..3e4d6150920 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/GenerateAlertEvents.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/GenerateAlertEvents.java @@ -19,10 +19,18 @@ */ package org.sonar.plugins.core.sensors; -import org.sonar.api.batch.*; +import org.sonar.api.batch.Decorator; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.DependsUpon; +import org.sonar.api.batch.Event; +import org.sonar.api.batch.TimeMachine; +import org.sonar.api.batch.TimeMachineQuery; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; +import org.sonar.api.measures.Metric.Level; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationManager; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; @@ -34,17 +42,18 @@ public class GenerateAlertEvents implements Decorator { private final RulesProfile profile; private final TimeMachine timeMachine; + private NotificationManager notificationManager; - public GenerateAlertEvents(RulesProfile profile, TimeMachine timeMachine) { + public GenerateAlertEvents(RulesProfile profile, TimeMachine timeMachine, NotificationManager notificationManager) { this.profile = profile; this.timeMachine = timeMachine; + this.notificationManager = notificationManager; } public boolean shouldExecuteOnProject(Project project) { return profile != null && profile.getAlerts() != null && profile.getAlerts().size() > 0; } - @DependsUpon public Metric dependsUponAlertStatus() { return CoreMetrics.ALERT_STATUS; @@ -63,15 +72,41 @@ public class GenerateAlertEvents implements Decorator { List<Measure> measures = timeMachine.getMeasures(query); Measure pastStatus = (measures != null && measures.size() == 1 ? measures.get(0) : null); - if (pastStatus != null && pastStatus.getDataAsLevel() != currentStatus.getDataAsLevel()) { - createEvent(context, getName(pastStatus, currentStatus), currentStatus.getAlertText()); - - } else if (pastStatus == null && currentStatus.getDataAsLevel() != Metric.Level.OK) { - createEvent(context, getName(currentStatus), currentStatus.getAlertText()); + String alertText = currentStatus.getAlertText(); + Level alertLevel = currentStatus.getDataAsLevel(); + String alertName = null; + boolean isNewAlert = true; + if (pastStatus != null && pastStatus.getDataAsLevel() != alertLevel) { + // The alert status has changed + alertName = getName(pastStatus, currentStatus); + if (pastStatus.getDataAsLevel() != Metric.Level.OK) { + // There was already a Orange/Red alert, so this is no new alert: it has just changed + isNewAlert = false; + } + createEvent(context, alertName, alertText); + notifyUsers(resource, alertName, alertText, alertLevel, isNewAlert); + + } else if (pastStatus == null && alertLevel != Metric.Level.OK) { + // There were no defined alerts before, so this one is a new one + alertName = getName(currentStatus); + createEvent(context, alertName, alertText); + notifyUsers(resource, alertName, alertText, alertLevel, isNewAlert); } } + protected void notifyUsers(Resource<?> resource, String alertName, String alertText, Level alertLevel, boolean isNewAlert) { + Notification notification = new Notification("alerts") + .setFieldValue("projectName", resource.getLongName()) + .setFieldValue("projectKey", resource.getKey()) + .setFieldValue("projectId", String.valueOf(resource.getId())) + .setFieldValue("alertName", alertName) + .setFieldValue("alertText", alertText) + .setFieldValue("alertLevel", alertLevel.toString()) + .setFieldValue("isNewAlert", Boolean.toString(isNewAlert)); + notificationManager.scheduleForSending(notification); + } + private boolean shouldDecorateResource(Resource resource) { return ResourceUtils.isRootProject(resource); } diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index a84bef09098..ba45487df1e 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -1495,6 +1495,7 @@ server_id_configuration.generation_error=Organisation and/or IP address are not notification.channel.EmailNotificationChannel=Email notification.dispatcher.ChangesInReviewAssignedToMeOrCreatedByMe=Changes in review assigned to me or created by me notification.dispatcher.NewViolationsOnMyFavouriteProject=New violations on my favourite projects introduced during the first differential view period +notification.dispatcher.AlertsOnMyFavouriteProject=Alerts on my favourite projects #------------------------------------------------------------------------------ diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/GenerateAlertEventsTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/GenerateAlertEventsTest.java index ddbd9cc18e4..994bb282a70 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/GenerateAlertEventsTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/GenerateAlertEventsTest.java @@ -28,21 +28,27 @@ import org.sonar.api.batch.TimeMachineQuery; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationManager; import org.sonar.api.profiles.Alert; import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.test.ProjectTestBuilder; import java.util.Arrays; import java.util.Date; +import static org.fest.assertions.Assertions.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,6 +57,7 @@ public class GenerateAlertEventsTest { private DecoratorContext context; private RulesProfile profile; private TimeMachine timeMachine; + private NotificationManager notificationManager; private Project project; @Before @@ -58,12 +65,18 @@ public class GenerateAlertEventsTest { context = mock(DecoratorContext.class); timeMachine = mock(TimeMachine.class); profile = mock(RulesProfile.class); - decorator = new GenerateAlertEvents(profile, timeMachine); + notificationManager = mock(NotificationManager.class); + decorator = new GenerateAlertEvents(profile, timeMachine, notificationManager); project = new ProjectTestBuilder().build(); } @Test - public void doNotDecorateIfNoThresholds() { + public void shouldDependUponAlertStatus() { + assertThat(decorator.dependsUponAlertStatus()).isEqualTo(CoreMetrics.ALERT_STATUS); + } + + @Test + public void shouldNotDecorateIfNoThresholds() { assertThat(decorator.shouldExecuteOnProject(project), is(false)); } @@ -74,17 +87,29 @@ public class GenerateAlertEventsTest { } @Test + public void shouldNotDecorateIfNotRootProject() { + decorator.decorate(new File("Foo"), context); + verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + } + + @Test public void shouldCreateEventWhenNewErrorAlert() { when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); + decorator.decorate(project, context); + verify(context).createEvent(Metric.Level.ERROR.getColorName(), "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Red", "desc", "ERROR", "true"); } @Test public void shouldCreateEventWhenNewWarnAlert() { when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.WARN, "desc")); + decorator.decorate(project, context); + verify(context).createEvent(Metric.Level.WARN.getColorName(), "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Orange", "desc", "WARN", "true"); } @Test @@ -95,6 +120,7 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context).createEvent("Red (was Orange)", "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Red (was Orange)", "desc", "ERROR", "false"); } @Test @@ -105,6 +131,18 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context).createEvent("Green (was Red)", null, Event.CATEGORY_ALERT, null); + verifyNotificationSent("Green (was Red)", null, "OK", "false"); + } + + @Test + public void shouldCreateEventWhenOkToError() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.OK, null))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); + + decorator.decorate(project, context); + + verify(context).createEvent("Red (was Green)", "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Red (was Green)", "desc", "ERROR", "true"); } @Test @@ -115,6 +153,7 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context).createEvent("Orange (was Red)", "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Orange (was Red)", "desc", "WARN", "false"); } @Test @@ -122,6 +161,7 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + verify(notificationManager, never()).scheduleForSending(any(Notification.class)); } @Test @@ -132,6 +172,7 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + verify(notificationManager, never()).scheduleForSending(any(Notification.class)); } @Test @@ -142,6 +183,7 @@ public class GenerateAlertEventsTest { decorator.decorate(project, context); verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + verify(notificationManager, never()).scheduleForSending(any(Notification.class)); } private Measure newAlertStatus(Metric.Level level, String label) { @@ -150,4 +192,16 @@ public class GenerateAlertEventsTest { measure.setAlertText(label); return measure; } + + private void verifyNotificationSent(String alertName, String alertText, String alertLevel, String isNewAlert) { + Notification notification = new Notification("alerts") + .setFieldValue("projectName", project.getLongName()) + .setFieldValue("projectKey", project.getKey()) + .setFieldValue("projectId", String.valueOf(project.getId())) + .setFieldValue("alertName", alertName) + .setFieldValue("alertText", alertText) + .setFieldValue("alertLevel", alertLevel) + .setFieldValue("isNewAlert", isNewAlert); + verify(notificationManager, times(1)).scheduleForSending(eq(notification)); + } } diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java index bf46289eb47..61051c38e10 100644 --- a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/EmailNotificationsPlugin.java @@ -22,6 +22,8 @@ package org.sonar.plugins.emailnotifications; import com.google.common.collect.ImmutableList; import org.sonar.api.ServerExtension; import org.sonar.api.SonarPlugin; +import org.sonar.plugins.emailnotifications.alerts.AlertsEmailTemplate; +import org.sonar.plugins.emailnotifications.alerts.AlertsOnMyFavouriteProject; import org.sonar.plugins.emailnotifications.newviolations.NewViolationsEmailTemplate; import org.sonar.plugins.emailnotifications.newviolations.NewViolationsOnMyFavouriteProject; import org.sonar.plugins.emailnotifications.reviews.ChangesInReviewAssignedToMeOrCreatedByMe; @@ -32,10 +34,16 @@ import java.util.List; public class EmailNotificationsPlugin extends SonarPlugin { public List<Class<? extends ServerExtension>> getExtensions() { return ImmutableList.of( - ChangesInReviewAssignedToMeOrCreatedByMe.class, EmailNotificationChannel.class, - NewViolationsEmailTemplate.class, + // Notify incoming violations on my favourite projects NewViolationsOnMyFavouriteProject.class, - ReviewEmailTemplate.class); + NewViolationsEmailTemplate.class, + // Notify reviews changes + ChangesInReviewAssignedToMeOrCreatedByMe.class, + ReviewEmailTemplate.class, + // Notify alerts on my favourite projects + AlertsOnMyFavouriteProject.class, + AlertsEmailTemplate.class + ); } } diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplate.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplate.java new file mode 100644 index 00000000000..96d96cb3ad7 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplate.java @@ -0,0 +1,107 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.alerts; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.config.EmailSettings; +import org.sonar.api.measures.Metric; +import org.sonar.api.notifications.Notification; +import org.sonar.plugins.emailnotifications.api.EmailMessage; +import org.sonar.plugins.emailnotifications.api.EmailTemplate; + +/** + * Creates email message for notification "alerts". + * + * @since 3.5 + */ +public class AlertsEmailTemplate extends EmailTemplate { + + private EmailSettings configuration; + + public AlertsEmailTemplate(EmailSettings configuration) { + this.configuration = configuration; + } + + @Override + public EmailMessage format(Notification notification) { + if (!"alerts".equals(notification.getType())) { + return null; + } + + // Retrieve useful values + String projectId = notification.getFieldValue("projectId"); + String projectKey = notification.getFieldValue("projectKey"); + String projectName = notification.getFieldValue("projectName"); + String alertName = notification.getFieldValue("alertName"); + String alertText = notification.getFieldValue("alertText"); + String alertLevel = notification.getFieldValue("alertLevel"); + boolean isNewAlert = Boolean.valueOf(notification.getFieldValue("isNewAlert")); + + // Generate text + String subject = generateSubject(projectName, alertLevel, isNewAlert); + String messageBody = generateMessageBody(projectName, projectKey, alertName, alertText, isNewAlert); + + // And finally return the email that will be sent + return new EmailMessage() + .setMessageId("alerts/" + projectId) + .setSubject(subject) + .setMessage(messageBody); + } + + private String generateSubject(String projectName, String alertLevel, boolean isNewAlert) { + StringBuilder subjectBuilder = new StringBuilder(); + if (Metric.Level.OK.toString().equals(alertLevel)) { + subjectBuilder.append("\"").append(projectName).append("\" is back to green"); + } else if (isNewAlert) { + subjectBuilder.append("New alert on \"").append(projectName).append("\""); + } else { + subjectBuilder.append("Alert level changed on \"").append(projectName).append("\""); + } + return subjectBuilder.toString(); + } + + private String generateMessageBody(String projectName, String projectKey, String alertName, String alertText, boolean isNewAlert) { + StringBuilder messageBody = new StringBuilder(); + messageBody.append("Project: ").append(projectName).append("\n"); + messageBody.append("Alert level: ").append(alertName).append("\n\n"); + + String[] alerts = StringUtils.split(alertText, ","); + if (alerts.length > 0) { + if (isNewAlert) { + messageBody.append("New alert"); + } else { + messageBody.append("Alert"); + } + if (alerts.length == 1) { + messageBody.append(": ").append(alerts[0].trim()).append("\n"); + } else { + messageBody.append("s:\n"); + for (String alert : alerts) { + messageBody.append(" - ").append(alert.trim()).append("\n"); + } + } + } + + messageBody.append("\n").append("See it in Sonar: ").append(configuration.getServerBaseURL()).append("/dashboard/index/").append(projectKey); + + return messageBody.toString(); + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProject.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProject.java new file mode 100644 index 00000000000..38a46a6ca49 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProject.java @@ -0,0 +1,53 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.alerts; + +import org.apache.commons.lang.StringUtils; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; +import org.sonar.core.properties.PropertiesDao; + +import java.util.List; + +/** + * This dispatcher means: "notify me when alerts are raised on projects that I flagged as favourite". + * + * @since 3.5 + */ +public class AlertsOnMyFavouriteProject extends NotificationDispatcher { + + private PropertiesDao propertiesDao; + + public AlertsOnMyFavouriteProject(PropertiesDao propertiesDao) { + this.propertiesDao = propertiesDao; + } + + @Override + public void dispatch(Notification notification, Context context) { + if (StringUtils.equals(notification.getType(), "alerts")) { + Long projectId = Long.parseLong(notification.getFieldValue("projectId")); + List<String> userLogins = propertiesDao.findUserIdsForFavouriteResource(projectId); + for (String userLogin : userLogins) { + context.addUser(userLogin); + } + } + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplateTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplateTest.java new file mode 100644 index 00000000000..1a68497f1c9 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsEmailTemplateTest.java @@ -0,0 +1,131 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.alerts; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.config.EmailSettings; +import org.sonar.api.notifications.Notification; +import org.sonar.plugins.emailnotifications.api.EmailMessage; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class AlertsEmailTemplateTest { + + private AlertsEmailTemplate template; + + @Before + public void setUp() { + EmailSettings configuration = mock(EmailSettings.class); + when(configuration.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org"); + template = new AlertsEmailTemplate(configuration); + } + + @Test + public void shouldNotFormatIfNotCorrectNotification() { + Notification notification = new Notification("other-notif"); + EmailMessage message = template.format(notification); + assertThat(message, nullValue()); + } + + @Test + public void shouldFormatAlertWithSeveralMessages() { + Notification notification = createNotification("Orange (was Red)", "violations > 4, coverage < 75%", "WARN", "false"); + + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("alerts/45")); + assertThat(message.getSubject(), is("Alert level changed on \"Foo\"")); + assertThat(message.getMessage(), is("" + + "Project: Foo\n" + + "Alert level: Orange (was Red)\n" + + "\n" + + "Alerts:\n" + + " - violations > 4\n" + + " - coverage < 75%\n" + + "\n" + + "See it in Sonar: http://nemo.sonarsource.org/dashboard/index/org.sonar.foo:foo")); + } + + @Test + public void shouldFormatNewAlertWithSeveralMessages() { + Notification notification = createNotification("Orange (was Red)", "violations > 4, coverage < 75%", "WARN", "true"); + + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("alerts/45")); + assertThat(message.getSubject(), is("New alert on \"Foo\"")); + assertThat(message.getMessage(), is("" + + "Project: Foo\n" + + "Alert level: Orange (was Red)\n" + + "\n" + + "New alerts:\n" + + " - violations > 4\n" + + " - coverage < 75%\n" + + "\n" + + "See it in Sonar: http://nemo.sonarsource.org/dashboard/index/org.sonar.foo:foo")); + } + + @Test + public void shouldFormatNewAlertWithOneMessage() { + Notification notification = createNotification("Orange (was Red)", "violations > 4", "WARN", "true"); + + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("alerts/45")); + assertThat(message.getSubject(), is("New alert on \"Foo\"")); + assertThat(message.getMessage(), is("" + + "Project: Foo\n" + + "Alert level: Orange (was Red)\n" + + "\n" + + "New alert: violations > 4\n" + + "\n" + + "See it in Sonar: http://nemo.sonarsource.org/dashboard/index/org.sonar.foo:foo")); + } + + @Test + public void shouldFormatBackToGreenMessage() { + Notification notification = createNotification("Green (was Red)", "", "OK", "false"); + + EmailMessage message = template.format(notification); + assertThat(message.getMessageId(), is("alerts/45")); + assertThat(message.getSubject(), is("\"Foo\" is back to green")); + assertThat(message.getMessage(), is("" + + "Project: Foo\n" + + "Alert level: Green (was Red)\n" + + "\n" + + "\n" + + "See it in Sonar: http://nemo.sonarsource.org/dashboard/index/org.sonar.foo:foo")); + } + + private Notification createNotification(String alertName, String alertText, String alertLevel, String isNewAlert) { + Notification notification = new Notification("alerts") + .setFieldValue("projectName", "Foo") + .setFieldValue("projectKey", "org.sonar.foo:foo") + .setFieldValue("projectId", "45") + .setFieldValue("alertName", alertName) + .setFieldValue("alertText", alertText) + .setFieldValue("alertLevel", alertLevel) + .setFieldValue("isNewAlert", isNewAlert); + return notification; + } + +} diff --git a/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProjectTest.java b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProjectTest.java new file mode 100644 index 00000000000..fe29748d332 --- /dev/null +++ b/plugins/sonar-email-notifications-plugin/src/test/java/org/sonar/plugins/emailnotifications/alerts/AlertsOnMyFavouriteProjectTest.java @@ -0,0 +1,62 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2012 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * Sonar is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.plugins.emailnotifications.alerts; + +import com.google.common.collect.Lists; +import org.junit.Test; +import org.sonar.api.notifications.Notification; +import org.sonar.api.notifications.NotificationDispatcher; +import org.sonar.core.properties.PropertiesDao; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +public class AlertsOnMyFavouriteProjectTest { + + @Test + public void shouldNotDispatchIfNotNewViolationsNotification() throws Exception { + NotificationDispatcher.Context context = mock(NotificationDispatcher.Context.class); + AlertsOnMyFavouriteProject dispatcher = new AlertsOnMyFavouriteProject(null); + Notification notification = new Notification("other-notif"); + dispatcher.dispatch(notification, context); + + verify(context, never()).addUser(any(String.class)); + } + + @Test + public void shouldDispatchToUsersWhoHaveFlaggedProjectAsFavourite() { + NotificationDispatcher.Context context = mock(NotificationDispatcher.Context.class); + PropertiesDao propertiesDao = mock(PropertiesDao.class); + when(propertiesDao.findUserIdsForFavouriteResource(34L)).thenReturn(Lists.newArrayList("user1", "user2")); + AlertsOnMyFavouriteProject dispatcher = new AlertsOnMyFavouriteProject(propertiesDao); + + Notification notification = new Notification("alerts").setFieldValue("projectId", "34"); + dispatcher.dispatch(notification, context); + + verify(context).addUser("user1"); + verify(context).addUser("user2"); + verifyNoMoreInteractions(context); + } + +} |