From: Jean-Baptiste Lievremont Date: Thu, 20 Mar 2014 11:34:40 +0000 (+0100) Subject: SONAR-4366 Move a core plugin component to batch (remove server dependency on batch... X-Git-Tag: 4.3~342 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=77e103ed19bd216665ad3804c49bd483306b6a21;p=sonarqube.git SONAR-4366 Move a core plugin component to batch (remove server dependency on batch component) --- diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 3b4d49268d3..463c7cc3243 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -19,6 +19,8 @@ */ package org.sonar.plugins.core; +import org.sonar.batch.qualitygate.GenerateQualityGateEvents; + import com.google.common.collect.ImmutableList; import org.sonar.api.*; import org.sonar.api.checks.NoSonarFilter; @@ -300,7 +302,6 @@ public final class CorePlugin extends SonarPlugin { ProjectLinksSensor.class, UnitTestDecorator.class, VersionEventsSensor.class, - GenerateAlertEvents.class, LineCoverageDecorator.class, CoverageDecorator.class, BranchCoverageDecorator.class, 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 deleted file mode 100644 index 4d6a8550dbe..00000000000 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/GenerateAlertEvents.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.core.sensors; - -import org.sonar.api.batch.*; -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; -import org.sonar.api.resources.ResourceUtils; -import org.sonar.batch.qualitygate.QualityGate; - -import java.util.List; - -public class GenerateAlertEvents implements Decorator { - - private final QualityGate qualityGate; - private final TimeMachine timeMachine; - private NotificationManager notificationManager; - - public GenerateAlertEvents(QualityGate qualityGate, TimeMachine timeMachine, NotificationManager notificationManager) { - this.qualityGate = qualityGate; - this.timeMachine = timeMachine; - this.notificationManager = notificationManager; - } - - public boolean shouldExecuteOnProject(Project project) { - return qualityGate.isEnabled(); - } - - @DependsUpon - public Metric dependsUponAlertStatus() { - return CoreMetrics.ALERT_STATUS; - } - - public void decorate(Resource resource, DecoratorContext context) { - if (!shouldDecorateResource(resource)) { - return; - } - Measure currentStatus = context.getMeasure(CoreMetrics.ALERT_STATUS); - if (currentStatus == null) { - return; - } - - TimeMachineQuery query = new TimeMachineQuery(resource).setOnlyLastAnalysis(true).setMetrics(CoreMetrics.ALERT_STATUS); - List measures = timeMachine.getMeasures(query); - - Measure pastStatus = measures != null && measures.size() == 1 ? measures.get(0) : null; - 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") - .setDefaultMessage("Alert on " + resource.getLongName() + ": " + alertName) - .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); - } - - private String getName(Measure pastStatus, Measure currentStatus) { - return getName(currentStatus) + " (was " + getName(pastStatus) + ")"; - - } - - private String getName(Measure currentStatus) { - return currentStatus.getDataAsLevel().getColorName(); - } - - private void createEvent(DecoratorContext context, String name, String description) { - context.createEvent(name, description, Event.CATEGORY_ALERT, null); - } -} 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 deleted file mode 100644 index 8d6b8a10b22..00000000000 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/GenerateAlertEventsTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.core.sensors; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.batch.DecoratorContext; -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.notifications.Notification; -import org.sonar.api.notifications.NotificationManager; -import org.sonar.api.resources.File; -import org.sonar.api.resources.Project; -import org.sonar.api.test.ProjectTestBuilder; -import org.sonar.batch.qualitygate.QualityGate; - -import java.util.Arrays; -import java.util.Date; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.*; -import static org.mockito.Mockito.*; - -public class GenerateAlertEventsTest { - private GenerateAlertEvents decorator; - private DecoratorContext context; - private QualityGate qualityGate; - private TimeMachine timeMachine; - private NotificationManager notificationManager; - private Project project; - - @Before - public void setup() { - context = mock(DecoratorContext.class); - timeMachine = mock(TimeMachine.class); - qualityGate = mock(QualityGate.class); - notificationManager = mock(NotificationManager.class); - decorator = new GenerateAlertEvents(qualityGate, timeMachine, notificationManager); - project = new ProjectTestBuilder().build(); - } - - @Test - public void shouldDependUponAlertStatus() { - assertThat(decorator.dependsUponAlertStatus()).isEqualTo(CoreMetrics.ALERT_STATUS); - } - - @Test - public void shouldNotDecorateIfNoThresholds() { - assertThat(decorator.shouldExecuteOnProject(project)).isFalse(); - } - - @Test - public void shouldDecorateIfQualityGateEnabled() { - when(qualityGate.isEnabled()).thenReturn(true); - assertThat(decorator.shouldExecuteOnProject(project)).isTrue(); - } - - @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 - public void shouldCreateEventWhenWarnToError() { - when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.WARN, "desc"))); - when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); - - decorator.decorate(project, context); - - verify(context).createEvent("Red (was Orange)", "desc", Event.CATEGORY_ALERT, null); - verifyNotificationSent("Red (was Orange)", "desc", "ERROR", "false"); - } - - @Test - public void shouldCreateEventWhenErrorToOk() { - when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); - when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.OK, null)); - - 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 - public void shouldCreateEventWhenErrorToWarn() { - when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); - when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.WARN, "desc")); - - decorator.decorate(project, context); - - verify(context).createEvent("Orange (was Red)", "desc", Event.CATEGORY_ALERT, null); - verifyNotificationSent("Orange (was Red)", "desc", "WARN", "false"); - } - - @Test - public void shouldNotCreateEventWhenNoAlertStatus() { - decorator.decorate(project, context); - - verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); - verify(notificationManager, never()).scheduleForSending(any(Notification.class)); - } - - @Test - public void shouldNotCreateEventWhenSameLevel() { - when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); - when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); - - decorator.decorate(project, context); - - verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); - verify(notificationManager, never()).scheduleForSending(any(Notification.class)); - } - - @Test - public void shouldNotCreateEventIfNoMoreAlertStatus() { - when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); - when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(null); - - 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) { - Measure measure = new Measure(CoreMetrics.ALERT_STATUS, level); - measure.setAlertStatus(level); - measure.setAlertText(label); - return measure; - } - - private void verifyNotificationSent(String alertName, String alertText, String alertLevel, String isNewAlert) { - Notification notification = new Notification("alerts") - .setDefaultMessage("Alert on " + project.getLongName() + ": " + alertName) - .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/sonar-batch/src/main/java/org/sonar/batch/qualitygate/GenerateQualityGateEvents.java b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/GenerateQualityGateEvents.java new file mode 100644 index 00000000000..2d99ed9015f --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/qualitygate/GenerateQualityGateEvents.java @@ -0,0 +1,122 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.qualitygate; + +import org.sonar.api.batch.*; +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; +import org.sonar.api.resources.ResourceUtils; + +import java.util.List; + +public class GenerateQualityGateEvents implements Decorator { + + private final QualityGate qualityGate; + private final TimeMachine timeMachine; + private NotificationManager notificationManager; + + public GenerateQualityGateEvents(QualityGate qualityGate, TimeMachine timeMachine, NotificationManager notificationManager) { + this.qualityGate = qualityGate; + this.timeMachine = timeMachine; + this.notificationManager = notificationManager; + } + + public boolean shouldExecuteOnProject(Project project) { + return qualityGate.isEnabled(); + } + + @DependsUpon + public Metric dependsUponAlertStatus() { + return CoreMetrics.ALERT_STATUS; + } + + public void decorate(Resource resource, DecoratorContext context) { + if (!shouldDecorateResource(resource)) { + return; + } + Measure currentStatus = context.getMeasure(CoreMetrics.ALERT_STATUS); + if (currentStatus == null) { + return; + } + + TimeMachineQuery query = new TimeMachineQuery(resource).setOnlyLastAnalysis(true).setMetrics(CoreMetrics.ALERT_STATUS); + List measures = timeMachine.getMeasures(query); + + Measure pastStatus = measures != null && measures.size() == 1 ? measures.get(0) : null; + 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") + .setDefaultMessage("Alert on " + resource.getLongName() + ": " + alertName) + .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); + } + + private String getName(Measure pastStatus, Measure currentStatus) { + return getName(currentStatus) + " (was " + getName(pastStatus) + ")"; + + } + + private String getName(Measure currentStatus) { + return currentStatus.getDataAsLevel().getColorName(); + } + + private void createEvent(DecoratorContext context, String name, String description) { + context.createEvent(name, description, Event.CATEGORY_ALERT, null); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java index 73c2f6803bd..835aa9be91f 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java @@ -19,6 +19,8 @@ */ package org.sonar.batch.scan; +import org.sonar.batch.qualitygate.GenerateQualityGateEvents; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchExtension; @@ -125,6 +127,7 @@ public class ModuleScanContainer extends ComponentContainer { // quality gates new QualityGateProvider(), QualityGateVerifier.class, + GenerateQualityGateEvents.class, // rules ModuleQProfiles.class, diff --git a/sonar-batch/src/test/java/org/sonar/batch/qualitygate/GenerateQualityGateEventsTest.java b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/GenerateQualityGateEventsTest.java new file mode 100644 index 00000000000..edf86e96729 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/qualitygate/GenerateQualityGateEventsTest.java @@ -0,0 +1,200 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.qualitygate; + +import org.sonar.batch.qualitygate.GenerateQualityGateEvents; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.DecoratorContext; +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.notifications.Notification; +import org.sonar.api.notifications.NotificationManager; +import org.sonar.api.resources.File; +import org.sonar.api.resources.Project; +import org.sonar.api.test.ProjectTestBuilder; +import org.sonar.batch.qualitygate.QualityGate; + +import java.util.Arrays; +import java.util.Date; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +public class GenerateQualityGateEventsTest { + private GenerateQualityGateEvents decorator; + private DecoratorContext context; + private QualityGate qualityGate; + private TimeMachine timeMachine; + private NotificationManager notificationManager; + private Project project; + + @Before + public void setup() { + context = mock(DecoratorContext.class); + timeMachine = mock(TimeMachine.class); + qualityGate = mock(QualityGate.class); + notificationManager = mock(NotificationManager.class); + decorator = new GenerateQualityGateEvents(qualityGate, timeMachine, notificationManager); + project = new ProjectTestBuilder().build(); + } + + @Test + public void shouldDependUponAlertStatus() { + assertThat(decorator.dependsUponAlertStatus()).isEqualTo(CoreMetrics.ALERT_STATUS); + } + + @Test + public void shouldNotDecorateIfNoThresholds() { + assertThat(decorator.shouldExecuteOnProject(project)).isFalse(); + } + + @Test + public void shouldDecorateIfQualityGateEnabled() { + when(qualityGate.isEnabled()).thenReturn(true); + assertThat(decorator.shouldExecuteOnProject(project)).isTrue(); + } + + @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 + public void shouldCreateEventWhenWarnToError() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.WARN, "desc"))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); + + decorator.decorate(project, context); + + verify(context).createEvent("Red (was Orange)", "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Red (was Orange)", "desc", "ERROR", "false"); + } + + @Test + public void shouldCreateEventWhenErrorToOk() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.OK, null)); + + 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 + public void shouldCreateEventWhenErrorToWarn() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.WARN, "desc")); + + decorator.decorate(project, context); + + verify(context).createEvent("Orange (was Red)", "desc", Event.CATEGORY_ALERT, null); + verifyNotificationSent("Orange (was Red)", "desc", "WARN", "false"); + } + + @Test + public void shouldNotCreateEventWhenNoAlertStatus() { + decorator.decorate(project, context); + + verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + verify(notificationManager, never()).scheduleForSending(any(Notification.class)); + } + + @Test + public void shouldNotCreateEventWhenSameLevel() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(newAlertStatus(Metric.Level.ERROR, "desc")); + + decorator.decorate(project, context); + + verify(context, never()).createEvent(anyString(), anyString(), anyString(), (Date) isNull()); + verify(notificationManager, never()).scheduleForSending(any(Notification.class)); + } + + @Test + public void shouldNotCreateEventIfNoMoreAlertStatus() { + when(timeMachine.getMeasures(any(TimeMachineQuery.class))).thenReturn(Arrays.asList(newAlertStatus(Metric.Level.ERROR, "desc"))); + when(context.getMeasure(CoreMetrics.ALERT_STATUS)).thenReturn(null); + + 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) { + Measure measure = new Measure(CoreMetrics.ALERT_STATUS, level); + measure.setAlertStatus(level); + measure.setAlertText(label); + return measure; + } + + private void verifyNotificationSent(String alertName, String alertText, String alertLevel, String isNewAlert) { + Notification notification = new Notification("alerts") + .setDefaultMessage("Alert on " + project.getLongName() + ": " + alertName) + .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)); + } +}