diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2019-04-02 10:53:34 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-04-23 10:37:54 +0200 |
commit | 8420e1087f18f08d54d94e4f1a46770ca684ff9b (patch) | |
tree | 1c7c6fad4bd7389aad009f28f35fdb28974ab3f5 /server/sonar-server-common | |
parent | dfae66e01938fda55760991e65397f0d318c38c8 (diff) | |
download | sonarqube-8420e1087f18f08d54d94e4f1a46770ca684ff9b.tar.gz sonarqube-8420e1087f18f08d54d94e4f1a46770ca684ff9b.zip |
SONAR-11753 dont retrieve all subscribers if only interested in subset
Diffstat (limited to 'server/sonar-server-common')
7 files changed, 224 insertions, 59 deletions
diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandler.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandler.java index f6e69d39f9b..7d5e5243d74 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandler.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandler.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.CheckForNull; import org.sonar.server.notification.EmailNotificationHandler; @@ -89,8 +90,11 @@ public class ChangesOnMyIssueNotificationHandler extends EmailNotificationHandle } private Stream<? extends EmailDeliveryRequest> toEmailDeliveryRequests(String projectKey, Collection<IssueChangeNotification> notifications) { + Set<String> assignees = notifications.stream() + .map(IssueChangeNotification::getAssignee) + .collect(Collectors.toSet()); Map<String, EmailRecipient> recipientsByLogin = notificationManager - .findSubscribedEmailRecipients(KEY, projectKey, ALL_MUST_HAVE_ROLE_USER) + .findSubscribedEmailRecipients(KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER) .stream() .collect(uniqueIndex(EmailRecipient::getLogin)); return notifications.stream() diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandler.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandler.java index 84382720b83..9e4a19cc044 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandler.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandler.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.CheckForNull; import org.sonar.core.util.stream.MoreCollectors; @@ -84,8 +85,11 @@ public class MyNewIssuesNotificationHandler extends EmailNotificationHandler<MyN } private Stream<? extends EmailDeliveryRequest> toEmailDeliveryRequests(String projectKey, Collection<MyNewIssuesNotification> notifications) { + Set<String> assignees = notifications.stream() + .map(MyNewIssuesNotification::getAssignee) + .collect(Collectors.toSet()); Map<String, NotificationManager.EmailRecipient> recipientsByLogin = notificationManager - .findSubscribedEmailRecipients(KEY, projectKey, ALL_MUST_HAVE_ROLE_USER) + .findSubscribedEmailRecipients(KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER) .stream() .collect(MoreCollectors.uniqueIndex(NotificationManager.EmailRecipient::getLogin)); return notifications.stream() diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java b/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java index e1a2eae5b7b..1106e19e0fb 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/notification/DefaultNotificationManager.java @@ -188,16 +188,39 @@ public class DefaultNotificationManager implements NotificationManager { try (DbSession dbSession = dbClient.openSession(false)) { Set<EmailSubscriberDto> emailSubscribers = dbClient.propertiesDao().findEmailSubscribersForNotification( dbSession, dispatcherKey, EmailNotificationChannel.class.getSimpleName(), projectKey); - if (emailSubscribers.isEmpty()) { - return emptySet(); - } - return keepAuthorizedEmailSubscribers(dbSession, projectKey, emailSubscribers, subscriberPermissionsOnProject) - .map(emailSubscriber -> new EmailRecipient(emailSubscriber.getLogin(), emailSubscriber.getEmail())) - .collect(MoreCollectors.toSet()); + return keepAuthorizedEmailSubscribers(dbSession, projectKey, subscriberPermissionsOnProject, emailSubscribers); + } + } + + @Override + public Set<EmailRecipient> findSubscribedEmailRecipients(String dispatcherKey, String projectKey, Set<String> logins, + SubscriberPermissionsOnProject subscriberPermissionsOnProject) { + verifyProjectKey(projectKey); + requireNonNull(logins, "logins can't be null"); + if (logins.isEmpty()) { + return emptySet(); + } + + try (DbSession dbSession = dbClient.openSession(false)) { + Set<EmailSubscriberDto> emailSubscribers = dbClient.propertiesDao().findEmailSubscribersForNotification( + dbSession, dispatcherKey, EmailNotificationChannel.class.getSimpleName(), projectKey, logins); + + return keepAuthorizedEmailSubscribers(dbSession, projectKey, subscriberPermissionsOnProject, emailSubscribers); } } + private Set<EmailRecipient> keepAuthorizedEmailSubscribers(DbSession dbSession, String projectKey, + SubscriberPermissionsOnProject subscriberPermissionsOnProject, Set<EmailSubscriberDto> emailSubscribers) { + if (emailSubscribers.isEmpty()) { + return emptySet(); + } + + return keepAuthorizedEmailSubscribers(dbSession, projectKey, emailSubscribers, subscriberPermissionsOnProject) + .map(emailSubscriber -> new EmailRecipient(emailSubscriber.getLogin(), emailSubscriber.getEmail())) + .collect(MoreCollectors.toSet()); + } + private Stream<EmailSubscriberDto> keepAuthorizedEmailSubscribers(DbSession dbSession, String projectKey, Set<EmailSubscriberDto> emailSubscribers, SubscriberPermissionsOnProject requiredPermissions) { if (requiredPermissions.getGlobalSubscribers().equals(requiredPermissions.getProjectSubscribers())) { diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java b/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java index 6135dd4eb0c..13181fb4f2a 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/notification/NotificationManager.java @@ -63,6 +63,7 @@ public interface NotificationManager { Multimap<String, NotificationChannel> findSubscribedRecipientsForDispatcher(NotificationDispatcher dispatcher, String projectKey, SubscriberPermissionsOnProject subscriberPermissionsOnProject); + @Immutable final class EmailRecipient { private final String login; @@ -104,8 +105,21 @@ public interface NotificationManager { } } + /** + * Find login and email of users which have subscribed to the email notification of the specified {@code dispatcherKey}. + * <p> + * Obviously, only subscribers which have an email are returned. + */ Set<EmailRecipient> findSubscribedEmailRecipients(String dispatcherKey, String projectKey, SubscriberPermissionsOnProject subscriberPermissionsOnProject); + /** + * Find email of users with the specified {@code logins} which have subscribed to the email notification of the + * specified {@code dispatcherKey}. + * <p> + * Obviously, only subscribers which have an email are returned. + */ + Set<EmailRecipient> findSubscribedEmailRecipients(String dispatcherKey, String projectKey, Set<String> logins, SubscriberPermissionsOnProject subscriberPermissionsOnProject); + final class SubscriberPermissionsOnProject { public static final SubscriberPermissionsOnProject ALL_MUST_HAVE_ROLE_USER = new SubscriberPermissionsOnProject(UserRole.USER); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandlerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandlerTest.java index 6857262e9d8..60e859a8f5f 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandlerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/ChangesOnMyIssueNotificationHandlerTest.java @@ -36,7 +36,9 @@ import org.mockito.Mockito; import org.sonar.server.notification.NotificationDispatcherMetadata; import org.sonar.server.notification.NotificationManager; import org.sonar.server.notification.email.EmailNotificationChannel; +import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest; +import static java.util.Collections.singleton; import static java.util.stream.Collectors.toSet; import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; @@ -192,8 +194,8 @@ public class ChangesOnMyIssueNotificationHandlerTest { int deliver = underTest.deliver(Stream.concat(notifications1.stream(), notifications2.stream()).collect(toSet())); assertThat(deliver).isZero(); - verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER); - verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey1, singleton(assignee1), ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey2, singleton(assignee2), ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verifyNoMoreInteractions(emailNotificationChannel); @@ -205,17 +207,15 @@ public class ChangesOnMyIssueNotificationHandlerTest { String projectKey = randomAlphabetic(5); String assignee1 = randomAlphabetic(6); String assignee2 = randomAlphabetic(7); - String assignee3 = randomAlphabetic(8); // assignee1 is not authorized Set<IssueChangeNotification> assignee1Notifications = randomSetOfNotifications(projectKey, assignee1, noOrDifferentChangeAuthor); // assignee2 is authorized Set<IssueChangeNotification> assignee2Notifications = randomSetOfNotifications(projectKey, assignee2, noOrDifferentChangeAuthor); - // assignee3 is authorized but has no notification when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) - .thenReturn(ImmutableSet.of(emailRecipientOf(assignee2), emailRecipientOf(assignee3))); - Set<EmailNotificationChannel.EmailDeliveryRequest> expectedRequests = assignee2Notifications.stream() - .map(t -> new EmailNotificationChannel.EmailDeliveryRequest(emailOf(t.getAssignee()), t)) + when(notificationManager.findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ImmutableSet.of(assignee1, assignee2), ALL_MUST_HAVE_ROLE_USER)) + .thenReturn(ImmutableSet.of(emailRecipientOf(assignee2))); + Set<EmailDeliveryRequest> expectedRequests = assignee2Notifications.stream() + .map(t -> new EmailDeliveryRequest(emailOf(t.getAssignee()), t)) .collect(toSet()); int deliveredCount = new Random().nextInt(expectedRequests.size()); when(emailNotificationChannel.deliver(expectedRequests)).thenReturn(deliveredCount); @@ -223,7 +223,7 @@ public class ChangesOnMyIssueNotificationHandlerTest { int deliver = underTest.deliver(Stream.concat(assignee1Notifications.stream(), assignee2Notifications.stream()).collect(toSet())); assertThat(deliver).isEqualTo(deliveredCount); - verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ImmutableSet.of(assignee1, assignee2), ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); @@ -238,22 +238,23 @@ public class ChangesOnMyIssueNotificationHandlerTest { String assignee3 = randomAlphabetic(8); // assignee1 is the changeAuthor of every notification he's the assignee of Set<IssueChangeNotification> assignee1ChangeAuthor = randomSetOfNotifications(projectKey, assignee1, assignee1); - // assignee1 is the changeAuthor of some notification he's the assignee of + // assignee2 is the changeAuthor of some notification he's the assignee of Set<IssueChangeNotification> assignee2ChangeAuthor = randomSetOfNotifications(projectKey, assignee2, assignee2); Set<IssueChangeNotification> assignee2NotChangeAuthor = randomSetOfNotifications(projectKey, assignee2, randomAlphabetic(10)); Set<IssueChangeNotification> assignee2NoChangeAuthor = randomSetOfNotifications(projectKey, assignee2, NO_CHANGE_AUTHOR); - // assignee2 is never the changeAuthor of the notification he's the assignee of + // assignee3 is never the changeAuthor of the notification he's the assignee of Set<IssueChangeNotification> assignee3NotChangeAuthor = randomSetOfNotifications(projectKey, assignee3, randomAlphabetic(11)); Set<IssueChangeNotification> assignee3NoChangeAuthor = randomSetOfNotifications(projectKey, assignee3, NO_CHANGE_AUTHOR); when(emailNotificationChannel.isActivated()).thenReturn(true); - // all assignees have subscribed - when(notificationManager.findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) - .thenReturn(ImmutableSet.of(emailRecipientOf(assignee1), emailRecipientOf(assignee2), emailRecipientOf(assignee3))); - Set<EmailNotificationChannel.EmailDeliveryRequest> expectedRequests = Stream.of( + // assignees which are not changeAuthor have subscribed + Set<String> assigneesChangeAuthor = ImmutableSet.of(assignee2, assignee3); + when(notificationManager.findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, assigneesChangeAuthor, ALL_MUST_HAVE_ROLE_USER)) + .thenReturn(ImmutableSet.of(emailRecipientOf(assignee2), emailRecipientOf(assignee3))); + Set<EmailDeliveryRequest> expectedRequests = Stream.of( assignee2NotChangeAuthor.stream(), assignee2NoChangeAuthor.stream(), assignee3NotChangeAuthor.stream(), assignee3NoChangeAuthor.stream()) .flatMap(t -> t) - .map(t -> new EmailNotificationChannel.EmailDeliveryRequest(emailOf(t.getAssignee()), t)) + .map(t -> new EmailDeliveryRequest(emailOf(t.getAssignee()), t)) .collect(toSet()); int deliveredCount = new Random().nextInt(expectedRequests.size()); when(emailNotificationChannel.deliver(expectedRequests)).thenReturn(deliveredCount); @@ -266,7 +267,7 @@ public class ChangesOnMyIssueNotificationHandlerTest { int deliver = underTest.deliver(notifications); assertThat(deliver).isEqualTo(deliveredCount); - verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(CHANGE_ON_MY_ISSUES_DISPATCHER_KEY, projectKey, assigneesChangeAuthor, ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandlerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandlerTest.java index 6a85a4ddc9f..365d3e867f9 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandlerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/notification/MyNewIssuesNotificationHandlerTest.java @@ -19,7 +19,6 @@ */ package org.sonar.server.issue.notification; -import com.google.common.collect.ImmutableSet; import java.util.Collections; import java.util.Random; import java.util.Set; @@ -35,6 +34,7 @@ import org.sonar.server.notification.NotificationManager.EmailRecipient; import org.sonar.server.notification.email.EmailNotificationChannel; import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest; +import static com.google.common.collect.ImmutableSet.of; import static java.util.Collections.emptySet; import static java.util.stream.Collectors.toSet; import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; @@ -156,13 +156,13 @@ public class MyNewIssuesNotificationHandlerTest { String assignee = randomAlphabetic(10); MyNewIssuesNotification notification = newNotification(projectKey, assignee); when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, of(assignee), ALL_MUST_HAVE_ROLE_USER)) .thenReturn(emptySet()); int deliver = underTest.deliver(Collections.singleton(notification)); assertThat(deliver).isZero(); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, of(assignee), ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verifyNoMoreInteractions(emailNotificationChannel); @@ -185,7 +185,8 @@ public class MyNewIssuesNotificationHandlerTest { .map(n -> new EmailDeliveryRequest(n.getAssignee() + "@foo", n)) .collect(toSet()); when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) + Set<String> assignees = withProjectKey.stream().map(MyNewIssuesNotification::getAssignee).collect(toSet()); + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER)) .thenReturn(authorizedRecipients); Set<MyNewIssuesNotification> notifications = Stream.of(withProjectKey.stream(), noProjectKey.stream(), noProjectKeyNoAssignee.stream()) @@ -194,7 +195,7 @@ public class MyNewIssuesNotificationHandlerTest { int deliver = underTest.deliver(notifications); assertThat(deliver).isZero(); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); @@ -216,7 +217,8 @@ public class MyNewIssuesNotificationHandlerTest { .map(n -> new EmailDeliveryRequest(n.getAssignee() + "@foo", n)) .collect(toSet()); when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) + Set<String> assignees = withAssignee.stream().map(MyNewIssuesNotification::getAssignee).collect(toSet()); + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER)) .thenReturn(authorizedRecipients); Set<MyNewIssuesNotification> notifications = Stream.of(withAssignee.stream(), noAssignee.stream(), noProjectKeyNoAssignee.stream()) @@ -225,7 +227,7 @@ public class MyNewIssuesNotificationHandlerTest { int deliver = underTest.deliver(notifications); assertThat(deliver).isZero(); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); @@ -241,16 +243,16 @@ public class MyNewIssuesNotificationHandlerTest { Set<MyNewIssuesNotification> notifications1 = randomSetOfNotifications(projectKey1, assignee1); Set<MyNewIssuesNotification> notifications2 = randomSetOfNotifications(projectKey2, assignee2); when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER)) + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, of(assignee1), ALL_MUST_HAVE_ROLE_USER)) .thenReturn(emptySet()); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER)) + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, of(assignee2),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(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, of(assignee1), ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, of(assignee2), ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verifyNoMoreInteractions(emailNotificationChannel); @@ -261,15 +263,14 @@ public class MyNewIssuesNotificationHandlerTest { String projectKey = randomAlphabetic(5); String assignee1 = randomAlphabetic(6); String assignee2 = randomAlphabetic(7); - String assignee3 = randomAlphabetic(8); + Set<String> assignees = of(assignee1, assignee2); // assignee1 is not authorized Set<MyNewIssuesNotification> assignee1Notifications = randomSetOfNotifications(projectKey, assignee1); // assignee2 is authorized Set<MyNewIssuesNotification> assignee2Notifications = randomSetOfNotifications(projectKey, assignee2); - // assignee 3 is authorized but has no notification when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER)) - .thenReturn(ImmutableSet.of(emailRecipientOf(assignee2), emailRecipientOf(assignee3))); + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER)) + .thenReturn(of(emailRecipientOf(assignee2))); Set<EmailDeliveryRequest> expectedRequests = assignee2Notifications.stream() .map(t -> new EmailDeliveryRequest(emailOf(t.getAssignee()), t)) .collect(toSet()); @@ -279,7 +280,7 @@ public class MyNewIssuesNotificationHandlerTest { int deliver = underTest.deliver(Stream.concat(assignee1Notifications.stream(), assignee2Notifications.stream()).collect(toSet())); assertThat(deliver).isEqualTo(deliveredCount); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey, assignees, ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); @@ -305,11 +306,11 @@ public class MyNewIssuesNotificationHandlerTest { Set<MyNewIssuesNotification> assignee3Project2 = randomSetOfNotifications(projectKey2, assignee3); Set<MyNewIssuesNotification> assignee3Project3 = randomSetOfNotifications(projectKey3, assignee3); when(emailNotificationChannel.isActivated()).thenReturn(true); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER)) - .thenReturn(ImmutableSet.of(emailRecipientOf(assignee1), emailRecipientOf(assignee2))); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER)) - .thenReturn(ImmutableSet.of(emailRecipientOf(assignee2), emailRecipientOf(assignee3))); - when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey3, ALL_MUST_HAVE_ROLE_USER)) + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, of(assignee1, assignee2), ALL_MUST_HAVE_ROLE_USER)) + .thenReturn(of(emailRecipientOf(assignee1), emailRecipientOf(assignee2))); + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, of(assignee1, assignee2, assignee3), ALL_MUST_HAVE_ROLE_USER)) + .thenReturn(of(emailRecipientOf(assignee2), emailRecipientOf(assignee3))); + when(notificationManager.findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey3, of(assignee2, assignee3), ALL_MUST_HAVE_ROLE_USER)) .thenReturn(emptySet()); Set<EmailDeliveryRequest> expectedRequests = Stream.of( assignee1Project1.stream(), assignee2Project1.stream(), assignee2Project2.stream(), assignee3Project2.stream()) @@ -328,9 +329,9 @@ public class MyNewIssuesNotificationHandlerTest { int deliver = underTest.deliver(notifications); assertThat(deliver).isEqualTo(deliveredCount); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, ALL_MUST_HAVE_ROLE_USER); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, ALL_MUST_HAVE_ROLE_USER); - verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey3, ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey1, of(assignee1, assignee2), ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey2, of(assignee1, assignee2, assignee3), ALL_MUST_HAVE_ROLE_USER); + verify(notificationManager).findSubscribedEmailRecipients(MY_NEW_ISSUES_DISPATCHER_KEY, projectKey3, of(assignee2, assignee3), ALL_MUST_HAVE_ROLE_USER); verifyNoMoreInteractions(notificationManager); verify(emailNotificationChannel).isActivated(); verify(emailNotificationChannel).deliver(expectedRequests); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java index a78a8c5e985..d1520314553 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/notification/DefaultNotificationManagerTest.java @@ -272,6 +272,37 @@ public class DefaultNotificationManagerTest { } @Test + public void findSubscribedEmailRecipients_with_logins_fails_with_NPE_if_projectKey_is_null() { + String dispatcherKey = randomAlphabetic(12); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("projectKey is mandatory"); + + underTest.findSubscribedEmailRecipients(dispatcherKey, null, ImmutableSet.of(), ALL_MUST_HAVE_ROLE_USER); + } + + @Test + public void findSubscribedEmailRecipients_with_logins_fails_with_NPE_if_logins_is_null() { + String dispatcherKey = randomAlphabetic(12); + String projectKey = randomAlphabetic(6); + + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("logins can't be null"); + + underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, null, ALL_MUST_HAVE_ROLE_USER); + } + + @Test + public void findSubscribedEmailRecipients_with_logins_returns_empty_if_login_set_is_empty() { + String dispatcherKey = randomAlphabetic(12); + String projectKey = randomAlphabetic(6); + + Set<EmailRecipient> recipients = underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, ImmutableSet.of(), ALL_MUST_HAVE_ROLE_USER); + + assertThat(recipients).isEmpty(); + } + + @Test public void findSubscribedEmailRecipients_returns_empty_if_no_email_recipients_in_project_for_dispatcher_key() { String dispatcherKey = randomAlphabetic(12); String globalPermission = randomAlphanumeric(4); @@ -288,21 +319,33 @@ public class DefaultNotificationManagerTest { } @Test + public void findSubscribedEmailRecipients_with_logins_returns_empty_if_no_email_recipients_in_project_for_dispatcher_key() { + String dispatcherKey = randomAlphabetic(12); + String globalPermission = randomAlphanumeric(4); + String projectPermission = randomAlphanumeric(5); + String projectKey = randomAlphabetic(6); + Set<String> logins = IntStream.range(0, 1 + new Random().nextInt(10)) + .mapToObj(i -> "login_" + i) + .collect(Collectors.toSet()); + when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey, logins)) + .thenReturn(Collections.emptySet()); + + Set<EmailRecipient> emailRecipients = underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, logins, + new SubscriberPermissionsOnProject(globalPermission, projectPermission)); + assertThat(emailRecipients).isEmpty(); + + verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(any(DbSession.class), anySet(), anyString(), anyString()); + } + + @Test public void findSubscribedEmailRecipients_applies_distinct_permission_filtering_global_or_project_subscribers() { String dispatcherKey = randomAlphabetic(12); - String otherDispatcherKey = randomAlphabetic(13); String globalPermission = randomAlphanumeric(4); String projectPermission = randomAlphanumeric(5); String projectKey = randomAlphabetic(6); - String otherProjectKey = randomAlphabetic(7); when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey)) .thenReturn( newHashSet(new EmailSubscriberDto("user1", false, "user1@foo"), new EmailSubscriberDto("user3", false, "user3@foo"), new EmailSubscriberDto("user3", true, "user3@foo"))); - when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", otherProjectKey)) - .thenReturn(newHashSet(new EmailSubscriberDto("user2", false, "user2@foo"))); - when(propertiesDao.findEmailSubscribersForNotification(dbSession, otherDispatcherKey, "EmailNotificationChannel", projectKey)) - .thenReturn(newHashSet(new EmailSubscriberDto("user4", true, "user4@foo"))); - when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3", "user4"), projectKey, globalPermission)) .thenReturn(newHashSet("user3")); when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectKey, projectPermission)) @@ -319,7 +362,32 @@ public class DefaultNotificationManagerTest { } @Test - public void findSubscribedEmailRecipients_do_not_call_db_for_project_permission_filtering_if_there_is_no_project_subscriber() { + public void findSubscribedEmailRecipients_with_logins_applies_distinct_permission_filtering_global_or_project_subscribers() { + String dispatcherKey = randomAlphabetic(12); + String globalPermission = randomAlphanumeric(4); + String projectPermission = randomAlphanumeric(5); + String projectKey = randomAlphabetic(6); + Set<String> logins = ImmutableSet.of("user1", "user2", "user3"); + when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey, logins)) + .thenReturn( + newHashSet(new EmailSubscriberDto("user1", false, "user1@foo"), new EmailSubscriberDto("user3", false, "user3@foo"), new EmailSubscriberDto("user3", true, "user3@foo"))); + when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user3", "user4"), projectKey, globalPermission)) + .thenReturn(newHashSet("user3")); + when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, newHashSet("user1", "user3"), projectKey, projectPermission)) + .thenReturn(newHashSet("user1", "user3")); + + Set<EmailRecipient> emailRecipients = underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, logins, + new SubscriberPermissionsOnProject(globalPermission, projectPermission)); + assertThat(emailRecipients) + .isEqualTo(ImmutableSet.of(new EmailRecipient("user1", "user1@foo"), new EmailRecipient("user3", "user3@foo"))); + + // code is optimized to perform only 2 SQL requests for all channels + verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); + verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); + } + + @Test + public void findSubscribedEmailRecipients_does_not_call_db_for_project_permission_filtering_if_there_is_no_project_subscriber() { String dispatcherKey = randomAlphabetic(12); String globalPermission = randomAlphanumeric(4); String projectPermission = randomAlphanumeric(5); @@ -327,9 +395,9 @@ public class DefaultNotificationManagerTest { Set<EmailSubscriberDto> subscribers = IntStream.range(0, 1 + new Random().nextInt(10)) .mapToObj(i -> new EmailSubscriberDto("user" + i, true, "user" + i + "@sonarsource.com")) .collect(Collectors.toSet()); + Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey)) .thenReturn(subscribers); - Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, logins, projectKey, globalPermission)) .thenReturn(logins); @@ -344,6 +412,31 @@ public class DefaultNotificationManagerTest { } @Test + public void findSubscribedEmailRecipients_with_logins_does_not_call_db_for_project_permission_filtering_if_there_is_no_project_subscriber() { + String dispatcherKey = randomAlphabetic(12); + String globalPermission = randomAlphanumeric(4); + String projectPermission = randomAlphanumeric(5); + String projectKey = randomAlphabetic(6); + Set<EmailSubscriberDto> subscribers = IntStream.range(0, 1 + new Random().nextInt(10)) + .mapToObj(i -> new EmailSubscriberDto("user" + i, true, "user" + i + "@sonarsource.com")) + .collect(Collectors.toSet()); + Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); + when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey, logins)) + .thenReturn(subscribers); + when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, logins, projectKey, globalPermission)) + .thenReturn(logins); + + Set<EmailRecipient> emailRecipients = underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, logins, + new SubscriberPermissionsOnProject(globalPermission, projectPermission)); + Set<EmailRecipient> expected = subscribers.stream().map(i -> new EmailRecipient(i.getLogin(), i.getEmail())).collect(Collectors.toSet()); + assertThat(emailRecipients) + .isEqualTo(expected); + + verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); + verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); + } + + @Test public void findSubscribedEmailRecipients_does_not_call_DB_for_project_permission_filtering_if_there_is_no_global_subscriber() { String dispatcherKey = randomAlphabetic(12); String globalPermission = randomAlphanumeric(4); @@ -352,9 +445,9 @@ public class DefaultNotificationManagerTest { Set<EmailSubscriberDto> subscribers = IntStream.range(0, 1 + new Random().nextInt(10)) .mapToObj(i -> new EmailSubscriberDto("user" + i, false, "user" + i + "@sonarsource.com")) .collect(Collectors.toSet()); + Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey)) .thenReturn(subscribers); - Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, logins, projectKey, projectPermission)) .thenReturn(logins); @@ -367,4 +460,29 @@ public class DefaultNotificationManagerTest { verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); } + + @Test + public void findSubscribedEmailRecipients_with_logins_does_not_call_DB_for_project_permission_filtering_if_there_is_no_global_subscriber() { + String dispatcherKey = randomAlphabetic(12); + String globalPermission = randomAlphanumeric(4); + String projectPermission = randomAlphanumeric(5); + String projectKey = randomAlphabetic(6); + Set<EmailSubscriberDto> subscribers = IntStream.range(0, 1 + new Random().nextInt(10)) + .mapToObj(i -> new EmailSubscriberDto("user" + i, false, "user" + i + "@sonarsource.com")) + .collect(Collectors.toSet()); + Set<String> logins = subscribers.stream().map(EmailSubscriberDto::getLogin).collect(Collectors.toSet()); + when(propertiesDao.findEmailSubscribersForNotification(dbSession, dispatcherKey, "EmailNotificationChannel", projectKey, logins)) + .thenReturn(subscribers); + when(authorizationDao.keepAuthorizedLoginsOnProject(dbSession, logins, projectKey, projectPermission)) + .thenReturn(logins); + + Set<EmailRecipient> emailRecipients = underTest.findSubscribedEmailRecipients(dispatcherKey, projectKey, logins, + new SubscriberPermissionsOnProject(globalPermission, projectPermission)); + Set<EmailRecipient> expected = subscribers.stream().map(i -> new EmailRecipient(i.getLogin(), i.getEmail())).collect(Collectors.toSet()); + assertThat(emailRecipients) + .isEqualTo(expected); + + verify(authorizationDao, times(0)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(globalPermission)); + verify(authorizationDao, times(1)).keepAuthorizedLoginsOnProject(eq(dbSession), anySet(), anyString(), eq(projectPermission)); + } } |