From 7922fa3d2a2f0a00d84f77995c88e47f46938eb7 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Wed, 3 Dec 2025 17:52:32 +0000 Subject: [PATCH] Change ArtifactLauncher.start to return the listening address --- .../java/io/quarkus/it/jaxb/AwtJaxbTest.java | 6 +- .../quarkus/test/common/ArtifactLauncher.java | 5 +- .../DefaultDockerContainerLauncher.java | 22 ++----- .../test/common/DefaultJarLauncher.java | 20 ++---- .../common/DefaultNativeImageLauncher.java | 35 +++++----- .../io/quarkus/test/common/LauncherUtil.java | 14 ---- .../test/common/RunCommandLauncher.java | 7 +- .../quarkus/test/common/TestHostLauncher.java | 10 +-- .../junit/IntegrationTestExtensionState.java | 8 ++- .../test/junit/IntegrationTestUtil.java | 42 ++++++------ .../QuarkusIntegrationTestExtension.java | 64 +++++++------------ .../QuarkusMainIntegrationTestExtension.java | 24 +++---- .../test/junit/QuarkusTestExtensionState.java | 30 ++++++++- .../test/junit/TestProfileAndProperties.java | 30 +++++++-- 14 files changed, 155 insertions(+), 162 deletions(-) diff --git a/integration-tests/awt-packaging/src/test/java/io/quarkus/it/jaxb/AwtJaxbTest.java b/integration-tests/awt-packaging/src/test/java/io/quarkus/it/jaxb/AwtJaxbTest.java index fba2e61a5befb..7427d39a0f751 100644 --- a/integration-tests/awt-packaging/src/test/java/io/quarkus/it/jaxb/AwtJaxbTest.java +++ b/integration-tests/awt-packaging/src/test/java/io/quarkus/it/jaxb/AwtJaxbTest.java @@ -1,7 +1,7 @@ package io.quarkus.it.jaxb; import static io.restassured.RestAssured.given; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.containsString; import org.junit.jupiter.api.Test; @@ -31,7 +31,7 @@ void book() { .then() .statusCode(200) // The height in pixels of the book's cover image. - .body(equalTo("\"10\"")); + .body(containsString("10")); } /** @@ -47,6 +47,6 @@ void lambda() { .post() .then() .statusCode(200) - .body(equalTo("\"10\"")); + .body(containsString("10")); } } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java index ba498a21a7c52..4b4b5c54d4fda 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java @@ -5,6 +5,7 @@ import java.time.Duration; import java.util.List; import java.util.Map; +import java.util.Optional; import io.quarkus.bootstrap.app.CuratedApplication; @@ -12,14 +13,12 @@ public interface ArtifactLauncher extend void init(T t); - void start() throws IOException; + Optional start() throws IOException; LaunchResult runToCompletion(String[] args); void includeAsSysProps(Map systemProps); - boolean listensOnSsl(); - interface InitContext { int httpPort(); diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java index 845dd806aa7b2..79dbe751c22c2 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java @@ -1,7 +1,6 @@ package io.quarkus.test.common; import static io.quarkus.test.common.LauncherUtil.createStartedFunction; -import static io.quarkus.test.common.LauncherUtil.updateConfigForPort; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; import static java.lang.ProcessBuilder.Redirect.DISCARD; @@ -52,7 +51,6 @@ public class DefaultDockerContainerLauncher implements DockerContainerArtifactLa private Map volumeMounts; private Map labels; private final Map systemProps = new HashMap<>(); - private boolean isSsl; private final String containerName = "quarkus-integration-test-" + RandomStringUtils.insecure().next(5, true, false); private String containerRuntimeBinaryName; private final ExecutorService executorService = Executors.newSingleThreadExecutor(); @@ -96,8 +94,6 @@ public LaunchResult runToCompletion(String[] argz) { } } - System.setProperty("test.url", TestHTTPResourceManager.getUri()); - final List args = new ArrayList<>(); args.add(containerRuntimeBinaryName); args.add("run"); @@ -188,7 +184,7 @@ public LaunchResult runToCompletion(String[] argz) { } @Override - public void start() throws IOException { + public Optional start() throws IOException { SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); LogRuntimeConfig logRuntimeConfig = config.getConfigMapping(LogRuntimeConfig.class); @@ -208,8 +204,6 @@ public void start() throws IOException { } } - System.setProperty("test.url", TestHTTPResourceManager.getUri()); - if (httpPort == 0) { httpPort = getRandomPort(); } @@ -301,15 +295,13 @@ public void start() throws IOException { .start(); if (startedFunction != null) { - final IntegrationTestStartedNotifier.Result result = waitForStartedFunction(startedFunction, containerProcess, - waitTimeSeconds, logPath); - isSsl = result.isSsl(); + waitForStartedFunction(startedFunction, containerProcess, waitTimeSeconds, logPath); + return Optional.empty(); } else { log.info("Wait for server to start by capturing listening data..."); - final ListeningAddress result = waitForCapturedListeningData(containerProcess, logPath, waitTimeSeconds); + ListeningAddress result = waitForCapturedListeningData(containerProcess, logPath, waitTimeSeconds); log.infof("Server started on port %s", result.getPort()); - updateConfigForPort(result.getPort()); - isSsl = result.isSsl(); + return Optional.of(result); } } @@ -319,10 +311,6 @@ private int getRandomPort() throws IOException { } } - public boolean listensOnSsl() { - return isSsl; - } - public void includeAsSysProps(Map systemProps) { this.systemProps.putAll(systemProps); } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java index f5e59d334b5f7..d619a42e866b3 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java @@ -1,7 +1,6 @@ package io.quarkus.test.common; import static io.quarkus.test.common.LauncherUtil.createStartedFunction; -import static io.quarkus.test.common.LauncherUtil.updateConfigForPort; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; @@ -15,6 +14,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import org.eclipse.microprofile.config.ConfigProvider; @@ -55,7 +55,6 @@ public class DefaultJarLauncher implements JarArtifactLauncher { private final Map systemProps = new HashMap<>(); private Process quarkusProcess; - private boolean isSsl; private Path logFile; @Override @@ -70,21 +69,20 @@ public void init(JarArtifactLauncher.JarInitContext initContext) { this.generateAotFile = initContext.generateAotFile(); } - public void start() throws IOException { + @Override + public Optional start() throws IOException { start(new String[0], true); Function startedFunction = createStartedFunction(); LogRuntimeConfig logRuntimeConfig = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class) .getConfigMapping(LogRuntimeConfig.class); logFile = logRuntimeConfig.file().path().toPath(); if (startedFunction != null) { - IntegrationTestStartedNotifier.Result result = waitForStartedFunction(startedFunction, quarkusProcess, - waitTimeSeconds, logFile); - isSsl = result.isSsl(); + waitForStartedFunction(startedFunction, quarkusProcess, waitTimeSeconds, logFile); + return Optional.empty(); } else { ListeningAddress result = waitForCapturedListeningData(quarkusProcess, logRuntimeConfig.file().path().toPath(), waitTimeSeconds); - updateConfigForPort(result.getPort()); - isSsl = result.isSsl(); + return Optional.of(result); } } @@ -110,7 +108,6 @@ public void start(String[] programArgs, boolean handleIo) throws IOException { SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); LogRuntimeConfig logRuntimeConfig = config.getConfigMapping(LogRuntimeConfig.class); logFile = logRuntimeConfig.file().path().toPath(); - System.setProperty("test.url", TestHTTPResourceManager.getUri()); List args = new ArrayList<>(); args.add(determineJavaPath()); @@ -180,11 +177,6 @@ private String determineJavaPath() { return "java"; } - @Override - public boolean listensOnSsl() { - return isSsl; - } - @Override public void includeAsSysProps(Map systemProps) { this.systemProps.putAll(systemProps); diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java index 581511cf21541..59bcd7a2f9e2f 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java @@ -1,7 +1,6 @@ package io.quarkus.test.common; import static io.quarkus.test.common.LauncherUtil.createStartedFunction; -import static io.quarkus.test.common.LauncherUtil.updateConfigForPort; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; @@ -19,6 +18,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; @@ -26,7 +26,7 @@ import org.jboss.logging.Logger; import io.quarkus.runtime.logging.LogRuntimeConfig; -import io.quarkus.test.common.http.TestHTTPResourceManager; +import io.smallrye.config.ConfigValue; import io.smallrye.config.SmallRyeConfig; public class DefaultNativeImageLauncher implements NativeImageLauncher { @@ -47,7 +47,6 @@ public class DefaultNativeImageLauncher implements NativeImageLauncher { private Process quarkusProcess; private final Map systemProps = new HashMap<>(); - private boolean isSsl; private Path logFile; @Override @@ -83,28 +82,26 @@ public LaunchResult runToCompletion(String[] args) { } } - public void start() throws IOException { + @Override + public Optional start() throws IOException { start(new String[0], true); LogRuntimeConfig logRuntimeConfig = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class) .getConfigMapping(LogRuntimeConfig.class); logFile = logRuntimeConfig.file().path().toPath(); Function startedFunction = createStartedFunction(); if (startedFunction != null) { - IntegrationTestStartedNotifier.Result result = waitForStartedFunction(startedFunction, quarkusProcess, - waitTimeSeconds, logRuntimeConfig.file().path().toPath()); - isSsl = result.isSsl(); + waitForStartedFunction(startedFunction, quarkusProcess, waitTimeSeconds, logRuntimeConfig.file().path().toPath()); + return Optional.empty(); } else { ListeningAddress result = waitForCapturedListeningData(quarkusProcess, logRuntimeConfig.file().path().toPath(), waitTimeSeconds); - updateConfigForPort(result.getPort()); - isSsl = result.isSsl(); + return Optional.of(result); } } public void start(String[] programArgs, boolean handleIo) throws IOException { SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); LogRuntimeConfig logRuntimeConfig = config.getConfigMapping(LogRuntimeConfig.class); - System.setProperty("test.url", TestHTTPResourceManager.getUri()); if (nativeImagePath == null) { nativeImagePath = guessPath(testClass); @@ -117,9 +114,15 @@ public void start(String[] programArgs, boolean handleIo) throws IOException { if (DefaultJarLauncher.HTTP_PRESENT) { args.add("-Dquarkus.http.port=" + httpPort); args.add("-Dquarkus.http.ssl-port=" + httpsPort); - // this won't be correct when using the random port but it's really only used by us for the rest client tests - // in the main module, since those tests hit the application itself - args.add("-Dtest.url=" + TestHTTPResourceManager.getUri()); + // Check io.quarkus.test.common.http.TestHTTPConfigSourceInterceptor.sanitizeUrl + String rootPath = ""; + // These are build time properties so it is fine to evaluate them here + ConfigValue rootPathValue = config.getConfigValue("${quarkus.http.root-path:${quarkus.servlet.context-path:}}"); + if (rootPathValue.getValue() != null && rootPathValue.getValue().endsWith("/")) { + rootPath = rootPathValue.getValue().substring(0, rootPathValue.getValue().length() - 1); + } + // We want to keep `quarkus.http.test-port` as an expression so it is evaluated correctly + args.add("-Dtest.url=http://localhost:${quarkus.http.test-port:8081}" + rootPath); } logFile = logRuntimeConfig.file().path().toPath(); args.add("-Dquarkus.log.file.path=" + logFile.toAbsolutePath()); @@ -148,7 +151,6 @@ public void start(String[] programArgs, boolean handleIo) throws IOException { } else { quarkusProcess = LauncherUtil.launchProcess(args, env); } - } private void waitForStartedSupplier(Supplier startedSupplier, Process quarkusProcess, long waitTime) { @@ -161,7 +163,6 @@ private void waitForStartedSupplier(Supplier startedSupplier, Process q try { Thread.sleep(100); if (startedSupplier.get()) { - isSsl = false; started = true; break; } @@ -264,10 +265,6 @@ private static void logGuessedPath(String guessedPath) { System.err.println("======================================================================================"); } - public boolean listensOnSsl() { - return isSsl; - } - @Override public void includeAsSysProps(Map systemProps) { this.systemProps.putAll(systemProps); diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 68067456adab6..facffaa00b24b 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -23,7 +23,6 @@ import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; -import io.quarkus.test.common.http.TestHTTPResourceManager; import io.smallrye.common.os.OS; public final class LauncherUtil { @@ -208,19 +207,6 @@ static IntegrationTestStartedNotifier.Result waitForStartedFunction( return result; } - /** - * Updates the configuration necessary to make all test systems knowledgeable about the port on which the launched - * process is listening - */ - static void updateConfigForPort(Integer effectivePort) { - if (effectivePort != null) { - System.setProperty("quarkus.http.port", effectivePort.toString()); //set the port as a system property in order to have it applied to Config - System.setProperty("quarkus.http.test-port", effectivePort.toString()); // needed for RestAssuredManager - System.clearProperty("test.url"); // make sure the old value does not interfere with setting the new one - System.setProperty("test.url", TestHTTPResourceManager.getUri()); - } - } - static void toStdOut(Path log) { if (log != null) { try (var r = Files.newBufferedReader(log, StandardCharsets.UTF_8)) { diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/RunCommandLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/RunCommandLauncher.java index 292159f4c9cfa..1eaf51ff4a48b 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/RunCommandLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/RunCommandLauncher.java @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -110,7 +111,7 @@ public LaunchResult runToCompletion(String[] args) { } @Override - public void start() throws IOException { + public Optional start() throws IOException { System.setProperty("test.url", TestHTTPResourceManager.getUri()); Path logFile = logFilePath; @@ -161,10 +162,8 @@ public void start() throws IOException { LauncherUtil.destroyProcess(quarkusProcess, true); throw new RuntimeException("Unable to start target quarkus application " + this.waitTimeSeconds + "s"); } - } - public boolean listensOnSsl() { - return false; + return Optional.empty(); } public void includeAsSysProps(Map systemProps) { diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/TestHostLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/TestHostLauncher.java index 95978e11f5eaf..0c14a52643232 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/TestHostLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/TestHostLauncher.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.util.Map; +import java.util.Optional; /** * A launcher that simply sets the {@code quarkus.http.host} property based on the value {@code quarkus.http.test-host} @@ -10,13 +11,13 @@ */ @SuppressWarnings("rawtypes") public class TestHostLauncher implements ArtifactLauncher { - private String previousHost; @Override - public void start() throws IOException { + public Optional start() throws IOException { // set 'quarkus.http.host' to ensure that RestAssured targets the proper host previousHost = System.setProperty("quarkus.http.host", System.getProperty("quarkus.http.test-host")); + return Optional.empty(); } @Override @@ -26,11 +27,6 @@ public void close() throws IOException { } } - @Override - public boolean listensOnSsl() { - return Boolean.parseBoolean(System.getProperty("quarkus.http.test-ssl-enabled", "false")); - } - @Override public void includeAsSysProps(Map systemProps) { diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestExtensionState.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestExtensionState.java index 3c5821b4f9844..b6588b18121ba 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestExtensionState.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/IntegrationTestExtensionState.java @@ -3,9 +3,11 @@ import java.io.Closeable; import java.io.IOException; import java.util.Map; +import java.util.Optional; import org.eclipse.microprofile.config.ConfigProvider; +import io.quarkus.test.common.ListeningAddress; import io.quarkus.test.common.TestResourceManager; import io.smallrye.config.SmallRyeConfig; @@ -13,9 +15,9 @@ public class IntegrationTestExtensionState extends QuarkusTestExtensionState { private final Map sysPropRestore; - public IntegrationTestExtensionState(TestResourceManager testResourceManager, Closeable resource, - Runnable clearCallbacks, Map sysPropRestore) { - super(testResourceManager, resource, clearCallbacks); + public IntegrationTestExtensionState(TestResourceManager testResourceManager, Closeable resource, Runnable clearCallbacks, + Optional listeningAddress, Map sysPropRestore) { + super(testResourceManager, resource, clearCallbacks, listeningAddress); this.sysPropRestore = sysPropRestore; } 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 fd22ebb1d7ced..4ff1a7c6b3fbe 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 @@ -1,6 +1,7 @@ package io.quarkus.test.junit; import static io.quarkus.deployment.util.ContainerRuntimeUtil.detectContainerRuntime; +import static io.quarkus.runtime.configuration.QuarkusConfigBuilderCustomizer.QUARKUS_PROFILE; import static io.quarkus.test.common.PathTestHelper.getAppClassLocationForTestLocation; import static io.quarkus.test.common.PathTestHelper.getTestClassesLocation; @@ -22,6 +23,7 @@ import java.util.Properties; import java.util.Set; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.stream.Collectors; import jakarta.enterprise.inject.Alternative; @@ -30,6 +32,7 @@ import org.apache.commons.lang3.RandomStringUtils; import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.config.spi.ConfigSource; import org.jboss.jandex.Index; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.platform.commons.JUnitException; @@ -51,6 +54,7 @@ import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.logging.LoggingSetupRecorder; import io.quarkus.test.common.ArtifactLauncher; +import io.quarkus.test.common.ListeningAddress; import io.quarkus.test.common.PathTestHelper; import io.quarkus.test.common.TestClassIndexer; import io.quarkus.test.common.TestResourceManager; @@ -120,8 +124,7 @@ static Map getSysPropsToRestore() { return sysPropRestore; } - static TestProfileAndProperties determineTestProfileAndProperties(Class profile, - Map sysPropRestore) + static TestProfileAndProperties determineTestProfileAndProperties(Class profile) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { final Map properties = new HashMap<>(); QuarkusTestProfile testProfile = null; @@ -144,23 +147,17 @@ static TestProfileAndProperties determineTestProfileAndProperties(Class i : properties.entrySet()) { - sysPropRestore.put(i.getKey(), System.getProperty(i.getKey())); - } - for (Map.Entry i : properties.entrySet()) { - System.setProperty(i.getKey(), i.getValue()); - } } // recalculate the property names that may have changed ConfigProvider.getConfig().unwrap(SmallRyeConfig.class).getLatestPropertyNames(); return new TestProfileAndProperties(testProfile, properties); } - static void startLauncher(ArtifactLauncher launcher, Map additionalProperties, Runnable sslSetter) + static Optional startLauncher(ArtifactLauncher launcher, Map additionalProperties) throws IOException { - launcher.includeAsSysProps(additionalProperties); try { - launcher.start(); + launcher.includeAsSysProps(additionalProperties); + return launcher.start(); } catch (IOException e) { try { launcher.close(); @@ -168,15 +165,12 @@ static void startLauncher(ArtifactLauncher launcher, Map additio } throw e; } - if (launcher.listensOnSsl()) { - if (sslSetter != null) { - sslSetter.run(); - } - } } - static ArtifactLauncher.InitContext.DevServicesLaunchResult handleDevServices(ExtensionContext context, - boolean isDockerAppLaunch) throws Exception { + static ArtifactLauncher.InitContext.DevServicesLaunchResult handleDevServices( + ExtensionContext context, + boolean isDockerAppLaunch, + TestProfileAndProperties testProfileAndProperties) throws Exception { Class requiredTestClass = context.getRequiredTestClass(); Path testClassLocation = getTestClassesLocation(requiredTestClass); final Path appClassLocation = getAppClassLocationForTestLocation(testClassLocation); @@ -245,8 +239,20 @@ static ArtifactLauncher.InitContext.DevServicesLaunchResult handleDevServices(Ex } runnerBuilder.setApplicationRoot(rootBuilder.build()); + // Set the config profile and properties overrides from the @TestProfile also for DevServices augmentation + Properties properties = new Properties(); + // Ensure that these properties cannot be overridden + properties.put(ConfigSource.CONFIG_ORDINAL, Integer.MAX_VALUE); + testProfileAndProperties.configProfile().ifPresent(new Consumer() { + @Override + public void accept(String configProfile) { + properties.put(QUARKUS_PROFILE, configProfile); + } + }); + properties.putAll(testProfileAndProperties.properties()); CuratedApplication curatedApplication = runnerBuilder .setTest(true) + .setBuildSystemProperties(properties) .build() .bootstrap(); diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java index 329c1a526f9e0..83d110603d99b 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusIntegrationTestExtension.java @@ -26,6 +26,7 @@ import java.util.Optional; import java.util.Properties; import java.util.ServiceLoader; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; @@ -46,7 +47,7 @@ import io.quarkus.runtime.logging.LogRuntimeConfig; import io.quarkus.runtime.test.TestHttpEndpointProvider; import io.quarkus.test.common.ArtifactLauncher; -import io.quarkus.test.common.DevServicesContext; +import io.quarkus.test.common.ListeningAddress; import io.quarkus.test.common.RestAssuredStateManager; import io.quarkus.test.common.RunCommandLauncher; import io.quarkus.test.common.TestConfigUtil; @@ -66,7 +67,6 @@ public class QuarkusIntegrationTestExtension extends AbstractQuarkusTestWithCont private static boolean failedBoot; private static List, String>> testHttpEndpointProviders; - private static boolean ssl; private static Class quarkusTestProfile; private static Throwable firstException; //if this is set then it will be thrown from the very first test that is run, the rest are aborted @@ -74,7 +74,6 @@ public class QuarkusIntegrationTestExtension extends AbstractQuarkusTestWithCont private static Class currentJUnitTestClass; private static Map devServicesProps; - private static String containerNetworkId; @Override public void afterTestExecution(ExtensionContext context) throws Exception { @@ -115,8 +114,14 @@ public void beforeEach(ExtensionContext context) throws Exception { if (!isBeforeEachCallbacksEmpty()) { invokeBeforeEachCallbacks(createQuarkusTestMethodContext(context)); } - - RestAssuredStateManager.setURL(ssl, QuarkusTestExtension.getEndpointPath(context, testHttpEndpointProviders)); + QuarkusTestExtensionState state = getState(context); + state.getListeningAddress().ifPresent(new Consumer() { + @Override + public void accept(ListeningAddress listeningAddress) { + RestAssuredStateManager.setURL(listeningAddress.isSsl(), listeningAddress.getPort(), + QuarkusTestExtension.getEndpointPath(context, testHttpEndpointProviders)); + } + }); TestScopeManager.setup(true); } } @@ -204,26 +209,25 @@ private QuarkusTestExtensionState doProcessStart(Properties quarkusArtifactPrope Map sysPropRestore = getSysPropsToRestore(); - TestProfileAndProperties testProfileAndProperties = determineTestProfileAndProperties(profile, sysPropRestore); + TestProfileAndProperties testProfileAndProperties = determineTestProfileAndProperties(profile); // prepare dev services after profile and properties have been determined ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult = handleDevServices(context, - isDockerLaunch); + isDockerLaunch, testProfileAndProperties); devServicesProps = devServicesLaunchResult.properties(); - containerNetworkId = devServicesLaunchResult.networkId(); for (String devServicesProp : devServicesProps.keySet()) { sysPropRestore.put(devServicesProp, null); // used to signal that the property needs to be cleared } - testResourceManager = new TestResourceManager(requiredTestClass, quarkusTestProfile, - copyEntriesFromProfile(testProfileAndProperties.testProfile, + testResourceManager = new TestResourceManager( + requiredTestClass, + quarkusTestProfile, + copyEntriesFromProfile(testProfileAndProperties.testProfile().orElse(null), context.getRequiredTestClass().getClassLoader()), - testProfileAndProperties.testProfile != null - && testProfileAndProperties.testProfile.disableGlobalTestResources(), - devServicesProps, containerNetworkId == null ? Optional.empty() : Optional.of(containerNetworkId)); - testResourceManager.init( - testProfileAndProperties.testProfile != null ? testProfileAndProperties.testProfile.getClass().getName() - : null); + testProfileAndProperties.isDisabledGlobalTestResources(), + devServicesProps, + Optional.ofNullable(devServicesLaunchResult.networkId())); + testResourceManager.init(testProfileAndProperties.testProfileClassName().orElse(null)); if (isCallbacksEnabledForIntegrationTests()) { populateCallbacks(requiredTestClass.getClassLoader()); @@ -242,7 +246,7 @@ private QuarkusTestExtensionState doProcessStart(Properties quarkusArtifactPrope } } - additionalProperties.putAll(testProfileAndProperties.properties); + additionalProperties.putAll(testProfileAndProperties.properties()); //we also make the dev services config accessible from the test itself Map resourceManagerProps = new HashMap<>(QuarkusIntegrationTestExtension.devServicesProps); // Allow override of dev services props by integration test extensions @@ -305,12 +309,12 @@ public void close() throws Exception { } activateLogging(); - startLauncher(launcher, additionalProperties, () -> ssl = true); + Optional listeningAddress = startLauncher(launcher, additionalProperties); Closeable resource = new IntegrationTestExtensionStateResource(launcher, devServicesLaunchResult.getCuratedApplication()); IntegrationTestExtensionState state = new IntegrationTestExtensionState(testResourceManager, resource, - AbstractTestWithCallbacksExtension::clearCallbacks, sysPropRestore); + AbstractTestWithCallbacksExtension::clearCallbacks, listeningAddress, sysPropRestore); testHttpEndpointProviders = TestHttpEndpointProvider.load(); return state; @@ -403,28 +407,6 @@ public ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchRes } } - private static class DefaultQuarkusIntegrationTestContext implements DevServicesContext { - - private final Map devServicesProperties; - private final Optional containerNetworkId; - - private DefaultQuarkusIntegrationTestContext(Map devServicesProperties, - Optional containerNetworkId) { - this.devServicesProperties = devServicesProperties; - this.containerNetworkId = containerNetworkId; - } - - @Override - public Map devServicesProperties() { - return devServicesProperties; - } - - @Override - public Optional containerNetworkId() { - return containerNetworkId; - } - } - private static final class IntegrationTestExtensionStateResource implements Closeable { private final ArtifactLauncher launcher; diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java index 0bea25b55acbc..031284094a50d 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusMainIntegrationTestExtension.java @@ -90,7 +90,8 @@ public void afterEach(ExtensionContext context) throws Exception { result = null; } - private void prepare(ExtensionContext extensionContext) throws Exception { + private void prepare(ExtensionContext extensionContext, TestProfileAndProperties testProfileAndProperties) + throws Exception { Class testClass = extensionContext.getRequiredTestClass(); ensureNoInjectAnnotationIsUsed(testClass, "@QuarkusMainIntegrationTest"); @@ -103,7 +104,7 @@ private void prepare(ExtensionContext extensionContext) throws Exception { boolean isDockerLaunch = isContainer(artifactType) || (isJar(artifactType) && "test-with-native-agent".equals(testConfig.integrationTestProfile())); - devServicesLaunchResult = handleDevServices(extensionContext, isDockerLaunch); + devServicesLaunchResult = handleDevServices(extensionContext, isDockerLaunch, testProfileAndProperties); devServicesProps = devServicesLaunchResult.properties(); ExtensionContext root = extensionContext.getRoot(); @@ -119,21 +120,20 @@ private ArtifactLauncher.LaunchResult doProcessStart(ExtensionContext context, S Class requiredTestClass = context.getRequiredTestClass(); Map sysPropRestore = getSysPropsToRestore(); - TestProfileAndProperties testProfileAndProperties = determineTestProfileAndProperties(profile, sysPropRestore); + TestProfileAndProperties testProfileAndProperties = determineTestProfileAndProperties(profile); // prepare dev services after profile and properties have been determined if (quarkusArtifactProperties == null) { - prepare(context); + prepare(context, testProfileAndProperties); } String artifactType = quarkusArtifactProperties.getProperty("type"); - testResourceManager = new TestResourceManager(requiredTestClass, profile, - copyEntriesFromProfile(testProfileAndProperties.testProfile, + testResourceManager = new TestResourceManager( + requiredTestClass, + profile, + copyEntriesFromProfile(testProfileAndProperties.testProfile().orElse(null), context.getRequiredTestClass().getClassLoader()), - testProfileAndProperties.testProfile != null - && testProfileAndProperties.testProfile.disableGlobalTestResources()); - testResourceManager.init( - testProfileAndProperties.testProfile != null ? testProfileAndProperties.testProfile.getClass().getName() - : null); + testProfileAndProperties.isDisabledGlobalTestResources()); + testResourceManager.init(testProfileAndProperties.testProfileClassName().orElse(null)); Map additionalProperties = new HashMap<>(); @@ -148,7 +148,7 @@ private ArtifactLauncher.LaunchResult doProcessStart(ExtensionContext context, S } } - additionalProperties.putAll(testProfileAndProperties.properties); + additionalProperties.putAll(testProfileAndProperties.properties()); //also make the dev services props accessible from the test Map resourceManagerProps = new HashMap<>(QuarkusMainIntegrationTestExtension.devServicesProps); // Allow override of dev services props by integration test extensions diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtensionState.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtensionState.java index aa477d6130b8c..7beec8185b93e 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtensionState.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/QuarkusTestExtensionState.java @@ -4,8 +4,10 @@ import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import io.quarkus.test.common.ListeningAddress; import io.quarkus.test.common.TestResourceManager; public class QuarkusTestExtensionState implements AutoCloseable { @@ -17,6 +19,7 @@ public class QuarkusTestExtensionState implements AutoCloseable { private Thread shutdownHook; private final Runnable clearCallbacks; private Throwable testErrorCause; + private Optional listeningAddress; // We need to move this between classloaders, and NewSerializingDeepClone can't clone this // Instead, clone by brute force and knowledge of internals @@ -78,6 +81,11 @@ public Runnable getClearCallbacksRunner() { return clearCallbacks; } + public Optional getListeningAddress() { + return listeningAddress; + } + + @Deprecated(forRemoval = true) public QuarkusTestExtensionState(Closeable testResourceManager, Closeable resource, Runnable clearCallbacks) { this.testResourceManager = testResourceManager; this.resource = resource; @@ -91,16 +99,32 @@ public void run() { } } }, "Quarkus Test Cleanup Shutdown task"); - Runtime.getRuntime() - .addShutdownHook(shutdownHook); + Runtime.getRuntime().addShutdownHook(shutdownHook); } public QuarkusTestExtensionState(Closeable testResourceManager, Closeable resource, Runnable clearCallbacks, - Thread shutdownHook) { + Optional listeningAddress) { this.testResourceManager = testResourceManager; this.resource = resource; this.clearCallbacks = clearCallbacks; + this.shutdownHook = new Thread(new Runnable() { + @Override + public void run() { + try { + QuarkusTestExtensionState.this.close(); + } catch (IOException ignored) { + } + } + }, "Quarkus Test Cleanup Shutdown task"); + Runtime.getRuntime().addShutdownHook(shutdownHook); + this.listeningAddress = listeningAddress; + } + public QuarkusTestExtensionState(Closeable testResourceManager, Closeable resource, Runnable clearCallbacks, + Thread shutdownHook) { + this.testResourceManager = testResourceManager; + this.resource = resource; + this.clearCallbacks = clearCallbacks; this.shutdownHook = shutdownHook; } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestProfileAndProperties.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestProfileAndProperties.java index 2cdbe83f48fb6..96422e1f03986 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestProfileAndProperties.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/TestProfileAndProperties.java @@ -1,13 +1,35 @@ package io.quarkus.test.junit; +import java.util.Collections; import java.util.Map; +import java.util.Optional; final class TestProfileAndProperties { - final QuarkusTestProfile testProfile; - final Map properties; + private final QuarkusTestProfile testProfile; + private final Map properties; - public TestProfileAndProperties(QuarkusTestProfile testProfile, Map properties) { + TestProfileAndProperties(QuarkusTestProfile testProfile, Map properties) { this.testProfile = testProfile; - this.properties = properties; + this.properties = properties != null ? properties : Collections.emptyMap(); + } + + public Optional testProfile() { + return Optional.ofNullable(testProfile); + } + + Map properties() { + return Collections.unmodifiableMap(properties); + } + + Optional configProfile() { + return testProfile().map(QuarkusTestProfile::getConfigProfile); + } + + boolean isDisabledGlobalTestResources() { + return testProfile().map(QuarkusTestProfile::disableGlobalTestResources).orElse(false); + } + + Optional testProfileClassName() { + return testProfile().map(testProfile -> testProfile.getClass().getName()); } }