Skip to content

Commit 98e8016

Browse files
committed
Test Micrometer config to property exposure
1 parent 3c70189 commit 98e8016

20 files changed

+227
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.springframework.boot.actuate.autoconfigure.metrics.export;
2+
3+
import java.lang.reflect.Method;
4+
import java.time.Duration;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.List;
8+
import java.util.stream.Collectors;
9+
10+
import org.apache.commons.lang3.ClassUtils;
11+
import org.junit.Assert;
12+
13+
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.PropertiesConfigAdapter;
14+
15+
public class TestConfigsToPropertiesExposure {
16+
/**
17+
* Assertion to test if default methods of a given config are overridden by the adapter which implements it.
18+
* This can be an indicator for micrometer config fields, that have been forgotten to expose via spring properties.
19+
* Not overridden default methods in adapters are the most common cause of forgotten field exposure, because
20+
* they do not for force an override.
21+
*
22+
* @param config micrometer config
23+
* @param adapter adapter for properties {@link PropertiesConfigAdapter}
24+
* @param excludedConfigMethods config methods that should be excluded for the assertion
25+
*/
26+
public static void assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(Class<?> config, Class<? extends PropertiesConfigAdapter<?>> adapter, String... excludedConfigMethods) {
27+
List<String> configDefaultMethodNames = Arrays.stream(config.getDeclaredMethods())
28+
.filter(method -> method.isDefault() && isSettableUsingProperties(method.getReturnType()))
29+
.map(Method::getName)
30+
.collect(Collectors.toList());
31+
32+
configDefaultMethodNames.removeAll(Arrays.stream(excludedConfigMethods).toList());
33+
List<String> notOverriddenDefaultMethods = new ArrayList<>(configDefaultMethodNames);
34+
35+
Class<?> currentClass = adapter;
36+
// loop through adapter class and superclasses to find not overridden config methods
37+
while (!Object.class.equals(currentClass)) {
38+
List<String> overriddenClassDefaultMethods = Arrays.stream(currentClass.getDeclaredMethods())
39+
.map(Method::getName)
40+
.filter(configDefaultMethodNames::contains)
41+
.toList();
42+
43+
notOverriddenDefaultMethods.removeAll(overriddenClassDefaultMethods);
44+
currentClass = currentClass.getSuperclass();
45+
}
46+
47+
if (notOverriddenDefaultMethods.size() >= 1) {
48+
Assert.fail("Found config default methods that are not overridden by the related PropertiesConfigAdapter: \n"
49+
+ notOverriddenDefaultMethods + "\n"
50+
+ "This could be an indicator for not exposed properties fields.\n"
51+
+ "Please check if the fields are meant to be exposed and if not, "
52+
+ "exclude them from this test by providing them to the method.");
53+
}
54+
}
55+
56+
/**
57+
* Guess if a class can be set using properties.
58+
* This will only catch the basic use cases regarding the micrometer configs to
59+
* filter out methods that are not likely to be designed to be set via properties.
60+
* <pre>
61+
* isSettableUsingProperties(String.class) = true
62+
* isSettableUsingProperties(boolean.class) = true
63+
* isSettableUsingProperties(Object.class) = false
64+
* </pre>
65+
*
66+
* @param clazz Class
67+
* @return is likely to be settable using properties
68+
*/
69+
private static boolean isSettableUsingProperties(Class<?> clazz) {
70+
if (Void.TYPE.equals(clazz)) {
71+
return false;
72+
}
73+
74+
if (ClassUtils.isPrimitiveOrWrapper(clazz)) {
75+
return true;
76+
}
77+
78+
return List.of(Duration.class, String.class).contains(clazz);
79+
}
80+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/appoptics/AppOpticsPropertiesConfigAdapterTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,13 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.appoptics;
1818

19+
import io.micrometer.appoptics.AppOpticsConfig;
1920
import org.junit.jupiter.api.Test;
2021

2122
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapterTests;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link AppOpticsPropertiesConfigAdapter}.
@@ -68,4 +70,9 @@ void whenPropertiesFloorTimesIsSetAdapterFloorTimesReturnsIt() {
6870
assertThat(createConfigAdapter(properties).floorTimes()).isTrue();
6971
}
7072

73+
@Test
74+
void allDefaultConfigMethodsAreOverriddenByAtlasPropertiesConfigAdapter() {
75+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(AppOpticsConfig.class, AppOpticsPropertiesConfigAdapter.class,
76+
"connectTimeout");
77+
}
7178
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/atlas/AtlasPropertiesConfigAdapterTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import java.time.Duration;
2020

