Run tests on various free ports instead of 9998 (#5213)

* Run tests on various free ports instead of 9998

Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
index 3a52c65..127668b 100644
--- a/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
+++ b/connectors/netty-connector/src/test/java/org/glassfish/jersey/netty/connector/FollowRedirectsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,7 @@
 import static org.junit.jupiter.api.Assertions.fail;
 
 import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.logging.Logger;
 
 import javax.ws.rs.GET;
@@ -37,12 +38,20 @@
 import org.glassfish.jersey.netty.connector.internal.RedirectException;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 public class FollowRedirectsTest extends JerseyTest {
 
     private static final Logger LOGGER = Logger.getLogger(FollowRedirectsTest.class.getName());
-    private static final String TEST_URL = "http://localhost:9998/test";
+    private static final String TEST_URL = "http://localhost:%d/test";
+    private static final AtomicReference<String> TEST_URL_REF = new AtomicReference<>();
+
+    @BeforeEach
+    public void before() {
+        final String url = String.format(TEST_URL, getPort());
+        TEST_URL_REF.set(url);
+    }
 
     @Path("/test")
     public static class RedirectResource {
@@ -54,19 +63,19 @@
         @GET
         @Path("redirect")
         public Response redirect() {
-            return Response.seeOther(URI.create(TEST_URL)).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get())).build();
         }
 
         @GET
         @Path("loop")
         public Response loop() {
-            return Response.seeOther(URI.create(TEST_URL + "/loop")).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get() + "/loop")).build();
         }
 
         @GET
         @Path("redirect2")
         public Response redirect2() {
-            return Response.seeOther(URI.create(TEST_URL + "/redirect")).build();
+            return Response.seeOther(URI.create(TEST_URL_REF.get() + "/redirect")).build();
         }
     }
 
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
index 02b4773..a3f3749 100644
--- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
+++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/AbstractJdkHttpServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.ws.rs.RuntimeType;
 import javax.ws.rs.core.UriBuilder;
 
 import com.sun.net.httpserver.HttpServer;
