diff --git a/flash/src/test/java/dev/relism/flash/HttpServerConcurrencyTest.java b/flash/src/test/java/dev/relism/flash/HttpServerConcurrencyTest.java index ea4368e..942a1d7 100644 --- a/flash/src/test/java/dev/relism/flash/HttpServerConcurrencyTest.java +++ b/flash/src/test/java/dev/relism/flash/HttpServerConcurrencyTest.java @@ -4,11 +4,10 @@ import dev.relism.flash.extension.FlashApp; import dev.relism.flash.extension.FlashConfiguration; import dev.relism.flash.http.ContentType; import dev.relism.flash.models.Response; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.net.ServerSocket; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; @@ -25,20 +24,17 @@ import static org.junit.jupiter.api.Assertions.*; class HttpServerConcurrencyTest { - private FlashApp app; - private int port; - private HttpClient httpClient; - - @BeforeEach - void setUp() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - port = s.getLocalPort(); - } + private static FlashApp app; + private static int port; + private static HttpClient httpClient; + @BeforeAll + static void setUp() { app = FlashApp.create(FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .build()); + port = app.port(); app.get("/ping", (req, res) -> "pong"); app.post("/echo", (req, res) -> { @@ -53,9 +49,9 @@ class HttpServerConcurrencyTest { .build(); } - @AfterEach - void tearDown() { - if (app != null) app.stop(); + @AfterAll + static void tearDown() { + if (app != null) app.stop().join(); } // --- helpers --- @@ -173,15 +169,13 @@ class HttpServerConcurrencyTest { */ @Test void concurrent_lazyCompile_noRaceCondition() throws Exception { - int freshPort; - try (ServerSocket s = new ServerSocket(0)) { - freshPort = s.getLocalPort(); - } - + // Deliberately a brand-new app: this test is about compiling routes lazily on first + // use, so it must not share the class-scoped server. FlashApp freshApp = FlashApp.create(FlashConfiguration.builder() - .port(freshPort) + .port(0) .host("127.0.0.1") .build()); + int freshPort = freshApp.port(); for (int i = 0; i < 10; i++) { final int idx = i; diff --git a/flash/src/test/java/dev/relism/flash/HttpServerTest.java b/flash/src/test/java/dev/relism/flash/HttpServerTest.java index ff4705f..3f7ab21 100644 --- a/flash/src/test/java/dev/relism/flash/HttpServerTest.java +++ b/flash/src/test/java/dev/relism/flash/HttpServerTest.java @@ -2,15 +2,14 @@ package dev.relism.flash; import dev.relism.flash.extension.FlashApp; import dev.relism.flash.extension.FlashConfiguration; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; -import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; @@ -18,19 +17,17 @@ import static org.junit.jupiter.api.Assertions.*; class HttpServerTest { - private FlashApp app; - private int port; - - @BeforeEach - void setUp() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - port = s.getLocalPort(); - } + // Every test here is read-only against the same routes, so one boot for the class. + private static FlashApp app; + private static int port; + @BeforeAll + static void setUp() { app = FlashApp.create(FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .build()); + port = app.port(); app.get("/api/ping", (req, res) -> "pong"); @@ -61,9 +58,9 @@ class HttpServerTest { app.start(); } - @AfterEach - void tearDown() { - if (app != null) app.stop(); + @AfterAll + static void tearDown() { + if (app != null) app.stop().join(); } // --- helpers --- diff --git a/flash/src/test/java/dev/relism/flash/HttpServerTimeoutTest.java b/flash/src/test/java/dev/relism/flash/HttpServerTimeoutTest.java index a354a90..471ef5a 100644 --- a/flash/src/test/java/dev/relism/flash/HttpServerTimeoutTest.java +++ b/flash/src/test/java/dev/relism/flash/HttpServerTimeoutTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import java.io.OutputStream; -import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.nio.file.Path; @@ -30,21 +29,15 @@ class HttpServerTimeoutTest { if (app != null) app.stop(); } - private int freePort() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - return s.getLocalPort(); - } - } - @Test void slowlorisHeaderDribble_disconnectedWithinHeaderReadTimeout() throws Exception { int headerTimeoutMs = 300; - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .headerReadTimeoutMs(headerTimeoutMs) .idleKeepAliveTimeoutMs(60_000) .build()); + int port = app.port(); app.get("/", (req, res) -> "ok"); app.start(); @@ -71,12 +64,12 @@ class HttpServerTimeoutTest { @Test void idleKeepAliveConnection_disconnectedWithinIdleTimeout() throws Exception { int idleTimeoutMs = 300; - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .headerReadTimeoutMs(10_000) .idleKeepAliveTimeoutMs(idleTimeoutMs) .build()); + int port = app.port(); app.get("/", (req, res) -> "ok"); app.start(); @@ -96,13 +89,13 @@ class HttpServerTimeoutTest { @Test void slowBodyDribble_disconnectedWithinBodyReadTimeout() throws Exception { int bodyTimeoutMs = 300; - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .headerReadTimeoutMs(10_000) .idleKeepAliveTimeoutMs(10_000) .bodyReadTimeoutMs(bodyTimeoutMs) .build()); + int port = app.port(); app.post("/echo", (req, res) -> req.body().bytes()); app.start(); @@ -130,12 +123,12 @@ class HttpServerTimeoutTest { int headerTimeoutMs = 300; Path ks = TestKeystores.build(dir, "timeout.p12", "changeit", TestKeystores.Entry.of("only", "timeout.test")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit")) .headerReadTimeoutMs(headerTimeoutMs) .build()); + int port = app.port(); app.get("/", (req, res) -> "ok"); app.start(); @@ -157,13 +150,13 @@ class HttpServerTimeoutTest { @Test void wellBehavedRequest_wellWithinTimeouts_unaffected() throws Exception { - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .headerReadTimeoutMs(300) .idleKeepAliveTimeoutMs(300) .bodyReadTimeoutMs(300) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); diff --git a/flash/src/test/java/dev/relism/flash/HttpServerTlsTest.java b/flash/src/test/java/dev/relism/flash/HttpServerTlsTest.java index d1c55d3..635ba36 100644 --- a/flash/src/test/java/dev/relism/flash/HttpServerTlsTest.java +++ b/flash/src/test/java/dev/relism/flash/HttpServerTlsTest.java @@ -60,9 +60,6 @@ class HttpServerTlsTest { if (app != null) app.stop(); } - private static int freePort() throws IOException { - try (ServerSocket s = new ServerSocket(0)) { return s.getLocalPort(); } - } private static String httpGet(SSLSocket socket, String path) throws IOException { socket.setSoTimeout(SOCKET_TIMEOUT_MS); @@ -79,11 +76,11 @@ class HttpServerTlsTest { @Test void httpsRequest_servedOverModernTls(@TempDir java.nio.file.Path dir) throws Exception { var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit")) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -103,11 +100,11 @@ class HttpServerTlsTest { var ks = TestKeystores.build(dir, "sni.p12", "changeit", TestKeystores.Entry.of("a", "a.test"), TestKeystores.Entry.of("b", "b.test")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit")) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -143,11 +140,11 @@ class HttpServerTlsTest { @Test void mTls_requireRejectsClientWithNoCertificate(@TempDir java.nio.file.Path dir) throws Exception { var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit").clientAuth(ClientAuth.REQUIRE)) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -180,11 +177,11 @@ class HttpServerTlsTest { SSLContext serverCtx = SSLContext.getInstance("TLS"); serverCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.ofContext(serverCtx).clientAuth(ClientAuth.REQUIRE)) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -219,12 +216,12 @@ class HttpServerTlsTest { @Test void multipleListeners_plainAndTlsServeTheSameApp(@TempDir java.nio.file.Path dir) throws Exception { var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost")); - int plainPort = freePort(); - int tlsPort = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .listener(new FlashConfiguration.Listener(plainPort, "127.0.0.1", null)) - .listener(new FlashConfiguration.Listener(tlsPort, "127.0.0.1", TlsConfig.keystore(ks, "changeit"))) + .listener(new FlashConfiguration.Listener(0, "127.0.0.1", null)) + .listener(new FlashConfiguration.Listener(0, "127.0.0.1", TlsConfig.keystore(ks, "changeit"))) .build()); + int plainPort = app.ports().get(0); + int tlsPort = app.ports().get(1); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -287,11 +284,11 @@ class HttpServerTlsTest { SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(managers, null, null); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.ofContext(ctx)) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -364,11 +361,11 @@ class HttpServerTlsTest { SSLContext[] boxedCtx = new SSLContext[1]; RecordingKeyManager recorder = buildRecordingContext(ks, boxedCtx); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.ofContext(boxedCtx[0]).applicationProtocols("acme-tls/1", "http/1.1")) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start(); @@ -422,11 +419,11 @@ class HttpServerTlsTest { @Test void request_isSecureAndSessionAvailableOverTls(@TempDir java.nio.file.Path dir) throws Exception { var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit")) .build()); + int port = app.port(); app.get("/secure-info", (req, res) -> { SSLSession session = req.sslSession(); return req.isSecure() + ":" + (session != null) + ":" + (session != null ? session.getCipherSuite() : ""); @@ -456,13 +453,13 @@ class HttpServerTlsTest { SSLContext serverCtx = SSLContext.getInstance("TLS"); serverCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") // OPTIONAL, not REQUIRE: proves getPeerCertificates() works without also // re-testing the REQUIRE-rejection path already covered elsewhere in this file. .tls(TlsConfig.ofContext(serverCtx).clientAuth(ClientAuth.OPTIONAL)) .build()); + int port = app.port(); app.get("/secure-info", (req, res) -> { try { X509Certificate peer = (X509Certificate) req.sslSession().getPeerCertificates()[0]; @@ -488,8 +485,8 @@ class HttpServerTlsTest { @Test void request_isNotSecureAndSessionIsNullOnPlainListener() throws Exception { - int port = freePort(); - app = FlashApp.create(FlashConfiguration.builder().port(port).host("127.0.0.1").build()); + app = FlashApp.create(FlashConfiguration.builder().port(0).host("127.0.0.1").build()); + int port = app.port(); app.get("/secure-info", (req, res) -> req.isSecure() + ":" + (req.sslSession() == null)); app.start(); @@ -524,11 +521,11 @@ class HttpServerTlsTest { @Test void wss_sessionIsSecureAndExposesSslSession(@TempDir java.nio.file.Path dir) throws Exception { var ks = TestKeystores.build(dir, "id.p12", "changeit", TestKeystores.Entry.of("srv", "localhost")); - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .tls(TlsConfig.keystore(ks, "changeit")) .build()); + int port = app.port(); AtomicReference observedSecure = new AtomicReference<>(); AtomicReference observedSession = new AtomicReference<>(); diff --git a/flash/src/test/java/dev/relism/flash/HttpServerWebSocketTest.java b/flash/src/test/java/dev/relism/flash/HttpServerWebSocketTest.java index d5eddd4..9d5e8d2 100644 --- a/flash/src/test/java/dev/relism/flash/HttpServerWebSocketTest.java +++ b/flash/src/test/java/dev/relism/flash/HttpServerWebSocketTest.java @@ -13,7 +13,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; -import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.Base64; @@ -29,14 +28,11 @@ class HttpServerWebSocketTest { @BeforeEach void setUp() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - port = s.getLocalPort(); - } - app = FlashApp.create(FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .build()); + port = app.port(); app.ws("/chat", new WebSocketHandler() { @Override diff --git a/flash/src/test/java/dev/relism/flash/extension/FlashAppWebSocketTest.java b/flash/src/test/java/dev/relism/flash/extension/FlashAppWebSocketTest.java index ffa059a..9589e9b 100644 --- a/flash/src/test/java/dev/relism/flash/extension/FlashAppWebSocketTest.java +++ b/flash/src/test/java/dev/relism/flash/extension/FlashAppWebSocketTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.net.ServerSocket; import static org.junit.jupiter.api.Assertions.*; @@ -20,14 +19,11 @@ class FlashAppWebSocketTest { @BeforeEach void setUp() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - port = s.getLocalPort(); - } - app = FlashApp.create(FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .build()); + port = app.port(); } @AfterEach diff --git a/flash/src/test/java/dev/relism/flash/http2/CurlInteropTest.java b/flash/src/test/java/dev/relism/flash/http2/CurlInteropTest.java index d269a74..ece753a 100644 --- a/flash/src/test/java/dev/relism/flash/http2/CurlInteropTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/CurlInteropTest.java @@ -32,7 +32,6 @@ class CurlInteropTest { @Test void tlsGetPostLargeUploadAndLargeDownload(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -43,23 +42,24 @@ class CurlInteropTest { FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); exercise(directory, "https://localhost:" + port, "--http2", "--insecure"); } @Test void cleartextGetPostLargeUploadAndLargeDownload(@TempDir Path directory) throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); exercise(directory, "http://127.0.0.1:" + port, "--http2-prior-knowledge"); } @@ -112,9 +112,4 @@ class CurlInteropTest { return result; } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/GrpcInteropTest.java b/flash/src/test/java/dev/relism/flash/http2/GrpcInteropTest.java index 1d06280..71692ec 100644 --- a/flash/src/test/java/dev/relism/flash/http2/GrpcInteropTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/GrpcInteropTest.java @@ -28,14 +28,14 @@ class GrpcInteropTest { @Test void grpcurlCompletesUnaryStreamingAndErrorCalls(@TempDir Path directory) throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.post("/flash.test.Echo/Unary", (request, response) -> response.type("application/grpc") .body(request.body().bytes()) @@ -156,11 +156,6 @@ class GrpcInteropTest { return count; } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } private record Result(int exitCode, String output) {} } diff --git a/flash/src/test/java/dev/relism/flash/http2/H2LoadMeasurementTest.java b/flash/src/test/java/dev/relism/flash/http2/H2LoadMeasurementTest.java index f0dee81..7b73b3e 100644 --- a/flash/src/test/java/dev/relism/flash/http2/H2LoadMeasurementTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/H2LoadMeasurementTest.java @@ -42,16 +42,16 @@ class H2LoadMeasurementTest { @Test void measureFlashAndNghttpdMatrix(@TempDir Path directory) throws Exception { - int flashPort = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(flashPort) + .port(0) .http2CleartextEnabled(true) .h2MaxStreamsCreatedPerInterval(Integer.MAX_VALUE) .h2MaxStreamsPerConnection(0) .build()); + int flashPort = app.port(); app.get("/index.html", (request, response) -> "flash-load"); app.start(); @@ -133,6 +133,10 @@ class H2LoadMeasurementTest { if (path != null) builder.environment().put("LD_LIBRARY_PATH", path); } + /** + * Still needed here: this port is handed to an external nghttpd process, which has no + * equivalent of {@code FlashApp.port()} to read an OS-assigned port back from. + */ private static int freePort() throws Exception { try (ServerSocket socket = new ServerSocket(0)) { return socket.getLocalPort(); diff --git a/flash/src/test/java/dev/relism/flash/http2/H2SpecComplianceTest.java b/flash/src/test/java/dev/relism/flash/http2/H2SpecComplianceTest.java index bbd29cb..40a7a9d 100644 --- a/flash/src/test/java/dev/relism/flash/http2/H2SpecComplianceTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/H2SpecComplianceTest.java @@ -36,14 +36,14 @@ class H2SpecComplianceTest { @Test void cleartextSuiteHasNoFailuresOrSkips(@TempDir Path directory) throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); registerProbeRoutes(); app.start(); @@ -52,7 +52,6 @@ class H2SpecComplianceTest { @Test void tlsSuiteHasNoFailuresOrSkips(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -63,10 +62,11 @@ class H2SpecComplianceTest { FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); registerProbeRoutes(); app.start(); @@ -145,11 +145,6 @@ class H2SpecComplianceTest { assertEquals(0, skipped.getLength(), output); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } private record ProcessResult(int exitCode, String output) {} } diff --git a/flash/src/test/java/dev/relism/flash/http2/H2cPriorKnowledgeTest.java b/flash/src/test/java/dev/relism/flash/http2/H2cPriorKnowledgeTest.java index fdd6186..a043eb5 100644 --- a/flash/src/test/java/dev/relism/flash/http2/H2cPriorKnowledgeTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/H2cPriorKnowledgeTest.java @@ -28,14 +28,14 @@ class H2cPriorKnowledgeTest { @Test void priorKnowledgeRequiresItsIndependentOptIn() throws Exception { - int disabledPort = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(disabledPort) + .port(0) .http2Enabled(true) .build()); + int disabledPort = app.port(); app.get("/", (request, response) -> "wrong protocol"); app.start(); @@ -47,14 +47,14 @@ class H2cPriorKnowledgeTest { } app.stop().join(); - int enabledPort = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(enabledPort) + .port(0) .http2CleartextEnabled(true) .build()); + int enabledPort = app.port(); app.get("/", (request, response) -> "h2c"); app.start(); @@ -125,9 +125,4 @@ class H2cPriorKnowledgeTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2AbuseTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2AbuseTest.java index c44a589..1c6bf96 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2AbuseTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2AbuseTest.java @@ -183,15 +183,15 @@ class Http2AbuseTest { @Test void idleOpenStreamIsCancelledWithinConfiguredDeadline() throws Exception { - int port = freePort(); FlashApp app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .h2StreamIdleTimeoutMs(20) .build()); + int port = app.port(); app.post("/idle", (request, response) -> request.body().bytes()); app.start(); ByteWriter headers = new ByteWriter(64); @@ -295,11 +295,6 @@ class Http2AbuseTest { throw new AssertionError("missing " + expected); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } private record Run(List frames) { int lastGoAwayError() { diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2ConcurrencyTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2ConcurrencyTest.java index 9793bf2..84c7096 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2ConcurrencyTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2ConcurrencyTest.java @@ -29,16 +29,16 @@ class Http2ConcurrencyTest { @Test void thousandMultiplexedStreamsCompleteOnOneConnection() throws Exception { - int port = freePort(); AtomicInteger handled = new AtomicInteger(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .h2MaxStreamsCreatedPerInterval(2_000) .build()); + int port = app.port(); app.get("/work", (request, response) -> Integer.toString(handled.incrementAndGet())); app.start(); @@ -110,9 +110,4 @@ class Http2ConcurrencyTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2ConnectTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2ConnectTest.java index 733a9fb..0cfa99f 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2ConnectTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2ConnectTest.java @@ -28,14 +28,14 @@ class Http2ConnectTest { @Test void connectTunnelCanExchangeDataBeforeEitherSideCloses() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.connect("tunnel", (request, response) -> response.type(ContentType.NONE).streaming(output -> { byte[] bytes = new byte[16]; @@ -100,9 +100,4 @@ class Http2ConnectTest { return text.getBytes(StandardCharsets.US_ASCII); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2ConnectionIntegrationTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2ConnectionIntegrationTest.java index febbb76..13acd2b 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2ConnectionIntegrationTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2ConnectionIntegrationTest.java @@ -48,7 +48,6 @@ class Http2ConnectionIntegrationTest { @Test void javaHttpClientUsesHttp2AgainstAnExistingParameterizedRoute(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -58,11 +57,12 @@ class Http2ConnectionIntegrationTest { app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.get( "/users/{id}", (request, response) -> request.param("id") + ":" + request.header("host")); app.start(); @@ -87,7 +87,6 @@ class Http2ConnectionIntegrationTest { @Test void javaHttpClientUploadsAndDownloadsFlowControlledBodies(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -102,11 +101,12 @@ class Http2ConnectionIntegrationTest { app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.post("/echo", (request, response) -> request.body().bytes()); app.get("/fixed", (request, response) -> response.body(download)); app.get( @@ -143,7 +143,6 @@ class Http2ConnectionIntegrationTest { @Test void pushStreamingAppliesBackpressureAcrossMultipleWindows(@TempDir Path directory) throws Exception { - int port = freePort(); int length = 2 * 1024 * 1024 + 31; Path keystore = TestKeystores.build( @@ -154,11 +153,12 @@ class Http2ConnectionIntegrationTest { app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.get( "/push", (request, response) -> @@ -197,7 +197,6 @@ class Http2ConnectionIntegrationTest { @Test void hundredMegabyteUploadAndDownloadRemainStreaming(@TempDir Path directory) throws Exception { - int port = freePort(); long length = 100L * 1024 * 1024; Path keystore = TestKeystores.build( @@ -208,11 +207,12 @@ class Http2ConnectionIntegrationTest { app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.post( "/upload", (request, response) -> { @@ -250,14 +250,14 @@ class Http2ConnectionIntegrationTest { @Test void bodylessGetRunsExistingRouteAndReturnsHeadersAndData() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .http2CleartextEnabled(true) .build()); + int port = app.port(); app.get("/api/ping", (request, response) -> "pong"); app.start(); @@ -314,15 +314,15 @@ class Http2ConnectionIntegrationTest { @Test void resetQueuedStreamCannotReleaseOrReuseItBeforeDispatchObservesCancellation() throws Exception { - int port = freePort(); AtomicInteger calls = new AtomicInteger(); app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .http2CleartextEnabled(true) .build()); + int port = app.port(); app.get( "/queued", (request, response) -> { @@ -384,15 +384,15 @@ class Http2ConnectionIntegrationTest { @Test void h2cTransportDispatchesControlFramesWithoutRunningApplicationWork() throws Exception { - int port = freePort(); AtomicBoolean handlerEntered = new AtomicBoolean(); app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .http2CleartextEnabled(true) .build()); + int port = app.port(); app.get( "/", (request, response) -> { @@ -442,15 +442,15 @@ class Http2ConnectionIntegrationTest { @Test void serverStopInitiatesTwoStageGoAwayOnIdleConnection() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .http2CleartextEnabled(true) .shutdownDrainTimeoutMs(5_000) .build()); + int port = app.port(); app.start(); try (Socket socket = new Socket("127.0.0.1", port)) { @@ -485,14 +485,14 @@ class Http2ConnectionIntegrationTest { @Test void protocolStateDoesNotLeakAcrossConsecutiveConnections() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .http2CleartextEnabled(true) .build()); + int port = app.port(); app.start(); try (Socket first = new Socket("127.0.0.1", port)) { @@ -537,7 +537,6 @@ class Http2ConnectionIntegrationTest { @Test void tlsListenerOffersAndNegotiatesH2WhenHttp2IsEnabled(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -547,11 +546,12 @@ class Http2ConnectionIntegrationTest { app = FlashApp.create( FlashConfiguration.builder() - .port(port) + .port(0) .host("127.0.0.1") .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.start(); try (SSLSocket socket = @@ -630,11 +630,6 @@ class Http2ConnectionIntegrationTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } private static String ascii(dev.relism.fpr.core.ByteView view) { byte[] bytes = new byte[view.length()]; diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2MisdirectedRequestTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2MisdirectedRequestTest.java index e8f04c2..0b8b9c3 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2MisdirectedRequestTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2MisdirectedRequestTest.java @@ -31,7 +31,6 @@ class Http2MisdirectedRequestTest { @Test void authorityOutsideSelectedCertificateReceives421(@TempDir Path directory) throws Exception { - int port = freePort(); Path keystore = TestKeystores.build( directory, @@ -42,10 +41,11 @@ class Http2MisdirectedRequestTest { FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .tls(TlsConfig.keystore(keystore, "changeit")) .http2Enabled(true) .build()); + int port = app.port(); app.get("/", (request, response) -> "must not run"); app.start(); @@ -114,9 +114,4 @@ class Http2MisdirectedRequestTest { } } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2RegressionCorpusTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2RegressionCorpusTest.java index 9cfcce0..0445ecd 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2RegressionCorpusTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2RegressionCorpusTest.java @@ -47,14 +47,14 @@ class Http2RegressionCorpusTest { @Test void headersOnHalfClosedRemoteStreamUseStreamErrorBeforeDispatch() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.get("/", (request, response) -> "ok"); app.start(); @@ -101,9 +101,4 @@ class Http2RegressionCorpusTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2SoakTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2SoakTest.java index cb8f827..8714f65 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2SoakTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2SoakTest.java @@ -35,18 +35,18 @@ class Http2SoakTest { @Test void sustainedMixedTrafficRetainsBoundedHeapAndCompletesRequests() throws Exception { long seconds = Long.getLong("flash.http2.soak.seconds", 600L); - int port = freePort(); byte[] streamBody = new byte[8 * 1024]; Arrays.fill(streamBody, (byte) 's'); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .h2MaxStreamsCreatedPerInterval(100_000) .h2MaxStreamsPerConnection(0) .build()); + int port = app.port(); app.get("/get", (request, response) -> "get"); app.post("/post", (request, response) -> request.body().bytes()); app.get("/stream", (request, response) -> response.chunked(new ByteArrayInputStream(streamBody))); @@ -182,9 +182,4 @@ class Http2SoakTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/Http2TrailersTest.java b/flash/src/test/java/dev/relism/flash/http2/Http2TrailersTest.java index 880c2ae..dcf3c1e 100644 --- a/flash/src/test/java/dev/relism/flash/http2/Http2TrailersTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/Http2TrailersTest.java @@ -27,14 +27,14 @@ class Http2TrailersTest { @Test void requestTrailersReachHandlerAfterBodyEof() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.post("/trailers", (request, response) -> { assertEquals("abc", new String(request.body().bytes(), StandardCharsets.US_ASCII)); return request.trailers().first("grpc-status"); @@ -99,14 +99,14 @@ class Http2TrailersTest { } private int startBlockingRoute() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.post("/trailers", (request, response) -> request.body().bytes()); app.start(); return port; @@ -152,9 +152,4 @@ class Http2TrailersTest { payload); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/NghttpInteropTest.java b/flash/src/test/java/dev/relism/flash/http2/NghttpInteropTest.java index 46fc5d7..0b542f2 100644 --- a/flash/src/test/java/dev/relism/flash/http2/NghttpInteropTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/NghttpInteropTest.java @@ -38,9 +38,8 @@ class NghttpInteropTest { } private void exercise(Path directory, boolean tls) throws Exception { - int port = freePort(); FlashConfiguration.FlashConfigurationBuilder builder = - FlashConfiguration.builder().host("127.0.0.1").port(port); + FlashConfiguration.builder().host("127.0.0.1").port(0); if (tls) { Path keystore = TestKeystores.build( @@ -54,6 +53,7 @@ class NghttpInteropTest { } byte[] large = new byte[2 * 1024 * 1024 + 29]; app = FlashApp.create(builder.build()); + int port = app.port(); app.get("/get", (request, response) -> "nghttp-get"); app.post("/post", (request, response) -> "uploaded-" + request.body().bytes().length); app.get("/large", (request, response) -> response.body(large)); @@ -93,9 +93,4 @@ class NghttpInteropTest { assertTrue(trace.contains("recv DATA frame"), trace); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/WebSocketOverH2Test.java b/flash/src/test/java/dev/relism/flash/http2/WebSocketOverH2Test.java index d269f51..8f1df4c 100644 --- a/flash/src/test/java/dev/relism/flash/http2/WebSocketOverH2Test.java +++ b/flash/src/test/java/dev/relism/flash/http2/WebSocketOverH2Test.java @@ -23,15 +23,15 @@ class WebSocketOverH2Test { @Test void opensEchoesFragmentsAndCarriesAMessageLargerThanTheFlowWindow() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .wsFrameBufferSize(2 * 1024 * 1024) .build()); + int port = app.port(); app.ws( "/chat", new WebSocketHandler() { @@ -67,9 +67,4 @@ class WebSocketOverH2Test { } } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/http2/WebSocketParityTest.java b/flash/src/test/java/dev/relism/flash/http2/WebSocketParityTest.java index fb120ae..c73d838 100644 --- a/flash/src/test/java/dev/relism/flash/http2/WebSocketParityTest.java +++ b/flash/src/test/java/dev/relism/flash/http2/WebSocketParityTest.java @@ -28,14 +28,14 @@ class WebSocketParityTest { @Test void oneRouteAndHandlerEchoTheSameMessageOverHttp1AndHttp2() throws Exception { - int port = freePort(); app = FlashApp.create( FlashConfiguration.builder() .host("127.0.0.1") - .port(port) + .port(0) .http2CleartextEnabled(true) .build()); + int port = app.port(); app.ws( "/parity", new WebSocketHandler() { @@ -135,9 +135,4 @@ class WebSocketParityTest { return input.readNBytes(length); } - private static int freePort() throws Exception { - try (ServerSocket socket = new ServerSocket(0)) { - return socket.getLocalPort(); - } - } } diff --git a/flash/src/test/java/dev/relism/flash/transport/ServerLifecycleGracefulShutdownTest.java b/flash/src/test/java/dev/relism/flash/transport/ServerLifecycleGracefulShutdownTest.java index e148835..b114284 100644 --- a/flash/src/test/java/dev/relism/flash/transport/ServerLifecycleGracefulShutdownTest.java +++ b/flash/src/test/java/dev/relism/flash/transport/ServerLifecycleGracefulShutdownTest.java @@ -28,22 +28,17 @@ class ServerLifecycleGracefulShutdownTest { if (app != null) app.stop(); } - private static int freePort() throws Exception { - try (ServerSocket s = new ServerSocket(0)) { - return s.getLocalPort(); - } - } @Test void inFlightRequest_completesWithConnectionClose_duringShutdown() throws Exception { - int port = freePort(); CountDownLatch handlerStarted = new CountDownLatch(1); CountDownLatch releaseHandler = new CountDownLatch(1); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .shutdownDrainTimeoutMs(5_000) .build()); + int port = app.port(); app.get("/slow", (req, res) -> { handlerStarted.countDown(); assertTrue(releaseHandler.await(5, TimeUnit.SECONDS)); @@ -80,11 +75,11 @@ class ServerLifecycleGracefulShutdownTest { @Test void stop_closesListener_soNewConnectionsAreRefused() throws Exception { - int port = freePort(); app = FlashApp.create(FlashConfiguration.builder() - .port(port).host("127.0.0.1") + .port(0).host("127.0.0.1") .shutdownDrainTimeoutMs(500) .build()); + int port = app.port(); app.get("/ping", (req, res) -> "pong"); app.start();