From 346b41e4dce0b353a255c455272e6b5f20851516 Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 22 Jun 2021 18:51:28 +0200 Subject: [PATCH] Support Test Resources from @TestProfile in native mode ## Description In https://github.com/quarkusio/quarkus/pull/13154, the annotation `@TestProfile` was supported also in Native tests. However, the native extension was not processing the test resources in the test profile like: ``` public class ConfluentTestProfile implements QuarkusTestProfile { @Override public String getConfigProfile() { return "confluent"; } @Override public List testResources() { return Collections.singletonList(new TestResourceEntry(ConfluentKafkaResource.class)); } } ``` This PR makes the above to be supported. The solution behaves the same as done in the Quarkus Test extension. --- ...RuntimeValueChangeFromTestResourcesIT.java | 12 +++++ ...ntimeValueChangeFromTestResourcesTest.java | 53 +++++++++++++++++++ .../test/junit/IntegrationTestUtil.java | 38 +++++++++++++ .../test/junit/NativeTestExtension.java | 5 +- .../test/junit/QuarkusTestExtension.java | 34 +----------- 5 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesIT.java create mode 100644 integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesTest.java diff --git a/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesIT.java b/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesIT.java new file mode 100644 index 00000000000000..28bbea1c9d90f0 --- /dev/null +++ b/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesIT.java @@ -0,0 +1,12 @@ +package io.quarkus.it.nat.test.profile; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.NativeImageTest; + +/** + * This test ensures that the NativeTestExtension starts the test resources from the Test Profile annotation. + */ +@NativeImageTest +public class RuntimeValueChangeFromTestResourcesIT extends RuntimeValueChangeFromTestResourcesTest { +} diff --git a/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesTest.java b/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesTest.java new file mode 100644 index 00000000000000..f3a0701bb0abd1 --- /dev/null +++ b/integration-tests/native-config-profile/src/test/java/io/quarkus/it/nat/test/profile/RuntimeValueChangeFromTestResourcesTest.java @@ -0,0 +1,53 @@ +package io.quarkus.it.nat.test.profile; + +import static org.hamcrest.Matchers.is; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.QuarkusTestProfile; +import io.quarkus.test.junit.TestProfile; +import io.restassured.RestAssured; + +@QuarkusTest +@TestProfile(RuntimeValueChangeFromTestResourcesTest.CustomTestProfile.class) +public class RuntimeValueChangeFromTestResourcesTest { + + private static final String EXPECTED_VALUE = "RuntimeTimeValueChangeFromTestResources"; + + @Test + public void failInNativeTestExtension_beforeEach() { + RestAssured.when() + .get("/native-config-profile/myConfigValue") + .then() + .body(is(EXPECTED_VALUE)); + } + + public static class CustomTestProfile implements QuarkusTestProfile { + @Override + public List testResources() { + return Collections.singletonList(new TestResourceEntry(DummyTestResource.class)); + } + } + + /** + * This only used to ensure that the TestResource has been handled correctly by the QuarkusTestExtension + */ + public static class DummyTestResource implements QuarkusTestResourceLifecycleManager { + + @Override + public Map start() { + return Collections.singletonMap("my.config.value", EXPECTED_VALUE); + } + + @Override + public void stop() { + // do nothing + } + } +} diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java index 37985743274581..d44411947a8858 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java @@ -7,6 +7,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.UncheckedIOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; @@ -15,7 +17,10 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; @@ -41,6 +46,7 @@ import io.quarkus.test.common.ArtifactLauncher; import io.quarkus.test.common.PathTestHelper; import io.quarkus.test.common.TestClassIndexer; +import io.quarkus.test.common.TestResourceManager; import io.quarkus.test.common.http.TestHTTPResourceManager; final class IntegrationTestUtil { @@ -125,6 +131,38 @@ static TestProfileAndProperties determineTestProfileAndProperties(Class List getAdditionalTestResources( + QuarkusTestProfile profileInstance, ClassLoader classLoader) { + if ((profileInstance == null) || profileInstance.testResources().isEmpty()) { + return Collections.emptyList(); + } + + try { + Constructor testResourceClassEntryConstructor = Class + .forName(TestResourceManager.TestResourceClassEntry.class.getName(), true, classLoader) + .getConstructor(Class.class, Map.class, Annotation.class, boolean.class); + + List testResources = profileInstance.testResources(); + List result = new ArrayList<>(testResources.size()); + for (QuarkusTestProfile.TestResourceEntry testResource : testResources) { + T instance = (T) testResourceClassEntryConstructor.newInstance( + Class.forName(testResource.getClazz().getName(), true, classLoader), testResource.getArgs(), + null, testResource.isParallel()); + result.add(instance); + } + + return result; + } catch (Exception e) { + throw new IllegalStateException("Unable to handle profile " + profileInstance.getClass(), e); + } + } + static void startLauncher(ArtifactLauncher launcher, Map additionalProperties, Runnable sslSetter) throws IOException { launcher.addSystemProperties(additionalProperties); diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java index 0af1e3c2ace557..4008cbd7af0401 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java @@ -3,11 +3,11 @@ import static io.quarkus.test.junit.IntegrationTestUtil.determineTestProfileAndProperties; import static io.quarkus.test.junit.IntegrationTestUtil.doProcessTestInstance; import static io.quarkus.test.junit.IntegrationTestUtil.ensureNoInjectAnnotationIsUsed; +import static io.quarkus.test.junit.IntegrationTestUtil.getAdditionalTestResources; import static io.quarkus.test.junit.IntegrationTestUtil.getSysPropsToRestore; import static io.quarkus.test.junit.IntegrationTestUtil.handleDevDb; import static io.quarkus.test.junit.IntegrationTestUtil.startLauncher; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -113,7 +113,8 @@ private IntegrationTestExtensionState doNativeStart(ExtensionContext context, Cl TestProfileAndProperties testProfileAndProperties = determineTestProfileAndProperties(profile, sysPropRestore); testResourceManager = new TestResourceManager(requiredTestClass, quarkusTestProfile, - Collections.emptyList(), testProfileAndProperties.testProfile != null + getAdditionalTestResources(testProfileAndProperties.testProfile, currentJUnitTestClass.getClassLoader()), + testProfileAndProperties.testProfile != null && testProfileAndProperties.testProfile.disableGlobalTestResources()); testResourceManager.init(); hasPerTestResources = testResourceManager.hasPerTestResources(); diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java index 1bae13a1216b30..0987cb3003e1cb 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtension.java @@ -2,6 +2,7 @@ import static io.quarkus.test.common.PathTestHelper.getAppClassLocationForTestLocation; import static io.quarkus.test.common.PathTestHelper.getTestClassesLocation; +import static io.quarkus.test.junit.IntegrationTestUtil.getAdditionalTestResources; import java.io.Closeable; import java.io.IOException; @@ -19,7 +20,6 @@ import java.util.AbstractMap; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.List; @@ -426,38 +426,6 @@ public void close() throws IOException { } } - /** - * Since {@link TestResourceManager} is loaded from the ClassLoader passed in as an argument, - * we need to convert the user input {@link QuarkusTestProfile.TestResourceEntry} into instances of - * {@link TestResourceManager.TestResourceClassEntry} - * that are loaded from that ClassLoader - */ - private List getAdditionalTestResources( - QuarkusTestProfile profileInstance, ClassLoader classLoader) { - if ((profileInstance == null) || profileInstance.testResources().isEmpty()) { - return Collections.emptyList(); - } - - try { - Constructor testResourceClassEntryConstructor = Class - .forName(TestResourceManager.TestResourceClassEntry.class.getName(), true, classLoader) - .getConstructor(Class.class, Map.class, Annotation.class, boolean.class); - - List testResources = profileInstance.testResources(); - List result = new ArrayList<>(testResources.size()); - for (QuarkusTestProfile.TestResourceEntry testResource : testResources) { - Object instance = testResourceClassEntryConstructor.newInstance( - Class.forName(testResource.getClazz().getName(), true, classLoader), testResource.getArgs(), - null, testResource.isParallel()); - result.add(instance); - } - - return result; - } catch (Exception e) { - throw new IllegalStateException("Unable to handle profile " + profileInstance.getClass(), e); - } - } - private void populateDeepCloneField(StartupAction startupAction) { deepClone = new SerializationWithXStreamFallbackDeepClone(startupAction.getClassLoader()); }