diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-03-25 10:59:50 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2015-03-25 15:20:10 +0100 |
commit | e157c182fb9f71f1a1bd16d48d4d09ac7b4fe92a (patch) | |
tree | 9119eb95b9e5b73e1914ba8a0f4639d8f1d14570 /sonar-batch/src | |
parent | ac44823d701c7ae3ea30ea8060c8fe28ca8ee6af (diff) | |
download | sonarqube-e157c182fb9f71f1a1bd16d48d4d09ac7b4fe92a.tar.gz sonarqube-e157c182fb9f71f1a1bd16d48d4d09ac7b4fe92a.zip |
SONAR-6280 Feed duplications in compute report
Diffstat (limited to 'sonar-batch/src')
5 files changed, 218 insertions, 67 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java new file mode 100644 index 00000000000..3648f47cc12 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/report/DuplicationsPublisher.java @@ -0,0 +1,90 @@ +/* + * 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.batch.report; + +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import org.sonar.api.batch.sensor.duplication.Duplication.Block; +import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.BatchResource; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReport.Duplication; +import org.sonar.batch.protocol.output.BatchReport.DuplicationBlock; +import org.sonar.batch.protocol.output.BatchReportWriter; + +public class DuplicationsPublisher implements ReportPublisher { + + private final ResourceCache resourceCache; + private final DuplicationCache duplicationCache; + + public DuplicationsPublisher(ResourceCache resourceCache, DuplicationCache duplicationCache) { + this.resourceCache = resourceCache; + this.duplicationCache = duplicationCache; + } + + @Override + public void publish(BatchReportWriter writer) { + for (final BatchResource resource : resourceCache.all()) { + Iterable<DefaultDuplication> dups = duplicationCache.byComponent(resource.resource().getEffectiveKey()); + if (dups.iterator().hasNext()) { + Iterable<org.sonar.batch.protocol.output.BatchReport.Duplication> reportDuplications = Iterables.transform(dups, + new Function<DefaultDuplication, BatchReport.Duplication>() { + private final BatchReport.Duplication.Builder dupBuilder = BatchReport.Duplication.newBuilder(); + private final BatchReport.DuplicationBlock.Builder blockBuilder = BatchReport.DuplicationBlock.newBuilder(); + + @Override + public BatchReport.Duplication apply(DefaultDuplication input) { + return toReportDuplication(resource.key(), dupBuilder, blockBuilder, input); + } + + }); + writer.writeComponentDuplications(resource.batchId(), reportDuplications); + } + } + } + + private Duplication toReportDuplication(String currentComponentKey, Duplication.Builder dupBuilder, DuplicationBlock.Builder blockBuilder, DefaultDuplication input) { + dupBuilder.clear(); + Block originBlock = input.originBlock(); + blockBuilder.clear(); + dupBuilder.setOriginBlock(blockBuilder + .setStartLine(originBlock.startLine()) + .setEndLine(originBlock.startLine() + originBlock.length() - 1).build()); + for (Block duplicate : input.duplicates()) { + blockBuilder.clear(); + String componentKey = duplicate.resourceKey(); + if (!currentComponentKey.equals(componentKey)) { + BatchResource sameProjectComponent = resourceCache.get(componentKey); + if (sameProjectComponent != null) { + blockBuilder.setOtherComponentRef(sameProjectComponent.batchId()); + } else { + blockBuilder.setComponentKey(componentKey); + } + } + dupBuilder.addDuplicatedBy(blockBuilder + .setStartLine(duplicate.startLine()) + .setEndLine(duplicate.startLine() + duplicate.length() - 1).build()); + } + return dupBuilder.build(); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java index e7c524ff52d..8aadc2180ee 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java +++ b/sonar-batch/src/main/java/org/sonar/batch/report/MeasuresPublisher.java @@ -23,7 +23,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; import org.sonar.api.measures.*; import org.sonar.api.measures.Metric.Level; import org.sonar.api.measures.Metric.ValueType; @@ -32,8 +31,6 @@ import org.sonar.api.resources.ResourceUtils; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RulePriority; import org.sonar.api.technicaldebt.batch.Characteristic; -import org.sonar.batch.duplication.DuplicationCache; -import org.sonar.batch.duplication.DuplicationUtils; import org.sonar.batch.index.BatchResource; import org.sonar.batch.index.ResourceCache; import org.sonar.batch.protocol.Constants; @@ -45,19 +42,16 @@ import org.sonar.batch.scan.measure.MeasureCache; import javax.annotation.Nullable; import java.io.Serializable; -import java.util.Arrays; public class MeasuresPublisher implements ReportPublisher { private final ResourceCache resourceCache; private final MeasureCache measureCache; - private final DuplicationCache duplicationCache; private final MetricFinder metricFinder; - public MeasuresPublisher(ResourceCache resourceCache, MeasureCache measureCache, DuplicationCache duplicationCache, MetricFinder metricFinder) { + public MeasuresPublisher(ResourceCache resourceCache, MeasureCache measureCache, MetricFinder metricFinder) { this.resourceCache = resourceCache; this.measureCache = measureCache; - this.duplicationCache = duplicationCache; this.metricFinder = metricFinder; } @@ -75,20 +69,14 @@ public class MeasuresPublisher implements ReportPublisher { }); Iterable<org.sonar.batch.protocol.output.BatchReport.Measure> reportMeasures = Iterables.transform(batchMeasures, new Function<Measure, BatchReport.Measure>() { - private BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder(); + private final BatchReport.Measure.Builder builder = BatchReport.Measure.newBuilder(); @Override public BatchReport.Measure apply(Measure input) { return toReportMeasure(builder, input); } }); - Iterable<DefaultDuplication> dups = duplicationCache.byComponent(resource.resource().getEffectiveKey()); - if (dups.iterator().hasNext()) { - org.sonar.batch.protocol.output.BatchReport.Measure dupMeasure = toReportMeasure(BatchReport.Measure.newBuilder(), dups); - writer.writeComponentMeasures(resource.batchId(), Iterables.concat(Arrays.asList(dupMeasure), reportMeasures)); - } else { - writer.writeComponentMeasures(resource.batchId(), reportMeasures); - } + writer.writeComponentMeasures(resource.batchId(), reportMeasures); } } @@ -109,15 +97,6 @@ public class MeasuresPublisher implements ReportPublisher { return measure.getValue() != null || measure.getData() != null || isNotEmpty; } - private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Iterable<DefaultDuplication> dups) { - builder.clear(); - - builder.setValueType(MeasureValueType.STRING); - builder.setStringValue(DuplicationUtils.toXml(dups)); - builder.setMetricKey(CoreMetrics.DUPLICATIONS_DATA_KEY); - return builder.build(); - } - private BatchReport.Measure toReportMeasure(BatchReport.Measure.Builder builder, Measure measure) { builder.clear(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java index aa35effd389..5df7f4c665d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ModuleScanContainer.java @@ -55,10 +55,7 @@ import org.sonar.batch.language.LanguageDistributionDecorator; import org.sonar.batch.phases.*; import org.sonar.batch.qualitygate.GenerateQualityGateEvents; import org.sonar.batch.qualitygate.QualityGateVerifier; -import org.sonar.batch.report.ComponentsPublisher; -import org.sonar.batch.report.IssuesPublisher; -import org.sonar.batch.report.MeasuresPublisher; -import org.sonar.batch.report.PublishReportJob; +import org.sonar.batch.report.*; import org.sonar.batch.rule.*; import org.sonar.batch.scan.filesystem.*; import org.sonar.batch.scan.report.IssuesReports; @@ -118,6 +115,7 @@ public class ModuleScanContainer extends ComponentContainer { ComponentsPublisher.class, IssuesPublisher.class, MeasuresPublisher.class, + DuplicationsPublisher.class, moduleDefinition.getContainerExtensions(), // file system diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java new file mode 100644 index 00000000000..b75efb3f275 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/report/DuplicationsPublisherTest.java @@ -0,0 +1,122 @@ +/* + * 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.batch.report; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.sensor.duplication.Duplication; +import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; +import org.sonar.api.resources.Project; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.index.ResourceCache; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.batch.protocol.output.BatchReportWriter; + +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class DuplicationsPublisherTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + private DuplicationCache duplicationCache; + private DuplicationsPublisher publisher; + + @Before + public void prepare() { + ResourceCache resourceCache = new ResourceCache(); + Project p = new Project("foo"); + resourceCache.add(p, null); + org.sonar.api.resources.Resource sampleFile = org.sonar.api.resources.File.create("src/Foo.php").setEffectiveKey("foo:src/Foo.php"); + resourceCache.add(sampleFile, null); + org.sonar.api.resources.Resource sampleFile2 = org.sonar.api.resources.File.create("src/Foo2.php").setEffectiveKey("foo:src/Foo2.php"); + resourceCache.add(sampleFile2, null); + duplicationCache = mock(DuplicationCache.class); + when(duplicationCache.byComponent(anyString())).thenReturn(Collections.<DefaultDuplication>emptyList()); + publisher = new DuplicationsPublisher(resourceCache, duplicationCache); + } + + @Test + public void publishDuplications() throws Exception { + + DefaultDuplication dup1 = new DefaultDuplication() + .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 1, 10)) + .isDuplicatedBy("foo:src/Foo.php", 20, 50); + DefaultDuplication dup2 = new DefaultDuplication() + .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 11, 10)) + .isDuplicatedBy("another", 20, 50); + DefaultDuplication dup3 = new DefaultDuplication() + .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 11, 10)) + .isDuplicatedBy("foo:src/Foo2.php", 20, 50); + when(duplicationCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(dup1, dup2, dup3)); + + File outputDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(outputDir); + + publisher.publish(writer); + + BatchReportReader reader = new BatchReportReader(outputDir); + + assertThat(reader.readComponentDuplications(1)).hasSize(0); + List<org.sonar.batch.protocol.output.BatchReport.Duplication> componentDuplications = reader.readComponentDuplications(2); + assertThat(componentDuplications).hasSize(3); + org.sonar.batch.protocol.output.BatchReport.Duplication savedDup1 = componentDuplications.get(0); + assertThat(savedDup1.getOriginBlock().hasComponentKey()).isFalse(); + assertThat(savedDup1.getOriginBlock().hasOtherComponentRef()).isFalse(); + assertThat(savedDup1.getOriginBlock().getStartLine()).isEqualTo(1); + assertThat(savedDup1.getOriginBlock().getEndLine()).isEqualTo(10); + assertThat(savedDup1.getDuplicatedBy(0).hasComponentKey()).isFalse(); + assertThat(savedDup1.getDuplicatedBy(0).hasOtherComponentRef()).isFalse(); + assertThat(savedDup1.getDuplicatedBy(0).getStartLine()).isEqualTo(20); + assertThat(savedDup1.getDuplicatedBy(0).getEndLine()).isEqualTo(50); + + org.sonar.batch.protocol.output.BatchReport.Duplication savedDup2 = componentDuplications.get(1); + assertThat(savedDup2.getOriginBlock().hasComponentKey()).isFalse(); + assertThat(savedDup2.getOriginBlock().hasOtherComponentRef()).isFalse(); + assertThat(savedDup2.getOriginBlock().getStartLine()).isEqualTo(11); + assertThat(savedDup2.getOriginBlock().getEndLine()).isEqualTo(20); + assertThat(savedDup2.getDuplicatedBy(0).getComponentKey()).isEqualTo("another"); + assertThat(savedDup2.getDuplicatedBy(0).hasOtherComponentRef()).isFalse(); + assertThat(savedDup2.getDuplicatedBy(0).getStartLine()).isEqualTo(20); + assertThat(savedDup2.getDuplicatedBy(0).getEndLine()).isEqualTo(50); + + org.sonar.batch.protocol.output.BatchReport.Duplication savedDup3 = componentDuplications.get(2); + assertThat(savedDup3.getOriginBlock().hasComponentKey()).isFalse(); + assertThat(savedDup3.getOriginBlock().hasOtherComponentRef()).isFalse(); + assertThat(savedDup3.getOriginBlock().getStartLine()).isEqualTo(11); + assertThat(savedDup3.getOriginBlock().getEndLine()).isEqualTo(20); + assertThat(savedDup3.getDuplicatedBy(0).hasComponentKey()).isFalse(); + assertThat(savedDup3.getDuplicatedBy(0).getOtherComponentRef()).isEqualTo(3); + assertThat(savedDup3.getDuplicatedBy(0).getStartLine()).isEqualTo(20); + assertThat(savedDup3.getDuplicatedBy(0).getEndLine()).isEqualTo(50); + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java index 29a75622c8f..3089a67cbee 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/report/MeasuresPublisherTest.java @@ -23,8 +23,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.sensor.duplication.Duplication; -import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; import org.sonar.api.database.model.Snapshot; import org.sonar.api.measures.*; import org.sonar.api.measures.Metric.Level; @@ -34,7 +32,6 @@ import org.sonar.api.resources.Resource; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RulePriority; import org.sonar.api.technicaldebt.batch.Characteristic; -import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.index.ResourceCache; import org.sonar.batch.protocol.output.BatchReportReader; import org.sonar.batch.protocol.output.BatchReportWriter; @@ -48,7 +45,6 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -58,7 +54,6 @@ public class MeasuresPublisherTest { public TemporaryFolder temp = new TemporaryFolder(); private MeasureCache measureCache; - private DuplicationCache duplicationCache; private MeasuresPublisher publisher; private org.sonar.api.resources.File aFile = org.sonar.api.resources.File.create("org/foo/Bar.java"); @@ -72,9 +67,7 @@ public class MeasuresPublisherTest { resourceCache.add(p, null).setSnapshot(new Snapshot().setId(2)); resourceCache.add(sampleFile, null); measureCache = mock(MeasureCache.class); - duplicationCache = mock(DuplicationCache.class); when(measureCache.byResource(any(Resource.class))).thenReturn(Collections.<Measure>emptyList()); - when(duplicationCache.byComponent(anyString())).thenReturn(Collections.<DefaultDuplication>emptyList()); MetricFinder metricFinder = mock(MetricFinder.class); when(metricFinder.findByKey(CoreMetrics.COVERAGE_KEY)).thenReturn(CoreMetrics.COVERAGE); when(metricFinder.findByKey(CoreMetrics.NEW_BLOCKER_VIOLATIONS_KEY)).thenReturn(CoreMetrics.NEW_BLOCKER_VIOLATIONS); @@ -83,7 +76,7 @@ public class MeasuresPublisherTest { when(metricFinder.findByKey(CoreMetrics.SQALE_RATING_KEY)).thenReturn(CoreMetrics.SQALE_RATING); when(metricFinder.findByKey(CoreMetrics.TECHNICAL_DEBT_KEY)).thenReturn(CoreMetrics.TECHNICAL_DEBT); when(metricFinder.findByKey(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION); - publisher = new MeasuresPublisher(resourceCache, measureCache, duplicationCache, metricFinder); + publisher = new MeasuresPublisher(resourceCache, measureCache, metricFinder); } @Test @@ -141,37 +134,6 @@ public class MeasuresPublisherTest { } @Test - public void publishMeasureAndDuplication() throws Exception { - - Measure measure1 = new Measure<>(CoreMetrics.COVERAGE) - .setValue(2.0); - - when(measureCache.byResource(sampleFile)).thenReturn(Arrays.asList(measure1)); - DefaultDuplication dup1 = new DefaultDuplication() - .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 1, 10)) - .isDuplicatedBy("foo:src/Foo.php", 20, 50); - DefaultDuplication dup2 = new DefaultDuplication() - .setOriginBlock(new Duplication.Block("foo:src/Foo.php", 1, 10)) - .isDuplicatedBy("another", 20, 50); - when(duplicationCache.byComponent("foo:src/Foo.php")).thenReturn(Arrays.asList(dup1, dup2)); - - File outputDir = temp.newFolder(); - BatchReportWriter writer = new BatchReportWriter(outputDir); - - publisher.publish(writer); - - BatchReportReader reader = new BatchReportReader(outputDir); - - assertThat(reader.readComponentMeasures(1)).hasSize(0); - List<org.sonar.batch.protocol.output.BatchReport.Measure> componentMeasures = reader.readComponentMeasures(2); - assertThat(componentMeasures).hasSize(2); - assertThat(componentMeasures.get(0).getStringValue()) - .isEqualTo( - "<duplications><g><b s=\"1\" l=\"10\" r=\"foo:src/Foo.php\"/><b s=\"20\" l=\"31\" r=\"foo:src/Foo.php\"/></g><g><b s=\"1\" l=\"10\" r=\"foo:src/Foo.php\"/><b s=\"20\" l=\"31\" r=\"another\"/></g></duplications>"); - - } - - @Test public void should_not_save_some_file_measures_with_best_value() { assertThat(MeasuresPublisher.shouldPersistMeasure(aFile, new Measure(CoreMetrics.LINES, 200.0))).isTrue(); assertThat(MeasuresPublisher.shouldPersistMeasure(aFile, new Measure(CoreMetrics.DUPLICATED_LINES_DENSITY, 3.0))).isTrue(); |