Issue

  • The tests in org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsIntegrationTests, specifically requestMappingIsInstrumented() and restTemplateIsInstrumented() are not idempotent, since they pollute the state registry
  • This might fail future tests that share the same state similar to https://github.com/spring-projects/spring-boot/issues/38363
  • AssertionFailedError log when restTemplateIsInstrumented was run twice in the same JVM
org.opentest4j.AssertionFailedError: 
expected: 1L
 but was: 2L
    at java.base@17.0.9/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base@17.0.9/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
    at java.base@17.0.9/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base@17.0.9/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsIntegrationTests.restTemplateIsInstrumented(MetricsIntegrationTests.java:111)
  • AssertionFailedError log when requestMappingIsInstrumented was run twice in the same JVM
org.awaitility.core.ConditionTimeoutException: Assertion condition defined as a org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsIntegrationTests 
expected: 1L
 but was: 2L within 5 seconds.
    at app//org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
    at app//org.awaitility.core.AssertionCondition.await(AssertionCondition.java:119)
    at app//org.awaitility.core.AssertionCondition.await(AssertionCondition.java:31)
    at app//org.awaitility.core.ConditionFactory.until(ConditionFactory.java:985)
    at app//org.awaitility.core.ConditionFactory.untilAsserted(ConditionFactory.java:769)
    at app//org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsIntegrationTests.requestMappingIsInstrumented(MetricsIntegrationTests.java:118)

Cause

  • Each of the above mentioned tests pollutes the shared state registry across test runs, which causes the second test run to fail for assertions on the registry's timer count
  • https://github.com/spring-projects/spring-boot/blob/212b80a04cbd213fcd77a9ba65663d8312fa8780/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java#L110
  • https://github.com/spring-projects/spring-boot/blob/212b80a04cbd213fcd77a9ba65663d8312fa8780/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/test/MetricsIntegrationTests.java#L117
  • It's better to clear this polluted state preemptively, so that future tests that use the same state will not fail.

Steps to reproduce

  • Run each of the above mentioned test twice in the same JVM using @RepeatedTest(2)

Proposed Fix

  • Since the registry's timer state is polluted across different runs, I have reset the registry state before each test run
  • Added a setUp() with @BeforeEach where the registry state is cleared using this.registry.clear()

Comment From: mhalbritter

Thanks for the analysis! I've fixed that.