21+
import com.netflix.spectator.atlas.AtlasConfig;
2122
import org.junit.jupiter.api.Test;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link AtlasPropertiesConfigAdapter}.
@@ -121,4 +123,10 @@ void whenPropertiesEvalUriIsSetAdapterEvalUriReturnsIt() {
121123
assertThat(createConfigAdapter(properties).evalUri()).isEqualTo("https://atlas.example.com/evaluate");
122124
}
123125

126+
@Test
127+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
128+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(AtlasConfig.class, AtlasPropertiesConfigAdapter.class,
129+
"lwcIgnorePublishStep", "initialPollingDelay", "autoStart", "lwcStep", "validTagCharacters");
130+
}
131+
124132
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/datadog/DatadogPropertiesConfigAdapterTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.datadog;
1818

19+
import io.micrometer.datadog.DatadogConfig;
1920
import org.junit.jupiter.api.Test;
2021

2122
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapterTests;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link DatadogPropertiesConfigAdapter}.
@@ -76,4 +78,10 @@ void whenPropertiesUriIsSetAdapterUriReturnsIt() {
7678
assertThat(createConfigAdapter(properties).uri()).isEqualTo("https://app.example.com/api/v1/series");
7779
}
7880

81+
@Test
82+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
83+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(DatadogConfig.class,
84+
DatadogPropertiesConfigAdapter.class);
85+
}
86+
7987
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/dynatrace/DynatracePropertiesConfigAdapterTests.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2022 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,9 +19,11 @@
1919
import java.util.HashMap;
2020

2121
import io.micrometer.dynatrace.DynatraceApiVersion;
22+
import io.micrometer.dynatrace.DynatraceConfig;
2223
import org.junit.jupiter.api.Test;
2324

2425
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2527

