From 9ab85f663d2076124cd250ce0eaa7964bfa38fda Mon Sep 17 00:00:00 2001 From: Eric Hartmann Date: Wed, 20 Sep 2017 17:58:56 +0200 Subject: [PATCH] SONAR-4824 Add ITs for notifications --- .../org/sonarqube/tests/Category2Suite.java | 4 +- .../org/sonarqube/tests/Category6Suite.java | 5 +- .../tests/issue/AbstractIssueTest.java | 2 +- .../tests/issue/IssueNotificationsTest.java | 415 ++++++++++++------ 4 files changed, 290 insertions(+), 136 deletions(-) diff --git a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java index c84781c885f..ab558497243 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java @@ -36,7 +36,6 @@ import org.sonarqube.tests.issue.IssueFilterExtensionTest; import org.sonarqube.tests.issue.IssueFilterOnCommonRulesTest; import org.sonarqube.tests.issue.IssueFilterTest; import org.sonarqube.tests.issue.IssueMeasureTest; -import org.sonarqube.tests.issue.IssueNotificationsTest; import org.sonarqube.tests.issue.IssuePurgeTest; import org.sonarqube.tests.issue.IssueSearchTest; import org.sonarqube.tests.issue.IssueTrackingTest; @@ -81,7 +80,6 @@ import static util.ItUtils.xooPlugin; IssueFilterTest.class, IssueFilterExtensionTest.class, IssueMeasureTest.class, - IssueNotificationsTest.class, IssuePurgeTest.class, IssueSearchTest.class, IssueTrackingTest.class, @@ -115,6 +113,8 @@ public class Category2Suite { // 1 second. Required for notification test. .setServerProperty("sonar.notifications.delay", "1") + .setServerProperty("organization.enabled", "true") + // reduce memory for Elasticsearch to 128M .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m") diff --git a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java index 8cebafd58bf..660ff241cd1 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java @@ -26,6 +26,7 @@ import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.sonarqube.tests.authorisation.PermissionTemplateTest; +import org.sonarqube.tests.issue.IssueNotificationsTest; import org.sonarqube.tests.ce.ReportFailureNotificationTest; import org.sonarqube.tests.issue.IssueTagsTest; import org.sonarqube.tests.issue.OrganizationIssueAssignTest; @@ -83,7 +84,8 @@ import static util.ItUtils.xooPlugin; ProjectKeyUpdateTest.class, ProjectSearchTest.class, PermissionTemplateTest.class, - ReportFailureNotificationTest.class + ReportFailureNotificationTest.class, + IssueNotificationsTest.class }) public class Category6Suite { @@ -96,6 +98,7 @@ public class Category6Suite { .setServerProperty("sonar.search.httpPort", "" + SEARCH_HTTP_PORT) .setServerProperty("sonar.search.recovery.delayInMs", "1000") .setServerProperty("sonar.search.recovery.minAgeInMs", "3000") + .setServerProperty("sonar.notifications.delay", "1") .addPlugin(xooPlugin()) .addPlugin(pluginArtifact("base-auth-plugin")) diff --git a/tests/src/test/java/org/sonarqube/tests/issue/AbstractIssueTest.java b/tests/src/test/java/org/sonarqube/tests/issue/AbstractIssueTest.java index 4f85822c7d6..fe452745f1a 100644 --- a/tests/src/test/java/org/sonarqube/tests/issue/AbstractIssueTest.java +++ b/tests/src/test/java/org/sonarqube/tests/issue/AbstractIssueTest.java @@ -20,13 +20,13 @@ package org.sonarqube.tests.issue; import com.sonar.orchestrator.Orchestrator; -import org.sonarqube.tests.Category2Suite; import java.util.List; import org.junit.ClassRule; import org.sonar.wsclient.issue.Issue; import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.issue.IssueQuery; import org.sonar.wsclient.issue.Issues; +import org.sonarqube.tests.Category2Suite; import static org.assertj.core.api.Assertions.assertThat; diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueNotificationsTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueNotificationsTest.java index a8ffdb9c0dd..477f3ab48d3 100644 --- a/tests/src/test/java/org/sonarqube/tests/issue/IssueNotificationsTest.java +++ b/tests/src/test/java/org/sonarqube/tests/issue/IssueNotificationsTest.java @@ -19,78 +19,83 @@ */ package org.sonarqube.tests.issue; -import java.util.Iterator; +import com.google.common.collect.ObjectArrays; +import com.sonar.orchestrator.Orchestrator; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.apache.commons.lang.RandomStringUtils; +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; -import org.sonar.wsclient.issue.Issue; -import org.sonar.wsclient.issue.IssueClient; -import org.sonar.wsclient.issue.IssueQuery; -import org.sonar.wsclient.issue.Issues; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.sonarqube.tests.Category6Suite; +import org.sonarqube.tests.Tester; +import org.sonarqube.ws.Issues.Issue; +import org.sonarqube.ws.Issues.SearchWsResponse; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.QualityProfiles; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.issue.AssignRequest; import org.sonarqube.ws.client.issue.BulkChangeRequest; -import org.sonarqube.ws.client.issue.IssuesService; +import org.sonarqube.ws.client.issue.SearchWsRequest; +import org.sonarqube.ws.client.permission.AddUserWsRequest; import org.subethamail.wiser.Wiser; import org.subethamail.wiser.WiserMessage; -import util.ItUtils; -import util.user.UserRule; +import static java.lang.String.format; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.newUserWsClient; -import static util.ItUtils.resetEmailSettings; +import static org.assertj.core.api.Fail.fail; import static util.ItUtils.runProjectAnalysis; -import static util.ItUtils.setServerProperty; -public class IssueNotificationsTest extends AbstractIssueTest { +@RunWith(Parameterized.class) +public class IssueNotificationsTest { + @ClassRule + public static final Orchestrator ORCHESTRATOR = Category6Suite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(ORCHESTRATOR); + + private final static String EMAIL_TEST = "test@test.com"; private final static String PROJECT_KEY = "sample"; - private final static String USER_LOGIN = "tester"; - private final static String USER_PASSWORD = "tester"; - private static final String USER_EMAIL = "tester@example.org"; private static Wiser smtpServer; - private IssueClient issueClient; + private Organization organization; + private User userWithUserRole; + private User userWithUserRoleThroughGroups; + private User userNotInOrganization; - private IssuesService issuesService; + @Parameters + public static List data() { + return Arrays.asList(true, false); + } + + @Parameter + public boolean privateProject; - @ClassRule - public static UserRule userRule = UserRule.from(ORCHESTRATOR); @BeforeClass - public static void before() throws Exception { + public static void setUp() { smtpServer = new Wiser(0); smtpServer.start(); System.out.println("SMTP Server port: " + smtpServer.getServer().getPort()); - - // Configure Sonar - resetEmailSettings(ORCHESTRATOR); - setServerProperty(ORCHESTRATOR, "email.smtp_host.secured", "localhost"); - setServerProperty(ORCHESTRATOR, "email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort())); - - // Send test email to the test user - newAdminWsClient(ORCHESTRATOR).wsConnector().call(new PostRequest("api/emails/send") - .setParam("to", USER_EMAIL) - .setParam("message", "This is a test message from SonarQube")) - .failIfNotSuccessful(); - - // We need to wait until all notifications will be delivered - waitUntilAllNotificationsAreDelivered(1); - - Iterator emails = smtpServer.getMessages().iterator(); - - MimeMessage message = emails.next().getMimeMessage(); - assertThat(message.getHeader("To", null)).isEqualTo("<" + USER_EMAIL + ">"); - assertThat((String) message.getContent()).contains("This is a test message from SonarQube"); - - assertThat(emails.hasNext()).isFalse(); } @AfterClass @@ -98,109 +103,128 @@ public class IssueNotificationsTest extends AbstractIssueTest { if (smtpServer != null) { smtpServer.stop(); } - userRule.deactivateUsers(USER_LOGIN); - setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", null); - resetEmailSettings(ORCHESTRATOR); } @Before - public void prepare() { - ORCHESTRATOR.resetData(); + public void before() throws Exception { + organization = tester.organizations().generate(); - // Create test user - userRule.createUser(USER_LOGIN, "Tester", USER_EMAIL, USER_LOGIN); + // Configure Sonar + tester.settings().setGlobalSettings("email.smtp_host.secured", "localhost"); + tester.settings().setGlobalSettings("email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort())); - smtpServer.getMessages().clear(); - issueClient = ORCHESTRATOR.getServer().adminWsClient().issueClient(); - issuesService = newAdminWsClient(ORCHESTRATOR).issues(); + clearSmtpMessages(); + checkEmailSettings(); + clearSmtpMessages(); + } - setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", null); - ItUtils.restoreProfile(ORCHESTRATOR, getClass().getResource("/issue/one-issue-per-line-profile.xml")); - ORCHESTRATOR.getServer().provisionProject(PROJECT_KEY, "Sample"); - ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT_KEY, "xoo", "one-issue-per-line-profile"); + @After + public void after() throws Exception { + clearSmtpMessages(); + } - // Add notifications to the test user - WsClient wsClient = newUserWsClient(ORCHESTRATOR, USER_LOGIN, USER_PASSWORD); - wsClient.wsConnector().call(new PostRequest("api/notifications/add") - .setParam("type", "NewIssues") - .setParam("channel", "EmailNotificationChannel")) - .failIfNotSuccessful(); - wsClient.wsConnector().call(new PostRequest("api/notifications/add") - .setParam("type", "ChangesOnMyIssue") - .setParam("channel", "EmailNotificationChannel")) - .failIfNotSuccessful(); - wsClient.wsConnector().call(new PostRequest("api/notifications/add") - .setParam("type", "SQ-MyNewIssues") - .setParam("channel", "EmailNotificationChannel")) - .failIfNotSuccessful(); + @Test + public void notifications_on_new_issues_should_send_emails_to_subscribers() throws Exception { + String version = RandomStringUtils.randomAlphanumeric(10); + createSampleProject(privateProject ? "private" : "public"); + createUsers(); + runAnalysis("shared/xoo-sample", + "sonar.projectVersion", version, + "sonar.projectDate", "2015-12-15"); + + // If project is private userNotInOrganization will not receive and email (missing UserRole.User permission) + waitUntilAllNotificationsAreDelivered(privateProject ? 2 : 3); + assertThat(smtpServer.getMessages()).hasSize(privateProject ? 2 : 3); + + if (privateProject) { + assertThat(extractRecipients(smtpServer.getMessages())) + .containsExactlyInAnyOrder( + format("<%s>", userWithUserRole.getEmail()), + format("<%s>", userWithUserRoleThroughGroups.getEmail())); + } else { + assertThat(extractRecipients(smtpServer.getMessages())) + .containsExactlyInAnyOrder( + format("<%s>", userWithUserRole.getEmail()), + format("<%s>", userWithUserRoleThroughGroups.getEmail()), + format("<%s>", userNotInOrganization.getEmail())); + } + + extractBodies(smtpServer.getMessages()).forEach( + message -> assertThat(message) + .contains("Project: Sample") + .contains("Version: " + version) + .contains("17 new issues (new debt: 17min)") + .contains("Type") + .contains("One Issue Per Line (xoo): 17") + .contains("More details at: http://localhost:9000/project/issues?id=sample&createdAt=2015-12-15T00%3A00%3A00%2B") + ); + + clearSmtpMessages(); } @Test - public void notifications_for_new_issues_and_issue_changes() throws Exception { + public void notifications_for_issue_changes() throws Exception { String version = RandomStringUtils.randomAlphanumeric(10); - runProjectAnalysis(ORCHESTRATOR, "shared/xoo-sample", - "sonar.projectDate", "2015-12-15", - "sonar.projectVersion", version); + createSampleProject(privateProject ? "private" : "public"); + createUsers(); + runAnalysis("shared/xoo-sample", + "sonar.projectVersion", version, + "sonar.projectDate", "2015-12-15"); - // change assignee - Issues issues = issueClient.find(IssueQuery.create().componentRoots(PROJECT_KEY)); - Issue issue = issues.list().get(0); - issueClient.assign(issue.key(), USER_LOGIN); + // Ignore the messages generated by the analysis + clearSmtpMessages(); - waitUntilAllNotificationsAreDelivered(2); + // Change assignee + SearchWsResponse issues = tester.wsClient().issues().search(new SearchWsRequest().setProjectKeys(singletonList(PROJECT_KEY))); + Issue issue = issues.getIssuesList().get(0); + tester.wsClient().issues().assign(new AssignRequest(issue.getKey(), userWithUserRole.getLogin())); - Iterator emails = smtpServer.getMessages().iterator(); + // Only the assignee should receive the email + waitUntilAllNotificationsAreDelivered(1); + assertThat(smtpServer.getMessages()).hasSize(1); + assertThat(extractRecipients(smtpServer.getMessages())).containsExactly(format("<%s>", userWithUserRole.getEmail())); - assertThat(emails.hasNext()).isTrue(); - MimeMessage message = emails.next().getMimeMessage(); - assertThat(message.getHeader("To", null)).isEqualTo(""); - assertThat((String) message.getContent()) - .contains("Project: Sample") - .contains("Version: " + version) - .contains("17 new issues (new debt: 17min)") - .contains("Type") - .contains("One Issue Per Line (xoo): 17") - .contains("More details at: http://localhost:9000/project/issues?id=sample&createdAt=2015-12-15T00%3A00%3A00%2B"); - - assertThat(emails.hasNext()).isTrue(); - message = emails.next().getMimeMessage(); - assertThat(message.getHeader("To", null)).isEqualTo(""); - assertThat((String) message.getContent()) + assertThat(extractBodies(smtpServer.getMessages()).get(0)) .contains("sample/Sample.xoo") - .contains("Assignee changed to Tester") - .contains("More details at: http://localhost:9000/project/issues?id=sample&issues=" + issue.key() + "&open=" + issue.key()); - - assertThat(emails.hasNext()).isFalse(); + .contains("Assignee changed to userWithUserRole") + .contains("More details at: http://localhost:9000/project/issues?id=sample&issues=" + issue.getKey() + "&open=" + issue.getKey()); } @Test public void notifications_for_personalized_emails() throws Exception { String version = RandomStringUtils.randomAlphanumeric(10); - setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", USER_LOGIN); // 1st analysis without any issue (because no file is analyzed) - runProjectAnalysis(ORCHESTRATOR, "issue/xoo-with-scm", + createSampleProject(privateProject ? "private" : "public"); + createUsers(); + tester.settings().setGlobalSettings("sonar.issues.defaultAssigneeLogin", userWithUserRole.getLogin()); + + runAnalysis("issue/xoo-with-scm", + "sonar.projectVersion", version, "sonar.scm.provider", "xoo", "sonar.scm.disabled", "false", - "sonar.exclusions", "**/*", - "sonar.projectVersion", version); + "sonar.exclusions", "**/*" + ); - waitUntilAllNotificationsAreDelivered(2); + // No email since all code is ignored + waitUntilAllNotificationsAreDelivered(1); assertThat(smtpServer.getMessages()).isEmpty(); // run 2nd analysis which will generate issues on the leak period - runProjectAnalysis(ORCHESTRATOR, "issue/xoo-with-scm", + runAnalysis("issue/xoo-with-scm", + "sonar.projectVersion", version, "sonar.scm.provider", "xoo", - "sonar.scm.disabled", "false", - "sonar.projectVersion", version); + "sonar.scm.disabled", "false" + ); - waitUntilAllNotificationsAreDelivered(2); + // We expect to receive a notification for each subscriber with UserRole.user + // And a personalized email for the assignee userWithUserRole + waitUntilAllNotificationsAreDelivered(privateProject ? 3 : 4); + assertThat(smtpServer.getMessages()).hasSize(privateProject ? 3 : 4); - Iterator emails = smtpServer.getMessages().iterator(); - emails.next(); - // the second email sent is the personalized one - MimeMessage message = emails.next().getMimeMessage(); + // the last email sent is the personalized one + MimeMessage message = smtpServer.getMessages().get(privateProject ? 2 : 3).getMimeMessage(); - assertThat(message.getHeader("To", null)).isEqualTo(""); + assertThat(message.getHeader("To", null)).isEqualTo(format("<%s>", userWithUserRole.getEmail())); assertThat(message.getSubject()).contains("You have 13 new issues"); assertThat((String) message.getContent()) .contains("Project: Sample") @@ -212,42 +236,123 @@ public class IssueNotificationsTest extends AbstractIssueTest { */ @Test public void notifications_for_bulk_change_ws() throws Exception { - runProjectAnalysis(ORCHESTRATOR, "shared/xoo-sample", "sonar.projectDate", "2015-12-15"); + String version = RandomStringUtils.randomAlphanumeric(10); + createSampleProject(privateProject ? "private" : "public"); + createUsers(); + runAnalysis("shared/xoo-sample", + "sonar.projectVersion", version, + "sonar.projectDate", "2015-12-15"); + + // If project is private userNotInOrganization will not receive and email (missing UserRole.User permission) + waitUntilAllNotificationsAreDelivered(privateProject ? 2 : 3); + assertThat(smtpServer.getMessages()).hasSize(privateProject ? 2 : 3); + clearSmtpMessages(); - Issues issues = issueClient.find(IssueQuery.create().componentRoots(PROJECT_KEY)); - Issue issue = issues.list().get(0); + SearchWsResponse issues = tester.wsClient().issues().search(new SearchWsRequest().setProjectKeys(singletonList(PROJECT_KEY))); + Issue issue = issues.getIssuesList().get(0); // bulk change without notification by default - issuesService.bulkChange(BulkChangeRequest.builder() - .setIssues(singletonList(issue.key())) - .setAssign(USER_LOGIN) + tester.wsClient().issues().bulkChange(BulkChangeRequest.builder() + .setIssues(singletonList(issue.getKey())) + .setAssign(userWithUserRole.getLogin()) .setSetSeverity("MINOR") .build()); // bulk change with notification - issuesService.bulkChange(BulkChangeRequest.builder() - .setIssues(singletonList(issue.key())) + tester.wsClient().issues().bulkChange(BulkChangeRequest.builder() + .setIssues(singletonList(issue.getKey())) .setSetSeverity("BLOCKER") .setSendNotifications(true) .build()); + // We are waiting for a single notification for userWithUserRole + // for a change on MyIssues + waitUntilAllNotificationsAreDelivered(1); + assertThat(smtpServer.getMessages()).hasSize(1); + + assertThat(extractRecipients(smtpServer.getMessages())) + .containsExactly(format("<%s>", userWithUserRole.getEmail())); + assertThat(extractBodies(smtpServer.getMessages()).get(0)) + .contains("sample/Sample.xoo") + .contains("Severity: BLOCKER (was MINOR)") + .contains("More details at: http://localhost:9000/project/issues?id=sample&issues=" + issue.getKey() + "&open=" + issue.getKey()); + } + + private void runAnalysis(String projectRelativePath, String... extraParameters) throws Exception { + String[] parameters = { + "sonar.login", "admin", + "sonar.password", "admin", + "sonar.organization", organization.getKey()}; + runProjectAnalysis(ORCHESTRATOR, projectRelativePath, + ObjectArrays.concat(parameters, extraParameters, String.class)); + + // Two emails should be sent for subscribers of "New issues" waitUntilAllNotificationsAreDelivered(2); + } + + private void createSampleProject(String visibility) { + // Create project + QualityProfiles.CreateWsResponse.QualityProfile profile = tester.qProfiles().createXooProfile(organization); + Project project = tester.projects().generate(organization, p -> p.setKey(PROJECT_KEY) + .setName("Sample") + .setVisibility(visibility)); + tester.qProfiles() + .activateRule(profile, "xoo:OneIssuePerLine") + .assignQProfileToProject(profile, project); + } - Iterator emails = smtpServer.getMessages().iterator(); + private void createUsers() { + // Create a user with User role + userWithUserRole = tester.users().generateMember(organization, + u -> u.setLogin("userWithUserRole") + .setPassword("userWithUserRole") + .setName("userWithUserRole") + .setEmail("userWithUserRole@nowhere.com")); + tester.organizations().addMember(organization, userWithUserRole); + tester.wsClient().permissions().addUser( + new AddUserWsRequest() + .setLogin(userWithUserRole.getLogin()) + .setProjectKey(PROJECT_KEY) + .setPermission("user")); + addNotificationsTo(userWithUserRole); + + // Create a user that have User role through Members group + userWithUserRoleThroughGroups = tester.users().generate( + u -> u.setLogin("userWithUserRoleThroughGroups") + .setPassword("userWithUserRoleThroughGroups") + .setName("userWithUserRoleThroughGroups") + .setEmail("userWithUserRoleThroughGroups@nowhere.com")); + tester.organizations().addMember(organization, userWithUserRoleThroughGroups); + addNotificationsTo(userWithUserRoleThroughGroups); + + // Create a user that does not belongs to organization + userNotInOrganization = tester.users().generate( + u -> u.setLogin("userNotInOrganization") + .setPassword("userNotInOrganization") + .setName("userNotInOrganization") + .setEmail("userNotInOrganization@nowhere.com")); + addNotificationsTo(userNotInOrganization); + } + + void checkEmailSettings() throws Exception { + // Send test email to the test user + tester.wsClient().wsConnector().call(new PostRequest("api/emails/send") + .setParam("to", EMAIL_TEST) + .setParam("message", "This is a test message from SonarQube")) + .failIfNotSuccessful(); + + // We need to wait until all notifications will be delivered + waitUntilAllNotificationsAreDelivered(1); - emails.next(); - MimeMessage message = emails.next().getMimeMessage(); - assertThat(message.getHeader("To", null)).isEqualTo(""); - assertThat((String) message.getContent()).contains("sample/Sample.xoo"); - assertThat((String) message.getContent()).contains("Severity: BLOCKER (was MINOR)"); - assertThat((String) message.getContent()).contains( - "More details at: http://localhost:9000/project/issues?id=sample&issues=" + issue.key() + "&open=" + issue.key()); + assertThat(smtpServer.getMessages()).hasSize(1); - assertThat(emails.hasNext()).isFalse(); + MimeMessage message = smtpServer.getMessages().get(0).getMimeMessage(); + assertThat(message.getHeader("To", null)).isEqualTo("<" + EMAIL_TEST + ">"); + assertThat((String) message.getContent()).contains("This is a test message from SonarQube"); } private static void waitUntilAllNotificationsAreDelivered(int expectedNumberOfEmails) throws InterruptedException { - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 5; i++) { if (smtpServer.getMessages().size() == expectedNumberOfEmails) { break; } @@ -255,4 +360,50 @@ public class IssueNotificationsTest extends AbstractIssueTest { } } + private static void clearSmtpMessages() { + synchronized (smtpServer.getMessages()) { + smtpServer.getMessages().clear(); + } + } + + private List extractRecipients(List messages) { + return messages.stream() + .map(m -> { + try { + return m.getMimeMessage().getHeader("To", null); + } catch (MessagingException e) { + fail(e.getMessage(), e); + return null; + } + }).collect(Collectors.toList()); + } + + private List extractBodies(List messages) { + return messages.stream() + .map(m -> { + try { + return m.getMimeMessage().getContent().toString(); + } catch (MessagingException | IOException e) { + fail(e.getMessage(), e); + return null; + } + }).collect(Collectors.toList()); + } + + private void addNotificationsTo(WsUsers.CreateWsResponse.User user) { + // Add notifications to the test user + WsClient wsClient = tester.as(user.getLogin()).wsClient(); + wsClient.wsConnector().call(new PostRequest("api/notifications/add") + .setParam("type", "NewIssues") + .setParam("channel", "EmailNotificationChannel")) + .failIfNotSuccessful(); + wsClient.wsConnector().call(new PostRequest("api/notifications/add") + .setParam("type", "ChangesOnMyIssue") + .setParam("channel", "EmailNotificationChannel")) + .failIfNotSuccessful(); + wsClient.wsConnector().call(new PostRequest("api/notifications/add") + .setParam("type", "SQ-MyNewIssues") + .setParam("channel", "EmailNotificationChannel")) + .failIfNotSuccessful(); + } } -- 2.39.5