aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-08-25 18:10:39 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-08-31 09:49:14 +0200
commit27ad46fd2b4f9bcd3becdf0c68b38200e6f6b5b8 (patch)
tree686012aef81b8289a4ccd9fe25a1c272d90e64aa /server
parent62def73057ecf234e2e066231364e57193b005f0 (diff)
downloadsonarqube-27ad46fd2b4f9bcd3becdf0c68b38200e6f6b5b8.tar.gz
sonarqube-27ad46fd2b4f9bcd3becdf0c68b38200e6f6b5b8.zip
SONAR-6730 Create a repository of issues for a given component
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java45
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImpl.java54
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesVisitor.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/issue/MutableComponentIssuesRepository.java37
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImplTest.java92
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryRule.java78
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/issue/IntegrateIssuesVisitorTest.java43
8 files changed, 356 insertions, 3 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
index 4c16f1ed92e..664a04ace82 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ReportComputeEngineContainerPopulator.java
@@ -36,6 +36,7 @@ import org.sonar.server.computation.component.SettingsRepositoryImpl;
import org.sonar.server.computation.debt.DebtModelHolderImpl;
import org.sonar.server.computation.event.EventRepositoryImpl;
import org.sonar.server.computation.issue.BaseIssuesLoader;
+import org.sonar.server.computation.issue.ComponentIssuesRepositoryImpl;
import org.sonar.server.computation.issue.ComponentsWithUnprocessedIssues;
import org.sonar.server.computation.issue.DebtAggregator;
import org.sonar.server.computation.issue.DebtCalculator;
@@ -141,6 +142,7 @@ public final class ReportComputeEngineContainerPopulator implements ContainerPop
IssueVisitors.class,
IssueLifecycle.class,
ComponentsWithUnprocessedIssues.class,
+ ComponentIssuesRepositoryImpl.class,
// common rules
CommonRuleEngineImpl.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java
new file mode 100644
index 00000000000..51a87d20910
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepository.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.issue;
+
+import java.util.List;
+import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.api.issue.Issue;
+import org.sonar.server.computation.component.Component;
+
+/**
+ * This repository contains issues for only one component at a time. It's populated by {@link IntegrateIssuesVisitor} and
+ * it's mainly used by {@link org.sonar.server.computation.measure.api.MeasureComputerImplementationContext} in order for a {@link MeasureComputer}
+ * to access to the issues of a component.
+ *
+ * This repository must NEVER contains more issues than in issues from one component order to not consume to much memory.
+ */
+public interface ComponentIssuesRepository {
+
+ /**
+ * Return issues from the component
+ *
+ * @throws IllegalStateException if no issues have been set
+ * @throws IllegalArgumentException if the component is not the component that contains current issues.
+ */
+ List<Issue> getIssues(Component component);
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImpl.java
new file mode 100644
index 00000000000..16dfd4c9242
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImpl.java
@@ -0,0 +1,54 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.issue;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.api.issue.Issue;
+import org.sonar.server.computation.component.Component;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+public class ComponentIssuesRepositoryImpl implements MutableComponentIssuesRepository {
+
+ @CheckForNull
+ private List<Issue> issues;
+
+ @CheckForNull
+ private Component component;
+
+ @Override
+ public void setIssues(Component component, List<Issue> issues) {
+ this.issues = requireNonNull(issues, "issues cannot be null");
+ this.component = requireNonNull(component, "component cannot be null");
+ }
+
+ @Override
+ public List<Issue> getIssues(Component component) {
+ checkState(this.component != null && this.issues != null, "Issues have not been initialized");
+ checkArgument(component.equals(this.component),
+ String.format("Only issues from component '%s' are available, but wanted component is '%s'.",
+ this.component.getReportAttributes().getRef(), component.getReportAttributes().getRef()));
+ return issues;
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesVisitor.java
index 4cbcf06ed33..595b51160ee 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IntegrateIssuesVisitor.java
@@ -22,6 +22,7 @@ package org.sonar.server.computation.issue;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import org.sonar.api.issue.Issue;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.tracking.Tracking;
@@ -38,18 +39,20 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
private final IssueCache issueCache;
private final IssueLifecycle issueLifecycle;
private final IssueVisitors issueVisitors;
+ private final MutableComponentIssuesRepository componentIssuesRepository;
private final ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues;
- private final List<DefaultIssue> componentIssues = new ArrayList<>();
+ private final List<Issue> componentIssues = new ArrayList<>();
public IntegrateIssuesVisitor(TrackerExecution tracker, IssueCache issueCache, IssueLifecycle issueLifecycle, IssueVisitors issueVisitors,
- ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues) {
+ ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues, MutableComponentIssuesRepository componentIssuesRepository) {
super(CrawlerDepthLimit.FILE, POST_ORDER);
this.tracker = tracker;
this.issueCache = issueCache;
this.issueLifecycle = issueLifecycle;
this.issueVisitors = issueVisitors;
this.componentsWithUnprocessedIssues = componentsWithUnprocessedIssues;
+ this.componentIssuesRepository = componentIssuesRepository;
}
@Override
@@ -57,6 +60,7 @@ public class IntegrateIssuesVisitor extends TypeAwareVisitorAdapter {
componentIssues.clear();
processIssues(component);
componentsWithUnprocessedIssues.remove(component.getUuid());
+ componentIssuesRepository.setIssues(component, componentIssues);
}
private void processIssues(Component component) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/MutableComponentIssuesRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/MutableComponentIssuesRepository.java
new file mode 100644
index 00000000000..6086381ee18
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/MutableComponentIssuesRepository.java
@@ -0,0 +1,37 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.issue;
+
+import java.util.List;
+import org.sonar.api.issue.Issue;
+import org.sonar.server.computation.component.Component;
+
+public interface MutableComponentIssuesRepository extends ComponentIssuesRepository {
+
+ /**
+ * Add issues of the component.
+ * *
+ * @throws NullPointerException if {@code component} is {@code null}
+ * @throws NullPointerException if {@code issues} is {@code null}
+ */
+ void setIssues(Component component, List<Issue> issues);
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImplTest.java
new file mode 100644
index 00000000000..1ec999ae1db
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryImplTest.java
@@ -0,0 +1,92 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.issue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.issue.Issue;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.server.computation.component.Component;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.computation.component.ReportComponent.builder;
+
+public class ComponentIssuesRepositoryImplTest {
+
+ @org.junit.Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ static final Component FILE_1 = builder(Component.Type.FILE, 1).build();
+ static final Component FILE_2 = builder(Component.Type.FILE, 2).build();
+
+ static final Issue DUMB_ISSUE = new DefaultIssue().setKey("ISSUE");
+
+ ComponentIssuesRepositoryImpl sut = new ComponentIssuesRepositoryImpl();
+
+ @Test
+ public void get_issues() throws Exception {
+ sut.setIssues(FILE_1, Arrays.asList(DUMB_ISSUE));
+
+ assertThat(sut.getIssues(FILE_1)).containsOnly(DUMB_ISSUE);
+ }
+
+ @Test
+ public void set_empty_issues() throws Exception {
+ sut.setIssues(FILE_1, Collections.<Issue>emptyList());
+
+ assertThat(sut.getIssues(FILE_1)).isEmpty();
+ }
+
+ @Test
+ public void fail_with_NPE_when_setting_issues_with_null_component() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("component cannot be null");
+
+ sut.setIssues(null, Arrays.asList(DUMB_ISSUE));
+ }
+
+ @Test
+ public void fail_with_NPE_when_setting_issues_with_null_issues() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("issues cannot be null");
+
+ sut.setIssues(FILE_1, null);
+ }
+
+ @Test
+ public void fail_with_IAE_when_getting_issues_on_different_component() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Only issues from component '1' are available, but wanted component is '2'.");
+
+ sut.setIssues(FILE_1, Arrays.asList(DUMB_ISSUE));
+ sut.getIssues(FILE_2);
+ }
+
+ @Test
+ public void fail_with_ISE_when_getting_issues_but_issues_are_null() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Issues have not been initialized");
+
+ sut.getIssues(FILE_1);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryRule.java
new file mode 100644
index 00000000000..ab7995b07e3
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/ComponentIssuesRepositoryRule.java
@@ -0,0 +1,78 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.issue;
+
+import java.util.List;
+import javax.annotation.CheckForNull;
+import org.junit.rules.ExternalResource;
+import org.sonar.api.issue.Issue;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.ReportTreeRootHolder;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+public class ComponentIssuesRepositoryRule extends ExternalResource implements MutableComponentIssuesRepository, ComponentIssuesRepository {
+
+ private final ReportTreeRootHolder reportTreeRootHolder;
+
+ @CheckForNull
+ private List<Issue> issues;
+
+ @CheckForNull
+ private Component component;
+
+ public ComponentIssuesRepositoryRule(ReportTreeRootHolder reportTreeRootHolder) {
+ this.reportTreeRootHolder = reportTreeRootHolder;
+ }
+
+ @Override
+ public void setIssues(Component component, List<Issue> issues) {
+ checkNotNull(component, "component cannot be null");
+ setIssues(component.getReportAttributes().getRef(), issues);
+ }
+
+ public void setIssues(int componentRef, List<Issue> issues) {
+ this.issues = requireNonNull(issues, "issues cannot be null");
+ Component component = reportTreeRootHolder.getComponentByRef(componentRef);
+ checkArgument(component != null, String.format("Component '%s' does not exists in the report ", componentRef));
+ this.component = component;
+ }
+
+ @Override
+ public List<Issue> getIssues(Component component) {
+ checkNotNull(component, "component cannot be null");
+ return getIssues(component.getReportAttributes().getRef());
+ }
+
+ public List<Issue> getIssues(int componentRef) {
+ checkState(this.component != null && this.issues != null, "Issues have not been initialized");
+ Component component = reportTreeRootHolder.getComponentByRef(componentRef);
+ checkArgument(component != null, String.format("Component '%s' does not exists in the report ", componentRef));
+ checkArgument(component == this.component,
+ String.format("Only issues from component '%s' are available, but wanted component is '%s'.",
+ this.component.getReportAttributes().getRef(), component.getReportAttributes().getRef()));
+ return issues;
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IntegrateIssuesVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IntegrateIssuesVisitorTest.java
index 7a810775bda..d0c04e06a3b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IntegrateIssuesVisitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IntegrateIssuesVisitorTest.java
@@ -95,6 +95,9 @@ public class IntegrateIssuesVisitorTest {
@Rule
public RuleRepositoryRule ruleRepositoryRule = new RuleRepositoryRule();
+ @Rule
+ public ComponentIssuesRepositoryRule componentIssuesRepository = new ComponentIssuesRepositoryRule(treeRootHolder);
+
ArgumentCaptor<DefaultIssue> defaultIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
BaseIssuesLoader baseIssuesLoader = new BaseIssuesLoader(treeRootHolder, dbTester.getDbClient(), ruleRepositoryRule, activeRulesHolderRule);
@@ -113,7 +116,7 @@ public class IntegrateIssuesVisitorTest {
public void setUp() throws Exception {
treeRootHolder.setRoot(PROJECT);
issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
- underTest = new IntegrateIssuesVisitor(tracker, issueCache, issueLifecycle, issueVisitors, componentsWithUnprocessedIssues);
+ underTest = new IntegrateIssuesVisitor(tracker, issueCache, issueLifecycle, issueVisitors, componentsWithUnprocessedIssues, componentIssuesRepository);
}
@Test
@@ -234,6 +237,44 @@ public class IntegrateIssuesVisitorTest {
assertThat(componentsWithUnprocessedIssues.getUuids()).isEmpty();
}
+ @Test
+ public void feed_component_issues_repo() throws Exception {
+ componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
+
+ BatchReport.Issue reportIssue = BatchReport.Issue.newBuilder()
+ .setMsg("the message")
+ .setRuleRepository("xoo")
+ .setRuleKey("S001")
+ .setSeverity(Constants.Severity.BLOCKER)
+ .build();
+ reportReader.putIssues(FILE_REF, asList(reportIssue));
+ reportReader.putFileSourceLines(FILE_REF, "line1");
+
+ underTest.visitAny(FILE);
+
+ assertThat(componentIssuesRepository.getIssues(FILE_REF)).hasSize(1);
+ }
+
+ @Test
+ public void empty_component_issues_repo_when_no_issue() throws Exception {
+ componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
+
+ BatchReport.Issue reportIssue = BatchReport.Issue.newBuilder()
+ .setMsg("the message")
+ .setRuleRepository("xoo")
+ .setRuleKey("S001")
+ .setSeverity(Constants.Severity.BLOCKER)
+ .build();
+ reportReader.putIssues(FILE_REF, asList(reportIssue));
+ reportReader.putFileSourceLines(FILE_REF, "line1");
+
+ underTest.visitAny(FILE);
+ assertThat(componentIssuesRepository.getIssues(FILE_REF)).hasSize(1);
+
+ underTest.visitAny(PROJECT);
+ assertThat(componentIssuesRepository.getIssues(PROJECT)).isEmpty();
+ }
+
private void addBaseIssue(RuleKey ruleKey) {
ComponentDto project = ComponentTesting.newProjectDto(PROJECT_UUID).setKey(PROJECT_KEY);
ComponentDto file = ComponentTesting.newFileDto(project, FILE_UUID).setKey(FILE_KEY);