diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-08-25 19:16:57 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2015-08-29 15:58:41 +0200 |
commit | e70a46f46eef8d1d9d0c60e0f2a9802bacdd661b (patch) | |
tree | bd0be5c782089965d88e5e7852fc429fe26f7d2d /server | |
parent | a659e5a2fc406507c359bbb346c9e7bd127d23e7 (diff) | |
download | sonarqube-e70a46f46eef8d1d9d0c60e0f2a9802bacdd661b.tar.gz sonarqube-e70a46f46eef8d1d9d0c60e0f2a9802bacdd661b.zip |
add support for Views Component tree to NewCoverageVariationSumFormula
Diffstat (limited to 'server')
10 files changed, 543 insertions, 40 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java index d5039b00107..4cc72415667 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/FormulaExecutorComponentVisitor.java @@ -65,7 +65,7 @@ public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter<For private final MeasureRepository measureRepository; private final List<Formula> formulas; - private FormulaExecutorComponentVisitor(Builder builder, List<Formula> formulas) { + private FormulaExecutorComponentVisitor(Builder builder, Iterable<Formula> formulas) { super(CrawlerDepthLimit.LEAVES, ComponentVisitor.Order.POST_ORDER, COUNTERS_FACTORY); this.periodsHolder = builder.periodsHolder; this.measureRepository = builder.measureRepository; @@ -97,7 +97,7 @@ public class FormulaExecutorComponentVisitor extends PathAwareVisitorAdapter<For return this; } - public FormulaExecutorComponentVisitor buildFor(List<Formula> formulas) { + public FormulaExecutorComponentVisitor buildFor(Iterable<Formula> formulas) { return new FormulaExecutorComponentVisitor(this, formulas); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageUtils.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageUtils.java index 4646c06bd9b..58e4ce1efa3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageUtils.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageUtils.java @@ -20,11 +20,17 @@ package org.sonar.server.computation.formula.coverage; import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import java.util.List; +import javax.annotation.Nonnull; +import org.sonar.server.computation.component.Component; import org.sonar.server.computation.formula.CounterInitializationContext; +import org.sonar.server.computation.formula.CreateMeasureContext; import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureVariations; import org.sonar.server.computation.period.Period; +import static com.google.common.collect.FluentIterable.from; import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; public final class CoverageUtils { @@ -64,4 +70,36 @@ public final class CoverageUtils { } return 0L; } + + /** + * Since Periods 4 and 5 can be customized per project and/or per view/subview, aggregating values on this period + * will only generate garbage data which will make no sense. These Periods should be ignored when processing views/subviews. + */ + static Iterable<Period> supportedPeriods(CreateMeasureContext context) { + return supportedPeriods(context.getComponent().getType(), context.getPeriods()); + } + + /** + * Since Periods 4 and 5 can be customized per project and/or per view/subview, aggregating values on this period + * will only generate garbage data which will make no sense. These Periods should be ignored when processing views/subviews. + */ + public static Iterable<Period> supportedPeriods(CounterInitializationContext context) { + return supportedPeriods(context.getLeaf().getType(), context.getPeriods()); + } + + private static Iterable<Period> supportedPeriods(Component.Type type, List<Period> periods) { + if (type.isReportType()) { + return periods; + } + return from(periods).filter(ViewsSupportedPeriods.INSTANCE); + } + + private enum ViewsSupportedPeriods implements Predicate<Period> { + INSTANCE; + + @Override + public boolean apply(@Nonnull Period input) { + return input.getIndex() < 4; + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageVariationFormula.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageVariationFormula.java index e7b3ef3cf1c..47cfb845a03 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageVariationFormula.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/CoverageVariationFormula.java @@ -28,6 +28,7 @@ import org.sonar.server.computation.measure.MeasureVariations; import org.sonar.server.computation.period.Period; import static org.sonar.server.computation.formula.coverage.CoverageUtils.calculateCoverage; +import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods; import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; /** @@ -48,7 +49,7 @@ public abstract class CoverageVariationFormula<T extends ElementsAndCoveredEleme private MeasureVariations.Builder createAndPopulateBuilder(T counter, CreateMeasureContext context) { MeasureVariations.Builder builder = MeasureVariations.newMeasureVariationsBuilder(); - for (Period period : context.getPeriods()) { + for (Period period : supportedPeriods(context)) { LongVariationValue elements = counter.elements.get(period); if (elements.isSet() && elements.getValue() > 0d) { LongVariationValue coveredElements = counter.coveredElements.get(period); @@ -57,5 +58,4 @@ public abstract class CoverageVariationFormula<T extends ElementsAndCoveredEleme } return builder; } - } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/ElementsAndCoveredElementsVariationCounter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/ElementsAndCoveredElementsVariationCounter.java index f260bb6ac47..6b5eee72a5d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/ElementsAndCoveredElementsVariationCounter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/ElementsAndCoveredElementsVariationCounter.java @@ -38,7 +38,7 @@ public abstract class ElementsAndCoveredElementsVariationCounter implements Coun @Override public void initialize(CounterInitializationContext context) { - if (context.getLeaf().getFileAttributes().isUnitTest()) { + if (context.getLeaf().getType().isReportType() && context.getLeaf().getFileAttributes().isUnitTest()) { return; } initializeForSupportedLeaf(context); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/LinesAndConditionsWithUncoveredVariationCounter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/LinesAndConditionsWithUncoveredVariationCounter.java index bb28272c194..96fc9422021 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/LinesAndConditionsWithUncoveredVariationCounter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/LinesAndConditionsWithUncoveredVariationCounter.java @@ -25,6 +25,8 @@ import org.sonar.server.computation.measure.Measure; import org.sonar.server.computation.measure.MeasureVariations; import org.sonar.server.computation.period.Period; +import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods; + public final class LinesAndConditionsWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter { private final LinesAndConditionsWithUncoveredMetricKeys metricKeys; @@ -43,7 +45,7 @@ public final class LinesAndConditionsWithUncoveredVariationCounter extends Eleme MeasureVariations newConditions = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getConditions()); MeasureVariations uncoveredLines = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredLines()); MeasureVariations uncoveredConditions = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredConditions()); - for (Period period : counterContext.getPeriods()) { + for (Period period : supportedPeriods(counterContext)) { if (!newLines.hasVariation(period.getIndex())) { continue; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/NewCoverageVariationSumFormula.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/NewCoverageVariationSumFormula.java new file mode 100644 index 00000000000..6bcf790a0c8 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/NewCoverageVariationSumFormula.java @@ -0,0 +1,110 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.formula.coverage; + +import com.google.common.base.Optional; +import org.sonar.server.computation.component.CrawlerDepthLimit; +import org.sonar.server.computation.formula.Counter; +import org.sonar.server.computation.formula.CounterInitializationContext; +import org.sonar.server.computation.formula.CreateMeasureContext; +import org.sonar.server.computation.formula.Formula; +import org.sonar.server.computation.formula.counter.DoubleVariationValue; +import org.sonar.server.computation.measure.Measure; +import org.sonar.server.computation.measure.MeasureVariations; +import org.sonar.server.computation.period.Period; + +import static java.util.Objects.requireNonNull; +import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; + +/** + * A Formula which aggregates a new coverage measure by simply making the sums of its variations. + */ +public class NewCoverageVariationSumFormula implements Formula<NewCoverageVariationSumFormula.VariationSumCounter> { + private final String metricKey; + + public NewCoverageVariationSumFormula(String metricKey) { + this.metricKey = requireNonNull(metricKey, "Metric key cannot be null"); + } + + @Override + public VariationSumCounter createNewCounter() { + return new VariationSumCounter(metricKey); + } + + @Override + public Optional<Measure> createMeasure(VariationSumCounter counter, CreateMeasureContext context) { + if (!CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) { + return Optional.absent(); + } + MeasureVariations.Builder variations = createAndPopulateBuilder(counter.array, context); + if (variations.isEmpty()) { + return Optional.absent(); + } + return Optional.of(newMeasureBuilder().setVariations(variations.build()).createNoValue()); + } + + private static MeasureVariations.Builder createAndPopulateBuilder(DoubleVariationValue.Array array, CreateMeasureContext context) { + MeasureVariations.Builder builder = MeasureVariations.newMeasureVariationsBuilder(); + for (Period period : supportedPeriods(context)) { + DoubleVariationValue elements = array.get(period); + if (elements.isSet()) { + builder.setVariation(period, elements.getValue()); + } + } + return builder; + } + + @Override + public String[] getOutputMetricKeys() { + return new String[] { metricKey }; + } + + public static final class VariationSumCounter implements Counter<VariationSumCounter> { + private final DoubleVariationValue.Array array = DoubleVariationValue.newArray(); + private final String metricKey; + + private VariationSumCounter(String metricKey) { + this.metricKey = metricKey; + } + + @Override + public void aggregate(VariationSumCounter counter) { + array.incrementAll(counter.array); + } + + @Override + public void initialize(CounterInitializationContext context) { + Optional<Measure> measure = context.getMeasure(metricKey); + if (!measure.isPresent() || !measure.get().hasVariations()) { + return; + } + MeasureVariations variations = measure.get().getVariations(); + for (Period period : supportedPeriods(context)) { + if (variations.hasVariation(period.getIndex())) { + double variation = variations.getVariation(period.getIndex()); + if (variation > 0) { + array.increment(period, variations.getVariation(period.getIndex())); + } + } + } + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/SingleWithUncoveredVariationCounter.java b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/SingleWithUncoveredVariationCounter.java index 4009600977b..44c850f9ffe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/SingleWithUncoveredVariationCounter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/formula/coverage/SingleWithUncoveredVariationCounter.java @@ -26,6 +26,7 @@ import org.sonar.server.computation.period.Period; import static java.util.Objects.requireNonNull; import static org.sonar.server.computation.formula.coverage.CoverageUtils.getLongVariation; import static org.sonar.server.computation.formula.coverage.CoverageUtils.getMeasureVariations; +import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods; public final class SingleWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter { private final SingleWithUncoveredMetricKeys metricKeys; @@ -38,7 +39,7 @@ public final class SingleWithUncoveredVariationCounter extends ElementsAndCovere protected void initializeForSupportedLeaf(CounterInitializationContext counterContext) { MeasureVariations newConditions = getMeasureVariations(counterContext, metricKeys.getCovered()); MeasureVariations uncoveredConditions = getMeasureVariations(counterContext, metricKeys.getUncovered()); - for (Period period : counterContext.getPeriods()) { + for (Period period : supportedPeriods(counterContext)) { long elements = getLongVariation(newConditions, period); this.elements.increment(period, elements); coveredElements.increment(period, elements - getLongVariation(uncoveredConditions, period)); diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/NewCoverageMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/NewCoverageMeasuresStep.java index 5e2de9e9525..d503f5077d5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/NewCoverageMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/NewCoverageMeasuresStep.java @@ -21,10 +21,12 @@ package org.sonar.server.computation.step; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; +import javax.annotation.CheckForNull; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import org.apache.commons.lang.ObjectUtils; @@ -35,10 +37,11 @@ import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; import org.sonar.server.computation.component.PathAwareCrawler; import org.sonar.server.computation.component.TreeRootHolder; -import org.sonar.server.computation.formula.CreateMeasureContext; import org.sonar.server.computation.formula.CounterInitializationContext; +import org.sonar.server.computation.formula.CreateMeasureContext; import org.sonar.server.computation.formula.Formula; import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor; +import org.sonar.server.computation.formula.coverage.NewCoverageVariationSumFormula; import org.sonar.server.computation.formula.counter.IntVariationValue; import org.sonar.server.computation.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys; import org.sonar.server.computation.formula.coverage.LinesAndConditionsWithUncoveredVariationFormula; @@ -58,12 +61,32 @@ import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; * Computes measures related to the New Coverage. These measures do not have values, only variations. */ public class NewCoverageMeasuresStep implements ComputationStep { + private static final List<Formula> FORMULAS = ImmutableList.<Formula>of( + // UT coverage + new NewCoverageFormula() + , + new NewBranchCoverageFormula(), + new NewLineCoverageFormula(), + // IT File coverage + new NewItCoverageFormula(), + new NewItBranchCoverageFormula(), + new NewItLinesCoverageFormula(), + // Overall coverage + new NewOverallCodeCoverageFormula(), + new NewOverallBranchCoverageFormula(), + new NewOverallLineCoverageFormula() + ); + private final TreeRootHolder treeRootHolder; private final PeriodsHolder periodsHolder; + @CheckForNull private final BatchReportReader batchReportReader; private final MetricRepository metricRepository; private final MeasureRepository measureRepository; + /** + * Constructor used when processing a Report (ie. a {@link BatchReportReader} instance is available in the container) + */ public NewCoverageMeasuresStep(TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, BatchReportReader batchReportReader, MeasureRepository measureRepository, final MetricRepository metricRepository) { this.treeRootHolder = treeRootHolder; @@ -73,28 +96,30 @@ public class NewCoverageMeasuresStep implements ComputationStep { this.measureRepository = measureRepository; } + /** + * Constructor used when processing Views (ie. no {@link BatchReportReader} instance is available in the container) + */ + public NewCoverageMeasuresStep(TreeRootHolder treeRootHolder, PeriodsHolder periodsHolder, + MeasureRepository measureRepository, final MetricRepository metricRepository) { + this.treeRootHolder = treeRootHolder; + this.periodsHolder = periodsHolder; + this.batchReportReader = null; + this.metricRepository = metricRepository; + this.measureRepository = measureRepository; + } + @Override public void execute() { new PathAwareCrawler<>( FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) .withVariationSupport(periodsHolder) - .buildFor(ImmutableList.<Formula>of( - // UT coverage - new NewLinesAndConditionsCoverageFormula(batchReportReader), - new NewCoverageFormula(), - new NewBranchCoverageFormula(), - new NewLineCoverageFormula(), - // IT File coverage - new NewItLinesAndConditionsCoverageFormula(batchReportReader), - new NewItCoverageFormula(), - new NewItBranchCoverageFormula(), - new NewItLinesCoverageFormula(), - // Overall coverage - new NewOverallLinesAndConditionsCoverageFormula(batchReportReader), - new NewOverallCodeCoverageFormula(), - new NewOverallBranchCoverageFormula(), - new NewOverallLineCoverageFormula()))) - .visit(treeRootHolder.getRoot()); + .buildFor( + Iterables.concat( + NewLinesAndConditionsCoverageFormula.from(batchReportReader), + NewItLinesAndConditionsCoverageFormula.from(batchReportReader), + NewOverallLinesAndConditionsCoverageFormula.from(batchReportReader), + FORMULAS))) + .visit(treeRootHolder.getRoot()); } @Override @@ -103,13 +128,24 @@ public class NewCoverageMeasuresStep implements ComputationStep { } private static class NewLinesAndConditionsCoverageFormula extends NewLinesAndConditionsFormula { - public NewLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { + + 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<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS); + + private NewLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { super(batchReportReader, new NewCoverageInputMetricKeys( CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, CoreMetrics.CONDITIONS_BY_LINE_KEY, CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY), - new NewCoverageOutputMetricKeys( - CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_LINES_KEY, - CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY)); + OUTPUT_METRIC_KEYS); + } + + public static Iterable<Formula<?>> from(@Nullable BatchReportReader batchReportReader) { + if (batchReportReader == null) { + return VIEWS_FORMULAS; + } + return Collections.<Formula<?>>singleton(new NewLinesAndConditionsCoverageFormula(batchReportReader)); } } @@ -126,8 +162,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(CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY), CoreMetrics.NEW_BRANCH_COVERAGE_KEY); } } @@ -141,13 +176,24 @@ public class NewCoverageMeasuresStep implements ComputationStep { } private static class NewItLinesAndConditionsCoverageFormula extends NewLinesAndConditionsFormula { - public NewItLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { + + private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys( + CoreMetrics.NEW_IT_LINES_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_LINES_KEY, + CoreMetrics.NEW_IT_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS_KEY); + private static final Iterable<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS); + + private NewItLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { super(batchReportReader, new NewCoverageInputMetricKeys( CoreMetrics.IT_COVERAGE_LINE_HITS_DATA_KEY, CoreMetrics.IT_CONDITIONS_BY_LINE_KEY, CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE_KEY), - new NewCoverageOutputMetricKeys( - CoreMetrics.NEW_IT_LINES_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_LINES_KEY, - CoreMetrics.NEW_IT_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS_KEY)); + OUTPUT_METRIC_KEYS); + } + + public static Iterable<Formula<?>> from(@Nullable BatchReportReader batchReportReader) { + if (batchReportReader == null) { + return VIEWS_FORMULAS; + } + return Collections.<Formula<?>>singleton(new NewItLinesAndConditionsCoverageFormula(batchReportReader)); } } @@ -179,13 +225,24 @@ public class NewCoverageMeasuresStep implements ComputationStep { } private static class NewOverallLinesAndConditionsCoverageFormula extends NewLinesAndConditionsFormula { - public NewOverallLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { + + private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys( + CoreMetrics.NEW_OVERALL_LINES_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_LINES_KEY, + CoreMetrics.NEW_OVERALL_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_CONDITIONS_KEY); + private static final Iterable<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS); + + private NewOverallLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) { super(batchReportReader, new NewCoverageInputMetricKeys( CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA_KEY, CoreMetrics.OVERALL_CONDITIONS_BY_LINE_KEY, CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE_KEY), - new NewCoverageOutputMetricKeys( - CoreMetrics.NEW_OVERALL_LINES_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_LINES_KEY, - CoreMetrics.NEW_OVERALL_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_CONDITIONS_KEY)); + OUTPUT_METRIC_KEYS); + } + + public static Iterable<Formula<?>> from(@Nullable BatchReportReader batchReportReader) { + if (batchReportReader == null) { + return VIEWS_FORMULAS; + } + return Collections.<Formula<?>>singleton(new NewOverallLinesAndConditionsCoverageFormula(batchReportReader)); } } @@ -217,6 +274,18 @@ public class NewCoverageMeasuresStep implements ComputationStep { } } + /** + * Creates a List of {@link org.sonar.server.computation.formula.SumFormula.IntSumFormula} for each + * metric key of the specified {@link NewCoverageOutputMetricKeys} instance. + */ + private static Iterable<Formula<?>> intSumFormulas(NewCoverageOutputMetricKeys outputMetricKeys) { + return ImmutableList.<Formula<?>>of( + new NewCoverageVariationSumFormula(outputMetricKeys.getNewLinesToCover()), + new NewCoverageVariationSumFormula(outputMetricKeys.getNewUncoveredLines()), + new NewCoverageVariationSumFormula(outputMetricKeys.getNewConditionsToCover()), + new NewCoverageVariationSumFormula(outputMetricKeys.getNewUncoveredConditions())); + } + public static class NewLinesAndConditionsFormula implements Formula<NewCoverageCounter> { private final BatchReportReader batchReportReader; private final NewCoverageInputMetricKeys inputMetricKeys; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/NewCoverageMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportNewCoverageMeasuresStepTest.java index 3801da410ff..35c66c745ea 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/NewCoverageMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportNewCoverageMeasuresStepTest.java @@ -60,7 +60,7 @@ import static org.sonar.server.computation.measure.MeasureRepoEntry.entryOf; import static org.sonar.server.computation.measure.MeasureRepoEntry.toEntries; import static org.sonar.server.computation.measure.MeasureVariations.newMeasureVariationsBuilder; -public class NewCoverageMeasuresStepTest { +public class ReportNewCoverageMeasuresStepTest { private static final int ROOT_REF = 1; private static final int MODULE_REF = 11; diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsNewCoverageMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsNewCoverageMeasuresStepTest.java new file mode 100644 index 00000000000..80ac1823e0c --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsNewCoverageMeasuresStepTest.java @@ -0,0 +1,283 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.computation.step; + +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.server.computation.batch.TreeRootHolderRule; +import org.sonar.server.computation.component.ViewsComponent; +import org.sonar.server.computation.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys; +import org.sonar.server.computation.measure.Measure; +import org.sonar.server.computation.measure.MeasureRepositoryRule; +import org.sonar.server.computation.measure.MeasureVariations; +import org.sonar.server.computation.metric.MetricRepositoryRule; +import org.sonar.server.computation.period.Period; +import org.sonar.server.computation.period.PeriodsHolderRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.guava.api.Assertions.assertThat; +import static org.sonar.api.utils.DateUtils.parseDate; +import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW; +import static org.sonar.server.computation.component.Component.Type.SUBVIEW; +import static org.sonar.server.computation.component.Component.Type.VIEW; +import static org.sonar.server.computation.component.ViewsComponent.builder; +import static org.sonar.server.computation.measure.Measure.newMeasureBuilder; +import static org.sonar.server.computation.measure.MeasureRepoEntry.entryOf; +import static org.sonar.server.computation.measure.MeasureRepoEntry.toEntries; +import static org.sonar.server.computation.measure.MeasureVariations.newMeasureVariationsBuilder; + +public class ViewsNewCoverageMeasuresStepTest { + + private static final int ROOT_REF = 1; + private static final int SUBVIEW_REF = 11; + private static final int SUB_SUBVIEW_1_REF = 111; + private static final int PROJECT_VIEW_1_REF = 1111; + private static final int SUB_SUBVIEW_2_REF = 112; + private static final int PROJECT_VIEW_2_REF = 1121; + private static final int PROJECT_VIEW_3_REF = 1122; + private static final int PROJECT_VIEW_4_REF = 12; + + private static final ViewsComponent VIEWS_TREE = builder(VIEW, ROOT_REF) + .addChildren( + builder(SUBVIEW, SUBVIEW_REF) + .addChildren( + builder(SUBVIEW, SUB_SUBVIEW_1_REF) + .addChildren( + builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build()) + .build(), + builder(SUBVIEW, SUB_SUBVIEW_2_REF) + .addChildren( + builder(PROJECT_VIEW, PROJECT_VIEW_2_REF).build(), + builder(PROJECT_VIEW, PROJECT_VIEW_3_REF).build()) + .build(), + builder(PROJECT_VIEW, PROJECT_VIEW_4_REF).build()) + .build()) + .build(); + private static final Double NO_PERIOD_4_OR_5_IN_VIEWS = null; + + @Rule + public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + @Rule + public PeriodsHolderRule periodsHolder = new PeriodsHolderRule(); + @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) + .add(CoreMetrics.NEW_UNCOVERED_CONDITIONS) + .add(CoreMetrics.NEW_COVERAGE) + .add(CoreMetrics.NEW_BRANCH_COVERAGE) + .add(CoreMetrics.NEW_LINE_COVERAGE) + + .add(CoreMetrics.IT_COVERAGE_LINE_HITS_DATA) + .add(CoreMetrics.IT_CONDITIONS_BY_LINE) + .add(CoreMetrics.IT_COVERED_CONDITIONS_BY_LINE) + .add(CoreMetrics.NEW_IT_LINES_TO_COVER) + .add(CoreMetrics.NEW_IT_UNCOVERED_LINES) + .add(CoreMetrics.NEW_IT_CONDITIONS_TO_COVER) + .add(CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS) + .add(CoreMetrics.NEW_IT_COVERAGE) + .add(CoreMetrics.NEW_IT_BRANCH_COVERAGE) + .add(CoreMetrics.NEW_IT_LINE_COVERAGE) + + .add(CoreMetrics.OVERALL_COVERAGE_LINE_HITS_DATA) + .add(CoreMetrics.OVERALL_CONDITIONS_BY_LINE) + .add(CoreMetrics.OVERALL_COVERED_CONDITIONS_BY_LINE) + .add(CoreMetrics.NEW_OVERALL_LINES_TO_COVER) + .add(CoreMetrics.NEW_OVERALL_UNCOVERED_LINES) + .add(CoreMetrics.NEW_OVERALL_CONDITIONS_TO_COVER) + .add(CoreMetrics.NEW_OVERALL_UNCOVERED_CONDITIONS) + .add(CoreMetrics.NEW_OVERALL_COVERAGE) + .add(CoreMetrics.NEW_OVERALL_BRANCH_COVERAGE) + .add(CoreMetrics.NEW_OVERALL_LINE_COVERAGE); + @Rule + public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + + private NewCoverageMeasuresStep underTest = new NewCoverageMeasuresStep(treeRootHolder, periodsHolder, + measureRepository, metricRepository); + + @Before + public void setUp() { + periodsHolder.setPeriods( + new Period(2, "mode_p_1", null, parseDate("2009-12-25").getTime(), 1), + new Period(5, "mode_p_5", null, parseDate("2011-02-18").getTime(), 2)); + } + + @Test + public void verify_aggregation_of_measures_for_new_conditions() { + String newLinesToCover = CoreMetrics.NEW_IT_LINES_TO_COVER_KEY; + String newUncoveredLines = CoreMetrics.NEW_IT_UNCOVERED_LINES_KEY; + String newConditionsToCover = CoreMetrics.NEW_IT_CONDITIONS_TO_COVER_KEY; + String newUncoveredConditions = CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS_KEY; + + MetricKeys metricKeys = new MetricKeys(newLinesToCover, newUncoveredLines, newConditionsToCover, newUncoveredConditions); + + treeRootHolder.setRoot(VIEWS_TREE); + // PROJECT_VIEW_1_REF has no measure + measureRepository.addRawMeasure(PROJECT_VIEW_2_REF, newLinesToCover, createMeasure(1d, 2d)); + measureRepository.addRawMeasure(PROJECT_VIEW_2_REF, newUncoveredLines, createMeasure(10d, 20d)); + measureRepository.addRawMeasure(PROJECT_VIEW_2_REF, newConditionsToCover, createMeasure(4d, 5d)); + measureRepository.addRawMeasure(PROJECT_VIEW_2_REF, newUncoveredConditions, createMeasure(40d, 50d)); + measureRepository.addRawMeasure(PROJECT_VIEW_3_REF, newLinesToCover, createMeasure(11d, 12d)); + measureRepository.addRawMeasure(PROJECT_VIEW_3_REF, newUncoveredLines, createMeasure(20d, 30d)); + measureRepository.addRawMeasure(PROJECT_VIEW_3_REF, newConditionsToCover, createMeasure(14d, 15d)); + measureRepository.addRawMeasure(PROJECT_VIEW_3_REF, newUncoveredConditions, createMeasure(50d, 60d)); + measureRepository.addRawMeasure(PROJECT_VIEW_4_REF, newLinesToCover, createMeasure(21d, 22d)); + measureRepository.addRawMeasure(PROJECT_VIEW_4_REF, newUncoveredLines, createMeasure(30d, 40d)); + measureRepository.addRawMeasure(PROJECT_VIEW_4_REF, newConditionsToCover, createMeasure(24d, 25d)); + measureRepository.addRawMeasure(PROJECT_VIEW_4_REF, newUncoveredConditions, createMeasure(60d, 70d)); + + underTest.execute(); + + assertNoAddedRawMeasureOnProjectViews(); + assertNoAddedRawMeasures(SUB_SUBVIEW_1_REF); + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_SUBVIEW_2_REF))).contains( + entryOf(metricKeys.newLinesToCover, createMeasure(12d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newUncoveredLines, createMeasure(30d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newConditionsToCover, createMeasure(18d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newUncoveredConditions, createMeasure(90d, NO_PERIOD_4_OR_5_IN_VIEWS))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains( + entryOf(metricKeys.newLinesToCover, createMeasure(33d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newUncoveredLines, createMeasure(60d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newConditionsToCover, createMeasure(42d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(metricKeys.newUncoveredConditions, createMeasure(150d, NO_PERIOD_4_OR_5_IN_VIEWS))); + } + + @Test + public void verify_aggregates_variations_for_new_code_line_and_branch_Coverage() { + LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( + CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, + CoreMetrics.NEW_UNCOVERED_LINES_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY); + String codeCoverageKey = CoreMetrics.NEW_COVERAGE_KEY; + String lineCoverageKey = CoreMetrics.NEW_LINE_COVERAGE_KEY; + String branchCoverageKey = CoreMetrics.NEW_BRANCH_COVERAGE_KEY; + + verify_aggregates_variations(metricKeys, codeCoverageKey, lineCoverageKey, branchCoverageKey); + } + + @Test + public void verify_aggregates_variations_for_new_IT_code_line_and_branch_Coverage() { + LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( + CoreMetrics.NEW_IT_LINES_TO_COVER_KEY, CoreMetrics.NEW_IT_CONDITIONS_TO_COVER_KEY, + CoreMetrics.NEW_IT_UNCOVERED_LINES_KEY, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS_KEY); + String codeCoverageKey = CoreMetrics.NEW_IT_COVERAGE_KEY; + String lineCoverageKey = CoreMetrics.NEW_IT_LINE_COVERAGE_KEY; + String branchCoverageKey = CoreMetrics.NEW_IT_BRANCH_COVERAGE_KEY; + + verify_aggregates_variations(metricKeys, codeCoverageKey, lineCoverageKey, branchCoverageKey); + } + + @Test + public void verify_aggregates_variations_for_new_Overall_code_line_and_branch_Coverage() { + LinesAndConditionsWithUncoveredMetricKeys metricKeys = new LinesAndConditionsWithUncoveredMetricKeys( + CoreMetrics.NEW_OVERALL_LINES_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_CONDITIONS_TO_COVER_KEY, + CoreMetrics.NEW_OVERALL_UNCOVERED_LINES_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_CONDITIONS_KEY); + String codeCoverageKey = CoreMetrics.NEW_OVERALL_COVERAGE_KEY; + String lineCoverageKey = CoreMetrics.NEW_OVERALL_LINE_COVERAGE_KEY; + String branchCoverageKey = CoreMetrics.NEW_OVERALL_BRANCH_COVERAGE_KEY; + + verify_aggregates_variations(metricKeys, codeCoverageKey, lineCoverageKey, branchCoverageKey); + } + + private void verify_aggregates_variations(LinesAndConditionsWithUncoveredMetricKeys metricKeys, String codeCoverageKey, String lineCoverageKey, String branchCoverageKey) { + treeRootHolder.setRoot(VIEWS_TREE); + measureRepository + .addRawMeasure(PROJECT_VIEW_1_REF, metricKeys.getLines(), createMeasure(3000d, 2000d)) + .addRawMeasure(PROJECT_VIEW_1_REF, metricKeys.getConditions(), createMeasure(300d, 400d)) + .addRawMeasure(PROJECT_VIEW_1_REF, metricKeys.getUncoveredLines(), createMeasure(30d, 200d)) + .addRawMeasure(PROJECT_VIEW_1_REF, metricKeys.getUncoveredConditions(), createMeasure(9d, 16d)) + // PROJECT_VIEW_2_REF + .addRawMeasure(PROJECT_VIEW_2_REF, metricKeys.getLines(), createMeasure(2000d, 3000d)) + .addRawMeasure(PROJECT_VIEW_2_REF, metricKeys.getConditions(), createMeasure(400d, 300d)) + .addRawMeasure(PROJECT_VIEW_2_REF, metricKeys.getUncoveredLines(), createMeasure(200d, 30d)) + .addRawMeasure(PROJECT_VIEW_2_REF, metricKeys.getUncoveredConditions(), createMeasure(16d, 9d)) + // PROJECT_VIEW_3_REF has no measure + // PROJECT_VIEW_4_REF + .addRawMeasure(PROJECT_VIEW_4_REF, metricKeys.getLines(), createMeasure(1000d, 2000d)) + .addRawMeasure(PROJECT_VIEW_4_REF, metricKeys.getConditions(), createMeasure(300d, 200d)) + .addRawMeasure(PROJECT_VIEW_4_REF, metricKeys.getUncoveredLines(), createMeasure(100d, 20d)) + .addRawMeasure(PROJECT_VIEW_4_REF, metricKeys.getUncoveredConditions(), createMeasure(6d, 9d)); + + underTest.execute(); + + assertNoAddedRawMeasureOnProjectViews(); + + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_SUBVIEW_1_REF))).contains( + entryOf(codeCoverageKey, createMeasure(98.8d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(lineCoverageKey, createMeasure(99d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(branchCoverageKey, createMeasure(97d, NO_PERIOD_4_OR_5_IN_VIEWS))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUB_SUBVIEW_2_REF))).contains( + entryOf(codeCoverageKey, createMeasure(91d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(lineCoverageKey, createMeasure(90d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(branchCoverageKey, createMeasure(96d, NO_PERIOD_4_OR_5_IN_VIEWS))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(SUBVIEW_REF))).contains( + entryOf(codeCoverageKey, createMeasure(94.8d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(lineCoverageKey, createMeasure(94.5d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(branchCoverageKey, createMeasure(96.9d, NO_PERIOD_4_OR_5_IN_VIEWS))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).contains( + entryOf(codeCoverageKey, createMeasure(94.8d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(lineCoverageKey, createMeasure(94.5d, NO_PERIOD_4_OR_5_IN_VIEWS)), + entryOf(branchCoverageKey, createMeasure(96.9d, NO_PERIOD_4_OR_5_IN_VIEWS))); + } + + private static final class MetricKeys { + private final String newLinesToCover; + private final String newUncoveredLines; + private final String newConditionsToCover; + private final String newUncoveredConditions; + + public MetricKeys(String newLinesToCover, String newUncoveredLines, String newConditionsToCover, String newUncoveredConditions) { + this.newLinesToCover = newLinesToCover; + this.newUncoveredLines = newUncoveredLines; + this.newConditionsToCover = newConditionsToCover; + this.newUncoveredConditions = newUncoveredConditions; + } + } + + private static Measure createMeasure(@Nullable Double variationPeriod2, @Nullable Double variationPeriod5) { + MeasureVariations.Builder variationBuilder = newMeasureVariationsBuilder(); + if (variationPeriod2 != null) { + variationBuilder.setVariation(new Period(2, "", null, 1L, 2L), variationPeriod2); + } + if (variationPeriod5 != null) { + variationBuilder.setVariation(new Period(5, "", null, 1L, 2L), variationPeriod5); + } + return newMeasureBuilder() + .setVariations(variationBuilder.build()) + .createNoValue(); + } + + private void assertNoAddedRawMeasureOnProjectViews() { + assertNoAddedRawMeasures(PROJECT_VIEW_1_REF); + assertNoAddedRawMeasures(PROJECT_VIEW_2_REF); + assertNoAddedRawMeasures(PROJECT_VIEW_3_REF); + } + + private void assertNoAddedRawMeasures(int componentRef) { + assertThat(measureRepository.getAddedRawMeasures(componentRef)).isEmpty(); + } + +} |