diff options
author | Jenkins CI <ci@sonarsource.com> | 2015-10-27 12:11:10 +0100 |
---|---|---|
committer | Jenkins CI <ci@sonarsource.com> | 2015-10-27 12:11:10 +0100 |
commit | 4a148c6971a77255a930226952aa4876241bf701 (patch) | |
tree | aabf1276b651495a7d751caf1e698eaddab2e9a0 /server | |
parent | bb19b581401ab54b1fb473b98dc60c18740378fe (diff) | |
parent | a4774e7d5a7a1e5903ed79f431a7c0f3c071c145 (diff) | |
download | sonarqube-4a148c6971a77255a930226952aa4876241bf701.tar.gz sonarqube-4a148c6971a77255a930226952aa4876241bf701.zip |
Automatic merge from branch-5.2
* origin/branch-5.2:
SONAR-6834 Purge CE_ACTIVITY when deleting a project
SONAR-5876 Add l10n info for the metric
SONAR-6414 Indexing tests should update updatedAt field
SONAR-6824 Use SCM Info repo
SONAR-5794 Send notification step should not use batch repo to get project name
Diffstat (limited to 'server')
7 files changed, 231 insertions, 173 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java index 5c312104dfe..f2299f4f69b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java @@ -21,8 +21,6 @@ package org.sonar.server.computation.source; import com.google.common.base.Optional; import org.sonar.api.measures.CoreMetrics; -import org.sonar.batch.protocol.output.BatchReport; -import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.CrawlerDepthLimit; import org.sonar.server.computation.component.PathAwareVisitorAdapter; @@ -30,17 +28,18 @@ import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureRepository; import org.sonar.server.computation.metric.Metric; import org.sonar.server.computation.metric.MetricRepository; +import org.sonar.server.computation.scm.ScmInfo; +import org.sonar.server.computation.scm.ScmInfoRepository; import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER; public class LastCommitVisitor extends PathAwareVisitorAdapter<LastCommitVisitor.LastCommit> { - private final BatchReportReader reportReader; private final MeasureRepository measureRepository; + private final ScmInfoRepository scmInfoRepository; private final Metric lastCommitDateMetric; - public LastCommitVisitor(BatchReportReader reportReader, MetricRepository metricRepository, - MeasureRepository measureRepository) { + public LastCommitVisitor(MetricRepository metricRepository, MeasureRepository measureRepository, ScmInfoRepository scmInfoRepository) { super(CrawlerDepthLimit.LEAVES, POST_ORDER, new SimpleStackElementFactory<LastCommit>() { @Override public LastCommit createForAny(Component component) { @@ -53,8 +52,8 @@ public class LastCommitVisitor extends PathAwareVisitorAdapter<LastCommitVisitor return null; } }); - this.reportReader = reportReader; this.measureRepository = measureRepository; + this.scmInfoRepository = scmInfoRepository; this.lastCommitDateMetric = metricRepository.getByKey(CoreMetrics.LAST_COMMIT_DATE_KEY); } @@ -79,21 +78,10 @@ public class LastCommitVisitor extends PathAwareVisitorAdapter<LastCommitVisitor // since previous analysis (optimization to decrease execution of blame commands). In this case // the date is loaded from database, as it did not change from previous analysis. - // TODO We should use ScmInfoRepository instead of reading the report - // (but should only be done when the repo is only used once per component, - // as it's done with ComponentIssuesRepository, to not increase number of calls to file_sources) - BatchReport.Changesets changesets = reportReader.readChangesets(file.getReportAttributes().getRef()); - if (changesets == null) { - Optional<Measure> baseMeasure = measureRepository.getBaseMeasure(file, lastCommitDateMetric); - if (baseMeasure.isPresent()) { - path.current().addDate(baseMeasure.get().getLongValue()); - } - } else { - for (BatchReport.Changesets.Changeset changeset : changesets.getChangesetList()) { - if (changeset.hasDate()) { - path.current().addDate(changeset.getDate()); - } - } + Optional<ScmInfo> scmInfoOptional = scmInfoRepository.getScmInfo(file); + if (scmInfoOptional.isPresent()) { + ScmInfo scmInfo = scmInfoOptional.get(); + path.current().addDate(scmInfo.getLatestChangeset().getDate()); } saveAndAggregate(file, path); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java index 84b0a1d117f..e84ae899a00 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java @@ -24,6 +24,7 @@ import java.util.Date; import java.util.Map; import java.util.Set; import org.sonar.core.issue.DefaultIssue; +import org.sonar.core.util.CloseableIterator; import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.TreeRootHolder; @@ -35,7 +36,6 @@ 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.core.util.CloseableIterator; /** * Reads issues from disk cache and send related notifications. For performance reasons, @@ -77,54 +77,63 @@ public class SendIssueNotificationsStep implements ComputationStep { private void doExecute(Component project) { NewIssuesStatistics newIssuesStats = new NewIssuesStatistics(); CloseableIterator<DefaultIssue> issues = issueCache.traverse(); - String projectName = reportReader.readComponent(reportReader.readMetadata().getRootComponentRef()).getName(); try { - while (issues.hasNext()) { - DefaultIssue issue = issues.next(); - if (issue.isNew() && issue.resolution() == null) { - newIssuesStats.add(issue); - } else if (issue.isChanged() && issue.mustSendNotifications()) { - IssueChangeNotification changeNotification = new IssueChangeNotification(); - changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName()); - changeNotification.setIssue(issue); - changeNotification.setProject(project.getKey(), projectName); - service.deliver(changeNotification); - } - } - + processIssues(newIssuesStats, issues, project); } finally { issues.close(); } - sendNewIssuesStatistics(newIssuesStats, project, projectName); + if (newIssuesStats.hasIssues()) { + long analysisDate = reportReader.readMetadata().getAnalysisDate(); + sendNewIssuesNotification(newIssuesStats, project, analysisDate); + sendNewIssuesNotificationToAssignees(newIssuesStats, project, analysisDate); + } } - private void sendNewIssuesStatistics(NewIssuesStatistics statistics, Component project, String projectName) { - if (statistics.hasIssues()) { - NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics(); - long analysisDate = reportReader.readMetadata().getAnalysisDate(); - NewIssuesNotification notification = newIssuesNotificationFactory - .newNewIssuesNotication() - .setProject(project.getKey(), project.getUuid(), projectName) - .setAnalysisDate(new Date(analysisDate)) - .setStatistics(projectName, globalStatistics) - .setDebt(globalStatistics.debt()); - service.deliver(notification); + private void processIssues(NewIssuesStatistics newIssuesStats, CloseableIterator<DefaultIssue> issues, Component project) { + while (issues.hasNext()) { + DefaultIssue issue = issues.next(); + if (issue.isNew() && issue.resolution() == null) { + newIssuesStats.add(issue); + } else if (issue.isChanged() && issue.mustSendNotifications()) { + sendIssueChangeNotification(issue, project); + } + } + } - // 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.getKey(), project.getUuid(), projectName) - .setAnalysisDate(new Date(analysisDate)) - .setStatistics(projectName, assigneeStatistics) - .setDebt(assigneeStatistics.debt()); + private void sendIssueChangeNotification(DefaultIssue issue, Component project) { + IssueChangeNotification changeNotification = new IssueChangeNotification(); + changeNotification.setRuleName(rules.getByKey(issue.ruleKey()).getName()); + changeNotification.setIssue(issue); + changeNotification.setProject(project.getKey(), project.getName()); + service.deliver(changeNotification); + } - service.deliver(myNewIssuesNotification); - } + private void sendNewIssuesNotification(NewIssuesStatistics statistics, Component project, long analysisDate) { + NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics(); + NewIssuesNotification notification = newIssuesNotificationFactory + .newNewIssuesNotication() + .setProject(project.getKey(), project.getUuid(), project.getName()) + .setAnalysisDate(new Date(analysisDate)) + .setStatistics(project.getName(), globalStatistics) + .setDebt(globalStatistics.debt()); + 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.getKey(), project.getUuid(), project.getName()) + .setAnalysisDate(new Date(analysisDate)) + .setStatistics(project.getName(), assigneeStatistics) + .setDebt(assigneeStatistics.debt()); + + service.deliver(myNewIssuesNotification); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java index 8c8316e5dbf..96104efd45a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java @@ -50,6 +50,7 @@ import static org.sonar.server.test.index.TestIndexDefinition.FIELD_PROJECT_UUID import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STACKTRACE; import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STATUS; import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_UPDATED_AT; import static org.sonar.server.test.index.TestIndexDefinition.INDEX; import static org.sonar.server.test.index.TestIndexDefinition.TYPE; @@ -99,6 +100,7 @@ public class TestResultSetIterator extends ResultSetIterator<Row> { writer.prop(FIELD_DURATION_IN_MS, test.hasExecutionTimeMs() ? test.getExecutionTimeMs() : null); writer.prop(FIELD_MESSAGE, test.hasMsg() ? test.getMsg() : null); writer.prop(FIELD_STACKTRACE, test.hasStacktrace() ? test.getStacktrace() : null); + writer.prop(FIELD_UPDATED_AT, updatedAt.getTime()); writer.name(FIELD_COVERED_FILES); writer.beginArray(); for (DbFileSources.Test.CoveredFile coveredFile : test.getCoveredFileList()) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java index 9647c66fda3..7cd63ec15c6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java @@ -24,8 +24,6 @@ import com.google.common.collect.Lists; import org.junit.Rule; import org.junit.Test; import org.sonar.api.measures.CoreMetrics; -import org.sonar.batch.protocol.output.BatchReport; -import org.sonar.server.computation.batch.BatchReportReaderRule; import org.sonar.server.computation.batch.TreeRootHolderRule; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.ComponentVisitor; @@ -36,6 +34,8 @@ import org.sonar.server.computation.component.VisitorsCrawler; import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureRepositoryRule; import org.sonar.server.computation.metric.MetricRepositoryRule; +import org.sonar.server.computation.scm.Changeset; +import org.sonar.server.computation.scm.ScmInfoRepositoryRule; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.api.measures.CoreMetrics.LAST_COMMIT_DATE_KEY; @@ -63,15 +63,15 @@ public class LastCommitVisitorTest { public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); @Rule - public BatchReportReaderRule reportReader = new BatchReportReaderRule(); - - @Rule public MetricRepositoryRule metricRepository = new MetricRepositoryRule() .add(CoreMetrics.LAST_COMMIT_DATE); @Rule public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + @Rule + public ScmInfoRepositoryRule scmInfoRepository = new ScmInfoRepositoryRule(); + @Test public void aggregate_date_of_last_commit_to_directories_and_project() { final long FILE_1_DATE = 1_100_000_000_000L; @@ -81,7 +81,7 @@ public class LastCommitVisitorTest { final long FILE_3_DATE = 1_300_000_000_000L; // simulate the output of visitFile() - LastCommitVisitor visitor = new LastCommitVisitor(reportReader, metricRepository, measureRepository) { + LastCommitVisitor visitor = new LastCommitVisitor(metricRepository, measureRepository, scmInfoRepository) { @Override public void visitFile(Component file, Path<LastCommit> path) { long fileDate; @@ -168,7 +168,7 @@ public class LastCommitVisitorTest { measureRepository.addRawMeasure(PROJECT_2_REF, LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(PROJECT_2_DATE)); measureRepository.addRawMeasure(PROJECT_3_REF, LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(PROJECT_3_DATE)); - VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository))); + VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(metricRepository, measureRepository, scmInfoRepository))); underTest.visit(view); // second level of sub-views @@ -183,64 +183,39 @@ public class LastCommitVisitorTest { } @Test - public void compute_date_of_file_from_blame_info_of_report() throws Exception { - VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository))); + public void compute_date_of_file_from_scm_repo() throws Exception { + VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(metricRepository, measureRepository, scmInfoRepository))); - BatchReport.Changesets changesets = BatchReport.Changesets.newBuilder() - .setComponentRef(FILE_1_REF) - .addChangeset(BatchReport.Changesets.Changeset.newBuilder() + scmInfoRepository.setScmInfo(FILE_1_REF, + Changeset.newChangesetBuilder() .setAuthor("john") .setDate(1_500_000_000_000L) .setRevision("rev-1") - .build()) - .addChangeset(BatchReport.Changesets.Changeset.newBuilder() + .build(), + Changeset.newChangesetBuilder() .setAuthor("tom") // this is the most recent change .setDate(1_600_000_000_000L) .setRevision("rev-2") - .build()) - .addChangeset(BatchReport.Changesets.Changeset.newBuilder() + .build(), + Changeset.newChangesetBuilder() .setAuthor("john") .setDate(1_500_000_000_000L) .setRevision("rev-1") - .build()) - .addChangesetIndexByLine(0) - .build(); - reportReader.putChangesets(changesets); - ReportComponent file = createFileComponent(FILE_1_REF); - treeRootHolder.setRoot(file); - - underTest.visit(file); - - assertDate(FILE_1_REF, 1_600_000_000_000L); - } - - private void assertDate(int componentRef, long expectedDate) { - Optional<Measure> measure = measureRepository.getAddedRawMeasure(componentRef, LAST_COMMIT_DATE_KEY); - assertThat(measure.isPresent()).isTrue(); - assertThat(measure.get().getLongValue()).isEqualTo(expectedDate); - } + .build() + ); - /** - * When the file was not changed since previous analysis, than the report may not contain - * the SCM blame information. In this case the date of last commit is loaded - * from the base measure of previous analysis, directly from database - */ - @Test - public void reuse_date_of_previous_analysis_if_blame_info_is_not_in_report() throws Exception { - VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository))); ReportComponent file = createFileComponent(FILE_1_REF); treeRootHolder.setRoot(file); - measureRepository.addBaseMeasure(FILE_1_REF, LAST_COMMIT_DATE_KEY, newMeasureBuilder().create(1_500_000_000L)); underTest.visit(file); - assertDate(FILE_1_REF, 1_500_000_000L); + assertDate(FILE_1_REF, 1_600_000_000_000L); } @Test - public void date_is_not_computed_on_file_if_blame_is_not_in_report_nor_in_previous_analysis() throws Exception { - VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(reportReader, metricRepository, measureRepository))); + public void date_is_not_computed_on_file_if_blame_is_not_in_scm_repo() throws Exception { + VisitorsCrawler underTest = new VisitorsCrawler(Lists.<ComponentVisitor>newArrayList(new LastCommitVisitor(metricRepository, measureRepository, scmInfoRepository))); ReportComponent file = createFileComponent(FILE_1_REF); treeRootHolder.setRoot(file); @@ -250,6 +225,12 @@ public class LastCommitVisitorTest { assertThat(measure.isPresent()).isFalse(); } + private void assertDate(int componentRef, long expectedDate) { + Optional<Measure> measure = measureRepository.getAddedRawMeasure(componentRef, LAST_COMMIT_DATE_KEY); + assertThat(measure.isPresent()).isTrue(); + assertThat(measure.get().getLongValue()).isEqualTo(expectedDate); + } + private ReportComponent createFileComponent(int fileRef) { return ReportComponent.builder(FILE, fileRef).setFileAttributes(new FileAttributes(false, "js")).build(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java index f0d088d383c..cd8512295df 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java @@ -19,92 +19,158 @@ */ package org.sonar.server.computation.step; +import java.util.Date; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.mockito.Mockito; import org.sonar.api.notifications.Notification; import org.sonar.api.rule.Severity; +import org.sonar.api.utils.Duration; import org.sonar.api.utils.System2; -import org.sonar.batch.protocol.Constants; import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.issue.DefaultIssue; import org.sonar.server.computation.batch.BatchReportReaderRule; import org.sonar.server.computation.batch.TreeRootHolderRule; import org.sonar.server.computation.component.Component; -import org.sonar.server.computation.component.ReportComponent; +import org.sonar.server.computation.component.Component.Type; import org.sonar.server.computation.issue.IssueCache; import org.sonar.server.computation.issue.RuleRepository; 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 static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.atLeastOnce; 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.server.computation.component.ReportComponent.builder; public class SendIssueNotificationsStepTest extends BaseStepTest { - private static final String PROJECT_UUID = "PROJECT_UUID"; - private static final String PROJECT_KEY = "PROJECT_KEY"; + static final String PROJECT_UUID = "PROJECT_UUID"; + static final String PROJECT_KEY = "PROJECT_KEY"; + static final String PROJECT_NAME = "PROJECT_NAME"; + + static final long ANALYSE_DATE = 123L; + + static final Duration ISSUE_DURATION = Duration.create(100L); + static final String ISSUE_ASSIGNEE = "John"; + + static final Component PROJECT = builder(Type.PROJECT, 1).setUuid(PROJECT_UUID).setKey(PROJECT_KEY).setName(PROJECT_NAME).build(); @Rule public BatchReportReaderRule reportReader = new BatchReportReaderRule(); @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule() + .setRoot(PROJECT); @Rule public TemporaryFolder temp = new TemporaryFolder(); - NotificationService notifService = mock(NotificationService.class); + NotificationService notificationService = mock(NotificationService.class); + NewIssuesNotificationFactory newIssuesNotificationFactory = mock(NewIssuesNotificationFactory.class); + NewIssuesNotification newIssuesNotificationMock = createNewIssuesNotificationMock(); + MyNewIssuesNotification myNewIssuesNotificationMock = createMyNewIssuesNotificationMock(); + IssueCache issueCache; SendIssueNotificationsStep underTest; @Before public void setUp() throws Exception { issueCache = new IssueCache(temp.newFile(), System2.INSTANCE); - NewIssuesNotificationFactory newIssuesNotificationFactory = mock(NewIssuesNotificationFactory.class, Mockito.RETURNS_DEEP_STUBS); - underTest = new SendIssueNotificationsStep(issueCache, mock(RuleRepository.class), treeRootHolder, notifService, reportReader, newIssuesNotificationFactory); + underTest = new SendIssueNotificationsStep(issueCache, mock(RuleRepository.class), treeRootHolder, notificationService, reportReader, newIssuesNotificationFactory); - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_UUID).setKey(PROJECT_KEY).build()); + when(newIssuesNotificationFactory.newNewIssuesNotication()).thenReturn(newIssuesNotificationMock); + when(newIssuesNotificationFactory.newMyNewIssuesNotification()).thenReturn(myNewIssuesNotificationMock); reportReader.setMetadata(BatchReport.Metadata.newBuilder() .setRootComponentRef(1) - .build()); - reportReader.putComponent(BatchReport.Component.newBuilder() - .setRef(1) - .setType(Constants.ComponentType.PROJECT) - .setKey(PROJECT_KEY) - .setName("Project name") + .setAnalysisDate(ANALYSE_DATE) .build()); } @Test public void do_not_send_notifications_if_no_subscribers() { - when(notifService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(false); + when(notificationService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(false); + + underTest.execute(); + + verify(notificationService, never()).deliver(any(Notification.class)); + } + + @Test + public void send_global_new_issues_notification() throws Exception { + issueCache.newAppender().append( + new DefaultIssue().setSeverity(Severity.BLOCKER).setDebt(ISSUE_DURATION) + ).close(); + + when(notificationService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true); underTest.execute(); - verify(notifService, never()).deliver(any(Notification.class)); + verify(notificationService).deliver(any(NewIssuesNotification.class)); + verify(newIssuesNotificationMock).setProject(PROJECT_KEY, PROJECT_UUID, PROJECT_NAME); + verify(newIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE)); + verify(newIssuesNotificationMock).setStatistics(eq(PROJECT_NAME), any(NewIssuesStatistics.Stats.class)); + verify(newIssuesNotificationMock).setDebt(ISSUE_DURATION); } @Test - public void send_notifications_if_subscribers() { - issueCache.newAppender().append(new DefaultIssue() - .setSeverity(Severity.BLOCKER)).close(); + public void send_new_issues_notification_to_user() throws Exception { + issueCache.newAppender().append( + new DefaultIssue().setSeverity(Severity.BLOCKER).setDebt(ISSUE_DURATION).setAssignee(ISSUE_ASSIGNEE) + ).close(); - when(notifService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true); + when(notificationService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true); underTest.execute(); - verify(notifService).deliver(any(NewIssuesNotification.class)); - verify(notifService, atLeastOnce()).deliver(any(IssueChangeNotification.class)); + verify(notificationService, times(2)).deliver(any(Notification.class)); + verify(myNewIssuesNotificationMock).setAssignee(ISSUE_ASSIGNEE); + verify(myNewIssuesNotificationMock).setProject(PROJECT_KEY, PROJECT_UUID, PROJECT_NAME); + verify(myNewIssuesNotificationMock).setAnalysisDate(new Date(ANALYSE_DATE)); + verify(myNewIssuesNotificationMock).setStatistics(eq(PROJECT_NAME), any(NewIssuesStatistics.Stats.class)); + verify(myNewIssuesNotificationMock).setDebt(ISSUE_DURATION); + } + + @Test + public void send_issues_change_notification() throws Exception { + DefaultIssue issue = new DefaultIssue().setSeverity(Severity.BLOCKER).setDebt(ISSUE_DURATION).setChanged(true).setSendNotifications(true); + issueCache.newAppender().append(issue).close(); + + when(notificationService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true); + + underTest.execute(); + + verify(notificationService).deliver(any(IssueChangeNotification.class)); + } + + private NewIssuesNotification createNewIssuesNotificationMock() { + NewIssuesNotification notification = mock(NewIssuesNotification.class); + when(notification.setProject(anyString(), anyString(), anyString())).thenReturn(notification); + when(notification.setAnalysisDate(any(Date.class))).thenReturn(notification); + when(notification.setStatistics(anyString(), any(NewIssuesStatistics.Stats.class))).thenReturn(notification); + when(notification.setDebt(any(Duration.class))).thenReturn(notification); + return notification; + } + + private MyNewIssuesNotification createMyNewIssuesNotificationMock() { + MyNewIssuesNotification notification = mock(MyNewIssuesNotification.class); + when(notification.setAssignee(anyString())).thenReturn(notification); + when(notification.setProject(anyString(), anyString(), anyString())).thenReturn(notification); + when(notification.setAnalysisDate(any(Date.class))).thenReturn(notification); + when(notification.setStatistics(anyString(), any(NewIssuesStatistics.Stats.class))).thenReturn(notification); + when(notification.setDebt(any(Duration.class))).thenReturn(notification); + return notification; } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java index 1290f7b4b45..4a802feac1c 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java @@ -40,7 +40,6 @@ import org.sonar.api.config.Settings; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; import org.sonar.db.protobuf.DbFileSources; -import org.sonar.server.db.DbClient; import org.sonar.server.es.EsTester; import org.sonar.server.source.index.FileSourcesUpdaterHelper; import org.sonar.server.test.db.TestTesting; @@ -75,7 +74,7 @@ public class TestIndexerTest { public void setUp() { es.truncateIndices(); db.truncateTables(); - underTest = new TestIndexer(new DbClient(db.database(), db.myBatis()), es.client()); + underTest = new TestIndexer(db.getDbClient(), es.client()); underTest.setEnabled(true); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java index fac2e442108..6d6b6acd60b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; -import org.assertj.core.data.MapEntry; import org.elasticsearch.action.update.UpdateRequest; import org.junit.After; import org.junit.Rule; @@ -39,6 +38,17 @@ import org.sonar.test.DbTests; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.data.MapEntry.entry; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILES; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_DURATION_IN_MS; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_MESSAGE; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_NAME; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_PROJECT_UUID; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STACKTRACE; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STATUS; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID; +import static org.sonar.server.test.index.TestIndexDefinition.FIELD_UPDATED_AT; @Category(DbTests.class) public class TestResultSetIteratorTest { @@ -48,6 +58,27 @@ public class TestResultSetIteratorTest { TestResultSetIterator underTest; + private static List<DbFileSources.Test> newFakeTests(int numberOfTests) { + List<DbFileSources.Test> tests = new ArrayList<>(); + for (int i = 1; i <= numberOfTests; i++) { + DbFileSources.Test.Builder test = DbFileSources.Test.newBuilder() + .setUuid("TEST_FILE_UUID_" + i) + .setName("NAME_" + i) + .setStatus(DbFileSources.Test.TestStatus.FAILURE) + .setStacktrace("STACKTRACE_" + i) + .setMsg("MESSAGE_" + i) + .setExecutionTimeMs(i); + for (int j = 1; j <= numberOfTests; j++) { + test.addCoveredFile( + DbFileSources.Test.CoveredFile.newBuilder() + .setFileUuid("MAIN_FILE_UUID_" + j) + .addCoveredLine(j)); + } + tests.add(test.build()); + } + return tests; + } + @After public void after() { if (underTest != null) { @@ -70,14 +101,15 @@ public class TestResultSetIteratorTest { UpdateRequest firstRequest = row.getUpdateRequests().get(0); Map<String, Object> doc = firstRequest.doc().sourceAsMap(); assertThat(doc).contains( - MapEntry.entry(TestIndexDefinition.FIELD_PROJECT_UUID, "P1"), - MapEntry.entry(TestIndexDefinition.FIELD_FILE_UUID, "F1"), - MapEntry.entry(TestIndexDefinition.FIELD_TEST_UUID, "TEST_FILE_UUID_1"), - MapEntry.entry(TestIndexDefinition.FIELD_STATUS, "FAILURE"), - MapEntry.entry(TestIndexDefinition.FIELD_MESSAGE, "MESSAGE_1"), - MapEntry.entry(TestIndexDefinition.FIELD_DURATION_IN_MS, 1), - MapEntry.entry(TestIndexDefinition.FIELD_STACKTRACE, "STACKTRACE_1"), - MapEntry.entry(TestIndexDefinition.FIELD_NAME, "NAME_1")); + entry(FIELD_PROJECT_UUID, "P1"), + entry(FIELD_FILE_UUID, "F1"), + entry(FIELD_TEST_UUID, "TEST_FILE_UUID_1"), + entry(FIELD_STATUS, "FAILURE"), + entry(FIELD_MESSAGE, "MESSAGE_1"), + entry(FIELD_DURATION_IN_MS, 1), + entry(FIELD_STACKTRACE, "STACKTRACE_1"), + entry(FIELD_NAME, "NAME_1"), + entry(FIELD_UPDATED_AT, 1416239042000L)); } /** @@ -103,17 +135,19 @@ public class TestResultSetIteratorTest { UpdateRequest firstRequest = row.getUpdateRequests().get(0); Map<String, Object> doc = firstRequest.doc().sourceAsMap(); assertThat(doc).contains( - MapEntry.entry(TestIndexDefinition.FIELD_PROJECT_UUID, "P1"), - MapEntry.entry(TestIndexDefinition.FIELD_FILE_UUID, "F1"), - MapEntry.entry(TestIndexDefinition.FIELD_TEST_UUID, "U1"), - MapEntry.entry(TestIndexDefinition.FIELD_NAME, "N1")); + entry(FIELD_PROJECT_UUID, "P1"), + entry(FIELD_FILE_UUID, "F1"), + entry(FIELD_TEST_UUID, "U1"), + entry(FIELD_NAME, "N1"), + entry(FIELD_UPDATED_AT, 1416239042000L)); + ; // null values assertThat(doc).containsKeys( - TestIndexDefinition.FIELD_DURATION_IN_MS, - TestIndexDefinition.FIELD_STACKTRACE, - TestIndexDefinition.FIELD_MESSAGE, - TestIndexDefinition.FIELD_STATUS, - TestIndexDefinition.FIELD_COVERED_FILES); + FIELD_DURATION_IN_MS, + FIELD_STACKTRACE, + FIELD_MESSAGE, + FIELD_STATUS, + FIELD_COVERED_FILES); } @Test @@ -170,25 +204,4 @@ public class TestResultSetIteratorTest { } } - private static List<DbFileSources.Test> newFakeTests(int numberOfTests) { - List<DbFileSources.Test> tests = new ArrayList<>(); - for (int i = 1; i <= numberOfTests; i++) { - DbFileSources.Test.Builder test = DbFileSources.Test.newBuilder() - .setUuid("TEST_FILE_UUID_" + i) - .setName("NAME_" + i) - .setStatus(DbFileSources.Test.TestStatus.FAILURE) - .setStacktrace("STACKTRACE_" + i) - .setMsg("MESSAGE_" + i) - .setExecutionTimeMs(i); - for (int j = 1; j <= numberOfTests; j++) { - test.addCoveredFile( - DbFileSources.Test.CoveredFile.newBuilder() - .setFileUuid("MAIN_FILE_UUID_" + j) - .addCoveredLine(j)); - } - tests.add(test.build()); - } - return tests; - } - } |