From f6b2a269c44043f1c230b646dbb8662aed3fa5a4 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Tue, 5 Mar 2019 09:59:43 +0100 Subject: [PATCH] SONAR-11795 Drop persistit and move coverage measures computation to CE side --- build.gradle | 3 - .../step/CoverageMeasuresStep.java | 81 ++ .../step/NewCoverageMeasuresStep.java | 224 ++--- .../batch/BatchReportReaderImplTest.java | 4 +- .../step/ReportCoverageMeasuresStepTest.java | 61 +- .../ReportNewCoverageMeasuresStepTest.java | 193 ++--- .../ViewsNewCoverageMeasuresStepTest.java | 5 - .../org/sonar/core/metric/ScannerMetrics.java | 23 +- .../sonar/core/metric/ScannerMetricsTest.java | 2 +- .../fs/internal/DefaultInputComponent.java | 12 + .../batch/fs/internal/DefaultInputFile.java | 56 +- .../batch/sensor/coverage/CoverageType.java | 89 +- .../org/sonar/api/measures/CoreMetrics.java | 788 ------------------ .../sonar/api/issue/NoSonarFilterTest.java | 2 +- sonar-scanner-engine/build.gradle | 1 - .../scanner/DefaultFileLinesContext.java | 31 +- .../DefaultFileLinesContextFactory.java | 7 +- .../scanner/bootstrap/GlobalContainer.java | 2 - .../scanner/report/CoveragePublisher.java | 100 --- .../scanner/report/MeasuresPublisher.java | 180 ---- .../sonar/scanner/report/ReportPublisher.java | 7 + .../report/TestExecutionPublisher.java | 90 ++ .../scanner/scan/ProjectScanContainer.java | 12 +- .../scanner/scan/measure/MeasureCache.java | 72 -- .../scan/measure/MeasureValueCoder.java | 56 -- .../scanner/sensor/DefaultSensorStorage.java | 273 ++---- .../scanner/source/ZeroCoverageSensor.java | 47 +- .../org/sonar/scanner/storage/Storage.java | 500 ----------- .../org/sonar/scanner/storage/Storages.java | 96 --- .../scanner/storage/StoragesManager.java | 96 --- .../sonar/scanner/storage/package-info.java | 23 - .../scanner/DefaultFileLinesContextTest.java | 40 +- .../scanner/index/AbstractCachesTest.java | 76 -- .../mediumtest/branch/BranchMediumTest.java | 18 +- .../coverage/CoverageMediumTest.java | 49 +- .../coverage/GenericCoverageMediumTest.java | 37 +- .../measures/MeasuresMediumTest.java | 60 -- .../scanner/mediumtest/scm/ScmMediumTest.java | 4 - .../scanner/report/CoveragePublisherTest.java | 104 --- .../scanner/report/MeasuresPublisherTest.java | 112 --- .../scan/measure/MeasureCacheTest.java | 162 ---- .../sensor/DefaultSensorStorageTest.java | 90 +- .../sonar/scanner/storage/StorageTest.java | 251 ------ .../scanner/storage/StoragesManagerTest.java | 42 - .../sonar/scanner/storage/StoragesTest.java | 90 -- .../protocol/output/ScannerReportWriter.java | 9 +- .../output/ScannerReportReaderTest.java | 2 +- .../output/ScannerReportWriterTest.java | 2 +- 48 files changed, 570 insertions(+), 3714 deletions(-) delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CoveragePublisher.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java create mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureCache.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureValueCoder.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java delete mode 100644 sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/measure/MeasureCacheTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java delete mode 100644 sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java diff --git a/build.gradle b/build.gradle index ad1bf2566bc..f442ce1f62a 100644 --- a/build.gradle +++ b/build.gradle @@ -226,9 +226,6 @@ subprojects { dependency 'org.reflections:reflections:0.9.9' dependency 'org.simpleframework:simple:4.1.21' dependency 'org.sonarsource.orchestrator:sonar-orchestrator:3.22.0.1791' - dependency('org.sonarsource:sonar-persistit:3.3.2') { - exclude 'commons-logging:commons-logging' - } dependency 'org.sonarsource.update-center:sonar-update-center-common:1.18.0.487' dependency 'org.subethamail:subethasmtp:3.1.7' dependency 'xml-apis:xml-apis:1.4.01' diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/CoverageMeasuresStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/CoverageMeasuresStep.java index d9c9baec0bd..507db1be6dc 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/CoverageMeasuresStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/CoverageMeasuresStep.java @@ -20,18 +20,28 @@ package org.sonar.ce.task.projectanalysis.step; import com.google.common.collect.ImmutableList; +import org.sonar.ce.task.projectanalysis.batch.BatchReportReader; +import org.sonar.ce.task.projectanalysis.component.Component; +import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit; +import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; import org.sonar.ce.task.projectanalysis.component.PathAwareCrawler; import org.sonar.ce.task.projectanalysis.component.TreeRootHolder; +import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter; import org.sonar.ce.task.projectanalysis.formula.Formula; import org.sonar.ce.task.projectanalysis.formula.FormulaExecutorComponentVisitor; import org.sonar.ce.task.projectanalysis.formula.coverage.LinesAndConditionsWithUncoveredFormula; import org.sonar.ce.task.projectanalysis.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys; import org.sonar.ce.task.projectanalysis.formula.coverage.SingleWithUncoveredFormula; import org.sonar.ce.task.projectanalysis.formula.coverage.SingleWithUncoveredMetricKeys; +import org.sonar.ce.task.projectanalysis.measure.Measure; import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; +import org.sonar.ce.task.projectanalysis.metric.Metric; import org.sonar.ce.task.projectanalysis.metric.MetricRepository; import org.sonar.ce.task.step.ComputationStep; +import org.sonar.core.util.CloseableIterator; +import org.sonar.scanner.protocol.output.ScannerReport; +import static java.lang.Math.min; import static org.sonar.api.measures.CoreMetrics.BRANCH_COVERAGE_KEY; import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER_KEY; import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY; @@ -57,20 +67,91 @@ public class CoverageMeasuresStep implements ComputationStep { private final TreeRootHolder treeRootHolder; private final MetricRepository metricRepository; private final MeasureRepository measureRepository; + private final BatchReportReader reportReader; + private final Metric linesToCoverMetric; + private final Metric uncoveredLinesMetric; + private final Metric conditionsToCoverMetric; + private final Metric uncoveredConditionsMetric; + /** + * Constructor used when processing a Report (ie. a {@link BatchReportReader} instance is available in the container) + */ + public CoverageMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository, BatchReportReader reportReader) { + this.treeRootHolder = treeRootHolder; + this.metricRepository = metricRepository; + this.measureRepository = measureRepository; + this.reportReader = reportReader; + this.linesToCoverMetric = metricRepository.getByKey(LINES_TO_COVER_KEY); + this.uncoveredLinesMetric = metricRepository.getByKey(UNCOVERED_LINES_KEY); + this.conditionsToCoverMetric = metricRepository.getByKey(CONDITIONS_TO_COVER_KEY); + this.uncoveredConditionsMetric = metricRepository.getByKey(UNCOVERED_CONDITIONS_KEY); + } + + /** + * Constructor used when processing Views (ie. no {@link BatchReportReader} instance is available in the container) + */ public CoverageMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) { this.treeRootHolder = treeRootHolder; this.metricRepository = metricRepository; this.measureRepository = measureRepository; + this.linesToCoverMetric = metricRepository.getByKey(LINES_TO_COVER_KEY); + this.uncoveredLinesMetric = metricRepository.getByKey(UNCOVERED_LINES_KEY); + this.conditionsToCoverMetric = metricRepository.getByKey(CONDITIONS_TO_COVER_KEY); + this.uncoveredConditionsMetric = metricRepository.getByKey(UNCOVERED_CONDITIONS_KEY); + this.reportReader = null; } @Override public void execute(ComputationStep.Context context) { + if (reportReader != null) { + new DepthTraversalTypeAwareCrawler(new FileCoverageVisitor(reportReader)).visit(treeRootHolder.getReportTreeRoot()); + } new PathAwareCrawler<>( FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository).buildFor(COVERAGE_FORMULAS)) .visit(treeRootHolder.getReportTreeRoot()); } + private class FileCoverageVisitor extends TypeAwareVisitorAdapter { + + private final BatchReportReader reportReader; + + private FileCoverageVisitor(BatchReportReader reportReader) { + super(CrawlerDepthLimit.FILE, Order.POST_ORDER); + this.reportReader = reportReader; + } + + @Override + public void visitFile(Component file) { + try (CloseableIterator lineCoverage = reportReader.readComponentCoverage(file.getReportAttributes().getRef())) { + int linesToCover = 0; + int coveredLines = 0; + int conditionsToCover = 0; + int coveredConditions = 0; + while (lineCoverage.hasNext()) { + final ScannerReport.LineCoverage line = lineCoverage.next(); + if (line.getHasHitsCase() == ScannerReport.LineCoverage.HasHitsCase.HITS) { + linesToCover++; + if (line.getHits()) { + coveredLines++; + } + } + if (line.getHasCoveredConditionsCase() == ScannerReport.LineCoverage.HasCoveredConditionsCase.COVERED_CONDITIONS) { + conditionsToCover += line.getConditions(); + coveredConditions += min(line.getCoveredConditions(), line.getConditions()); + } + } + if (linesToCover > 0) { + measureRepository.add(file, linesToCoverMetric, Measure.newMeasureBuilder().create(linesToCover)); + measureRepository.add(file, uncoveredLinesMetric, Measure.newMeasureBuilder().create(linesToCover - coveredLines)); + } + if (conditionsToCover > 0) { + measureRepository.add(file, conditionsToCoverMetric, Measure.newMeasureBuilder().create(conditionsToCover)); + measureRepository.add(file, uncoveredConditionsMetric, Measure.newMeasureBuilder().create(conditionsToCover - coveredConditions)); + } + } + } + } + private static class CodeCoverageFormula extends LinesAndConditionsWithUncoveredFormula { public CodeCoverageFormula() { super( diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/NewCoverageMeasuresStep.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/NewCoverageMeasuresStep.java index 64bce16d146..ff71dc779ec 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/NewCoverageMeasuresStep.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/NewCoverageMeasuresStep.java @@ -23,14 +23,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; -import javax.annotation.concurrent.Immutable; -import org.apache.commons.lang.ObjectUtils; import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.utils.KeyValueFormat; +import org.sonar.ce.task.projectanalysis.batch.BatchReportReader; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.PathAwareCrawler; import org.sonar.ce.task.projectanalysis.component.TreeRootHolder; @@ -51,7 +48,14 @@ import org.sonar.ce.task.projectanalysis.metric.Metric; import org.sonar.ce.task.projectanalysis.metric.MetricRepository; import org.sonar.ce.task.projectanalysis.source.NewLinesRepository; import org.sonar.ce.task.step.ComputationStep; - +import org.sonar.core.util.CloseableIterator; +import org.sonar.scanner.protocol.output.ScannerReport; + +import static java.lang.Math.min; +import static org.sonar.api.measures.CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_UNCOVERED_LINES_KEY; import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder; /** @@ -70,16 +74,19 @@ public class NewCoverageMeasuresStep implements ComputationStep { private final MeasureRepository measureRepository; @Nullable private final NewLinesRepository newLinesRepository; + @Nullable + private final BatchReportReader reportReader; /** * Constructor used when processing a Report (ie. a {@link NewLinesRepository} instance is available in the container) */ public NewCoverageMeasuresStep(TreeRootHolder treeRootHolder, - MeasureRepository measureRepository, MetricRepository metricRepository, NewLinesRepository newLinesRepository) { + MeasureRepository measureRepository, MetricRepository metricRepository, NewLinesRepository newLinesRepository, BatchReportReader reportReader) { this.treeRootHolder = treeRootHolder; this.metricRepository = metricRepository; this.measureRepository = measureRepository; this.newLinesRepository = newLinesRepository; + this.reportReader = reportReader; } /** @@ -90,6 +97,7 @@ public class NewCoverageMeasuresStep implements ComputationStep { this.metricRepository = metricRepository; this.measureRepository = measureRepository; this.newLinesRepository = null; + this.reportReader = null; } @Override @@ -97,8 +105,8 @@ public class NewCoverageMeasuresStep implements ComputationStep { new PathAwareCrawler<>( FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) .buildFor( - Iterables.concat(NewLinesAndConditionsCoverageFormula.from(newLinesRepository), FORMULAS))) - .visit(treeRootHolder.getRoot()); + Iterables.concat(NewLinesAndConditionsCoverageFormula.from(newLinesRepository, reportReader), FORMULAS))) + .visit(treeRootHolder.getRoot()); } @Override @@ -106,46 +114,12 @@ public class NewCoverageMeasuresStep implements ComputationStep { return "Compute new coverage"; } - private static class NewLinesAndConditionsCoverageFormula extends NewLinesAndConditionsFormula { - - private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys( - CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_LINES_KEY, - CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY); - private static final Iterable> VIEWS_FORMULAS = variationSumFormulas(OUTPUT_METRIC_KEYS); - - private NewLinesAndConditionsCoverageFormula(NewLinesRepository newLinesRepository) { - super(newLinesRepository, - new NewCoverageInputMetricKeys( - CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, CoreMetrics.CONDITIONS_BY_LINE_KEY, CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY), - OUTPUT_METRIC_KEYS); - } - - public static Iterable> from(@Nullable NewLinesRepository newLinesRepository) { - if (newLinesRepository == null) { - return VIEWS_FORMULAS; - } - return Collections.singleton(new NewLinesAndConditionsCoverageFormula(newLinesRepository)); - } - - /** - * Creates a List of {@link org.sonar.ce.task.projectanalysis.formula.SumFormula.IntSumFormula} for each - * metric key of the specified {@link NewCoverageOutputMetricKeys} instance. - */ - private static Iterable> variationSumFormulas(NewCoverageOutputMetricKeys outputMetricKeys) { - return ImmutableList.of( - new VariationSumFormula(outputMetricKeys.getNewLinesToCover()), - new VariationSumFormula(outputMetricKeys.getNewUncoveredLines()), - new VariationSumFormula(outputMetricKeys.getNewConditionsToCover()), - new VariationSumFormula(outputMetricKeys.getNewUncoveredConditions())); - } - } - private static class NewCoverageFormula extends LinesAndConditionsWithUncoveredVariationFormula { public NewCoverageFormula() { super( new LinesAndConditionsWithUncoveredMetricKeys( - CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, - CoreMetrics.NEW_UNCOVERED_LINES_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY), + NEW_LINES_TO_COVER_KEY, NEW_CONDITIONS_TO_COVER_KEY, + NEW_UNCOVERED_LINES_KEY, NEW_UNCOVERED_CONDITIONS_KEY), CoreMetrics.NEW_COVERAGE_KEY); } } @@ -153,7 +127,7 @@ public class NewCoverageMeasuresStep implements ComputationStep { private static class NewBranchCoverageFormula extends SingleWithUncoveredVariationFormula { public NewBranchCoverageFormula() { super( - new SingleWithUncoveredMetricKeys(CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY), + new SingleWithUncoveredMetricKeys(NEW_CONDITIONS_TO_COVER_KEY, NEW_UNCOVERED_CONDITIONS_KEY), CoreMetrics.NEW_BRANCH_COVERAGE_KEY); } } @@ -161,25 +135,39 @@ public class NewCoverageMeasuresStep implements ComputationStep { private static class NewLineCoverageFormula extends SingleWithUncoveredVariationFormula { public NewLineCoverageFormula() { super( - new SingleWithUncoveredMetricKeys(CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_LINES_KEY), + new SingleWithUncoveredMetricKeys(NEW_LINES_TO_COVER_KEY, NEW_UNCOVERED_LINES_KEY), CoreMetrics.NEW_LINE_COVERAGE_KEY); } } - public static class NewLinesAndConditionsFormula implements Formula { + public static class NewLinesAndConditionsCoverageFormula implements Formula { private final NewLinesRepository newLinesRepository; - private final NewCoverageInputMetricKeys inputMetricKeys; - private final NewCoverageOutputMetricKeys outputMetricKeys; + private final BatchReportReader reportReader; + private static final Iterable> VIEWS_FORMULAS = variationSumFormulas(); - public NewLinesAndConditionsFormula(NewLinesRepository newLinesRepository, NewCoverageInputMetricKeys inputMetricKeys, NewCoverageOutputMetricKeys outputMetricKeys) { + private NewLinesAndConditionsCoverageFormula(NewLinesRepository newLinesRepository, BatchReportReader reportReader) { this.newLinesRepository = newLinesRepository; - this.inputMetricKeys = inputMetricKeys; - this.outputMetricKeys = outputMetricKeys; + this.reportReader = reportReader; + } + + public static Iterable> from(@Nullable NewLinesRepository newLinesRepository, @Nullable BatchReportReader reportReader) { + if (newLinesRepository == null || reportReader == null) { + return VIEWS_FORMULAS; + } + return Collections.singleton(new NewLinesAndConditionsCoverageFormula(newLinesRepository, reportReader)); + } + + private static Iterable> variationSumFormulas() { + return ImmutableList.of( + new VariationSumFormula(NEW_LINES_TO_COVER_KEY), + new VariationSumFormula(NEW_UNCOVERED_LINES_KEY), + new VariationSumFormula(NEW_CONDITIONS_TO_COVER_KEY), + new VariationSumFormula(NEW_UNCOVERED_CONDITIONS_KEY)); } @Override public NewCoverageCounter createNewCounter() { - return new NewCoverageCounter(newLinesRepository, inputMetricKeys); + return new NewCoverageCounter(newLinesRepository, reportReader); } @Override @@ -192,16 +180,16 @@ public class NewCoverageMeasuresStep implements ComputationStep { } private int computeValueForMetric(NewCoverageCounter counter, Metric metric) { - if (metric.getKey().equals(outputMetricKeys.getNewLinesToCover())) { + if (metric.getKey().equals(NEW_LINES_TO_COVER_KEY)) { return counter.getNewLines(); } - if (metric.getKey().equals(outputMetricKeys.getNewUncoveredLines())) { + if (metric.getKey().equals(NEW_UNCOVERED_LINES_KEY)) { return counter.getNewLines() - counter.getNewCoveredLines(); } - if (metric.getKey().equals(outputMetricKeys.getNewConditionsToCover())) { + if (metric.getKey().equals(NEW_CONDITIONS_TO_COVER_KEY)) { return counter.getNewConditions(); } - if (metric.getKey().equals(outputMetricKeys.getNewUncoveredConditions())) { + if (metric.getKey().equals(NEW_UNCOVERED_CONDITIONS_KEY)) { return counter.getNewConditions() - counter.getNewCoveredConditions(); } throw new IllegalArgumentException("Unsupported metric " + metric.getKey()); @@ -210,10 +198,10 @@ public class NewCoverageMeasuresStep implements ComputationStep { @Override public String[] getOutputMetricKeys() { return new String[] { - outputMetricKeys.getNewLinesToCover(), - outputMetricKeys.getNewUncoveredLines(), - outputMetricKeys.getNewConditionsToCover(), - outputMetricKeys.getNewUncoveredConditions() + NEW_LINES_TO_COVER_KEY, + NEW_UNCOVERED_LINES_KEY, + NEW_CONDITIONS_TO_COVER_KEY, + NEW_UNCOVERED_CONDITIONS_KEY }; } } @@ -224,11 +212,11 @@ public class NewCoverageMeasuresStep implements ComputationStep { private final IntValue newConditions = new IntValue(); private final IntValue newCoveredConditions = new IntValue(); private final NewLinesRepository newLinesRepository; - private final NewCoverageInputMetricKeys metricKeys; + private final BatchReportReader reportReader; - public NewCoverageCounter(NewLinesRepository newLinesRepository, NewCoverageInputMetricKeys metricKeys) { + public NewCoverageCounter(NewLinesRepository newLinesRepository, BatchReportReader reportReader) { this.newLinesRepository = newLinesRepository; - this.metricKeys = metricKeys; + this.reportReader = reportReader; } @Override @@ -255,46 +243,25 @@ public class NewCoverageMeasuresStep implements ComputationStep { newConditions.increment(0); newCoveredConditions.increment(0); - Optional hitsByLineMeasure = context.getMeasure(metricKeys.getCoverageLineHitsData()); - Map hitsByLine = parseCountByLine(hitsByLineMeasure); - Map conditionsByLine = parseCountByLine(context.getMeasure(metricKeys.getConditionsByLine())); - Map coveredConditionsByLine = parseCountByLine(context.getMeasure(metricKeys.getCoveredConditionsByLine())); - - for (Map.Entry entry : hitsByLine.entrySet()) { - int lineId = entry.getKey(); - int hits = entry.getValue(); - int conditions = (Integer) ObjectUtils.defaultIfNull(conditionsByLine.get(lineId), 0); - int coveredConditions = (Integer) ObjectUtils.defaultIfNull(coveredConditionsByLine.get(lineId), 0); - if (newLinesSet.get().contains(lineId)) { - analyze(hits, conditions, coveredConditions); + try (CloseableIterator lineCoverage = reportReader.readComponentCoverage(component.getReportAttributes().getRef())) { + while (lineCoverage.hasNext()) { + final ScannerReport.LineCoverage line = lineCoverage.next(); + int lineId = line.getLine(); + if (newLinesSet.get().contains(lineId)) { + if (line.getHasHitsCase() == ScannerReport.LineCoverage.HasHitsCase.HITS) { + newLines.increment(1); + if (line.getHits()) { + newCoveredLines.increment(1); + } + } + if (line.getHasCoveredConditionsCase() == ScannerReport.LineCoverage.HasCoveredConditionsCase.COVERED_CONDITIONS) { + newConditions.increment(line.getConditions()); + newCoveredConditions.increment(min(line.getCoveredConditions(), line.getConditions())); + } + } } } - } - - private static Map parseCountByLine(Optional measure) { - if (measure.isPresent() && measure.get().getValueType() != Measure.ValueType.NO_VALUE) { - return KeyValueFormat.parseIntInt(measure.get().getStringValue()); - } - return Collections.emptyMap(); - } - void analyze(int hits, int conditions, int coveredConditions) { - incrementLines(hits); - incrementConditions(conditions, coveredConditions); - } - - private void incrementLines(int hits) { - newLines.increment(1); - if (hits > 0) { - newCoveredLines.increment(1); - } - } - - private void incrementConditions(int conditions, int coveredConditions) { - newConditions.increment(conditions); - if (conditions > 0) { - newCoveredConditions.increment(coveredConditions); - } } boolean hasNewCode() { @@ -318,59 +285,4 @@ public class NewCoverageMeasuresStep implements ComputationStep { } } - @Immutable - public static final class NewCoverageOutputMetricKeys { - private final String newLinesToCover; - private final String newUncoveredLines; - private final String newConditionsToCover; - private final String newUncoveredConditions; - - public NewCoverageOutputMetricKeys(String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) { - this.newLinesToCover = newLinesToCover; - this.newUncoveredLines = newUncoveredLines; - this.newConditionsToCover = newConditionsToCover; - this.newUncoveredConditions = newUncoveredConditions; - } - - public String getNewLinesToCover() { - return newLinesToCover; - } - - public String getNewUncoveredLines() { - return newUncoveredLines; - } - - public String getNewConditionsToCover() { - return newConditionsToCover; - } - - public String getNewUncoveredConditions() { - return newUncoveredConditions; - } - } - - @Immutable - public static class NewCoverageInputMetricKeys { - private final String coverageLineHitsData; - private final String conditionsByLine; - private final String coveredConditionsByLine; - - public NewCoverageInputMetricKeys(String coverageLineHitsData, String conditionsByLine, String coveredConditionsByLine) { - this.coverageLineHitsData = coverageLineHitsData; - this.conditionsByLine = conditionsByLine; - this.coveredConditionsByLine = coveredConditionsByLine; - } - - public String getCoverageLineHitsData() { - return coverageLineHitsData; - } - - public String getConditionsByLine() { - return conditionsByLine; - } - - public String getCoveredConditionsByLine() { - return coveredConditionsByLine; - } - } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java index c2c8b96f421..792ce499906 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java @@ -99,7 +99,7 @@ public class BatchReportReaderImplTest { @Test public void verify_readComponentMeasures_returns_measures() { - writer.writeComponentMeasures(COMPONENT_REF, of(MEASURE)); + writer.appendComponentMeasure(COMPONENT_REF, MEASURE); try (CloseableIterator measures = underTest.readComponentMeasures(COMPONENT_REF)) { assertThat(measures.next()).isEqualTo(MEASURE); @@ -109,7 +109,7 @@ public class BatchReportReaderImplTest { @Test public void readComponentMeasures_is_not_cached() { - writer.writeComponentMeasures(COMPONENT_REF, of(MEASURE)); + writer.appendComponentMeasure(COMPONENT_REF, MEASURE); assertThat(underTest.readComponentMeasures(COMPONENT_REF)).isNotSameAs(underTest.readComponentMeasures(COMPONENT_REF)); } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportCoverageMeasuresStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportCoverageMeasuresStepTest.java index 6ddde625535..052e07e1277 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportCoverageMeasuresStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportCoverageMeasuresStepTest.java @@ -23,6 +23,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.sonar.api.measures.CoreMetrics; +import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.ce.task.projectanalysis.component.FileAttributes; import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule; import org.sonar.ce.task.projectanalysis.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys; @@ -30,8 +31,14 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry; import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule; import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule; import org.sonar.ce.task.step.TestComputationStepContext; +import org.sonar.scanner.protocol.output.ScannerReport; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER_KEY; +import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER_KEY; +import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES_KEY; import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY; import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE; import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT; @@ -62,7 +69,10 @@ public class ReportCoverageMeasuresStepTest { @Rule public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); - CoverageMeasuresStep underTest = new CoverageMeasuresStep(treeRootHolder, metricRepository, measureRepository); + @Rule + public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + + CoverageMeasuresStep underTest = new CoverageMeasuresStep(treeRootHolder, metricRepository, measureRepository, reportReader); @Before public void setUp() throws Exception { @@ -79,32 +89,33 @@ public class ReportCoverageMeasuresStepTest { } @Test - public void verify_aggregates_values_for_ut_lines_and_conditions() { - LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( - CoreMetrics.LINES_TO_COVER_KEY, CoreMetrics.CONDITIONS_TO_COVER_KEY, - CoreMetrics.UNCOVERED_LINES_KEY, CoreMetrics.UNCOVERED_CONDITIONS_KEY); - verify_lines_and_conditions_aggregates_values(metricKeys); - } - - private void verify_lines_and_conditions_aggregates_values(LinesAndConditionsWithUncoveredMetricKeys metricKeys) { - measureRepository - .addRawMeasure(FILE_1_REF, metricKeys.getLines(), newMeasureBuilder().create(3000)) - .addRawMeasure(FILE_1_REF, metricKeys.getConditions(), newMeasureBuilder().create(300)) - .addRawMeasure(FILE_1_REF, metricKeys.getUncoveredLines(), newMeasureBuilder().create(30)) - .addRawMeasure(FILE_1_REF, metricKeys.getUncoveredConditions(), newMeasureBuilder().create(9)) - - .addRawMeasure(FILE_2_REF, metricKeys.getLines(), newMeasureBuilder().create(2000)) - .addRawMeasure(FILE_2_REF, metricKeys.getConditions(), newMeasureBuilder().create(400)) - .addRawMeasure(FILE_2_REF, metricKeys.getUncoveredLines(), newMeasureBuilder().create(200)) - .addRawMeasure(FILE_2_REF, metricKeys.getUncoveredConditions(), newMeasureBuilder().create(16)); + public void verify_aggregates_values_for_lines_and_conditions() { + + reportReader.putCoverage(FILE_1_REF, + asList( + ScannerReport.LineCoverage.newBuilder().setLine(2).setHits(false).build(), + ScannerReport.LineCoverage.newBuilder().setLine(3).setHits(true).build(), + ScannerReport.LineCoverage.newBuilder().setLine(4).setHits(true).setConditions(4).setCoveredConditions(1).build(), + ScannerReport.LineCoverage.newBuilder().setLine(5).setConditions(8).setCoveredConditions(2).build(), + ScannerReport.LineCoverage.newBuilder().setLine(6).setHits(false).setConditions(3).setCoveredConditions(0).build(), + ScannerReport.LineCoverage.newBuilder().setLine(7).setHits(false).build())); + + reportReader.putCoverage(FILE_2_REF, + asList( + ScannerReport.LineCoverage.newBuilder().setLine(2).setHits(true).build(), + ScannerReport.LineCoverage.newBuilder().setLine(3).setHits(false).build(), + ScannerReport.LineCoverage.newBuilder().setLine(5).setHits(true).setConditions(5).setCoveredConditions(1).build(), + ScannerReport.LineCoverage.newBuilder().setLine(6).setConditions(10).setCoveredConditions(3).build(), + ScannerReport.LineCoverage.newBuilder().setLine(7).setHits(false).setConditions(1).setCoveredConditions(0).build(), + ScannerReport.LineCoverage.newBuilder().setLine(8).setHits(false).build())); underTest.execute(new TestComputationStepContext()); MeasureRepoEntry[] nonFileRepoEntries = { - entryOf(metricKeys.getLines(), newMeasureBuilder().create(5000)), - entryOf(metricKeys.getConditions(), newMeasureBuilder().create(700)), - entryOf(metricKeys.getUncoveredLines(), newMeasureBuilder().create(230)), - entryOf(metricKeys.getUncoveredConditions(), newMeasureBuilder().create(25)) + entryOf(LINES_TO_COVER_KEY, newMeasureBuilder().create(5 + 5)), + entryOf(CONDITIONS_TO_COVER_KEY, newMeasureBuilder().create(4 + 8 + 3 + 5 + 10 + 1)), + entryOf(UNCOVERED_LINES_KEY, newMeasureBuilder().create(3 + 3)), + entryOf(UNCOVERED_CONDITIONS_KEY, newMeasureBuilder().create(3 + 6 + 3 + 4 + 7 + 1)) }; assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_REF))).contains(nonFileRepoEntries); @@ -114,8 +125,8 @@ public class ReportCoverageMeasuresStepTest { @Test public void verify_aggregates_values_for_code_line_and_branch_coverage() { LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( - CoreMetrics.LINES_TO_COVER_KEY, CoreMetrics.CONDITIONS_TO_COVER_KEY, - CoreMetrics.UNCOVERED_LINES_KEY, CoreMetrics.UNCOVERED_CONDITIONS_KEY); + LINES_TO_COVER_KEY, CONDITIONS_TO_COVER_KEY, + UNCOVERED_LINES_KEY, UNCOVERED_CONDITIONS_KEY); String codeCoverageKey = CoreMetrics.COVERAGE_KEY; String lineCoverageKey = CoreMetrics.LINE_COVERAGE_KEY; String branchCoverageKey = CoreMetrics.BRANCH_COVERAGE_KEY; diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportNewCoverageMeasuresStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportNewCoverageMeasuresStepTest.java index 3fe2036216c..9721f72e7a0 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportNewCoverageMeasuresStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ReportNewCoverageMeasuresStepTest.java @@ -19,7 +19,6 @@ */ package org.sonar.ce.task.projectanalysis.step; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Optional; @@ -27,6 +26,7 @@ import java.util.Set; import org.junit.Rule; import org.junit.Test; import org.sonar.api.measures.CoreMetrics; +import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.FileAttributes; import org.sonar.ce.task.projectanalysis.component.ReportComponent; @@ -38,14 +38,13 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule; import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule; import org.sonar.ce.task.projectanalysis.source.NewLinesRepository; import org.sonar.ce.task.step.TestComputationStepContext; +import org.sonar.scanner.protocol.output.ScannerReport; +import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY; -import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY; @@ -84,9 +83,6 @@ public class ReportNewCoverageMeasuresStepTest { public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); @Rule public MetricRepositoryRule metricRepository = new MetricRepositoryRule() - .add(CoreMetrics.COVERAGE_LINE_HITS_DATA) - .add(CoreMetrics.CONDITIONS_BY_LINE) - .add(CoreMetrics.COVERED_CONDITIONS_BY_LINE) .add(CoreMetrics.NEW_LINES_TO_COVER) .add(CoreMetrics.NEW_UNCOVERED_LINES) .add(CoreMetrics.NEW_CONDITIONS_TO_COVER) @@ -97,8 +93,12 @@ public class ReportNewCoverageMeasuresStepTest { @Rule public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + @Rule + public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + private NewLinesRepository newLinesRepository = mock(NewLinesRepository.class); - private NewCoverageMeasuresStep underTest = new NewCoverageMeasuresStep(treeRootHolder, measureRepository, metricRepository, newLinesRepository); + private NewCoverageMeasuresStep underTest = new NewCoverageMeasuresStep(treeRootHolder, measureRepository, metricRepository, newLinesRepository, reportReader); public static final ReportComponent FILE_COMPONENT = ReportComponent.builder(Component.Type.FILE, FILE_1_REF) .setFileAttributes(new FileAttributes(false, null, 1)).build(); @@ -143,9 +143,11 @@ public class ReportNewCoverageMeasuresStepTest { treeRootHolder.setRoot(FILE_COMPONENT); when(newLinesRepository.newLinesAvailable()).thenReturn(true); when(newLinesRepository.getNewLines(FILE_COMPONENT)).thenReturn(Optional.of(Collections.emptySet())); - measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), COVERAGE_LINE_HITS_DATA_KEY, newMeasureBuilder().create("2=1;3=1")); - measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), CONDITIONS_BY_LINE_KEY, newMeasureBuilder().create("2=1")); - measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), COVERED_CONDITIONS_BY_LINE_KEY, newMeasureBuilder().create("2=1")); + + reportReader.putCoverage(FILE_COMPONENT.getReportAttributes().getRef(), + asList( + ScannerReport.LineCoverage.newBuilder().setLine(2).setHits(true).setConditions(1).setCoveredConditions(1).build(), + ScannerReport.LineCoverage.newBuilder().setLine(3).setHits(true).build())); underTest.execute(new TestComputationStepContext()); @@ -166,106 +168,90 @@ public class ReportNewCoverageMeasuresStepTest { public void verify_computation_of_measures_for_new_lines_for_FILE() { when(newLinesRepository.newLinesAvailable()).thenReturn(true); - String coverageLineHitsData = COVERAGE_LINE_HITS_DATA_KEY; - String newLinesToCover = NEW_LINES_TO_COVER_KEY; - String newUncoveredLines = NEW_UNCOVERED_LINES_KEY; - String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY; - String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY; - - verify_computation_of_measures_for_new_lines(coverageLineHitsData, - newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions); - } - - private void verify_computation_of_measures_for_new_lines(String coverageLineHitsData, - String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) { treeRootHolder.setRoot(FILE_COMPONENT); setNewLines(FILE_1, 1, 2, 4); - measureRepository.addRawMeasure(FILE_COMPONENT.getReportAttributes().getRef(), coverageLineHitsData, newMeasureBuilder().create("2=0;3=2;4=3")); + reportReader.putCoverage(FILE_COMPONENT.getReportAttributes().getRef(), + asList( + ScannerReport.LineCoverage.newBuilder().setLine(2).setHits(false).build(), + ScannerReport.LineCoverage.newBuilder().setLine(3).setHits(true).build(), + ScannerReport.LineCoverage.newBuilder().setLine(4).setHits(true).build())); underTest.execute(new TestComputationStepContext()); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_COMPONENT.getReportAttributes().getRef()))).contains( - entryOf(newLinesToCover, createMeasure(2d)), - entryOf(newUncoveredLines, createMeasure(1d)), - entryOf(newConditionsToCover, createMeasure(0d)), - entryOf(newUncoveredConditions, createMeasure(0d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(2d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(1d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(0d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(0d))); } @Test public void verify_computation_of_measures_for_new_conditions_for_FILE() { when(newLinesRepository.newLinesAvailable()).thenReturn(true); - - String coverageLineHitsData = COVERAGE_LINE_HITS_DATA_KEY; - String conditionsByLine = CONDITIONS_BY_LINE_KEY; - String coveredConditionsByLine = COVERED_CONDITIONS_BY_LINE_KEY; - String newLinesToCover = NEW_LINES_TO_COVER_KEY; - String newUncoveredLines = NEW_UNCOVERED_LINES_KEY; - String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY; - String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY; - - verify_computation_of_measures_for_new_conditions(new MetricKeys(coverageLineHitsData, conditionsByLine, coveredConditionsByLine, - newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions)); + verify_computation_of_measures_for_new_conditions(); } @Test public void verify_aggregation_of_measures_for_new_conditions() { when(newLinesRepository.newLinesAvailable()).thenReturn(true); - String coverageLineHitsData = CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY; - String conditionsByLine = CoreMetrics.CONDITIONS_BY_LINE_KEY; - String coveredConditionsByLine = CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY; - String newLinesToCover = NEW_LINES_TO_COVER_KEY; - String newUncoveredLines = NEW_UNCOVERED_LINES_KEY; - String newConditionsToCover = NEW_CONDITIONS_TO_COVER_KEY; - String newUncoveredConditions = NEW_UNCOVERED_CONDITIONS_KEY; - - MetricKeys metricKeys = new MetricKeys(coverageLineHitsData, conditionsByLine, coveredConditionsByLine, - newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions); - treeRootHolder.setRoot(MULTIPLE_FILES_TREE); - defineNewLinesAndMeasures(FILE_1, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(0, 3, 2)); - defineNewLinesAndMeasures(FILE_2, metricKeys, new MeasureValues(0, 14, 6), new MeasureValues(0, 13, 7)); - defineNewLinesAndMeasures(FILE_3, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(1, 13, 7)); + defineNewLinesAndLineCoverage(FILE_1, new LineCoverageValues(3, 4, 1), new LineCoverageValues(0, 3, 2)); + defineNewLinesAndLineCoverage(FILE_2, new LineCoverageValues(0, 14, 6), new LineCoverageValues(0, 13, 7)); + defineNewLinesAndLineCoverage(FILE_3, new LineCoverageValues(3, 4, 1), new LineCoverageValues(1, 13, 7)); underTest.execute(new TestComputationStepContext()); // files assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(5d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(3d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(7d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(4d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(5d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(3d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(7d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(4d))); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(5d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(4d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(27d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(14d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(5d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(4d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(27d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(14d))); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_3_REF))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(5d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(2d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(17d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(9d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(5d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(2d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(17d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(9d))); // directories assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_1_REF))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(5d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(3d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(7d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(4d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(5d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(3d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(7d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(4d))); assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_2_REF))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(10d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(6d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(44d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(23d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(10d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(6d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(44d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(23d))); // submodule - MeasureRepoEntry[] repoEntriesFromProject = {entryOf(metricKeys.newLinesToCover, createMeasure(15d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(9d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(51d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(27d))}; + MeasureRepoEntry[] repoEntriesFromProject = {entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(15d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(9d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(51d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(27d))}; // project assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains(repoEntriesFromProject); } + private void defineNewLinesAndLineCoverage(Component c, LineCoverageValues line4, LineCoverageValues line6) { + setNewLines(c, 1, 2, 4, 5, 6, 7); + + reportReader.putCoverage(c.getReportAttributes().getRef(), + asList( + ScannerReport.LineCoverage.newBuilder().setLine(2).setHits(false).build(), + ScannerReport.LineCoverage.newBuilder().setLine(3).setHits(true).build(), + ScannerReport.LineCoverage.newBuilder().setLine(4).setHits(line4.lineHits > 0).setConditions(line4.conditions).setCoveredConditions(line4.coveredConditions).build(), + ScannerReport.LineCoverage.newBuilder().setLine(5).setHits(true).build(), + ScannerReport.LineCoverage.newBuilder().setLine(6).setHits(line6.lineHits > 0).setConditions(line6.conditions).setCoveredConditions(line6.coveredConditions).build(), + ScannerReport.LineCoverage.newBuilder().setLine(7).setHits(false).build())); + } + @Test public void verify_aggregates_variations_for_new_code_line_and_branch_Coverage() { LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( @@ -330,60 +316,29 @@ public class ReportNewCoverageMeasuresStepTest { entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(0d))); } - private void defineNewLinesAndMeasures(Component c, MetricKeys metricKeys, MeasureValues line4, MeasureValues line6) { - setNewLines(c, 1, 2, 4, 5, 6, 7); - measureRepository.addRawMeasure(c.getReportAttributes().getRef(), metricKeys.coverageLineHitsData, - newMeasureBuilder().create("2=0;3=2;4=" + line4.lineHits + ";5=1;6=" + line6.lineHits + ";7=0")); - measureRepository - .addRawMeasure(c.getReportAttributes().getRef(), metricKeys.conditionsByLine, newMeasureBuilder().create("4=" + line4.coveredConditions + ";6=" + line6.coveredConditions)); - measureRepository.addRawMeasure(c.getReportAttributes().getRef(), metricKeys.coveredConditionsByLine, - newMeasureBuilder().create("4=" + line4.uncoveredConditions + ";6=" + line6.uncoveredConditions)); - } - - private static final class MetricKeys { - private final String coverageLineHitsData; - private final String conditionsByLine; - private final String coveredConditionsByLine; - private final String newLinesToCover; - private final String newUncoveredLines; - private final String newConditionsToCover; - private final String newUncoveredConditions; - - public MetricKeys(String coverageLineHitsData, String conditionsByLine, String coveredConditionsByLine, - String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) { - this.coverageLineHitsData = coverageLineHitsData; - this.conditionsByLine = conditionsByLine; - this.coveredConditionsByLine = coveredConditionsByLine; - this.newLinesToCover = newLinesToCover; - this.newUncoveredLines = newUncoveredLines; - this.newConditionsToCover = newConditionsToCover; - this.newUncoveredConditions = newUncoveredConditions; - } - } - - private static final class MeasureValues { + private static final class LineCoverageValues { private final int lineHits; + private final int conditions; private final int coveredConditions; - private final int uncoveredConditions; - public MeasureValues(int lineHits, int coveredConditions, int uncoveredConditions) { + public LineCoverageValues(int lineHits, int conditions, int coveredConditions) { this.lineHits = lineHits; + this.conditions = conditions; this.coveredConditions = coveredConditions; - this.uncoveredConditions = uncoveredConditions; } } - private void verify_computation_of_measures_for_new_conditions(MetricKeys metricKeys) { + private void verify_computation_of_measures_for_new_conditions() { treeRootHolder.setRoot(FILE_COMPONENT); - defineNewLinesAndMeasures(FILE_COMPONENT, metricKeys, new MeasureValues(3, 4, 1), new MeasureValues(0, 3, 2)); + defineNewLinesAndLineCoverage(FILE_COMPONENT, new LineCoverageValues(3, 4, 1), new LineCoverageValues(0, 3, 2)); underTest.execute(new TestComputationStepContext()); assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_COMPONENT.getReportAttributes().getRef()))).contains( - entryOf(metricKeys.newLinesToCover, createMeasure(5d)), - entryOf(metricKeys.newUncoveredLines, createMeasure(3d)), - entryOf(metricKeys.newConditionsToCover, createMeasure(7d)), - entryOf(metricKeys.newUncoveredConditions, createMeasure(4d))); + entryOf(NEW_LINES_TO_COVER_KEY, createMeasure(5d)), + entryOf(NEW_UNCOVERED_LINES_KEY, createMeasure(3d)), + entryOf(NEW_CONDITIONS_TO_COVER_KEY, createMeasure(7d)), + entryOf(NEW_UNCOVERED_CONDITIONS_KEY, createMeasure(4d))); } private static Measure createMeasure(Double expectedVariation) { @@ -394,7 +349,7 @@ public class ReportNewCoverageMeasuresStepTest { private void setNewLines(Component c, Integer... lines) { when(newLinesRepository.newLinesAvailable()).thenReturn(true); - Set newLines = new HashSet<>(Arrays.asList(lines)); + Set newLines = new HashSet<>(asList(lines)); when(newLinesRepository.getNewLines(c)).thenReturn(Optional.of(newLines)); } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ViewsNewCoverageMeasuresStepTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ViewsNewCoverageMeasuresStepTest.java index 90bfbfc1312..110b509e901 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ViewsNewCoverageMeasuresStepTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/ViewsNewCoverageMeasuresStepTest.java @@ -28,12 +28,10 @@ import org.sonar.ce.task.projectanalysis.formula.coverage.LinesAndConditionsWith import org.sonar.ce.task.projectanalysis.measure.Measure; import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule; import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule; -import org.sonar.ce.task.projectanalysis.source.NewLinesRepository; import org.sonar.ce.task.step.TestComputationStepContext; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT_VIEW; import static org.sonar.ce.task.projectanalysis.component.Component.Type.SUBVIEW; import static org.sonar.ce.task.projectanalysis.component.Component.Type.VIEW; @@ -75,9 +73,6 @@ public class ViewsNewCoverageMeasuresStepTest { @Rule public MetricRepositoryRule metricRepository = new MetricRepositoryRule() - .add(CoreMetrics.COVERAGE_LINE_HITS_DATA) - .add(CoreMetrics.CONDITIONS_BY_LINE) - .add(CoreMetrics.COVERED_CONDITIONS_BY_LINE) .add(CoreMetrics.NEW_LINES_TO_COVER) .add(CoreMetrics.NEW_UNCOVERED_LINES) .add(CoreMetrics.NEW_CONDITIONS_TO_COVER) diff --git a/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java b/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java index ee6830f2100..63ddb0b92c3 100644 --- a/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java +++ b/sonar-core/src/main/java/org/sonar/core/metric/ScannerMetrics.java @@ -26,10 +26,10 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Stream; import javax.annotation.concurrent.Immutable; -import org.sonar.api.scanner.ScannerSide; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metrics; +import org.sonar.api.scanner.ScannerSide; import static org.sonar.api.measures.CoreMetrics.CLASSES; import static org.sonar.api.measures.CoreMetrics.COGNITIVE_COMPLEXITY; @@ -37,22 +37,14 @@ import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES; import static org.sonar.api.measures.CoreMetrics.COMPLEXITY; import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_CLASSES; import static org.sonar.api.measures.CoreMetrics.COMPLEXITY_IN_FUNCTIONS; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA; -import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.DIRECTORIES; import static org.sonar.api.measures.CoreMetrics.EXECUTABLE_LINES_DATA; -import static org.sonar.api.measures.CoreMetrics.FILES; import static org.sonar.api.measures.CoreMetrics.FILE_COMPLEXITY_DISTRIBUTION; import static org.sonar.api.measures.CoreMetrics.FUNCTIONS; import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION; import static org.sonar.api.measures.CoreMetrics.GENERATED_LINES; import static org.sonar.api.measures.CoreMetrics.GENERATED_NCLOC; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; import static org.sonar.api.measures.CoreMetrics.NCLOC; import static org.sonar.api.measures.CoreMetrics.NCLOC_DATA; -import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION; import static org.sonar.api.measures.CoreMetrics.PUBLIC_API; import static org.sonar.api.measures.CoreMetrics.PUBLIC_UNDOCUMENTED_API; import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS; @@ -61,8 +53,6 @@ import static org.sonar.api.measures.CoreMetrics.TESTS; import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS; import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME; import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; import static org.sonar.core.util.stream.MoreCollectors.toSet; /** @@ -81,13 +71,10 @@ public class ScannerMetrics { NCLOC_DATA, GENERATED_NCLOC, COMMENT_LINES, - NCLOC_LANGUAGE_DISTRIBUTION, PUBLIC_API, PUBLIC_UNDOCUMENTED_API, - FILES, - DIRECTORIES, CLASSES, FUNCTIONS, STATEMENTS, @@ -105,14 +92,6 @@ public class ScannerMetrics { TEST_FAILURES, TEST_EXECUTION_TIME, - LINES_TO_COVER, - UNCOVERED_LINES, - COVERAGE_LINE_HITS_DATA, - CONDITIONS_TO_COVER, - UNCOVERED_CONDITIONS, - COVERED_CONDITIONS_BY_LINE, - CONDITIONS_BY_LINE, - EXECUTABLE_LINES_DATA); private final Set metrics; diff --git a/sonar-core/src/test/java/org/sonar/core/metric/ScannerMetricsTest.java b/sonar-core/src/test/java/org/sonar/core/metric/ScannerMetricsTest.java index 38e4f9fd4a8..b0599f24be2 100644 --- a/sonar-core/src/test/java/org/sonar/core/metric/ScannerMetricsTest.java +++ b/sonar-core/src/test/java/org/sonar/core/metric/ScannerMetricsTest.java @@ -35,7 +35,7 @@ public class ScannerMetricsTest { @Test public void check_number_of_allowed_core_metrics() { - assertThat(SENSOR_METRICS_WITHOUT_METRIC_PLUGIN).hasSize(32); + assertThat(SENSOR_METRICS_WITHOUT_METRIC_PLUGIN).hasSize(22); } @Test diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java index 9908523fc9a..19a5cce029b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java @@ -19,13 +19,17 @@ */ package org.sonar.api.batch.fs.internal; +import java.util.HashSet; +import java.util.Set; import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.measure.Metric; /** * @since 5.2 */ public abstract class DefaultInputComponent implements InputComponent { private int id; + private Set storedMetricKeys = new HashSet<>(); public DefaultInputComponent(int scannerId) { this.id = scannerId; @@ -57,4 +61,12 @@ public abstract class DefaultInputComponent implements InputComponent { public String toString() { return "[key=" + key() + "]"; } + + public void setHasMeasureFor(Metric metric) { + storedMetricKeys.add(metric.key()); + } + + public boolean hasMeasureFor(Metric metric) { + return storedMetricKeys.contains(metric.key()); + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java index c0fd7c38bcc..cf72686859d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java @@ -31,10 +31,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collection; -import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.io.ByteOrderMark; @@ -43,6 +45,8 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextPointer; import org.sonar.api.batch.fs.TextRange; +import static com.google.common.base.Preconditions.checkState; + /** * @since 4.2 * To create {@link InputFile} in tests, use {@link TestInputFileBuilder}. @@ -55,15 +59,17 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile private final String contents; private final Consumer metadataGenerator; - private Status status; - private Charset charset; - private Metadata metadata; private boolean published; private boolean excludedForCoverage; private boolean excludedForDuplication; - private final Set noSonarLines = new HashSet<>(); private boolean ignoreAllIssues; - private Collection ignoreIssuesOnlineRanges = new ArrayList<>(); + // Lazy init to save memory + private BitSet noSonarLines; + private Status status; + private Charset charset; + private Metadata metadata; + private Collection ignoreIssuesOnlineRanges; + private BitSet executableLines; public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer metadataGenerator) { this(indexedFile, metadataGenerator, null); @@ -90,7 +96,7 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile public InputStream inputStream() throws IOException { return contents != null ? new ByteArrayInputStream(contents.getBytes(charset())) : new BOMInputStream(Files.newInputStream(path()), - ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE); + ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE); } @Override @@ -245,16 +251,16 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile public int[] originalLineStartOffsets() { checkMetadata(); - Preconditions.checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized."); - Preconditions.checkState(metadata.originalLineStartOffsets().length == metadata.lines(), + checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized."); + checkState(metadata.originalLineStartOffsets().length == metadata.lines(), "InputFile is not properly initialized. 'originalLineStartOffsets' property length should be equal to 'lines'"); return metadata.originalLineStartOffsets(); } public int[] originalLineEndOffsets() { checkMetadata(); - Preconditions.checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized."); - Preconditions.checkState(metadata.originalLineEndOffsets().length == metadata.lines(), + checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized."); + checkState(metadata.originalLineEndOffsets().length == metadata.lines(), "InputFile is not properly initialized. 'originalLineEndOffsets' property length should be equal to 'lines'"); return metadata.originalLineEndOffsets(); } @@ -383,11 +389,17 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile } public void noSonarAt(Set noSonarLines) { - this.noSonarLines.addAll(noSonarLines); + if (this.noSonarLines == null) { + this.noSonarLines = new BitSet(lines()); + } + noSonarLines.forEach(l -> this.noSonarLines.set(l - 1)); } public boolean hasNoSonarAt(int line) { - return this.noSonarLines.contains(line); + if (this.noSonarLines == null) { + return false; + } + return this.noSonarLines.get(line - 1); } public boolean isIgnoreAllIssues() { @@ -399,13 +411,29 @@ public class DefaultInputFile extends DefaultInputComponent implements InputFile } public void addIgnoreIssuesOnLineRanges(Collection lineRanges) { + if (this.ignoreIssuesOnlineRanges == null) { + this.ignoreIssuesOnlineRanges = new ArrayList<>(); + } this.ignoreIssuesOnlineRanges.addAll(lineRanges); } public boolean isIgnoreAllIssuesOnLine(@Nullable Integer line) { - if (line == null) { + if (line == null || ignoreIssuesOnlineRanges == null) { return false; } return ignoreIssuesOnlineRanges.stream().anyMatch(r -> r[0] <= line && line <= r[1]); } + + public void setExecutableLines(Set executableLines) { + checkState(this.executableLines == null, "Executable lines have already been saved for file: {}", this.toString()); + this.executableLines = new BitSet(lines()); + executableLines.forEach(l -> this.executableLines.set(l - 1)); + } + + public Optional> getExecutableLines() { + if (this.executableLines == null) { + return Optional.empty(); + } + return Optional.of(this.executableLines.stream().map(i -> i + 1).boxed().collect(Collectors.toSet())); + } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/CoverageType.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/CoverageType.java index de201f00597..c63f94ce6eb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/CoverageType.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/coverage/CoverageType.java @@ -19,34 +19,6 @@ */ package org.sonar.api.batch.sensor.coverage; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; -import org.sonar.api.measures.Metric; - -import static java.util.Arrays.asList; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA; -import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.IT_COVERAGE_LINE_HITS_DATA; -import static org.sonar.api.measures.CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.IT_LINES_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_LINES; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA; -import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.OVERALL_LINES_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_LINES; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; - /** * Different coverage categories. * @since 5.2 @@ -56,63 +28,8 @@ import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; @Deprecated public enum CoverageType { - UNIT(LINES_TO_COVER, UNCOVERED_LINES, COVERAGE_LINE_HITS_DATA, CONDITIONS_TO_COVER, UNCOVERED_CONDITIONS, COVERED_CONDITIONS_BY_LINE, CONDITIONS_BY_LINE), - IT(IT_LINES_TO_COVER, IT_UNCOVERED_LINES, IT_COVERAGE_LINE_HITS_DATA, IT_CONDITIONS_TO_COVER, IT_UNCOVERED_CONDITIONS, IT_COVERED_CONDITIONS_BY_LINE, IT_CONDITIONS_BY_LINE), - OVERALL(OVERALL_LINES_TO_COVER, OVERALL_UNCOVERED_LINES, OVERALL_COVERAGE_LINE_HITS_DATA, OVERALL_CONDITIONS_TO_COVER, OVERALL_UNCOVERED_CONDITIONS, - OVERALL_COVERED_CONDITIONS_BY_LINE, OVERALL_CONDITIONS_BY_LINE); - - private final Metric linesToCover; - private final Metric uncoveredLines; - private final Metric lineHitsData; - private final Metric conditionsToCover; - private final Metric uncoveredConditions; - private final Metric coveredConditionsByLine; - private final Metric conditionsByLine; - private final Set all; - - CoverageType(Metric linesToCover, Metric uncoveredLines, Metric lineHitsData, Metric conditionsToCover, Metric uncoveredConditions, Metric coveredConditionsByLine, - Metric conditionsByLine) { - this.linesToCover = linesToCover; - this.uncoveredLines = uncoveredLines; - this.lineHitsData = lineHitsData; - this.conditionsToCover = conditionsToCover; - this.uncoveredConditions = uncoveredConditions; - this.coveredConditionsByLine = coveredConditionsByLine; - this.conditionsByLine = conditionsByLine; - this.all = Collections.unmodifiableSet(new LinkedHashSet<>( - asList(linesToCover, uncoveredLines, lineHitsData, conditionsToCover, uncoveredConditions, coveredConditionsByLine, conditionsByLine))); - } - - public Set allMetrics() { - return all; - } - - public Metric linesToCover() { - return linesToCover; - } - - public Metric uncoveredLines() { - return uncoveredLines; - } - - public Metric lineHitsData() { - return lineHitsData; - } - - public Metric conditionsToCover() { - return conditionsToCover; - } - - public Metric uncoveredConditions() { - return uncoveredConditions; - } - - public Metric coveredConditionsByLine() { - return coveredConditionsByLine; - } - - public Metric conditionsByLine() { - return conditionsByLine; - } + UNIT, + IT, + OVERALL; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java index b04a30671ca..d15be6890ac 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/CoreMetrics.java @@ -538,9 +538,6 @@ public final class CoreMetrics { public static final String LINES_TO_COVER_KEY = "lines_to_cover"; - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - */ public static final Metric LINES_TO_COVER = new Metric.Builder(LINES_TO_COVER_KEY, "Lines to Cover", Metric.ValueType.INT) .setDescription("Lines to cover") .setDirection(Metric.DIRECTION_WORST) @@ -559,9 +556,6 @@ public final class CoreMetrics { public static final String UNCOVERED_LINES_KEY = "uncovered_lines"; - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - */ public static final Metric UNCOVERED_LINES = new Metric.Builder(UNCOVERED_LINES_KEY, "Uncovered Lines", Metric.ValueType.INT) .setDescription("Uncovered lines") .setDirection(Metric.DIRECTION_WORST) @@ -599,30 +593,8 @@ public final class CoreMetrics { .setDeleteHistoricalData(true) .create(); - /** - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String COVERAGE_LINE_HITS_DATA_KEY = "coverage_line_hits_data"; - - /** - * Key-value pairs, where key - is a number of line, and value - is a number of hits for this line. - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - * - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric COVERAGE_LINE_HITS_DATA = new Metric.Builder(COVERAGE_LINE_HITS_DATA_KEY, "Coverage Hits by Line", Metric.ValueType.DATA) - .setDescription("Coverage hits by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - public static final String CONDITIONS_TO_COVER_KEY = "conditions_to_cover"; - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - */ public static final Metric CONDITIONS_TO_COVER = new Metric.Builder(CONDITIONS_TO_COVER_KEY, "Conditions to Cover", Metric.ValueType.INT) .setDescription("Conditions to cover") .setDomain(DOMAIN_COVERAGE) @@ -639,9 +611,6 @@ public final class CoreMetrics { public static final String UNCOVERED_CONDITIONS_KEY = "uncovered_conditions"; - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - */ public static final Metric UNCOVERED_CONDITIONS = new Metric.Builder(UNCOVERED_CONDITIONS_KEY, "Uncovered Conditions", Metric.ValueType.INT) .setDescription("Uncovered conditions") .setDirection(Metric.DIRECTION_WORST) @@ -679,763 +648,6 @@ public final class CoreMetrics { .setDeleteHistoricalData(true) .create(); - /** - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String CONDITIONS_BY_LINE_KEY = "conditions_by_line"; - - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - * - * @since 2.7 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric CONDITIONS_BY_LINE = new Metric.Builder(CONDITIONS_BY_LINE_KEY, "Conditions by Line", Metric.ValueType.DATA) - .setDescription("Conditions by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - /** - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String COVERED_CONDITIONS_BY_LINE_KEY = "covered_conditions_by_line"; - - /** - * Use {@link CoverageMeasuresBuilder} to build measure for this metric. - * - * @since 2.7 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric COVERED_CONDITIONS_BY_LINE = new Metric.Builder(COVERED_CONDITIONS_BY_LINE_KEY, "Covered Conditions by Line", Metric.ValueType.DATA) - .setDescription("Covered conditions by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - // -------------------------------------------------------------------------------------------------------------------- - // - // INTEGRATION TESTS - // - // -------------------------------------------------------------------------------------------------------------------- - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_COVERAGE_KEY = "it_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_COVERAGE = new Metric.Builder(IT_COVERAGE_KEY, "IT Coverage", Metric.ValueType.PERCENT) - .setDescription("Integration tests coverage") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_COVERAGE_KEY = "new_it_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_COVERAGE = new Metric.Builder(NEW_IT_COVERAGE_KEY, "Coverage by IT on New Code", Metric.ValueType.PERCENT) - .setDescription("Integration tests coverage of new/changed code") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_LINES_TO_COVER_KEY = "it_lines_to_cover"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_LINES_TO_COVER = new Metric.Builder(IT_LINES_TO_COVER_KEY, "IT Lines to Cover", Metric.ValueType.INT) - .setDescription("Lines to cover by Integration Tests") - .setDirection(Metric.DIRECTION_BETTER) - .setDomain(DOMAIN_COVERAGE) - .setQualitative(false) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_LINES_TO_COVER_KEY = "new_it_lines_to_cover"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_LINES_TO_COVER = new Metric.Builder(NEW_IT_LINES_TO_COVER_KEY, "Lines to Cover by IT on New Code", Metric.ValueType.INT) - .setDescription("Lines to cover on new code by integration tests") - .setDirection(Metric.DIRECTION_WORST) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_UNCOVERED_LINES_KEY = "it_uncovered_lines"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_UNCOVERED_LINES = new Metric.Builder(IT_UNCOVERED_LINES_KEY, "IT Uncovered Lines", Metric.ValueType.INT) - .setDescription("Uncovered lines by integration tests") - .setDirection(Metric.DIRECTION_WORST) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_UNCOVERED_LINES_KEY = "new_it_uncovered_lines"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_UNCOVERED_LINES = new Metric.Builder(NEW_IT_UNCOVERED_LINES_KEY, "Uncovered Lines by IT on New Code", Metric.ValueType.INT) - .setDescription("New lines that are not covered by integration tests") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setBestValue(0.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_LINE_COVERAGE_KEY = "it_line_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_LINE_COVERAGE = new Metric.Builder(IT_LINE_COVERAGE_KEY, "IT Line Coverage", Metric.ValueType.PERCENT) - .setDescription("Line coverage by integration tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_LINE_COVERAGE_KEY = "new_it_line_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_LINE_COVERAGE = new Metric.Builder(NEW_IT_LINE_COVERAGE_KEY, "Line Coverage by IT on New Code", Metric.ValueType.PERCENT) - .setDescription("Integration tests line coverage of added/changed code") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String IT_COVERAGE_LINE_HITS_DATA_KEY = "it_coverage_line_hits_data"; - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric IT_COVERAGE_LINE_HITS_DATA = new Metric.Builder(IT_COVERAGE_LINE_HITS_DATA_KEY, "IT Coverage Hits by Line", Metric.ValueType.DATA) - .setDescription("Coverage hits by line by integration tests") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_CONDITIONS_TO_COVER_KEY = "it_conditions_to_cover"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_CONDITIONS_TO_COVER = new Metric.Builder(IT_CONDITIONS_TO_COVER_KEY, "IT Branches to Cover", Metric.ValueType.INT) - .setDescription("Integration Tests conditions to cover") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_CONDITIONS_TO_COVER_KEY = "new_it_conditions_to_cover"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_CONDITIONS_TO_COVER = new Metric.Builder(NEW_IT_CONDITIONS_TO_COVER_KEY, "Branches to Cover by IT on New Code", Metric.ValueType.INT) - .setDescription("Branches to cover by Integration Tests on New Code") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_UNCOVERED_CONDITIONS_KEY = "it_uncovered_conditions"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_UNCOVERED_CONDITIONS = new Metric.Builder(IT_UNCOVERED_CONDITIONS_KEY, "IT Uncovered Conditions", Metric.ValueType.INT) - .setDescription("Uncovered conditions by integration tests") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_UNCOVERED_CONDITIONS_KEY = "new_it_uncovered_conditions"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_UNCOVERED_CONDITIONS = new Metric.Builder(NEW_IT_UNCOVERED_CONDITIONS_KEY, "Uncovered Conditions by IT on New Code", - Metric.ValueType.INT) - .setDescription("New conditions that are not covered by integration tests") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setBestValue(0.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String IT_BRANCH_COVERAGE_KEY = "it_branch_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric IT_BRANCH_COVERAGE = new Metric.Builder(IT_BRANCH_COVERAGE_KEY, "IT Condition Coverage", Metric.ValueType.PERCENT) - .setDescription("Condition coverage by integration tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_IT_BRANCH_COVERAGE_KEY = "new_it_branch_coverage"; - - /** - * @since 2.12 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_IT_BRANCH_COVERAGE = new Metric.Builder(NEW_IT_BRANCH_COVERAGE_KEY, "Condition Coverage by IT on New Code", Metric.ValueType.PERCENT) - .setDescription("Integration tests condition coverage of new/changed code") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String IT_CONDITIONS_BY_LINE_KEY = "it_conditions_by_line"; - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric IT_CONDITIONS_BY_LINE = new Metric.Builder(IT_CONDITIONS_BY_LINE_KEY, "IT Conditions by Line", Metric.ValueType.DATA) - .setDescription("IT conditions by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String IT_COVERED_CONDITIONS_BY_LINE_KEY = "it_covered_conditions_by_line"; - - /** - * @since 2.12 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric IT_COVERED_CONDITIONS_BY_LINE = new Metric.Builder(IT_COVERED_CONDITIONS_BY_LINE_KEY, "IT Covered Conditions by Line", Metric.ValueType.DATA) - .setDescription("IT covered conditions by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - // -------------------------------------------------------------------------------------------------------------------- - // - // OVERALL TESTS - // - // -------------------------------------------------------------------------------------------------------------------- - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_COVERAGE_KEY = "overall_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_COVERAGE = new Metric.Builder(OVERALL_COVERAGE_KEY, "Overall Coverage", Metric.ValueType.PERCENT) - .setDescription("Overall test coverage") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_COVERAGE_KEY = "new_overall_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_COVERAGE = new Metric.Builder(NEW_OVERALL_COVERAGE_KEY, "Overall Coverage on New Code", Metric.ValueType.PERCENT) - .setDescription("Overall coverage of new/changed code") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_LINES_TO_COVER_KEY = "overall_lines_to_cover"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_LINES_TO_COVER = new Metric.Builder(OVERALL_LINES_TO_COVER_KEY, "Overall Lines to Cover", Metric.ValueType.INT) - .setDescription("Overall lines to cover by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setDomain(DOMAIN_COVERAGE) - .setQualitative(false) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_LINES_TO_COVER_KEY = "new_overall_lines_to_cover"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_LINES_TO_COVER = new Metric.Builder(NEW_OVERALL_LINES_TO_COVER_KEY, "Overall Lines to Cover on New Code", Metric.ValueType.INT) - .setDescription("New lines to cover by all tests") - .setDirection(Metric.DIRECTION_WORST) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_UNCOVERED_LINES_KEY = "overall_uncovered_lines"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_UNCOVERED_LINES = new Metric.Builder(OVERALL_UNCOVERED_LINES_KEY, "Overall Uncovered Lines", Metric.ValueType.INT) - .setDescription("Uncovered lines by all tests") - .setDirection(Metric.DIRECTION_WORST) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_UNCOVERED_LINES_KEY = "new_overall_uncovered_lines"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_UNCOVERED_LINES = new Metric.Builder(NEW_OVERALL_UNCOVERED_LINES_KEY, "Overall Uncovered Lines on New Code", Metric.ValueType.INT) - .setDescription("New lines that are not covered by any tests") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setBestValue(0.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_LINE_COVERAGE_KEY = "overall_line_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_LINE_COVERAGE = new Metric.Builder(OVERALL_LINE_COVERAGE_KEY, "Overall Line Coverage", Metric.ValueType.PERCENT) - .setDescription("Line coverage by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_LINE_COVERAGE_KEY = "new_overall_line_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_LINE_COVERAGE = new Metric.Builder(NEW_OVERALL_LINE_COVERAGE_KEY, "Overall Line Coverage on New Code", Metric.ValueType.PERCENT) - .setDescription("Line coverage of added/changed code by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String OVERALL_COVERAGE_LINE_HITS_DATA_KEY = "overall_coverage_line_hits_data"; - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric OVERALL_COVERAGE_LINE_HITS_DATA = new Metric.Builder(OVERALL_COVERAGE_LINE_HITS_DATA_KEY, "Overall Coverage Hits by Line", - Metric.ValueType.DATA) - .setDescription("Coverage hits by all tests and by line") - .setDirection(Metric.DIRECTION_NONE) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_CONDITIONS_TO_COVER_KEY = "overall_conditions_to_cover"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_CONDITIONS_TO_COVER = new Metric.Builder(OVERALL_CONDITIONS_TO_COVER_KEY, "Overall Branches to Cover", Metric.ValueType.INT) - .setDescription("Branches to cover by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(false) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_CONDITIONS_TO_COVER_KEY = "new_overall_conditions_to_cover"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_CONDITIONS_TO_COVER = new Metric.Builder(NEW_OVERALL_CONDITIONS_TO_COVER_KEY, "Overall Branches to Cover on New Code", - Metric.ValueType.INT) - .setDescription("New branches to cover by all tests") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_UNCOVERED_CONDITIONS_KEY = "overall_uncovered_conditions"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_UNCOVERED_CONDITIONS = new Metric.Builder(OVERALL_UNCOVERED_CONDITIONS_KEY, "Overall Uncovered Conditions", Metric.ValueType.INT) - .setDescription("Uncovered conditions by all tests") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_UNCOVERED_CONDITIONS_KEY = "new_overall_uncovered_conditions"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_UNCOVERED_CONDITIONS = new Metric.Builder(NEW_OVERALL_UNCOVERED_CONDITIONS_KEY, "Overall Uncovered Conditions on New Code", - Metric.ValueType.INT) - .setDescription("New conditions that are not covered by any test") - .setDirection(Metric.DIRECTION_WORST) - .setDomain(DOMAIN_COVERAGE) - .setBestValue(0.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String OVERALL_BRANCH_COVERAGE_KEY = "overall_branch_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric OVERALL_BRANCH_COVERAGE = new Metric.Builder(OVERALL_BRANCH_COVERAGE_KEY, "Overall Condition Coverage", Metric.ValueType.PERCENT) - .setDescription("Condition coverage by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final String NEW_OVERALL_BRANCH_COVERAGE_KEY = "new_overall_branch_coverage"; - - /** - * @since 3.3 - * @deprecated since 6.2 all coverage reports are merged in the same measures - */ - @Deprecated - public static final Metric NEW_OVERALL_BRANCH_COVERAGE = new Metric.Builder(NEW_OVERALL_BRANCH_COVERAGE_KEY, "Overall Condition Coverage on New Code", - Metric.ValueType.PERCENT) - .setDescription("Condition coverage of new/changed code by all tests") - .setDirection(Metric.DIRECTION_BETTER) - .setQualitative(true) - .setDomain(DOMAIN_COVERAGE) - .setWorstValue(0.0) - .setBestValue(100.0) - .setDeleteHistoricalData(true) - .setHidden(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String OVERALL_CONDITIONS_BY_LINE_KEY = "overall_conditions_by_line"; - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric OVERALL_CONDITIONS_BY_LINE = new Metric.Builder(OVERALL_CONDITIONS_BY_LINE_KEY, "Overall Conditions by Line", Metric.ValueType.DATA) - .setDescription("Overall conditions by all tests and by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final String OVERALL_COVERED_CONDITIONS_BY_LINE_KEY = "overall_covered_conditions_by_line"; - - /** - * @since 3.3 - * @deprecated since 5.2 soon to be removed - */ - @Deprecated - public static final Metric OVERALL_COVERED_CONDITIONS_BY_LINE = new Metric.Builder(OVERALL_COVERED_CONDITIONS_BY_LINE_KEY, "Overall Covered Conditions by Line", - Metric.ValueType.DATA) - .setDescription("Overall covered conditions by all tests and by line") - .setDomain(DOMAIN_COVERAGE) - .setDeleteHistoricalData(true) - .create(); - // -------------------------------------------------------------------------------------------------------------------- // // DUPLICATIONS diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/issue/NoSonarFilterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/issue/NoSonarFilterTest.java index 0665df11878..b28f70876fd 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/issue/NoSonarFilterTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/issue/NoSonarFilterTest.java @@ -31,7 +31,7 @@ public class NoSonarFilterTest { @Test public void should_store_nosonar_lines_on_inputfile() { - DefaultInputFile f = TestInputFileBuilder.create("module1", "myfile.java").build(); + DefaultInputFile f = TestInputFileBuilder.create("module1", "myfile.java").setLines(8).build(); new NoSonarFilter().noSonarInFile(f, new HashSet<>(Arrays.asList(1,4))); assertThat(f.hasNoSonarAt(1)).isTrue(); diff --git a/sonar-scanner-engine/build.gradle b/sonar-scanner-engine/build.gradle index 9ad0ce807ba..77c26c7466d 100644 --- a/sonar-scanner-engine/build.gradle +++ b/sonar-scanner-engine/build.gradle @@ -26,7 +26,6 @@ dependencies { compile 'org.slf4j:jul-to-slf4j' compile 'org.slf4j:log4j-over-slf4j' compile 'org.slf4j:slf4j-api' - compile 'org.sonarsource:sonar-persistit' compile project(':sonar-core') compile project(':sonar-scanner-protocol') compile project(':sonar-ws') diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java index 7ef71bbb221..eecbbd15e84 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContext.java @@ -32,15 +32,12 @@ import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.FileLinesContext; import org.sonar.api.utils.KeyValueFormat; -import org.sonar.api.utils.KeyValueFormat.Converter; -import org.sonar.scanner.scan.measure.MeasureCache; import static java.util.stream.Collectors.toMap; public class DefaultFileLinesContext implements FileLinesContext { private final InputFile inputFile; private final MetricFinder metricFinder; - private final MeasureCache measureCache; /** * metric key -> line -> value @@ -48,11 +45,10 @@ public class DefaultFileLinesContext implements FileLinesContext { private final Map> map = new HashMap<>(); private final SensorStorage sensorStorage; - public DefaultFileLinesContext(SensorStorage sensorStorage, InputFile inputFile, MetricFinder metricFinder, MeasureCache measureCache) { + public DefaultFileLinesContext(SensorStorage sensorStorage, InputFile inputFile, MetricFinder metricFinder) { this.sensorStorage = sensorStorage; this.inputFile = inputFile; this.metricFinder = metricFinder; - this.measureCache = measureCache; } @Override @@ -68,13 +64,6 @@ public class DefaultFileLinesContext implements FileLinesContext { Preconditions.checkArgument(line <= inputFile.lines(), "Line %s is out of range for file %s. File has %s lines.", line, inputFile, inputFile.lines()); } - public Integer getIntValue(String metricKey, int line) { - Preconditions.checkNotNull(metricKey); - checkLineRange(line); - Map lines = map.computeIfAbsent(metricKey, k -> loadData(k, KeyValueFormat.newIntegerConverter())); - return (Integer) lines.get(line); - } - @Override public void setStringValue(String metricKey, int line, String value) { Preconditions.checkNotNull(metricKey); @@ -84,13 +73,6 @@ public class DefaultFileLinesContext implements FileLinesContext { setValue(metricKey, line, value); } - public String getStringValue(String metricKey, int line) { - Preconditions.checkNotNull(metricKey); - checkLineRange(line); - Map lines = map.computeIfAbsent(metricKey, k -> loadData(k, KeyValueFormat.newStringConverter())); - return (String) lines.get(line); - } - private void setValue(String metricKey, int line, Object value) { map.computeIfAbsent(metricKey, k -> new HashMap<>()) .put(line, value); @@ -123,20 +105,9 @@ public class DefaultFileLinesContext implements FileLinesContext { return lines; } - private Map loadData(String metricKey, Converter converter) { - DefaultMeasure measure = measureCache.byMetric(inputFile.key(), metricKey); - String data = measure != null ? (String) measure.value() : null; - if (data != null) { - return ImmutableMap.copyOf(KeyValueFormat.parse(data, KeyValueFormat.newIntegerConverter(), converter)); - } - // no such measure - return ImmutableMap.of(); - } - /** * Checks that measure was not saved. * - * @see #loadData(String, Converter) * @see #save() */ private static boolean shouldSave(Map lines) { diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContextFactory.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContextFactory.java index 8ed50b88710..209f3544810 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContextFactory.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/DefaultFileLinesContextFactory.java @@ -25,24 +25,21 @@ import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.measures.FileLinesContext; import org.sonar.api.measures.FileLinesContextFactory; -import org.sonar.scanner.scan.measure.MeasureCache; @Immutable public class DefaultFileLinesContextFactory implements FileLinesContextFactory { private final SensorStorage sensorStorage; private final MetricFinder metricFinder; - private final MeasureCache measureCache; - public DefaultFileLinesContextFactory(SensorStorage sensorStorage, MetricFinder metricFinder, MeasureCache measureCache) { + public DefaultFileLinesContextFactory(SensorStorage sensorStorage, MetricFinder metricFinder) { this.sensorStorage = sensorStorage; this.metricFinder = metricFinder; - this.measureCache = measureCache; } @Override public FileLinesContext createFor(InputFile inputFile) { - return new DefaultFileLinesContext(sensorStorage, inputFile, metricFinder, measureCache); + return new DefaultFileLinesContext(sensorStorage, inputFile, metricFinder); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java index 4857692b80c..302f263a92f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java @@ -52,7 +52,6 @@ import org.sonar.scanner.repository.MetricsRepositoryProvider; import org.sonar.scanner.repository.settings.DefaultGlobalSettingsLoader; import org.sonar.scanner.repository.settings.GlobalSettingsLoader; import org.sonar.scanner.scan.ProjectScanContainer; -import org.sonar.scanner.storage.StoragesManager; public class GlobalContainer extends ComponentContainer { private static final Logger LOG = Loggers.get(GlobalContainer.class); @@ -90,7 +89,6 @@ public class GlobalContainer extends ComponentContainer { new SonarQubeVersion(apiVersion), SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER), - StoragesManager.class, new GlobalServerSettingsProvider(), new GlobalConfigurationProvider(), new ScannerWsClientProvider(), diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CoveragePublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CoveragePublisher.java deleted file mode 100644 index d2bb71b1cd3..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/CoveragePublisher.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.report; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage; -import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage.Builder; -import org.sonar.scanner.protocol.output.ScannerReportWriter; -import org.sonar.scanner.scan.filesystem.InputComponentStore; -import org.sonar.scanner.scan.measure.MeasureCache; - -public class CoveragePublisher implements ReportPublisherStep { - - private final InputComponentStore componentStore; - private final MeasureCache measureCache; - - public CoveragePublisher(InputComponentStore componentStore, MeasureCache measureCache) { - this.componentStore = componentStore; - this.measureCache = measureCache; - } - - @Override - public void publish(ScannerReportWriter writer) { - for (final DefaultInputFile inputFile : componentStore.allFilesToPublish()) { - Map coveragePerLine = new LinkedHashMap<>(); - - int lineCount = inputFile.lines(); - applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine, - (value, builder) -> builder.setHits(Integer.parseInt(value) > 0)); - applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.CONDITIONS_BY_LINE_KEY, coveragePerLine, - (value, builder) -> builder.setConditions(Integer.parseInt(value))); - applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine, - (value, builder) -> builder.setCoveredConditions(Integer.parseInt(value))); - - writer.writeComponentCoverage(inputFile.scannerId(), coveragePerLine.values().stream().map(BuildCoverage.INSTANCE).collect(Collectors.toList())); - } - } - - void applyLineMeasure(String inputFileKey, int lineCount, String metricKey, Map coveragePerLine, MeasureOperation op) { - DefaultMeasure measure = measureCache.byMetric(inputFileKey, metricKey); - if (measure != null) { - Map lineMeasures = KeyValueFormat.parseIntString((String) measure.value()); - for (Map.Entry lineMeasure : lineMeasures.entrySet()) { - int lineIdx = lineMeasure.getKey(); - if (lineIdx <= lineCount) { - String value = lineMeasure.getValue(); - if (StringUtils.isNotEmpty(value)) { - LineCoverage.Builder coverageBuilder = coveragePerLine.get(lineIdx); - if (coverageBuilder == null) { - coverageBuilder = LineCoverage.newBuilder(); - coverageBuilder.setLine(lineIdx); - coveragePerLine.put(lineIdx, coverageBuilder); - } - op.apply(value, coverageBuilder); - } - } - } - } - } - - interface MeasureOperation { - void apply(String value, LineCoverage.Builder builder); - } - - private enum BuildCoverage implements Function { - INSTANCE; - - @Override - public LineCoverage apply(@Nonnull Builder input) { - return input.build(); - } - } - -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java deleted file mode 100644 index 75692161a69..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/MeasuresPublisher.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.report; - -import com.google.common.collect.Iterables; -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; -import org.sonar.api.batch.fs.InputComponent; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputFile.Type; -import org.sonar.api.batch.fs.internal.DefaultInputComponent; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.measure.Metric; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.test.MutableTestPlan; -import org.sonar.api.test.TestCase.Status; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.scanner.deprecated.test.TestPlanBuilder; -import org.sonar.scanner.protocol.output.ScannerReport; -import org.sonar.scanner.protocol.output.ScannerReport.Measure.BoolValue; -import org.sonar.scanner.protocol.output.ScannerReport.Measure.DoubleValue; -import org.sonar.scanner.protocol.output.ScannerReport.Measure.IntValue; -import org.sonar.scanner.protocol.output.ScannerReport.Measure.LongValue; -import org.sonar.scanner.protocol.output.ScannerReport.Measure.StringValue; -import org.sonar.scanner.protocol.output.ScannerReportWriter; -import org.sonar.scanner.scan.filesystem.InputComponentStore; -import org.sonar.scanner.scan.measure.MeasureCache; - -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS; -import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS_KEY; -import static org.sonar.api.measures.CoreMetrics.TESTS; -import static org.sonar.api.measures.CoreMetrics.TESTS_KEY; -import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS; -import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS_KEY; -import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME; -import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME_KEY; -import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES; -import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES_KEY; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES_KEY; - -public class MeasuresPublisher implements ReportPublisherStep { - - private final InputComponentStore componentStore; - private final MeasureCache measureCache; - private final TestPlanBuilder testPlanBuilder; - - public MeasuresPublisher(InputComponentStore componentStore, MeasureCache measureCache, TestPlanBuilder testPlanBuilder) { - this.componentStore = componentStore; - this.measureCache = measureCache; - this.testPlanBuilder = testPlanBuilder; - } - - @Override - public void publish(ScannerReportWriter writer) { - final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder(); - - for (final InputComponent c : componentStore.all()) { - DefaultInputComponent component = (DefaultInputComponent) c; - if (component.isFile()) { - DefaultInputFile file = (DefaultInputFile) component; - // Recompute all coverage measures from line data to take into account the possible merge of several reports - updateCoverageFromLineData(file); - // Recompute test execution measures from MutableTestPlan to take into account the possible merge of several reports - updateTestExecutionFromTestPlan(file); - } - - Iterable> scannerMeasures = measureCache.byComponentKey(component.key()); - if (scannerMeasures.iterator().hasNext()) { - writer.writeComponentMeasures(component.scannerId(), StreamSupport.stream(scannerMeasures.spliterator(), false) - .map(input -> { - if (input.value() == null) { - throw new IllegalArgumentException( - String.format("Measure on metric '%s' and component '%s' has no value, but it's not allowed", input.metric().key(), component.key())); - } - builder.clear(); - builder.setMetricKey(input.metric().key()); - setValueAccordingToType(builder, input); - return builder.build(); - }).collect(Collectors.toList())); - } - } - } - - private static void setValueAccordingToType(ScannerReport.Measure.Builder builder, DefaultMeasure measure) { - Serializable value = measure.value(); - Metric metric = measure.metric(); - if (Boolean.class.equals(metric.valueType())) { - builder.setBooleanValue(BoolValue.newBuilder().setValue(((Boolean) value).booleanValue())); - } else if (Integer.class.equals(metric.valueType())) { - builder.setIntValue(IntValue.newBuilder().setValue(((Number) value).intValue())); - } else if (Double.class.equals(metric.valueType())) { - builder.setDoubleValue(DoubleValue.newBuilder().setValue(((Number) value).doubleValue())); - } else if (String.class.equals(metric.valueType())) { - builder.setStringValue(StringValue.newBuilder().setValue((String) value)); - } else if (Long.class.equals(metric.valueType())) { - builder.setLongValue(LongValue.newBuilder().setValue(((Number) value).longValue())); - } else { - throw new UnsupportedOperationException("Unsupported type :" + metric.valueType()); - } - } - - private void updateTestExecutionFromTestPlan(final InputFile inputFile) { - final MutableTestPlan testPlan = testPlanBuilder.getTestPlanByFile(inputFile); - if (testPlan == null || Iterables.isEmpty(testPlan.testCases())) { - return; - } - long nonSkippedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() != Status.SKIPPED).count(); - measureCache.put(inputFile.key(), TESTS_KEY, new DefaultMeasure().forMetric(TESTS).withValue((int) nonSkippedTests)); - long executionTime = StreamSupport.stream(testPlan.testCases().spliterator(), false).mapToLong(t -> t.durationInMs() != null ? t.durationInMs().longValue() : 0L).sum(); - measureCache.put(inputFile.key(), TEST_EXECUTION_TIME_KEY, new DefaultMeasure().forMetric(TEST_EXECUTION_TIME).withValue(executionTime)); - long errorTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.ERROR).count(); - measureCache.put(inputFile.key(), TEST_ERRORS_KEY, new DefaultMeasure().forMetric(TEST_ERRORS).withValue((int) errorTests)); - long skippedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.SKIPPED).count(); - measureCache.put(inputFile.key(), SKIPPED_TESTS_KEY, new DefaultMeasure().forMetric(SKIPPED_TESTS).withValue((int) skippedTests)); - long failedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.FAILURE).count(); - measureCache.put(inputFile.key(), TEST_FAILURES_KEY, new DefaultMeasure().forMetric(TEST_FAILURES).withValue((int) failedTests)); - } - - private void updateCoverageFromLineData(final InputFile inputFile) { - if (inputFile.type() != Type.MAIN) { - return; - } - DefaultMeasure lineHitsMeasure = (DefaultMeasure) measureCache.byMetric(inputFile.key(), CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY); - if (lineHitsMeasure != null) { - Map lineHits = KeyValueFormat.parseIntInt(lineHitsMeasure.value()); - measureCache.put(inputFile.key(), LINES_TO_COVER_KEY, new DefaultMeasure().forMetric(LINES_TO_COVER).withValue(lineHits.keySet().size())); - measureCache.put(inputFile.key(), UNCOVERED_LINES_KEY, - new DefaultMeasure().forMetric(UNCOVERED_LINES).withValue((int) lineHits.values() - .stream() - .filter(hit -> hit == 0) - .count())); - } - DefaultMeasure conditionsMeasure = (DefaultMeasure) measureCache.byMetric(inputFile.key(), CoreMetrics.CONDITIONS_BY_LINE_KEY); - DefaultMeasure coveredConditionsMeasure = (DefaultMeasure) measureCache.byMetric(inputFile.key(), CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY); - if (conditionsMeasure != null) { - Map conditions = KeyValueFormat.parseIntInt(conditionsMeasure.value()); - Map coveredConditions = coveredConditionsMeasure != null ? KeyValueFormat.parseIntInt(coveredConditionsMeasure.value()) : Collections.emptyMap(); - measureCache.put(inputFile.key(), CONDITIONS_TO_COVER_KEY, new DefaultMeasure().forMetric(CONDITIONS_TO_COVER).withValue(conditions - .values() - .stream() - .mapToInt(Integer::intValue) - .sum())); - measureCache.put(inputFile.key(), UNCOVERED_CONDITIONS_KEY, - new DefaultMeasure().forMetric(UNCOVERED_CONDITIONS) - .withValue((int) conditions.keySet() - .stream() - .mapToInt(line -> conditions.get(line) - coveredConditions.get(line)) - .sum())); - } - } - -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java index 2843699a626..5ed8769d2f9 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/ReportPublisher.java @@ -45,6 +45,7 @@ import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.scanner.bootstrap.GlobalAnalysisMode; import org.sonar.scanner.bootstrap.ScannerWsClient; +import org.sonar.scanner.protocol.output.ScannerReportReader; import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.scan.ScanProperties; import org.sonar.scanner.scan.branch.BranchConfiguration; @@ -83,6 +84,7 @@ public class ReportPublisher implements Startable { private Path reportDir; private ScannerReportWriter writer; + private ScannerReportReader reader; public ReportPublisher(ScanProperties properties, ScannerWsClient wsClient, Server server, AnalysisContextReportPublisher contextPublisher, InputModuleHierarchy moduleHierarchy, GlobalAnalysisMode analysisMode, TempFolder temp, ReportPublisherStep[] publishers, BranchConfiguration branchConfiguration) { @@ -101,6 +103,7 @@ public class ReportPublisher implements Startable { public void start() { reportDir = moduleHierarchy.root().getWorkDir().resolve("scanner-report"); writer = new ScannerReportWriter(reportDir.toFile()); + reader = new ScannerReportReader(reportDir.toFile()); contextPublisher.init(writer); if (!analysisMode.isMediumTest()) { @@ -126,6 +129,10 @@ public class ReportPublisher implements Startable { return writer; } + public ScannerReportReader getReader() { + return reader; + } + public void execute() { String taskId = null; File report = generateReportFile(); diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java new file mode 100644 index 00000000000..9c19a887d68 --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionPublisher.java @@ -0,0 +1,90 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.scanner.report; + +import com.google.common.collect.Iterables; +import java.util.Objects; +import java.util.stream.StreamSupport; +import org.sonar.api.batch.fs.InputComponent; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputComponent; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.test.MutableTestPlan; +import org.sonar.api.test.TestCase; +import org.sonar.api.test.TestCase.Status; +import org.sonar.scanner.deprecated.test.TestPlanBuilder; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.scanner.protocol.output.ScannerReportWriter; +import org.sonar.scanner.scan.filesystem.InputComponentStore; + +import static org.sonar.api.measures.CoreMetrics.SKIPPED_TESTS; +import static org.sonar.api.measures.CoreMetrics.TESTS; +import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS; +import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME; +import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES; +import static org.sonar.scanner.sensor.DefaultSensorStorage.toReportMeasure; + +public class TestExecutionPublisher implements ReportPublisherStep { + + private final InputComponentStore componentStore; + private final TestPlanBuilder testPlanBuilder; + + public TestExecutionPublisher(InputComponentStore componentStore, TestPlanBuilder testPlanBuilder) { + this.componentStore = componentStore; + this.testPlanBuilder = testPlanBuilder; + } + + @Override + public void publish(ScannerReportWriter writer) { + final ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder(); + + for (final InputComponent c : componentStore.all()) { + DefaultInputComponent component = (DefaultInputComponent) c; + if (component.isFile()) { + DefaultInputFile file = (DefaultInputFile) component; + // Recompute test execution measures from MutableTestPlan to take into account the possible merge of several reports + updateTestExecutionFromTestPlan(file, writer); + } + } + } + + private void updateTestExecutionFromTestPlan(final InputFile inputFile, ScannerReportWriter writer) { + final MutableTestPlan testPlan = testPlanBuilder.getTestPlanByFile(inputFile); + if (testPlan == null || Iterables.isEmpty(testPlan.testCases())) { + return; + } + long nonSkippedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() != Status.SKIPPED).count(); + appendMeasure(inputFile, writer, new DefaultMeasure().forMetric(TESTS).withValue((int) nonSkippedTests)); + long executionTime = StreamSupport.stream(testPlan.testCases().spliterator(), false).map(TestCase::durationInMs).filter(Objects::nonNull).mapToLong(Long::longValue).sum(); + appendMeasure(inputFile, writer, new DefaultMeasure().forMetric(TEST_EXECUTION_TIME).withValue(executionTime)); + long errorTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.ERROR).count(); + appendMeasure(inputFile, writer, new DefaultMeasure().forMetric(TEST_ERRORS).withValue((int) errorTests)); + long skippedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.SKIPPED).count(); + appendMeasure(inputFile, writer, new DefaultMeasure().forMetric(SKIPPED_TESTS).withValue((int) skippedTests)); + long failedTests = StreamSupport.stream(testPlan.testCases().spliterator(), false).filter(t -> t.status() == Status.FAILURE).count(); + appendMeasure(inputFile, writer, new DefaultMeasure().forMetric(TEST_FAILURES).withValue((int) failedTests)); + } + + private void appendMeasure(InputFile inputFile, ScannerReportWriter writer, DefaultMeasure measure) { + writer.appendComponentMeasure(((DefaultInputComponent) inputFile).scannerId(), toReportMeasure(measure)); + } + +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java index b18e5db8fae..dc242a2b4bd 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java @@ -69,11 +69,10 @@ import org.sonar.scanner.report.AnalysisWarningsPublisher; import org.sonar.scanner.report.ChangedLinesPublisher; import org.sonar.scanner.report.ComponentsPublisher; import org.sonar.scanner.report.ContextPropertiesPublisher; -import org.sonar.scanner.report.CoveragePublisher; -import org.sonar.scanner.report.MeasuresPublisher; import org.sonar.scanner.report.MetadataPublisher; import org.sonar.scanner.report.ReportPublisher; import org.sonar.scanner.report.SourcePublisher; +import org.sonar.scanner.report.TestExecutionPublisher; import org.sonar.scanner.repository.ContextPropertiesCache; import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader; import org.sonar.scanner.repository.DefaultQualityProfileLoader; @@ -107,7 +106,6 @@ import org.sonar.scanner.scan.filesystem.ProjectFileIndexer; import org.sonar.scanner.scan.filesystem.ScannerComponentIdGenerator; import org.sonar.scanner.scan.filesystem.StatusDetection; import org.sonar.scanner.scan.measure.DefaultMetricFinder; -import org.sonar.scanner.scan.measure.MeasureCache; import org.sonar.scanner.scm.ScmChangedFilesProvider; import org.sonar.scanner.scm.ScmConfiguration; import org.sonar.scanner.scm.ScmPublisher; @@ -116,7 +114,6 @@ import org.sonar.scanner.sensor.ProjectSensorContext; import org.sonar.scanner.sensor.ProjectSensorExtensionDictionnary; import org.sonar.scanner.sensor.ProjectSensorOptimizer; import org.sonar.scanner.sensor.ProjectSensorsExecutor; -import org.sonar.scanner.storage.Storages; import static org.sonar.api.batch.InstantiationStrategy.PER_BATCH; import static org.sonar.core.extension.CoreExtensionsInstaller.noExtensionFilter; @@ -155,7 +152,6 @@ public class ProjectScanContainer extends ComponentContainer { ProjectReactorValidator.class, MetricProvider.class, ProjectInfo.class, - Storages.class, new RulesProvider(), new BranchConfigurationProvider(), new ProjectBranchesProvider(), @@ -205,9 +201,6 @@ public class ProjectScanContainer extends ComponentContainer { Languages.class, DefaultLanguagesRepository.class, - // Measures - MeasureCache.class, - // issue exclusions IssueInclusionPatternInitializer.class, IssueExclusionPatternInitializer.class, @@ -237,8 +230,7 @@ public class ProjectScanContainer extends ComponentContainer { ActiveRulesPublisher.class, AnalysisWarningsPublisher.class, ComponentsPublisher.class, - MeasuresPublisher.class, - CoveragePublisher.class, + TestExecutionPublisher.class, SourcePublisher.class, ChangedLinesPublisher.class, diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureCache.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureCache.java deleted file mode 100644 index 68b30bf84f9..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureCache.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.scan.measure; - -import com.google.common.base.Preconditions; -import javax.annotation.CheckForNull; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.scanner.storage.Storage; -import org.sonar.scanner.storage.Storage.Entry; -import org.sonar.scanner.storage.Storages; - -/** - * Cache of all measures. This cache is shared amongst all project modules. - */ -public class MeasureCache { - - private final Storage> cache; - - public MeasureCache(Storages caches, MetricFinder metricFinder) { - caches.registerValueCoder(DefaultMeasure.class, new MeasureValueCoder(metricFinder)); - cache = caches.createCache("measures"); - } - - public Iterable>> entries() { - return cache.entries(); - } - - public Iterable> all() { - return cache.values(); - } - - public Iterable> byComponentKey(String effectiveKey) { - return cache.values(effectiveKey); - } - - @CheckForNull - public DefaultMeasure byMetric(String componentKey, String metricKey) { - return cache.get(componentKey, metricKey); - } - - public MeasureCache put(String componentKey, String metricKey, DefaultMeasure measure) { - Preconditions.checkNotNull(componentKey); - Preconditions.checkNotNull(metricKey); - cache.put(componentKey, metricKey, measure); - return this; - } - - public boolean contains(String componentKey, String metricKey) { - Preconditions.checkNotNull(componentKey); - Preconditions.checkNotNull(metricKey); - return cache.containsKey(componentKey, metricKey); - } - -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureValueCoder.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureValueCoder.java deleted file mode 100644 index c7d87a1d2e0..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureValueCoder.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.scan.measure; - -import com.persistit.Value; -import com.persistit.encoding.CoderContext; -import com.persistit.encoding.ValueCoder; -import java.io.Serializable; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; - -class MeasureValueCoder implements ValueCoder { - - private final MetricFinder metricFinder; - - public MeasureValueCoder(MetricFinder metricFinder) { - this.metricFinder = metricFinder; - } - - @Override - public void put(Value value, Object object, CoderContext context) { - DefaultMeasure m = (DefaultMeasure) object; - org.sonar.api.batch.measure.Metric metric = m.metric(); - value.putString(metric.key()); - value.put(m.value()); - } - - @Override - public Object get(Value value, Class clazz, CoderContext context) { - String metricKey = value.getString(); - org.sonar.api.batch.measure.Metric metric = metricFinder.findByKey(metricKey); - if (metric == null) { - throw new IllegalStateException("Unknow metric with key " + metricKey); - } - return new DefaultMeasure() - .forMetric(metric) - .withValue((Serializable) value.get()); - } -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java index ab27aa0b0fa..42965a37d98 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/sensor/DefaultSensorStorage.java @@ -19,21 +19,20 @@ */ package org.sonar.scanner.sensor; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; +import java.io.Serializable; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; +import java.util.SortedMap; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.Nullable; import org.sonar.api.batch.fs.InputComponent; import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.fs.internal.DefaultInputComponent; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DefaultInputModule; import org.sonar.api.batch.measure.Metric; @@ -51,10 +50,12 @@ import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.Configuration; +import org.sonar.api.measures.CoreMetrics; import org.sonar.api.utils.KeyValueFormat; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.metric.ScannerMetrics; +import org.sonar.core.util.CloseableIterator; import org.sonar.duplications.block.Block; import org.sonar.duplications.internal.pmd.PmdBlockChunker; import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; @@ -67,52 +68,15 @@ import org.sonar.scanner.report.ReportPublisher; import org.sonar.scanner.report.ScannerReportUtils; import org.sonar.scanner.repository.ContextPropertiesCache; import org.sonar.scanner.scan.branch.BranchConfiguration; -import org.sonar.scanner.scan.measure.MeasureCache; +import static java.lang.Math.max; import static java.util.Arrays.asList; import static java.util.Collections.unmodifiableSet; import static java.util.stream.Collectors.toList; -import static org.sonar.api.measures.CoreMetrics.BRANCH_COVERAGE; import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_DATA_KEY; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.CONDITIONS_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.COVERAGE; -import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA; -import static org.sonar.api.measures.CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY; -import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE; -import static org.sonar.api.measures.CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_BRANCH_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_CONDITIONS_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_COVERAGE_LINE_HITS_DATA_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_LINES_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_LINE_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_CONDITIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.IT_UNCOVERED_LINES_KEY; import static org.sonar.api.measures.CoreMetrics.LINES_KEY; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER; -import static org.sonar.api.measures.CoreMetrics.LINES_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.LINE_COVERAGE; -import static org.sonar.api.measures.CoreMetrics.OVERALL_BRANCH_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_CONDITIONS_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_LINES_TO_COVER_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_LINE_COVERAGE_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_CONDITIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.OVERALL_UNCOVERED_LINES_KEY; import static org.sonar.api.measures.CoreMetrics.PUBLIC_DOCUMENTED_API_DENSITY_KEY; import static org.sonar.api.measures.CoreMetrics.TEST_SUCCESS_DENSITY_KEY; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_CONDITIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES; -import static org.sonar.api.measures.CoreMetrics.UNCOVERED_LINES_KEY; public class DefaultSensorStorage implements SensorStorage { @@ -140,51 +104,9 @@ public class DefaultSensorStorage implements SensorStorage { TEST_SUCCESS_DENSITY_KEY, PUBLIC_DOCUMENTED_API_DENSITY_KEY))); - private static final Set COVERAGE_METRIC_KEYS = unmodifiableSet(new HashSet<>(asList( - UNCOVERED_LINES_KEY, - LINES_TO_COVER_KEY, - UNCOVERED_CONDITIONS_KEY, - CONDITIONS_TO_COVER_KEY, - CONDITIONS_BY_LINE_KEY, - COVERED_CONDITIONS_BY_LINE_KEY, - COVERAGE_LINE_HITS_DATA_KEY))); - - private static final Set COVERAGE_BY_LINE_METRIC_KEYS = unmodifiableSet(new HashSet<>(asList( - COVERAGE_LINE_HITS_DATA_KEY, - COVERED_CONDITIONS_BY_LINE_KEY, - CONDITIONS_BY_LINE_KEY))); - - private static final Map DEPRECATED_COVERAGE_METRICS_MAPPING; - - static { - Map map = new HashMap<>(); - map.put(IT_COVERAGE_KEY, COVERAGE); - map.put(IT_LINE_COVERAGE_KEY, LINE_COVERAGE); - map.put(IT_BRANCH_COVERAGE_KEY, BRANCH_COVERAGE); - map.put(IT_UNCOVERED_LINES_KEY, UNCOVERED_LINES); - map.put(IT_LINES_TO_COVER_KEY, LINES_TO_COVER); - map.put(IT_UNCOVERED_CONDITIONS_KEY, UNCOVERED_CONDITIONS); - map.put(IT_CONDITIONS_TO_COVER_KEY, CONDITIONS_TO_COVER); - map.put(IT_CONDITIONS_BY_LINE_KEY, CONDITIONS_BY_LINE); - map.put(IT_COVERED_CONDITIONS_BY_LINE_KEY, COVERED_CONDITIONS_BY_LINE); - map.put(IT_COVERAGE_LINE_HITS_DATA_KEY, COVERAGE_LINE_HITS_DATA); - map.put(OVERALL_COVERAGE_KEY, COVERAGE); - map.put(OVERALL_LINE_COVERAGE_KEY, LINE_COVERAGE); - map.put(OVERALL_BRANCH_COVERAGE_KEY, BRANCH_COVERAGE); - map.put(OVERALL_UNCOVERED_LINES_KEY, UNCOVERED_LINES); - map.put(OVERALL_LINES_TO_COVER_KEY, LINES_TO_COVER); - map.put(OVERALL_UNCOVERED_CONDITIONS_KEY, UNCOVERED_CONDITIONS); - map.put(OVERALL_CONDITIONS_TO_COVER_KEY, CONDITIONS_TO_COVER); - map.put(OVERALL_CONDITIONS_BY_LINE_KEY, CONDITIONS_BY_LINE); - map.put(OVERALL_COVERED_CONDITIONS_BY_LINE_KEY, COVERED_CONDITIONS_BY_LINE); - map.put(OVERALL_COVERAGE_LINE_HITS_DATA_KEY, COVERAGE_LINE_HITS_DATA); - DEPRECATED_COVERAGE_METRICS_MAPPING = Collections.unmodifiableMap(map); - } - private final MetricFinder metricFinder; private final IssuePublisher moduleIssues; private final ReportPublisher reportPublisher; - private final MeasureCache measureCache; private final SonarCpdBlockIndex index; private final ContextPropertiesCache contextPropertiesCache; private final Configuration settings; @@ -193,13 +115,12 @@ public class DefaultSensorStorage implements SensorStorage { private final Set alreadyLogged = new HashSet<>(); public DefaultSensorStorage(MetricFinder metricFinder, IssuePublisher moduleIssues, Configuration settings, - ReportPublisher reportPublisher, MeasureCache measureCache, SonarCpdBlockIndex index, - ContextPropertiesCache contextPropertiesCache, ScannerMetrics scannerMetrics, BranchConfiguration branchConfiguration) { + ReportPublisher reportPublisher, SonarCpdBlockIndex index, + ContextPropertiesCache contextPropertiesCache, ScannerMetrics scannerMetrics, BranchConfiguration branchConfiguration) { this.metricFinder = metricFinder; this.moduleIssues = moduleIssues; this.settings = settings; this.reportPublisher = reportPublisher; - this.measureCache = measureCache; this.index = index; this.contextPropertiesCache = contextPropertiesCache; this.scannerMetrics = scannerMetrics; @@ -243,107 +164,48 @@ public class DefaultSensorStorage implements SensorStorage { return; } - DefaultMeasure measureToSave; - if (DEPRECATED_COVERAGE_METRICS_MAPPING.containsKey(metric.key())) { - metric = DEPRECATED_COVERAGE_METRICS_MAPPING.get(metric.key()); - measureToSave = new DefaultMeasure<>() - .forMetric(metric) - .on(measure.inputComponent()) - .withValue(measure.value()); - } else { - measureToSave = measure; - } - if (!scannerMetrics.getMetrics().contains(metric)) { throw new UnsupportedOperationException("Metric '" + metric.key() + "' should not be computed by a Sensor"); } - if (COVERAGE_METRIC_KEYS.contains(metric.key())) { - logOnce(metric.key(), "Coverage measure for metric '{}' should not be saved directly by a Sensor. Plugin should be updated to use SensorContext::newCoverage instead.", - metric.key()); - if (!component.isFile()) { - throw new UnsupportedOperationException("Saving coverage measure is only allowed on files. Attempt to save '" + metric.key() + "' on '" + component.key() + "'"); - } - if (((DefaultInputFile) component).isExcludedForCoverage()) { - return; - } - saveCoverageMetricInternal((InputFile) component, metric, measureToSave); - } else { - if (measureCache.contains(component.key(), metric.key())) { - throw new UnsupportedOperationException("Can not add the same measure twice on " + component + ": " + measure); - } - measureCache.put(component.key(), metric.key(), measureToSave); + if (((DefaultInputComponent) component).hasMeasureFor(metric)) { + throw new UnsupportedOperationException("Can not add the same measure twice on " + component + ": " + measure); } - } - - private void saveCoverageMetricInternal(InputFile file, Metric metric, DefaultMeasure measure) { - if (COVERAGE_BY_LINE_METRIC_KEYS.contains(metric.key())) { - validateCoverageMeasure((String) measure.value(), file); - DefaultMeasure previousMeasure = measureCache.byMetric(file.key(), metric.key()); - if (previousMeasure != null) { - measureCache.put(file.key(), metric.key(), new DefaultMeasure() - .forMetric((Metric) metric) - .withValue(mergeCoverageLineMetric(metric, (String) previousMeasure.value(), (String) measure.value()))); + ((DefaultInputComponent) component).setHasMeasureFor(metric); + if (metric.key().equals(CoreMetrics.EXECUTABLE_LINES_DATA_KEY)) { + if (component.isFile()) { + ((DefaultInputFile) component).setExecutableLines( + KeyValueFormat.parseIntInt((String) measure.value()).entrySet().stream().filter(e -> e.getValue() > 0).map(Map.Entry::getKey).collect(Collectors.toSet())); } else { - measureCache.put(file.key(), metric.key(), measure); + throw new IllegalArgumentException("Executable lines can only be saved on files"); } } else { - // Other coverage metrics are all integer values. Just erase value, it will be recomputed at the end anyway - measureCache.put(file.key(), metric.key(), measure); + reportPublisher.getWriter().appendComponentMeasure(((DefaultInputComponent) component).scannerId(), toReportMeasure(measure)); } } - /** - * Merge the two line coverage data measures. For lines hits use the sum, and for conditions - * keep max value in case they both contains a value for the same line. - */ - static String mergeCoverageLineMetric(Metric metric, String value1, String value2) { - Map data1 = KeyValueFormat.parseIntInt(value1); - Map data2 = KeyValueFormat.parseIntInt(value2); - if (metric.key().equals(COVERAGE_LINE_HITS_DATA_KEY)) { - return KeyValueFormat.format(Stream.of(data1, data2) - .map(Map::entrySet) - .flatMap(Collection::stream) - .collect( - Collectors.toMap( - Map.Entry::getKey, - Map.Entry::getValue, - Integer::sum, - TreeMap::new))); - } else { - return KeyValueFormat.format(Stream.of(data1, data2) - .map(Map::entrySet) - .flatMap(Collection::stream) - .collect( - Collectors.toMap( - Map.Entry::getKey, - Map.Entry::getValue, - Integer::max, - TreeMap::new))); - } - } - - static void validateCoverageMeasure(String value, InputFile inputFile) { - Map m = KeyValueFormat.parseIntInt(value); - validatePositiveLine(m, inputFile.toString()); - validateMaxLine(m, inputFile); - } - - private static void validateMaxLine(Map m, InputFile inputFile) { - int maxLine = inputFile.lines(); - - for (int line : m.keySet()) { - if (line > maxLine) { - throw new IllegalStateException(String.format("Can't create measure for line %d for file '%s' with %d lines", line, inputFile, maxLine)); - } - } + public static ScannerReport.Measure toReportMeasure(DefaultMeasure measureToSave) { + ScannerReport.Measure.Builder builder = ScannerReport.Measure.newBuilder(); + builder.setMetricKey(measureToSave.metric().key()); + setValueAccordingToType(builder, measureToSave); + return builder.build(); } - private static void validatePositiveLine(Map m, String filePath) { - for (int l : m.keySet()) { - if (l <= 0) { - throw new IllegalStateException(String.format("Measure with line %d for file '%s' must be > 0", l, filePath)); - } + private static void setValueAccordingToType(ScannerReport.Measure.Builder builder, DefaultMeasure measure) { + Serializable value = measure.value(); + Metric metric = measure.metric(); + if (Boolean.class.equals(metric.valueType())) { + builder.setBooleanValue(ScannerReport.Measure.BoolValue.newBuilder().setValue((Boolean) value)); + } else if (Integer.class.equals(metric.valueType())) { + builder.setIntValue(ScannerReport.Measure.IntValue.newBuilder().setValue(((Number) value).intValue())); + } else if (Double.class.equals(metric.valueType())) { + builder.setDoubleValue(ScannerReport.Measure.DoubleValue.newBuilder().setValue(((Number) value).doubleValue())); + } else if (String.class.equals(metric.valueType())) { + builder.setStringValue(ScannerReport.Measure.StringValue.newBuilder().setValue((String) value)); + } else if (Long.class.equals(metric.valueType())) { + builder.setLongValue(ScannerReport.Measure.LongValue.newBuilder().setValue(((Number) value).longValue())); + } else { + throw new UnsupportedOperationException("Unsupported type :" + metric.valueType()); } } @@ -462,22 +324,51 @@ public class DefaultSensorStorage implements SensorStorage { public void store(DefaultCoverage defaultCoverage) { DefaultInputFile inputFile = (DefaultInputFile) defaultCoverage.inputFile(); inputFile.setPublished(true); - if (defaultCoverage.linesToCover() > 0) { - saveCoverageMetricInternal(inputFile, LINES_TO_COVER, new DefaultMeasure().forMetric(LINES_TO_COVER).withValue(defaultCoverage.linesToCover())); - saveCoverageMetricInternal(inputFile, UNCOVERED_LINES, - new DefaultMeasure().forMetric(UNCOVERED_LINES).withValue(defaultCoverage.linesToCover() - defaultCoverage.coveredLines())); - saveCoverageMetricInternal(inputFile, COVERAGE_LINE_HITS_DATA, - new DefaultMeasure().forMetric(COVERAGE_LINE_HITS_DATA).withValue(KeyValueFormat.format(defaultCoverage.hitsByLine()))); + + Map coveragePerLine = reloadExistingCoverage(inputFile); + + int lineCount = inputFile.lines(); + mergeLineCoverageValues(lineCount, defaultCoverage.hitsByLine(), coveragePerLine, (value, builder) -> builder.setHits(builder.getHits() || value > 0)); + mergeLineCoverageValues(lineCount, defaultCoverage.conditionsByLine(), coveragePerLine, (value, builder) -> builder.setConditions(max(value, builder.getConditions()))); + mergeLineCoverageValues(lineCount, defaultCoverage.coveredConditionsByLine(), coveragePerLine, + (value, builder) -> builder.setCoveredConditions(max(value, builder.getCoveredConditions()))); + + reportPublisher.getWriter().writeComponentCoverage(inputFile.scannerId(), + coveragePerLine.values().stream().map(ScannerReport.LineCoverage.Builder::build).collect(Collectors.toList())); + + } + + private Map reloadExistingCoverage(DefaultInputFile inputFile) { + Map coveragePerLine = new LinkedHashMap<>(); + try (CloseableIterator lineCoverageCloseableIterator = reportPublisher.getReader().readComponentCoverage(inputFile.scannerId())) { + while (lineCoverageCloseableIterator.hasNext()) { + final ScannerReport.LineCoverage lineCoverage = lineCoverageCloseableIterator.next(); + coveragePerLine.put(lineCoverage.getLine(), ScannerReport.LineCoverage.newBuilder(lineCoverage)); + } + } + return coveragePerLine; + } + + interface LineCoverageOperation { + void apply(Integer value, ScannerReport.LineCoverage.Builder builder); + } + + private void mergeLineCoverageValues(int lineCount, SortedMap valueByLine, Map coveragePerLine, + LineCoverageOperation op) { + for (Map.Entry lineMeasure : valueByLine.entrySet()) { + int lineIdx = lineMeasure.getKey(); + if (lineIdx <= lineCount) { + Integer value = lineMeasure.getValue(); + op.apply(value, coveragePerLine.computeIfAbsent(lineIdx, line -> ScannerReport.LineCoverage.newBuilder().setLine(line))); + } } - if (defaultCoverage.conditions() > 0) { - saveCoverageMetricInternal(inputFile, CONDITIONS_TO_COVER, - new DefaultMeasure().forMetric(CONDITIONS_TO_COVER).withValue(defaultCoverage.conditions())); - saveCoverageMetricInternal(inputFile, UNCOVERED_CONDITIONS, - new DefaultMeasure().forMetric(UNCOVERED_CONDITIONS).withValue(defaultCoverage.conditions() - defaultCoverage.coveredConditions())); - saveCoverageMetricInternal(inputFile, COVERED_CONDITIONS_BY_LINE, - new DefaultMeasure().forMetric(COVERED_CONDITIONS_BY_LINE).withValue(KeyValueFormat.format(defaultCoverage.coveredConditionsByLine()))); - saveCoverageMetricInternal(inputFile, CONDITIONS_BY_LINE, - new DefaultMeasure().forMetric(CONDITIONS_BY_LINE).withValue(KeyValueFormat.format(defaultCoverage.conditionsByLine()))); + } + + private static void validatePositiveLine(Map m, String filePath) { + for (int l : m.keySet()) { + if (l <= 0) { + throw new IllegalStateException(String.format("Measure with line %d for file '%s' must be > 0", l, filePath)); + } } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java index ffec3a709ef..f549ec6216c 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/source/ZeroCoverageSensor.java @@ -19,41 +19,30 @@ */ package org.sonar.scanner.source; -import com.google.common.collect.Sets; -import java.util.Map; import java.util.Set; -import java.util.stream.StreamSupport; import org.sonar.api.batch.Phase; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.measure.Metric; -import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.coverage.CoverageType; import org.sonar.api.batch.sensor.coverage.NewCoverage; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.utils.KeyValueFormat; -import org.sonar.scanner.scan.measure.MeasureCache; - -import static org.sonar.core.util.stream.MoreCollectors.toSet; +import org.sonar.api.scanner.sensor.ProjectSensor; +import org.sonar.scanner.report.ReportPublisher; @Phase(name = Phase.Name.POST) -public final class ZeroCoverageSensor implements Sensor { +public final class ZeroCoverageSensor implements ProjectSensor { - private final MeasureCache measureCache; + private final ReportPublisher reportPublisher; - public ZeroCoverageSensor(MeasureCache measureCache) { - this.measureCache = measureCache; + public ZeroCoverageSensor(ReportPublisher reportPublisher) { + this.reportPublisher = reportPublisher; } @Override public void describe(SensorDescriptor descriptor) { - descriptor.name("Zero Coverage Sensor") - .global(); + descriptor.name("Zero Coverage Sensor"); } @Override @@ -63,32 +52,26 @@ public final class ZeroCoverageSensor implements Sensor { if (((DefaultInputFile) f).isExcludedForCoverage()) { continue; } - if (!isCoverageMeasuresAlreadyDefined(f)) { - DefaultMeasure execLines = (DefaultMeasure) measureCache.byMetric(f.key(), CoreMetrics.EXECUTABLE_LINES_DATA_KEY); - if (execLines != null) { + if (!isCoverageAlreadyDefined(f)) { + ((DefaultInputFile) f).getExecutableLines().ifPresent(execLines -> { storeZeroCoverageForEachExecutableLine(context, f, execLines); - } + }); } } } - private static void storeZeroCoverageForEachExecutableLine(final SensorContext context, InputFile f, DefaultMeasure execLines) { + private static void storeZeroCoverageForEachExecutableLine(final SensorContext context, InputFile f, Set executableLines) { NewCoverage newCoverage = context.newCoverage().onFile(f); - Map lineMeasures = KeyValueFormat.parseIntInt((String) execLines.value()); - for (Map.Entry lineMeasure : lineMeasures.entrySet()) { - int lineIdx = lineMeasure.getKey(); - if (lineIdx <= f.lines() && lineMeasure.getValue() > 0) { + for (Integer lineIdx : executableLines) { + if (lineIdx <= f.lines()) { newCoverage.lineHits(lineIdx, 0); } } newCoverage.save(); } - private boolean isCoverageMeasuresAlreadyDefined(InputFile f) { - Set metricKeys = StreamSupport.stream(measureCache.byComponentKey(f.key()).spliterator(), false) - .map(m -> m.metric().key()).collect(toSet()); - Set allCoverageMetricKeys = CoverageType.UNIT.allMetrics().stream().map(Metric::key).collect(toSet()); - return !Sets.intersection(metricKeys, allCoverageMetricKeys).isEmpty(); + private boolean isCoverageAlreadyDefined(InputFile f) { + return reportPublisher.getReader().hasCoverage(((DefaultInputFile) f).scannerId()); } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java deleted file mode 100644 index c7b64639b44..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java +++ /dev/null @@ -1,500 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import com.persistit.Exchange; -import com.persistit.Key; -import com.persistit.KeyFilter; -import com.persistit.exception.PersistitException; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.NoSuchElementException; -import java.util.Set; -import javax.annotation.CheckForNull; -import org.apache.commons.lang.builder.ToStringBuilder; - -/** - *

- * This storage is not thread-safe, due to direct usage of {@link com.persistit.Exchange} - *

- */ -public class Storage { - - private final String name; - private final Exchange exchange; - - Storage(String name, Exchange exchange) { - this.name = name; - this.exchange = exchange; - } - - public Storage put(Object key, V value) { - resetKey(key); - return doPut(value); - } - - public Storage put(Object firstKey, Object secondKey, V value) { - resetKey(firstKey, secondKey); - return doPut(value); - } - - public Storage put(Object firstKey, Object secondKey, Object thirdKey, V value) { - resetKey(firstKey, secondKey, thirdKey); - return doPut(value); - } - - public Storage put(Object[] key, V value) { - resetKey(key); - return doPut(value); - } - - private Storage doPut(V value) { - try { - exchange.getValue().put(value); - exchange.store(); - return this; - } catch (Exception e) { - throw new IllegalStateException("Fail to put element in the storage '" + name + "'", e); - } - } - - /** - * Returns the value object associated with keys, or null if not found. - */ - public V get(Object key) { - resetKey(key); - return doGet(); - } - - /** - * Returns the value object associated with keys, or null if not found. - */ - @CheckForNull - public V get(Object firstKey, Object secondKey) { - resetKey(firstKey, secondKey); - return doGet(); - } - - /** - * Returns the value object associated with keys, or null if not found. - */ - @CheckForNull - public V get(Object firstKey, Object secondKey, Object thirdKey) { - resetKey(firstKey, secondKey, thirdKey); - return doGet(); - } - - /** - * Returns the value object associated with keys, or null if not found. - */ - @CheckForNull - public V get(Object[] key) { - resetKey(key); - return doGet(); - } - - @SuppressWarnings("unchecked") - @CheckForNull - private V doGet() { - try { - exchange.fetch(); - if (!exchange.getValue().isDefined()) { - return null; - } - return (V) exchange.getValue().get(); - } catch (Exception e) { - // TODO add parameters to message - throw new IllegalStateException("Fail to get element from cache " + name, e); - } - } - - public boolean containsKey(Object key) { - resetKey(key); - return doContainsKey(); - } - - public boolean containsKey(Object firstKey, Object secondKey) { - resetKey(firstKey, secondKey); - return doContainsKey(); - } - - public boolean containsKey(Object firstKey, Object secondKey, Object thirdKey) { - resetKey(firstKey, secondKey, thirdKey); - return doContainsKey(); - } - - public boolean containsKey(Object[] key) { - resetKey(key); - return doContainsKey(); - } - - private boolean doContainsKey() { - try { - exchange.fetch(); - return exchange.isValueDefined(); - } catch (Exception e) { - // TODO add parameters to message - throw new IllegalStateException("Fail to check if element is in cache " + name, e); - } - } - - public boolean remove(Object key) { - resetKey(key); - return doRemove(); - } - - public boolean remove(Object firstKey, Object secondKey) { - resetKey(firstKey, secondKey); - return doRemove(); - } - - public boolean remove(Object firstKey, Object secondKey, Object thirdKey) { - resetKey(firstKey, secondKey, thirdKey); - return doRemove(); - } - - public boolean remove(Object[] key) { - resetKey(key); - return doRemove(); - } - - private boolean doRemove() { - try { - return exchange.remove(); - } catch (Exception e) { - // TODO add parameters to message - throw new IllegalStateException("Fail to get element from cache " + name, e); - } - } - - /** - * Removes everything in the specified group. - */ - public Storage clear(Object key) { - resetKey(key); - return doClear(); - } - - public Storage clear(Object firstKey, Object secondKey) { - resetKey(firstKey, secondKey); - return doClear(); - } - - public Storage clear(Object firstKey, Object secondKey, Object thirdKey) { - resetKey(firstKey, secondKey, thirdKey); - return doClear(); - } - - public Storage clear(Object[] key) { - resetKey(key); - return doClear(); - } - - private Storage doClear() { - try { - Key to = new Key(exchange.getKey()); - to.append(Key.AFTER); - exchange.removeKeyRange(exchange.getKey(), to); - return this; - } catch (Exception e) { - throw new IllegalStateException("Fail to clear values from cache " + name, e); - } - } - - /** - * Clears the default as well as all group caches. - */ - public void clear() { - try { - exchange.clear(); - exchange.removeAll(); - } catch (Exception e) { - throw new IllegalStateException("Fail to clear cache", e); - } - } - - /** - * Returns the set of cache keys associated with this group. - * TODO implement a lazy-loading equivalent with Iterator/Iterable - * - * @return The set of cache keys for this group. - */ - @SuppressWarnings("rawtypes") - public Set keySet(Object key) { - try { - Set keys = new LinkedHashSet<>(); - exchange.clear(); - Exchange iteratorExchange = new Exchange(exchange); - iteratorExchange.append(key); - iteratorExchange.append(Key.BEFORE); - while (iteratorExchange.next(false)) { - keys.add(iteratorExchange.getKey().indexTo(-1).decode()); - } - return keys; - } catch (Exception e) { - throw new IllegalStateException("Fail to get keys from cache " + name, e); - } - } - - @SuppressWarnings("rawtypes") - public Set keySet(Object firstKey, Object secondKey) { - try { - Set keys = new LinkedHashSet<>(); - exchange.clear(); - Exchange iteratorExchange = new Exchange(exchange); - iteratorExchange.append(firstKey); - iteratorExchange.append(secondKey); - iteratorExchange.append(Key.BEFORE); - while (iteratorExchange.next(false)) { - keys.add(iteratorExchange.getKey().indexTo(-1).decode()); - } - return keys; - } catch (Exception e) { - throw new IllegalStateException("Fail to get keys from cache " + name, e); - } - } - - /** - * Returns the set of keys associated with this cache. - * - * @return The set containing the keys for this cache. - */ - public Set keySet() { - try { - Set keys = new LinkedHashSet<>(); - exchange.clear(); - Exchange iteratorExchange = new Exchange(exchange); - iteratorExchange.append(Key.BEFORE); - while (iteratorExchange.next(false)) { - keys.add(iteratorExchange.getKey().indexTo(-1).decode()); - } - return keys; - } catch (Exception e) { - throw new IllegalStateException("Fail to get keys from cache " + name, e); - } - } - - /** - * Lazy-loading values for given keys - */ - public Iterable values(Object firstKey, Object secondKey) { - return new ValueIterable<>(exchange, firstKey, secondKey); - } - - /** - * Lazy-loading values for a given key - */ - public Iterable values(Object firstKey) { - return new ValueIterable<>(exchange, firstKey); - } - - /** - * Lazy-loading values - */ - public Iterable values() { - return new ValueIterable<>(exchange); - } - - public Iterable> entries() { - return new EntryIterable<>(exchange); - } - - public Iterable> entries(Object firstKey) { - return new EntryIterable<>(exchange, firstKey); - } - - private void resetKey(Object key) { - exchange.clear(); - exchange.append(key); - } - - private void resetKey(Object first, Object second) { - exchange.clear(); - exchange.append(first).append(second); - } - - private void resetKey(Object first, Object second, Object third) { - exchange.clear(); - exchange.append(first).append(second).append(third); - } - - private void resetKey(Object[] keys) { - exchange.clear(); - for (Object o : keys) { - exchange.append(o); - } - } - - // - // LAZY ITERATORS AND ITERABLES - // - - private static class ValueIterable implements Iterable { - private final Exchange originExchange; - private final Object[] keys; - - private ValueIterable(Exchange originExchange, Object... keys) { - this.originExchange = originExchange; - this.keys = keys; - } - - @Override - public Iterator iterator() { - originExchange.clear(); - KeyFilter filter = new KeyFilter(); - for (Object key : keys) { - originExchange.append(key); - filter = filter.append(KeyFilter.simpleTerm(key)); - } - originExchange.append(Key.BEFORE); - Exchange iteratorExchange = new Exchange(originExchange); - return new ValueIterator<>(iteratorExchange, filter); - } - } - - private static class ValueIterator implements Iterator { - private final Exchange exchange; - private final KeyFilter keyFilter; - - private ValueIterator(Exchange exchange, KeyFilter keyFilter) { - this.exchange = exchange; - this.keyFilter = keyFilter; - } - - @Override - public boolean hasNext() { - try { - return exchange.hasNext(keyFilter); - } catch (PersistitException e) { - throw new IllegalStateException(e); - } - } - - @SuppressWarnings("unchecked") - @Override - public T next() { - try { - exchange.next(keyFilter); - } catch (PersistitException e) { - throw new IllegalStateException(e); - } - if (exchange.getValue().isDefined()) { - return (T) exchange.getValue().get(); - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("Removing an item is not supported"); - } - } - - private static class EntryIterable implements Iterable> { - private final Exchange originExchange; - private final Object[] keys; - - private EntryIterable(Exchange originExchange, Object... keys) { - this.originExchange = originExchange; - this.keys = keys; - } - - @Override - public Iterator> iterator() { - originExchange.clear(); - KeyFilter filter = new KeyFilter(); - for (Object key : keys) { - originExchange.append(key); - filter = filter.append(KeyFilter.simpleTerm(key)); - } - originExchange.append(Key.BEFORE); - Exchange iteratorExchange = new Exchange(originExchange); - return new EntryIterator<>(iteratorExchange, filter); - } - } - - private static class EntryIterator implements Iterator> { - private final Exchange exchange; - private final KeyFilter keyFilter; - - private EntryIterator(Exchange exchange, KeyFilter keyFilter) { - this.exchange = exchange; - this.keyFilter = keyFilter; - } - - @Override - public boolean hasNext() { - try { - return exchange.hasNext(keyFilter); - } catch (PersistitException e) { - throw new IllegalStateException(e); - } - } - - @SuppressWarnings("unchecked") - @Override - public Entry next() { - try { - exchange.next(keyFilter); - } catch (PersistitException e) { - throw new IllegalStateException(e); - } - if (exchange.getValue().isDefined()) { - T value = (T) exchange.getValue().get(); - Key key = exchange.getKey(); - Object[] array = new Object[key.getDepth()]; - for (int i = 0; i < key.getDepth(); i++) { - array[i] = key.indexTo(i - key.getDepth()).decode(); - } - return new Entry<>(array, value); - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("Removing an item is not supported"); - } - } - - public static class Entry { - private final Object[] key; - private final V value; - - Entry(Object[] key, V value) { - this.key = key; - this.value = value; - } - - public Object[] key() { - return key; - } - - public V value() { - return value; - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this); - } - } - -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java deleted file mode 100644 index 23827ebe5d0..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import com.google.common.base.Preconditions; -import com.persistit.Exchange; -import com.persistit.Persistit; -import com.persistit.Value; -import com.persistit.Volume; -import com.persistit.encoding.CoderManager; -import com.persistit.encoding.ValueCoder; -import com.persistit.exception.PersistitException; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import org.picocontainer.Startable; - -public class Storages implements Startable { - private final Map cacheMap = new HashMap<>(); - private Persistit persistit; - private Volume volume; - - public Storages(StoragesManager storagesManager) { - persistit = storagesManager.persistit(); - doStart(); - } - - @Override - public void start() { - // done in constructor - } - - private void doStart() { - try { - persistit.flush(); - volume = persistit.createTemporaryVolume(); - } catch (Exception e) { - throw new IllegalStateException("Fail to create a cache volume", e); - } - } - - public void registerValueCoder(Class clazz, ValueCoder coder) { - CoderManager cm = persistit.getCoderManager(); - cm.registerValueCoder(clazz, coder); - } - - public Storage createCache(String cacheName) { - Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized"); - Preconditions.checkState(!cacheMap.containsKey(cacheName), "Cache is already created: %s", cacheName); - try { - Exchange exchange = persistit.getExchange(volume, cacheName, true); - exchange.setMaximumValueSize(Value.MAXIMUM_SIZE); - Storage cache = new Storage<>(cacheName, exchange); - cacheMap.put(cacheName, exchange); - return cache; - } catch (Exception e) { - throw new IllegalStateException("Fail to create cache: " + cacheName, e); - } - } - - @Override - public void stop() { - for (Entry e : cacheMap.entrySet()) { - persistit.releaseExchange(e.getValue()); - } - - cacheMap.clear(); - - if (volume != null) { - try { - volume.close(); - volume.delete(); - } catch (PersistitException e) { - throw new IllegalStateException("Fail to close caches", e); - } - volume = null; - } - } -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java deleted file mode 100644 index 3f1b1d9dcbe..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import com.persistit.Persistit; -import com.persistit.exception.PersistitException; -import com.persistit.logging.Slf4jAdapter; -import java.io.File; -import java.util.Properties; -import org.picocontainer.Startable; -import org.slf4j.LoggerFactory; -import org.sonar.api.utils.TempFolder; - -import static org.sonar.core.util.FileUtils.deleteQuietly; - -/** - * Factory of storages - * - * @since 3.6 - */ -public class StoragesManager implements Startable { - private File tempDir; - private Persistit persistit; - private final TempFolder tempFolder; - - public StoragesManager(TempFolder tempFolder) { - this.tempFolder = tempFolder; - initPersistit(); - } - - private void initPersistit() { - try { - tempDir = tempFolder.newDir("caches"); - persistit = new Persistit(); - persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT"))); - Properties props = new Properties(); - props.setProperty("datapath", tempDir.getAbsolutePath()); - props.setProperty("logpath", "${datapath}/log"); - props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log"); - props.setProperty("buffer.count.8192", "10"); - props.setProperty("journalpath", "${datapath}/journal"); - props.setProperty("tmpvoldir", "${datapath}"); - props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000"); - props.setProperty("jmx", "false"); - persistit.setProperties(props); - persistit.initialize(); - - } catch (Exception e) { - throw new IllegalStateException("Fail to start caches", e); - } - } - - @Override - public void start() { - // already started in constructor - } - - @Override - public void stop() { - if (persistit != null) { - try { - persistit.close(false); - persistit = null; - } catch (PersistitException e) { - throw new IllegalStateException("Fail to close caches", e); - } - } - deleteQuietly(tempDir); - tempDir = null; - } - - File tempDir() { - return tempDir; - } - - Persistit persistit() { - return persistit; - } -} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java deleted file mode 100644 index 8187995b887..00000000000 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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. - */ -@ParametersAreNonnullByDefault -package org.sonar.scanner.storage; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java index 7d28d497230..6bd3a77f43c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/DefaultFileLinesContextTest.java @@ -31,13 +31,9 @@ import org.sonar.api.batch.measure.MetricFinder; import org.sonar.api.batch.sensor.internal.SensorStorage; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.measures.CoreMetrics; -import org.sonar.scanner.scan.measure.MeasureCache; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -56,7 +52,6 @@ public class DefaultFileLinesContextTest { private DefaultFileLinesContext fileLineMeasures; - private MeasureCache measureCache; private SensorStorage sensorStorage; private DefaultInputFile file; @@ -77,11 +72,9 @@ public class DefaultFileLinesContextTest { when(metricFinder.findByKey(BRANCHES_METRIC_KEY)).thenReturn(branchesMetric); when(metricFinder.findByKey(CoreMetrics.NCLOC_DATA_KEY)).thenReturn(CoreMetrics.NCLOC_DATA); when(metricFinder.findByKey(CoreMetrics.EXECUTABLE_LINES_DATA_KEY)).thenReturn(CoreMetrics.EXECUTABLE_LINES_DATA); - measureCache = mock(MeasureCache.class); sensorStorage = mock(SensorStorage.class); file = new TestInputFileBuilder("foo", "src/foo.php").initMetadata("Foo\nbar\nbiz").build(); - fileLineMeasures = new DefaultFileLinesContext(sensorStorage, file, metricFinder, - measureCache); + fileLineMeasures = new DefaultFileLinesContext(sensorStorage, file, metricFinder); } @Test @@ -158,36 +151,5 @@ public class DefaultFileLinesContextTest { fileLineMeasures.setIntValue(HITS_METRIC_KEY, 1, 2); } - @Test - public void shouldLoadIntValues() { - when(measureCache.byMetric("foo:src/foo.php", HITS_METRIC_KEY)).thenReturn(new DefaultMeasure().withValue("1=2;3=4")); - - assertThat(fileLineMeasures.getIntValue(HITS_METRIC_KEY, 1), is(2)); - assertThat(fileLineMeasures.getIntValue(HITS_METRIC_KEY, 3), is(4)); - assertThat("no measure on line", fileLineMeasures.getIntValue(HITS_METRIC_KEY, 2), nullValue()); - } - - @Test - public void shouldLoadStringValues() { - when(measureCache.byMetric("foo:src/foo.php", AUTHOR_METRIC_KEY)).thenReturn(new DefaultMeasure().withValue("1=simon;3=evgeny")); - - assertThat(fileLineMeasures.getStringValue(AUTHOR_METRIC_KEY, 1), is("simon")); - assertThat(fileLineMeasures.getStringValue(AUTHOR_METRIC_KEY, 3), is("evgeny")); - assertThat("no measure on line", fileLineMeasures.getStringValue(AUTHOR_METRIC_KEY, 2), nullValue()); - } - - @Test(expected = UnsupportedOperationException.class) - public void shouldNotModifyAfterLoad() { - when(measureCache.byMetric("foo:src/foo.php", AUTHOR_METRIC_KEY)).thenReturn(new DefaultMeasure().withValue("1=simon;3=evgeny")); - - fileLineMeasures.getStringValue(AUTHOR_METRIC_KEY, 1); - fileLineMeasures.setStringValue(AUTHOR_METRIC_KEY, 1, "evgeny"); - } - - @Test - public void shouldNotFailIfNoMeasureInIndex() { - assertThat(fileLineMeasures.getIntValue(HITS_METRIC_KEY, 1), nullValue()); - assertThat(fileLineMeasures.getStringValue(AUTHOR_METRIC_KEY, 1), nullValue()); - } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java deleted file mode 100644 index c2b1580ff15..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.index; - -import com.google.common.collect.ImmutableMap; -import java.util.Map; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.CoreProperties; -import org.sonar.scanner.bootstrap.GlobalTempFolderProvider; -import org.sonar.scanner.bootstrap.RawScannerProperties; -import org.sonar.scanner.storage.Storages; -import org.sonar.scanner.storage.StoragesManager; - -public abstract class AbstractCachesTest { - @ClassRule - public static TemporaryFolder temp = new TemporaryFolder(); - - protected static StoragesManager cachesManager; - protected Storages caches; - - private static StoragesManager createCacheOnTemp() { - Map props = ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.getRoot().getAbsolutePath(), - CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.getRoot().getAbsolutePath()); - - return new StoragesManager(new GlobalTempFolderProvider().provide(new RawScannerProperties(props))); - } - - @BeforeClass - public static void startClass() { - cachesManager = createCacheOnTemp(); - cachesManager.start(); - } - - @Before - public void start() { - caches = new Storages(cachesManager); - caches.start(); - } - - @After - public void stop() { - if (caches != null) { - caches.stop(); - caches = null; - } - } - - @AfterClass - public static void stopClass() { - if (cachesManager != null) { - cachesManager.stop(); - } - } -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java index 7c52194f8de..f376d56999e 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/branch/BranchMediumTest.java @@ -25,13 +25,15 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.FileMetadata; -import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.protocol.output.ScannerReport; import org.sonar.scanner.repository.FileData; import org.sonar.scanner.scan.branch.BranchType; @@ -63,6 +65,9 @@ public class BranchMediumTest { Path filepath = baseDir.toPath().resolve(FILE_PATH); Files.write(filepath, FILE_CONTENT.getBytes()); + Path xooUtCoverageFile = baseDir.toPath().resolve(FILE_PATH + ".coverage"); + FileUtils.write(xooUtCoverageFile.toFile(), "1:2:2:1", StandardCharsets.UTF_8); + String md5sum = new FileMetadata() .readMetadata(Files.newInputStream(filepath), StandardCharsets.UTF_8, FILE_PATH) .hash(); @@ -73,15 +78,18 @@ public class BranchMediumTest { public void should_not_skip_report_for_unchanged_files_in_short_branch() { // sanity check, normally report gets generated AnalysisResult result = getResult(tester); - assertThat(getResult(tester).getReportComponent(result.inputFile(FILE_PATH))).isNotNull(); - int fileId = 2; + final DefaultInputFile file = (DefaultInputFile) result.inputFile(FILE_PATH); + assertThat(getResult(tester).getReportComponent(file)).isNotNull(); + int fileId = file.scannerId(); assertThat(result.getReportReader().readChangesets(fileId)).isNotNull(); assertThat(result.getReportReader().hasCoverage(fileId)).isTrue(); assertThat(result.getReportReader().readFileSource(fileId)).isNotNull(); // file is not skipped for short branches (need coverage, duplications coming soon) AnalysisResult result2 = getResult(tester.setBranchType(BranchType.SHORT)); - assertThat(result2.getReportComponent(result2.inputFile(FILE_PATH))).isNotNull(); + final DefaultInputFile fileOnShortBranch = (DefaultInputFile) result2.inputFile(FILE_PATH); + assertThat(result2.getReportComponent(fileOnShortBranch)).isNotNull(); + fileId = fileOnShortBranch.scannerId(); assertThat(result2.getReportReader().readChangesets(fileId)).isNull(); assertThat(result2.getReportReader().hasCoverage(fileId)).isTrue(); assertThat(result2.getReportReader().readFileSource(fileId)).isNull(); @@ -108,10 +116,8 @@ public class BranchMediumTest { return tester .newAnalysis() .properties(ImmutableMap.builder() - .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) .put("sonar.projectKey", PROJECT_KEY) - .put("sonar.sources", ".") .put("sonar.scm.provider", "xoo") .build()) .execute(); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java index 0b6744565de..c51d03d3785 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/CoverageMediumTest.java @@ -23,22 +23,18 @@ import com.google.common.collect.ImmutableMap; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.measures.CoreMetrics; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; -import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.xoo.XooPlugin; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; public class CoverageMediumTest { @@ -77,13 +73,6 @@ public class CoverageMediumTest { assertThat(result.coverageFor(file, 2).getHits()).isTrue(); assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2); assertThat(result.coverageFor(file, 2).getCoveredConditions()).isEqualTo(1); - - Map> allMeasures = result.allMeasures(); - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value") - .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0), - tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2), - tuple(CoreMetrics.UNCOVERED_CONDITIONS_KEY, 1)); } @Test @@ -98,7 +87,7 @@ public class CoverageMediumTest { File xooUtCoverageFile = new File(srcDir, "sample.xoo.coverage"); FileUtils.write(xooUtCoverageFile, "2:2:2:2\n4:0", StandardCharsets.UTF_8); File xooItCoverageFile = new File(srcDir, "sample.xoo.itcoverage"); - FileUtils.write(xooItCoverageFile, "2:2:2:1\n3:1\n5:0", StandardCharsets.UTF_8); + FileUtils.write(xooItCoverageFile, "2:0:2:1\n3:1\n5:0", StandardCharsets.UTF_8); AnalysisResult result = tester.newAnalysis() .properties(ImmutableMap.builder() @@ -113,16 +102,6 @@ public class CoverageMediumTest { assertThat(result.coverageFor(file, 2).getConditions()).isEqualTo(2); assertThat(result.coverageFor(file, 2).getCoveredConditions()).isEqualTo(2); assertThat(result.coverageFor(file, 3).getHits()).isTrue(); - - Map> allMeasures = result.allMeasures(); - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value", "stringValue.value") - .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 4, ""), // 2, 3, 4, 5 - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 2, ""), // 4, 5 - tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2, ""), // 2 x 2 - tuple(CoreMetrics.UNCOVERED_CONDITIONS_KEY, 0, ""), - tuple(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, 0, "2=4;3=1;4=0;5=0"), - tuple(CoreMetrics.CONDITIONS_BY_LINE_KEY, 0, "2=2"), - tuple(CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, 0, "2=2")); } @Test @@ -148,11 +127,6 @@ public class CoverageMediumTest { InputFile file = result.inputFile("src/sample.xoo"); assertThat(result.coverageFor(file, 2)).isNull(); - - Map> allMeasures = result.allMeasures(); - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey") - .doesNotContain(CoreMetrics.LINES_TO_COVER_KEY, CoreMetrics.UNCOVERED_LINES_KEY, CoreMetrics.CONDITIONS_TO_COVER_KEY, - CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY); } @Test @@ -306,13 +280,6 @@ public class CoverageMediumTest { assertThat(result.coverageFor(file, 3).getHits()).isFalse(); assertThat(result.coverageFor(file, 4)).isNull(); - - Map> allMeasures = result.allMeasures(); - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value") - .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 2)); - - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey").doesNotContain(CoreMetrics.CONDITIONS_TO_COVER_KEY, CoreMetrics.UNCOVERED_CONDITIONS_KEY); } // SONAR-9557 @@ -359,18 +326,6 @@ public class CoverageMediumTest { assertThat(result.coverageFor(file2, 3)).isNull(); assertThat(result.coverageFor(file2, 4)).isNull(); - Map> allMeasures = result.allMeasures(); - - assertThat(allMeasures.get("com.foo.project:module1/src/sample1.xoo")).extracting("metricKey", "intValue.value") - .contains(tuple(CoreMetrics.LINES_TO_COVER_KEY, 2), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 2)); - - assertThat(allMeasures.get("com.foo.project:module1/src/sample1.xoo")).extracting("metricKey").doesNotContain(CoreMetrics.CONDITIONS_TO_COVER_KEY, - CoreMetrics.UNCOVERED_CONDITIONS_KEY); - - assertThat(allMeasures.get("com.foo.project:module1/src/sample2.xoo")).extracting("metricKey").doesNotContain(CoreMetrics.LINES_TO_COVER_KEY, - CoreMetrics.CONDITIONS_TO_COVER_KEY, - CoreMetrics.UNCOVERED_CONDITIONS_KEY, CoreMetrics.UNCOVERED_LINES_KEY); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/GenericCoverageMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/GenericCoverageMediumTest.java index e41b31e8d60..1fc4d93676c 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/GenericCoverageMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/coverage/GenericCoverageMediumTest.java @@ -26,13 +26,11 @@ import java.util.List; import org.junit.Rule; import org.junit.Test; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.scanner.mediumtest.AnalysisResult; +import org.sonar.scanner.mediumtest.ScannerMediumTester; import org.sonar.xoo.XooPlugin; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; public class GenericCoverageMediumTest { private final List logs = new ArrayList<>(); @@ -60,27 +58,11 @@ public class GenericCoverageMediumTest { assertThat(result.coverageFor(noConditions, 7).getHits()).isFalse(); - assertThat(result.allMeasures().get(noConditions.key())).extracting("metricKey", "intValue.value", "stringValue.value") - .containsOnly( - tuple(CoreMetrics.LINES_TO_COVER_KEY, 2, ""), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 1, ""), - tuple(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, 0, "6=1;7=0")); - InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo"); assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue(); assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2); assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isEqualTo(1); - assertThat(result.allMeasures().get(withConditions.key())).extracting("metricKey", "intValue.value", "stringValue.value") - .containsOnly( - tuple(CoreMetrics.LINES_TO_COVER_KEY, 1, ""), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0, ""), - tuple(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, 0, "3=1"), - tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2, ""), - tuple(CoreMetrics.UNCOVERED_CONDITIONS_KEY, 1, ""), - tuple(CoreMetrics.CONDITIONS_BY_LINE_KEY, 0, "3=2"), - tuple(CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, 0, "3=1") - ); assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'")); } @@ -117,28 +99,11 @@ public class GenericCoverageMediumTest { assertThat(result.coverageFor(noConditions, 7).getHits()).isTrue(); - assertThat(result.allMeasures().get(noConditions.key())).extracting("metricKey", "intValue.value", "stringValue.value") - .containsOnly( - tuple(CoreMetrics.LINES_TO_COVER_KEY, 2, ""), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0, ""), - tuple(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, 0, "6=1;7=1")); - InputFile withConditions = result.inputFile("xources/hello/WithConditions.xoo"); assertThat(result.coverageFor(withConditions, 3).getHits()).isTrue(); assertThat(result.coverageFor(withConditions, 3).getConditions()).isEqualTo(2); assertThat(result.coverageFor(withConditions, 3).getCoveredConditions()).isEqualTo(2); - assertThat(result.allMeasures().get(withConditions.key())).extracting("metricKey", "intValue.value", "stringValue.value") - .containsOnly( - tuple(CoreMetrics.LINES_TO_COVER_KEY, 1, ""), - tuple(CoreMetrics.UNCOVERED_LINES_KEY, 0, ""), - tuple(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, 0, "3=2"), - tuple(CoreMetrics.CONDITIONS_TO_COVER_KEY, 2, ""), - tuple(CoreMetrics.UNCOVERED_CONDITIONS_KEY, 0, ""), - tuple(CoreMetrics.CONDITIONS_BY_LINE_KEY, 0, "3=2"), - tuple(CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, 0, "3=2") - ); - assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.coverageReportPaths'")); } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/measures/MeasuresMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/measures/MeasuresMediumTest.java index 395dff17b10..34e57146bfe 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/measures/MeasuresMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/measures/MeasuresMediumTest.java @@ -64,66 +64,6 @@ public class MeasuresMediumTest { srcDir.mkdir(); } - @Test - public void applyExclusionsOnCoverageMeasures() throws IOException { - File xooFile = new File(srcDir, "sample.xoo"); - FileUtils.write(xooFile, "Sample xoo\n\ncontent", StandardCharsets.UTF_8); - - File measures = new File(srcDir, "sample.xoo.measures"); - FileUtils.write(measures, "lines_to_cover:2", StandardCharsets.UTF_8); - - AnalysisResult result = tester.newAnalysis() - .properties(ImmutableMap.builder() - .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) - .put("sonar.projectKey", "com.foo.project") - .put("sonar.sources", "src") - .build()) - .execute(); - - Map> allMeasures = result.allMeasures(); - - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value") - .containsOnly(tuple("lines_to_cover", 2)); - - result = tester.newAnalysis() - .properties(ImmutableMap.builder() - .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) - .put("sonar.projectKey", "com.foo.project") - .put("sonar.sources", "src") - .put("sonar.coverage.exclusions", "src/sample.xoo") - .build()) - .execute(); - - allMeasures = result.allMeasures(); - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value") - .isEmpty(); - } - - @Test - public void deprecatedCoverageMeasuresAreConverted() throws IOException { - File xooFile = new File(srcDir, "sample.xoo"); - FileUtils.write(xooFile, "Sample xoo\n\ncontent", StandardCharsets.UTF_8); - - File measures = new File(srcDir, "sample.xoo.measures"); - FileUtils.write(measures, "it_lines_to_cover:2", StandardCharsets.UTF_8); - - AnalysisResult result = tester.newAnalysis() - .properties(ImmutableMap.builder() - .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) - .put("sonar.projectKey", "com.foo.project") - .put("sonar.sources", "src") - .build()) - .execute(); - - Map> allMeasures = result.allMeasures(); - - assertThat(allMeasures.get("com.foo.project:src/sample.xoo")).extracting("metricKey", "intValue.value") - .containsOnly(tuple("lines_to_cover", 2)); - - assertThat(logTester.logs(LoggerLevel.WARN)) - .contains("Coverage measure for metric 'lines_to_cover' should not be saved directly by a Sensor. Plugin should be updated to use SensorContext::newCoverage instead."); - } - @Test public void failIfTryingToSaveServerSideMeasure() throws IOException { File xooFile = new File(srcDir, "sample.xoo"); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java index 42d7f836bf5..62ea71126ae 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/scm/ScmMediumTest.java @@ -80,12 +80,8 @@ public class ScmMediumTest { tester.newAnalysis() .properties(ImmutableMap.builder() - .put("sonar.task", "scan") .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) .put("sonar.projectKey", "com.foo.project") - .put("sonar.projectName", "Foo Project") - .put("sonar.projectVersion", "1.0-SNAPSHOT") - .put("sonar.projectDescription", "Description of Foo Project") .put("sonar.sources", "src") .put("sonar.scm.provider", "xoo") .build()) diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java deleted file mode 100644 index f1c75d6a3e3..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/CoveragePublisherTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.report; - -import java.io.File; -import java.io.IOException; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.fs.internal.DefaultInputProject; -import org.sonar.api.batch.fs.internal.TestInputFileBuilder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.core.util.CloseableIterator; -import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage; -import org.sonar.scanner.protocol.output.ScannerReportReader; -import org.sonar.scanner.protocol.output.ScannerReportWriter; -import org.sonar.scanner.scan.branch.BranchConfiguration; -import org.sonar.scanner.scan.filesystem.InputComponentStore; -import org.sonar.scanner.scan.measure.MeasureCache; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class CoveragePublisherTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - private MeasureCache measureCache; - private CoveragePublisher publisher; - - private DefaultInputFile inputFile; - - @Before - public void prepare() throws IOException { - String moduleKey = "foo"; - inputFile = new TestInputFileBuilder(moduleKey, "src/Foo.php").setLines(5).build(); - DefaultInputProject rootModule = TestInputFileBuilder.newDefaultInputProject(moduleKey, temp.newFolder()); - InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class)); - componentCache.put(moduleKey, inputFile); - - measureCache = mock(MeasureCache.class); - when(measureCache.byMetric(anyString(), anyString())).thenReturn(null); - publisher = new CoveragePublisher(componentCache, measureCache); - } - - @Test - public void publishCoverage() throws Exception { - - DefaultMeasure utLineHits = new DefaultMeasure().forMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA).withValue("2=1;3=1;5=0;6=3"); - when(measureCache.byMetric("foo:src/Foo.php", CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY)).thenReturn((DefaultMeasure) utLineHits); - - DefaultMeasure conditionsByLine = new DefaultMeasure().forMetric(CoreMetrics.CONDITIONS_BY_LINE).withValue("3=4"); - when(measureCache.byMetric("foo:src/Foo.php", CoreMetrics.CONDITIONS_BY_LINE_KEY)).thenReturn((DefaultMeasure) conditionsByLine); - - DefaultMeasure coveredConditionsByUts = new DefaultMeasure().forMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE).withValue("3=2"); - when(measureCache.byMetric("foo:src/Foo.php", CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY)).thenReturn((DefaultMeasure) coveredConditionsByUts); - - File outputDir = temp.newFolder(); - ScannerReportWriter writer = new ScannerReportWriter(outputDir); - - publisher.publish(writer); - - try (CloseableIterator it = new ScannerReportReader(outputDir).readComponentCoverage(inputFile.scannerId())) { - assertThat(it.next()).isEqualTo(LineCoverage.newBuilder() - .setLine(2) - .setHits(true) - .build()); - assertThat(it.next()).isEqualTo(LineCoverage.newBuilder() - .setLine(3) - .setHits(true) - .setConditions(4) - .setCoveredConditions(2) - .build()); - assertThat(it.next()).isEqualTo(LineCoverage.newBuilder() - .setLine(5) - .setHits(false) - .build()); - } - - } -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java deleted file mode 100644 index 6af538c600b..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/report/MeasuresPublisherTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.report; - -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import org.apache.commons.lang.exception.ExceptionUtils; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.fs.internal.DefaultInputProject; -import org.sonar.api.batch.fs.internal.TestInputFileBuilder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.core.util.CloseableIterator; -import org.sonar.scanner.deprecated.test.TestPlanBuilder; -import org.sonar.scanner.protocol.output.ScannerReport; -import org.sonar.scanner.protocol.output.ScannerReportReader; -import org.sonar.scanner.protocol.output.ScannerReportWriter; -import org.sonar.scanner.scan.branch.BranchConfiguration; -import org.sonar.scanner.scan.filesystem.InputComponentStore; -import org.sonar.scanner.scan.measure.MeasureCache; - -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MeasuresPublisherTest { - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - private MeasureCache measureCache; - private MeasuresPublisher publisher; - - private File outputDir; - private ScannerReportWriter writer; - private DefaultInputFile inputFile; - private DefaultInputProject project; - - @Before - public void prepare() throws IOException { - String projectKey = "foo"; - project = TestInputFileBuilder.newDefaultInputProject(projectKey, temp.newFolder()); - inputFile = new TestInputFileBuilder(projectKey, "src/Foo.php").setPublish(true).build(); - InputComponentStore componentCache = new InputComponentStore(mock(BranchConfiguration.class)); - componentCache.put(projectKey, inputFile); - measureCache = mock(MeasureCache.class); - when(measureCache.byComponentKey(anyString())).thenReturn(Collections.>emptyList()); - publisher = new MeasuresPublisher(componentCache, measureCache, mock(TestPlanBuilder.class)); - outputDir = temp.newFolder(); - writer = new ScannerReportWriter(outputDir); - } - - @Test - public void publishMeasures() throws Exception { - DefaultMeasure measure = new DefaultMeasure().forMetric(CoreMetrics.LINES_TO_COVER) - .withValue(2); - // String value - DefaultMeasure stringMeasure = new DefaultMeasure().forMetric(CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION) - .withValue("foo bar"); - when(measureCache.byComponentKey(inputFile.key())).thenReturn(asList(measure, stringMeasure)); - - publisher.publish(writer); - ScannerReportReader reader = new ScannerReportReader(outputDir); - - assertThat(reader.readComponentMeasures(project.scannerId())).hasSize(0); - try (CloseableIterator componentMeasures = reader.readComponentMeasures(inputFile.scannerId())) { - assertThat(componentMeasures).hasSize(2); - } - } - - @Test - public void fail_with_IAE_when_measure_has_no_value() throws Exception { - DefaultMeasure measure = new DefaultMeasure().forMetric(CoreMetrics.LINES_TO_COVER); - when(measureCache.byComponentKey(inputFile.key())).thenReturn(Collections.singletonList(measure)); - - try { - publisher.publish(writer); - fail(); - } catch (RuntimeException e) { - assertThat(ExceptionUtils.getFullStackTrace(e)).contains("Measure on metric 'lines_to_cover' and component 'foo:src/Foo.php' has no value, but it's not allowed"); - } - } - -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/measure/MeasureCacheTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/measure/MeasureCacheTest.java deleted file mode 100644 index f3e08e99d2e..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/measure/MeasureCacheTest.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.scan.measure; - -import java.util.Iterator; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.scanner.index.AbstractCachesTest; -import org.sonar.scanner.storage.Storage.Entry; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MeasureCacheTest extends AbstractCachesTest { - - private static final String COMPONENT_KEY = "struts"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private MetricFinder metricFinder; - - private MeasureCache measureCache; - - @Before - public void start() { - super.start(); - metricFinder = mock(MetricFinder.class); - when(metricFinder.findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC); - when(metricFinder.findByKey(CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY)).thenReturn(CoreMetrics.COVERAGE_LINE_HITS_DATA); - measureCache = new MeasureCache(caches, metricFinder); - } - - @Test - public void should_add_measure() { - assertThat(measureCache.entries()).hasSize(0); - assertThat(measureCache.byComponentKey(COMPONENT_KEY)).hasSize(0); - - DefaultMeasure m = new DefaultMeasure().forMetric(CoreMetrics.NCLOC).withValue(1.0); - measureCache.put(COMPONENT_KEY, CoreMetrics.NCLOC_KEY, m); - - assertThat(measureCache.contains(COMPONENT_KEY, CoreMetrics.NCLOC_KEY)).isTrue(); - assertThat(measureCache.entries()).hasSize(1); - Iterator>> iterator = measureCache.entries().iterator(); - iterator.hasNext(); - Entry> next = iterator.next(); - assertThat(next.value()).isEqualTo(m); - assertThat(next.key()[0]).isEqualTo(COMPONENT_KEY); - - assertThat(measureCache.byComponentKey(COMPONENT_KEY)).hasSize(1); - assertThat(measureCache.byComponentKey(COMPONENT_KEY).iterator().next()).isEqualTo(m); - } - - /** - * This test fails with stock PersisitIt. - */ - @Test - public void should_add_measure_with_too_big_data_for_persistit_pre_patch() { - assertThat(measureCache.entries()).hasSize(0); - assertThat(measureCache.byComponentKey(COMPONENT_KEY)).hasSize(0); - - StringBuilder data = new StringBuilder(4_500_000); - for (int i = 0; i < 4_500_000; i++) { - data.append('a'); - } - DefaultMeasure m = new DefaultMeasure().forMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA).withValue(data.toString()); - measureCache.put(COMPONENT_KEY, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, m); - - assertThat(measureCache.contains(COMPONENT_KEY, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY)).isTrue(); - assertThat(measureCache.entries()).hasSize(1); - Iterator>> iterator = measureCache.entries().iterator(); - iterator.hasNext(); - Entry> next = iterator.next(); - assertThat(next.value()).isEqualTo(m); - assertThat(next.key()[0]).isEqualTo(COMPONENT_KEY); - - assertThat(measureCache.byComponentKey(COMPONENT_KEY)).hasSize(1); - assertThat(measureCache.byComponentKey(COMPONENT_KEY).iterator().next()).isEqualTo(m); - - } - - @Test - public void should_add_measure_with_too_big_data_for_persistit() { - assertThat(measureCache.entries()).hasSize(0); - assertThat(measureCache.byComponentKey(COMPONENT_KEY)).hasSize(0); - - // Limit is 64Mo - StringBuilder data = new StringBuilder(64 * 1024 * 1024 + 1); - for (int i = 0; i < 64 * 1024 * 1024 + 1; i++) { - data.append('a'); - } - DefaultMeasure m = new DefaultMeasure().forMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA).withValue(data.toString()); - - thrown.expect(IllegalStateException.class); - thrown.expectMessage("Fail to put element in the storage 'measures'"); - - measureCache.put(COMPONENT_KEY, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, m); - } - - @Test - public void should_get_measures() { - String projectKey = "struts"; - String dirKey = "struts:foo/bar"; - String file1Key = "struts:foo/bar/File1.txt"; - String file2Key = "struts:foo/bar/File2.txt"; - - assertThat(measureCache.entries()).hasSize(0); - - assertThat(measureCache.byComponentKey(projectKey)).hasSize(0); - assertThat(measureCache.byComponentKey(dirKey)).hasSize(0); - - DefaultMeasure mFile1 = new DefaultMeasure().forMetric(CoreMetrics.NCLOC).withValue(1.0); - measureCache.put(file1Key, CoreMetrics.NCLOC_DATA_KEY, mFile1); - DefaultMeasure mFile2 = new DefaultMeasure().forMetric(CoreMetrics.NCLOC).withValue(3.0); - measureCache.put(file2Key, CoreMetrics.NCLOC_DATA_KEY, mFile2); - - assertThat(measureCache.entries()).hasSize(2); - assertThat(measureCache.byComponentKey(projectKey)).hasSize(0); - assertThat(measureCache.byComponentKey(dirKey)).hasSize(0); - - DefaultMeasure mDir = new DefaultMeasure().forMetric(CoreMetrics.NCLOC).withValue(4.0); - measureCache.put(dirKey, CoreMetrics.NCLOC_DATA_KEY, mDir); - - assertThat(measureCache.entries()).hasSize(3); - assertThat(measureCache.byComponentKey(projectKey)).hasSize(0); - assertThat(measureCache.byComponentKey(dirKey)).hasSize(1); - assertThat(measureCache.byComponentKey(dirKey).iterator().next()).isEqualTo(mDir); - - DefaultMeasure mProj = new DefaultMeasure().forMetric(CoreMetrics.NCLOC).withValue(4.0); - measureCache.put(projectKey, CoreMetrics.NCLOC_DATA_KEY, mProj); - - assertThat(measureCache.entries()).hasSize(4); - assertThat(measureCache.byComponentKey(projectKey)).hasSize(1); - assertThat(measureCache.byComponentKey(projectKey).iterator().next()).isEqualTo(mProj); - assertThat(measureCache.byComponentKey(dirKey)).hasSize(1); - assertThat(measureCache.byComponentKey(dirKey).iterator().next()).isEqualTo(mDir); - } - -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java index 96aef89bfc0..264e666429f 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/sensor/DefaultSensorStorageTest.java @@ -19,9 +19,8 @@ */ package org.sonar.scanner.sensor; -import com.google.common.collect.ImmutableMap; +import java.io.File; import java.io.IOException; -import java.util.Map; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -48,20 +47,19 @@ import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.utils.KeyValueFormat; import org.sonar.core.metric.ScannerMetrics; import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; import org.sonar.scanner.issue.IssuePublisher; import org.sonar.scanner.protocol.output.FileStructure; +import org.sonar.scanner.protocol.output.ScannerReport; +import org.sonar.scanner.protocol.output.ScannerReportReader; import org.sonar.scanner.protocol.output.ScannerReportWriter; import org.sonar.scanner.report.ReportPublisher; import org.sonar.scanner.repository.ContextPropertiesCache; import org.sonar.scanner.scan.branch.BranchConfiguration; -import org.sonar.scanner.scan.measure.MeasureCache; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.MapEntry.entry; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -79,11 +77,12 @@ public class DefaultSensorStorageTest { private DefaultSensorStorage underTest; private MapSettings settings; private IssuePublisher moduleIssues; - private MeasureCache measureCache; private ScannerReportWriter reportWriter; private ContextPropertiesCache contextPropertiesCache = new ContextPropertiesCache(); private BranchConfiguration branchConfiguration; private DefaultInputProject project; + private ScannerReportReader reportReader; + private ReportPublisher reportPublisher; @Before public void prepare() throws Exception { @@ -94,17 +93,18 @@ public class DefaultSensorStorageTest { settings = new MapSettings(); moduleIssues = mock(IssuePublisher.class); - measureCache = mock(MeasureCache.class); - ReportPublisher reportPublisher = mock(ReportPublisher.class); - reportWriter = new ScannerReportWriter(temp.newFolder()); + reportPublisher = mock(ReportPublisher.class); + final File reportDir = temp.newFolder(); + reportWriter = new ScannerReportWriter(reportDir); + reportReader = new ScannerReportReader(reportDir); when(reportPublisher.getWriter()).thenReturn(reportWriter); + when(reportPublisher.getReader()).thenReturn(reportReader); branchConfiguration = mock(BranchConfiguration.class); underTest = new DefaultSensorStorage(metricFinder, - moduleIssues, settings.asConfig(), reportPublisher, measureCache, - mock(SonarCpdBlockIndex.class), contextPropertiesCache, new ScannerMetrics(), branchConfiguration); + moduleIssues, settings.asConfig(), reportPublisher, mock(SonarCpdBlockIndex.class), contextPropertiesCache, new ScannerMetrics(), branchConfiguration); project = new DefaultInputProject(ProjectDefinition.create() .setKey("foo") @@ -132,7 +132,7 @@ public class DefaultSensorStorageTest { .forMetric(CoreMetrics.LINES) .withValue(10)); - verifyNoMoreInteractions(measureCache); + verifyNoMoreInteractions(reportPublisher); } @Test @@ -145,7 +145,7 @@ public class DefaultSensorStorageTest { .forMetric(CoreMetrics.LINES) .withValue(10)); - verifyNoMoreInteractions(measureCache); + verifyNoMoreInteractions(reportPublisher); } @Test @@ -209,35 +209,32 @@ public class DefaultSensorStorageTest { @Test public void should_save_file_measure() { - InputFile file = new TestInputFileBuilder("foo", "src/Foo.php").build(); + DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.php") + .build(); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DefaultMeasure.class); - when(measureCache.put(eq(file.key()), eq(CoreMetrics.NCLOC_KEY), argumentCaptor.capture())).thenReturn(null); underTest.store(new DefaultMeasure() .on(file) .forMetric(CoreMetrics.NCLOC) .withValue(10)); - DefaultMeasure m = argumentCaptor.getValue(); - assertThat(m.value()).isEqualTo(10); - assertThat(m.metric()).isEqualTo(CoreMetrics.NCLOC); + ScannerReport.Measure m = reportReader.readComponentMeasures(file.scannerId()).next(); + assertThat(m.getIntValue().getValue()).isEqualTo(10); + assertThat(m.getMetricKey()).isEqualTo(CoreMetrics.NCLOC_KEY); } @Test public void should_not_skip_file_measures_on_short_lived_branch_or_pull_request_when_file_status_is_SAME() { - InputFile file = new TestInputFileBuilder("foo", "src/Foo.php").setStatus(InputFile.Status.SAME).build(); + DefaultInputFile file = new TestInputFileBuilder("foo", "src/Foo.php").setStatus(InputFile.Status.SAME).build(); when(branchConfiguration.isShortOrPullRequest()).thenReturn(true); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DefaultMeasure.class); - when(measureCache.put(eq(file.key()), eq(CoreMetrics.LINES_TO_COVER_KEY), argumentCaptor.capture())).thenReturn(null); underTest.store(new DefaultMeasure() .on(file) - .forMetric(CoreMetrics.LINES_TO_COVER) + .forMetric(CoreMetrics.NCLOC) .withValue(10)); - DefaultMeasure m = argumentCaptor.getValue(); - assertThat(m.value()).isEqualTo(10); - assertThat(m.metric()).isEqualTo(CoreMetrics.LINES_TO_COVER); + ScannerReport.Measure m = reportReader.readComponentMeasures(file.scannerId()).next(); + assertThat(m.getIntValue().getValue()).isEqualTo(10); + assertThat(m.getMetricKey()).isEqualTo(CoreMetrics.NCLOC_KEY); } @Test @@ -272,17 +269,14 @@ public class DefaultSensorStorageTest { String projectKey = "myProject"; DefaultInputModule module = new DefaultInputModule(ProjectDefinition.create().setKey(projectKey).setBaseDir(temp.newFolder()).setWorkDir(temp.newFolder())); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(DefaultMeasure.class); - when(measureCache.put(eq(module.key()), eq(CoreMetrics.NCLOC_KEY), argumentCaptor.capture())).thenReturn(null); - underTest.store(new DefaultMeasure() .on(module) .forMetric(CoreMetrics.NCLOC) .withValue(10)); - DefaultMeasure m = argumentCaptor.getValue(); - assertThat(m.value()).isEqualTo(10); - assertThat(m.metric()).isEqualTo(CoreMetrics.NCLOC); + ScannerReport.Measure m = reportReader.readComponentMeasures(module.scannerId()).next(); + assertThat(m.getIntValue().getValue()).isEqualTo(10); + assertThat(m.getMetricKey()).isEqualTo(CoreMetrics.NCLOC_KEY); } @Test(expected = UnsupportedOperationException.class) @@ -321,36 +315,4 @@ public class DefaultSensorStorageTest { assertThat(contextPropertiesCache.getAll()).containsOnly(entry("foo", "bar")); } - @Test - public void shouldValidateStrictlyPositiveLine() throws Exception { - InputFile file = new TestInputFileBuilder("module", "testfile").setModuleBaseDir(temp.newFolder().toPath()).build(); - Map map = ImmutableMap.of(0, 3); - String data = KeyValueFormat.format(map); - - thrown.expect(IllegalStateException.class); - thrown.expectMessage("must be > 0"); - underTest.validateCoverageMeasure(data, file); - } - - @Test - public void shouldValidateMaxLine() throws Exception { - InputFile file = new TestInputFileBuilder("module", "testfile").setModuleBaseDir(temp.newFolder().toPath()).build(); - Map map = ImmutableMap.of(11, 3); - String data = KeyValueFormat.format(map); - - thrown.expect(IllegalStateException.class); - underTest.validateCoverageMeasure(data, file); - } - - @Test - public void mergeCoverageLineMetrics_should_be_sorted() { - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=1", "1=1")).isEqualTo("1=2"); - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "1=1", "2=1")).isEqualTo("1=1;2=1"); - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERAGE_LINE_HITS_DATA, "2=1", "1=1")).isEqualTo("1=1;2=1"); - - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "1=1", "1=1")).isEqualTo("1=1"); - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "1=1", "2=1")).isEqualTo("1=1;2=1"); - assertThat(DefaultSensorStorage.mergeCoverageLineMetric(CoreMetrics.COVERED_CONDITIONS_BY_LINE, "2=1", "1=1")).isEqualTo("1=1;2=1"); - } - } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java deleted file mode 100644 index 45e9e1e7c5e..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import com.google.common.collect.Iterables; -import org.junit.Test; -import org.sonar.scanner.index.AbstractCachesTest; -import org.sonar.scanner.storage.Storage.Entry; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StorageTest extends AbstractCachesTest { - - @Test - public void one_part_key() { - Storage cache = caches.createCache("capitals"); - - assertThat(cache.get("france")).isNull(); - - cache.put("france", "paris"); - cache.put("italy", "rome"); - assertThat(cache.get("france")).isEqualTo("paris"); - assertThat(cache.keySet()).containsOnly("france", "italy"); - assertThat(cache.keySet("france")).isEmpty(); - Iterable values = cache.values(); - assertThat(values).containsOnly("paris", "rome"); - assertThat(values).containsOnly("paris", "rome"); - assertThat(cache.containsKey("france")).isTrue(); - - Iterable> iterable = cache.entries(); - Storage.Entry[] entries = Iterables.toArray(iterable, Storage.Entry.class); - assertThat(entries).hasSize(2); - assertThat(iterable).hasSize(2); - assertThat(entries[0].key()[0]).isEqualTo("france"); - assertThat(entries[0].value()).isEqualTo("paris"); - assertThat(entries[1].key()[0]).isEqualTo("italy"); - assertThat(entries[1].value()).isEqualTo("rome"); - - cache.remove("france"); - assertThat(cache.get("france")).isNull(); - assertThat(cache.get("italy")).isEqualTo("rome"); - assertThat(cache.keySet()).containsOnly("italy"); - assertThat(cache.keySet("france")).isEmpty(); - assertThat(cache.containsKey("france")).isFalse(); - assertThat(cache.containsKey("italy")).isTrue(); - assertThat(values).containsOnly("rome"); - - cache.clear(); - assertThat(values).isEmpty(); - } - - @Test - public void test_key_being_prefix_of_another_key() throws Exception { - Storage cache = caches.createCache("components"); - - cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTag", "the Tag"); - cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo", "the BeanInfo"); - - assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTag")).isEqualTo("the Tag"); - assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo")).isEqualTo("the BeanInfo"); - } - - @Test - public void two_parts_key() { - Storage cache = caches.createCache("capitals"); - - assertThat(cache.get("europe", "france")).isNull(); - - cache.put("europe", "france", "paris"); - cache.put("europe", "italy", "rome"); - cache.put("asia", "china", "pekin"); - assertThat(cache.get("europe")).isNull(); - assertThat(cache.get("europe", "france")).isEqualTo("paris"); - assertThat(cache.get("europe", "italy")).isEqualTo("rome"); - assertThat(cache.get("europe")).isNull(); - assertThat(cache.keySet("europe")).containsOnly("france", "italy"); - assertThat(cache.keySet()).containsOnly("europe", "asia"); - assertThat(cache.containsKey("europe")).isFalse(); - assertThat(cache.containsKey("europe", "france")).isTrue(); - assertThat(cache.containsKey("europe", "spain")).isFalse(); - assertThat(cache.values()).containsOnly("paris", "rome", "pekin"); - assertThat(cache.values("america")).isEmpty(); - assertThat(cache.values("europe")).containsOnly("paris", "rome"); - assertThat(cache.values("oceania")).isEmpty(); - - Iterable> iterable = cache.entries(); - Storage.Entry[] allEntries = Iterables.toArray(iterable, Storage.Entry.class); - assertThat(allEntries).hasSize(3); - assertThat(iterable).hasSize(3); - assertThat(allEntries[0].key()).isEqualTo(new String[] {"asia", "china"}); - assertThat(allEntries[0].value()).isEqualTo("pekin"); - assertThat(allEntries[1].key()).isEqualTo(new String[] {"europe", "france"}); - assertThat(allEntries[1].value()).isEqualTo("paris"); - assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "italy"}); - assertThat(allEntries[2].value()).isEqualTo("rome"); - - Iterable> iterable2 = cache.entries("europe"); - Storage.Entry[] subEntries = Iterables.toArray(iterable2, Storage.Entry.class); - assertThat(subEntries).hasSize(2); - assertThat(iterable2).hasSize(2); - assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france"}); - assertThat(subEntries[0].value()).isEqualTo("paris"); - assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "italy"}); - assertThat(subEntries[1].value()).isEqualTo("rome"); - - cache.remove("europe", "france"); - assertThat(cache.values()).containsOnly("rome", "pekin"); - assertThat(cache.get("europe", "france")).isNull(); - assertThat(cache.get("europe", "italy")).isEqualTo("rome"); - assertThat(cache.containsKey("europe", "france")).isFalse(); - assertThat(cache.keySet("europe")).containsOnly("italy"); - - cache.clear("america"); - assertThat(cache.keySet()).containsOnly("europe", "asia"); - cache.clear(); - assertThat(cache.keySet()).isEmpty(); - } - - @Test - public void three_parts_key() { - Storage cache = caches.createCache("places"); - assertThat(cache.get("europe", "france", "paris")).isNull(); - - cache.put("europe", "france", "paris", "eiffel tower"); - cache.put("europe", "france", "annecy", "lake"); - cache.put("europe", "france", "poitiers", "notre dame"); - cache.put("europe", "italy", "rome", "colosseum"); - cache.put("europe2", "ukrania", "kiev", "dunno"); - cache.put("asia", "china", "pekin", "great wall"); - cache.put("america", "us", "new york", "empire state building"); - assertThat(cache.get("europe")).isNull(); - assertThat(cache.get("europe", "france")).isNull(); - assertThat(cache.get("europe", "france", "paris")).isEqualTo("eiffel tower"); - assertThat(cache.get("europe", "france", "annecy")).isEqualTo("lake"); - assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum"); - assertThat(cache.keySet()).containsOnly("europe", "asia", "america", "europe2"); - assertThat(cache.keySet("europe")).containsOnly("france", "italy"); - assertThat(cache.keySet("europe", "france")).containsOnly("annecy", "paris", "poitiers"); - assertThat(cache.containsKey("europe")).isFalse(); - assertThat(cache.containsKey("europe", "france")).isFalse(); - assertThat(cache.containsKey("europe", "france", "annecy")).isTrue(); - assertThat(cache.containsKey("europe", "france", "biarritz")).isFalse(); - assertThat(cache.values()).containsOnly("eiffel tower", "lake", "colosseum", "notre dame", "great wall", "empire state building", "dunno"); - assertThat(cache.values("europe")).containsOnly("eiffel tower", "lake", "colosseum", "notre dame"); - assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "lake", "notre dame"); - - Iterable> iterable = cache.entries(); - Storage.Entry[] allEntries = Iterables.toArray(iterable, Storage.Entry.class); - assertThat(allEntries).hasSize(7); - assertThat(iterable).hasSize(7); - assertThat(allEntries[0].key()).isEqualTo(new String[] {"america", "us", "new york"}); - assertThat(allEntries[0].value()).isEqualTo("empire state building"); - assertThat(allEntries[1].key()).isEqualTo(new String[] {"asia", "china", "pekin"}); - assertThat(allEntries[1].value()).isEqualTo("great wall"); - assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "france", "annecy"}); - assertThat(allEntries[2].value()).isEqualTo("lake"); - assertThat(allEntries[3].key()).isEqualTo(new String[] {"europe", "france", "paris"}); - assertThat(allEntries[3].value()).isEqualTo("eiffel tower"); - assertThat(allEntries[4].key()).isEqualTo(new String[] {"europe", "france", "poitiers"}); - assertThat(allEntries[4].value()).isEqualTo("notre dame"); - assertThat(allEntries[5].key()).isEqualTo(new String[] {"europe", "italy", "rome"}); - assertThat(allEntries[5].value()).isEqualTo("colosseum"); - - Iterable> iterable2 = cache.entries("europe"); - Storage.Entry[] subEntries = Iterables.toArray(iterable2, Storage.Entry.class); - assertThat(subEntries).hasSize(4); - assertThat(iterable2).hasSize(4); - assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france", "annecy"}); - assertThat(subEntries[0].value()).isEqualTo("lake"); - assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "france", "paris"}); - assertThat(subEntries[1].value()).isEqualTo("eiffel tower"); - assertThat(subEntries[2].key()).isEqualTo(new String[] {"europe", "france", "poitiers"}); - assertThat(subEntries[2].value()).isEqualTo("notre dame"); - assertThat(subEntries[3].key()).isEqualTo(new String[] {"europe", "italy", "rome"}); - assertThat(subEntries[3].value()).isEqualTo("colosseum"); - - cache.remove("europe", "france", "annecy"); - assertThat(cache.values()).containsOnly("eiffel tower", "colosseum", "notre dame", "great wall", "empire state building", "dunno"); - assertThat(cache.values("europe")).containsOnly("eiffel tower", "colosseum", "notre dame"); - assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "notre dame"); - assertThat(cache.get("europe", "france", "annecy")).isNull(); - assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum"); - assertThat(cache.containsKey("europe", "france")).isFalse(); - - cache.clear("europe", "italy"); - assertThat(cache.values()).containsOnly("eiffel tower", "notre dame", "great wall", "empire state building", "dunno"); - - cache.clear("europe"); - assertThat(cache.values()).containsOnly("great wall", "empire state building", "dunno"); - - cache.clear(); - assertThat(cache.values()).isEmpty(); - } - - @Test - public void remove_versus_clear() { - Storage cache = caches.createCache("capitals"); - cache.put("europe", "france", "paris"); - cache.put("europe", "italy", "rome"); - - // remove("europe") does not remove sub-keys - cache.remove("europe"); - assertThat(cache.values()).containsOnly("paris", "rome"); - - // clear("europe") removes sub-keys - cache.clear("europe"); - assertThat(cache.values()).isEmpty(); - } - - @Test - public void empty_cache() { - Storage cache = caches.createCache("empty"); - - assertThat(cache.get("foo")).isNull(); - assertThat(cache.get("foo", "bar")).isNull(); - assertThat(cache.get("foo", "bar", "baz")).isNull(); - assertThat(cache.keySet()).isEmpty(); - assertThat(cache.keySet("foo")).isEmpty(); - assertThat(cache.containsKey("foo")).isFalse(); - assertThat(cache.containsKey("foo", "bar")).isFalse(); - assertThat(cache.containsKey("foo", "bar", "baz")).isFalse(); - assertThat(cache.values()).isEmpty(); - assertThat(cache.values("foo")).isEmpty(); - - // do not fail - cache.remove("foo"); - cache.remove("foo", "bar"); - cache.remove("foo", "bar", "baz"); - cache.clear("foo"); - cache.clear("foo", "bar"); - cache.clear("foo", "bar", "baz"); - cache.clear(); - } -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java deleted file mode 100644 index 5c43aa793d6..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import java.io.File; -import org.junit.Test; -import org.sonar.scanner.index.AbstractCachesTest; - -import static org.assertj.core.api.Assertions.assertThat; - -public class StoragesManagerTest extends AbstractCachesTest { - @Test - public void should_stop_and_clean_temp_dir() { - File tempDir = cachesManager.tempDir(); - assertThat(tempDir).isDirectory().exists(); - assertThat(cachesManager.persistit()).isNotNull(); - assertThat(cachesManager.persistit().isInitialized()).isTrue(); - - cachesManager.stop(); - - assertThat(tempDir).doesNotExist(); - assertThat(cachesManager.tempDir()).isNull(); - assertThat(cachesManager.persistit()).isNull(); - } -} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java deleted file mode 100644 index e35ec4f8b16..00000000000 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program 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. - * - * This program 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.scanner.storage; - -import com.persistit.exception.PersistitException; -import java.io.Serializable; -import org.junit.Test; -import org.sonar.scanner.index.AbstractCachesTest; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -public class StoragesTest extends AbstractCachesTest { - @Test - public void should_create_cache() { - Storage cache = caches.createCache("foo"); - assertThat(cache).isNotNull(); - } - - @Test - public void should_not_create_cache_twice() { - caches.createCache("foo"); - try { - caches.createCache("foo"); - fail(); - } catch (IllegalStateException e) { - // ok - } - } - - @Test - public void should_clean_resources() { - Storage c = caches.createCache("test1"); - for (int i = 0; i < 1_000_000; i++) { - c.put("a" + i, "a" + i); - } - - caches.stop(); - - // manager continues up - assertThat(cachesManager.persistit().isInitialized()).isTrue(); - - caches = new Storages(cachesManager); - caches.start(); - caches.createCache("test1"); - } - - @Test - public void leak_test() throws PersistitException { - caches.stop(); - - int len = 1 * 1024 * 1024; - StringBuilder sb = new StringBuilder(len); - for (int i = 0; i < len; i++) { - sb.append("a"); - } - - for (int i = 0; i < 3; i++) { - caches = new Storages(cachesManager); - caches.start(); - Storage c = caches.createCache("test" + i); - c.put("key" + i, sb.toString()); - cachesManager.persistit().flush(); - - caches.stop(); - } - } - - private static class Element implements Serializable { - private static final long serialVersionUID = 1L; - - } -} diff --git a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java index e20e37ff852..42292da429b 100644 --- a/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java +++ b/sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java @@ -112,10 +112,13 @@ public class ScannerReportWriter { } } - public File writeComponentMeasures(int componentRef, Iterable measures) { + public void appendComponentMeasure(int componentRef, ScannerReport.Measure measure) { File file = fileStructure.fileFor(FileStructure.Domain.MEASURES, componentRef); - Protobuf.writeStream(measures, file, false); - return file; + try (OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true))) { + measure.writeDelimitedTo(out); + } catch (Exception e) { + throw ContextException.of("Unable to write measure", e).addContext("file", file); + } } public File writeComponentChangesets(ScannerReport.Changesets changesets) { diff --git a/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java b/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java index 928166b5a31..b405c69cbe3 100644 --- a/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java +++ b/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java @@ -124,7 +124,7 @@ public class ScannerReportReaderTest { ScannerReportWriter writer = new ScannerReportWriter(dir); ScannerReport.Measure.Builder measure = ScannerReport.Measure.newBuilder() .setStringValue(StringValue.newBuilder().setValue("value_a")); - writer.writeComponentMeasures(1, asList(measure.build())); + writer.appendComponentMeasure(1, measure.build()); assertThat(underTest.readComponentMeasures(1)).hasSize(1); } diff --git a/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java b/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java index 3a6f84961dd..ade53f3bca5 100644 --- a/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java +++ b/sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java @@ -183,7 +183,7 @@ public class ScannerReportWriterTest { .setDoubleValue(DoubleValue.newBuilder().setValue(2.5d).setData("text-value")) .build(); - underTest.writeComponentMeasures(1, asList(measure)); + underTest.appendComponentMeasure(1, measure); assertThat(underTest.hasComponentData(FileStructure.Domain.MEASURES, 1)).isTrue(); File file = underTest.getFileStructure().fileFor(FileStructure.Domain.MEASURES, 1); -- 2.39.5