@@ -37,7 +38,7 @@
 public abstract class AbstractJdkHttpServerTester {
 
     public static final String CONTEXT = "";
-    private final int DEFAULT_PORT = 9998;
+    private final int DEFAULT_PORT = 0; // rather JDK server choose than 9998
 
     private static final Logger LOGGER = Logger.getLogger(AbstractJdkHttpServerTester.class.getName());
 
@@ -47,6 +48,9 @@
      * @return The HTTP port of the URI
      */
     protected final int getPort() {
+        if (server != null) {
+            return server.getAddress().getPort();
+        }
         final String value =
                 AccessController.doPrivileged(PropertiesHelper.getSystemProperty("jersey.config.test.container.port"));
         if (value != null) {
@@ -68,10 +72,20 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getAddress().getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
     private volatile HttpServer server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -79,18 +93,18 @@
         config.register(LoggingFeature.class);
         final URI baseUri = getBaseUri();
         server = JdkHttpServerFactory.createHttpServer(baseUri, config);
-        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         config.register(LoggingFeature.class);
         server = JdkHttpServerFactory.createHttpServer(baseUri, config);
-        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "jdk-http server started on base uri: " + server.getAddress());
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void stopServer() {
diff --git a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
index 02a0dda..fc6913e 100644
--- a/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
+++ b/containers/jdk-http/src/test/java/org/glassfish/jersey/jdkhttp/JdkHttpsServerTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -116,7 +116,7 @@
             // access the https server with not configured client
             final Client client = ClientBuilder.newBuilder().newClient();
             try {
-                client.target(httpsUri).path("testHttps").request().get(String.class);
+                client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
             } catch (final ProcessingException e) {
                 throw e.getCause();
             }
@@ -136,8 +136,8 @@
             server.start();
 
             final Client client = ClientBuilder.newBuilder().newClient();
-           try {
-                client.target(httpsUri).path("testHttps").request().get(String.class);
+            try {
+                client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
             } catch (final ProcessingException e) {
                 throw e.getCause();
             }
@@ -173,7 +173,7 @@
 
         final SSLContext clientSslContext = getClientSslContext();
         final Client client = ClientBuilder.newBuilder().sslContext(clientSslContext).build();
-        final String response = client.target(httpsUri).path("testHttps").request().get(String.class);
+        final String response = client.target(updatePort(httpsUri)).path("testHttps").request().get(String.class);
 
         assertEquals("test", response);
     }
@@ -216,6 +216,11 @@
         return sslConfigServer.createSSLContext();
     }
 
+
+    private URI updatePort(URI uri) {
+        return UriBuilder.fromUri(httpsUri).port(server.getAddress().getPort()).build();
+    }
+
     @AfterEach
     public void tearDown() {
         if (server != null) {
diff --git a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
index 13bfe6a..34d6d4c 100644
--- a/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
+++ b/containers/jetty-http/src/test/java/org/glassfish/jersey/jetty/AbstractJettyServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.ws.rs.RuntimeType;
 import javax.ws.rs.core.UriBuilder;
 
 import org.glassfish.jersey.logging.LoggingFeature;
@@ -42,7 +43,7 @@
     private static final Logger LOGGER = Logger.getLogger(AbstractJettyServerTester.class.getName());
 
     public static final String CONTEXT = "";
-    private static final int DEFAULT_PORT = 9998;
+    private static final int DEFAULT_PORT = 0; // rather Jetty choose than 9998
 
     /**
      * Get the port to be used for test application deployments.
@@ -71,10 +72,21 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getURI().getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
+
     private volatile Server server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -82,17 +94,17 @@
         config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY));
         final URI baseUri = getBaseUri();
         server = JettyHttpContainerFactory.createServer(baseUri, config);
-        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         server = JettyHttpContainerFactory.createServer(baseUri, config);
-        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Jetty-http server started on base uri: " + server.getURI());
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void stopServer() {
diff --git a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
index 290de52..f5025ee 100644
--- a/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
+++ b/containers/simple-http/src/test/java/org/glassfish/jersey/simple/AbstractSimpleServerTester.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -21,6 +21,7 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javax.ws.rs.RuntimeType;
 import javax.ws.rs.core.UriBuilder;
 
 import org.glassfish.jersey.internal.util.PropertiesHelper;
@@ -39,7 +40,7 @@
 public abstract class AbstractSimpleServerTester {
 
     public static final String CONTEXT = "";
-    private final int DEFAULT_PORT = 9998;
+    private final int DEFAULT_PORT = 0; // rather SimpleFramework server choose than 9998
 
     private static final Logger LOGGER = Logger.getLogger(AbstractSimpleServerTester.class.getName());
 
@@ -72,10 +73,20 @@
         return DEFAULT_PORT;
     }
 
+    private final int getPort(RuntimeType runtimeType) {
+        switch (runtimeType) {
+            case SERVER:
+                return getPort();
+            case CLIENT:
+                return server.getPort();
+            default:
+                throw new IllegalStateException("Unexpected runtime type");
+        }
+    }
     private volatile SimpleServer server;
 
     public UriBuilder getUri() {
-        return UriBuilder.fromUri("http://localhost").port(getPort()).path(CONTEXT);
+        return UriBuilder.fromUri("http://localhost").port(getPort(RuntimeType.CLIENT)).path(CONTEXT);
     }
 
     public void startServer(Class... resources) {
@@ -83,21 +94,21 @@
         config.register(LoggingFeature.class);
         final URI baseUri = getBaseUri();
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServerNoLoggingFilter(Class... resources) {
         ResourceConfig config = new ResourceConfig(resources);
         final URI baseUri = getBaseUri();
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServer(ResourceConfig config) {
         final URI baseUri = getBaseUri();
         config.register(LoggingFeature.class);
         server = SimpleContainerFactory.create(baseUri, config);
-        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri);
+        LOGGER.log(Level.INFO, "Simple-http server started on base uri: " + baseUri.getHost() + ":" + server.getPort());
     }
 
     public void startServer(ResourceConfig config, int count, int select) {
@@ -108,7 +119,7 @@
     }
 
     public URI getBaseUri() {
-        return UriBuilder.fromUri("http://localhost/").port(getPort()).build();
+        return UriBuilder.fromUri("http://localhost/").port(getPort(RuntimeType.SERVER)).build();
     }
 
     public void setDebug(boolean enable) {
diff --git a/pom.xml b/pom.xml
index 8a1f112..3df2d34 100644
--- a/pom.xml
+++ b/pom.xml
@@ -428,6 +428,12 @@
                                 junit.jupiter.execution.parallel.mode.default=same_thread
                             </configurationParameters>
                         </properties>
+                        <systemProperties>
+                            <property>
+                                <name>jersey.config.test.container.port</name>
+                                <value>${jersey.config.test.container.port}</value>
+                            </property>
+                        </systemProperties>
                         <threadCount>124</threadCount>
                     </configuration>
                     <dependencies>
@@ -630,6 +636,12 @@
                         <skipTests>${skip.tests}</skipTests>
                         <skipITs>${skip.tests}</skipITs>
                         <argLine>${failsafe.coverage.argline}</argLine>
+                        <systemProperties>
+                            <property>
+                                <name>jersey.config.test.container.port</name>
+                                <value>${jersey.config.test.container.port}</value>
+                            </property>
+                        </systemProperties>
                     </configuration>
                     <executions>
                         <execution>
@@ -838,6 +850,26 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-resources-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>${buildhelper.mvn.plugin.version}</version>
+                <configuration>
+                    <portNames>
+                        <portName>jersey.config.test.container.port</portName>
+                        <portName>jersey.config.test.container.stop.port</portName>
+                    </portNames>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>reserve-port</id>
+                        <phase>process-test-classes</phase> <!-- pre-integration-test -->
+                        <goals>
+                            <goal>reserve-network-port</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
         <extensions>
             <extension>
@@ -1431,7 +1463,7 @@
                     <doctitle>Jersey ${jersey.version} API Documentation</doctitle>
                     <windowtitle>Jersey ${jersey.version} API</windowtitle>
                     <bottom>
-                        <![CDATA[Copyright &#169; 2007-2017,
+                        <![CDATA[Copyright &#169; 2007-2023,
                             <a href="http://www.oracle.com">Oracle</a>
                             and/or its affiliates.
                             All Rights Reserved. Use is subject to license terms.]]>
diff --git a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
index d588cf5..c4581ae 100644
--- a/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
+++ b/tests/e2e-server/src/test/java/org/glassfish/jersey/tests/e2e/server/ManagedClientExecutorTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -33,6 +33,7 @@
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.LogRecord;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -63,6 +64,11 @@
  */
 public class ManagedClientExecutorTest extends JerseyTest {
 
+    public ManagedClientExecutorTest() {
+        // The tests need to run on port 9998, since @Uri() annotation needs a constant String with a port
+        System.setProperty(TestProperties.CONTAINER_PORT, "9998");
+    }
+
     @Override
     protected ResourceConfig configure() {
         enable(TestProperties.LOG_TRAFFIC);
@@ -256,8 +262,15 @@
 
     @Test
     public void testManagedClientExecutor() {
-        final String response = target().path("test/executor").request().get(String.class);
-        Assertions.assertEquals("foo-executor-service-0", response);
+        try {
+            final String response = target().path("test/executor").request().get(String.class);
+            Assertions.assertEquals("foo-executor-service-0", response);
+        } catch (Exception e) {
+            for (LogRecord record : getLoggedRecords()) {
+                System.out.println(record.getMessage());
+            }
+        }
+
     }
 
     @Test
diff --git a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
index 56792d3..092b2df 100644
--- a/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
+++ b/tests/integration/externalproperties/src/test/java/org/glassfish/jersey/tests/externalproperties/HttpProxyTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2023 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -22,6 +22,7 @@
 import org.glassfish.jersey.ExternalProperties;
 import org.glassfish.jersey.server.ResourceConfig;
 import org.glassfish.jersey.test.JerseyTest;
+import org.glassfish.jersey.test.TestProperties;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -34,9 +35,12 @@
 import javax.ws.rs.core.Response;
 
 public class HttpProxyTest extends JerseyTest {
+    public HttpProxyTest() {
+        set(TestProperties.CONTAINER_PORT, 0);
+    }
 
     private static final String PROXY_HOST = "localhost";
-    private static final String PROXY_PORT = "9997";
+    private static final String PROXY_PORT = "0";
     private static boolean proxyHit = false;
 
     @Path("resource")
@@ -57,7 +61,6 @@
     @BeforeEach
     public void startFakeProxy() {
         System.setProperty(ExternalProperties.HTTP_PROXY_HOST, PROXY_HOST);
-        System.setProperty(ExternalProperties.HTTP_PROXY_PORT, PROXY_PORT);
         Server server = new Server(Integer.parseInt(PROXY_PORT));
         server.setHandler(new ProxyHandler(false));
         try {
@@ -65,6 +68,7 @@
         } catch (Exception e) {
 
         }
+        System.setProperty(ExternalProperties.HTTP_PROXY_PORT, String.valueOf(server.getURI().getPort()));
     }
 
     @Test