From 1519b51ebbb9d5c5180bb6db30687786ae43639c Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 25 Nov 2025 01:00:51 +0000 Subject: [PATCH 1/2] API to store real Runtime values --- .../io/quarkus/runtime/RuntimeValues.java | 101 ++++++++++++++++++ .../runtime/RuntimeValuesConfigSource.java | 31 ++++++ .../configuration/RuntimeConfigBuilder.java | 2 + 3 files changed, 134 insertions(+) create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/RuntimeValues.java create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/RuntimeValuesConfigSource.java diff --git a/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValues.java b/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValues.java new file mode 100644 index 0000000000000..5ff9bddf0af15 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValues.java @@ -0,0 +1,101 @@ +package io.quarkus.runtime; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Provides a low-level API for registering and accessing runtime values generated by Quarkus or Quarkus + * extensions. Typically, such values describe a fully configured application, known only at application startup, + * such as the HTTP port. + *

+ * These values should not be exposed by the Config mechanism directly, as that would require mutating the Config + * system, which should be immutable, and cause hard-to-debug issues. Instead, RuntimeValues should be preferred for + * exposing such values. + */ +public class RuntimeValues { + private static final Map values = new ConcurrentHashMap<>(); + + /** + * Registers a value with a specified key. + * + * @param key key with which the specified value is to be associated + * @param value value to be associated with the specified key + * @return the value associated with the specified key + * @throws IllegalArgumentException if the specified key already has an associated value + */ + @SuppressWarnings("unchecked") + public static T register(final RuntimeKey key, final T value) { + Object mapValue = values.putIfAbsent(key.key(), value); + if (mapValue != null && !mapValue.equals(value)) { + throw new IllegalArgumentException("Key already registered " + key.key() + " with value " + mapValue); + } + return (T) mapValue; + } + + /** + * Returns the value to which the specified key is mapped. + * + * @param key the key whose associated value is to be returned + * @return the value to which the specified key is mapped + * @throws java.lang.IllegalArgumentException if the specified key has no associated value + */ + @SuppressWarnings("unchecked") + public static T get(final RuntimeKey key) { + T t = (T) values.get(key.key()); + if (t == null) { + throw new IllegalArgumentException("Key " + key.key() + " not found"); + } + return t; + } + + /** + * Returns the value to which the specified key is mapped. + * + * @param key the key whose associated value is to be returned + * @param defaultValue the default mapping of the key + * @return the value to which the specified key is mapped, or {@code defaultValue} if the key has no value + */ + @SuppressWarnings("unchecked") + public static T get(final RuntimeKey key, final T defaultValue) { + return (T) values.getOrDefault(key.key(), defaultValue); + } + + static String getValue(final String propertyName) { + Object value = values.get(propertyName); + // TODO - We may require to convert this to the expected config string + return value != null ? value.toString() : null; + } + + public static final class RuntimeKey { + private final String key; + + RuntimeKey(String key) { + this.key = key; + } + + public String key() { + return key; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof RuntimeKey that)) + return false; + return Objects.equals(key, that.key); + } + + @Override + public int hashCode() { + return Objects.hashCode(key); + } + + public static RuntimeKey key(final String key) { + return new RuntimeKey<>(key); + } + + public static RuntimeKey intKey(final String key) { + return new RuntimeKey<>(key); + } + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValuesConfigSource.java b/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValuesConfigSource.java new file mode 100644 index 0000000000000..7eeff8ed66615 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/RuntimeValuesConfigSource.java @@ -0,0 +1,31 @@ +package io.quarkus.runtime; + +import java.util.Set; + +import io.smallrye.config.common.AbstractConfigSource; + +/** + * A ConfigSource to bridge between Config and {@link RuntimeValues}. + *

+ * While {@link RuntimeValues} shouldn't be exposed as Config, this is intended to + * work as a temporary compatibility layer, since until the introduction of {@link RuntimeValues}, + * the norm was to use Config to relay this kind of information. + *

+ * This should be kept until we decide on an alternate solution in the discussion + * #46915. + */ +public class RuntimeValuesConfigSource extends AbstractConfigSource { + public RuntimeValuesConfigSource() { + super(RuntimeValuesConfigSource.class.getName(), Integer.MAX_VALUE - 10); + } + + @Override + public Set getPropertyNames() { + return Set.of(); + } + + @Override + public String getValue(String propertyName) { + return RuntimeValues.getValue(propertyName); + } +} diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java index 64279e30a9388..85b6b5a71d3a6 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/RuntimeConfigBuilder.java @@ -5,6 +5,7 @@ import org.eclipse.microprofile.config.spi.ConfigSource; +import io.quarkus.runtime.RuntimeValuesConfigSource; import io.smallrye.config.SmallRyeConfigBuilder; import io.smallrye.config.SmallRyeConfigBuilderCustomizer; @@ -15,6 +16,7 @@ public class RuntimeConfigBuilder implements SmallRyeConfigBuilderCustomizer { @Override public void configBuilder(final SmallRyeConfigBuilder builder) { new QuarkusConfigBuilderCustomizer().configBuilder(builder); + builder.withSources(new RuntimeValuesConfigSource()); builder.withSources(new UuidConfigSource()); builder.forClassLoader(Thread.currentThread().getContextClassLoader()) From c8d2d14465b234e12d259e1cc4dea9261a355411 Mon Sep 17 00:00:00 2001 From: Roberto Cortez Date: Tue, 25 Nov 2025 01:01:03 +0000 Subject: [PATCH 2/2] Use RuntimeValues to store and retrieve the real runtime values of HTTP ports --- .../http/deployment/VertxHttpProcessor.java | 2 + .../io/quarkus/vertx/http/HttpServerTest.java | 27 +++++++ .../io/quarkus/vertx/http/RandomPortTest.java | 17 +++-- .../vertx/http/runtime/HttpServer.java | 74 +++++++++++++++++++ .../http/runtime/HttpServerProducer.java | 13 ++++ .../vertx/http/runtime/VertxHttpRecorder.java | 63 +++------------- .../test/HttpFunctionRandomPortTestCase.java | 20 +++-- .../RandomPortVertxServerTlsTestBase.java | 2 +- .../it/vertx/RandomTestPortTestCase.java | 20 ----- .../DefaultDockerContainerLauncher.java | 4 +- .../test/common/DefaultJarLauncher.java | 4 +- .../common/DefaultNativeImageLauncher.java | 4 +- .../io/quarkus/test/common/LauncherUtil.java | 8 +- .../test/common/RestAssuredURLManager.java | 33 +++++---- .../functions/test/CloudFunctionsInvoker.java | 7 +- 15 files changed, 183 insertions(+), 115 deletions(-) create mode 100644 extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/HttpServerTest.java create mode 100644 extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServer.java create mode 100644 extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServerProducer.java diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java index a18c7e48697a9..f25f9223470ef 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java @@ -68,6 +68,7 @@ import io.quarkus.vertx.http.runtime.CurrentRequestProducer; import io.quarkus.vertx.http.runtime.CurrentVertxRequest; import io.quarkus.vertx.http.runtime.HttpCertificateUpdateEventListener; +import io.quarkus.vertx.http.runtime.HttpServerProducer; import io.quarkus.vertx.http.runtime.VertxConfigBuilder; import io.quarkus.vertx.http.runtime.VertxHttpBuildTimeConfig; import io.quarkus.vertx.http.runtime.VertxHttpConfig.InsecureRequests; @@ -161,6 +162,7 @@ FilterBuildItem cors(CORSRecorder recorder, AdditionalBeanBuildItem additionalBeans() { return AdditionalBeanBuildItem.builder() .setUnremovable() + .addBeanClass(HttpServerProducer.class) .addBeanClass(CurrentVertxRequest.class) .addBeanClass(CurrentRequestProducer.class) .addBeanClass(HttpCertificateUpdateEventListener.class) diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/HttpServerTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/HttpServerTest.java new file mode 100644 index 0000000000000..5e55253a8636f --- /dev/null +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/HttpServerTest.java @@ -0,0 +1,27 @@ +package io.quarkus.vertx.http; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.vertx.http.runtime.HttpServer; + +public class HttpServerTest { + @RegisterExtension + static final QuarkusUnitTest CONFIG = new QuarkusUnitTest(); + + @Inject + HttpServer webServer; + + @Test + void ports() { + assertTrue(webServer.getPort() > 0); + assertEquals(-1, webServer.getSecurePort()); + assertEquals(-1, webServer.getManagementPort()); + } +} diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/RandomPortTest.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/RandomPortTest.java index 6527a9383f0b5..aff54eea077ed 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/RandomPortTest.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/RandomPortTest.java @@ -5,9 +5,9 @@ import java.net.URL; import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; import org.eclipse.microprofile.config.ConfigProvider; -import org.eclipse.microprofile.config.inject.ConfigProperty; import org.hamcrest.Matchers; import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.Test; @@ -15,6 +15,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.quarkus.test.common.http.TestHTTPResource; +import io.quarkus.vertx.http.runtime.VertxHttpConfig; import io.restassured.RestAssured; import io.vertx.core.Handler; import io.vertx.ext.web.Router; @@ -30,6 +31,8 @@ public class RandomPortTest { @TestHTTPResource("test") URL url; + @Inject + VertxHttpConfig vertxHttpConfig; @Test public void portShouldNotBeZero() { @@ -42,16 +45,17 @@ public void testActualPortAccessibleToApp() { RestAssured.get("/app").then().body(Matchers.equalTo(Integer.toString(url.getPort()))); } - public static class AppClass { - - @ConfigProperty(name = "quarkus.http.port") - String port; + @Test + void mappingPortIsZero() { + assertThat(vertxHttpConfig.testPort()).isZero(); + } + public static class AppClass { public void route(@Observes Router router) { router.route("/test").handler(new Handler() { @Override public void handle(RoutingContext event) { - event.response().end(System.getProperty("quarkus.http.test-port")); + event.response().end(ConfigProvider.getConfig().getValue("quarkus.http.test-port", String.class)); } }); router.route("/app").handler(new Handler() { @@ -62,5 +66,4 @@ public void handle(RoutingContext event) { }); } } - } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServer.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServer.java new file mode 100644 index 0000000000000..db810455dafd9 --- /dev/null +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServer.java @@ -0,0 +1,74 @@ +package io.quarkus.vertx.http.runtime; + +import io.quarkus.runtime.RuntimeValues; +import io.quarkus.runtime.RuntimeValues.RuntimeKey; + +public class HttpServer { + private final static HttpServer INSTANCE = new HttpServer(); + + public static final RuntimeKey HTTP_PORT = RuntimeKey.intKey("quarkus.http.port"); + public static final RuntimeKey HTTP_TEST_PORT = RuntimeKey.intKey("quarkus.http.test-port"); + public static final RuntimeKey HTTPS_PORT = RuntimeKey.intKey("quarkus.http.ssl-port"); + public static final RuntimeKey HTTPS_TEST_PORT = RuntimeKey.intKey("quarkus.http.test-ssl-port"); + public static final RuntimeKey MANAGEMENT_PORT = RuntimeKey.intKey("quarkus.management.port"); + public static final RuntimeKey MANAGEMENT_TEST_PORT = RuntimeKey.intKey("quarkus.management.test-port"); + + private HttpServer() { + } + + /** + * Return the http port that Quarkus is listening on. + * + * @return the port or -1 if Quarkus is not set to listen to the http port. + */ + public int getPort() { + // TODO - What if this method gets called before being set? Should this be an event instead? + return RuntimeValues.get(HTTP_PORT, -1); + } + + static void setPort(int port) { + RuntimeValues.register(HTTP_PORT, port); + } + + static void setTestPort(int testPort) { + RuntimeValues.register(HTTP_TEST_PORT, testPort); + } + + /** + * Return the https port that Quarkus is listening on. + * + * @return the port or -1 if Quarkus is not set to listen to the https port. + */ + public int getSecurePort() { + return RuntimeValues.get(HTTPS_PORT, -1); + } + + static void setSecurePort(int port) { + RuntimeValues.register(HTTPS_PORT, port); + } + + static void setSecureTestPort(int testPort) { + RuntimeValues.register(HTTPS_TEST_PORT, testPort); + } + + /** + * Return the management http port that Quarkus is listening on. + * + * @return the port or -1 if Quarkus is not set to listen to the management http port. + */ + public int getManagementPort() { + return RuntimeValues.get(MANAGEMENT_PORT, -1); + } + + static void setManagementPort(int managementPort) { + RuntimeValues.register(MANAGEMENT_PORT, managementPort); + } + + static void setManagementTestPort(int testPort) { + RuntimeValues.register(MANAGEMENT_TEST_PORT, testPort); + } + + public static HttpServer instance() { + return INSTANCE; + } +} diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServerProducer.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServerProducer.java new file mode 100644 index 0000000000000..8baac39cdb952 --- /dev/null +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpServerProducer.java @@ -0,0 +1,13 @@ +package io.quarkus.vertx.http.runtime; + +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Singleton; + +@Singleton +public class HttpServerProducer { + @Produces + @Singleton + public HttpServer producer() { + return HttpServer.instance(); + } +} diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java index d97ae42cc7a5f..4d131ed67d72d 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java @@ -100,7 +100,6 @@ import io.smallrye.config.SmallRyeConfigBuilderCustomizer; import io.vertx.core.AbstractVerticle; import io.vertx.core.AsyncResult; -import io.vertx.core.Closeable; import io.vertx.core.Context; import io.vertx.core.DeploymentOptions; import io.vertx.core.Handler; @@ -769,15 +768,10 @@ private static CompletableFuture initializeManagementInterface(Vertx actualManagementPort = ar.result().actualPort(); if (actualManagementPort != httpManagementServerOptions.getPort()) { - var managementPortSystemProperties = new PortSystemProperties(); - managementPortSystemProperties.set("management", actualManagementPort, launchMode); - ((VertxInternal) vertx).addCloseHook(new Closeable() { - @Override - public void close(Promise completion) { - managementPortSystemProperties.restore(); - completion.complete(); - } - }); + io.quarkus.vertx.http.runtime.HttpServer.setManagementPort(actualManagementPort); + if (launchMode.isDevOrTest()) { + io.quarkus.vertx.http.runtime.HttpServer.setManagementTestPort(actualManagementPort); + } } managementInterfaceFuture.complete(ar.result()); } @@ -1180,9 +1174,6 @@ private static class WebDeploymentVerticle extends AbstractVerticle implements R private final HttpServerOptions httpsOptions; private final HttpServerOptions domainSocketOptions; private final LaunchMode launchMode; - private volatile boolean clearHttpProperty = false; - private volatile boolean clearHttpsProperty = false; - private volatile PortSystemProperties portSystemProperties; private final InsecureRequests insecureRequests; private final VertxHttpConfig quarkusConfig; private final AtomicInteger connectionCount; @@ -1364,23 +1355,17 @@ public void handle(AsyncResult event) { if (https) { actualHttpsPort = actualPort; validateHttpPorts(actualHttpPort, actualHttpsPort); + io.quarkus.vertx.http.runtime.HttpServer.setSecurePort(actualPort); + if (launchMode.isDevOrTest()) { + io.quarkus.vertx.http.runtime.HttpServer.setSecureTestPort(actualPort); + } } else { actualHttpPort = actualPort; validateHttpPorts(actualHttpPort, actualHttpsPort); - } - if (actualPort != options.getPort()) { - // Override quarkus.http(s)?.(test-)?port - String schema; - if (https) { - clearHttpsProperty = true; - schema = "https"; - } else { - clearHttpProperty = true; - actualHttpPort = actualPort; - schema = "http"; + io.quarkus.vertx.http.runtime.HttpServer.setPort(actualPort); + if (launchMode.isDevOrTest()) { + io.quarkus.vertx.http.runtime.HttpServer.setTestPort(actualPort); } - portSystemProperties = new PortSystemProperties(); - portSystemProperties.set(schema, actualPort, launchMode); } if (https && (quarkusConfig.ssl().certificate().reloadPeriod().isPresent())) { @@ -1451,28 +1436,6 @@ public void stop(Promise stopFuture) { Handler> handleClose = event -> { if (remainingCount.decrementAndGet() == 0) { - - if (clearHttpProperty) { - String portPropertyName = launchMode == LaunchMode.TEST ? "quarkus.http.test-port" - : "quarkus.http.port"; - System.clearProperty(portPropertyName); - if (launchMode.isDevOrTest()) { - System.clearProperty(propertyWithProfilePrefix(portPropertyName)); - } - - } - if (clearHttpsProperty) { - String portPropertyName = launchMode == LaunchMode.TEST ? "quarkus.http.test-ssl-port" - : "quarkus.http.ssl-port"; - System.clearProperty(portPropertyName); - if (launchMode.isDevOrTest()) { - System.clearProperty(propertyWithProfilePrefix(portPropertyName)); - } - } - if (portSystemProperties != null) { - portSystemProperties.restore(); - } - stopFuture.complete(); } }; @@ -1488,10 +1451,6 @@ public void stop(Promise stopFuture) { } } - private String propertyWithProfilePrefix(String portPropertyName) { - return "%" + launchMode.getDefaultProfile() + "." + portPropertyName; - } - @Override public void beforeCheckpoint(org.crac.Context context) throws Exception { Promise p = Promise.promise(); diff --git a/integration-tests/google-cloud-functions/src/test/java/io/quarkus/gcp/function/test/HttpFunctionRandomPortTestCase.java b/integration-tests/google-cloud-functions/src/test/java/io/quarkus/gcp/function/test/HttpFunctionRandomPortTestCase.java index 62bc600f3ff76..e8983b57d4f70 100644 --- a/integration-tests/google-cloud-functions/src/test/java/io/quarkus/gcp/function/test/HttpFunctionRandomPortTestCase.java +++ b/integration-tests/google-cloud-functions/src/test/java/io/quarkus/gcp/function/test/HttpFunctionRandomPortTestCase.java @@ -3,22 +3,21 @@ import static io.restassured.RestAssured.when; import static org.hamcrest.Matchers.is; -import org.junit.jupiter.api.BeforeAll; +import java.util.Map; + import org.junit.jupiter.api.Test; +import io.quarkus.gcp.function.test.HttpFunctionRandomPortTestCase.RandomPort; import io.quarkus.google.cloud.functions.test.FunctionType; import io.quarkus.google.cloud.functions.test.WithFunction; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.QuarkusTestProfile; +import io.quarkus.test.junit.TestProfile; @QuarkusTest +@TestProfile(RandomPort.class) @WithFunction(FunctionType.HTTP) class HttpFunctionRandomPortTestCase { - - @BeforeAll - public static void setup() { - System.setProperty("quarkus.http.test-port", "0"); - } - @Test public void test() { // test the function using RestAssured @@ -28,4 +27,11 @@ public void test() { .statusCode(200) .body(is("Hello World!")); } + + public static class RandomPort implements QuarkusTestProfile { + @Override + public Map getConfigOverrides() { + return Map.of("quarkus.http.test-port", "0"); + } + } } diff --git a/integration-tests/grpc-test-random-port/src/test/java/io/quarkus/grpc/examples/hello/RandomPortVertxServerTlsTestBase.java b/integration-tests/grpc-test-random-port/src/test/java/io/quarkus/grpc/examples/hello/RandomPortVertxServerTlsTestBase.java index 93f7d45925c45..5320de108a146 100644 --- a/integration-tests/grpc-test-random-port/src/test/java/io/quarkus/grpc/examples/hello/RandomPortVertxServerTlsTestBase.java +++ b/integration-tests/grpc-test-random-port/src/test/java/io/quarkus/grpc/examples/hello/RandomPortVertxServerTlsTestBase.java @@ -21,6 +21,6 @@ public Map getConfigOverrides() { @Override protected String serverPortProperty() { - return "quarkus.https.test-port"; + return "quarkus.http.test-ssl-port"; } } diff --git a/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/RandomTestPortTestCase.java b/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/RandomTestPortTestCase.java index b8275f241d538..c8cb286c9a5e9 100644 --- a/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/RandomTestPortTestCase.java +++ b/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/RandomTestPortTestCase.java @@ -5,10 +5,7 @@ import java.net.URL; import java.util.Map; -import java.util.Optional; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.ConfigProvider; import org.eclipse.microprofile.config.inject.ConfigProperty; import org.junit.jupiter.api.Test; @@ -59,23 +56,6 @@ public void testHttpsTestPort() { assertEquals(httpsTestPort, httpsTestUrl.getPort()); } - @Test - public void testLegacyProperties() { - Config config = ConfigProvider.getConfig(); - - testLegacyProperty(config, "quarkus.http.ssl-port", "quarkus.https.port", httpsPort); - testLegacyProperty(config, "quarkus.http.test-ssl-port", "quarkus.https.test-port", httpsTestPort); - testLegacyProperty(config, "%test.quarkus.http.ssl-port", "%test.quarkus.https.port", httpsTestPort); - } - - private void testLegacyProperty(Config config, String correctName, String legacyName, int expectedValue) { - Optional portWithCorrectProperty = config.getOptionalValue(correctName, Integer.class); - Optional portWithLegacyProperty = config.getOptionalValue(legacyName, Integer.class); - - assertEquals(Optional.of(expectedValue), portWithCorrectProperty); - assertEquals(portWithCorrectProperty, portWithLegacyProperty); - } - public static class TestPortProfile implements QuarkusTestProfile { @Override 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..a359638945733 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,7 @@ 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.registerRuntimeValues; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; import static java.lang.ProcessBuilder.Redirect.DISCARD; @@ -308,7 +308,7 @@ public void start() throws IOException { log.info("Wait for server to start by capturing listening data..."); final ListeningAddress result = waitForCapturedListeningData(containerProcess, logPath, waitTimeSeconds); log.infof("Server started on port %s", result.getPort()); - updateConfigForPort(result.getPort()); + registerRuntimeValues(result.getPort()); isSsl = result.isSsl(); } } 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..9e46e000f39fb 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,7 @@ 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.registerRuntimeValues; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; @@ -83,7 +83,7 @@ public void start() throws IOException { } else { ListeningAddress result = waitForCapturedListeningData(quarkusProcess, logRuntimeConfig.file().path().toPath(), waitTimeSeconds); - updateConfigForPort(result.getPort()); + registerRuntimeValues(result.getPort()); isSsl = result.isSsl(); } } 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 08da6ccd05d11..a58406cf5ff87 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,7 @@ 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.registerRuntimeValues; import static io.quarkus.test.common.LauncherUtil.waitForCapturedListeningData; import static io.quarkus.test.common.LauncherUtil.waitForStartedFunction; @@ -118,7 +118,7 @@ public void start() throws IOException { } else { ListeningAddress result = waitForCapturedListeningData(quarkusProcess, logRuntimeConfig.file().path().toPath(), waitTimeSeconds); - updateConfigForPort(result.getPort()); + registerRuntimeValues(result.getPort()); isSsl = result.isSsl(); } } 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..2282709717b86 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,6 +23,8 @@ import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; +import io.quarkus.runtime.RuntimeValues; +import io.quarkus.runtime.RuntimeValues.RuntimeKey; import io.quarkus.test.common.http.TestHTTPResourceManager; import io.smallrye.common.os.OS; @@ -212,10 +214,10 @@ static IntegrationTestStartedNotifier.Result waitForStartedFunction( * 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) { + static void registerRuntimeValues(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 + RuntimeValues.register(RuntimeKey.intKey("quarkus.http.port"), effectivePort); + RuntimeValues.register(RuntimeKey.intKey("quarkus.http.test-port"), effectivePort); System.clearProperty("test.url"); // make sure the old value does not interfere with setting the new one System.setProperty("test.url", TestHTTPResourceManager.getUri()); } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/RestAssuredURLManager.java b/test-framework/common/src/main/java/io/quarkus/test/common/RestAssuredURLManager.java index ec615d334a041..78cdf58d8fa1d 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/RestAssuredURLManager.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/RestAssuredURLManager.java @@ -5,10 +5,13 @@ import org.eclipse.microprofile.config.ConfigProvider; +import io.quarkus.runtime.RuntimeValues; +import io.quarkus.runtime.RuntimeValues.RuntimeKey; import io.restassured.RestAssured; import io.restassured.config.HttpClientConfig; import io.restassured.config.RestAssuredConfig; import io.restassured.specification.RequestSpecification; +import io.smallrye.config.SmallRyeConfig; /** * Utility class that sets the rest assured port to the default test port and meaningful timeouts. @@ -45,15 +48,6 @@ private RestAssuredURLManager() { } - private static int getPortFromConfig(int defaultValue, String... keys) { - for (String key : keys) { - Optional port = ConfigProvider.getConfig().getOptionalValue(key, Integer.class); - if (port.isPresent()) - return port.get(); - } - return defaultValue; - } - public static void setURL(boolean useSecureConnection) { setURL(useSecureConnection, null, null); } @@ -71,17 +65,24 @@ public static void setURL(boolean useSecureConnection, Integer port, String addi return; } + SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class); + oldPort = RestAssured.port; if (port == null) { - port = useSecureConnection ? getPortFromConfig(DEFAULT_HTTPS_PORT, "quarkus.http.test-ssl-port") - : getPortFromConfig(DEFAULT_HTTP_PORT, "quarkus.lambda.mock-event-server.test-port", - "quarkus.http.test-port"); + if (useSecureConnection) { + port = RuntimeValues.get(RuntimeKey.intKey("quarkus.http.test-ssl-port"), DEFAULT_HTTPS_PORT); + } else { + // TODO - We shouldn't leak extension configuration here + port = config + .getOptionalValue("quarkus.lambda.mock-event-server.test-port", int.class) + .orElse(RuntimeValues.get(RuntimeKey.intKey("quarkus.http.test-port"), DEFAULT_HTTP_PORT)); + } } RestAssured.port = port; oldBaseURI = RestAssured.baseURI; final String protocol = useSecureConnection ? "https://" : "http://"; - String host = ConfigProvider.getConfig().getOptionalValue("quarkus.http.host", String.class) + String host = config.getOptionalValue("quarkus.http.host", String.class) .orElse("localhost"); if (host.equals("0.0.0.0")) { host = "localhost"; @@ -89,7 +90,7 @@ public static void setURL(boolean useSecureConnection, Integer port, String addi RestAssured.baseURI = protocol + host; oldBasePath = RestAssured.basePath; - Optional basePath = ConfigProvider.getConfig().getOptionalValue("quarkus.http.root-path", + Optional basePath = config.getOptionalValue("quarkus.http.root-path", String.class); if (basePath.isPresent() || additionalPath != null) { StringBuilder bp = new StringBuilder(); @@ -117,12 +118,12 @@ public static void setURL(boolean useSecureConnection, Integer port, String addi oldRestAssuredConfig = RestAssured.config(); - Duration timeout = ConfigProvider.getConfig() + Duration timeout = config .getOptionalValue("quarkus.http.test-timeout", Duration.class).orElse(Duration.ofSeconds(30)); configureTimeouts(timeout); oldRequestSpecification = RestAssured.requestSpecification; - if (ConfigProvider.getConfig() + if (config .getOptionalValue("quarkus.test.rest-assured.enable-logging-on-failure", Boolean.class).orElse(true)) { RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); } diff --git a/test-framework/google-cloud-functions/src/main/java/io/quarkus/google/cloud/functions/test/CloudFunctionsInvoker.java b/test-framework/google-cloud-functions/src/main/java/io/quarkus/google/cloud/functions/test/CloudFunctionsInvoker.java index efe8648db5351..60f28ac933aa1 100644 --- a/test-framework/google-cloud-functions/src/main/java/io/quarkus/google/cloud/functions/test/CloudFunctionsInvoker.java +++ b/test-framework/google-cloud-functions/src/main/java/io/quarkus/google/cloud/functions/test/CloudFunctionsInvoker.java @@ -2,6 +2,9 @@ import com.google.cloud.functions.invoker.runner.Invoker; +import io.quarkus.runtime.RuntimeValues; +import io.quarkus.runtime.RuntimeValues.RuntimeKey; + class CloudFunctionsInvoker { private final Invoker invoker; @@ -12,9 +15,7 @@ class CloudFunctionsInvoker { CloudFunctionsInvoker(FunctionType functionType, int port) { int realPort = port == 0 ? SocketUtil.findAvailablePort() : port; - if (realPort != port) { - System.setProperty("quarkus.http.test-port", String.valueOf(realPort)); - } + RuntimeValues.register(RuntimeKey.intKey("quarkus.http.test-port"), realPort); this.invoker = new Invoker( realPort, functionType.getTarget(),