aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJenkins CI <ci@sonarsource.com>2015-10-27 12:11:10 +0100
committerJenkins CI <ci@sonarsource.com>2015-10-27 12:11:10 +0100
commit4a148c6971a77255a930226952aa4876241bf701 (patch)
treeaabf1276b651495a7d751caf1e698eaddab2e9a0 /server
parentbb19b581401ab54b1fb473b98dc60c18740378fe (diff)
parenta4774e7d5a7a1e5903ed79f431a7c0f3c071c145 (diff)
downloadsonarqube-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')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/source/LastCommitVisitor.java30
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java91
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/source/LastCommitVisitorTest.java71
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java116
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java91
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;
- }
-
}