test(core): read bound ports back from the app instead of guessing free ones

Every integration test picked a port by opening ServerSocket(0), closing it and
reusing the number, which races anything else on the machine between the close
and the rebind. FlashApp.port() reports the port the listener actually bound,
so the guess is gone: 18 freePort() helpers deleted, 40 call sites now pass
port(0) and read the result back.

Two ServerSocket(0) uses remain and are correct. ConnectionRunnerTest accepts
on its socket rather than using it to pick a number. H2LoadMeasurementTest
hands its port to an external nghttpd process, which has no equivalent of
port() to read back; that one is now commented to say so.

HttpServerTlsTest's two-listener case reads both back through ports().

HttpServerTest and HttpServerConcurrencyTest also move from @BeforeEach to
@BeforeAll — every test in them is read-only against the same routes, so 11 and
3 boots respectively become 1. HttpServerConcurrencyTest's lazy-compile test
keeps building its own app, since a freshly compiled router is the thing it
tests. HttpServerTest now runs 11 tests in 0.06s.

The http2 interop suites (curl, nghttp, grpcurl, h2spec), the load measurement
and the soak test are skipped without their external binaries or system
property, so those edits are compile-verified here and exercised in CI.

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