3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.issue.notification;
22 import com.google.common.collect.ImmutableSet;
23 import com.google.common.collect.ListMultimap;
24 import com.tngtech.java.junit.dataprovider.DataProvider;
25 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
26 import com.tngtech.java.junit.dataprovider.UseDataProvider;
28 import java.util.function.Consumer;
29 import java.util.stream.IntStream;
30 import java.util.stream.Stream;
31 import org.junit.Test;
32 import org.junit.runner.RunWith;
33 import org.mockito.ArgumentCaptor;
34 import org.mockito.Mockito;
35 import org.sonar.api.issue.Issue;
36 import org.sonar.api.issue.IssueStatus;
37 import org.sonar.server.issue.notification.FPOrAcceptedNotification.FpPrAccepted;
38 import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Change;
39 import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.ChangedIssue;
40 import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.Project;
41 import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.User;
42 import org.sonar.server.issue.notification.IssuesChangesNotificationBuilder.UserChange;
43 import org.sonar.server.notification.NotificationDispatcherMetadata;
44 import org.sonar.server.notification.NotificationManager;
45 import org.sonar.server.notification.email.EmailNotificationChannel;
46 import org.sonar.server.notification.email.EmailNotificationChannel.EmailDeliveryRequest;
48 import static java.util.Collections.singleton;
49 import static java.util.stream.Collectors.toSet;
50 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
51 import static org.assertj.core.api.Assertions.assertThat;
52 import static org.junit.Assert.fail;
53 import static org.mockito.ArgumentMatchers.any;
54 import static org.mockito.ArgumentMatchers.anySet;
55 import static org.mockito.Mockito.mock;
56 import static org.mockito.Mockito.reset;
57 import static org.mockito.Mockito.spy;
58 import static org.mockito.Mockito.times;
59 import static org.mockito.Mockito.verify;
60 import static org.mockito.Mockito.verifyNoInteractions;
61 import static org.mockito.Mockito.verifyNoMoreInteractions;
62 import static org.mockito.Mockito.when;
63 import static org.sonar.api.issue.Issue.RESOLUTION_FALSE_POSITIVE;
64 import static org.sonar.core.util.stream.MoreCollectors.index;
65 import static org.sonar.server.issue.notification.IssuesChangesNotificationBuilderTesting.newProject;
66 import static org.sonar.server.issue.notification.IssuesChangesNotificationBuilderTesting.newRandomNotAHotspotRule;
67 import static org.sonar.server.notification.NotificationDispatcherMetadata.GLOBAL_NOTIFICATION;
68 import static org.sonar.server.notification.NotificationDispatcherMetadata.PER_PROJECT_NOTIFICATION;
69 import static org.sonar.server.notification.NotificationManager.SubscriberPermissionsOnProject.ALL_MUST_HAVE_ROLE_USER;
71 @RunWith(DataProviderRunner.class)
72 public class FPOrAcceptedNotificationHandlerTest {
73 private static final String DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY = "NewFalsePositiveIssue";
74 private NotificationManager notificationManager = mock(NotificationManager.class);
75 private EmailNotificationChannel emailNotificationChannel = mock(EmailNotificationChannel.class);
76 private IssuesChangesNotificationSerializer serializerMock = mock(IssuesChangesNotificationSerializer.class);
77 private IssuesChangesNotificationSerializer serializer = spy(new IssuesChangesNotificationSerializer());
78 private Class<Set<EmailDeliveryRequest>> requestSetType = (Class<Set<EmailDeliveryRequest>>) (Class<?>) Set.class;
79 private FPOrAcceptedNotificationHandler underTest = new FPOrAcceptedNotificationHandler(notificationManager, emailNotificationChannel, serializer);
82 public void getMetadata_returns_same_instance_as_static_method() {
83 assertThat(underTest.getMetadata()).containsSame(FPOrAcceptedNotificationHandler.newMetadata());
87 public void verify_fpOrWontFixIssues_notification_dispatcher_key() {
88 NotificationDispatcherMetadata metadata = FPOrAcceptedNotificationHandler.newMetadata();
90 assertThat(metadata.getDispatcherKey()).isEqualTo(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY);
94 public void fpOrWontFixIssues_notification_is_disabled_at_global_level() {
95 NotificationDispatcherMetadata metadata = FPOrAcceptedNotificationHandler.newMetadata();
97 assertThat(metadata.getProperty(GLOBAL_NOTIFICATION)).isEqualTo("false");
101 public void fpOrWontFixIssues_notification_is_enable_at_project_level() {
102 NotificationDispatcherMetadata metadata = FPOrAcceptedNotificationHandler.newMetadata();
104 assertThat(metadata.getProperty(PER_PROJECT_NOTIFICATION)).isEqualTo("true");
108 public void getNotificationClass_is_IssueChangeNotification() {
109 assertThat(underTest.getNotificationClass()).isEqualTo(IssuesChangesNotification.class);
113 public void deliver_has_no_effect_if_emailNotificationChannel_is_disabled() {
114 when(emailNotificationChannel.isActivated()).thenReturn(false);
115 Set<IssuesChangesNotification> notifications = IntStream.range(0, 5)
116 .mapToObj(i -> mock(IssuesChangesNotification.class))
119 int deliver = underTest.deliver(notifications);
121 assertThat(deliver).isZero();
122 verifyNoInteractions(notificationManager);
123 verify(emailNotificationChannel).isActivated();
124 verifyNoMoreInteractions(emailNotificationChannel);
125 notifications.forEach(Mockito::verifyNoInteractions);
129 public void deliver_parses_every_notification_in_order() {
130 Set<IssuesChangesNotification> notifications = IntStream.range(0, 10)
131 .mapToObj(i -> mock(IssuesChangesNotification.class))
133 when(emailNotificationChannel.isActivated()).thenReturn(true);
134 when(serializerMock.from(any(IssuesChangesNotification.class))).thenReturn(mock(IssuesChangesNotificationBuilder.class));
135 FPOrAcceptedNotificationHandler underTest = new FPOrAcceptedNotificationHandler(notificationManager, emailNotificationChannel, serializerMock);
137 underTest.deliver(notifications);
139 notifications.forEach(notification -> verify(serializerMock).from(notification));
143 public void deliver_fails_with_IAE_if_serializer_throws_IAE() {
144 Set<IssuesChangesNotification> notifications = IntStream.range(0, 10)
145 .mapToObj(i -> mock(IssuesChangesNotification.class))
147 when(emailNotificationChannel.isActivated()).thenReturn(true);
148 IllegalArgumentException expected = new IllegalArgumentException("faking serializer#from throwing a IllegalArgumentException");
149 when(serializerMock.from(any(IssuesChangesNotification.class)))
150 .thenReturn(mock(IssuesChangesNotificationBuilder.class))
151 .thenReturn(mock(IssuesChangesNotificationBuilder.class))
152 .thenThrow(expected);
153 FPOrAcceptedNotificationHandler underTest = new FPOrAcceptedNotificationHandler(notificationManager, emailNotificationChannel, serializerMock);
156 underTest.deliver(notifications);
157 fail("should have throws IAE");
158 } catch (IllegalArgumentException e) {
159 verify(serializerMock, times(3)).from(any(IssuesChangesNotification.class));
160 assertThat(e).isSameAs(expected);
165 @UseDataProvider("notFPorAcceptedIssueStatus")
166 public void deliver_has_no_effect_if_no_issue_has_FP_or_wontfix_resolution(IssueStatus newIssueStatus) {
167 when(emailNotificationChannel.isActivated()).thenReturn(true);
168 Change changeMock = mock(Change.class);
169 Set<IssuesChangesNotification> notifications = IntStream.range(0, 10)
170 .mapToObj(j -> new IssuesChangesNotificationBuilder(streamOfIssues(t -> t.setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)).collect(toSet()), changeMock))
171 .map(serializer::serialize)
175 int deliver = underTest.deliver(notifications);
177 assertThat(deliver).isZero();
178 verify(serializer, times(notifications.size())).from(any(IssuesChangesNotification.class));
179 verifyNoInteractions(changeMock);
180 verifyNoMoreInteractions(serializer);
181 verifyNoInteractions(notificationManager);
182 verify(emailNotificationChannel).isActivated();
183 verifyNoMoreInteractions(emailNotificationChannel);
187 @UseDataProvider("FPorWontFixResolutionWithCorrespondingIssueStatus")
188 public void deliver_shouldNotSendNotification_WhenIssueStatusHasNotChanged(String newResolution,
189 IssueStatus newIssueStatus) {
190 when(emailNotificationChannel.isActivated()).thenReturn(true);
191 Change changeMock = mock(Change.class);
192 Set<IssuesChangesNotification> notifications = IntStream.range(0, 5)
193 .mapToObj(j -> new IssuesChangesNotificationBuilder(streamOfIssues(t -> t.setNewIssueStatus(newIssueStatus).setOldIssueStatus(newIssueStatus)).collect(toSet()), changeMock))
194 .map(serializer::serialize)
198 int deliver = underTest.deliver(notifications);
200 assertThat(deliver).isZero();
201 verify(serializer, times(notifications.size())).from(any(IssuesChangesNotification.class));
202 verifyNoInteractions(changeMock);
203 verifyNoMoreInteractions(serializer);
204 verifyNoInteractions(notificationManager);
205 verify(emailNotificationChannel).isActivated();
206 verifyNoMoreInteractions(emailNotificationChannel);
210 public static Object[][] notFPorAcceptedIssueStatus() {
211 return new Object[][] {
219 @UseDataProvider("FPorWontFixResolutionWithCorrespondingIssueStatus")
220 public void deliver_checks_by_projectKey_if_notifications_have_subscribed_assignee_to_FPorWontFix_notifications(String newResolution,
221 IssueStatus newIssueStatus) {
222 Project projectKey1 = newProject(randomAlphabetic(4));
223 Project projectKey2 = newProject(randomAlphabetic(5));
224 Project projectKey3 = newProject(randomAlphabetic(6));
225 Project projectKey4 = newProject(randomAlphabetic(7));
226 Change changeMock = mock(Change.class);
227 // some notifications with some issues on project1
228 Stream<IssuesChangesNotificationBuilder> project1Notifications = IntStream.range(0, 5)
229 .mapToObj(j -> new IssuesChangesNotificationBuilder(
230 streamOfIssues(t -> t.setProject(projectKey1).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)).collect(toSet()),
232 // some notifications with some issues on project2
233 Stream<IssuesChangesNotificationBuilder> project2Notifications = IntStream.range(0, 5)
234 .mapToObj(j -> new IssuesChangesNotificationBuilder(
235 streamOfIssues(t -> t.setProject(projectKey2).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)).collect(toSet()),
237 // some notifications with some issues on project3 and project 4
238 Stream<IssuesChangesNotificationBuilder> project3And4Notifications = IntStream.range(0, 5)
239 .mapToObj(j -> new IssuesChangesNotificationBuilder(
241 streamOfIssues(t -> t.setProject(projectKey3).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)),
242 streamOfIssues(t -> t.setProject(projectKey4).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)))
245 when(emailNotificationChannel.isActivated()).thenReturn(true);
247 Set<IssuesChangesNotification> notifications = Stream.of(project1Notifications, project2Notifications, project3And4Notifications)
249 .map(serializer::serialize)
251 int deliver = underTest.deliver(notifications);
253 assertThat(deliver).isZero();
254 verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, projectKey1.getKey(), ALL_MUST_HAVE_ROLE_USER);
255 verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, projectKey2.getKey(), ALL_MUST_HAVE_ROLE_USER);
256 verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, projectKey3.getKey(), ALL_MUST_HAVE_ROLE_USER);
257 verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, projectKey4.getKey(), ALL_MUST_HAVE_ROLE_USER);
258 verifyNoMoreInteractions(notificationManager);
259 verify(emailNotificationChannel).isActivated();
260 verifyNoMoreInteractions(emailNotificationChannel);
261 verifyNoInteractions(changeMock);
265 @UseDataProvider("FPorWontFixResolutionWithCorrespondingIssueStatus")
266 public void deliver_does_not_send_email_request_for_notifications_a_subscriber_is_the_changeAuthor_of(String newResolution, IssueStatus newIssueStatus) {
267 Project project = newProject(randomAlphabetic(5));
268 User subscriber1 = newUser("subscriber1");
269 User subscriber2 = newUser("subscriber2");
270 User subscriber3 = newUser("subscriber3");
271 User otherChangeAuthor = newUser("otherChangeAuthor");
273 // subscriber1 is the changeAuthor of some notifications with issues assigned to subscriber1 only
274 Set<IssuesChangesNotificationBuilder> subscriber1Notifications = IntStream.range(0, 5)
275 .mapToObj(j -> new IssuesChangesNotificationBuilder(
276 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber2)).collect(toSet()),
277 newUserChange(subscriber1)))
279 // subscriber1 is the changeAuthor of some notifications with issues assigned to subscriber1 and subscriber2
280 Set<IssuesChangesNotificationBuilder> subscriber1and2Notifications = IntStream.range(0, 5)
281 .mapToObj(j -> new IssuesChangesNotificationBuilder(
283 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber2)),
284 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber1)))
286 newUserChange(subscriber1)))
288 // subscriber2 is the changeAuthor of some notifications with issues assigned to subscriber2 only
289 Set<IssuesChangesNotificationBuilder> subscriber2Notifications = IntStream.range(0, 5)
290 .mapToObj(j -> new IssuesChangesNotificationBuilder(
291 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber2)).collect(toSet()),
292 newUserChange(subscriber2)))
294 // subscriber2 is the changeAuthor of some notifications with issues assigned to subscriber2 and subscriber 3
295 Set<IssuesChangesNotificationBuilder> subscriber2And3Notifications = IntStream.range(0, 5)
296 .mapToObj(j -> new IssuesChangesNotificationBuilder(
298 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber2)),
299 streamOfIssues(t -> t.setProject(project).setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber3)))
301 newUserChange(subscriber2)))
303 // subscriber3 is the changeAuthor of no notification
304 // otherChangeAuthor has some notifications
305 Set<IssuesChangesNotificationBuilder> otherChangeAuthorNotifications = IntStream.range(0, 5)
306 .mapToObj(j -> new IssuesChangesNotificationBuilder(streamOfIssues(t -> t.setProject(project)
307 .setNewIssueStatus(newIssueStatus).setOldIssueStatus(IssueStatus.OPEN)).collect(toSet()),
308 newUserChange(otherChangeAuthor)))
310 when(emailNotificationChannel.isActivated()).thenReturn(true);
312 Set<String> subscriberLogins = ImmutableSet.of(subscriber1.getLogin(), subscriber2.getLogin(), subscriber3.getLogin());
313 when(notificationManager.findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, project.getKey(), ALL_MUST_HAVE_ROLE_USER))
314 .thenReturn(subscriberLogins.stream().map(FPOrAcceptedNotificationHandlerTest::emailRecipientOf).collect(toSet()));
316 int deliveredCount = 200;
317 when(emailNotificationChannel.deliverAll(anySet()))
318 .thenReturn(deliveredCount)
319 .thenThrow(new IllegalStateException("deliver should be called only once"));
321 Set<IssuesChangesNotification> notifications = Stream.of(
322 subscriber1Notifications.stream(),
323 subscriber1and2Notifications.stream(),
324 subscriber2Notifications.stream(),
325 subscriber2And3Notifications.stream(),
326 otherChangeAuthorNotifications.stream())
328 .map(serializer::serialize)
332 int deliver = underTest.deliver(notifications);
334 assertThat(deliver).isEqualTo(deliveredCount);
335 verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, project.getKey(), ALL_MUST_HAVE_ROLE_USER);
336 verifyNoMoreInteractions(notificationManager);
337 verify(emailNotificationChannel).isActivated();
338 ArgumentCaptor<Set<EmailDeliveryRequest>> captor = ArgumentCaptor.forClass(requestSetType);
339 verify(emailNotificationChannel).deliverAll(captor.capture());
340 verifyNoMoreInteractions(emailNotificationChannel);
341 ListMultimap<String, EmailDeliveryRequest> requestsByRecipientEmail = captor.getValue().stream()
342 .collect(index(EmailDeliveryRequest::recipientEmail));
343 assertThat(requestsByRecipientEmail.get(emailOf(subscriber1.getLogin())))
346 subscriber2Notifications.stream()
347 .map(notif -> newEmailDeliveryRequest(notif, subscriber1, toFpOrAccepted(newResolution))),
348 subscriber2And3Notifications.stream()
349 .map(notif -> newEmailDeliveryRequest(notif, subscriber1, toFpOrAccepted(newResolution))),
350 otherChangeAuthorNotifications.stream()
351 .map(notif -> newEmailDeliveryRequest(notif, subscriber1, toFpOrAccepted(newResolution))))
353 .toArray(EmailDeliveryRequest[]::new));
354 assertThat(requestsByRecipientEmail.get(emailOf(subscriber2.getLogin())))
357 subscriber1Notifications.stream()
358 .map(notif -> newEmailDeliveryRequest(notif, subscriber2, toFpOrAccepted(newResolution))),
359 subscriber1and2Notifications.stream()
360 .map(notif -> newEmailDeliveryRequest(notif, subscriber2, toFpOrAccepted(newResolution))),
361 otherChangeAuthorNotifications.stream()
362 .map(notif -> newEmailDeliveryRequest(notif, subscriber2, toFpOrAccepted(newResolution))))
364 .toArray(EmailDeliveryRequest[]::new));
365 assertThat(requestsByRecipientEmail.get(emailOf(subscriber3.getLogin())))
368 subscriber1Notifications.stream()
369 .map(notif -> newEmailDeliveryRequest(notif, subscriber3, toFpOrAccepted(newResolution))),
370 subscriber1and2Notifications.stream()
371 .map(notif -> newEmailDeliveryRequest(notif, subscriber3, toFpOrAccepted(newResolution))),
372 subscriber2Notifications.stream()
373 .map(notif -> newEmailDeliveryRequest(notif, subscriber3, toFpOrAccepted(newResolution))),
374 subscriber2And3Notifications.stream()
375 .map(notif -> newEmailDeliveryRequest(notif, subscriber3, toFpOrAccepted(newResolution))),
376 otherChangeAuthorNotifications.stream()
377 .map(notif -> newEmailDeliveryRequest(notif, subscriber3, toFpOrAccepted(newResolution))))
379 .toArray(EmailDeliveryRequest[]::new));
380 assertThat(requestsByRecipientEmail.get(emailOf(otherChangeAuthor.getLogin())))
385 @UseDataProvider("oneOrMoreProjectCounts")
386 public void deliver_send_a_separated_email_request_for_FPs_and_Wont_Fix_issues(int projectCount) {
387 Set<Project> projects = IntStream.range(0, projectCount).mapToObj(i -> newProject("prk_key_" + i)).collect(toSet());
388 User subscriber1 = newUser("subscriber1");
389 User changeAuthor = newUser("changeAuthor");
391 Set<ChangedIssue> fpIssues = projects.stream()
392 .flatMap(project -> streamOfIssues(t -> t.setProject(project)
393 .setNewIssueStatus(IssueStatus.FALSE_POSITIVE).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber1)))
395 Set<ChangedIssue> wontFixIssues = projects.stream()
396 .flatMap(project -> streamOfIssues(t -> t.setProject(project)
397 .setNewIssueStatus(IssueStatus.ACCEPTED).setOldIssueStatus(IssueStatus.OPEN).setAssignee(subscriber1)))
399 UserChange userChange = newUserChange(changeAuthor);
400 IssuesChangesNotificationBuilder fpAndWontFixNotifications = new IssuesChangesNotificationBuilder(
401 Stream.concat(fpIssues.stream(), wontFixIssues.stream()).collect(toSet()),
403 when(emailNotificationChannel.isActivated()).thenReturn(true);
404 projects.forEach(project -> when(notificationManager.findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, project.getKey(), ALL_MUST_HAVE_ROLE_USER))
405 .thenReturn(singleton(emailRecipientOf(subscriber1.getLogin()))));
407 int deliveredCount = 200;
408 when(emailNotificationChannel.deliverAll(anySet()))
409 .thenReturn(deliveredCount)
410 .thenThrow(new IllegalStateException("deliver should be called only once"));
411 Set<IssuesChangesNotification> notifications = singleton(serializer.serialize(fpAndWontFixNotifications));
414 int deliver = underTest.deliver(notifications);
416 assertThat(deliver).isEqualTo(deliveredCount);
418 .forEach(project -> verify(notificationManager).findSubscribedEmailRecipients(DO_NOT_FIX_ISSUE_CHANGE_DISPATCHER_KEY, project.getKey(), ALL_MUST_HAVE_ROLE_USER));
419 verifyNoMoreInteractions(notificationManager);
420 verify(emailNotificationChannel).isActivated();
421 ArgumentCaptor<Set<EmailDeliveryRequest>> captor = ArgumentCaptor.forClass(requestSetType);
422 verify(emailNotificationChannel).deliverAll(captor.capture());
423 verifyNoMoreInteractions(emailNotificationChannel);
424 ListMultimap<String, EmailDeliveryRequest> requestsByRecipientEmail = captor.getValue().stream()
425 .collect(index(EmailDeliveryRequest::recipientEmail));
426 assertThat(requestsByRecipientEmail.get(emailOf(subscriber1.getLogin())))
428 new EmailDeliveryRequest(emailOf(subscriber1.getLogin()), new FPOrAcceptedNotification(
429 userChange, wontFixIssues, FpPrAccepted.ACCEPTED)),
430 new EmailDeliveryRequest(emailOf(subscriber1.getLogin()), new FPOrAcceptedNotification(
431 userChange, fpIssues, FpPrAccepted.FP)));
435 public static Object[][] oneOrMoreProjectCounts() {
436 return new Object[][] {
442 private static EmailDeliveryRequest newEmailDeliveryRequest(IssuesChangesNotificationBuilder notif, User user, FpPrAccepted resolution) {
443 return new EmailDeliveryRequest(
444 emailOf(user.getLogin()),
445 new FPOrAcceptedNotification(notif.getChange(), notif.getIssues(), resolution));
448 private static FpPrAccepted toFpOrAccepted(String newResolution) {
449 if (newResolution.equals(Issue.RESOLUTION_WONT_FIX)) {
450 return FpPrAccepted.ACCEPTED;
452 if (newResolution.equals(RESOLUTION_FALSE_POSITIVE)) {
453 return FpPrAccepted.FP;
455 throw new IllegalArgumentException("unsupported resolution " + newResolution);
458 private static long counter = 233_343;
460 private static UserChange newUserChange(User subscriber1) {
461 return new UserChange(counter += 100, subscriber1);
464 public User newUser(String subscriber1) {
465 return new User(subscriber1, subscriber1 + "_login", subscriber1 + "_name");
469 public static Object[][] FPorWontFixResolutionWithCorrespondingIssueStatus() {
470 return new Object[][] {
471 {RESOLUTION_FALSE_POSITIVE, IssueStatus.FALSE_POSITIVE},
472 {Issue.RESOLUTION_WONT_FIX, IssueStatus.ACCEPTED}
476 private static Stream<ChangedIssue> streamOfIssues(Consumer<ChangedIssue.Builder> consumer) {
477 return IntStream.range(0, 5)
479 ChangedIssue.Builder builder = new ChangedIssue.Builder("key_" + i)
480 .setAssignee(new User(randomAlphabetic(3), randomAlphabetic(4), randomAlphabetic(5)))
481 .setNewStatus(randomAlphabetic(12))
482 .setRule(newRandomNotAHotspotRule(randomAlphabetic(8)))
483 .setProject(new Project.Builder(randomAlphabetic(9))
484 .setKey(randomAlphabetic(10))
485 .setProjectName(randomAlphabetic(11))
487 consumer.accept(builder);
488 return builder.build();
492 private static NotificationManager.EmailRecipient emailRecipientOf(String assignee1) {
493 return new NotificationManager.EmailRecipient(assignee1, emailOf(assignee1));
496 private static String emailOf(String assignee1) {
497 return assignee1 + "@baffe";