2628
/**
2729
* Tests for {@link DynatracePropertiesConfigAdapter}.
@@ -125,4 +127,9 @@ void defaultValues() {
125127
assertThat(properties.getV2().isUseDynatraceSummaryInstruments()).isTrue();
126128
}
127129

130+
@Test
131+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
132+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(DynatraceConfig.class, DynatracePropertiesConfigAdapter.class,
133+
"documentType");
134+
}
128135
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/elastic/ElasticPropertiesConfigAdapterTests.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,9 +16,11 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.elastic;
1818

19+
import io.micrometer.elastic.ElasticConfig;
1920
import org.junit.jupiter.api.Test;
2021

2122
import static org.assertj.core.api.Assertions.assertThat;
23+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2224

2325
/**
2426
* Tests for {@link ElasticPropertiesConfigAdapter}.
@@ -97,4 +99,10 @@ void whenPropertiesApiKeyCredentialsIsSetAdapterPipelineReturnsIt() {
9799
assertThat(new ElasticPropertiesConfigAdapter(properties).apiKeyCredentials()).isEqualTo("secret");
98100
}
99101

102+
@Test
103+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
104+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(ElasticConfig.class, ElasticPropertiesConfigAdapter.class,
105+
"documentType"
106+
);
107+
}
100108
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/ganglia/GangliaPropertiesConfigAdapterTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
import java.util.concurrent.TimeUnit;
2121

2222
import info.ganglia.gmetric4j.gmetric.GMetric.UDPAddressingMode;
23+
import io.micrometer.ganglia.GangliaConfig;
2324
import org.junit.jupiter.api.Test;
2425

2526
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2628

2729
/**
2830
* Tests for {@link GangliaPropertiesConfigAdapter}.
@@ -88,4 +90,10 @@ void whenPropertiesPortIsSetAdapterPortReturnsIt() {
8890
assertThat(createConfigAdapter(properties).port()).isEqualTo(4242);
8991
}
9092

93+
@Test
94+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
95+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(GangliaConfig.class,
96+
GangliaPropertiesConfigAdapter.class, "protocolVersion");
97+
}
98+
9199
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/graphite/GraphitePropertiesConfigAdapterTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
import java.time.Duration;
2020
import java.util.concurrent.TimeUnit;
2121

22+
import io.micrometer.graphite.GraphiteConfig;
2223
import io.micrometer.graphite.GraphiteProtocol;
2324
import org.junit.jupiter.api.Test;
2425

2526
import static org.assertj.core.api.Assertions.assertThat;
27+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2628

2729
/**
2830
* Tests for {@link GraphitePropertiesConfigAdapter}.
@@ -102,4 +104,10 @@ void whenPropertiesTagsAsPrefixIsSetAdapterTagsAsPrefixReturnsIt() {
102104
assertThat(createConfigAdapter(properties).tagsAsPrefix()).isEqualTo(new String[] { "worker" });
103105
}
104106

107+
@Test
108+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
109+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(GraphiteConfig.class,
110+
GraphitePropertiesConfigAdapter.class);
111+
}
112+
105113
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/humio/HumioPropertiesConfigAdapterTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import java.util.Collections;
2020

21+
import io.micrometer.humio.HumioConfig;
2122
import org.junit.jupiter.api.Test;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link HumioPropertiesConfigAdapter}.
@@ -51,4 +53,9 @@ void whenPropertiesUriIsSetAdapterUriReturnsIt() {
5153
assertThat(new HumioPropertiesConfigAdapter(properties).uri()).isEqualTo("https://humio.example.com");
5254
}
5355

56+
@Test
57+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
58+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(HumioConfig.class, HumioPropertiesConfigAdapter.class,
59+
"connectTimeout");
60+
}
5461
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/influx/InfluxPropertiesConfigAdapterTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.influx;
1818

1919
import io.micrometer.influx.InfluxApiVersion;
20+
import io.micrometer.influx.InfluxConfig;
2021
import org.junit.jupiter.api.Test;
2122

2223
import static org.assertj.core.api.Assertions.assertThat;
24+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2325

2426
/**
2527
* Tests for {@link InfluxPropertiesConfigAdapter}.
@@ -58,4 +60,8 @@ void adaptInfluxV2BasicConfig() {
5860
assertThat(adapter.token()).isEqualTo("token");
5961
}
6062

63+
@Test
64+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
65+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(InfluxConfig.class, InfluxPropertiesConfigAdapter.class);
66+
}
6167
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/jmx/JmxPropertiesConfigAdapterTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import java.time.Duration;
2020

21+
import io.micrometer.jmx.JmxConfig;
2122
import org.junit.jupiter.api.Test;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link JmxPropertiesConfigAdapter}.
@@ -51,4 +53,9 @@ void whenPropertiesDomainIsSetAdapterDomainReturnsIt() {
5153
assertThat(createConfigAdapter(properties).domain()).isEqualTo("abc");
5254
}
5355

56+
@Test
57+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
58+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(JmxConfig.class, JmxPropertiesConfigAdapter.class);
59+
}
60+
5461
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/kairos/KairosPropertiesConfigAdapterTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.kairos;
1818

19+
import io.micrometer.kairos.KairosConfig;
1920
import org.junit.jupiter.api.Test;
2021

2122
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapterTests;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link KairosPropertiesConfigAdapter}.
@@ -62,4 +64,8 @@ void whenPropertiesPasswordIsSetAdapterPasswordReturnsIt() {
6264
assertThat(createConfigAdapter(properties).password()).isEqualTo("secret");
6365
}
6466

67+
@Test
68+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
69+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(KairosConfig.class, KairosPropertiesConfigAdapter.class);
70+
}
6571
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/newrelic/NewRelicPropertiesConfigAdapterTests.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
package org.springframework.boot.actuate.autoconfigure.metrics.export.newrelic;
1818

1919
import io.micrometer.newrelic.ClientProviderType;
20+
import io.micrometer.newrelic.NewRelicConfig;
2021
import org.junit.jupiter.api.Test;
2122

2223
import org.springframework.boot.actuate.autoconfigure.metrics.export.properties.StepRegistryPropertiesConfigAdapterTests;
2324

2425
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2527

2628
/**
2729
* Tests for {@link NewRelicPropertiesConfigAdapter}.
@@ -83,4 +85,10 @@ void whenPropertiesUriIsSetAdapterUriReturnsIt() {
8385
assertThat(createConfigAdapter(properties).uri()).isEqualTo("https://example.newrelic.com");
8486
}
8587

88+
@Test
89+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
90+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(NewRelicConfig.class,
91+
NewRelicPropertiesConfigAdapter.class);
92+
}
93+
8694
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/otlp/OtlpPropertiesConfigAdapterTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818

1919
import java.util.Map;
2020

21+
import io.micrometer.registry.otlp.OtlpConfig;
2122
import org.junit.jupiter.api.Test;
2223

2324
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.springframework.boot.actuate.autoconfigure.metrics.export.TestConfigsToPropertiesExposure.assertThatAllConfigDefaultMethodsAreOverriddenByAdapter;
2426

2527
/**
2628
* Tests for {@link OtlpPropertiesConfigAdapter}.
@@ -51,4 +53,8 @@ void whenPropertiesHeadersIsSetAdapterHeadersReturnsIt() {
5153
assertThat(new OtlpPropertiesConfigAdapter(properties).headers()).containsEntry("header", "value");
5254
}
5355

56+
@Test
57+
void allConfigDefaultMethodsAreOverriddenByAdapter() {
58+
assertThatAllConfigDefaultMethodsAreOverriddenByAdapter(OtlpConfig.class, OtlpPropertiesConfigAdapter.class);
59+
}
5460
}

0 commit comments

Comments
 (0)