From 3a909ccdf82dc8adb667aabeca415bf76e922a75 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Fri, 7 Feb 2020 12:23:41 +1100 Subject: [PATCH] Make sure that src/test/resources takes precidence for @QuarkusTest This allows for easy config overriding in tests --- .../bootstrap/app/AdditionalDependency.java | 15 +++++++ .../bootstrap/app/CuratedApplication.java | 43 +++++++++++++------ .../it/resteasy/jackson/MessageResource.java | 19 ++++++++ .../src/main/resources/application.properties | 1 + .../ApplicationPropertiesOverrideIT.java | 28 ++++++++++++ .../ApplicationPropertiesOverrideTest.java | 28 ++++++++++++ .../src/test/resources/application.properties | 1 + .../test/junit/QuarkusTestExtension.java | 7 ++- 8 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 integration-tests/resteasy-jackson/src/main/java/io/quarkus/it/resteasy/jackson/MessageResource.java create mode 100644 integration-tests/resteasy-jackson/src/main/resources/application.properties create mode 100644 integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideIT.java create mode 100644 integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideTest.java create mode 100644 integration-tests/resteasy-jackson/src/test/resources/application.properties diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/AdditionalDependency.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/AdditionalDependency.java index 05998f3e2..9ae070753 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/AdditionalDependency.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/AdditionalDependency.java @@ -30,10 +30,21 @@ public class AdditionalDependency implements Serializable { */ private final boolean forceApplicationArchive; + /** + * If this dep is the test classes directory. If so then this will have precedence over the application + */ + private final boolean testClassRoot; + public AdditionalDependency(Path archivePath, boolean hotReloadable, boolean forceApplicationArchive) { + this(archivePath, hotReloadable, forceApplicationArchive, false); + } + + public AdditionalDependency(Path archivePath, boolean hotReloadable, boolean forceApplicationArchive, + boolean testClassRoot) { this.archivePath = archivePath; this.hotReloadable = hotReloadable; this.forceApplicationArchive = forceApplicationArchive; + this.testClassRoot = testClassRoot; } public Path getArchivePath() { @@ -47,4 +58,8 @@ public class AdditionalDependency implements Serializable { public boolean isForceApplicationArchive() { return forceApplicationArchive; } + + public boolean isTestClassRoot() { + return testClassRoot; + } } diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java index 14ad9834b..0e71bb128 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/app/CuratedApplication.java @@ -1,7 +1,6 @@ package io.quarkus.bootstrap.app; import java.io.Closeable; -import java.io.IOException; import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; @@ -113,7 +112,8 @@ public class CuratedApplication implements Serializable, Closeable { public AugmentAction createAugmentor(String functionName, Map props) { try { Class augmentor = getAugmentClassLoader().loadClass(AUGMENTOR); - Function> function = (Function>) getAugmentClassLoader().loadClass(functionName).newInstance(); + Function> function = (Function>) getAugmentClassLoader().loadClass(functionName) + .newInstance(); List res = function.apply(props); return (AugmentAction) augmentor.getConstructor(CuratedApplication.class, List.class).newInstance(this, res); } catch (Exception e) { @@ -224,18 +224,27 @@ public class CuratedApplication implements Serializable, Closeable { QuarkusClassLoader.Builder builder = QuarkusClassLoader.builder("Quarkus Base Runtime ClassLoader", quarkusBootstrap.getBaseClassLoader(), false); if (quarkusBootstrap.getMode() == QuarkusBootstrap.Mode.TEST) { - //in test mode we have everything in the base class loader //there is no need to restart so there is no need for an additional CL + + for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) { + //src/test is the highest priority + if (i.isTestClassRoot()) { + builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); + } + } + builder.addElement(ClassPathElement.fromPath(getQuarkusBootstrap().getApplicationRoot())); } //additional user class path elements first Set hotReloadPaths = new HashSet<>(); for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) { - if (!i.isHotReloadable()) { - builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); - } else { - hotReloadPaths.add(i.getArchivePath()); + if (!i.isTestClassRoot()) { + if (!i.isHotReloadable()) { + builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); + } else { + hotReloadPaths.add(i.getArchivePath()); + } } } builder.setResettableElement(new MemoryClassPathElement(Collections.emptyMap())); @@ -264,20 +273,26 @@ public class CuratedApplication implements Serializable, Closeable { QuarkusClassLoader.Builder builder = QuarkusClassLoader.builder("Deployment Class Loader", getAugmentClassLoader(), false) .setAggregateParentResources(true); - //add the application root + //add the application root, and test roots + for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) { + if (i.isTestClassRoot()) { + builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); + } + } builder.addElement(ClassPathElement.fromPath(quarkusBootstrap.getApplicationRoot())); //additional user class path elements first for (AdditionalDependency i : quarkusBootstrap.getAdditionalApplicationArchives()) { - builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); + if (!i.isTestClassRoot()) { + builder.addElement(ClassPathElement.fromPath(i.getArchivePath())); + } } return builder.build(); } - public QuarkusClassLoader createRuntimeClassLoader(QuarkusClassLoader loader, - Map>> bytecodeTransformers, - ClassLoader deploymentClassLoader, Map resources) { + Map>> bytecodeTransformers, + ClassLoader deploymentClassLoader, Map resources) { QuarkusClassLoader.Builder builder = QuarkusClassLoader.builder("Quarkus Runtime ClassLoader", loader, false) .setAggregateParentResources(true); @@ -296,10 +311,10 @@ public class CuratedApplication implements Serializable, Closeable { @Override public void close() { - if(augmentClassLoader != null) { + if (augmentClassLoader != null) { augmentClassLoader.close(); } - if(baseRuntimeClassLoader != null) { + if (baseRuntimeClassLoader != null) { baseRuntimeClassLoader.close(); } } diff --git a/integration-tests/resteasy-jackson/src/main/java/io/quarkus/it/resteasy/jackson/MessageResource.java b/integration-tests/resteasy-jackson/src/main/java/io/quarkus/it/resteasy/jackson/MessageResource.java new file mode 100644 index 000000000..7d30f0027 --- /dev/null +++ b/integration-tests/resteasy-jackson/src/main/java/io/quarkus/it/resteasy/jackson/MessageResource.java @@ -0,0 +1,19 @@ +package io.quarkus.it.resteasy.jackson; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +@Path("/message") +public class MessageResource { + + @ConfigProperty(name = "message") + String message; + + @GET + public String message() { + return message; + } + +} diff --git a/integration-tests/resteasy-jackson/src/main/resources/application.properties b/integration-tests/resteasy-jackson/src/main/resources/application.properties new file mode 100644 index 000000000..7df30cbf2 --- /dev/null +++ b/integration-tests/resteasy-jackson/src/main/resources/application.properties @@ -0,0 +1 @@ +message=Production \ No newline at end of file diff --git a/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideIT.java b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideIT.java new file mode 100644 index 000000000..9de9f9d87 --- /dev/null +++ b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideIT.java @@ -0,0 +1,28 @@ +package io.quarkus.it.resteasy.jackson; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.NativeImageTest; + +/** + * tests that application.properties is read from src/main/resources when running native image tests + * + * This does not necessarily belong here, but main and test-extension have a lot of existing + * config that would need to be duplicated, so it is here out of convenience. + */ +@NativeImageTest +class ApplicationPropertiesOverrideIT { + + @Test + void testEndpoint() { + given() + .when().get("/message") + .then() + .statusCode(200) + .body(containsString("Production")); + } + +} diff --git a/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideTest.java b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideTest.java new file mode 100644 index 000000000..604ec73a1 --- /dev/null +++ b/integration-tests/resteasy-jackson/src/test/java/io/quarkus/it/resteasy/jackson/ApplicationPropertiesOverrideTest.java @@ -0,0 +1,28 @@ +package io.quarkus.it.resteasy.jackson; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +/** + * tests that application.properties is read from src/test/resources + * + * This does not necessarily belong here, but main and test-extension have a lot of existing + * config that would need to be duplicated, so it is here out of convenience. + */ +@QuarkusTest +class ApplicationPropertiesOverrideTest { + + @Test + void testEndpoint() { + given() + .when().get("/message") + .then() + .statusCode(200) + .body(containsString("Test")); + } + +} diff --git a/integration-tests/resteasy-jackson/src/test/resources/application.properties b/integration-tests/resteasy-jackson/src/test/resources/application.properties new file mode 100644 index 000000000..42963ee9e --- /dev/null +++ b/integration-tests/resteasy-jackson/src/test/resources/application.properties @@ -0,0 +1 @@ +message=Test \ No newline at end of file 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 cade5f79d..315d863f5 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 @@ -80,7 +80,7 @@ public class QuarkusTestExtension testClassLocation = getTestClassesLocation(context.getRequiredTestClass()); if (!appClassLocation.equals(testClassLocation)) { - runnerBuilder.addAdditionalApplicationArchive(new AdditionalDependency(testClassLocation, false, true)); + runnerBuilder.addAdditionalApplicationArchive(new AdditionalDependency(testClassLocation, false, true, true)); } CuratedApplication curatedApplication = runnerBuilder .setTest(true) @@ -171,7 +171,7 @@ public class QuarkusTestExtension ExtensionContext root = extensionContext.getRoot(); ExtensionContext.Store store = root.getStore(ExtensionContext.Namespace.GLOBAL); ExtensionState state = store.get(ExtensionState.class.getName(), ExtensionState.class); - if (state == null) { + if (state == null && !failedBoot) { PropertyTestUtil.setLogFileProperty(); TestResourceManager testResourceManager = new TestResourceManager(extensionContext.getRequiredTestClass()); try { @@ -261,6 +261,9 @@ public class QuarkusTestExtension Thread.currentThread().setContextClassLoader(old); } ExtensionState state = ensureStarted(extensionContext); + if (failedBoot) { + return invocation.proceed(); + } initTestState(extensionContext, state); return result; }