From 1cf6d1dd9d4037d50ba68a59575a346cca772414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Thu, 25 May 2023 13:50:03 +0200 Subject: [PATCH] Refine GraalVM tracing agent detection This commit refines how GraalVM tracing agent detection works for both test and application executions. It rolls back the introduction of TestAotDetector done in 111309605c7c1b4c4b8b40d7f8086a0e2338ca82 and instead updates AotDetector.useGeneratedArtifacts() to only detect "buildtime" and "runtime" imagecode system property values by leveraging a new method NativeDetector.inNativeImage(NativeDetector.Context...). This commit also adds a workaround for https://github.com/oracle/graal/issues/6691. Closes gh-30511 --- .../org/springframework/aot/AotDetector.java | 9 ++- .../feature/PreComputeFieldFeature.java | 5 +- .../cglib/core/AbstractClassGenerator.java | 10 ++- .../springframework/core/NativeDetector.java | 57 +++++++++++++- .../test/context/aot/AotTestAttributes.java | 17 +++-- .../context/aot/AotTestAttributesFactory.java | 5 +- .../aot/AotTestContextInitializers.java | 3 +- .../AotTestContextInitializersFactory.java | 7 +- .../context/aot/DefaultAotTestAttributes.java | 3 +- .../test/context/aot/TestAotDetector.java | 58 -------------- .../context/aot/TestContextAotGenerator.java | 3 +- ...efaultCacheAwareContextLoaderDelegate.java | 4 +- .../util/TestContextFailureHandler.java | 8 ++ ...TestContextAotGeneratorErrorCaseTests.java | 76 ------------------- .../basic/BasicSpringVintageTests.java | 4 +- .../ImportsContextCustomizerFactory.java | 4 +- 16 files changed, 107 insertions(+), 166 deletions(-) delete mode 100644 spring-test/src/main/java/org/springframework/test/context/aot/TestAotDetector.java delete mode 100644 spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorErrorCaseTests.java diff --git a/spring-core/src/main/java/org/springframework/aot/AotDetector.java b/spring-core/src/main/java/org/springframework/aot/AotDetector.java index 556e58f9bb73..a3c1740733a7 100644 --- a/spring-core/src/main/java/org/springframework/aot/AotDetector.java +++ b/spring-core/src/main/java/org/springframework/aot/AotDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,14 @@ import org.springframework.core.NativeDetector; import org.springframework.core.SpringProperties; +import static org.springframework.core.NativeDetector.Context; + /** * Utility for determining if AOT-processed optimizations must be used rather * than the regular runtime. Strictly for internal use within the framework. * * @author Stephane Nicoll + * @author Sebastien Deleuze * @since 6.0 */ public abstract class AotDetector { @@ -36,6 +39,8 @@ public abstract class AotDetector { */ public static final String AOT_ENABLED = "spring.aot.enabled"; + private static final boolean inNativeImage = NativeDetector.inNativeImage(Context.RUNTIME, Context.BUILD_TIME); + /** * Determine whether AOT optimizations must be considered at runtime. This * is mandatory in a native image but can be triggered on the JVM using @@ -43,7 +48,7 @@ public abstract class AotDetector { * @return whether AOT optimizations must be considered */ public static boolean useGeneratedArtifacts() { - return (NativeDetector.inNativeImage() || SpringProperties.getFlag(AOT_ENABLED)); + return (inNativeImage || SpringProperties.getFlag(AOT_ENABLED)); } } diff --git a/spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java b/spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java index 4c8596b30e91..ae9c33052e99 100644 --- a/spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java +++ b/spring-core/src/main/java/org/springframework/aot/nativex/feature/PreComputeFieldFeature.java @@ -33,8 +33,9 @@ class PreComputeFieldFeature implements Feature { private static Pattern[] patterns = { - Pattern.compile(Pattern.quote("org.springframework.core.NativeDetector#imageCode")), - Pattern.compile(Pattern.quote("org.springframework.cglib.core.AbstractClassGenerator#imageCode")), + Pattern.compile(Pattern.quote("org.springframework.core.NativeDetector#inNativeImage")), + Pattern.compile(Pattern.quote("org.springframework.cglib.core.AbstractClassGenerator#inNativeImage")), + Pattern.compile(Pattern.quote("org.springframework.aot.AotDetector#inNativeImage")), Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*Present"), Pattern.compile(Pattern.quote("org.springframework.") + ".*#.*PRESENT"), Pattern.compile(Pattern.quote("reactor.") + ".*#.*Available"), diff --git a/spring-core/src/main/java/org/springframework/cglib/core/AbstractClassGenerator.java b/spring-core/src/main/java/org/springframework/cglib/core/AbstractClassGenerator.java index 9196cdf1b915..af66af94c9c7 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/AbstractClassGenerator.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/AbstractClassGenerator.java @@ -43,8 +43,12 @@ abstract public class AbstractClassGenerator implements ClassGenerator { private static final boolean DEFAULT_USE_CACHE = Boolean.parseBoolean(System.getProperty("cglib.useCache", "true")); - // See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java - private static final boolean imageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null); + private static final boolean inNativeImage; + + static { + String imageCode = System.getProperty("org.graalvm.nativeimage.imagecode"); + inNativeImage = "buildtime".equals(imageCode) || "runtime".equals(imageCode); + } private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE; @@ -354,7 +358,7 @@ protected Class generate(ClassLoaderData data) { } } // SPRING PATCH BEGIN - if (imageCode) { + if (inNativeImage) { throw new UnsupportedOperationException("CGLIB runtime enhancement not supported on native image. " + "Make sure to include a pre-generated class on the classpath instead: " + getClassName()); } diff --git a/spring-core/src/main/java/org/springframework/core/NativeDetector.java b/spring-core/src/main/java/org/springframework/core/NativeDetector.java index c3419e85c897..697af695e6f1 100644 --- a/spring-core/src/main/java/org/springframework/core/NativeDetector.java +++ b/spring-core/src/main/java/org/springframework/core/NativeDetector.java @@ -16,6 +16,8 @@ package org.springframework.core; +import org.springframework.lang.Nullable; + /** * A common delegate for detecting a GraalVM native image environment. * @@ -25,12 +27,61 @@ public abstract class NativeDetector { // See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java - private static final boolean imageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null); + @Nullable + private static final String imageCode = System.getProperty("org.graalvm.nativeimage.imagecode"); + + private static final boolean inNativeImage = (imageCode != null); /** - * Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}. + * Returns {@code true} if running in a native image context (for example {@code buildtime}, {@code runtime} or + * {@code agent}) expressed by setting {@code org.graalvm.nativeimage.imagecode} system property to any value, else {@code false}. */ public static boolean inNativeImage() { - return imageCode; + return inNativeImage; + } + + /** + * Returns {@code true} if running in any of the specified native image context(s), else {@code false}. + * @param contexts the native image context(s) + * @since 6.0.10 + */ + public static boolean inNativeImage(Context... contexts) { + for (Context context: contexts) { + if (context.key.equals(imageCode)) { + return true; + } + } + return false; + } + + /** + * Native image context as defined in + * ImageInfo.java. + * + * @since 6.0.10 + */ + public enum Context { + + /** + * The code is executing in the context of image building. + */ + BUILD_TIME("buildtime"), + + /** + * The code is executing at image runtime. + */ + RUNTIME("runtime"); + + private final String key; + + Context(final String key) { + this.key = key; + } + + @Override + public String toString() { + return this.key; + } } + } diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributes.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributes.java index 2f86fda382b7..cfb243b4915c 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributes.java @@ -16,6 +16,7 @@ package org.springframework.test.context.aot; +import org.springframework.aot.AotDetector; import org.springframework.lang.Nullable; /** @@ -26,7 +27,7 @@ * and run-time. At build time, test components can {@linkplain #setAttribute contribute} * attributes during the AOT processing phase. At run time, test components can * {@linkplain #getString(String) retrieve} attributes that were contributed at - * build time. If {@link TestAotDetector#useGeneratedArtifacts()} returns {@code true}, + * build time. If {@link AotDetector#useGeneratedArtifacts()} returns {@code true}, * run-time mode applies. * *

