From 18ac23214fc038ce5b2a5bcd5719ed5cd7564c6e Mon Sep 17 00:00:00 2001 From: waschndolos Date: Sat, 6 Jan 2024 08:55:44 +0100 Subject: [PATCH 1/4] Adding test for Runs --- .../plugins/prometheus/util/Runs.java | 10 -- .../plugins/prometheus/util/RunsTest.java | 114 ++++++++++++++++++ 2 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 src/test/java/org/jenkinsci/plugins/prometheus/util/RunsTest.java diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/util/Runs.java b/src/main/java/org/jenkinsci/plugins/prometheus/util/Runs.java index 52f4de9eb..9cce9ea46 100644 --- a/src/main/java/org/jenkinsci/plugins/prometheus/util/Runs.java +++ b/src/main/java/org/jenkinsci/plugins/prometheus/util/Runs.java @@ -34,16 +34,6 @@ public static boolean includeBuildInMetrics(Run build) { return include; } - public static String getResultText(Run run) { - if (run != null) { - Result result = run.getResult(); - if (result != null) { - return result.toString(); - } - } - return null; - } - public static Map getBuildParameters(Run build) { List actions = build.getActions(ParametersAction.class); Map answer = new HashMap<>(); diff --git a/src/test/java/org/jenkinsci/plugins/prometheus/util/RunsTest.java b/src/test/java/org/jenkinsci/plugins/prometheus/util/RunsTest.java new file mode 100644 index 000000000..481a4b830 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/prometheus/util/RunsTest.java @@ -0,0 +1,114 @@ +package org.jenkinsci.plugins.prometheus.util; + +import hudson.model.ParameterValue; +import hudson.model.ParametersAction; +import hudson.model.Result; +import hudson.model.Run; +import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class RunsTest { + + @Mock + Run mockedRun; + + @Test + void testIncludeBuildMetricsReturnsFalseIfRunIsBuilding() { + when(mockedRun.isBuilding()).thenReturn(true); + + boolean include = Runs.includeBuildInMetrics(mockedRun); + assertFalse(include); + } + + @Test + void testGetBuildParametersWontFailIfNoActionsAvailable() { + when(mockedRun.getActions(ParametersAction.class)).thenReturn(List.of()); + + Map parameters = Runs.getBuildParameters(mockedRun); + assertEquals(0, parameters.size()); + } + + @Test + void testGetBuildParametersWontFailIfParameterValueIsNull() { + ParameterValue parameterValue = mock(ParameterValue.class); + when(parameterValue.getName()).thenReturn("failBuildOnError"); + when(parameterValue.getValue()).thenReturn(true); + ParametersAction action = new ParametersAction(parameterValue); + when(mockedRun.getActions(ParametersAction.class)).thenReturn(List.of(action)); + + Map parameters = Runs.getBuildParameters(mockedRun); + assertEquals(1, parameters.size()); + + + assertEquals(true, parameters.get("failBuildOnError")); + } + + @ParameterizedTest + @MethodSource("provideBuildResults") + void testIncludeBuildMetrics(Result result) { + when(mockedRun.isBuilding()).thenReturn(false); + when(mockedRun.getResult()).thenReturn(result); + try (MockedStatic prometheusConfigurationStatic = mockStatic(PrometheusConfiguration.class)) { + + + PrometheusConfiguration configuration = getPrometheusConfigurationForTest(result, true); + prometheusConfigurationStatic.when(PrometheusConfiguration::get).thenReturn(configuration); + + boolean include = Runs.includeBuildInMetrics(mockedRun); + assertTrue(include, "Run is aborted and Prometheus is configured to return results for these builds"); + + configuration = getPrometheusConfigurationForTest(result, false); + prometheusConfigurationStatic.when(PrometheusConfiguration::get).thenReturn(configuration); + + include = Runs.includeBuildInMetrics(mockedRun); + assertFalse(include, "Run is aborted and Prometheus is not configured to return results for these builds"); + } + } + + + + private static Stream provideBuildResults() { + return Stream.of( + Arguments.of(Result.ABORTED), + Arguments.of(Result.FAILURE), + Arguments.of(Result.NOT_BUILT), + Arguments.of(Result.SUCCESS), + Arguments.of(Result.UNSTABLE) + ); + } + + private PrometheusConfiguration getPrometheusConfigurationForTest(Result result, boolean prometheusPluginConfiguredToReturn) { + PrometheusConfiguration mockedPrometheusConfiguration = mock(PrometheusConfiguration.class); + if (Result.ABORTED.equals(result)) { + when(mockedPrometheusConfiguration.isCountAbortedBuilds()).thenReturn(prometheusPluginConfiguredToReturn); + } + if (Result.FAILURE.equals(result)) { + when(mockedPrometheusConfiguration.isCountFailedBuilds()).thenReturn(prometheusPluginConfiguredToReturn); + } + if (Result.NOT_BUILT.equals(result)) { + when(mockedPrometheusConfiguration.isCountNotBuiltBuilds()).thenReturn(prometheusPluginConfiguredToReturn); + } + if (Result.SUCCESS.equals(result)) { + when(mockedPrometheusConfiguration.isCountSuccessfulBuilds()).thenReturn(prometheusPluginConfiguredToReturn); + } + if (Result.UNSTABLE.equals(result)) { + when(mockedPrometheusConfiguration.isCountUnstableBuilds()).thenReturn(prometheusPluginConfiguredToReturn); + } + return mockedPrometheusConfiguration; + } +} \ No newline at end of file From 8517fb0cb0afa09bed8e8f8ea8525f655f69c84c Mon Sep 17 00:00:00 2001 From: waschndolos Date: Sat, 6 Jan 2024 09:17:34 +0100 Subject: [PATCH 2/4] Removing unnecessary null check --- .../jenkinsci/plugins/prometheus/CodeCoverageCollector.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollector.java b/src/main/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollector.java index 7040e4e7a..cb606276f 100644 --- a/src/main/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollector.java +++ b/src/main/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollector.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.stream.Collectors; -public class CodeCoverageCollector extends BaseCollector { +public class CodeCoverageCollector extends Collector { private static final Logger LOGGER = LoggerFactory.getLogger(CodeCoverageCollector.class); @@ -44,9 +44,6 @@ public List collect() { } private List collectCoverageMetricForJob(Job job) { - if (job == null) { - return Collections.emptyList(); - } Run lastBuild = job.getLastBuild(); if (lastBuild == null || lastBuild.isBuilding()) { From 7b764b045a8e06cbe327b4dc8dcd6ee32a16de3b Mon Sep 17 00:00:00 2001 From: waschndolos Date: Sat, 6 Jan 2024 09:29:09 +0100 Subject: [PATCH 3/4] Removing unused class + adding tests for CodeCoverageCollector --- .../plugins/prometheus/BaseCollector.java | 19 --- .../prometheus/CodeCoverageCollectorTest.java | 138 ++++++++++++++++++ 2 files changed, 138 insertions(+), 19 deletions(-) delete mode 100644 src/main/java/org/jenkinsci/plugins/prometheus/BaseCollector.java create mode 100644 src/test/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollectorTest.java diff --git a/src/main/java/org/jenkinsci/plugins/prometheus/BaseCollector.java b/src/main/java/org/jenkinsci/plugins/prometheus/BaseCollector.java deleted file mode 100644 index 571733658..000000000 --- a/src/main/java/org/jenkinsci/plugins/prometheus/BaseCollector.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.jenkinsci.plugins.prometheus; - -import io.prometheus.client.Collector; -import io.prometheus.client.Gauge; -import org.jenkinsci.plugins.prometheus.util.ConfigurationUtils; - -public abstract class BaseCollector extends Collector { - - - protected static Gauge.Builder newGaugeBuilder(String... labels) { - return newGaugeBuilder().labelNames(labels); - } - - protected static Gauge.Builder newGaugeBuilder() { - return Gauge.build() - .namespace(ConfigurationUtils.getNamespace()) - .subsystem(ConfigurationUtils.getSubSystem()); - } -} diff --git a/src/test/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollectorTest.java b/src/test/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollectorTest.java new file mode 100644 index 000000000..14d762939 --- /dev/null +++ b/src/test/java/org/jenkinsci/plugins/prometheus/CodeCoverageCollectorTest.java @@ -0,0 +1,138 @@ +package org.jenkinsci.plugins.prometheus; + +import hudson.Plugin; +import hudson.model.Item; +import hudson.model.Job; +import hudson.model.Run; +import io.jenkins.plugins.coverage.metrics.steps.CoverageBuildAction; +import io.prometheus.client.Collector; +import jenkins.model.Jenkins; +import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration; +import org.jenkinsci.plugins.prometheus.util.ConfigurationUtils; +import org.jenkinsci.plugins.prometheus.util.Jobs; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + + +@ExtendWith(MockitoExtension.class) +class CodeCoverageCollectorTest { + + @Mock + private Jenkins jenkins; + + @Mock + private PrometheusConfiguration config; + + @Test + void shouldNotProduceMetricsWhenNoCoveragePluginDetected() { + try (MockedStatic jenkinsStatic = mockStatic(Jenkins.class)) { + jenkinsStatic.when(Jenkins::get).thenReturn(jenkins); + when(jenkins.getPlugin("coverage")).thenReturn(null); + CodeCoverageCollector sut = new CodeCoverageCollector(); + + List collect = sut.collect(); + assertEquals(0, collect.size()); + } + } + + @Test + void shouldNotProduceMetricsWhenItIsNotConfigured() { + try ( + MockedStatic jenkinsStatic = mockStatic(Jenkins.class); + MockedStatic configurationStatic = mockStatic(PrometheusConfiguration.class) + ) { + jenkinsStatic.when(Jenkins::get).thenReturn(jenkins); + configurationStatic.when(PrometheusConfiguration::get).thenReturn(config); + when(jenkins.getPlugin("coverage")).thenReturn(new Plugin.DummyImpl()); + when(config.isCollectCodeCoverage()).thenReturn(false); + + CodeCoverageCollector sut = new CodeCoverageCollector(); + + List collect = sut.collect(); + assertEquals(0, collect.size()); + } + } + + @Test + void shouldNotProduceMetricsWhenJobIsBuilding() { + try ( + MockedStatic jenkinsStatic = mockStatic(Jenkins.class); + MockedStatic configurationStatic = mockStatic(PrometheusConfiguration.class); + ) { + jenkinsStatic.when(Jenkins::get).thenReturn(jenkins); + configurationStatic.when(PrometheusConfiguration::get).thenReturn(config); + Job jobUnderTest = mock(Job.class); + Run lastBuild = mock(Run.class); + when(lastBuild.isBuilding()).thenReturn(true); + when(jobUnderTest.getLastBuild()).thenReturn(lastBuild); + when(jenkins.getAllItems(Job.class)).thenReturn(List.of(jobUnderTest)); + when(jenkins.getPlugin("coverage")).thenReturn(new Plugin.DummyImpl()); + when(config.isCollectCodeCoverage()).thenReturn(true); + + CodeCoverageCollector sut = new CodeCoverageCollector(); + + List collect = sut.collect(); + assertEquals(0, collect.size()); + } + } + + @Test + void shouldNotProduceMetricsWhenJobHasNoCoverageBuildAction() { + try ( + MockedStatic jenkinsStatic = mockStatic(Jenkins.class); + MockedStatic configurationStatic = mockStatic(PrometheusConfiguration.class); + ) { + jenkinsStatic.when(Jenkins::get).thenReturn(jenkins); + configurationStatic.when(PrometheusConfiguration::get).thenReturn(config); + Job jobUnderTest = mock(Job.class); + Run lastBuild = mock(Run.class); + when(lastBuild.isBuilding()).thenReturn(false); + when(jobUnderTest.getLastBuild()).thenReturn(lastBuild); + when(jenkins.getAllItems(Job.class)).thenReturn(List.of(jobUnderTest)); + when(jenkins.getPlugin("coverage")).thenReturn(new Plugin.DummyImpl()); + when(config.isCollectCodeCoverage()).thenReturn(true); + + CodeCoverageCollector sut = new CodeCoverageCollector(); + + List collect = sut.collect(); + assertEquals(0, collect.size()); + } + } + + @Test + void shouldProduceMetricsWhenJobHasCoverageBuildAction() { + try ( + MockedStatic jenkinsStatic = mockStatic(Jenkins.class); + MockedStatic configurationStatic = mockStatic(PrometheusConfiguration.class); + MockedStatic configurationUtils = mockStatic(ConfigurationUtils.class); + ) { + configurationUtils.when(ConfigurationUtils::getNamespace).thenReturn("foo"); + configurationUtils.when(ConfigurationUtils::getSubSystem).thenReturn("bar"); + jenkinsStatic.when(Jenkins::get).thenReturn(jenkins); + configurationStatic.when(PrometheusConfiguration::get).thenReturn(config); + Job jobUnderTest = mock(Job.class); + Run lastBuild = mock(Run.class); + when(lastBuild.isBuilding()).thenReturn(false); + when(jobUnderTest.getLastBuild()).thenReturn(lastBuild); + CoverageBuildAction action = mock(CoverageBuildAction.class); + when(lastBuild.getAction(CoverageBuildAction.class)).thenReturn(action); + when(jenkins.getAllItems(Job.class)).thenReturn(List.of(jobUnderTest)); + when(jenkins.getPlugin("coverage")).thenReturn(new Plugin.DummyImpl()); + when(config.getJobAttributeName()).thenReturn("jenkins_job"); + when(config.isCollectCodeCoverage()).thenReturn(true); + + CodeCoverageCollector sut = new CodeCoverageCollector(); + + List collect = sut.collect(); + assertEquals(12, collect.size(), "12 metrics should have been collected"); + } + } +} \ No newline at end of file From c81a99d50a84f8f283adc6ebc242dcf780ec89d3 Mon Sep 17 00:00:00 2001 From: waschndolos Date: Sat, 6 Jan 2024 09:47:00 +0100 Subject: [PATCH 4/4] further tests --- .../service/PrometheusAsyncWorkerTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/test/java/org/jenkinsci/plugins/prometheus/service/PrometheusAsyncWorkerTest.java b/src/test/java/org/jenkinsci/plugins/prometheus/service/PrometheusAsyncWorkerTest.java index 57065871a..a8c120e14 100644 --- a/src/test/java/org/jenkinsci/plugins/prometheus/service/PrometheusAsyncWorkerTest.java +++ b/src/test/java/org/jenkinsci/plugins/prometheus/service/PrometheusAsyncWorkerTest.java @@ -1,11 +1,21 @@ package org.jenkinsci.plugins.prometheus.service; +import hudson.Plugin; +import io.prometheus.client.Collector; +import jenkins.model.Jenkins; +import org.jenkinsci.plugins.prometheus.CodeCoverageCollector; +import org.jenkinsci.plugins.prometheus.config.PrometheusConfiguration; import org.junit.jupiter.api.Test; +import org.jvnet.hudson.test.Issue; +import org.mockito.MockedStatic; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; public class PrometheusAsyncWorkerTest { @@ -25,6 +35,26 @@ public void shouldCollectMetrics() { assertEquals("1", actual); } + @Test + public void testConvertSecondsToMillis() { + try (MockedStatic configurationStatic = mockStatic(PrometheusConfiguration.class)) { + + PrometheusConfiguration config = mock(PrometheusConfiguration.class); + configurationStatic.when(PrometheusConfiguration::get).thenReturn(config); + when(config.getCollectingMetricsPeriodInSeconds()).thenReturn(12345L); + PrometheusAsyncWorker sut = new PrometheusAsyncWorker(); + long recurrencePeriod = sut.getRecurrencePeriod(); + assertEquals(12345000L, recurrencePeriod); + } + } + + @Test + @Issue("#157") + public void ensureLoggingLevel() { + PrometheusAsyncWorker sut = new PrometheusAsyncWorker(); + Level level = sut.getNormalLoggingLevel(); + assertEquals(Level.FINE, level); + } private static class TestPrometheusMetrics implements PrometheusMetrics { private final AtomicReference cachedMetrics = new AtomicReference<>("");