import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Predicate;
import org.sonar.api.issue.Issue;
import org.sonar.api.utils.Duration;
import org.sonar.core.issue.DefaultIssue;
private void doExecute(Component project) {
long analysisDate = analysisMetadataHolder.getAnalysisDate();
- NewIssuesStatistics newIssuesStats = new NewIssuesStatistics(i -> i.isNew() && i.creationDate().getTime() >= truncateToSeconds(analysisDate));
- CloseableIterator<DefaultIssue> issues = issueCache.traverse();
- try {
+ Predicate<Issue> isOnLeakPredicate = i -> i.isNew() && i.creationDate().getTime() >= truncateToSeconds(analysisDate);
+ NewIssuesStatistics newIssuesStats = new NewIssuesStatistics(isOnLeakPredicate);
+ try (CloseableIterator<DefaultIssue> issues = issueCache.traverse()) {
processIssues(newIssuesStats, issues, project);
- } finally {
- issues.close();
}
- if (newIssuesStats.hasIssues()) {
+ if (newIssuesStats.hasIssuesOnLeak()) {
sendNewIssuesNotification(newIssuesStats, project, analysisDate);
sendNewIssuesNotificationToAssignees(newIssuesStats, project, analysisDate);
}
.setProject(project.getPublicKey(), project.getUuid(), project.getName(), getBranchName())
.setAnalysisDate(new Date(analysisDate))
.setStatistics(project.getName(), globalStatistics)
- .setDebt(Duration.create(globalStatistics.effort().getTotal()));
+ .setDebt(Duration.create(globalStatistics.effort().getOnLeak()));
service.deliver(notification);
}
private void sendNewIssuesNotificationToAssignees(NewIssuesStatistics statistics, Component project, long analysisDate) {
- // send email to each user having issues
- for (Map.Entry<String, NewIssuesStatistics.Stats> assigneeAndStatisticsTuple : statistics.assigneesStatistics().entrySet()) {
- String assignee = assigneeAndStatisticsTuple.getKey();
- NewIssuesStatistics.Stats assigneeStatistics = assigneeAndStatisticsTuple.getValue();
- MyNewIssuesNotification myNewIssuesNotification = newIssuesNotificationFactory
- .newMyNewIssuesNotification()
- .setAssignee(assignee);
- myNewIssuesNotification
- .setProject(project.getPublicKey(), project.getUuid(), project.getName(), getBranchName())
- .setAnalysisDate(new Date(analysisDate))
- .setStatistics(project.getName(), assigneeStatistics)
- .setDebt(Duration.create(assigneeStatistics.effort().getTotal()));
-
- service.deliver(myNewIssuesNotification);
- }
+ statistics.getAssigneesStatistics().entrySet()
+ .stream()
+ .filter(e -> e.getValue().hasIssuesOnLeak())
+ .forEach(e -> {
+ String assignee = e.getKey();
+ NewIssuesStatistics.Stats assigneeStatistics = e.getValue();
+ MyNewIssuesNotification myNewIssuesNotification = newIssuesNotificationFactory
+ .newMyNewIssuesNotification()
+ .setAssignee(assignee);
+ myNewIssuesNotification
+ .setProject(project.getPublicKey(), project.getUuid(), project.getName(), getBranchName())
+ .setAnalysisDate(new Date(analysisDate))
+ .setStatistics(project.getName(), assigneeStatistics)
+ .setDebt(Duration.create(assigneeStatistics.effort().getOnLeak()));
+
+ service.deliver(myNewIssuesNotification);
+ });
}
private Optional<Component> getComponentKey(DefaultIssue issue) {
}
public NewIssuesNotification setStatistics(String projectName, NewIssuesStatistics.Stats stats) {
- setDefaultMessage(stats.getDistributedMetricStats(SEVERITY).getTotal() + " new issues on " + projectName + ".\n");
+ setDefaultMessage(stats.getDistributedMetricStats(SEVERITY).getOnLeak() + " new issues on " + projectName + ".\n");
try (DbSession dbSession = dbClient.openSession(false)) {
setSeverityStatistics(stats);
private void setRuleStatistics(DbSession dbSession, NewIssuesStatistics.Stats stats) {
Metric metric = Metric.RULE;
int i = 1;
- for (Map.Entry<String, MetricStatsInt> ruleStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getTotal)) {
+ for (Map.Entry<String, MetricStatsInt> ruleStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) {
String ruleKey = ruleStats.getKey();
RuleDefinitionDto rule = dbClient.ruleDao().selectOrFailDefinitionByKey(dbSession, RuleKey.parse(ruleKey));
String name = rule.getName() + " (" + rule.getLanguage() + ")";
setFieldValue(metric + DOT + i + LABEL, name);
- setFieldValue(metric + DOT + i + COUNT, String.valueOf(ruleStats.getValue().getTotal()));
+ setFieldValue(metric + DOT + i + COUNT, String.valueOf(ruleStats.getValue().getOnLeak()));
i++;
}
}
private void setComponentsStatistics(DbSession dbSession, NewIssuesStatistics.Stats stats) {
Metric metric = Metric.COMPONENT;
int i = 1;
- for (Map.Entry<String, MetricStatsInt> componentStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getTotal)) {
+ for (Map.Entry<String, MetricStatsInt> componentStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) {
String uuid = componentStats.getKey();
String componentName = dbClient.componentDao().selectOrFailByUuid(dbSession, uuid).name();
setFieldValue(metric + DOT + i + LABEL, componentName);
- setFieldValue(metric + DOT + i + COUNT, String.valueOf(componentStats.getValue().getTotal()));
+ setFieldValue(metric + DOT + i + COUNT, String.valueOf(componentStats.getValue().getOnLeak()));
i++;
}
}
private void setTagsStatistics(NewIssuesStatistics.Stats stats) {
Metric metric = Metric.TAG;
int i = 1;
- for (Map.Entry<String, MetricStatsInt> tagStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getTotal)) {
- setFieldValue(metric + DOT + i + COUNT, String.valueOf(tagStats.getValue().getTotal()));
+ for (Map.Entry<String, MetricStatsInt> tagStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) {
+ setFieldValue(metric + DOT + i + COUNT, String.valueOf(tagStats.getValue().getOnLeak()));
setFieldValue(metric + DOT + i + ".label", tagStats.getKey());
i++;
}
private void setAssigneesStatistics(NewIssuesStatistics.Stats stats) {
Metric metric = Metric.ASSIGNEE;
- ToIntFunction<MetricStatsInt> biggerCriteria = MetricStatsInt::getTotal;
int i = 1;
- for (Map.Entry<String, MetricStatsInt> assigneeStats : fiveBiggest(stats.getDistributedMetricStats(metric), biggerCriteria)) {
+ for (Map.Entry<String, MetricStatsInt> assigneeStats : fiveBiggest(stats.getDistributedMetricStats(metric), MetricStatsInt::getOnLeak)) {
String login = assigneeStats.getKey();
UserDoc user = userIndex.getNullableByLogin(login);
String name = user == null ? login : user.name();
setFieldValue(metric + DOT + i + LABEL, name);
- setFieldValue(metric + DOT + i + COUNT, String.valueOf(biggerCriteria.applyAsInt(assigneeStats.getValue())));
+ setFieldValue(metric + DOT + i + COUNT, String.valueOf(assigneeStats.getValue().getOnLeak()));
i++;
}
}
private void setSeverityStatistics(NewIssuesStatistics.Stats stats) {
DistributedMetricStatsInt distributedMetricStats = stats.getDistributedMetricStats(SEVERITY);
- setFieldValue(SEVERITY + COUNT, String.valueOf(distributedMetricStats.getTotal()));
+ setFieldValue(SEVERITY + COUNT, String.valueOf(distributedMetricStats.getOnLeak()));
for (String severity : Severity.ALL) {
setFieldValue(
SEVERITY + DOT + severity + COUNT,
- String.valueOf(distributedMetricStats.getForLabel(severity).map(MetricStatsInt::getTotal).orElse(0)));
+ String.valueOf(distributedMetricStats.getForLabel(severity).map(MetricStatsInt::getOnLeak).orElse(0)));
}
}
}
}
- public Map<String, Stats> assigneesStatistics() {
+ public Map<String, Stats> getAssigneesStatistics() {
return assigneesStatistics;
}
return globalStatistics.hasIssues();
}
- enum Metric {
+ public boolean hasIssuesOnLeak() {
+ return globalStatistics.hasIssuesOnLeak();
+ }
+
+ public boolean hasIssuesOffLeak() {
+ return globalStatistics.hasIssuesOffLeak();
+ }
+
+ public enum Metric {
SEVERITY(true), TAG(true), COMPONENT(true), ASSIGNEE(true), EFFORT(false), RULE(true);
private final boolean isComputedByDistribution;
return getDistributedMetricStats(SEVERITY).getTotal() > 0;
}
+ public boolean hasIssuesOnLeak() {
+ return getDistributedMetricStats(SEVERITY).getOnLeak() > 0;
+ }
+
+ public boolean hasIssuesOffLeak() {
+ return getDistributedMetricStats(SEVERITY).getOffLeak() > 0;
+ }
+
}
}
*/
package org.sonar.server.computation.task.projectanalysis.step;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
+import org.mockito.exceptions.verification.junit.ArgumentsAreDifferent;
import org.sonar.api.notifications.Notification;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.Duration;
import org.sonar.server.computation.task.projectanalysis.issue.IssueCache;
import org.sonar.server.computation.task.projectanalysis.issue.RuleRepositoryRule;
import org.sonar.server.computation.task.step.ComputationStep;
+import org.sonar.server.issue.notification.DistributedMetricStatsInt;
import org.sonar.server.issue.notification.IssueChangeNotification;
import org.sonar.server.issue.notification.MyNewIssuesNotification;
import org.sonar.server.issue.notification.NewIssuesNotification;
import org.sonar.server.issue.notification.NewIssuesNotificationFactory;
import org.sonar.server.issue.notification.NewIssuesStatistics;
import org.sonar.server.notification.NotificationService;
+import org.sonar.server.util.cache.DiskCache;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.db.component.ComponentTesting.newBranchDto;
private static final String BRANCH_NAME = "feature";
private static final long ANALYSE_DATE = 123L;
+ private static final int FIVE_MINUTES_IN_MS = 1000 * 60 * 5;
private static final Duration ISSUE_DURATION = Duration.create(100L);
private static final String ISSUE_ASSIGNEE = "John";
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
.setRoot(PROJECT);
-
@Rule
public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule()
.setBranch(new DefaultBranchImpl())
.setAnalysisDate(new Date(ANALYSE_DATE));
-
@Rule
public RuleRepositoryRule ruleRepository = new RuleRepositoryRule();
-
@Rule
public TemporaryFolder temp = new TemporaryFolder();
new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION)
.setCreationDate(new Date(ANALYSE_DATE)))
.close();
-
when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
underTest.execute();
- verify(notificationService).deliver(any(NewIssuesNotification.class));
+ verify(notificationService).deliver(newIssuesNotificationMock);
verify(newIssuesNotificationMock).setProject(PROJECT.getPublicKey(), PROJECT.getUuid(), PROJECT.getName(), null);
verify(newIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(newIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), any(NewIssuesStatistics.Stats.class));
}
@Test
- public void send_global_new_issues_notification_on_branch() throws Exception {
- ComponentDto project = newPrivateProjectDto(newOrganizationDto());
- ComponentDto branch = newProjectBranch(project, newBranchDto(project).setKey(BRANCH_NAME));
- ComponentDto file = newFileDto(branch);
- treeRootHolder.setRoot(builder(Type.PROJECT, 2).setKey(branch.getDbKey()).setPublicKey(branch.getKey()).setName(branch.longName()).setUuid(branch.uuid()).addChildren(
- builder(Component.Type.FILE, 11).setKey(file.getDbKey()).setPublicKey(file.getKey()).setName(file.longName()).build()).build());
+ public void send_global_new_issues_notification_only_for_non_backdated_issues() {
+ Random random = new Random();
+ Integer[] efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).toArray(Integer[]::new);
+ Integer[] backDatedEfforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10 + random.nextInt(100)).toArray(Integer[]::new);
+ Duration expectedEffort = Duration.create(Arrays.stream(efforts).mapToInt(i -> i).sum());
+ List<DefaultIssue> issues = Stream.concat(Arrays.stream(efforts)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setCreationDate(new Date(ANALYSE_DATE))),
+ Arrays.stream(backDatedEfforts)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setCreationDate(new Date(ANALYSE_DATE - FIVE_MINUTES_IN_MS))))
+ .collect(Collectors.toList());
+ Collections.shuffle(issues);
+ DiskCache<DefaultIssue>.DiskAppender issueCache = this.issueCache.newAppender();
+ issues.forEach(issueCache::append);
+ when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+
+ underTest.execute();
+
+ verify(notificationService).deliver(newIssuesNotificationMock);
+ ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = ArgumentCaptor.forClass(NewIssuesStatistics.Stats.class);
+ verify(newIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
+ verify(newIssuesNotificationMock).setDebt(expectedEffort);
+ NewIssuesStatistics.Stats stats = statsCaptor.getValue();
+ assertThat(stats.hasIssues()).isTrue();
+ // just checking all issues have been added to the stats
+ DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.SEVERITY);
+ assertThat(severity.getOnLeak()).isEqualTo(efforts.length);
+ assertThat(severity.getOffLeak()).isEqualTo(backDatedEfforts.length);
+ assertThat(severity.getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);
+ }
+
+ @Test
+ public void do_not_send_global_new_issues_notification_if_issue_has_been_backdated() {
issueCache.newAppender().append(
- new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION)).close();
+ new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION)
+ .setCreationDate(new Date(ANALYSE_DATE - FIVE_MINUTES_IN_MS)))
+ .close();
+ when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+
+ underTest.execute();
+ verify(notificationService, never()).deliver(any(Notification.class));
+ }
+
+ @Test
+ public void send_global_new_issues_notification_on_branch() throws Exception {
+ ComponentDto branch = setUpProjectWithBranch();
+ issueCache.newAppender().append(
+ new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION).setCreationDate(new Date(ANALYSE_DATE))).close();
when(notificationService.hasProjectSubscribersForTypes(branch.uuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
analysisMetadataHolder.setBranch(newBranch());
underTest.execute();
- verify(notificationService).deliver(any(NewIssuesNotification.class));
+ verify(notificationService).deliver(newIssuesNotificationMock);
verify(newIssuesNotificationMock).setProject(branch.getKey(), branch.uuid(), branch.longName(), BRANCH_NAME);
verify(newIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(newIssuesNotificationMock).setStatistics(eq(branch.longName()), any(NewIssuesStatistics.Stats.class));
verify(newIssuesNotificationMock).setDebt(ISSUE_DURATION);
}
+ @Test
+ public void do_not_send_global_new_issues_notification_on_branch_if_issue_has_been_backdated() throws Exception {
+ ComponentDto branch = setUpProjectWithBranch();
+ issueCache.newAppender().append(
+ new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION).setCreationDate(new Date(ANALYSE_DATE - FIVE_MINUTES_IN_MS))).close();
+ when(notificationService.hasProjectSubscribersForTypes(branch.uuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+ analysisMetadataHolder.setBranch(newBranch());
+
+ underTest.execute();
+
+ verify(notificationService, never()).deliver(any(Notification.class));
+ }
+
@Test
public void send_new_issues_notification_to_user() throws Exception {
issueCache.newAppender().append(
new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION).setAssignee(ISSUE_ASSIGNEE)
.setCreationDate(new Date(ANALYSE_DATE)))
.close();
-
when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
underTest.execute();
- verify(notificationService, times(2)).deliver(any(Notification.class));
+ verify(notificationService).deliver(newIssuesNotificationMock);
+ verify(notificationService).deliver(myNewIssuesNotificationMock);
verify(myNewIssuesNotificationMock).setAssignee(ISSUE_ASSIGNEE);
verify(myNewIssuesNotificationMock).setProject(PROJECT.getPublicKey(), PROJECT.getUuid(), PROJECT.getName(), null);
verify(myNewIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE));
verify(myNewIssuesNotificationMock).setDebt(ISSUE_DURATION);
}
+ @Test
+ public void send_new_issues_notification_to_user_only_for_those_assigned_to_her() {
+ Random random = new Random();
+ Integer[] assigned = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).toArray(Integer[]::new);
+ Integer[] assignedToOther = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10 + random.nextInt(100)).toArray(Integer[]::new);
+ Duration expectedEffort = Duration.create(Arrays.stream(assigned).mapToInt(i -> i).sum());
+ String assignee = randomAlphanumeric(5);
+ String otherAssignee = randomAlphanumeric(5);
+ List<DefaultIssue> issues = Stream.concat(Arrays.stream(assigned)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setAssignee(assignee)
+ .setCreationDate(new Date(ANALYSE_DATE))),
+ Arrays.stream(assignedToOther)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setAssignee(otherAssignee)
+ .setCreationDate(new Date(ANALYSE_DATE))))
+ .collect(Collectors.toList());
+ Collections.shuffle(issues);
+ DiskCache<DefaultIssue>.DiskAppender issueCache = this.issueCache.newAppender();
+ issues.forEach(issueCache::append);
+ when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+ MyNewIssuesNotification myNewIssuesNotificationMock2 = createMyNewIssuesNotificationMock();
+ when(newIssuesNotificationFactory.newMyNewIssuesNotification())
+ .thenReturn(myNewIssuesNotificationMock)
+ .thenReturn(myNewIssuesNotificationMock2);
+
+ underTest.execute();
+
+ verify(notificationService).deliver(newIssuesNotificationMock);
+ verify(notificationService).deliver(myNewIssuesNotificationMock);
+ verify(notificationService).deliver(myNewIssuesNotificationMock2);
+
+ MyNewIssuesNotification effectiveMyNewIssuesNotificationMock = this.myNewIssuesNotificationMock;
+ try {
+ verify(effectiveMyNewIssuesNotificationMock).setAssignee(assignee);
+ } catch (ArgumentsAreDifferent e) {
+ assertThat(e.getMessage())
+ .contains("Wanted:\nmyNewIssuesNotification.setAssignee(\"" + assignee + "\")")
+ .contains("Actual invocation has different arguments:\n" +
+ "myNewIssuesNotification.setAssignee(\"" + otherAssignee + "\")");
+ effectiveMyNewIssuesNotificationMock = myNewIssuesNotificationMock2;
+ }
+ ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = ArgumentCaptor.forClass(NewIssuesStatistics.Stats.class);
+ verify(effectiveMyNewIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
+ verify(effectiveMyNewIssuesNotificationMock).setDebt(expectedEffort);
+ NewIssuesStatistics.Stats stats = statsCaptor.getValue();
+ assertThat(stats.hasIssues()).isTrue();
+ // just checking all issues have been added to the stats
+ DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.SEVERITY);
+ assertThat(severity.getOnLeak()).isEqualTo(assigned.length);
+ assertThat(severity.getOffLeak()).isEqualTo(0);
+ assertThat(severity.getTotal()).isEqualTo(assigned.length);
+ }
+
+ @Test
+ public void send_new_issues_notification_to_user_only_for_non_backdated_issues() throws Exception {
+ Random random = new Random();
+ Integer[] efforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10_000 * i).toArray(Integer[]::new);
+ Integer[] backDatedEfforts = IntStream.range(0, 1 + random.nextInt(10)).mapToObj(i -> 10 + random.nextInt(100)).toArray(Integer[]::new);
+ Duration expectedEffort = Duration.create(Arrays.stream(efforts).mapToInt(i -> i).sum());
+ List<DefaultIssue> issues = Stream.concat(Arrays.stream(efforts)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setAssignee(ISSUE_ASSIGNEE)
+ .setCreationDate(new Date(ANALYSE_DATE))),
+ Arrays.stream(backDatedEfforts)
+ .map(effort -> new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(Duration.create(effort))
+ .setAssignee(ISSUE_ASSIGNEE)
+ .setCreationDate(new Date(ANALYSE_DATE - FIVE_MINUTES_IN_MS))))
+ .collect(Collectors.toList());
+ Collections.shuffle(issues);
+ DiskCache<DefaultIssue>.DiskAppender issueCache = this.issueCache.newAppender();
+ issues.forEach(issueCache::append);
+ when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+
+ underTest.execute();
+
+ verify(notificationService).deliver(newIssuesNotificationMock);
+ verify(notificationService).deliver(myNewIssuesNotificationMock);
+ verify(myNewIssuesNotificationMock).setAssignee(ISSUE_ASSIGNEE);
+ ArgumentCaptor<NewIssuesStatistics.Stats> statsCaptor = ArgumentCaptor.forClass(NewIssuesStatistics.Stats.class);
+ verify(myNewIssuesNotificationMock).setStatistics(eq(PROJECT.getName()), statsCaptor.capture());
+ verify(myNewIssuesNotificationMock).setDebt(expectedEffort);
+ NewIssuesStatistics.Stats stats = statsCaptor.getValue();
+ assertThat(stats.hasIssues()).isTrue();
+ // just checking all issues have been added to the stats
+ DistributedMetricStatsInt severity = stats.getDistributedMetricStats(NewIssuesStatistics.Metric.SEVERITY);
+ assertThat(severity.getOnLeak()).isEqualTo(efforts.length);
+ assertThat(severity.getOffLeak()).isEqualTo(backDatedEfforts.length);
+ assertThat(severity.getTotal()).isEqualTo(backDatedEfforts.length + efforts.length);
+ }
+
+ @Test
+ public void do_not_send_new_issues_notification_to_user_if_issue_is_backdated() throws Exception {
+ issueCache.newAppender().append(
+ new DefaultIssue().setSeverity(Severity.BLOCKER).setEffort(ISSUE_DURATION).setAssignee(ISSUE_ASSIGNEE)
+ .setCreationDate(new Date(ANALYSE_DATE - FIVE_MINUTES_IN_MS)))
+ .close();
+ when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
+
+ underTest.execute();
+
+ verify(notificationService, never()).deliver(any(Notification.class));
+ }
+
@Test
public void send_issues_change_notification() throws Exception {
+ sendIssueChangeNotification(ANALYSE_DATE);
+ }
+
+ @Test
+ public void send_issues_change_notification_even_if_issue_is_backdated() throws Exception {
+ sendIssueChangeNotification(ANALYSE_DATE - FIVE_MINUTES_IN_MS);
+ }
+
+ private void sendIssueChangeNotification(long issueCreatedAt) {
ComponentDto project = newPrivateProjectDto(newOrganizationDto()).setDbKey(PROJECT.getKey()).setLongName(PROJECT.getName());
ComponentDto file = newFileDto(project).setDbKey(FILE.getKey()).setLongName(FILE.getName());
RuleDefinitionDto ruleDefinitionDto = newRule();
DefaultIssue issue = newIssue(ruleDefinitionDto, project, file).toDefaultIssue()
- .setNew(false).setChanged(true).setSendNotifications(true).setCreationDate(new Date(ANALYSE_DATE));
+ .setNew(false).setChanged(true).setSendNotifications(true).setCreationDate(new Date(issueCreatedAt));
ruleRepository.add(ruleDefinitionDto.getKey()).setName(ruleDefinitionDto.getName());
issueCache.newAppender().append(issue).close();
when(notificationService.hasProjectSubscribersForTypes(PROJECT.getUuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
ArgumentCaptor<IssueChangeNotification> issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class);
verify(notificationService).deliver(issueChangeNotificationCaptor.capture());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("key")).isEqualTo(issue.key());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("assignee")).isEqualTo(issue.assignee());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("message")).isEqualTo(issue.message());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("ruleName")).isEqualTo(ruleDefinitionDto.getName());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(project.longName());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(project.getKey());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentKey")).isEqualTo(file.getKey());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(file.longName());
+ IssueChangeNotification issueChangeNotification = issueChangeNotificationCaptor.getValue();
+ assertThat(issueChangeNotification.getFieldValue("key")).isEqualTo(issue.key());
+ assertThat(issueChangeNotification.getFieldValue("assignee")).isEqualTo(issue.assignee());
+ assertThat(issueChangeNotification.getFieldValue("message")).isEqualTo(issue.message());
+ assertThat(issueChangeNotification.getFieldValue("ruleName")).isEqualTo(ruleDefinitionDto.getName());
+ assertThat(issueChangeNotification.getFieldValue("projectName")).isEqualTo(project.longName());
+ assertThat(issueChangeNotification.getFieldValue("projectKey")).isEqualTo(project.getKey());
+ assertThat(issueChangeNotification.getFieldValue("componentKey")).isEqualTo(file.getKey());
+ assertThat(issueChangeNotification.getFieldValue("componentName")).isEqualTo(file.longName());
}
@Test
public void send_issues_change_notification_on_branch() throws Exception {
+ sendIssueChangeNotificationOnBranch(ANALYSE_DATE);
+ }
+
+ @Test
+ public void send_issues_change_notification_on_branch_even_if_issue_is_backdated() throws Exception {
+ sendIssueChangeNotificationOnBranch(ANALYSE_DATE - FIVE_MINUTES_IN_MS);
+ }
+
+ private void sendIssueChangeNotificationOnBranch(long issueCreatedAt) {
ComponentDto project = newPrivateProjectDto(newOrganizationDto());
ComponentDto branch = newProjectBranch(project, newBranchDto(project).setKey(BRANCH_NAME));
ComponentDto file = newFileDto(branch);
treeRootHolder.setRoot(builder(Type.PROJECT, 2).setKey(branch.getDbKey()).setPublicKey(branch.getKey()).setName(branch.longName()).setUuid(branch.uuid()).addChildren(
- builder(Component.Type.FILE, 11).setKey(file.getDbKey()).setPublicKey(file.getKey()).setName(file.longName()).build()).build());
+ builder(Type.FILE, 11).setKey(file.getDbKey()).setPublicKey(file.getKey()).setName(file.longName()).build()).build());
RuleDefinitionDto ruleDefinitionDto = newRule();
DefaultIssue issue = newIssue(ruleDefinitionDto, branch, file).toDefaultIssue()
.setNew(false)
.setChanged(true)
- .setSendNotifications(true);
+ .setSendNotifications(true)
+ .setCreationDate(new Date(issueCreatedAt));
ruleRepository.add(ruleDefinitionDto.getKey()).setName(ruleDefinitionDto.getName());
issueCache.newAppender().append(issue).close();
when(notificationService.hasProjectSubscribersForTypes(branch.uuid(), SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
ArgumentCaptor<IssueChangeNotification> issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class);
verify(notificationService).deliver(issueChangeNotificationCaptor.capture());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectName")).isEqualTo(branch.longName());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("projectKey")).isEqualTo(branch.getKey());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("branch")).isEqualTo(BRANCH_NAME);
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentKey")).isEqualTo(file.getKey());
- assertThat(issueChangeNotificationCaptor.getValue().getFieldValue("componentName")).isEqualTo(file.longName());
+ IssueChangeNotification issueChangeNotification = issueChangeNotificationCaptor.getValue();
+ assertThat(issueChangeNotification.getFieldValue("projectName")).isEqualTo(branch.longName());
+ assertThat(issueChangeNotification.getFieldValue("projectKey")).isEqualTo(branch.getKey());
+ assertThat(issueChangeNotification.getFieldValue("branch")).isEqualTo(BRANCH_NAME);
+ assertThat(issueChangeNotification.getFieldValue("componentKey")).isEqualTo(file.getKey());
+ assertThat(issueChangeNotification.getFieldValue("componentName")).isEqualTo(file.longName());
}
private NewIssuesNotification createNewIssuesNotificationMock() {
return branch;
}
+ private ComponentDto setUpProjectWithBranch() {
+ ComponentDto project = newPrivateProjectDto(newOrganizationDto());
+ ComponentDto branch = newProjectBranch(project, newBranchDto(project).setKey(BRANCH_NAME));
+ ComponentDto file = newFileDto(branch);
+ treeRootHolder.setRoot(builder(Type.PROJECT, 2).setKey(branch.getDbKey()).setPublicKey(branch.getKey()).setName(branch.longName()).setUuid(branch.uuid()).addChildren(
+ builder(Type.FILE, 11).setKey(file.getDbKey()).setPublicKey(file.getKey()).setName(file.longName()).build()).build());
+ return branch;
+ }
+
@Override
protected ComputationStep step() {
return underTest;
assertThat(underTest.globalStatistics().effort().getTotal()).isEqualTo(15L);
assertThat(underTest.globalStatistics().hasIssues()).isTrue();
assertThat(underTest.hasIssues()).isTrue();
- assertThat(underTest.assigneesStatistics().get("maynard").hasIssues()).isTrue();
+ assertThat(underTest.getAssigneesStatistics().get("maynard").hasIssues()).isTrue();
}
@Test
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.SEVERITY);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertStats(distribution, Severity.INFO, 1, 0, 1);
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.SEVERITY);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertStats(distribution, Severity.INFO, 0, 1, 1);
underTest.add(new DefaultIssue().setSeverity(null).setAssignee(assignee).setNew(new Random().nextBoolean()));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.SEVERITY);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.SEVERITY);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getTotal()).isEqualTo(1);
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 1, 0, 1)));
}
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
- NewIssuesStatistics.Stats stats = underTest.assigneesStatistics().get(assignee);
+ NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.COMPONENT);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> componentUuids.forEach(componentUuid -> assertStats(distribution, componentUuid, 0, 1, 1)));
underTest.add(new DefaultIssue().setComponentUuid(null).setAssignee(assignee).setNew(new Random().nextBoolean()));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getTotal()).isEqualTo(1);
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
- NewIssuesStatistics.Stats stats = underTest.assigneesStatistics().get(assignee);
+ NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
DistributedMetricStatsInt assigneeDistribution = stats.getDistributedMetricStats(Metric.RULE);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 1, 0, 1)));
.forEach(underTest::add);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> ruleKeys.forEach(ruleKey -> assertStats(distribution, RuleKey.of(repository, ruleKey).toString(), 0, 1, 1)));
}
underTest.add(new DefaultIssue().setRuleKey(null).setAssignee(assignee).setNew(new Random().nextBoolean()));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getTotal()).isEqualTo(0);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 1, 0, 1));
assignees.forEach(assignee -> {
- NewIssuesStatistics.Stats stats = underTest.assigneesStatistics().get(assignee);
+ NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
assertThat(assigneeStats.getOnLeak()).isEqualTo(1);
assertThat(assigneeStats.getOffLeak()).isEqualTo(0);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
assignees.forEach(assignee -> assertStats(globalDistribution, assignee, 0, 1, 1));
assignees.forEach(assignee -> {
- NewIssuesStatistics.Stats stats = underTest.assigneesStatistics().get(assignee);
+ NewIssuesStatistics.Stats stats = underTest.getAssigneesStatistics().get(assignee);
DistributedMetricStatsInt assigneeStats = stats.getDistributedMetricStats(Metric.ASSIGNEE);
assertThat(assigneeStats.getOnLeak()).isEqualTo(0);
assertThat(assigneeStats.getOffLeak()).isEqualTo(1);
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
assertThat(globalDistribution.getTotal()).isEqualTo(0);
assertThat(globalDistribution.getForLabel(null).isPresent()).isFalse();
- assertThat(underTest.assigneesStatistics()).isEmpty();
+ assertThat(underTest.getAssigneesStatistics()).isEmpty();
}
@Test
underTest.add(new DefaultIssue().setTags(tags).setAssignee(assignee).setNew(true));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 1, 0, 1)));
}
underTest.add(new DefaultIssue().setTags(tags).setAssignee(assignee).setNew(false));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> tags.forEach(tag -> assertStats(distribution, tag, 0, 1, 1)));
}
underTest.add(new DefaultIssue().setTags(Collections.emptyList()).setAssignee(assignee).setNew(new Random().nextBoolean()));
DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
- DistributedMetricStatsInt assigneeDistribution = underTest.assigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
+ DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getTotal()).isEqualTo(0);
.forEach(underTest::add);
MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
- MetricStatsLong assigneeDistribution = underTest.assigneesStatistics().get(assignee).effort();
+ MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getOnLeak()).isEqualTo(expected);
.forEach(underTest::add);
MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
- MetricStatsLong assigneeDistribution = underTest.assigneesStatistics().get(assignee).effort();
+ MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> {
assertThat(distribution.getOnLeak()).isEqualTo(0);
underTest.add(new DefaultIssue().setEffort(null).setAssignee(assignee).setNew(new Random().nextBoolean()));
MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
- MetricStatsLong assigneeDistribution = underTest.assigneesStatistics().get(assignee).effort();
+ MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
Stream.of(globalDistribution, assigneeDistribution)
.forEach(distribution -> assertThat(distribution.getTotal()).isEqualTo(0));
}
*/
package org.sonarqube.tests.issue;
+import com.google.common.collect.ImmutableList;
import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.SonarScanner;
import java.io.File;
+import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
+import javax.mail.MessagingException;
+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.IssueQuery;
+import org.sonarqube.tests.Tester;
import org.sonarqube.ws.client.PostRequest;
+import org.sonarqube.ws.client.WsClient;
+import org.subethamail.wiser.Wiser;
import util.ItUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
+import static util.ItUtils.newUserWsClient;
import static util.ItUtils.pluginArtifact;
import static util.ItUtils.projectDir;
import static util.ItUtils.xooPlugin;
private static final String SAMPLE_PROJECT_NAME = "Creation date sample";
private static final String SAMPLE_QUALITY_PROFILE_NAME = "creation-date-plugin";
+ private final static String USER_LOGIN = "tester";
+ private final static String USER_PASSWORD = "tester";
+ private static final String USER_EMAIL = "tester@example.org";
+
@ClassRule
public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv()
.addPlugin(xooPlugin())
.addPlugin(ItUtils.pluginArtifact("backdating-plugin-v1"))
.addPlugin(ItUtils.pluginArtifact("backdating-customplugin"))
.build();
+ @Rule
+ public Tester tester = new Tester(ORCHESTRATOR);
+
+ private static Wiser smtpServer;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ smtpServer = new Wiser(0);
+ smtpServer.start();
+ }
@Before
- public void cleanup() {
+ public void before() throws InterruptedException, MessagingException, IOException {
ORCHESTRATOR.resetData();
+
+ // Configure Sonar
+ tester.settings().setGlobalSetting("email.smtp_host.secured", "localhost");
+ tester.settings().setGlobalSetting("email.smtp_port.secured", Integer.toString(smtpServer.getServer().getPort()));
+
+ // Create a user and register her to receive notification on NewIssues
+ tester.users().generate(t -> t.setLogin(USER_LOGIN).setPassword(USER_PASSWORD).setEmail(USER_EMAIL)
+ .setScmAccounts(ImmutableList.of("jhenry")));
+ // 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", "SQ-MyNewIssues")
+ .setParam("channel", "EmailNotificationChannel"))
+ .failIfNotSuccessful();
+ }
+
+ @AfterClass
+ public static void stop() {
+ if (smtpServer != null) {
+ smtpServer.stop();
+ }
}
@Test
- public void should_use_scm_date_for_new_issues_if_plugin_updated() {
+ public void should_use_scm_date_for_new_issues_if_plugin_updated() throws InterruptedException, MessagingException, IOException {
ItUtils.restoreProfile(ORCHESTRATOR, getClass().getResource("/issue/IssueCreationDatePluginChangedTest/profile.xml"));
ORCHESTRATOR.getServer().provisionProject(SAMPLE_PROJECT_KEY, SAMPLE_PROJECT_NAME);
.setProperty("sonar.scm.disabled", "false");
ORCHESTRATOR.executeBuild(scanner);
- List<Issue> issues = getIssues(issueQuery().components("creation-date-sample:src/main/xoo/sample/Sample.xoo"));
-
// Check that issue is backdated to SCM (because it is the first analysis)
+ List<Issue> issues = getIssues(issueQuery().components("creation-date-sample:src/main/xoo/sample/Sample.xoo"));
assertThat(issues)
.extracting(Issue::line, Issue::creationDate)
.containsExactly(tuple(1, dateTimeParse("2005-01-01T00:00:00+0000")));
+ // ensure no notification is sent as all issues are off the leak period
+ waitUntilAllNotificationsAreDelivered();
+ assertThat(smtpServer.getMessages()).isEmpty();
+
// Update the plugin
// uninstall plugin V1
ItUtils.newAdminWsClient(ORCHESTRATOR).wsConnector().call(new PostRequest("api/plugins/uninstall").setParam("key", "backdating")).failIfNotSuccessful();
.containsExactly(tuple(1, dateTimeParse("2005-01-01T00:00:00+0000")),
tuple(2, dateTimeParse("2005-01-01T00:00:00+0000")),
tuple(3, dateTimeParse("2005-01-01T00:00:00+0000")));
+
+ // ensure no notification is sent as all issues are off the leak period
+ waitUntilAllNotificationsAreDelivered();
+ assertThat(smtpServer.getMessages()).isEmpty();
}
private static List<Issue> getIssues(IssueQuery query) {
}
}
+ private static void waitUntilAllNotificationsAreDelivered() throws InterruptedException {
+ for (int i = 0; i < 10; i++) {
+ if (smtpServer.getMessages().size() == 3) {
+ break;
+ }
+ Thread.sleep(1_000);
+ }
+ }
+
}
@Test
public void notifications_for_personalized_emails() throws Exception {
setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", USER_LOGIN);
+ // 1st analysis without any issue (because no file is analyzed)
+ runProjectAnalysis(ORCHESTRATOR, "issue/xoo-with-scm", "sonar.scm.provider", "xoo", "sonar.scm.disabled", "false", "sonar.exclusions", "**/*");
+
+ waitUntilAllNotificationsAreDelivered(2);
+ assertThat(smtpServer.getMessages()).isEmpty();
+
+ // run 2nd analysis which will generate issues on the leak period
runProjectAnalysis(ORCHESTRATOR, "issue/xoo-with-scm", "sonar.scm.provider", "xoo", "sonar.scm.disabled", "false");
waitUntilAllNotificationsAreDelivered(2);