import java.util.Optional;
import javax.annotation.Nullable;
import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.notifications.Notification;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.server.notification.NotificationService;
+import org.sonar.server.qualitygate.notification.QGChangeNotification;
+
+import static java.util.Collections.singleton;
/**
* This step must be executed after computation of quality gate measure {@link QualityGateMeasuresStep}
* @param rawStatus OK or ERROR + optional text
*/
private void notifyUsers(Component project, String label, QualityGateStatus rawStatus, boolean isNewAlert) {
- Notification notification = new Notification("alerts")
+ QGChangeNotification notification = new QGChangeNotification();
+ notification
.setDefaultMessage(String.format("Alert on %s: %s", project.getName(), label))
.setFieldValue("projectName", project.getName())
.setFieldValue("projectKey", project.getKey())
if (!branch.isMain()) {
notification.setFieldValue("branch", branch.getName());
}
+ notificationService.deliverEmails(singleton(notification));
+
+ // compatibility with old API
notificationService.deliver(notification);
}
*/
package org.sonar.ce.task.projectanalysis.step;
+import java.util.Collection;
import java.util.Optional;
-import java.util.Random;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.component.BranchType;
import org.sonar.server.notification.NotificationService;
import org.sonar.server.project.Project;
+import org.sonar.server.qualitygate.notification.QGChangeNotification;
import static java.util.Collections.emptyList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
assertThat(event.getDescription()).isEqualTo(ALERT_TEXT);
assertThat(event.getData()).isNull();
+ ArgumentCaptor<Collection> collectionCaptor = ArgumentCaptor.forClass(Collection.class);
+ verify(notificationService).deliverEmails(collectionCaptor.capture());
verify(notificationService).deliver(notificationArgumentCaptor.capture());
Notification notification = notificationArgumentCaptor.getValue();
+ assertThat(collectionCaptor.getValue()).hasSize(1);
+ assertThat(collectionCaptor.getValue().iterator().next()).isSameAs(notification);
+ assertThat(notification).isInstanceOf(QGChangeNotification.class);
assertThat(notification.getType()).isEqualTo("alerts");
assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey());
assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName());
import org.sonar.server.config.ConfigurationProvider;
import org.sonar.server.es.EsModule;
import org.sonar.server.es.ProjectIndexersImpl;
-import org.sonar.server.qualitygate.notification.NewAlerts;
import org.sonar.server.extension.CoreExtensionBootstraper;
import org.sonar.server.extension.CoreExtensionStopper;
import org.sonar.server.favorite.FavoriteUpdater;
import org.sonar.server.metric.DefaultMetricFinder;
import org.sonar.server.notification.DefaultNotificationManager;
import org.sonar.server.notification.NotificationService;
-import org.sonar.server.qualitygate.notification.AlertsEmailTemplate;
import org.sonar.server.notification.email.EmailNotificationChannel;
import org.sonar.server.organization.BillingValidationsProxyImpl;
import org.sonar.server.organization.DefaultOrganizationProviderImpl;
import org.sonar.server.property.InternalPropertiesImpl;
import org.sonar.server.qualitygate.QualityGateEvaluatorImpl;
import org.sonar.server.qualitygate.QualityGateFinder;
+import org.sonar.server.qualitygate.notification.QGChangeEmailTemplate;
+import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler;
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer;
import org.sonar.server.rule.DefaultRuleFinder;
import org.sonar.server.rule.index.RuleIndex;
// components,
FavoriteUpdater.class,
ProjectIndexersImpl.class,
- NewAlerts.class,
- NewAlerts.newMetadata(),
+ QGChangeNotificationHandler.class,
+ QGChangeNotificationHandler.newMetadata(),
ProjectMeasuresIndexer.class,
ComponentIndexer.class,
DoNotFixNotificationHandler.newMetadata(),
// Notifications
- AlertsEmailTemplate.class,
+ QGChangeEmailTemplate.class,
EmailSettings.class,
NotificationService.class,
DefaultNotificationManager.class,
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.server.qualitygate.notification;
-
-import javax.annotation.Nullable;
-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 projectVersion = notification.getFieldValue("projectVersion");
- String branchName = notification.getFieldValue("branch");
- String alertName = notification.getFieldValue("alertName");
- String alertText = notification.getFieldValue("alertText");
- String alertLevel = notification.getFieldValue("alertLevel");
- boolean isNewAlert = Boolean.parseBoolean(notification.getFieldValue("isNewAlert"));
- String fullProjectName = computeFullProjectName(projectName, branchName);
-
- // Generate text
- String subject = generateSubject(fullProjectName, alertLevel, isNewAlert);
- String messageBody = generateMessageBody(projectName, projectKey, projectVersion, branchName, alertName, alertText, isNewAlert);
-
- // And finally return the email that will be sent
- return new EmailMessage()
- .setMessageId("alerts/" + projectId)
- .setSubject(subject)
- .setMessage(messageBody);
- }
-
- private static String computeFullProjectName(String projectName, @Nullable String branchName) {
- if (branchName == null || branchName.isEmpty()) {
- return projectName;
- }
- return String.format("%s (%s)", projectName, branchName);
- }
-
- private static String generateSubject(String fullProjectName, String alertLevel, boolean isNewAlert) {
- StringBuilder subjectBuilder = new StringBuilder();
- if (Metric.Level.OK.toString().equals(alertLevel)) {
- subjectBuilder.append("\"").append(fullProjectName).append("\" is back to green");
- } else if (isNewAlert) {
- subjectBuilder.append("New quality gate threshold reached on \"").append(fullProjectName).append("\"");
- } else {
- subjectBuilder.append("Quality gate status changed on \"").append(fullProjectName).append("\"");
- }
- return subjectBuilder.toString();
- }
-
- private String generateMessageBody(String projectName, String projectKey,
- @Nullable String projectVersion, @Nullable String branchName,
- String alertName, String alertText, boolean isNewAlert) {
- StringBuilder messageBody = new StringBuilder();
- messageBody.append("Project: ").append(projectName).append("\n");
- if (branchName != null) {
- messageBody.append("Branch: ").append(branchName).append("\n");
- }
- if (projectVersion != null) {
- messageBody.append("Version: ").append(projectVersion).append("\n");
- }
- messageBody.append("Quality gate status: ").append(alertName).append("\n\n");
-
- String[] alerts = StringUtils.split(alertText, ",");
- if (alerts.length > 0) {
- if (isNewAlert) {
- messageBody.append("New quality gate threshold");
- } else {
- messageBody.append("Quality gate threshold");
- }
- 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("More details at: ").append(configuration.getServerBaseURL()).append("/dashboard?id=").append(projectKey);
- if (branchName != null) {
- messageBody.append("&branch=").append(branchName);
- }
-
- return messageBody.toString();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.server.qualitygate.notification;
-
-import com.google.common.collect.Multimap;
-import java.util.Collection;
-import java.util.Map;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.server.notification.NotificationDispatcher;
-import org.sonar.server.notification.NotificationDispatcherMetadata;
-import org.sonar.server.notification.NotificationManager;
-
-import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
-
-/**
- * This dispatcher means: "notify me each new alert event".
- *
- * @since 3.5
- */
-public class NewAlerts extends NotificationDispatcher {
-
- public static final String KEY = "NewAlerts";
- private final NotificationManager notifications;
-
- public NewAlerts(NotificationManager notifications) {
- super("alerts");
- this.notifications = notifications;
- }
-
- @Override
- public String getKey() {
- return KEY;
- }
-
- public static NotificationDispatcherMetadata newMetadata() {
- return NotificationDispatcherMetadata.create(KEY)
- .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, String.valueOf(true))
- .setProperty(NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION, String.valueOf(true));
- }
-
- @Override
- public void dispatch(Notification notification, Context context) {
- String projectKey = notification.getFieldValue("projectKey");
- if (projectKey != null) {
- Multimap<String, NotificationChannel> subscribedRecipients = notifications
- .findSubscribedRecipientsForDispatcher(this, projectKey, ALL_MUST_HAVE_ROLE_USER);
-
- for (Map.Entry<String, Collection<NotificationChannel>> channelsByRecipients : subscribedRecipients.asMap().entrySet()) {
- String userLogin = channelsByRecipients.getKey();
- for (NotificationChannel channel : channelsByRecipients.getValue()) {
- context.addUser(userLogin, channel);
- }
- }
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.server.qualitygate.notification;
+
+import javax.annotation.Nullable;
+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 QGChangeEmailTemplate extends EmailTemplate {
+
+ private EmailSettings configuration;
+
+ public QGChangeEmailTemplate(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 projectVersion = notification.getFieldValue("projectVersion");
+ String branchName = notification.getFieldValue("branch");
+ String alertName = notification.getFieldValue("alertName");
+ String alertText = notification.getFieldValue("alertText");
+ String alertLevel = notification.getFieldValue("alertLevel");
+ boolean isNewAlert = Boolean.parseBoolean(notification.getFieldValue("isNewAlert"));
+ String fullProjectName = computeFullProjectName(projectName, branchName);
+
+ // Generate text
+ String subject = generateSubject(fullProjectName, alertLevel, isNewAlert);
+ String messageBody = generateMessageBody(projectName, projectKey, projectVersion, branchName, alertName, alertText, isNewAlert);
+
+ // And finally return the email that will be sent
+ return new EmailMessage()
+ .setMessageId("alerts/" + projectId)
+ .setSubject(subject)
+ .setMessage(messageBody);
+ }
+
+ private static String computeFullProjectName(String projectName, @Nullable String branchName) {
+ if (branchName == null || branchName.isEmpty()) {
+ return projectName;
+ }
+ return String.format("%s (%s)", projectName, branchName);
+ }
+
+ private static String generateSubject(String fullProjectName, String alertLevel, boolean isNewAlert) {
+ StringBuilder subjectBuilder = new StringBuilder();
+ if (Metric.Level.OK.toString().equals(alertLevel)) {
+ subjectBuilder.append("\"").append(fullProjectName).append("\" is back to green");
+ } else if (isNewAlert) {
+ subjectBuilder.append("New quality gate threshold reached on \"").append(fullProjectName).append("\"");
+ } else {
+ subjectBuilder.append("Quality gate status changed on \"").append(fullProjectName).append("\"");
+ }
+ return subjectBuilder.toString();
+ }
+
+ private String generateMessageBody(String projectName, String projectKey,
+ @Nullable String projectVersion, @Nullable String branchName,
+ String alertName, String alertText, boolean isNewAlert) {
+ StringBuilder messageBody = new StringBuilder();
+ messageBody.append("Project: ").append(projectName).append("\n");
+ if (branchName != null) {
+ messageBody.append("Branch: ").append(branchName).append("\n");
+ }
+ if (projectVersion != null) {
+ messageBody.append("Version: ").append(projectVersion).append("\n");
+ }
+ messageBody.append("Quality gate status: ").append(alertName).append("\n\n");
+
+ String[] alerts = StringUtils.split(alertText, ",");
+ if (alerts.length > 0) {
+ if (isNewAlert) {
+ messageBody.append("New quality gate threshold");
+ } else {
+ messageBody.append("Quality gate threshold");
+ }
+ 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("More details at: ").append(configuration.getServerBaseURL()).append("/dashboard?id=").append(projectKey);
+ if (branchName != null) {
+ messageBody.append("&branch=").append(branchName);
+ }
+
+ return messageBody.toString();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.server.qualitygate.notification;
+
+import javax.annotation.CheckForNull;
+import org.sonar.api.notifications.Notification;
+
+public class QGChangeNotification extends Notification {
+ public QGChangeNotification() {
+ super("alerts");
+ }
+
+ @CheckForNull
+ public String getProjectKey() {
+ return getFieldValue("projectKey");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.server.qualitygate.notification;
+
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Stream;
+import org.sonar.server.notification.NotificationDispatcherMetadata;
+import org.sonar.server.notification.NotificationHandler;
+import org.sonar.server.notification.NotificationManager;
+import org.sonar.server.notification.email.EmailNotificationChannel;
+import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest;
+
+import static org.sonar.core.util.stream.MoreCollectors.index;
+import static org.sonar.core.util.stream.MoreCollectors.toSet;
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
+public class QGChangeNotificationHandler implements NotificationHandler<QGChangeNotification> {
+
+ public static final String KEY = "NewAlerts";
+
+ private final NotificationManager notificationManager;
+ private final EmailNotificationChannel emailNotificationChannel;
+
+ public QGChangeNotificationHandler(NotificationManager notificationManager, EmailNotificationChannel emailNotificationChannel) {
+ this.notificationManager = notificationManager;
+ this.emailNotificationChannel = emailNotificationChannel;
+ }
+
+ @Override
+ public Class<QGChangeNotification> getNotificationClass() {
+ return QGChangeNotification.class;
+ }
+
+ public static NotificationDispatcherMetadata newMetadata() {
+ return NotificationDispatcherMetadata.create(KEY)
+ .setProperty(NotificationDispatcherMetadata.GLOBAL_NOTIFICATION, String.valueOf(true))
+ .setProperty(NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION, String.valueOf(true));
+ }
+
+ @Override
+ public int deliver(Collection<QGChangeNotification> notifications) {
+ if (notifications.isEmpty() || !emailNotificationChannel.isActivated()) {
+ return 0;
+ }
+
+ Multimap<String, QGChangeNotification> notificationsByProjectKey = notifications.stream()
+ .filter(t -> t.getProjectKey() != null)
+ .collect(index(QGChangeNotification::getProjectKey));
+ if (notificationsByProjectKey.isEmpty()) {
+ return 0;
+ }
+
+ Set<EmailDeliveryRequest> deliveryRequests = notificationsByProjectKey.asMap().entrySet()
+ .stream()
+ .flatMap(e -> toEmailDeliveryRequests(e.getKey(), e.getValue()))
+ .collect(toSet(notifications.size()));
+ if (deliveryRequests.isEmpty()) {
+ return 0;
+ }
+ return emailNotificationChannel.deliver(deliveryRequests);
+ }
+
+ private Stream<? extends EmailDeliveryRequest> toEmailDeliveryRequests(String projectKey, Collection<QGChangeNotification> notifications) {
+ return notificationManager.findSubscribedEmailRecipients(KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)
+ .stream()
+ .flatMap(emailRecipient -> notifications.stream()
+ .map(notification -> new EmailDeliveryRequest(emailRecipient.getEmail(), notification)));
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.server.qualitygate.notification;
-
-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 org.sonar.server.qualitygate.notification.AlertsEmailTemplate;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.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("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "false");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("Quality gate status changed on \"Foo\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "Quality gate thresholds:\n" +
- " - violations > 4\n" +
- " - coverage < 75%\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
- }
-
- @Test
- public void shouldFormatAlertWithSeveralMessagesOnBranch() {
- Notification notification = createNotification("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "false")
- .setFieldValue("branch", "feature");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("Quality gate status changed on \"Foo (feature)\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Branch: feature\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "Quality gate thresholds:\n" +
- " - violations > 4\n" +
- " - coverage < 75%\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
- }
-
- @Test
- public void shouldFormatNewAlertWithSeveralMessages() {
- Notification notification = createNotification("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "true");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "New quality gate thresholds:\n" +
- " - violations > 4\n" +
- " - coverage < 75%\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
- }
-
- @Test
- public void shouldFormatNewAlertWithOneMessage() {
- Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "New quality gate threshold: violations > 4\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
- }
-
- @Test
- public void shouldFormatNewAlertWithoutVersion() {
- Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true")
- .setFieldValue("projectVersion", null);
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "New quality gate threshold: violations > 4\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
- }
-
- @Test
- public void shouldFormatNewAlertWithOneMessageOnBranch() {
- Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true")
- .setFieldValue("branch", "feature");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo (feature)\""));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Branch: feature\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Red (was Green)\n" +
- "\n" +
- "New quality gate threshold: violations > 4\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
- }
-
- @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" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Green (was Red)\n" +
- "\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
- }
-
- @Test
- public void shouldFormatBackToGreenMessageOnBranch() {
- Notification notification = createNotification("Green (was Red)", "", "OK", "false")
- .setFieldValue("branch", "feature");
-
- EmailMessage message = template.format(notification);
- assertThat(message.getMessageId(), is("alerts/45"));
- assertThat(message.getSubject(), is("\"Foo (feature)\" is back to green"));
- assertThat(message.getMessage(), is("" +
- "Project: Foo\n" +
- "Branch: feature\n" +
- "Version: V1-SNAP\n" +
- "Quality gate status: Green (was Red)\n" +
- "\n" +
- "\n" +
- "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
- }
-
- 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("projectVersion", "V1-SNAP")
- .setFieldValue("alertName", alertName)
- .setFieldValue("alertText", alertText)
- .setFieldValue("alertLevel", alertLevel)
- .setFieldValue("isNewAlert", isNewAlert);
- return notification;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.server.qualitygate.notification;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimap;
-import org.junit.Test;
-import org.sonar.api.notifications.Notification;
-import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.api.web.UserRole;
-import org.sonar.server.notification.NotificationDispatcher;
-import org.sonar.server.notification.NotificationManager;
-
-import static org.mockito.Mockito.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 NewAlertsTest {
-
- private NotificationManager notificationManager = mock(NotificationManager.class);
- private NotificationDispatcher.Context context = mock(NotificationDispatcher.Context.class);
- private NotificationChannel emailChannel = mock(NotificationChannel.class);
- private NotificationChannel twitterChannel = mock(NotificationChannel.class);
- private NewAlerts dispatcher = new NewAlerts(notificationManager);
-
- @Test
- public void should_not_dispatch_if_not_alerts_notification() {
- Notification notification = new Notification("other-notif");
- dispatcher.performDispatch(notification, context);
-
- verify(context, never()).addUser(any(String.class), any(NotificationChannel.class));
- }
-
- @Test
- public void should_dispatch_to_users_who_have_subscribed() {
- Multimap<String, NotificationChannel> recipients = HashMultimap.create();
- recipients.put("user1", emailChannel);
- recipients.put("user2", twitterChannel);
- when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "key_34", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER)))
- .thenReturn(recipients);
-
- Notification notification = new Notification("alerts")
- .setFieldValue("projectKey", "key_34");
- dispatcher.performDispatch(notification, context);
-
- verify(context).addUser("user1", emailChannel);
- verify(context).addUser("user2", twitterChannel);
- verifyNoMoreInteractions(context);
- }
-
- @Test
- public void should_not_dispatch_if_missing_project_key() {
- Multimap<String, NotificationChannel> recipients = HashMultimap.create();
- recipients.put("user1", emailChannel);
- recipients.put("user2", twitterChannel);
- when(notificationManager.findSubscribedRecipientsForDispatcher(dispatcher, "key_34", new NotificationManager.SubscriberPermissionsOnProject(UserRole.USER)))
- .thenReturn(recipients);
-
- Notification notification = new Notification("alerts");
- dispatcher.performDispatch(notification, context);
-
- verifyNoMoreInteractions(context);
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.server.qualitygate.notification;
+
+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.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class QGChangeEmailTemplateTest {
+
+ private QGChangeEmailTemplate template;
+
+ @Before
+ public void setUp() {
+ EmailSettings configuration = mock(EmailSettings.class);
+ when(configuration.getServerBaseURL()).thenReturn("http://nemo.sonarsource.org");
+ template = new QGChangeEmailTemplate(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("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "false");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("Quality gate status changed on \"Foo\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "Quality gate thresholds:\n" +
+ " - violations > 4\n" +
+ " - coverage < 75%\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
+ }
+
+ @Test
+ public void shouldFormatAlertWithSeveralMessagesOnBranch() {
+ Notification notification = createNotification("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "false")
+ .setFieldValue("branch", "feature");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("Quality gate status changed on \"Foo (feature)\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Branch: feature\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "Quality gate thresholds:\n" +
+ " - violations > 4\n" +
+ " - coverage < 75%\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
+ }
+
+ @Test
+ public void shouldFormatNewAlertWithSeveralMessages() {
+ Notification notification = createNotification("Red (was Green)", "violations > 4, coverage < 75%", "ERROR", "true");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "New quality gate thresholds:\n" +
+ " - violations > 4\n" +
+ " - coverage < 75%\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
+ }
+
+ @Test
+ public void shouldFormatNewAlertWithOneMessage() {
+ Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "New quality gate threshold: violations > 4\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
+ }
+
+ @Test
+ public void shouldFormatNewAlertWithoutVersion() {
+ Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true")
+ .setFieldValue("projectVersion", null);
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "New quality gate threshold: violations > 4\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
+ }
+
+ @Test
+ public void shouldFormatNewAlertWithOneMessageOnBranch() {
+ Notification notification = createNotification("Red (was Green)", "violations > 4", "ERROR", "true")
+ .setFieldValue("branch", "feature");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("New quality gate threshold reached on \"Foo (feature)\""));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Branch: feature\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Red (was Green)\n" +
+ "\n" +
+ "New quality gate threshold: violations > 4\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
+ }
+
+ @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" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Green (was Red)\n" +
+ "\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo"));
+ }
+
+ @Test
+ public void shouldFormatBackToGreenMessageOnBranch() {
+ Notification notification = createNotification("Green (was Red)", "", "OK", "false")
+ .setFieldValue("branch", "feature");
+
+ EmailMessage message = template.format(notification);
+ assertThat(message.getMessageId(), is("alerts/45"));
+ assertThat(message.getSubject(), is("\"Foo (feature)\" is back to green"));
+ assertThat(message.getMessage(), is("" +
+ "Project: Foo\n" +
+ "Branch: feature\n" +
+ "Version: V1-SNAP\n" +
+ "Quality gate status: Green (was Red)\n" +
+ "\n" +
+ "\n" +
+ "More details at: http://nemo.sonarsource.org/dashboard?id=org.sonar.foo:foo&branch=feature"));
+ }
+
+ 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("projectVersion", "V1-SNAP")
+ .setFieldValue("alertName", alertName)
+ .setFieldValue("alertText", alertText)
+ .setFieldValue("alertLevel", alertLevel)
+ .setFieldValue("isNewAlert", isNewAlert);
+ return notification;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.server.qualitygate.notification;
+
+import java.util.Collections;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.server.notification.NotificationDispatcherMetadata;
+import org.sonar.server.notification.NotificationManager;
+import org.sonar.server.notification.email.EmailNotificationChannel;
+
+import static java.util.Collections.emptySet;
+import static java.util.stream.Collectors.toSet;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
+import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
+import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
+
+public class QGChangeNotificationHandlerTest {
+ private static final String QG_CHANGE_DISPATCHER_KEY = "NewAlerts";
+ private NotificationManager notificationManager = mock(NotificationManager.class);
+ private EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class);
+ private QGChangeNotificationHandler underTest = new QGChangeNotificationHandler(notificationManager, emailNotificationChannel);
+
+ @Test
+ public void verify_qgChange_notification_dispatcher_key() {
+ NotificationDispatcherMetadata metadata = QGChangeNotificationHandler.newMetadata();
+
+ assertThat(metadata.getDispatcherKey()).isEqualTo(QG_CHANGE_DISPATCHER_KEY);
+ }
+
+ @Test
+ public void qgChange_notification_is_enable_at_global_level() {
+ NotificationDispatcherMetadata metadata = QGChangeNotificationHandler.newMetadata();
+
+ assertThat(metadata.getProperty(GLOBAL_NOTIFICATION)).isEqualTo("true");
+ }
+
+ @Test
+ public void qgChange_notification_is_enable_at_project_level() {
+ NotificationDispatcherMetadata metadata = QGChangeNotificationHandler.newMetadata();
+
+ assertThat(metadata.getProperty(PER_PROJECT_NOTIFICATION)).isEqualTo("true");
+ }
+
+ @Test
+ public void getNotificationClass_is_QGChangeNotification() {
+ assertThat(underTest.getNotificationClass()).isEqualTo(QGChangeNotification.class);
+ }
+
+ @Test
+ public void deliver_has_no_effect_if_notifications_is_empty() {
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+ int deliver = underTest.deliver(Collections.emptyList());
+
+ assertThat(deliver).isZero();
+ verifyZeroInteractions(notificationManager, emailNotificationChannel);
+ }
+
+ @Test
+ public void deliver_has_no_effect_if_emailNotificationChannel_is_disabled() {
+ when(emailNotificationChannel.isActivated()).thenReturn(false);
+ Set<QGChangeNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
+ .mapToObj(i -> mock(QGChangeNotification.class))
+ .collect(toSet());
+
+ int deliver = underTest.deliver(notifications);
+
+ assertThat(deliver).isZero();
+ verifyZeroInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verifyNoMoreInteractions(emailNotificationChannel);
+ notifications.forEach(Mockito::verifyZeroInteractions);
+ }
+
+ @Test
+ public void deliver_has_no_effect_if_no_notification_has_projectKey() {
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+ Set<QGChangeNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
+ .mapToObj(i -> newNotification(null))
+ .collect(toSet());
+
+ int deliver = underTest.deliver(notifications);
+
+ assertThat(deliver).isZero();
+ verifyZeroInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verifyNoMoreInteractions(emailNotificationChannel);
+ notifications.forEach(notification -> {
+ verify(notification).getProjectKey();
+ verifyNoMoreInteractions(notification);
+ });
+ }
+
+ @Test
+ public void deliver_has_no_effect_if_no_notification_has_subscribed_recipients_to_QGChange_notifications() {
+ String projectKey = randomAlphabetic(12);
+ QGChangeNotification notification = newNotification(projectKey);
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emptySet());
+
+ int deliver = underTest.deliver(Collections.singleton(notification));
+
+ assertThat(deliver).isZero();
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER);
+ verifyNoMoreInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verifyNoMoreInteractions(emailNotificationChannel);
+ }
+
+ @Test
+ public void deliver_ignores_notification_without_projectKey() {
+ String projectKey = randomAlphabetic(10);
+ Set<QGChangeNotification> withProjectKey = IntStream.range(0, 1 + new Random().nextInt(5))
+ .mapToObj(i -> newNotification(projectKey))
+ .collect(toSet());
+ Set<QGChangeNotification> noProjectKey = IntStream.range(0, 1 + new Random().nextInt(5))
+ .mapToObj(i -> newNotification(null))
+ .collect(toSet());
+ Set<NotificationManager.EmailRecipient> emailRecipients = IntStream.range(0, 1 + new Random().nextInt(10))
+ .mapToObj(i -> "user_" + i)
+ .map(login -> new NotificationManager.EmailRecipient(login, emailOf(login)))
+ .collect(toSet());
+ Set<EmailNotificationChannel.EmailDeliveryRequest> expectedRequests = emailRecipients.stream()
+ .flatMap(emailRecipient -> withProjectKey.stream().map(notif -> new EmailNotificationChannel.EmailDeliveryRequest(emailRecipient.getEmail(), notif)))
+ .collect(toSet());
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emailRecipients);
+
+ Set<QGChangeNotification> notifications = Stream.of(withProjectKey.stream(), noProjectKey.stream())
+ .flatMap(t -> t)
+ .collect(toSet());
+ int deliver = underTest.deliver(notifications);
+
+ assertThat(deliver).isZero();
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER);
+ verifyNoMoreInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verify(emailNotificationChannel).deliver(expectedRequests);
+ verifyNoMoreInteractions(emailNotificationChannel);
+ }
+
+ @Test
+ public void deliver_checks_by_projectKey_if_notifications_have_subscribed_assignee_to_QGChange_notifications() {
+ String projectKey1 = randomAlphabetic(10);
+ String projectKey2 = randomAlphabetic(11);
+ Set<QGChangeNotification> notifications1 = randomSetOfNotifications(projectKey1);
+ Set<QGChangeNotification> notifications2 = randomSetOfNotifications(projectKey2);
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+
+ Set<NotificationManager.EmailRecipient> emailRecipients1 = IntStream.range(0, 1 + new Random().nextInt(10))
+ .mapToObj(i -> "user1_" + i)
+ .map(login -> new NotificationManager.EmailRecipient(login, emailOf(login)))
+ .collect(toSet());
+ Set<NotificationManager.EmailRecipient> emailRecipients2 = IntStream.range(0, 1 + new Random().nextInt(10))
+ .mapToObj(i -> "user2_" + i)
+ .map(login -> new NotificationManager.EmailRecipient(login, emailOf(login)))
+ .collect(toSet());
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emailRecipients1);
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emailRecipients2);
+ Set<EmailNotificationChannel.EmailDeliveryRequest> expectedRequests = Stream.concat(
+ emailRecipients1.stream()
+ .flatMap(emailRecipient -> notifications1.stream().map(notif -> new EmailNotificationChannel.EmailDeliveryRequest(emailRecipient.getEmail(), notif))),
+ emailRecipients2.stream()
+ .flatMap(emailRecipient -> notifications2.stream().map(notif -> new EmailNotificationChannel.EmailDeliveryRequest(emailRecipient.getEmail(), notif))))
+ .collect(toSet());
+
+ int deliver = underTest.deliver(Stream.concat(notifications1.stream(), notifications2.stream()).collect(toSet()));
+
+ assertThat(deliver).isZero();
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER);
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER);
+ verifyNoMoreInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verify(emailNotificationChannel).deliver(expectedRequests);
+ verifyNoMoreInteractions(emailNotificationChannel);
+ }
+
+ @Test
+ public void deliver_send_notifications_to_all_subscribers_of_all_projects() {
+ String projectKey1 = randomAlphabetic(10);
+ String projectKey2 = randomAlphabetic(11);
+ Set<QGChangeNotification> notifications1 = randomSetOfNotifications(projectKey1);
+ Set<QGChangeNotification> notifications2 = randomSetOfNotifications(projectKey2);
+ when(emailNotificationChannel.isActivated()).thenReturn(true);
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emptySet());
+ when(notificationManager.findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER))
+ .thenReturn(emptySet());
+
+ int deliver = underTest.deliver(Stream.concat(notifications1.stream(), notifications2.stream()).collect(toSet()));
+
+ assertThat(deliver).isZero();
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER);
+ verify(notificationManager).findSubscribedEmailRecipients(QG_CHANGE_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER);
+ verifyNoMoreInteractions(notificationManager);
+ verify(emailNotificationChannel).isActivated();
+ verifyNoMoreInteractions(emailNotificationChannel);
+ }
+
+ private static Set<QGChangeNotification> randomSetOfNotifications(@Nullable String projectKey) {
+ return IntStream.range(0, 1 + new Random().nextInt(5))
+ .mapToObj(i -> newNotification(projectKey))
+ .collect(Collectors.toSet());
+ }
+
+ private static QGChangeNotification newNotification(@Nullable String projectKey) {
+ QGChangeNotification notification = mock(QGChangeNotification.class);
+ when(notification.getProjectKey()).thenReturn(projectKey);
+ return notification;
+ }
+
+ private static String emailOf(String assignee1) {
+ return assignee1 + "@giraffe";
+ }
+
+
+
+}
import org.sonar.api.Startable;
import org.sonar.api.config.Configuration;
import org.sonar.process.ProcessProperties;
-import org.sonar.server.qualitygate.notification.NewAlerts;
import org.sonar.server.issue.notification.DoNotFixNotificationHandler;
import org.sonar.server.issue.notification.NewIssuesNotificationHandler;
import org.sonar.server.notification.NotificationCenter;
+import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler;
import static org.sonar.core.util.stream.MoreCollectors.toList;
import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
public class DispatchersImpl implements Dispatchers, Startable {
private static final Set<String> GLOBAL_DISPATCHERS_TO_IGNORE_ON_SONAR_CLOUD = ImmutableSet.of(
- NewAlerts.KEY,
+ QGChangeNotificationHandler.KEY,
DoNotFixNotificationHandler.KEY,
NewIssuesNotificationHandler.KEY);
import org.sonar.server.es.metadata.EsDbCompatibilityImpl;
import org.sonar.server.es.metadata.MetadataIndex;
import org.sonar.server.es.metadata.MetadataIndexDefinition;
-import org.sonar.server.qualitygate.notification.NewAlerts;
import org.sonar.server.extension.CoreExtensionBootstraper;
import org.sonar.server.extension.CoreExtensionStopper;
import org.sonar.server.favorite.FavoriteModule;
import org.sonar.server.property.InternalPropertiesImpl;
import org.sonar.server.property.ws.PropertiesWs;
import org.sonar.server.qualitygate.QualityGateModule;
+import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler;
import org.sonar.server.qualityprofile.BuiltInQProfileDefinitionsBridge;
import org.sonar.server.qualityprofile.BuiltInQProfileRepositoryImpl;
import org.sonar.server.qualityprofile.BuiltInQualityProfilesNotificationDispatcher;
ComponentService.class,
ComponentUpdater.class,
ComponentFinder.class,
- NewAlerts.class,
- NewAlerts.newMetadata(),
+ QGChangeNotificationHandler.class,
+ QGChangeNotificationHandler.newMetadata(),
ComponentCleanerService.class,
ComponentIndexDefinition.class,
ComponentIndex.class,
import org.junit.Test;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.server.qualitygate.notification.NewAlerts;
import org.sonar.server.issue.notification.DoNotFixNotificationHandler;
import org.sonar.server.issue.notification.MyNewIssuesNotificationHandler;
import org.sonar.server.issue.notification.NewIssuesNotificationHandler;
import org.sonar.server.notification.NotificationCenter;
import org.sonar.server.notification.NotificationDispatcherMetadata;
+import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
.setProperty(PER_PROJECT_NOTIFICATION, "true"),
NotificationDispatcherMetadata.create(NewIssuesNotificationHandler.KEY)
.setProperty(GLOBAL_NOTIFICATION, "true"),
- NotificationDispatcherMetadata.create(NewAlerts.KEY)
+ NotificationDispatcherMetadata.create(QGChangeNotificationHandler.KEY)
.setProperty(GLOBAL_NOTIFICATION, "true")
.setProperty(PER_PROJECT_NOTIFICATION, "true"),
NotificationDispatcherMetadata.create(DoNotFixNotificationHandler.KEY)
underTest.start();
assertThat(underTest.getGlobalDispatchers()).containsExactly(
- NewAlerts.KEY, DoNotFixNotificationHandler.KEY, NewIssuesNotificationHandler.KEY, MyNewIssuesNotificationHandler.KEY);
+ QGChangeNotificationHandler.KEY, DoNotFixNotificationHandler.KEY, NewIssuesNotificationHandler.KEY, MyNewIssuesNotificationHandler.KEY);
}
@Test
underTest.start();
assertThat(underTest.getProjectDispatchers()).containsExactly(
- NewAlerts.KEY, DoNotFixNotificationHandler.KEY, MyNewIssuesNotificationHandler.KEY);
+ QGChangeNotificationHandler.KEY, DoNotFixNotificationHandler.KEY, MyNewIssuesNotificationHandler.KEY);
}
@Test
underTest.start();
assertThat(underTest.getProjectDispatchers()).containsOnly(
- MyNewIssuesNotificationHandler.KEY, NewAlerts.KEY, DoNotFixNotificationHandler.KEY);
+ MyNewIssuesNotificationHandler.KEY, QGChangeNotificationHandler.KEY, DoNotFixNotificationHandler.KEY);
}
}