From aac84dd7bd38cf7e60712fd7f0192bd2559b7a33 Mon Sep 17 00:00:00 2001 From: Ulli Hafner Date: Thu, 16 Nov 2023 16:40:53 +0100 Subject: [PATCH] Fix quality gates for all baselines. --- plugin/pom.xml | 2 +- .../metrics/steps/CoverageReporter.java | 64 ++++++++++--------- .../metrics/model/Messages.properties | 2 +- .../CoverageQualityGate/help-baseline.html | 27 ++++---- .../metrics/AbstractCoverageTest.java | 6 +- .../charts/CoverageSeriesBuilderTest.java | 20 +++--- .../metrics/source/SourceCodeITest.java | 6 +- .../steps/CoverageBuildActionTest.java | 53 +++++++-------- .../steps/CoverageChecksPublisherTest.java | 6 +- .../steps/CoverageMetricColumnTest.java | 2 +- .../metrics/steps/CoveragePluginITest.java | 22 ++++--- .../metrics/steps/DeltaComputationITest.java | 36 +++++------ .../metrics/steps/GitForensicsITest.java | 28 ++++---- .../metrics/steps/QualityGateITest.java | 28 ++++++++ 14 files changed, 172 insertions(+), 130 deletions(-) diff --git a/plugin/pom.xml b/plugin/pom.xml index e5cab1df..9420a8e7 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -25,7 +25,7 @@ jenkinsci/coverage-plugin - 0.30.0 + 0.31.0 1.16.2 diff --git a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageReporter.java b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageReporter.java index a73e0256..1014a246 100644 --- a/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageReporter.java +++ b/plugin/src/main/java/io/jenkins/plugins/coverage/metrics/steps/CoverageReporter.java @@ -1,6 +1,5 @@ package io.jenkins.plugins.coverage.metrics.steps; -import java.util.ArrayList; import java.util.List; import java.util.NavigableMap; import java.util.Optional; @@ -32,13 +31,16 @@ /** * Transforms the old model to the new model and invokes all steps that work on the new model. Currently, only the - * source code painting and copying has been moved to this new reporter class. + * source code painting and copying have been moved to this new reporter class. * * @author Ullrich Hafner */ -@SuppressWarnings("checkstyle:ClassDataAbstractionCoupling") +@SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling", "PMD.LooseCoupling"}) public class CoverageReporter { - @SuppressWarnings("checkstyle:ParameterNumber") + private static final NavigableMap EMPTY_DELTA = new TreeMap<>(); + private static final List EMPTY_VALUES = List.of(); + + @SuppressWarnings({"checkstyle:ParameterNumber", "checkstyle:JavaNCSS"}) CoverageBuildAction publishAction(final String id, final String optionalName, final String icon, final Node rootNode, final Run build, final FilePath workspace, final TaskListener listener, final List qualityGates, final String scm, final String sourceCodeEncoding, @@ -63,29 +65,34 @@ CoverageBuildAction publishAction(final String id, final String optionalName, fi Node modifiedLinesCoverageRoot = rootNode.filterByModifiedLines(); - NavigableMap modifiedLinesCoverageDelta; - List aggregatedModifiedFilesCoverage; - NavigableMap modifiedFilesCoverageDelta; + NavigableMap modifiedLinesDelta; + List modifiedFilesValues; + NavigableMap modifiedFilesDelta; if (hasModifiedLinesCoverage(modifiedLinesCoverageRoot)) { Node modifiedFilesCoverageRoot = rootNode.filterByModifiedFiles(); - aggregatedModifiedFilesCoverage = modifiedFilesCoverageRoot.aggregateValues(); - modifiedFilesCoverageDelta = modifiedFilesCoverageRoot.computeDelta(rootNode); - modifiedLinesCoverageDelta = modifiedLinesCoverageRoot.computeDelta(modifiedFilesCoverageRoot); + modifiedFilesValues = modifiedFilesCoverageRoot.aggregateValues(); + modifiedFilesDelta = modifiedFilesCoverageRoot.computeDelta( + referenceRoot.filterByFileNames(modifiedFilesCoverageRoot.getFiles())); + + modifiedLinesDelta = modifiedLinesCoverageRoot.computeDelta(modifiedFilesCoverageRoot); } else { - modifiedLinesCoverageDelta = new TreeMap<>(); - aggregatedModifiedFilesCoverage = new ArrayList<>(); - modifiedFilesCoverageDelta = new TreeMap<>(); + modifiedLinesDelta = EMPTY_DELTA; + modifiedFilesValues = EMPTY_VALUES; + modifiedFilesDelta = EMPTY_DELTA; + if (rootNode.hasModifiedLines()) { log.logInfo("No detected code changes affect the code coverage"); } } - NavigableMap coverageDelta = rootNode.computeDelta(referenceRoot); + var overallValues = rootNode.aggregateValues(); + NavigableMap overallDelta = rootNode.computeDelta(referenceRoot); + var modifiedLinesValues = modifiedLinesCoverageRoot.aggregateValues(); - QualityGateResult qualityGateResult = evaluateQualityGates(rootNode, log, - modifiedLinesCoverageRoot.aggregateValues(), modifiedLinesCoverageDelta, coverageDelta, - resultHandler, qualityGates); + var statistics = new CoverageStatistics(overallValues, overallDelta, + modifiedLinesValues, modifiedLinesDelta, modifiedFilesValues, modifiedFilesDelta); + QualityGateResult qualityGateResult = evaluateQualityGates(qualityGates, statistics, resultHandler, log); if (sourceCodeRetention == SourceCodeRetention.MODIFIED) { filesToStore = modifiedLinesCoverageRoot.getAllFileNodes(); @@ -96,14 +103,16 @@ CoverageBuildAction publishAction(final String id, final String optionalName, fi } action = new CoverageBuildAction(build, id, optionalName, icon, rootNode, qualityGateResult, log, - referenceAction.getOwner().getExternalizableId(), coverageDelta, - modifiedLinesCoverageRoot.aggregateValues(), modifiedLinesCoverageDelta, - aggregatedModifiedFilesCoverage, modifiedFilesCoverageDelta, + referenceAction.getOwner().getExternalizableId(), overallDelta, + modifiedLinesValues, modifiedLinesDelta, + modifiedFilesValues, modifiedFilesDelta, rootNode.filterByIndirectChanges().aggregateValues()); } else { - QualityGateResult qualityGateStatus = evaluateQualityGates(rootNode, log, - List.of(), new TreeMap<>(), new TreeMap<>(), resultHandler, qualityGates); + var statistics = new CoverageStatistics(rootNode.aggregateValues(), + EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA, EMPTY_VALUES, EMPTY_DELTA); + QualityGateResult qualityGateStatus = evaluateQualityGates(qualityGates, + statistics, resultHandler, log); filesToStore = rootNode.getAllFileNodes(); @@ -152,16 +161,11 @@ private void createDeltaReports(final Node rootNode, final FilteredLog log, fina } } - private QualityGateResult evaluateQualityGates(final Node rootNode, final FilteredLog log, - final List modifiedLinesCoverageDistribution, - final NavigableMap modifiedLinesCoverageDelta, - final NavigableMap coverageDelta, final StageResultHandler resultHandler, - final List qualityGates) { - var statistics = new CoverageStatistics(rootNode.aggregateValues(), coverageDelta, - modifiedLinesCoverageDistribution, modifiedLinesCoverageDelta, List.of(), new TreeMap<>()); + private QualityGateResult evaluateQualityGates(final List qualityGates, + final CoverageStatistics statistics, final StageResultHandler resultHandler, final FilteredLog log) { CoverageQualityGateEvaluator evaluator = new CoverageQualityGateEvaluator(qualityGates, statistics); var qualityGateStatus = evaluator.evaluate(); - if (qualityGateStatus.isInactive()) { + if (qualityGateStatus.isInactive() && qualityGates.isEmpty()) { log.logInfo("No quality gates have been set - skipping"); } else { diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/model/Messages.properties b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/model/Messages.properties index 8dc16b9d..8e765eb9 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/model/Messages.properties +++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/model/Messages.properties @@ -38,5 +38,5 @@ Baseline.PROJECT_DELTA=Overall project (difference to reference job) Baseline.MODIFIED_LINES=Modified code lines Baseline.MODIFIED_LINES_DELTA=Modified code lines (difference to modified files) Baseline.MODIFIED_FILES=Modified files -Baseline.MODIFIED_FILES_DELTA=Modified files (difference to overall project) +Baseline.MODIFIED_FILES_DELTA=Modified files (difference to reference job) Baseline.INDIRECT=Indirect changes diff --git a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-baseline.html b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-baseline.html index febd55a8..24296f3b 100644 --- a/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-baseline.html +++ b/plugin/src/main/resources/io/jenkins/plugins/coverage/metrics/steps/CoverageQualityGate/help-baseline.html @@ -11,27 +11,30 @@
Overall project (difference to reference job) - PROJECT_DELTA
Difference between the project coverages of the current build and the reference build. Teams can use this delta - value to ensure that the coverage will not decrease. + value to ensure that the overall project coverage will not decrease.
-
Modified code lines - MODIFIED_LINES
+
Modified files - MODIFIED_FILES
- Coverage of the modified lines (e.g., within the modified lines of a pull or merge request) - will focus on new or modified code only. + Coverage of the modified files (e.g., within the files that have been touched in a pull or merge request) + will focus on new or modified files only.
-
Modified code lines (difference to overall project) - MODIFIED_LINES_DELTA
+
Modified files (difference to reference job) - MODIFIED_FILES_DELTA
- Difference between the project coverage and the modified lines coverage of the current build. Teams can use this delta - value to ensure that the coverage of pull requests is better than the whole project coverage. + Difference between the file coverages of the current build and the reference build. Teams can use this delta + value to ensure that the overall coverage of all modified files will not decrease. + This also implies that the overall project coverage will not decrease, making this metric stricter + than the PROJECT_DELTA metric
-
Modified files - MODIFIED_FILES
+
Modified code lines - MODIFIED_LINES
- Coverage of the modified files (e.g., within the files that have been touched in a pull or merge request) + Coverage of the modified lines (e.g., within the modified lines of a pull or merge request) will focus on new or modified code only.
-
Modified files (difference to overall project) - MODIFIED_FILES_DELTA
+
Modified code lines (difference to modified files) - MODIFIED_LINES_DELTA
- Difference between the project coverage and the modified files coverage of the current build. Teams can use this delta - value to ensure that the coverage of pull requests is better than the whole project coverage. + Difference between the coverages of the modified lines and the modified files of the current build. + Teams can use this delta value to ensure that the coverage of pull requests is better than the + existing coverage of the modified files.
diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractCoverageTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractCoverageTest.java index ea31fe7b..12290b8d 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractCoverageTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/AbstractCoverageTest.java @@ -105,9 +105,9 @@ public static CoverageStatistics createOnlyProjectStatistics() { private static List fillValues() { var builder = new CoverageBuilder(); return List.of( - builder.setMetric(Metric.FILE).setCovered(3).setMissed(1).build(), - builder.setMetric(Metric.LINE).setCovered(2).setMissed(2).build(), - builder.setMetric(Metric.BRANCH).setCovered(9).setMissed(1).build(), + builder.withMetric(Metric.FILE).withCovered(3).withMissed(1).build(), + builder.withMetric(Metric.LINE).withCovered(2).withMissed(2).build(), + builder.withMetric(Metric.BRANCH).withCovered(9).withMissed(1).build(), new CyclomaticComplexity(150), new CyclomaticComplexity(15, Metric.COMPLEXITY_MAXIMUM), new LinesOfCode(1000) diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java index 8e9ce50c..99e41435 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/charts/CoverageSeriesBuilderTest.java @@ -45,16 +45,16 @@ void shouldCreateChart() { CoverageTrendChart trendChart = new CoverageTrendChart(); BuildResult smallLineCoverage = createResult(1, - new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(1).build(), - new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(3).setMissed(1).build()); + new CoverageBuilder().withMetric(Metric.LINE).withCovered(1).withMissed(1).build(), + new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(3).withMissed(1).build()); LinesChartModel lineCoverage = trendChart.create(Collections.singletonList(smallLineCoverage), createConfiguration()); verifySeriesDetails(lineCoverage); BuildResult smallBranchCoverage = createResult(1, - new CoverageBuilder().setMetric(Metric.LINE).setCovered(3).setMissed(1).build(), - new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(1).setMissed(1).build()); + new CoverageBuilder().withMetric(Metric.LINE).withCovered(3).withMissed(1).build(), + new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(1).withMissed(1).build()); LinesChartModel branchCoverage = trendChart.create(Collections.singletonList(smallBranchCoverage), createConfiguration()); @@ -85,8 +85,8 @@ void shouldHaveTwoValuesForSingleBuild() { CoverageSeriesBuilder builder = new CoverageSeriesBuilder(); BuildResult singleResult = createResult(1, - new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(1).build(), - new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(3).setMissed(1).build()); + new CoverageBuilder().withMetric(Metric.LINE).withCovered(1).withMissed(1).build(), + new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(3).withMissed(1).build()); LinesDataSet dataSet = builder.createDataSet(createConfiguration(), Collections.singletonList(singleResult)); @@ -106,11 +106,11 @@ void shouldHaveTwoValuesForTwoBuilds() { CoverageSeriesBuilder builder = new CoverageSeriesBuilder(); BuildResult first = createResult(1, - new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(1).build(), - new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(3).setMissed(1).build()); + new CoverageBuilder().withMetric(Metric.LINE).withCovered(1).withMissed(1).build(), + new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(3).withMissed(1).build()); BuildResult second = createResult(2, - new CoverageBuilder().setMetric(Metric.LINE).setCovered(1).setMissed(3).build(), - new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(1).setMissed(3).build()); + new CoverageBuilder().withMetric(Metric.LINE).withCovered(1).withMissed(3).build(), + new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(1).withMissed(3).build()); LinesDataSet dataSet = builder.createDataSet(createConfiguration(), List.of(first, second)); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java index 02ff0912..7918a728 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/source/SourceCodeITest.java @@ -175,10 +175,10 @@ private CpsFlowDefinition createPipelineWithSourceCode(final SourceCodeRetention private void verifySourceCodeInBuild(final String pathPrefix, final Run build, final String acuCobolParserSourceCodeSnippet, final String pathUtilSourceCodeSnippet) { List actions = build.getActions(CoverageBuildAction.class); - var builder = new CoverageBuilder().setMetric(Metric.LINE).setMissed(0); + var builder = new CoverageBuilder().withMetric(Metric.LINE).withMissed(0); assertThat(actions).hasSize(2).satisfiesExactly( action -> { - assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.setCovered(8).build()); + assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.withCovered(8).build()); var relativePath = getRelativePath(pathPrefix, ACU_COBOL_PARSER_SOURCE_FILE_PATH); Optional fileNode = action.getResult().find(Metric.FILE, relativePath); assertThat(fileNode).isNotEmpty().get() @@ -188,7 +188,7 @@ private void verifySourceCodeInBuild(final String pathPrefix, final Run bu .contains(acuCobolParserSourceCodeSnippet); }, action -> { - assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.setCovered(43).build()); + assertThat(action.getAllValues(Baseline.PROJECT)).contains(builder.withCovered(43).build()); var relativePath = getRelativePath(pathPrefix, PATH_UTIL_SOURCE_FILE_PATH); Optional fileNode = action.getResult().find(Metric.FILE, relativePath); assertThat(fileNode).isNotEmpty().get() diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java index 78ba7b14..24076ff8 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageBuildActionTest.java @@ -1,7 +1,7 @@ package io.jenkins.plugins.coverage.metrics.steps; import java.util.List; -import java.util.Optional; +import java.util.Map; import java.util.TreeMap; import org.apache.commons.lang3.StringUtils; @@ -31,31 +31,13 @@ */ @DefaultLocale("en") class CoverageBuildActionTest { - private CoverageBuildAction createCoverageBuildActionWithDelta(final Metric metric, final Optional delta) { - Node module = new ModuleNode("module"); - - var coverageBuilder = new CoverageBuilder(); - var percent = coverageBuilder.setMetric(metric).setCovered(1).setMissed(1).build(); - - module.addValue(percent); - - var deltas = new TreeMap(); - delta.ifPresent(d -> deltas.put(metric, d)); - - var coverages = List.of(percent); - - return spy(new CoverageBuildAction(mock(FreeStyleBuild.class), CoverageRecorder.DEFAULT_ID, - StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(), - createLog(), "-", deltas, coverages, deltas, coverages, deltas, coverages, false)); - } - @Test void shouldNotLoadResultIfCoverageValuesArePersistedInAction() { Node module = new ModuleNode("module"); var coverageBuilder = new CoverageBuilder(); - var percent50 = coverageBuilder.setMetric(Metric.BRANCH).setCovered(1).setMissed(1).build(); - var percent80 = coverageBuilder.setMetric(Metric.LINE).setCovered(8).setMissed(2).build(); + var percent50 = coverageBuilder.withMetric(Metric.BRANCH).withCovered(1).withMissed(1).build(); + var percent80 = coverageBuilder.withMetric(Metric.LINE).withCovered(8).withMissed(2).build(); module.addValue(percent50); module.addValue(percent80); @@ -110,25 +92,46 @@ void shouldCreateViewModel() { @Test void shouldReturnPositiveTrendForLineMetric() { - CoverageBuildAction action = createCoverageBuildActionWithDelta(Metric.LINE, Optional.of(Fraction.getFraction(1, 1000))); + CoverageBuildAction action = createCoverageBuildActionWithDelta(createMap(Fraction.getFraction(1, 1000))); assertThat(action.getTrend(Baseline.PROJECT, Metric.LINE)).isPositive(); } @Test void shouldReturnNegativeTrendForLineMetric() { - CoverageBuildAction action = createCoverageBuildActionWithDelta(Metric.LINE, Optional.of(Fraction.getFraction(-1, 1000))); + CoverageBuildAction action = createCoverageBuildActionWithDelta(createMap(Fraction.getFraction(-1, 1000))); assertThat(action.getTrend(Baseline.PROJECT, Metric.LINE)).isNegative(); } @Test void shouldReturnZeroForDeltaWithinBoundaries() { - CoverageBuildAction action = createCoverageBuildActionWithDelta(Metric.LINE, Optional.of(Fraction.getFraction(9, 10_000))); + CoverageBuildAction action = createCoverageBuildActionWithDelta(createMap(Fraction.getFraction(9, 10_000))); assertThat(action.getTrend(Baseline.PROJECT, Metric.LINE)).isZero(); } @Test void shouldReturnZeroWhenDeltaIsNotPresentForGivenMetric() { - CoverageBuildAction action = createCoverageBuildActionWithDelta(Metric.LINE, Optional.empty()); + CoverageBuildAction action = createCoverageBuildActionWithDelta(Map.of()); assertThat(action.getTrend(Baseline.PROJECT, Metric.LINE)).isZero(); } + + private Map createMap(final Fraction fraction) { + return Map.of(Metric.LINE, fraction); + } + + private CoverageBuildAction createCoverageBuildActionWithDelta(final Map deltas) { + Node module = new ModuleNode("module"); + + var coverageBuilder = new CoverageBuilder(); + var percent = coverageBuilder.withMetric(Metric.LINE).withCovered(1).withMissed(1).build(); + + module.addValue(percent); + + var coverages = List.of(percent); + + var sortedDeltas = new TreeMap<>(deltas); + return spy(new CoverageBuildAction(mock(FreeStyleBuild.class), CoverageRecorder.DEFAULT_ID, + StringUtils.EMPTY, StringUtils.EMPTY, module, new QualityGateResult(), + createLog(), "-", sortedDeltas, coverages, + sortedDeltas, coverages, sortedDeltas, coverages, false)); + } } diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java index 85d9c6bb..2ddb1d46 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageChecksPublisherTest.java @@ -181,9 +181,9 @@ private JenkinsFacade createJenkins() { } private CoverageBuildAction createCoverageBuildAction(final Node result) { - var testCoverage = new CoverageBuilder().setMetric(Metric.LINE) - .setCovered(1) - .setMissed(1) + var testCoverage = new CoverageBuilder(Metric.LINE) + .withCovered(1) + .withMissed(1) .build(); var run = mock(Run.class); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java index 206065ee..5c42bb6b 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoverageMetricColumnTest.java @@ -198,7 +198,7 @@ void shouldCalculateProjectCoverage() { assertThat(column.getCoverageValue(job)) .isNotEmpty() .satisfies(coverage -> { - assertThat(coverage.get()).isEqualTo(new CoverageBuilder().setMetric(Metric.BRANCH).setCovered(109).setMissed(7).build()); + assertThat(coverage.get()).isEqualTo(new CoverageBuilder().withMetric(Metric.BRANCH).withCovered(109).withMissed(7).build()); assertThat(column.getDisplayColors(job, coverage).getLineColor()) .isEqualTo(Color.white); }); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java index be45a8d5..35373251 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/CoveragePluginITest.java @@ -158,8 +158,8 @@ private static void verifyJaCoCoAction(final CoverageBuildAction coverageResult) .containsExactly(Metric.LINE, Metric.BRANCH, Metric.MUTATION, Metric.COMPLEXITY_DENSITY, Metric.LOC); assertThat(coverageResult.getAllValues(Baseline.PROJECT)) .contains(createLineCoverageBuilder() - .setCovered(JACOCO_ANALYSIS_MODEL_COVERED) - .setMissed(JACOCO_ANALYSIS_MODEL_TOTAL - JACOCO_ANALYSIS_MODEL_COVERED) + .withCovered(JACOCO_ANALYSIS_MODEL_COVERED) + .withMissed(JACOCO_ANALYSIS_MODEL_TOTAL - JACOCO_ANALYSIS_MODEL_COVERED) .build()); } @@ -192,8 +192,8 @@ private void verifyTwoJacocoResults(final ParameterizedJob project) { CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getAllValues(Baseline.PROJECT)) .contains(createLineCoverageBuilder() - .setCovered(JACOCO_ANALYSIS_MODEL_COVERED + JACOCO_CODING_STYLE_COVERED) - .setMissed(JACOCO_ANALYSIS_MODEL_MISSED + JACOCO_CODING_STYLE_MISSED) + .withCovered(JACOCO_ANALYSIS_MODEL_COVERED + JACOCO_CODING_STYLE_COVERED) + .withMissed(JACOCO_ANALYSIS_MODEL_MISSED + JACOCO_CODING_STYLE_MISSED) .build()); } @@ -225,9 +225,11 @@ private void verifyOneCoberturaResult(final ParameterizedJob project) { } private static void verifyCoberturaAction(final CoverageBuildAction coverageResult) { - assertThat(coverageResult.getAllValues(Baseline.PROJECT)) - .contains(new CoverageBuilder().setMetric(Metric.LINE).setCovered(COBERTURA_COVERED_LINES) - .setMissed(COBERTURA_MISSED_LINES) + assertThat(coverageResult.getAllValues(Baseline.PROJECT)).contains( + new CoverageBuilder() + .withMetric(Metric.LINE) + .withCovered(COBERTURA_COVERED_LINES) + .withMissed(COBERTURA_MISSED_LINES) .build()); } @@ -292,8 +294,8 @@ private void verifyForOneCoberturaAndOneJacoco(final ParameterizedJob proj CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getAllValues(Baseline.PROJECT)) .contains(createLineCoverageBuilder() - .setCovered(JACOCO_ANALYSIS_MODEL_COVERED + COBERTURA_COVERED_LINES) - .setMissed(JACOCO_ANALYSIS_MODEL_MISSED) + .withCovered(JACOCO_ANALYSIS_MODEL_COVERED + COBERTURA_COVERED_LINES) + .withMissed(JACOCO_ANALYSIS_MODEL_MISSED) .build()); } @@ -318,7 +320,7 @@ private void verifyOnePitResult(final ParameterizedJob project) { } private static CoverageBuilder createLineCoverageBuilder() { - return new CoverageBuilder().setMetric(Metric.LINE); + return new CoverageBuilder(Metric.LINE); } @Test diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java index ce21ae9d..f9dfa4d8 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/DeltaComputationITest.java @@ -107,13 +107,13 @@ private void verifyPitDelta(final CoverageBuildAction pit) { private void verifyPitProjectValues(final CoverageBuildAction pit) { CoverageBuilder builder = new CoverageBuilder(); assertThat(pit.getAllValues(Baseline.PROJECT)).contains( - builder.setMetric(LINE) - .setCovered(198) - .setMissed(211 - 198) + builder.withMetric(LINE) + .withCovered(198) + .withMissed(211 - 198) .build(), - builder.setMetric(MUTATION) - .setCovered(222) - .setMissed(246 - 222) + builder.withMetric(MUTATION) + .withCovered(222) + .withMissed(246 - 222) .build(), new LinesOfCode(211)); } @@ -123,13 +123,13 @@ private static void verifyFirstBuild(final Run firstBuild) { var builder = new CoverageBuilder(); assertThat(action.getAllValues(Baseline.PROJECT)).contains( - builder.setMetric(LINE) - .setCovered(JACOCO_ANALYSIS_MODEL_COVERED + JACOCO_CODING_STYLE_COVERED) - .setMissed(JACOCO_ANALYSIS_MODEL_MISSED + JACOCO_CODING_STYLE_MISSED) + builder.withMetric(LINE) + .withCovered(JACOCO_ANALYSIS_MODEL_COVERED + JACOCO_CODING_STYLE_COVERED) + .withMissed(JACOCO_ANALYSIS_MODEL_MISSED + JACOCO_CODING_STYLE_MISSED) .build(), - builder.setMetric(BRANCH) - .setCovered(1544 + 109) - .setMissed(1865 - (1544 + 109)) + builder.withMetric(BRANCH) + .withCovered(1544 + 109) + .withMissed(1865 - (1544 + 109)) .build(), new LinesOfCode(JACOCO_ANALYSIS_MODEL_TOTAL + JACOCO_CODING_STYLE_TOTAL), new CyclomaticComplexity(2718)); @@ -138,13 +138,13 @@ private static void verifyFirstBuild(final Run firstBuild) { private void verifyJaCoCoProjectValues(final CoverageBuildAction action) { var builder = new CoverageBuilder(); assertThat(action.getAllValues(Baseline.PROJECT)).contains( - builder.setMetric(LINE) - .setCovered(JACOCO_CODING_STYLE_COVERED) - .setMissed(JACOCO_CODING_STYLE_MISSED) + builder.withMetric(LINE) + .withCovered(JACOCO_CODING_STYLE_COVERED) + .withMissed(JACOCO_CODING_STYLE_MISSED) .build(), - builder.setMetric(BRANCH) - .setCovered(109) - .setMissed(7) + builder.withMetric(BRANCH) + .withCovered(109) + .withMissed(7) .build(), new LinesOfCode(JACOCO_CODING_STYLE_TOTAL), new CyclomaticComplexity(160)); diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java index 12880618..fd852976 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/GitForensicsITest.java @@ -98,7 +98,7 @@ void shouldComputeDeltaInPipelineOnDockerAgent(final SourceCodeRetention sourceC "PROJECT, 60, 56.46", "PROJECT_DELTA, 1, 0.72", "MODIFIED_FILES, 60, 54.55", - "MODIFIED_FILES_DELTA, -1, -1.91", + "MODIFIED_FILES_DELTA, 5, +4.55", "MODIFIED_LINES, 60, 50.00", "MODIFIED_LINES_DELTA, -1, -4.55" }) @@ -121,6 +121,8 @@ void shouldVerifyQualityGate(final Baseline baseline, final double threshold, fi project.setDefinition(createPipelineForCommit(node, COMMIT, JACOCO_FILE, SourceCodeRetention.EVERY_BUILD, qualityGate)); Run build = buildWithResult(project, Result.UNSTABLE); + verifyCoverage(build.getAction(CoverageBuildAction.class), referenceBuild.getAction(CoverageBuildAction.class)); + assertThat(getConsoleLog(build)) .contains("[Coverage] -> Some quality gates have been missed: overall result is UNSTABLE"); if (baseline == Baseline.PROJECT_DELTA @@ -196,12 +198,6 @@ private void verifyGitIntegration(final Run build, final Run referen verifyCoverage(action, referenceBuild.getAction(CoverageBuildAction.class)); } - /** - * Verifies the calculated coverage for the most important metrics line and branch coverage. - * - * @param action - * The created Jenkins action - */ private void verifyCoverage(final CoverageBuildAction action, final CoverageBuildAction reference) { verifyOverallCoverage(action); verifyModifiedFilesCoverage(action, reference); @@ -225,16 +221,22 @@ private void verifyModifiedFilesCoverage(final CoverageBuildAction action, final Coverage.valueOf(LINE, "12/22"), Coverage.valueOf(BRANCH, "1/2"), new LinesOfCode(22)); - // FIXME: Modified files delta with respect to reference build needs to be computed first -// assertThat(action.getAllDeltas(Baseline.MODIFIED_FILES_DELTA)).contains( -// entry(LINE, Fraction.getFraction("-394/20614")), -// entry(BRANCH, Fraction.getFraction("-21/230")), -// entry(LOC, Fraction.getFraction("--915/1"))); + var affectedFiles = action.getResult().filterByModifiedFiles().getFiles(); + assertThat(reference.getResult().filterByFileNames(affectedFiles).aggregateValues()).contains( + Coverage.valueOf(LINE, "17/34"), + Coverage.valueOf(BRANCH, "1/2"), + new LinesOfCode(34)); + assertThat(action.getAllDeltas(Baseline.MODIFIED_FILES_DELTA)).contains( + entry(LINE, Fraction.getFraction("17/374")), + entry(BRANCH, Fraction.getFraction("0/1")), + entry(LOC, Fraction.getFraction("-12/1"))); } private void verifyModifiedLinesCoverage(final CoverageBuildAction action) { assertThat(action.getAllValues(Baseline.MODIFIED_LINES)).contains( - Coverage.valueOf(LINE, "1/1")); + Coverage.valueOf(LINE, "1/2")); + assertThat(action.getAllDeltas(Baseline.MODIFIED_LINES_DELTA)).contains( + entry(LINE, Fraction.getFraction("-1/22"))); } private void verifyIndirectCoverageChanges(final CoverageBuildAction action) { diff --git a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/QualityGateITest.java b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/QualityGateITest.java index 89909b10..6a8662ed 100644 --- a/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/QualityGateITest.java +++ b/plugin/src/test/java/io/jenkins/plugins/coverage/metrics/steps/QualityGateITest.java @@ -37,6 +37,22 @@ void shouldNotHaveQualityGate() { CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getQualityGateResult()).hasOverallStatus(QualityGateStatus.INACTIVE); + assertThat(coverageResult.getLog().getInfoMessages()).contains("No quality gates have been set - skipping"); + } + + @Test + void shouldNotHaveValuesForQualityGate() { + var qualityGates = List.of(new CoverageQualityGate(-100.0, Metric.LINE, Baseline.PROJECT_DELTA, QualityGateCriticality.UNSTABLE)); + FreeStyleProject project = createFreestyleJob(Parser.JACOCO, r -> r.setQualityGates(qualityGates), JACOCO_ANALYSIS_MODEL_FILE); + + Run build = buildWithResult(project, Result.SUCCESS); + + CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); + assertThat(coverageResult.getQualityGateResult()).hasOverallStatus(QualityGateStatus.INACTIVE); + assertThat(coverageResult.getLog().getInfoMessages()).contains("Evaluating quality gates", + "-> All quality gates have been passed", + "-> Details for each quality gate:", + "-> [Overall project (difference to reference job) - Line Coverage]: ≪Not built≫ - (Actual value: n/a, Quality gate: -100.00)"); } @Test @@ -48,6 +64,10 @@ void shouldPassQualityGate() { CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getQualityGateResult()).hasOverallStatus(QualityGateStatus.PASSED); + assertThat(coverageResult.getLog().getInfoMessages()).contains("Evaluating quality gates", + "-> All quality gates have been passed", + "-> Details for each quality gate:", + "-> [Overall project - Line Coverage]: ≪Success≫ - (Actual value: 95.39%, Quality gate: -100.00)"); } @Test @@ -59,6 +79,10 @@ void shouldFailQualityGateWithUnstable() { CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getQualityGateResult()).hasOverallStatus(QualityGateStatus.WARNING); + assertThat(coverageResult.getLog().getInfoMessages()).contains("Evaluating quality gates", + "-> Some quality gates have been missed: overall result is UNSTABLE", + "-> Details for each quality gate:", + "-> [Overall project - Line Coverage]: ≪Unstable≫ - (Actual value: 95.39%, Quality gate: 100.00)"); } @Test @@ -70,6 +94,10 @@ void shouldFailQualityGateWithFailure() { CoverageBuildAction coverageResult = build.getAction(CoverageBuildAction.class); assertThat(coverageResult.getQualityGateResult()).hasOverallStatus(QualityGateStatus.FAILED); + assertThat(coverageResult.getLog().getInfoMessages()).contains("Evaluating quality gates", + "-> Some quality gates have been missed: overall result is FAILURE", + "-> Details for each quality gate:", + "-> [Overall project - Line Coverage]: ≪Failed≫ - (Actual value: 95.39%, Quality gate: 100.00)"); } @Test