You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ReportAnalysisFailureNotificationHandlerTest.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.ce.task.projectanalysis.notification;
  21. import java.util.Collections;
  22. import java.util.Random;
  23. import java.util.Set;
  24. import java.util.stream.Collectors;
  25. import java.util.stream.IntStream;
  26. import java.util.stream.Stream;
  27. import javax.annotation.Nullable;
  28. import org.junit.Test;
  29. import org.mockito.Mockito;
  30. import org.sonar.api.web.UserRole;
  31. import org.sonar.server.notification.NotificationDispatcherMetadata;
  32. import org.sonar.server.notification.NotificationManager;
  33. import org.sonar.server.notification.NotificationManager.EmailRecipient;
  34. import org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject;
  35. import org.sonar.server.notification.email.EmailNotificationChannel;
  36. import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest;
  37. import static java.util.Collections.emptySet;
  38. import static java.util.stream.Collectors.toSet;
  39. import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
  40. import static org.assertj.core.api.Assertions.assertThat;
  41. import static org.mockito.Mockito.mock;
  42. import static org.mockito.Mockito.verify;
  43. import static org.mockito.Mockito.verifyNoInteractions;
  44. import static org.mockito.Mockito.verifyNoMoreInteractions;
  45. import static org.mockito.Mockito.when;
  46. import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
  47. import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
  48. public class ReportAnalysisFailureNotificationHandlerTest {
  49. private static final String REPORT_FAILURE_DISPATCHER_KEY = "CeReportTaskFailure";
  50. private static final SubscriberPermissionsOnProject REQUIRED_SUBSCRIBER_PERMISSIONS = new SubscriberPermissionsOnProject(UserRole.ADMIN, UserRole.USER);
  51. private NotificationManager notificationManager = mock(NotificationManager.class);
  52. private EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class);
  53. private ReportAnalysisFailureNotificationHandler underTest = new ReportAnalysisFailureNotificationHandler(notificationManager, emailNotificationChannel);
  54. @Test
  55. public void getMetadata_returns_same_instance_as_static_method() {
  56. assertThat(underTest.getMetadata()).containsSame(ReportAnalysisFailureNotificationHandler.newMetadata());
  57. }
  58. @Test
  59. public void verify_reportFailures_notification_dispatcher_key() {
  60. NotificationDispatcherMetadata metadata = ReportAnalysisFailureNotificationHandler.newMetadata();
  61. assertThat(metadata.getDispatcherKey()).isEqualTo(REPORT_FAILURE_DISPATCHER_KEY);
  62. }
  63. @Test
  64. public void reportFailures_notification_is_enable_at_global_level() {
  65. NotificationDispatcherMetadata metadata = ReportAnalysisFailureNotificationHandler.newMetadata();
  66. assertThat(metadata.getProperty(GLOBAL_NOTIFICATION)).isEqualTo("true");
  67. }
  68. @Test
  69. public void reportFailures_notification_is_enable_at_project_level() {
  70. NotificationDispatcherMetadata metadata = ReportAnalysisFailureNotificationHandler.newMetadata();
  71. assertThat(metadata.getProperty(PER_PROJECT_NOTIFICATION)).isEqualTo("true");
  72. }
  73. @Test
  74. public void getNotificationClass_is_ReportAnalysisFailureNotification() {
  75. assertThat(underTest.getNotificationClass()).isEqualTo(ReportAnalysisFailureNotification.class);
  76. }
  77. @Test
  78. public void deliver_has_no_effect_if_notifications_is_empty() {
  79. when(emailNotificationChannel.isActivated()).thenReturn(true);
  80. int deliver = underTest.deliver(Collections.emptyList());
  81. assertThat(deliver).isZero();
  82. verifyNoInteractions(notificationManager, emailNotificationChannel);
  83. }
  84. @Test
  85. public void deliver_has_no_effect_if_emailNotificationChannel_is_disabled() {
  86. when(emailNotificationChannel.isActivated()).thenReturn(false);
  87. Set<ReportAnalysisFailureNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
  88. .mapToObj(i -> mock(ReportAnalysisFailureNotification.class))
  89. .collect(toSet());
  90. int deliver = underTest.deliver(notifications);
  91. assertThat(deliver).isZero();
  92. verifyNoInteractions(notificationManager);
  93. verify(emailNotificationChannel).isActivated();
  94. verifyNoMoreInteractions(emailNotificationChannel);
  95. notifications.forEach(Mockito::verifyNoInteractions);
  96. }
  97. @Test
  98. public void deliver_has_no_effect_if_no_notification_has_projectKey() {
  99. when(emailNotificationChannel.isActivated()).thenReturn(true);
  100. Set<ReportAnalysisFailureNotification> notifications = IntStream.range(0, 1 + new Random().nextInt(10))
  101. .mapToObj(i -> newNotification(null))
  102. .collect(toSet());
  103. int deliver = underTest.deliver(notifications);
  104. assertThat(deliver).isZero();
  105. verifyNoInteractions(notificationManager);
  106. verify(emailNotificationChannel).isActivated();
  107. verifyNoMoreInteractions(emailNotificationChannel);
  108. notifications.forEach(notification -> {
  109. verify(notification).getProjectKey();
  110. verifyNoMoreInteractions(notification);
  111. });
  112. }
  113. @Test
  114. public void deliver_has_no_effect_if_no_notification_has_subscribed_recipients_to_ReportFailure_notifications() {
  115. String projectKey = randomAlphabetic(12);
  116. ReportAnalysisFailureNotification notification = newNotification(projectKey);
  117. when(emailNotificationChannel.isActivated()).thenReturn(true);
  118. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey, REQUIRED_SUBSCRIBER_PERMISSIONS))
  119. .thenReturn(emptySet());
  120. int deliver = underTest.deliver(Collections.singleton(notification));
  121. assertThat(deliver).isZero();
  122. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey, REQUIRED_SUBSCRIBER_PERMISSIONS);
  123. verifyNoMoreInteractions(notificationManager);
  124. verify(emailNotificationChannel).isActivated();
  125. verifyNoMoreInteractions(emailNotificationChannel);
  126. }
  127. @Test
  128. public void deliver_ignores_notification_without_projectKey() {
  129. String projectKey = randomAlphabetic(10);
  130. Set<ReportAnalysisFailureNotification> withProjectKey = IntStream.range(0, 1 + new Random().nextInt(5))
  131. .mapToObj(i -> newNotification(projectKey))
  132. .collect(toSet());
  133. Set<ReportAnalysisFailureNotification> noProjectKey = IntStream.range(0, 1 + new Random().nextInt(5))
  134. .mapToObj(i -> newNotification(null))
  135. .collect(toSet());
  136. Set<EmailRecipient> emailRecipients = IntStream.range(0, 1 + new Random().nextInt(10))
  137. .mapToObj(i -> "user_" + i)
  138. .map(login -> new EmailRecipient(login, emailOf(login)))
  139. .collect(toSet());
  140. Set<EmailDeliveryRequest> expectedRequests = emailRecipients.stream()
  141. .flatMap(emailRecipient -> withProjectKey.stream().map(notif -> new EmailDeliveryRequest(emailRecipient.email(), notif)))
  142. .collect(toSet());
  143. when(emailNotificationChannel.isActivated()).thenReturn(true);
  144. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey, REQUIRED_SUBSCRIBER_PERMISSIONS))
  145. .thenReturn(emailRecipients);
  146. Set<ReportAnalysisFailureNotification> notifications = Stream.of(withProjectKey.stream(), noProjectKey.stream())
  147. .flatMap(t -> t)
  148. .collect(toSet());
  149. int deliver = underTest.deliver(notifications);
  150. assertThat(deliver).isZero();
  151. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey, REQUIRED_SUBSCRIBER_PERMISSIONS);
  152. verifyNoMoreInteractions(notificationManager);
  153. verify(emailNotificationChannel).isActivated();
  154. verify(emailNotificationChannel).deliverAll(expectedRequests);
  155. verifyNoMoreInteractions(emailNotificationChannel);
  156. }
  157. @Test
  158. public void deliver_checks_by_projectKey_if_notifications_have_subscribed_assignee_to_ReportFailure_notifications() {
  159. String projectKey1 = randomAlphabetic(10);
  160. String projectKey2 = randomAlphabetic(11);
  161. Set<ReportAnalysisFailureNotification> notifications1 = randomSetOfNotifications(projectKey1);
  162. Set<ReportAnalysisFailureNotification> notifications2 = randomSetOfNotifications(projectKey2);
  163. when(emailNotificationChannel.isActivated()).thenReturn(true);
  164. Set<EmailRecipient> emailRecipients1 = IntStream.range(0, 1 + new Random().nextInt(10))
  165. .mapToObj(i -> "user1_" + i)
  166. .map(login -> new EmailRecipient(login, emailOf(login)))
  167. .collect(toSet());
  168. Set<EmailRecipient> emailRecipients2 = IntStream.range(0, 1 + new Random().nextInt(10))
  169. .mapToObj(i -> "user2_" + i)
  170. .map(login -> new EmailRecipient(login, emailOf(login)))
  171. .collect(toSet());
  172. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey1, REQUIRED_SUBSCRIBER_PERMISSIONS))
  173. .thenReturn(emailRecipients1);
  174. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey2, REQUIRED_SUBSCRIBER_PERMISSIONS))
  175. .thenReturn(emailRecipients2);
  176. Set<EmailDeliveryRequest> expectedRequests = Stream.concat(
  177. emailRecipients1.stream()
  178. .flatMap(emailRecipient -> notifications1.stream().map(notif -> new EmailDeliveryRequest(emailRecipient.email(), notif))),
  179. emailRecipients2.stream()
  180. .flatMap(emailRecipient -> notifications2.stream().map(notif -> new EmailDeliveryRequest(emailRecipient.email(), notif))))
  181. .collect(toSet());
  182. int deliver = underTest.deliver(Stream.concat(notifications1.stream(), notifications2.stream()).collect(toSet()));
  183. assertThat(deliver).isZero();
  184. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey1, REQUIRED_SUBSCRIBER_PERMISSIONS);
  185. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey2, REQUIRED_SUBSCRIBER_PERMISSIONS);
  186. verifyNoMoreInteractions(notificationManager);
  187. verify(emailNotificationChannel).isActivated();
  188. verify(emailNotificationChannel).deliverAll(expectedRequests);
  189. verifyNoMoreInteractions(emailNotificationChannel);
  190. }
  191. @Test
  192. public void deliver_send_notifications_to_all_subscribers_of_all_projects() {
  193. String projectKey1 = randomAlphabetic(10);
  194. String projectKey2 = randomAlphabetic(11);
  195. Set<ReportAnalysisFailureNotification> notifications1 = randomSetOfNotifications(projectKey1);
  196. Set<ReportAnalysisFailureNotification> notifications2 = randomSetOfNotifications(projectKey2);
  197. when(emailNotificationChannel.isActivated()).thenReturn(true);
  198. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey1, REQUIRED_SUBSCRIBER_PERMISSIONS))
  199. .thenReturn(emptySet());
  200. when(notificationManager.findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey2, REQUIRED_SUBSCRIBER_PERMISSIONS))
  201. .thenReturn(emptySet());
  202. int deliver = underTest.deliver(Stream.concat(notifications1.stream(), notifications2.stream()).collect(toSet()));
  203. assertThat(deliver).isZero();
  204. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey1, REQUIRED_SUBSCRIBER_PERMISSIONS);
  205. verify(notificationManager).findSubscribedEmailRecipients(REPORT_FAILURE_DISPATCHER_KEY, projectKey2, REQUIRED_SUBSCRIBER_PERMISSIONS);
  206. verifyNoMoreInteractions(notificationManager);
  207. verify(emailNotificationChannel).isActivated();
  208. verifyNoMoreInteractions(emailNotificationChannel);
  209. }
  210. private static Set<ReportAnalysisFailureNotification> randomSetOfNotifications(@Nullable String projectKey) {
  211. return IntStream.range(0, 1 + new Random().nextInt(5))
  212. .mapToObj(i -> newNotification(projectKey))
  213. .collect(Collectors.toSet());
  214. }
  215. private static ReportAnalysisFailureNotification newNotification(@Nullable String projectKey) {
  216. ReportAnalysisFailureNotification notification = mock(ReportAnalysisFailureNotification.class);
  217. when(notification.getProjectKey()).thenReturn(projectKey);
  218. return notification;
  219. }
  220. private static String emailOf(String assignee1) {
  221. return assignee1 + "@house";
  222. }
  223. }