For example, if a test component computes something at build time that @@ -43,7 +44,7 @@ * — can choose to contribute an attribute at any point in time. Note that * contributing an attribute during standard JVM test execution will not have any * adverse side effect since AOT attributes will be ignored in that scenario. In - * any case, you should use {@link TestAotDetector#useGeneratedArtifacts()} to determine + * any case, you should use {@link AotDetector#useGeneratedArtifacts()} to determine * if invocations of {@link #setAttribute(String, String)} and * {@link #removeAttribute(String)} are permitted. * @@ -70,12 +71,12 @@ static AotTestAttributes getInstance() { * @param name the unique attribute name * @param value the associated attribute value * @throws UnsupportedOperationException if invoked during - * {@linkplain TestAotDetector#useGeneratedArtifacts() AOT run-time execution} + * {@linkplain AotDetector#useGeneratedArtifacts() AOT run-time execution} * @throws IllegalArgumentException if the provided value is {@code null} or * if an attempt is made to override an existing attribute * @see #setAttribute(String, boolean) * @see #removeAttribute(String) - * @see TestAotDetector#useGeneratedArtifacts() + * @see AotDetector#useGeneratedArtifacts() */ void setAttribute(String name, String value); @@ -87,13 +88,13 @@ static AotTestAttributes getInstance() { * @param name the unique attribute name * @param value the associated attribute value * @throws UnsupportedOperationException if invoked during - * {@linkplain TestAotDetector#useGeneratedArtifacts() AOT run-time execution} + * {@linkplain AotDetector#useGeneratedArtifacts() AOT run-time execution} * @throws IllegalArgumentException if an attempt is made to override an * existing attribute * @see #setAttribute(String, String) * @see #removeAttribute(String) * @see Boolean#toString(boolean) - * @see TestAotDetector#useGeneratedArtifacts() + * @see AotDetector#useGeneratedArtifacts() */ default void setAttribute(String name, boolean value) { setAttribute(name, Boolean.toString(value)); @@ -103,8 +104,8 @@ default void setAttribute(String name, boolean value) { * Remove the attribute stored under the provided name. * @param name the unique attribute name * @throws UnsupportedOperationException if invoked during - * {@linkplain TestAotDetector#useGeneratedArtifacts() AOT run-time execution} - * @see TestAotDetector#useGeneratedArtifacts() + * {@linkplain AotDetector#useGeneratedArtifacts() AOT run-time execution} + * @see AotDetector#useGeneratedArtifacts() * @see #setAttribute(String, String) */ void removeAttribute(String name); diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributesFactory.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributesFactory.java index 185b6a573ce8..1414083bd66b 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributesFactory.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestAttributesFactory.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.springframework.aot.AotDetector; import org.springframework.lang.Nullable; /** @@ -39,7 +40,7 @@ private AotTestAttributesFactory() { /** * Get the underlying attributes map. *

If the map is not already loaded, this method loads the map from the - * generated class when running in {@linkplain TestAotDetector#useGeneratedArtifacts() + * generated class when running in {@linkplain AotDetector#useGeneratedArtifacts() * AOT execution mode} and otherwise creates a new map for storing attributes * during the AOT processing phase. */ @@ -49,7 +50,7 @@ static Map getAttributes() { synchronized (AotTestAttributesFactory.class) { attrs = attributes; if (attrs == null) { - attrs = (TestAotDetector.useGeneratedArtifacts() ? loadAttributesMap() : new ConcurrentHashMap<>()); + attrs = (AotDetector.useGeneratedArtifacts() ? loadAttributesMap() : new ConcurrentHashMap<>()); attributes = attrs; } } diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializers.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializers.java index 0dd5d912668b..15b95e18ec3d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializers.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializers.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.function.Supplier; +import org.springframework.aot.AotDetector; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.lang.Nullable; @@ -29,7 +30,7 @@ * *

Intended solely for internal use within the framework. * - *

If we are not running in {@linkplain TestAotDetector#useGeneratedArtifacts() + *

If we are not running in {@linkplain AotDetector#useGeneratedArtifacts() * AOT mode} or if a test class is not {@linkplain #isSupportedTestClass(Class) * supported} in AOT mode, {@link #getContextInitializer(Class)} and * {@link #getContextInitializerClass(Class)} will return {@code null}. diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializersFactory.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializersFactory.java index 1e6685c1093d..e130258a8ef2 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializersFactory.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotTestContextInitializersFactory.java @@ -19,6 +19,7 @@ import java.util.Map; import java.util.function.Supplier; +import org.springframework.aot.AotDetector; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.lang.Nullable; @@ -44,7 +45,7 @@ private AotTestContextInitializersFactory() { /** * Get the underlying map. *

If the map is not already loaded, this method loads the map from the - * generated class when running in {@linkplain TestAotDetector#useGeneratedArtifacts() + * generated class when running in {@linkplain AotDetector#useGeneratedArtifacts() * AOT execution mode} and otherwise creates an immutable, empty map. */ static Map>> getContextInitializers() { @@ -53,7 +54,7 @@ static Map>> getContextInitialize synchronized (AotTestContextInitializersFactory.class) { initializerClasses = contextInitializerClasses; if (initializerClasses == null) { - initializerClasses = (TestAotDetector.useGeneratedArtifacts() ? loadContextInitializerClassesMap() : Map.of()); + initializerClasses = (AotDetector.useGeneratedArtifacts() ? loadContextInitializerClassesMap() : Map.of()); contextInitializerClasses = initializerClasses; } } diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/DefaultAotTestAttributes.java b/spring-test/src/main/java/org/springframework/test/context/aot/DefaultAotTestAttributes.java index ac3dbfa1bdfa..966485d5b519 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/DefaultAotTestAttributes.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/DefaultAotTestAttributes.java @@ -18,6 +18,7 @@ import java.util.Map; +import org.springframework.aot.AotDetector; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -60,7 +61,7 @@ public String getString(String name) { private static void assertNotInAotRuntime() { - if (TestAotDetector.useGeneratedArtifacts()) { + if (AotDetector.useGeneratedArtifacts()) { throw new UnsupportedOperationException( "AOT attributes cannot be modified during AOT run-time execution"); } diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestAotDetector.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestAotDetector.java deleted file mode 100644 index f095d40ff1c0..000000000000 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestAotDetector.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.aot; - -import org.springframework.aot.AotDetector; -import org.springframework.core.SpringProperties; -import org.springframework.util.StringUtils; - -/** - * TestContext framework specific utility for determining if AOT-processed - * optimizations must be used rather than the regular runtime. - * - *

Strictly for internal use within the framework. - * - * @author Sam Brannen - * @since 6.0.9 - */ -public abstract class TestAotDetector { - - /** - * Determine whether AOT optimizations must be considered at runtime. - *

This can be triggered using the {@value AotDetector#AOT_ENABLED} - * Spring property or via GraalVM's {@code "org.graalvm.nativeimage.imagecode"} - * JVM system property (if set to any non-empty value other than {@code agent}). - * @return {@code true} if AOT optimizations must be considered - * @see GraalVM's ImageInfo.java - * @see AotDetector#useGeneratedArtifacts() - */ - public static boolean useGeneratedArtifacts() { - return (SpringProperties.getFlag(AotDetector.AOT_ENABLED) || inNativeImage()); - } - - /** - * Determine if we are currently running within a GraalVM native image from - * the perspective of the TestContext framework. - * @return {@code true} if the {@code org.graalvm.nativeimage.imagecode} JVM - * system property has been set to any value other than {@code agent}. - */ - private static boolean inNativeImage() { - String imageCode = System.getProperty("org.graalvm.nativeimage.imagecode"); - return (StringUtils.hasText(imageCode) && !"agent".equalsIgnoreCase(imageCode.trim())); - } - -} diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index 1909a5a05639..cfeb405ab150 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.AotDetector; import org.springframework.aot.generate.ClassNameGenerator; import org.springframework.aot.generate.DefaultGenerationContext; import org.springframework.aot.generate.GeneratedClasses; @@ -122,7 +123,7 @@ public final RuntimeHints getRuntimeHints() { * @throws TestContextAotException if an error occurs during AOT processing */ public void processAheadOfTime(Stream> testClasses) throws TestContextAotException { - Assert.state(!TestAotDetector.useGeneratedArtifacts(), "Cannot perform AOT processing during AOT run-time execution"); + Assert.state(!AotDetector.useGeneratedArtifacts(), "Cannot perform AOT processing during AOT run-time execution"); try { resetAotFactories(); diff --git a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java index a6ae78aa5c56..8f537a9e5572 100644 --- a/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java +++ b/spring-test/src/main/java/org/springframework/test/context/cache/DefaultCacheAwareContextLoaderDelegate.java @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.AotDetector; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; @@ -35,7 +36,6 @@ import org.springframework.test.context.SmartContextLoader; import org.springframework.test.context.aot.AotContextLoader; import org.springframework.test.context.aot.AotTestContextInitializers; -import org.springframework.test.context.aot.TestAotDetector; import org.springframework.test.context.aot.TestContextAotException; import org.springframework.test.context.util.TestContextSpringFactoriesUtils; import org.springframework.util.Assert; @@ -248,7 +248,7 @@ private ContextLoader getContextLoader(MergedContextConfiguration mergedConfig) */ @SuppressWarnings("unchecked") private MergedContextConfiguration replaceIfNecessary(MergedContextConfiguration mergedConfig) { - if (TestAotDetector.useGeneratedArtifacts()) { + if (AotDetector.useGeneratedArtifacts()) { Class testClass = mergedConfig.getTestClass(); Class> contextInitializerClass = this.aotTestContextInitializers.getContextInitializerClass(testClass); diff --git a/spring-test/src/main/java/org/springframework/test/context/util/TestContextFailureHandler.java b/spring-test/src/main/java/org/springframework/test/context/util/TestContextFailureHandler.java index 0fbe8e4795bf..bac8625032de 100644 --- a/spring-test/src/main/java/org/springframework/test/context/util/TestContextFailureHandler.java +++ b/spring-test/src/main/java/org/springframework/test/context/util/TestContextFailureHandler.java @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.core.NativeDetector; import org.springframework.core.io.support.SpringFactoriesLoader.FailureHandler; /** @@ -53,6 +54,13 @@ else if (ex instanceof LinkageError) { available.""".formatted(factoryType.getSimpleName(), factoryImplementationName), ex); } } + // Workaround for https://github.com/oracle/graal/issues/6691 + else if (NativeDetector.inNativeImage() && ex instanceof IllegalStateException) { + if (logger.isDebugEnabled()) { + logger.debug("Skipping candidate %1$s [%2$s] due to an error when loading it in a native image." + .formatted(factoryType.getSimpleName(), factoryImplementationName)); + } + } else { if (ex instanceof RuntimeException runtimeException) { throw runtimeException; diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorErrorCaseTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorErrorCaseTests.java deleted file mode 100644 index f886d96bd22a..000000000000 --- a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorErrorCaseTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2002-2023 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.test.context.aot; - -import java.util.stream.Stream; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -import org.springframework.aot.generate.InMemoryGeneratedFiles; - -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.assertj.core.api.Assertions.assertThatNoException; - -/** - * Tests for error cases in {@link TestContextAotGenerator}. - * - * @author Sam Brannen - * @since 6.0.9 - */ -class TestContextAotGeneratorErrorCaseTests { - - @ParameterizedTest - @CsvSource(delimiter = '=', textBlock = """ - 'spring.aot.enabled' = 'true' - 'org.graalvm.nativeimage.imagecode' = 'buildtime' - 'org.graalvm.nativeimage.imagecode' = 'runtime' - 'org.graalvm.nativeimage.imagecode' = 'bogus' - """) - void attemptToProcessWhileRunningInAotMode(String property, String value) { - try { - System.setProperty(property, value); - - assertThatIllegalStateException() - .isThrownBy(() -> generator().processAheadOfTime(Stream.empty())) - .withMessage("Cannot perform AOT processing during AOT run-time execution"); - } - finally { - System.clearProperty(property); - } - } - - @Test - void attemptToProcessWhileRunningInGraalVmNativeBuildToolsAgentMode() { - final String IMAGECODE = "org.graalvm.nativeimage.imagecode"; - try { - System.setProperty(IMAGECODE, "AgenT"); - - assertThatNoException().isThrownBy(() -> generator().processAheadOfTime(Stream.empty())); - } - finally { - System.clearProperty(IMAGECODE); - } - } - - private static TestContextAotGenerator generator() { - InMemoryGeneratedFiles generatedFiles = new InMemoryGeneratedFiles(); - return new TestContextAotGenerator(generatedFiles); - } - -} diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringVintageTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringVintageTests.java index db63efb3b8dc..4e1189674b04 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringVintageTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringVintageTests.java @@ -18,6 +18,7 @@ import org.junit.runner.RunWith; +import org.springframework.aot.AotDetector; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; @@ -27,7 +28,6 @@ import org.springframework.test.context.MergedContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.aot.AotTestAttributes; -import org.springframework.test.context.aot.TestAotDetector; import org.springframework.test.context.aot.samples.basic.BasicSpringVintageTests.CustomXmlBootstrapper; import org.springframework.test.context.aot.samples.common.MessageService; import org.springframework.test.context.junit4.SpringRunner; @@ -78,7 +78,7 @@ protected MergedContextConfiguration processMergedContextConfiguration(MergedCon String booleanKey1 = "@SpringBootConfiguration-" + mergedConfig.getTestClass().getName() + "-active1"; String booleanKey2 = "@SpringBootConfiguration-" + mergedConfig.getTestClass().getName() + "-active2"; AotTestAttributes aotAttributes = AotTestAttributes.getInstance(); - if (TestAotDetector.useGeneratedArtifacts()) { + if (AotDetector.useGeneratedArtifacts()) { assertThat(aotAttributes.getString(stringKey)) .as("AOT String attribute must already be present during AOT run-time execution") .isEqualTo("org.example.Main"); diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/ImportsContextCustomizerFactory.java b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/ImportsContextCustomizerFactory.java index 431ff14489d1..4fe84402eb7c 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/ImportsContextCustomizerFactory.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/ImportsContextCustomizerFactory.java @@ -19,6 +19,7 @@ import java.util.Arrays; import java.util.List; +import org.springframework.aot.AotDetector; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.annotation.Import; @@ -27,7 +28,6 @@ import org.springframework.test.context.ContextCustomizer; import org.springframework.test.context.ContextCustomizerFactory; import org.springframework.test.context.MergedContextConfiguration; -import org.springframework.test.context.aot.TestAotDetector; /** * Emulates {@code ImportsContextCustomizerFactory} from Spring Boot's testing support. @@ -41,7 +41,7 @@ class ImportsContextCustomizerFactory implements ContextCustomizerFactory { public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { - if (TestAotDetector.useGeneratedArtifacts()) { + if (AotDetector.useGeneratedArtifacts()) { return null; } if (testClass.getName().startsWith("org.springframework.test.context.aot.samples") &&