diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2019-03-25 17:11:44 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-04-23 10:37:53 +0200 |
commit | a3f19897401c93d659d421fbb0d8f8362fe2a3f6 (patch) | |
tree | f452195671cc8360e39a4df0a76c4840747ca59b /server/sonar-server | |
parent | 9158bb5d1863562feeef609951bc73dfbb0df7cb (diff) | |
download | sonarqube-a3f19897401c93d659d421fbb0d8f8362fe2a3f6.tar.gz sonarqube-a3f19897401c93d659d421fbb0d8f8362fe2a3f6.zip |
SONAR-11753 NotificationDaemon supports email specific algo
Diffstat (limited to 'server/sonar-server')
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; + } + }; + } +} |