From 78aef13d494e0b9121d26788c10152ec4683dd59 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Fri, 29 May 2026 15:11:12 +0200 Subject: [PATCH] Modernize HttpSendFileTest. --- .../http/sendfile/Http1xSendFileTest.java | 28 +-- .../tests/http/sendfile/HttpSendFileTest.java | 197 ++++++++---------- 2 files changed, 104 insertions(+), 121 deletions(-) diff --git a/vertx-core/src/test/java/io/vertx/tests/http/sendfile/Http1xSendFileTest.java b/vertx-core/src/test/java/io/vertx/tests/http/sendfile/Http1xSendFileTest.java index f89aa620f66..efdf8577fe7 100644 --- a/vertx-core/src/test/java/io/vertx/tests/http/sendfile/Http1xSendFileTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/http/sendfile/Http1xSendFileTest.java @@ -18,26 +18,31 @@ import io.vertx.core.net.NetClient; import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.NetSocket; +import io.vertx.test.core.Checkpoint; import io.vertx.test.core.TestUtils; import org.junit.Assume; import org.junit.Assert; import org.junit.Test; import java.io.File; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; +import static org.assertj.core.api.Assertions.*; + public class Http1xSendFileTest extends HttpSendFileTest { @Test - public void testSendFileWithConnectionCloseHeader() throws Exception { + public void testSendFileWithConnectionCloseHeader(Checkpoint checkpoint) throws Exception { String content = TestUtils.randomUnicodeString(1024 * 1024 * 2); - sendFile("test-send-file.html", content, false, + sendFile(checkpoint, "test-send-file.html", content, false, () -> client.request(requestOptions).map(req -> req.putHeader(HttpHeaders.CONNECTION, "close"))); } @Test - public void testSendFileFailsWhenClientClosesConnection() throws Exception { + public void testSendFileFailsWhenClientClosesConnection(Checkpoint checkpoint) throws Exception { // 10 megs final File f = setupFile("file.pdf", TestUtils.randomUnicodeString(10 * 1024 * 1024)); CyclicBarrier barrier = new CyclicBarrier(1); @@ -46,7 +51,7 @@ public void testSendFileFailsWhenClientClosesConnection() throws Exception { barrier.await(10, TimeUnit.SECONDS); req.response().sendFile(f.getAbsolutePath()).onComplete(TestUtils.onFailure(err -> { // Broken pipe - testComplete(); + checkpoint.succeed(); })); } catch (Exception e) { // this was the bug reported with issues/issue-80 @@ -67,29 +72,27 @@ public void testSendFileFailsWhenClientClosesConnection() throws Exception { } finally { client.close(); } - await(); + checkpoint.awaitSuccess(); } @Test - public void testSendFilePipelined() throws Exception { + public void testSendFilePipelined(Checkpoint checkpoint) throws Exception { int n = 2; - waitFor(n); File sent = TestUtils.tmpFile(".dat", 16 * 1024); server.requestHandler( req -> { req.response().sendFile(sent.getAbsolutePath()); }); startServer(testAddress); - client.close(); client = vertx.createHttpClient(createBaseClientOptions().setPipelining(true), new PoolOptions().setHttp1MaxSize(1)); + CountDownLatch latch = checkpoint.asLatch(n); for (int i = 0;i < n;i++) { client.request(requestOptions) .compose(req -> req.send().compose(HttpClientResponse::body)) .onComplete(TestUtils.onSuccess(body -> { - complete(); + latch.countDown(); })); } - await(); } @Test @@ -103,11 +106,10 @@ public void testHttpServerWithIdleTimeoutSendChunkedFile() throws Exception { // Now test with timeout relative to this delay int timeout = delay / 2; delay = retrieveFileFromServer(file, createBaseServerOptions().setIdleTimeout(timeout).setIdleTimeoutUnit(TimeUnit.MILLISECONDS)); - Assert.assertTrue(delay > timeout); + assertThat(delay).isGreaterThan(timeout); } private int retrieveFileFromServer(File file, HttpServerOptions options) throws Exception { - server.close().await(); server = vertx .createHttpServer(options) .requestHandler( @@ -131,7 +133,7 @@ private int retrieveFileFromServer(File file, HttpServerOptions options) throws return resp.end(); })) .map(v -> length[0]).await(); - Assert.assertEquals((int)len, file.length()); + assertEquals((int)len, file.length()); return (int) (System.currentTimeMillis() - now); } } diff --git a/vertx-core/src/test/java/io/vertx/tests/http/sendfile/HttpSendFileTest.java b/vertx-core/src/test/java/io/vertx/tests/http/sendfile/HttpSendFileTest.java index 47625fdb423..b7c12ec4ad8 100644 --- a/vertx-core/src/test/java/io/vertx/tests/http/sendfile/HttpSendFileTest.java +++ b/vertx-core/src/test/java/io/vertx/tests/http/sendfile/HttpSendFileTest.java @@ -19,75 +19,75 @@ import io.vertx.core.http.HttpResponseExpectation; import io.vertx.core.http.HttpServerResponse; import io.vertx.core.http.HttpVersion; +import io.vertx.test.core.Checkpoint; import io.vertx.test.core.DetectFileDescriptorLeaks; +import io.vertx.test.core.FileDescriptorLeakDetectorRule; import io.vertx.test.core.TestUtils; -import io.vertx.test.http.HttpTestBase; +import io.vertx.test.http.HttpTestBase2; +import static org.assertj.core.api.Assertions.*; import org.junit.Assume; import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; import java.io.File; import java.io.FileNotFoundException; import java.io.RandomAccessFile; import java.nio.file.Files; -import java.util.concurrent.atomic.AtomicBoolean; +import java.time.Duration; +import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Supplier; import static io.vertx.test.core.AssertExpectations.that; +import static org.junit.Assert.*; -public abstract class HttpSendFileTest extends HttpTestBase { +public abstract class HttpSendFileTest extends HttpTestBase2 { - public HttpSendFileTest() { - super(ReportMode.FORBIDDEN); - } + @Rule + public FileDescriptorLeakDetectorRule fileDescriptorLeakDetectorRule = new FileDescriptorLeakDetectorRule(); @Test @DetectFileDescriptorLeaks(iterations = 40) - public void testSendFile() throws Exception { + public void testSendFile(Checkpoint checkpoint) throws Exception { String content = TestUtils.randomUnicodeString(10000); - sendFile("test-send-file.html", content, false, () -> client.request(requestOptions)); + sendFile(checkpoint, "test-send-file.html", content, false, () -> client.request(requestOptions)); } @Test - public void testSendFileUpperCaseSuffix() throws Exception { + public void testSendFileUpperCaseSuffix(Checkpoint checkpoint) throws Exception { String content = TestUtils.randomUnicodeString(10000); - sendFile("test-send-file.HTML", content, true, () -> client.request(requestOptions)); + sendFile(checkpoint, "test-send-file.HTML", content, true, () -> client.request(requestOptions)); } @Test - public void testSendFileWithHandler() throws Exception { + public void testSendFileWithHandler(Checkpoint checkpoint) throws Exception { String content = TestUtils.randomUnicodeString(10000); - sendFile("test-send-file.html", content, true, () -> client.request(requestOptions)); + sendFile(checkpoint, "test-send-file.html", content, true, () -> client.request(requestOptions)); } - protected void sendFile(String fileName, String contentExpected, boolean useHandler, Supplier> requestFact) throws Exception { - waitFor(2); + protected void sendFile(Checkpoint checkpoint, String fileName, String contentExpected, boolean useHandler, Supplier> requestFact) throws Exception { File fileToSend = setupFile(fileName, contentExpected); server.requestHandler(req -> { if (useHandler) { - req.response().sendFile(fileToSend.getAbsolutePath()).onComplete(TestUtils.onSuccess(v -> complete())); + req.response().sendFile(fileToSend.getAbsolutePath()).onComplete(checkpoint); } else { req.response().sendFile(fileToSend.getAbsolutePath()); - complete(); + checkpoint.succeed(); } }); startServer(testAddress); requestFact.get().compose(req -> req .send() .expecting(that(resp -> { - Assert.assertEquals(200, resp.statusCode()); - Assert.assertEquals("text/html", resp.headers().get("Content-Type")); - Assert.assertEquals(fileToSend.length(), Long.parseLong(resp.headers().get("content-length"))); + assertEquals(200, resp.statusCode()); + assertEquals("text/html", resp.headers().get("Content-Type")); + assertEquals(fileToSend.length(), Long.parseLong(resp.headers().get("content-length"))); resp.exceptionHandler(err -> Assert.fail(err.getMessage())); })) .compose(HttpClientResponse::body)) - .onComplete(TestUtils.onSuccess(buff -> { - Assert.assertEquals(contentExpected, buff.toString()); - complete(); - })); - await(); + .await(); } @Test @@ -95,7 +95,7 @@ public void testSendNonExistingFile() throws Exception { server.requestHandler(req -> { final Context ctx = vertx.getOrCreateContext(); req.response().sendFile("/not/existing/path").onComplete(event -> { - Assert.assertEquals(ctx, vertx.getOrCreateContext()); + assertEquals(ctx, vertx.getOrCreateContext()); if (event.failed()) { req.response().end("failed"); } @@ -108,10 +108,8 @@ public void testSendNonExistingFile() throws Exception { .send() .expecting(HttpResponseExpectation.SC_OK) .compose(HttpClientResponse::body) - .expecting(that(buff -> Assert.assertEquals("failed", buff.toString())))) - .onComplete(TestUtils.onSuccess(v -> testComplete())); - - await(); + .expecting(that(buff -> assertEquals("failed", buff.toString())))) + .await(); } @Test @@ -129,45 +127,40 @@ public void testSendFileOverrideHeaders() throws Exception { .compose(req -> req .send() .expecting(that(resp -> { - Assert.assertEquals(200, resp.statusCode()); - Assert.assertEquals(file.length(), Long.parseLong(resp.headers().get("content-length"))); - Assert.assertEquals("wibble", resp.headers().get("content-type")); + assertEquals(200, resp.statusCode()); + assertEquals(file.length(), Long.parseLong(resp.headers().get("content-length"))); + assertEquals("wibble", resp.headers().get("content-type")); })) .compose(HttpClientResponse::body) - .expecting(that(buff -> Assert.assertEquals(content, buff.toString())))) - .onComplete(TestUtils.onSuccess(v -> testComplete())); - - await(); + .expecting(that(buff -> assertEquals(content, buff.toString())))) + .await(); } @Test - public void testSendFileNotFound() throws Exception { - waitFor(2); - + public void testSendFileNotFound(Checkpoint checkpoint) throws Exception { server.requestHandler(req -> { - req.response().putHeader("Content-Type", "wibble"); - req.response().sendFile("nosuchfile.html").onComplete(TestUtils.onFailure(v -> complete())); + req.response() + .putHeader("Content-Type", "wibble") + .sendFile("nosuchfile.html") + .onComplete(TestUtils.onFailure(v -> checkpoint.succeed())); }); startServer(testAddress); - AtomicBoolean completed = new AtomicBoolean(); - client.request(requestOptions).onComplete(TestUtils.onSuccess(req -> { - req.send().onComplete(ar -> { - if (!completed.get()) { - Assert.fail(); - } - }); - })); - vertx.setTimer(100, tid -> { - completed.set(true); - complete(); - }); - - await(); + try { + client + .request(requestOptions) + .compose(HttpClientRequest::send) + .timeout(Duration.ofMillis(100)) + .await(); + Assert.fail(); + } catch (Exception e) { + assertThat(e) + .isInstanceOf(TimeoutException.class); + } } @Test - public void testSendFileDirectoryWithHandler() throws Exception { + public void testSendFileDirectoryWithHandler(Checkpoint checkpoint) throws Exception { File dir = Files.createTempDirectory("vertx").toFile(); @@ -175,17 +168,21 @@ public void testSendFileDirectoryWithHandler() throws Exception { req.response().putHeader("Content-Type", "wibble"); req.response().sendFile(dir.getAbsolutePath()) .onComplete(TestUtils.onFailure(t -> { - Assert.assertTrue(t instanceof FileNotFoundException); - testComplete(); + assertThat(t).isInstanceOf(FileNotFoundException.class); + checkpoint.succeed(); })); }); startServer(testAddress); - client.request(requestOptions).onComplete(TestUtils.onSuccess(req -> { - req.send().onComplete(TestUtils.onFailure(err -> {})); - })); - - await(); + try { + client + .request(requestOptions) + .compose(HttpClientRequest::send) + .timeout(Duration.ofMillis(100)) + .await(); + Assert.fail(); + } catch (Exception ignore) { + } } @Test @@ -194,18 +191,14 @@ public void testSendOpenRangeFileFromClasspath() throws Exception { res.response().sendFile("hosts_config.txt", 13); }); startServer(testAddress); - client.request(requestOptions).onComplete(TestUtils.onSuccess(req -> { - client.request(requestOptions) - .compose(HttpClientRequest::send) - .expecting(that(resp -> Assert.assertEquals(String.valueOf(10), resp.headers().get("Content-Length")))) - .compose(HttpClientResponse::body) - .onComplete(TestUtils.onSuccess(body -> { - Assert.assertTrue(body.toString().startsWith("server.net")); - Assert.assertEquals(10, body.toString().length()); - testComplete(); - })); - })); - await(); + Buffer body = client.request(requestOptions) + .compose(HttpClientRequest::send) + .expecting(that(resp -> assertEquals(String.valueOf(10), resp.headers().get("Content-Length")))) + .compose(HttpClientResponse::body) + .await(); + assertThat(body.toString()) + .startsWith("server.net") + .hasSize(10); } @Test @@ -214,17 +207,14 @@ public void testSendRangeFileFromClasspath() throws Exception { res.response().sendFile("hosts_config.txt", 13, 10); }); startServer(testAddress); - client.request(requestOptions) + Buffer body = client.request(requestOptions) .compose(req -> req .send() - .expecting(that(resp -> Assert.assertEquals(String.valueOf(10), resp.headers().get("Content-Length")))) + .expecting(that(resp -> assertEquals(String.valueOf(10), resp.headers().get("Content-Length")))) .compose(HttpClientResponse::body)) - .onComplete(TestUtils.onSuccess(body -> { - Assert.assertEquals("server.net", body.toString()); - Assert.assertEquals(10, body.toString().length()); - testComplete(); - })); - await(); + .await(); + assertEquals("server.net", body.toString()); + assertEquals(10, body.toString().length()); } @Test @@ -232,42 +222,37 @@ public void testSendZeroRangeFile() throws Exception { File f = setupFile("twenty_three_bytes.txt", TestUtils.randomAlphaString(23)); server.requestHandler(res -> res.response().sendFile(f.getAbsolutePath(), 23, 0)); startServer(testAddress); - client.request(requestOptions) + Buffer body = client.request(requestOptions) .compose(req -> req .send() - .expecting(that(resp -> Assert.assertEquals(String.valueOf(0), resp.headers().get("Content-Length")))) + .expecting(that(resp -> assertEquals(String.valueOf(0), resp.headers().get("Content-Length")))) .compose(HttpClientResponse::body)) - .onComplete(TestUtils.onSuccess(body -> { - Assert.assertEquals("", body.toString()); - Assert.assertEquals(0, body.toString().length()); - testComplete(); - })); - await(); + .await(); + assertEquals("", body.toString()); } @Test public void testSendFileOffsetIsHigherThanFileLength() throws Exception { testSendFileWithFailure( (resp, f) -> resp.sendFile(f.getAbsolutePath(), 33, 10), - err -> Assert.assertEquals("offset : 33 is larger than the requested file length : 23", err.getMessage())); + err -> assertEquals("offset : 33 is larger than the requested file length : 23", err.getMessage())); } @Test public void testSendFileWithNegativeLength() throws Exception { testSendFileWithFailure((resp, f) -> resp.sendFile(f.getAbsolutePath(), 0, -100), err -> { - Assert.assertEquals("length : -100 (expected: >= 0)", err.getMessage()); + assertEquals("length : -100 (expected: >= 0)", err.getMessage()); }); } @Test public void testSendFileWithNegativeOffset() throws Exception { testSendFileWithFailure((resp, f) -> resp.sendFile(f.getAbsolutePath(), -100, 23), err -> { - Assert.assertEquals("offset : -100 (expected: >= 0)", err.getMessage()); + assertEquals("offset : -100 (expected: >= 0)", err.getMessage()); }); } private void testSendFileWithFailure(BiFunction> sendFile, Consumer checker) throws Exception { - waitFor(2); File f = setupFile("twenty_three_bytes.txt", TestUtils.randomAlphaString(23)); server.requestHandler(res -> { // Expected @@ -276,18 +261,14 @@ private void testSendFileWithFailure(BiFunction res.response().setStatusCode(500).end()) .onComplete(TestUtils.onSuccess(v -> { - complete(); })); }); startServer(testAddress); client.request(requestOptions) .compose(HttpClientRequest::send) - .onComplete(TestUtils.onSuccess(response -> { - Assert.assertEquals(500, response.statusCode()); - complete(); - })); - - await(); + .expecting(HttpResponseExpectation.SC_INTERNAL_SERVER_ERROR) + .compose(HttpClientResponse::end) + .await(); } @Test @@ -295,7 +276,7 @@ public void testSendFileWithFileChannel() throws Exception { int fileLength = 16 * 1024 * 1024; BiFunction> sender = (file, response) -> response.sendFile(file.getChannel()); try (RandomAccessFile raf = testSendFileWithFileChannel(fileLength, sender, "application/octet-stream", fileLength)) { - Assert.assertTrue(raf.getChannel().isOpen()); + assertTrue(raf.getChannel().isOpen()); } } @@ -306,7 +287,7 @@ public void testSendFileWithFileChannelAndExtension() throws Exception { .putHeader(HttpHeaders.CONTENT_TYPE, "video/mp4") .sendFile(file.getChannel()); try (RandomAccessFile raf = testSendFileWithFileChannel(fileLength, sender, "video/mp4", fileLength)) { - Assert.assertTrue(raf.getChannel().isOpen()); + assertTrue(raf.getChannel().isOpen()); } } @@ -319,7 +300,7 @@ public void testSendFileWithFileChannelRange() throws Exception { .putHeader(HttpHeaders.CONTENT_TYPE, "video/mp4") .sendFile(file.getChannel(), offset, expectedRange); try (RandomAccessFile raf = testSendFileWithFileChannel(fileLength, sender, "video/mp4", expectedRange)) { - Assert.assertTrue(raf.getChannel().isOpen()); + assertTrue(raf.getChannel().isOpen()); } } @@ -361,14 +342,14 @@ private RandomAccessFile testSendFileWithFileChannel(int flen, BiFunction sender.apply(raf, req.response()).onComplete(TestUtils.onSuccess(v -> testComplete()))); + server.requestHandler(req -> sender.apply(raf, req.response()).onComplete(TestUtils.onSuccess(v -> { + }))); startServer(testAddress); Buffer body = client.request(requestOptions) .compose(req -> req.send() .expecting(HttpResponseExpectation.contentType(expectedContentType)) .compose(HttpClientResponse::body)).await(); - Assert.assertEquals(body.length(), expectedLength); - await(); + assertEquals(body.length(), expectedLength); return raf; } }