aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2019-03-25 17:11:44 +0100
committersonartech <sonartech@sonarsource.com>2019-04-23 10:37:53 +0200
commita3f19897401c93d659d421fbb0d8f8362fe2a3f6 (patch)
treef452195671cc8360e39a4df0a76c4840747ca59b /server/sonar-server
parent9158bb5d1863562feeef609951bc73dfbb0df7cb (diff)
downloadsonarqube-a3f19897401c93d659d421fbb0d8f8362fe2a3f6.tar.gz
sonarqube-a3f19897401c93d659d421fbb0d8f8362fe2a3f6.zip
SONAR-11753 NotificationDaemon supports email specific algo
Diffstat (limited to 'server/sonar-server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/notification/NotificationDaemon.java7
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java248
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/notification/NotificationMediumTest.java261
3 files changed, 312 insertions, 204 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/notification/NotificationDaemon.java b/server/sonar-server/src/main/java/org/sonar/server/notification/NotificationDaemon.java
index 946db5e86a8..acf90de9586 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/notification/NotificationDaemon.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/notification/NotificationDaemon.java
@@ -33,6 +33,8 @@ import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
+import static java.util.Collections.singleton;
+
@Properties({
@Property(
key = NotificationDaemon.PROPERTY_DELAY,
@@ -106,8 +108,9 @@ public class NotificationDaemon implements Startable {
Notification notifToSend = manager.getFromQueue();
while (notifToSend != null) {
- service.deliver(notifToSend);
- notifSentCount++;
+ notifSentCount += service.deliverEmails(singleton(notifToSend));
+ // compatibility with old API
+ notifSentCount += service.deliver(notifToSend);
if (stopping) {
break;
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java b/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java
index 8c43891542e..8a24e6b092c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationDaemonTest.java
@@ -19,243 +19,87 @@
*/
package org.sonar.server.notification;
-import com.google.common.collect.Sets;
-import java.util.Arrays;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+import org.mockito.verification.Timeout;
import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.notifications.Notification;
-import org.sonar.api.notifications.NotificationChannel;
-import org.sonar.db.DbClient;
-import org.sonar.db.property.PropertiesDao;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.same;
-import static org.mockito.Mockito.doAnswer;
+import static java.util.Collections.singleton;
+import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class NotificationDaemonTest {
- private static String CREATOR_SIMON = "simon";
- private static String CREATOR_EVGENY = "evgeny";
- private static String ASSIGNEE_SIMON = "simon";
-
private DefaultNotificationManager manager = mock(DefaultNotificationManager.class);
- private Notification notification = mock(Notification.class);
- private NotificationChannel emailChannel = mock(NotificationChannel.class);
- private NotificationChannel gtalkChannel = mock(NotificationChannel.class);
- private NotificationDispatcher commentOnIssueAssignedToMe = mock(NotificationDispatcher.class);
- private NotificationDispatcher commentOnIssueCreatedByMe = mock(NotificationDispatcher.class);
- private NotificationDispatcher qualityGateChange = mock(NotificationDispatcher.class);
- private DbClient dbClient = mock(DbClient.class);
- private NotificationService service = new NotificationService(dbClient, new NotificationDispatcher[] {commentOnIssueAssignedToMe, commentOnIssueCreatedByMe, qualityGateChange});
- private NotificationDaemon underTest = null;
-
- private void setUpMocks() {
- when(emailChannel.getKey()).thenReturn("email");
- when(gtalkChannel.getKey()).thenReturn("gtalk");
- when(commentOnIssueAssignedToMe.getKey()).thenReturn("CommentOnIssueAssignedToMe");
- when(commentOnIssueAssignedToMe.getType()).thenReturn("issue-changes");
- when(commentOnIssueCreatedByMe.getKey()).thenReturn("CommentOnIssueCreatedByMe");
- when(commentOnIssueCreatedByMe.getType()).thenReturn("issue-changes");
- when(qualityGateChange.getKey()).thenReturn("QGateChange");
- when(qualityGateChange.getType()).thenReturn("qgate-changes");
- when(manager.getFromQueue()).thenReturn(notification).thenReturn(null);
+ private NotificationService notificationService = mock(NotificationService.class);
+ private NotificationDaemon underTest;
+ private InOrder inOrder;
+ @Before
+ public void setUp() throws Exception {
MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
- underTest = new NotificationDaemon(settings.asConfig(), manager, service);
- }
-
- /**
- * Given:
- * Simon wants to receive notifications by email on comments for reviews assigned to him or created by him.
- * <p/>
- * When:
- * Freddy adds comment to review created by Simon and assigned to Simon.
- * <p/>
- * Then:
- * Only one notification should be delivered to Simon by Email.
- */
- @Test
- public void scenario1() {
- setUpMocks();
- doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
- doAnswer(addUser(CREATOR_SIMON, emailChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
-
- underTest.start();
- verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
- underTest.stop();
-
- verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
- }
-
- /**
- * Given:
- * Evgeny wants to receive notification by GTalk on comments for reviews created by him.
- * Simon wants to receive notification by Email on comments for reviews assigned to him.
- * <p/>
- * When:
- * Freddy adds comment to review created by Evgeny and assigned to Simon.
- * <p/>
- * Then:
- * Two notifications should be delivered - one to Simon by Email and another to Evgeny by GTalk.
- */
- @Test
- public void scenario2() {
- setUpMocks();
- doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
- doAnswer(addUser(CREATOR_EVGENY, gtalkChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
-
- underTest.start();
- verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
- verify(gtalkChannel, timeout(2000)).deliver(notification, CREATOR_EVGENY);
- underTest.stop();
-
- verify(emailChannel, never()).deliver(notification, CREATOR_EVGENY);
- verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
+ underTest = new NotificationDaemon(settings.asConfig(), manager, notificationService);
+ inOrder = Mockito.inOrder(notificationService);
}
- /**
- * Given:
- * Simon wants to receive notifications by Email and GTLak on comments for reviews assigned to him.
- * <p/>
- * When:
- * Freddy adds comment to review created by Evgeny and assigned to Simon.
- * <p/>
- * Then:
- * Two notifications should be delivered to Simon - one by Email and another by GTalk.
- */
- @Test
- public void scenario3() {
- setUpMocks();
- doAnswer(addUser(ASSIGNEE_SIMON, new NotificationChannel[] {emailChannel, gtalkChannel}))
- .when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
-
- underTest.start();
- verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
- verify(gtalkChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ @After
+ public void tearDown() {
underTest.stop();
-
- verify(emailChannel, never()).deliver(notification, CREATOR_EVGENY);
- verify(gtalkChannel, never()).deliver(notification, CREATOR_EVGENY);
}
- /**
- * Given:
- * Nobody wants to receive notifications.
- * <p/>
- * When:
- * Freddy adds comment to review created by Evgeny and assigned to Simon.
- * <p/>
- * Then:
- * No notifications.
- */
@Test
- public void scenario4() {
- setUpMocks();
+ public void no_effect_when_no_notification() {
+ when(manager.getFromQueue()).thenReturn(null);
underTest.start();
+ inOrder.verify(notificationService, new Timeout(2000, Mockito.times(0))).deliverEmails(anyCollection());
+ inOrder.verifyNoMoreInteractions();
underTest.stop();
-
- verify(emailChannel, never()).deliver(any(Notification.class), anyString());
- verify(gtalkChannel, never()).deliver(any(Notification.class), anyString());
}
- // SONAR-4548
@Test
- public void shouldNotStopWhenException() {
- setUpMocks();
- when(manager.getFromQueue()).thenThrow(new RuntimeException("Unexpected exception")).thenReturn(notification).thenReturn(null);
- doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
- doAnswer(addUser(CREATOR_SIMON, emailChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
-
- underTest.start();
- verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
- underTest.stop();
-
- verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
- }
-
- @Test
- public void shouldNotAddNullAsUser() {
- setUpMocks();
- doAnswer(addUser(null, gtalkChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+ public void calls_both_api_and_deprecated_API() {
+ Notification notification = mock(Notification.class);
+ when(manager.getFromQueue()).thenReturn(notification).thenReturn(null);
underTest.start();
+ inOrder.verify(notificationService, timeout(2000)).deliverEmails(singleton(notification));
+ inOrder.verify(notificationService).deliver(notification);
+ inOrder.verifyNoMoreInteractions();
underTest.stop();
-
- verify(emailChannel, never()).deliver(any(Notification.class), anyString());
- verify(gtalkChannel, never()).deliver(any(Notification.class), anyString());
- }
-
- @Test
- public void getDispatchers() {
- setUpMocks();
-
- assertThat(service.getDispatchers()).containsOnly(commentOnIssueAssignedToMe, commentOnIssueCreatedByMe, qualityGateChange);
}
@Test
- public void getDispatchers_empty() {
- Settings settings = new MapSettings().setProperty("sonar.notifications.delay", 1L);
+ public void notifications_are_processed_one_by_one_even_with_new_API() {
+ Notification notification1 = mock(Notification.class);
+ Notification notification2 = mock(Notification.class);
+ Notification notification3 = mock(Notification.class);
+ Notification notification4 = mock(Notification.class);
+ when(manager.getFromQueue())
+ .thenReturn(notification1)
+ .thenReturn(notification2)
+ .thenReturn(notification3)
+ .thenReturn(notification4)
+ .thenReturn(null);
- service = new NotificationService(dbClient);
- assertThat(service.getDispatchers()).hasSize(0);
- }
-
- @Test
- public void shouldLogEvery10Minutes() {
- setUpMocks();
- // Emulate 2 notifications in DB
- when(manager.getFromQueue()).thenReturn(notification).thenReturn(notification).thenReturn(null);
- when(manager.count()).thenReturn(1L).thenReturn(0L);
- underTest = spy(underTest);
- // Emulate processing of each notification take 10 min to have a log each time
- when(underTest.now()).thenReturn(0L).thenReturn(10 * 60 * 1000 + 1L).thenReturn(20 * 60 * 1000 + 2L);
underTest.start();
- verify(underTest, timeout(200)).log(1, 1, 10);
- verify(underTest, timeout(200)).log(2, 0, 20);
+ inOrder.verify(notificationService, timeout(2000)).deliverEmails(singleton(notification1));
+ inOrder.verify(notificationService).deliver(notification1);
+ inOrder.verify(notificationService, timeout(2000)).deliverEmails(singleton(notification2));
+ inOrder.verify(notificationService).deliver(notification2);
+ inOrder.verify(notificationService, timeout(2000)).deliverEmails(singleton(notification3));
+ inOrder.verify(notificationService).deliver(notification3);
+ inOrder.verify(notificationService, timeout(2000)).deliverEmails(singleton(notification4));
+ inOrder.verify(notificationService).deliver(notification4);
+ inOrder.verifyNoMoreInteractions();
underTest.stop();
- }
-
- @Test
- public void hasProjectSubscribersForType() {
- setUpMocks();
-
- PropertiesDao dao = mock(PropertiesDao.class);
- when(dbClient.propertiesDao()).thenReturn(dao);
-
- // no subscribers
- when(dao.hasProjectNotificationSubscribersForDispatchers("PROJECT_UUID", Arrays.asList("CommentOnIssueAssignedToMe", "CommentOnIssueCreatedByMe"))).thenReturn(false);
- assertThat(service.hasProjectSubscribersForTypes("PROJECT_UUID", Sets.newHashSet("issue-changes"))).isFalse();
-
- // has subscribers on one dispatcher (among the two)
- when(dao.hasProjectNotificationSubscribersForDispatchers("PROJECT_UUID", Arrays.asList("CommentOnIssueAssignedToMe", "CommentOnIssueCreatedByMe"))).thenReturn(true);
- assertThat(service.hasProjectSubscribersForTypes("PROJECT_UUID", Sets.newHashSet("issue-changes"))).isTrue();
- }
-
- private static Answer<Object> addUser(final String user, final NotificationChannel channel) {
- return addUser(user, new NotificationChannel[] {channel});
- }
- private static Answer<Object> addUser(final String user, final NotificationChannel[] channels) {
- return new Answer<Object>() {
- public Object answer(InvocationOnMock invocation) {
- for (NotificationChannel channel : channels) {
- ((NotificationDispatcher.Context) invocation.getArguments()[1]).addUser(user, channel);
- }
- return null;
- }
- };
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationMediumTest.java
new file mode 100644
index 00000000000..5df98ad0394
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/notification/NotificationMediumTest.java
@@ -0,0 +1,261 @@
+/*
+ * 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.notification;
+
+import com.google.common.collect.Sets;
+import java.util.Arrays;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.notifications.Notification;
+import org.sonar.api.notifications.NotificationChannel;
+import org.sonar.db.DbClient;
+import org.sonar.db.property.PropertiesDao;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class NotificationMediumTest {
+ private static String CREATOR_SIMON = "simon";
+ private static String CREATOR_EVGENY = "evgeny";
+ private static String ASSIGNEE_SIMON = "simon";
+
+ private DefaultNotificationManager manager = mock(DefaultNotificationManager.class);
+ private Notification notification = mock(Notification.class);
+ private NotificationChannel emailChannel = mock(NotificationChannel.class);
+ private NotificationChannel gtalkChannel = mock(NotificationChannel.class);
+ private NotificationDispatcher commentOnIssueAssignedToMe = mock(NotificationDispatcher.class);
+ private NotificationDispatcher commentOnIssueCreatedByMe = mock(NotificationDispatcher.class);
+ private NotificationDispatcher qualityGateChange = mock(NotificationDispatcher.class);
+ private DbClient dbClient = mock(DbClient.class);
+ private NotificationService service = new NotificationService(dbClient, new NotificationDispatcher[] {commentOnIssueAssignedToMe, commentOnIssueCreatedByMe, qualityGateChange});
+ private NotificationDaemon underTest = null;
+
+ private void setUpMocks() {
+ when(emailChannel.getKey()).thenReturn("email");
+ when(gtalkChannel.getKey()).thenReturn("gtalk");
+ when(commentOnIssueAssignedToMe.getKey()).thenReturn("CommentOnIssueAssignedToMe");
+ when(commentOnIssueAssignedToMe.getType()).thenReturn("issue-changes");
+ when(commentOnIssueCreatedByMe.getKey()).thenReturn("CommentOnIssueCreatedByMe");
+ when(commentOnIssueCreatedByMe.getType()).thenReturn("issue-changes");
+ when(qualityGateChange.getKey()).thenReturn("QGateChange");
+ when(qualityGateChange.getType()).thenReturn("qgate-changes");
+ when(manager.getFromQueue()).thenReturn(notification).thenReturn(null);
+
+ MapSettings settings = new MapSettings(new PropertyDefinitions(NotificationDaemon.class)).setProperty("sonar.notifications.delay", 1L);
+
+ underTest = new NotificationDaemon(settings.asConfig(), manager, service);
+ }
+
+ /**
+ * Given:
+ * Simon wants to receive notifications by email on comments for reviews assigned to him or created by him.
+ * <p/>
+ * When:
+ * Freddy adds comment to review created by Simon and assigned to Simon.
+ * <p/>
+ * Then:
+ * Only one notification should be delivered to Simon by Email.
+ */
+ @Test
+ public void scenario1() {
+ setUpMocks();
+ doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+ doAnswer(addUser(CREATOR_SIMON, emailChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+
+ underTest.start();
+ verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ underTest.stop();
+
+ verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
+ }
+
+ /**
+ * Given:
+ * Evgeny wants to receive notification by GTalk on comments for reviews created by him.
+ * Simon wants to receive notification by Email on comments for reviews assigned to him.
+ * <p/>
+ * When:
+ * Freddy adds comment to review created by Evgeny and assigned to Simon.
+ * <p/>
+ * Then:
+ * Two notifications should be delivered - one to Simon by Email and another to Evgeny by GTalk.
+ */
+ @Test
+ public void scenario2() {
+ setUpMocks();
+ doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+ doAnswer(addUser(CREATOR_EVGENY, gtalkChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+
+ underTest.start();
+ verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ verify(gtalkChannel, timeout(2000)).deliver(notification, CREATOR_EVGENY);
+ underTest.stop();
+
+ verify(emailChannel, never()).deliver(notification, CREATOR_EVGENY);
+ verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
+ }
+
+ /**
+ * Given:
+ * Simon wants to receive notifications by Email and GTLak on comments for reviews assigned to him.
+ * <p/>
+ * When:
+ * Freddy adds comment to review created by Evgeny and assigned to Simon.
+ * <p/>
+ * Then:
+ * Two notifications should be delivered to Simon - one by Email and another by GTalk.
+ */
+ @Test
+ public void scenario3() {
+ setUpMocks();
+ doAnswer(addUser(ASSIGNEE_SIMON, new NotificationChannel[] {emailChannel, gtalkChannel}))
+ .when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+
+ underTest.start();
+ verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ verify(gtalkChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ underTest.stop();
+
+ verify(emailChannel, never()).deliver(notification, CREATOR_EVGENY);
+ verify(gtalkChannel, never()).deliver(notification, CREATOR_EVGENY);
+ }
+
+ /**
+ * Given:
+ * Nobody wants to receive notifications.
+ * <p/>
+ * When:
+ * Freddy adds comment to review created by Evgeny and assigned to Simon.
+ * <p/>
+ * Then:
+ * No notifications.
+ */
+ @Test
+ public void scenario4() {
+ setUpMocks();
+
+ underTest.start();
+ underTest.stop();
+
+ verify(emailChannel, never()).deliver(any(Notification.class), anyString());
+ verify(gtalkChannel, never()).deliver(any(Notification.class), anyString());
+ }
+
+ // SONAR-4548
+ @Test
+ public void shouldNotStopWhenException() {
+ setUpMocks();
+ when(manager.getFromQueue()).thenThrow(new RuntimeException("Unexpected exception")).thenReturn(notification).thenReturn(null);
+ doAnswer(addUser(ASSIGNEE_SIMON, emailChannel)).when(commentOnIssueAssignedToMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+ doAnswer(addUser(CREATOR_SIMON, emailChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+
+ underTest.start();
+ verify(emailChannel, timeout(2000)).deliver(notification, ASSIGNEE_SIMON);
+ underTest.stop();
+
+ verify(gtalkChannel, never()).deliver(notification, ASSIGNEE_SIMON);
+ }
+
+ @Test
+ public void shouldNotAddNullAsUser() {
+ setUpMocks();
+ doAnswer(addUser(null, gtalkChannel)).when(commentOnIssueCreatedByMe).dispatch(same(notification), any(NotificationDispatcher.Context.class));
+
+ underTest.start();
+ underTest.stop();
+
+ verify(emailChannel, never()).deliver(any(Notification.class), anyString());
+ verify(gtalkChannel, never()).deliver(any(Notification.class), anyString());
+ }
+
+ @Test
+ public void getDispatchers() {
+ setUpMocks();
+
+ assertThat(service.getDispatchers()).containsOnly(commentOnIssueAssignedToMe, commentOnIssueCreatedByMe, qualityGateChange);
+ }
+
+ @Test
+ public void getDispatchers_empty() {
+ Settings settings = new MapSettings().setProperty("sonar.notifications.delay", 1L);
+
+ service = new NotificationService(dbClient);
+ assertThat(service.getDispatchers()).hasSize(0);
+ }
+
+ @Test
+ public void shouldLogEvery10Minutes() {
+ setUpMocks();
+ // Emulate 2 notifications in DB
+ when(manager.getFromQueue()).thenReturn(notification).thenReturn(notification).thenReturn(null);
+ when(manager.count()).thenReturn(1L).thenReturn(0L);
+ underTest = spy(underTest);
+ // Emulate processing of each notification take 10 min to have a log each time
+ when(underTest.now()).thenReturn(0L).thenReturn(10 * 60 * 1000 + 1L).thenReturn(20 * 60 * 1000 + 2L);
+ underTest.start();
+ verify(underTest, timeout(200)).log(1, 1, 10);
+ verify(underTest, timeout(200)).log(2, 0, 20);
+ underTest.stop();
+ }
+
+ @Test
+ public void hasProjectSubscribersForType() {
+ setUpMocks();
+
+ PropertiesDao dao = mock(PropertiesDao.class);
+ when(dbClient.propertiesDao()).thenReturn(dao);
+
+ // no subscribers
+ when(dao.hasProjectNotificationSubscribersForDispatchers("PROJECT_UUID", Arrays.asList("CommentOnIssueAssignedToMe", "CommentOnIssueCreatedByMe"))).thenReturn(false);
+ assertThat(service.hasProjectSubscribersForTypes("PROJECT_UUID", Sets.newHashSet("issue-changes"))).isFalse();
+
+ // has subscribers on one dispatcher (among the two)
+ when(dao.hasProjectNotificationSubscribersForDispatchers("PROJECT_UUID", Arrays.asList("CommentOnIssueAssignedToMe", "CommentOnIssueCreatedByMe"))).thenReturn(true);
+ assertThat(service.hasProjectSubscribersForTypes("PROJECT_UUID", Sets.newHashSet("issue-changes"))).isTrue();
+ }
+
+ private static Answer<Object> addUser(final String user, final NotificationChannel channel) {
+ return addUser(user, new NotificationChannel[] {channel});
+ }
+
+ private static Answer<Object> addUser(final String user, final NotificationChannel[] channels) {
+ return new Answer<Object>() {
+ public Object answer(InvocationOnMock invocation) {
+ for (NotificationChannel channel : channels) {
+ ((NotificationDispatcher.Context) invocation.getArguments()[1]).addUser(user, channel);
+ }
+ return null;
+ }
+ };
+ }
+}