diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2018-04-16 18:06:08 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-05-02 20:20:56 +0200 |
commit | d13e2d9a08ea6fc3cb29bcf4add0c4f2f12cc3b8 (patch) | |
tree | 73bffcc464d1995e7c90fd27af1f84ea7f608b09 /server | |
parent | 5c78e445609eaf1c6bb00b0c863623ea497237a0 (diff) | |
download | sonarqube-d13e2d9a08ea6fc3cb29bcf4add0c4f2f12cc3b8.tar.gz sonarqube-d13e2d9a08ea6fc3cb29bcf4add0c4f2f12cc3b8.zip |
SONAR-9384 Fix computation of project without src but with test measures
Diffstat (limited to 'server')
3 files changed, 163 insertions, 14 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/UnitTestMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/UnitTestMeasuresStep.java index 54712d2e572..87253d0fef5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/UnitTestMeasuresStep.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/UnitTestMeasuresStep.java @@ -22,7 +22,6 @@ package org.sonar.server.computation.task.projectanalysis.step; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.sonar.server.computation.task.projectanalysis.component.Component; -import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler; import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolder; import org.sonar.server.computation.task.projectanalysis.formula.Counter; @@ -31,6 +30,7 @@ import org.sonar.server.computation.task.projectanalysis.formula.CreateMeasureCo import org.sonar.server.computation.task.projectanalysis.formula.Formula; import org.sonar.server.computation.task.projectanalysis.formula.FormulaExecutorComponentVisitor; import org.sonar.server.computation.task.projectanalysis.formula.counter.IntSumCounter; +import org.sonar.server.computation.task.projectanalysis.formula.counter.LongSumCounter; import org.sonar.server.computation.task.projectanalysis.measure.Measure; import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepository; import org.sonar.server.computation.task.projectanalysis.metric.MetricRepository; @@ -42,20 +42,15 @@ import static org.sonar.api.measures.CoreMetrics.TEST_ERRORS_KEY; import static org.sonar.api.measures.CoreMetrics.TEST_EXECUTION_TIME_KEY; import static org.sonar.api.measures.CoreMetrics.TEST_FAILURES_KEY; import static org.sonar.api.measures.CoreMetrics.TEST_SUCCESS_DENSITY_KEY; -import static org.sonar.server.computation.task.projectanalysis.formula.SumFormula.createIntSumFormula; -import static org.sonar.server.computation.task.projectanalysis.formula.SumFormula.createLongSumFormula; /** * Computes unit test measures on files and then aggregates them on higher components. */ public class UnitTestMeasuresStep implements ComputationStep { - private static final String[] METRICS = new String[] {TESTS_KEY, TEST_ERRORS_KEY, TEST_FAILURES_KEY, TEST_SUCCESS_DENSITY_KEY}; + private static final String[] METRICS = new String[] {TESTS_KEY, TEST_ERRORS_KEY, TEST_FAILURES_KEY, SKIPPED_TESTS_KEY, TEST_SUCCESS_DENSITY_KEY, TEST_EXECUTION_TIME_KEY}; - private static final ImmutableList<Formula> FORMULAS = ImmutableList.of( - createLongSumFormula(TEST_EXECUTION_TIME_KEY), - createIntSumFormula(SKIPPED_TESTS_KEY), - new UnitTestsFormula()); + private static final ImmutableList<Formula> FORMULAS = ImmutableList.of(new UnitTestsFormula()); private final TreeRootHolder treeRootHolder; private final MetricRepository metricRepository; @@ -84,13 +79,18 @@ public class UnitTestMeasuresStep implements ComputationStep { @Override public Optional<Measure> createMeasure(UnitTestsCounter counter, CreateMeasureContext context) { String metricKey = context.getMetric().getKey(); + Component leaf = counter.getLeaf(); switch (metricKey) { case TESTS_KEY: - return createMeasure(context.getComponent().getType(), counter.testsCounter.getValue()); + return createIntMeasure(context.getComponent(), leaf, counter.testsCounter.getValue()); case TEST_ERRORS_KEY: - return createMeasure(context.getComponent().getType(), counter.testsErrorsCounter.getValue()); + return createIntMeasure(context.getComponent(), leaf, counter.testsErrorsCounter.getValue()); case TEST_FAILURES_KEY: - return createMeasure(context.getComponent().getType(), counter.testsFailuresCounter.getValue()); + return createIntMeasure(context.getComponent(), leaf, counter.testsFailuresCounter.getValue()); + case SKIPPED_TESTS_KEY: + return createIntMeasure(context.getComponent(), leaf, counter.skippedTestsCounter.getValue()); + case TEST_EXECUTION_TIME_KEY: + return createLongMeasure(context.getComponent(), leaf, counter.testExecutionTimeCounter.getValue()); case TEST_SUCCESS_DENSITY_KEY: return createDensityMeasure(counter, context.getMetric().getDecimalScale()); default: @@ -98,8 +98,15 @@ public class UnitTestMeasuresStep implements ComputationStep { } } - private static Optional<Measure> createMeasure(Component.Type componentType, Optional<Integer> metricValue) { - if (metricValue.isPresent() && CrawlerDepthLimit.LEAVES.isDeeperThan(componentType)) { + private static Optional<Measure> createIntMeasure(Component currentComponent, Component leafComponent, Optional<Integer> metricValue) { + if (metricValue.isPresent() && leafComponent.getType().isDeeperThan(currentComponent.getType())) { + return Optional.of(Measure.newMeasureBuilder().create(metricValue.get())); + } + return Optional.absent(); + } + + private static Optional<Measure> createLongMeasure(Component currentComponent, Component leafComponent, Optional<Long> metricValue) { + if (metricValue.isPresent() && leafComponent.getType().isDeeperThan(currentComponent.getType())) { return Optional.of(Measure.newMeasureBuilder().create(metricValue.get())); } return Optional.absent(); @@ -133,19 +140,32 @@ public class UnitTestMeasuresStep implements ComputationStep { private final IntSumCounter testsCounter = new IntSumCounter(TESTS_KEY); private final IntSumCounter testsErrorsCounter = new IntSumCounter(TEST_ERRORS_KEY); private final IntSumCounter testsFailuresCounter = new IntSumCounter(TEST_FAILURES_KEY); + private final IntSumCounter skippedTestsCounter = new IntSumCounter(SKIPPED_TESTS_KEY); + private final LongSumCounter testExecutionTimeCounter = new LongSumCounter(TEST_EXECUTION_TIME_KEY); + + private Component leaf; @Override public void aggregate(UnitTestsCounter counter) { testsCounter.aggregate(counter.testsCounter); testsErrorsCounter.aggregate(counter.testsErrorsCounter); testsFailuresCounter.aggregate(counter.testsFailuresCounter); + skippedTestsCounter.aggregate(counter.skippedTestsCounter); + testExecutionTimeCounter.aggregate(counter.testExecutionTimeCounter); } @Override public void initialize(CounterInitializationContext context) { + this.leaf = context.getLeaf(); testsCounter.initialize(context); testsErrorsCounter.initialize(context); testsFailuresCounter.initialize(context); + skippedTestsCounter.initialize(context); + testExecutionTimeCounter.initialize(context); + } + + Component getLeaf() { + return leaf; } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/formula/ReportFormulaExecutorComponentVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/formula/ReportFormulaExecutorComponentVisitorTest.java index 2c57de63585..4238d9d4d3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/formula/ReportFormulaExecutorComponentVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/formula/ReportFormulaExecutorComponentVisitorTest.java @@ -23,6 +23,7 @@ import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.sonar.api.measures.CoreMetrics; import org.sonar.server.computation.task.projectanalysis.component.Component; import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler; @@ -48,6 +49,7 @@ import static org.sonar.server.computation.task.projectanalysis.component.Report import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf; import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries; +import static org.sonar.test.ExceptionCauseMatcher.hasType; public class ReportFormulaExecutorComponentVisitorTest { private static final int ROOT_REF = 1; @@ -79,6 +81,8 @@ public class ReportFormulaExecutorComponentVisitorTest { .build(); @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); @Rule public MetricRepositoryRule metricRepository = new MetricRepositoryRule() @@ -211,6 +215,83 @@ public class ReportFormulaExecutorComponentVisitorTest { assertAddedRawMeasure(DIRECTORY_1_REF, 0); } + @Test + public void compute_measure_on_project_without_children() { + ReportComponent root = builder(PROJECT, ROOT_REF).build(); + treeRootHolder.setRoot(root); + measureRepository.addRawMeasure(ROOT_REF, LINES_KEY, newMeasureBuilder().create(10)); + + new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula())) + .visit(root); + + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).containsOnly(entryOf(NCLOC_KEY, newMeasureBuilder().create(10))); + } + + @Test + public void ignore_measure_defined_on_project_when_measure_is_defined_on_leaf() { + ReportComponent root = builder(PROJECT, ROOT_REF) + .addChildren( + builder(Component.Type.FILE, FILE_1_REF).build()) + .build(); + treeRootHolder.setRoot(root); + measureRepository.addRawMeasure(ROOT_REF, LINES_KEY, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(FILE_1_REF, LINES_KEY, newMeasureBuilder().create(2)); + + new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula())) + .visit(root); + + assertAddedRawMeasure(ROOT_REF, 2); + assertAddedRawMeasure(FILE_1_REF, 2); + } + + @Test + public void fail_when_trying_to_compute_file_measure_already_existing_in_report() { + ReportComponent root = builder(PROJECT, ROOT_REF) + .addChildren( + builder(Component.Type.FILE, FILE_1_REF).build()) + .build(); + treeRootHolder.setRoot(root); + measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(2)); + + expectedException.expectCause(hasType(UnsupportedOperationException.class) + .andMessage(String.format("A measure can only be set once for Component (ref=%s), Metric (key=%s)", FILE_1_REF, NCLOC_KEY))); + + new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula())) + .visit(root); + } + + @Test + public void fail_on_project_without_children_already_having_computed_measure() { + ReportComponent root = builder(PROJECT, ROOT_REF).build(); + treeRootHolder.setRoot(root); + measureRepository.addRawMeasure(ROOT_REF, NCLOC_KEY, newMeasureBuilder().create(10)); + + expectedException.expectCause(hasType(UnsupportedOperationException.class) + .andMessage(String.format("A measure can only be set once for Component (ref=%s), Metric (key=%s)", ROOT_REF, NCLOC_KEY))); + + new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula())) + .visit(root); + } + + @Test + public void fail_on_project_containing_module_without_children_already_having_computed_measure() { + ReportComponent root = builder(PROJECT, ROOT_REF) + .addChildren( + ReportComponent.builder(MODULE, MODULE_1_REF).build(), + builder(Component.Type.FILE, FILE_1_REF).build()) + .build(); + treeRootHolder.setRoot(root); + measureRepository.addRawMeasure(FILE_1_REF, LINES_KEY, newMeasureBuilder().create(10)); + // Ncloc is already computed on module + measureRepository.addRawMeasure(MODULE_1_REF, NCLOC_KEY, newMeasureBuilder().create(3)); + + expectedException.expectCause(hasType(UnsupportedOperationException.class) + .andMessage(String.format("A measure can only be set once for Component (ref=%s), Metric (key=%s)", MODULE_1_REF, NCLOC_KEY))); + + new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula())) + .visit(root); + } + private FormulaExecutorComponentVisitor formulaExecutorComponentVisitor(Formula formula) { return FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository) .withVariationSupport(periodsHolder) diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportUnitTestMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportUnitTestMeasuresStepTest.java index d26db3dfee6..8426f509bc6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportUnitTestMeasuresStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/ReportUnitTestMeasuresStepTest.java @@ -113,7 +113,7 @@ public class ReportUnitTestMeasuresStepTest { } @Test - public void aggregate_skipped_tests_time() { + public void aggregate_skipped_tests() { checkMeasuresAggregation(SKIPPED_TESTS_KEY, 100, 400, 500); } @@ -258,6 +258,54 @@ public class ReportUnitTestMeasuresStepTest { assertThat(measureRepository.getAddedRawMeasure(ROOT_REF, TEST_SUCCESS_DENSITY_KEY)).isAbsent(); } + @Test + public void aggregate_measures_when_tests_measures_are_defined_on_directory() { + treeRootHolder.setRoot(builder(PROJECT, ROOT_REF) + .addChildren( + builder(MODULE, MODULE_REF) + .addChildren( + builder(DIRECTORY, DIRECTORY_REF).build()) + .build()) + .build()); + measureRepository.addRawMeasure(DIRECTORY_REF, TESTS_KEY, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(DIRECTORY_REF, TEST_ERRORS_KEY, newMeasureBuilder().create(2)); + measureRepository.addRawMeasure(DIRECTORY_REF, TEST_FAILURES_KEY, newMeasureBuilder().create(1)); + measureRepository.addRawMeasure(DIRECTORY_REF, SKIPPED_TESTS_KEY, newMeasureBuilder().create(5)); + measureRepository.addRawMeasure(DIRECTORY_REF, TEST_EXECUTION_TIME_KEY, newMeasureBuilder().create(100L)); + + underTest.execute(); + + assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_REF))).containsOnly( + entryOf(TESTS_KEY, newMeasureBuilder().create(10)), + entryOf(TEST_ERRORS_KEY, newMeasureBuilder().create(2)), + entryOf(TEST_FAILURES_KEY, newMeasureBuilder().create(1)), + entryOf(SKIPPED_TESTS_KEY, newMeasureBuilder().create(5)), + entryOf(TEST_EXECUTION_TIME_KEY, newMeasureBuilder().create(100L)), + entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(70d, 1))); + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).containsOnly( + entryOf(TESTS_KEY, newMeasureBuilder().create(10)), + entryOf(TEST_ERRORS_KEY, newMeasureBuilder().create(2)), + entryOf(TEST_FAILURES_KEY, newMeasureBuilder().create(1)), + entryOf(SKIPPED_TESTS_KEY, newMeasureBuilder().create(5)), + entryOf(TEST_EXECUTION_TIME_KEY, newMeasureBuilder().create(100L)), + entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(70d, 1))); + } + + @Test + public void compute_test_success_density_measure_when_tests_measures_are_defined_at_project_level_and_no_children() { + treeRootHolder.setRoot(builder(PROJECT, ROOT_REF).build()); + measureRepository.addRawMeasure(ROOT_REF, TESTS_KEY, newMeasureBuilder().create(10)); + measureRepository.addRawMeasure(ROOT_REF, TEST_ERRORS_KEY, newMeasureBuilder().create(2)); + measureRepository.addRawMeasure(ROOT_REF, TEST_FAILURES_KEY, newMeasureBuilder().create(1)); + measureRepository.addRawMeasure(ROOT_REF, SKIPPED_TESTS_KEY, newMeasureBuilder().create(5)); + measureRepository.addRawMeasure(ROOT_REF, TEST_EXECUTION_TIME_KEY, newMeasureBuilder().create(100L)); + + underTest.execute(); + + assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).containsOnly( + entryOf(TEST_SUCCESS_DENSITY_KEY, newMeasureBuilder().create(70d, 1))); + } + private void checkMeasuresAggregation(String metricKey, int file1Value, int file2Value, int expectedValue) { measureRepository.addRawMeasure(FILE_1_REF, metricKey, newMeasureBuilder().create(file1Value)); measureRepository.addRawMeasure(FILE_2_REF, metricKey, newMeasureBuilder().create(file2Value)); |