In order to reduce the surface area of published APIs in the affected
classes, this commit:
- Reverts the changes made to GeneratedClasses in c354b1014d.
- Reverts the changes made to DefaultGenerationContext in a28ec3a0a8.
- Makes the DefaultGenerationContext(DefaultGenerationContext, String)
constructor protected.
- Reworks the internals of TestContextGenerationContext to align with
the above changes.
See gh-30861
Closes gh-30895
Closes gh-30897
Prior to this commit, test AOT processing failed if a feature name for
generated class names was used for more than one ApplicationContext.
For example, when generating code for org.example.MessageService with a
"Management" feature name, the "BeanDefinitions" class was named as
follows (without a uniquely identifying TestContext###_ feature name
prefix).
org/example/MessageService__ManagementBeanDefinitions.java
When another attempt was made to generate code for the MessageService
using the same "Management" feature name, a FileAlreadyExistsException
was thrown denoting that the class/file name was already in use.
To avoid such naming collisions, this commit introduces a
TestContextGenerationContext which provides a custom implementation of
withName(String) that prepends an existing feature name (if present) to
a new feature name, thereby treating any existing feature name as a
prefix to a new, nested feature name.
Consequently, code generation for the above example now results in
unique class/file names like the following (which retain the uniquely
identifying TestContext###_ prefixes).
org/example/MessageService__TestContext002_ManagementBeanDefinitions.java
org/example/MessageService__TestContext003_ManagementBeanDefinitions.java
Closes gh-30861
This commit introduces a `failOnError` flag in TestContextAotGenerator.
When set to `true`, any error encountered during AOT processing will
result in an exception that fails the overall process. When set to
`false` (the default), the previous behavior remains unchanged: a DEBUG
or WARN message will be logged, and processing will continue.
This feature is currently only used for internal testing.
See gh-30861
Closes gh-30898
This commit also reverts to using ReflectionUtils.findMethod in order
to make the check more robust in case the Micrometer team refactors the
code base and declares the `getObservationRegistry()` method in a super
type.
Prior to this commit, the required runtime dependencies were checked
via reflection each time an attempt was made to instantiate
MicrometerObservationRegistryTestExecutionListener.
Since it's sufficient to check for the presence of required runtime
dependencies only once, this commit caches the results of the
dependency checks in a static field.
This commit also introduces automated tests for the runtime dependency
checks in MicrometerObservationRegistryTestExecutionListener.
See gh-30747
Prior to this commit, dependency checks in the static initialization
block for MicrometerObservationRegistryTestExecutionListener resulted
in an ExceptionInInitializerError which led to verbose logging in
TestContextFailureHandler.
This commit improves the logging for missing dependencies in
MicrometerObservationRegistryTestExecutionListener by moving the
dependency checks to the constructor and by throwing a
NoClassDefFoundError instead of an IllegalStateException. This allows
TestContextFailureHandler to log a concise DEBUG message denoting that
the listener is being skipped due to missing dependencies.
This commit also now checks for the presence of
io.micrometer.context.ThreadLocalAccessor in addition to
io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor.
Furthermore, this commit now explicitly mentions the need for
io.micrometer:context-propagation in the error message.
The following demonstrate the generated DEBUB message when
ObservationThreadLocalAccessor and ThreadLocalAccessor are missing,
respectively.
Skipping candidate TestExecutionListener [org.springframework.test.context.observation.MicrometerObservationRegistryTestExecutionListener] due to a missing dependency. Specify custom TestExecutionListener classes or make the default TestExecutionListener classes and their required dependencies available. Offending class: io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor. MicrometerObservationRegistryTestExecutionListener requires io.micrometer:micrometer-observation:1.10.8 or higher and io.micrometer:context-propagation:1.0.3 or higher.
Skipping candidate TestExecutionListener [org.springframework.test.context.observation.MicrometerObservationRegistryTestExecutionListener] due to a missing dependency. Specify custom TestExecutionListener classes or make the default TestExecutionListener classes and their required dependencies available. Offending class: io.micrometer.context.ThreadLocalAccessor. MicrometerObservationRegistryTestExecutionListener requires io.micrometer:micrometer-observation:1.10.8 or higher and io.micrometer:context-propagation:1.0.3 or higher.
Closes gh-30747
In the original implementation of
MicrometerObservationRegistryTestExecutionListener I accidentally
imported JUnit 5's org.junit.platform.launcher.TestExecutionListener
instead Spring's
org.springframework.test.context.TestExecutionListener. The code
therefore attempts to use the ClassLoader for the JUnit Platform's
TestExecutionListener which may fail to see the required types. In
addition, if the JUnit Platform's TestExecutionListener is not on the
classpath, the attempt to access its ClassLoader will fail.
This commit addresses this by properly using the ClassLoader for
Spring's TestExecutionListener to detect dependencies of the
MicrometerObservationRegistryTestExecutionListener.
Closes gh-30726
This commit overhauls the TestExecutionListener for Micrometer's
ObservationRegistry that was introduced in the previous commit.
Specifically, this commit:
- Renames the listener to MicrometerObservationRegistryTestExecutionListener
since the use of a ThreadLocal is an implementation detail that may
change over time.
- Makes the listener package-private instead of public in order to
allow the team greater flexibility in evolving this feature.
- Eagerly loads the ObservationThreadLocalAccessor class and verifies
that it has a getObservationRegistry() method to ensure that the
listener is properly skipped when SpringFactoriesLoader attempts to
load it, if Micrometer 1.10.8+ is not on the classpath.
- Switches the listener's automatic registration order to 2500 in order
to register it after the DependencyInjectionTestExecutionListener.
- Only tracks the previous ObservationRegistry in beforeTestMethod() if
the test's ApplicationContext contains an ObservationRegistry bean.
- Properly removes the TestContext attribute for the previous
ObservationRegistry in afterTestMethod().
- Introduces DEBUG logging for diagnostics.
- Adds an entry in the Javadoc for TestExecutionListener as well as in
the Testing chapter in the reference manual.
Closes gh-30658
Prior to this commit, there was no way to specify the
ObservationRegistry that is registered in the given test's
ApplicationContext as the one that should be used by Micrometer's
ObservationThreadLocalAccessor for context propagation.
This commit introduces a TestExecutionListener for Micrometer's
ObservationRegistry in the Spring TestContext Framework. Specifically,
this listener obtains the ObservationRegistry registered in the test's
ApplicationContext, stores it in ObservationThreadLocalAccessor for the
duration of each test method execution, and restores the original
ObservationRegistry in ObservationThreadLocalAccessor after each test.
Co-authored-by: Sam Brannen <sam@sambrannen.com>
See gh-30658