diff --git a/AGENTS.md b/AGENTS.md index fe1e439f57..8c2f5392c6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -94,7 +94,7 @@ Common commands: * Extend `AbstractBasicTest` for tests requiring an embedded Jetty server. * Extend `AbstractBasicWebSocketTest` for WebSocket tests. * Never use `Thread.sleep()` for synchronization. Use futures, latches or timeouts. -* Mark known flaky tests with `@RepeatedIfExceptionsTest` instead of `@Test`. +* Do not retry flaky tests. A flaky test is a bug. Find and fix the race. * Do not leak Netty `ByteBuf` instances. The leak detector extension will fail the test. * Keep the default test suite hermetic. * Tests requiring public hosts must be tagged `external`. diff --git a/client/pom.xml b/client/pom.xml index 862c52d3c6..dbd48c1996 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -171,14 +171,6 @@ test - - - io.github.artsok - rerunner-jupiter - 2.1.6 - test - - io.netty netty-pkitesting diff --git a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java index 38724e1aa6..05705bf1aa 100644 --- a/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java +++ b/client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java @@ -335,6 +335,9 @@ default long getMaxDecompressedResponseSize() { /** * Return the number of time the library will retry when an {@link IOException} is throw by the remote server * + *

A refused TCP connect is retried too. A connect timeout is not retried on the first attempt, but + * once a request is being retried any failure is. Retries are immediate and re-resolve the host. + * * @return the number of time the library will retry when an {@link IOException} is throw by the remote server */ int getMaxRequestRetry(); diff --git a/client/src/main/java/org/asynchttpclient/handler/BodyDeferringAsyncHandler.java b/client/src/main/java/org/asynchttpclient/handler/BodyDeferringAsyncHandler.java index dc58fc2c5b..5db40fe431 100644 --- a/client/src/main/java/org/asynchttpclient/handler/BodyDeferringAsyncHandler.java +++ b/client/src/main/java/org/asynchttpclient/handler/BodyDeferringAsyncHandler.java @@ -216,7 +216,9 @@ protected void closeOut() throws IOException { * * @return a {@link Response} * @throws InterruptedException if the latch is interrupted - * @throws IOException if the handler completed with an exception + * @throws IOException if the request failed before any response was received. A later body + * failure is reported by the request future and by + * {@link BodyDeferringInputStream#close()}, not here */ public @Nullable Response getResponse() throws InterruptedException, IOException { // block here as long as headers arrive @@ -224,11 +226,15 @@ protected void closeOut() throws IOException { try { semaphore.acquire(); + Response headers = response; + if (headers != null) { + // A failure recorded after the headers belongs to the body and is reported by the future. + return headers; + } if (throwable != null) { throw new IOException(throwable.getMessage(), throwable); - } else { - return response; } + return null; } finally { semaphore.release(); } diff --git a/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java b/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java index 5f78146577..5c63441b66 100755 --- a/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java +++ b/client/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java @@ -328,6 +328,10 @@ private void registerHttp2AndManageSemaphore(Channel channel, ConnectionSemaphor } } + /** + * Must only be called before {@link #writeRequest}: it may replay the request, and replaying one that was + * already written would send it twice. + */ public void onFailure(Channel channel, Throwable cause) { // beware, channel can be null diff --git a/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java b/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java index 487afe5072..3532de3889 100755 --- a/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java +++ b/client/src/main/java/org/asynchttpclient/netty/future/StackTraceInspector.java @@ -15,7 +15,10 @@ */ package org.asynchttpclient.netty.future; +import io.netty.channel.ConnectTimeoutException; + import java.io.IOException; +import java.net.ConnectException; import java.nio.channels.ClosedChannelException; public final class StackTraceInspector { @@ -38,7 +41,15 @@ private static boolean exceptionInMethod(Throwable t, String className, String m private static boolean recoverOnConnectCloseException(Throwable t) { while (true) { - if (exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect")) { + // Also a ConnectException, but retrying it would multiply the connect timeout. + if (t instanceof ConnectTimeoutException) { + return false; + } + // The type covers every transport. The frames (checkConnect up to JDK 12, pollConnect after) + // still matter: NIO reports an unreachable peer as NoRouteToHostException, not a ConnectException. + if (t instanceof ConnectException + || exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect") + || exceptionInMethod(t, "sun.nio.ch.Net", "pollConnect")) { return true; } if (t.getCause() == null) { @@ -49,6 +60,7 @@ private static boolean recoverOnConnectCloseException(Throwable t) { } public static boolean recoverOnNettyDisconnectException(Throwable t) { + // Start at the cause: NettyChannelConnector wraps every failure in a ConnectException. return t instanceof ClosedChannelException || exceptionInMethod(t, "io.netty.handler.ssl.SslHandler", "disconnect") || t.getCause() != null && recoverOnConnectCloseException(t.getCause()); diff --git a/client/src/test/java/org/asynchttpclient/AbsoluteRequestDeadlineTest.java b/client/src/test/java/org/asynchttpclient/AbsoluteRequestDeadlineTest.java index b292c76247..cd97f3142c 100644 --- a/client/src/test/java/org/asynchttpclient/AbsoluteRequestDeadlineTest.java +++ b/client/src/test/java/org/asynchttpclient/AbsoluteRequestDeadlineTest.java @@ -15,22 +15,30 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; import io.netty.util.concurrent.DefaultThreadFactory; +import org.asynchttpclient.netty.timeout.RequestTimeoutTimerTask; import org.asynchttpclient.testserver.HttpServer; import org.asynchttpclient.testserver.HttpTest; import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import static org.asynchttpclient.Dsl.config; @@ -46,20 +54,29 @@ * future, so with the deadline anchored on the holder each hop gets a budget of its own, and with it anchored * on the future a later hop gets only what is left. *

- * Timing-based, so repeated: the margins are wide (a 600 ms budget against hops of 400 ms) but a loaded CI box - * can still miss one. + * The tests read the budget each attempt is armed with, through {@link BudgetRecordingTimer}, instead of racing + * a server delay against the budget: connect and JVM warm-up also come out of the budget, so that race was lost + * on a cold JVM. */ public class AbsoluteRequestDeadlineTest extends HttpTest { private static final Duration BUDGET = Duration.ofMillis(600); + // Too large to run out, so the second hop is always sent. Nothing is timed against it. + private static final Duration UNSPENDABLE_BUDGET = Duration.ofSeconds(20); private static final long HOP_DELAY_MS = 400; private static final String FIRST_HOP = "/foo/bar"; private static final String SECOND_HOP = "/foo/bar2"; private HttpServer server; - // Coarse on purpose, for the one case that needs the request timeout not to fire: a wheel answers a + // Coarse on purpose, for the cases that need the request timeout not to fire: a wheel answers a // deadline on its first tick at or after it, so at this granularity nothing expires inside a test. private HashedWheelTimer stalledTimer; + private BudgetRecordingTimer budgetTimer; + // Read just before execute(), so never later than the future's own start. + private long executeNanos; + // The server's own measurement of its last delayed hop. Written on a Jetty thread, read here. + private final AtomicLong hopEnteredNanos = new AtomicLong(); + private final AtomicLong hopAnsweredNanos = new AtomicLong(); @BeforeEach public void start() throws Throwable { @@ -75,55 +92,81 @@ public void stop() throws Throwable { stalledTimer.stop(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void byDefaultEachHopGetsItsOwnBudget() throws Throwable { - // Two hops of 400 ms against a 600 ms budget. Each hop on its own fits, the pair does not, so with a - // per-attempt timeout the exchange completes. + // Two 400 ms hops do not fit in 600 ms, so the second one must have got a budget of its own. enqueueTwoDelayedHops(); - Outcome outcome = runAndAwait(baseConfig(), null); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer), null); outcome.assertReachedTheSecondHop(); + assertSecondHopGotAFreshBudget(); } - @RepeatedIfExceptionsTest(repeats = 5) - public void withAnAbsoluteDeadlineTheChainCannotOutrunTheBudget() throws Throwable { - enqueueTwoDelayedHops(); + @Test + public void anAbsoluteDeadlineLeavesTheSecondHopOnlyWhatIsLeft() throws Throwable { + // The upper bounds below are the only checks that fail if the full timeout is armed instead of the + // remainder. Not BUDGET: at 600 ms the second hop is only sent when the first round trip is fast. + enqueueDelayed(HOP_DELAY_MS, 302, SECOND_HOP); + server.enqueueOk(); - Outcome outcome = runAndAwait(baseConfig().setUseAbsoluteRequestDeadline(true), null); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer) + .setRequestTimeout(UNSPENDABLE_BUDGET) + .setUseAbsoluteRequestDeadline(true), null); - outcome.assertTimedOut(); + outcome.assertReachedTheSecondHop(); + assertEquals(2, budgetTimer.armedAttempts(), "expected one armed attempt per hop"); + long budget = UNSPENDABLE_BUDGET.toMillis(); + long first = budgetTimer.budgetOfAttempt(0); + long armed = budgetTimer.budgetOfAttempt(1); + assertTrue(armed < first, "the second hop was armed with " + armed + " ms, no less than the " + + first + " ms the first hop got, so nothing was netted off"); + // The server's measured delay, not HOP_DELAY_MS: Thread.sleep accuracy must not decide this. + long served = TimeUnit.NANOSECONDS.toMillis(hopAnsweredNanos.get() - hopEnteredNanos.get()); + assertTrue(armed <= budget - served, "the second hop was armed with " + armed + " ms, more than the " + + (budget - served) + " ms left after a first hop the server took " + served + " ms over"); + long spendable = TimeUnit.NANOSECONDS.toMillis(budgetTimer.armedAtNanos(1) - executeNanos); + assertTrue(armed >= budget - spendable, "the second hop was armed with " + armed + " ms of " + + budget + " ms, the exchange having spent at most " + spendable + " ms"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aRequestCanAskForAnAbsoluteDeadlineOnAPerAttemptClient() throws Throwable { - enqueueTwoDelayedHops(); + enqueueTheWholeBudgetThenAPromptHop(); - Outcome outcome = runAndAwait(baseConfig(), Boolean.TRUE); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer), Boolean.TRUE); - outcome.assertTimedOut(); + outcome.assertTimedOutBeforeSending(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aRequestCanOptOutOfAnAbsoluteDeadlineClient() throws Throwable { enqueueTwoDelayedHops(); - Outcome outcome = runAndAwait(baseConfig().setUseAbsoluteRequestDeadline(true), Boolean.FALSE); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer).setUseAbsoluteRequestDeadline(true), + Boolean.FALSE); outcome.assertReachedTheSecondHop(); + assertSecondHopGotAFreshBudget(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aSingleHopStillGetsTheWholeBudget() throws Throwable { // Guards the other direction: with a deadline, the first hop must not be handed a shortened budget. - enqueueDelayed(HOP_DELAY_MS, 200, null); + server.enqueueOk(); - Outcome outcome = runAndAwait(baseConfig().setUseAbsoluteRequestDeadline(true), null); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer).setUseAbsoluteRequestDeadline(true), null); outcome.assertCompletedAt(FIRST_HOP); + long armed = budgetTimer.budgetOfAttempt(0); + long spendable = TimeUnit.NANOSECONDS.toMillis(budgetTimer.armedAtNanos(0) - executeNanos); + assertTrue(armed >= BUDGET.toMillis() - spendable, "the first hop was armed with " + armed + + " ms of a " + BUDGET.toMillis() + " ms budget, having spent at most " + spendable + " ms"); + assertTrue(armed <= BUDGET.toMillis(), + "the first hop was armed with " + armed + " ms, more than the configured budget"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aHopWithNothingLeftToSpendIsNeverSent() throws Throwable { // The first hop answers after the budget is gone, and the timer is too coarse to have expired the // exchange in the meantime. That is the window in which a redirect used to be written anyway: a permit @@ -136,12 +179,12 @@ public void aHopWithNothingLeftToSpendIsNeverSent() throws Throwable { response.setStatus(200); }); - Outcome outcome = runAndAwait(baseConfig() - .setNettyTimer(stalledTimer) - .setUseAbsoluteRequestDeadline(true), null); + Outcome outcome = runAndAwait(recordingConfig(stalledTimer).setUseAbsoluteRequestDeadline(true), null); outcome.assertTimedOutBeforeSending(); assertFalse(secondHopServed.get(), "the redirect target was sent a request with no budget left"); + assertEquals(1, budgetTimer.armedAttempts(), + "a hop with nothing left to spend was armed a budget of its own"); } private DefaultAsyncHttpClientConfig.Builder baseConfig() { @@ -153,6 +196,83 @@ private void enqueueTwoDelayedHops() { enqueueDelayed(HOP_DELAY_MS, 200, null); } + /** + * The first hop outlasts the whole budget, so the redirect is refused however fast the box is. + */ + private void enqueueTheWholeBudgetThenAPromptHop() { + enqueueDelayed(BUDGET.toMillis() + HOP_DELAY_MS, 302, SECOND_HOP); + server.enqueueOk(); + } + + /** + * Event-loop timeouts are pinned off because the recorder only sees timeouts armed through the {@link Timer}. + */ + private DefaultAsyncHttpClientConfig.Builder recordingConfig(Timer wheel) { + budgetTimer = new BudgetRecordingTimer(wheel); + return baseConfig().setNettyTimer(budgetTimer).setUseEventLoopTimeouts(false); + } + + private void assertSecondHopGotAFreshBudget() { + assertEquals(BUDGET.toMillis(), budgetTimer.budgetOfAttempt(1), + "the second hop was not armed the whole budget over again"); + } + + /** + * Records the delay each request timeout is armed with. Delegates to the stalled wheel, so nothing fires. + */ + private static final class BudgetRecordingTimer implements Timer { + + private final Timer delegate; + private final List armings = new CopyOnWriteArrayList<>(); + + private BudgetRecordingTimer(Timer delegate) { + this.delegate = delegate; + } + + @Override + public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { + // The cookie evictor and the pool cleaner use this timer too. + if (task instanceof RequestTimeoutTimerTask) { + armings.add(new Arming(unit.toMillis(delay), System.nanoTime())); + } + return delegate.newTimeout(task, delay, unit); + } + + @Override + public Set stop() { + return delegate.stop(); + } + + long budgetOfAttempt(int index) { + return arming(index).budgetMillis; + } + + long armedAtNanos(int index) { + return arming(index).nanos; + } + + int armedAttempts() { + return armings.size(); + } + + private Arming arming(int index) { + assertTrue(armings.size() > index, "attempt " + (index + 1) + + " armed no request timeout, only " + armings.size() + " did"); + return armings.get(index); + } + + private static final class Arming { + + private final long budgetMillis; + private final long nanos; + + private Arming(long budgetMillis, long nanos) { + this.budgetMillis = budgetMillis; + this.nanos = nanos; + } + } + } + /** * What the exchange ended as. The passing cases assert where it ended and not merely that nothing was * thrown: a dropped {@code Location} header, or redirects turned off, would satisfy "no exception" having @@ -201,12 +321,15 @@ void assertTimedOutBeforeSending() { */ private void enqueueDelayed(long delayMs, int status, @Nullable String location) { server.enqueueResponse(response -> { + hopEnteredNanos.set(System.nanoTime()); try { Thread.sleep(delayMs); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException(e); } + // Stamped before the status is set, while the client is still waiting on this hop. + hopAnsweredNanos.set(System.nanoTime()); response.setStatus(status); if (location != null) { response.setHeader(HttpHeaderNames.LOCATION.toString(), location); @@ -225,6 +348,7 @@ private Outcome runAndAwait(DefaultAsyncHttpClientConfig.Builder builder, if (perRequestOverride != null) { request.setUseAbsoluteRequestDeadline(perRequestOverride); } + executeNanos = System.nanoTime(); request.execute(new AsyncCompletionHandler() { @Override public Void onCompleted(Response response) { diff --git a/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java b/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java index 2dcfa859dc..5cbd1c2416 100644 --- a/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java +++ b/client/src/test/java/org/asynchttpclient/AbstractBasicTest.java @@ -21,6 +21,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.ExtendWith; @@ -28,6 +29,7 @@ import org.slf4j.LoggerFactory; import static org.asynchttpclient.test.TestUtils.addHttpConnector; +import static org.junit.jupiter.api.Assertions.assertTrue; @TestInstance(TestInstance.Lifecycle.PER_CLASS) @ExtendWith(NettyLeakDetectorExtension.class) @@ -38,6 +40,7 @@ public abstract class AbstractBasicTest { protected Server server; protected int port1 = -1; protected int port2 = -1; + private Server lastObservedServer; @BeforeAll public void setUpGlobal() throws Exception { @@ -46,6 +49,8 @@ public void setUpGlobal() throws Exception { server.setHandler(configureHandler()); ServerConnector connector2 = addHttpConnector(server); server.start(); + // Lets the guard below catch a subclass that replaces this server in its very first test. + lastObservedServer = server; port1 = connector1.getLocalPort(); port2 = connector2.getLocalPort(); @@ -53,6 +58,10 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + /** + * An override does not inherit this annotation. A subclass that re-annotates {@code setUpGlobal} must + * re-annotate this method to match, or it leaks a server per test. + */ @AfterAll public void tearDownGlobal() throws Exception { logger.debug("Shutting down local server: {}", server); @@ -62,6 +71,20 @@ public void tearDownGlobal() throws Exception { } } + /** + * Fails a subclass that starts a server per test but only stops the last one. Only sees replacements + * between tests, not inside a test body. + */ + @AfterEach + public void assertReplacedServerWasStopped() { + Server previous = lastObservedServer; + lastObservedServer = server; + if (previous != null && previous != server) { + assertTrue(previous.isStopped(), "a Jetty server was replaced while it was still running;" + + " a fixture re-annotated as @BeforeEach needs its teardown re-annotated to match"); + } + } + protected String getTargetUrl() { return String.format("http://localhost:%d/foo/test", port1); } diff --git a/client/src/test/java/org/asynchttpclient/AddressResolverGroupTest.java b/client/src/test/java/org/asynchttpclient/AddressResolverGroupTest.java index d56c130b41..0a6f040adb 100644 --- a/client/src/test/java/org/asynchttpclient/AddressResolverGroupTest.java +++ b/client/src/test/java/org/asynchttpclient/AddressResolverGroupTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.resolver.dns.DnsAddressResolverGroup; import io.netty.resolver.dns.DnsServerAddressStreamProviders; @@ -25,6 +24,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.concurrent.ExecutionException; @@ -64,7 +64,7 @@ private String getTargetUrl() { return server.getHttpUrl() + "/foo/bar"; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void requestWithDnsAddressResolverGroupSucceeds() throws Throwable { DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup( NioDatagramChannel.class, @@ -78,7 +78,7 @@ public void requestWithDnsAddressResolverGroupSucceeds() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void dnsResolverGroupFiresHostnameResolutionEvents() throws Throwable { DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup( NioDatagramChannel.class, @@ -110,14 +110,14 @@ public void dnsResolverGroupFiresHostnameResolutionEvents() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void defaultConfigDoesNotSetAddressResolverGroup() { DefaultAsyncHttpClientConfig config = config().build(); assertNull(config.getAddressResolverGroup(), "Default config should not have an AddressResolverGroup"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void unknownHostWithDnsResolverGroupFails() throws Throwable { DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup( NioDatagramChannel.class, @@ -134,7 +134,7 @@ public void unknownHostWithDnsResolverGroupFails() throws Throwable { } @Tag("external") - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void resolveRealDomainWithDnsResolverGroup() throws Throwable { assumeTrue(isExternalNetworkAvailable(), "External network not available - skipping test"); @@ -151,7 +151,7 @@ public void resolveRealDomainWithDnsResolverGroup() throws Throwable { } @Tag("external") - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void resolveMultipleRealDomainsWithDnsResolverGroup() throws Throwable { assumeTrue(isExternalNetworkAvailable(), "External network not available - skipping test"); diff --git a/client/src/test/java/org/asynchttpclient/AsyncHttpClientDefaultsTest.java b/client/src/test/java/org/asynchttpclient/AsyncHttpClientDefaultsTest.java index 34056a8186..c83494bb7e 100644 --- a/client/src/test/java/org/asynchttpclient/AsyncHttpClientDefaultsTest.java +++ b/client/src/test/java/org/asynchttpclient/AsyncHttpClientDefaultsTest.java @@ -15,9 +15,9 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.config.AsyncHttpClientConfigDefaults; import org.asynchttpclient.config.AsyncHttpClientConfigHelper; +import org.junit.jupiter.api.Test; import java.lang.reflect.Method; import java.time.Duration; @@ -30,151 +30,151 @@ public class AsyncHttpClientDefaultsTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseOnlyEpollNativeTransport() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseOnlyEpollNativeTransport()); testBooleanSystemProperty("useOnlyEpollNativeTransport", "defaultUseOnlyEpollNativeTransport", "false"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultMaxTotalConnections() { assertEquals(AsyncHttpClientConfigDefaults.defaultMaxConnections(), -1); testIntegerSystemProperty("maxConnections", "defaultMaxConnections", "100"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultMaxConnectionPerHost() { assertEquals(AsyncHttpClientConfigDefaults.defaultMaxConnectionsPerHost(), -1); testIntegerSystemProperty("maxConnectionsPerHost", "defaultMaxConnectionsPerHost", "100"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultConnectTimeOut() { assertEquals(AsyncHttpClientConfigDefaults.defaultConnectTimeout(), Duration.ofSeconds(5)); testDurationSystemProperty("connectTimeout", "defaultConnectTimeout", "PT0.1S"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultPooledConnectionIdleTimeout() { assertEquals(AsyncHttpClientConfigDefaults.defaultPooledConnectionIdleTimeout(), Duration.ofMinutes(1)); testDurationSystemProperty("pooledConnectionIdleTimeout", "defaultPooledConnectionIdleTimeout", "PT0.1S"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultReadTimeout() { assertEquals(AsyncHttpClientConfigDefaults.defaultReadTimeout(), Duration.ofSeconds(60)); testDurationSystemProperty("readTimeout", "defaultReadTimeout", "PT0.1S"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultRequestTimeout() { assertEquals(AsyncHttpClientConfigDefaults.defaultRequestTimeout(), Duration.ofSeconds(60)); testDurationSystemProperty("requestTimeout", "defaultRequestTimeout", "PT0.1S"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultConnectionTtl() { assertEquals(AsyncHttpClientConfigDefaults.defaultConnectionTtl(), Duration.ofMillis(-1)); testDurationSystemProperty("connectionTtl", "defaultConnectionTtl", "PT0.1S"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseAbsoluteRequestDeadline() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseAbsoluteRequestDeadline()); testBooleanSystemProperty("useAbsoluteRequestDeadline", "defaultUseAbsoluteRequestDeadline", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseEventLoopTimeouts() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseEventLoopTimeouts()); testBooleanSystemProperty("useEventLoopTimeouts", "defaultUseEventLoopTimeouts", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultFollowRedirect() { assertFalse(AsyncHttpClientConfigDefaults.defaultFollowRedirect()); testBooleanSystemProperty("followRedirect", "defaultFollowRedirect", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultMaxRedirects() { assertEquals(AsyncHttpClientConfigDefaults.defaultMaxRedirects(), 5); testIntegerSystemProperty("maxRedirects", "defaultMaxRedirects", "100"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultCompressionEnforced() { assertFalse(AsyncHttpClientConfigDefaults.defaultCompressionEnforced()); testBooleanSystemProperty("compressionEnforced", "defaultCompressionEnforced", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUserAgent() { assertEquals(AsyncHttpClientConfigDefaults.defaultUserAgent(), "AHC/2.1"); testStringSystemProperty("userAgent", "defaultUserAgent", "MyAHC"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseProxySelector() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseProxySelector()); testBooleanSystemProperty("useProxySelector", "defaultUseProxySelector", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseProxyProperties() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseProxyProperties()); testBooleanSystemProperty("useProxyProperties", "defaultUseProxyProperties", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultStrict302Handling() { assertFalse(AsyncHttpClientConfigDefaults.defaultStrict302Handling()); testBooleanSystemProperty("strict302Handling", "defaultStrict302Handling", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultRefuseSchemeDowngradeOnRedirect() { assertFalse(AsyncHttpClientConfigDefaults.defaultRefuseSchemeDowngradeOnRedirect()); testBooleanSystemProperty("refuseSchemeDowngradeOnRedirect", "defaultRefuseSchemeDowngradeOnRedirect", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultRefuseCrossOriginBodyOnRedirect() { assertFalse(AsyncHttpClientConfigDefaults.defaultRefuseCrossOriginBodyOnRedirect()); testBooleanSystemProperty("refuseCrossOriginBodyOnRedirect", "defaultRefuseCrossOriginBodyOnRedirect", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultAllowPoolingConnection() { assertTrue(AsyncHttpClientConfigDefaults.defaultKeepAlive()); testBooleanSystemProperty("keepAlive", "defaultKeepAlive", "false"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultMaxRequestRetry() { assertEquals(AsyncHttpClientConfigDefaults.defaultMaxRequestRetry(), 5); testIntegerSystemProperty("maxRequestRetry", "defaultMaxRequestRetry", "100"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultDisableUrlEncodingForBoundRequests() { assertFalse(AsyncHttpClientConfigDefaults.defaultDisableUrlEncodingForBoundRequests()); testBooleanSystemProperty("disableUrlEncodingForBoundRequests", "defaultDisableUrlEncodingForBoundRequests", "true"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultUseInsecureTrustManager() { assertFalse(AsyncHttpClientConfigDefaults.defaultUseInsecureTrustManager()); testBooleanSystemProperty("useInsecureTrustManager", "defaultUseInsecureTrustManager", "false"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultHashedWheelTimerTickDuration() { assertEquals(AsyncHttpClientConfigDefaults.defaultHashedWheelTimerTickDuration(), 100); testIntegerSystemProperty("hashedWheelTimerTickDuration", "defaultHashedWheelTimerTickDuration", "100"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultHashedWheelTimerSize() { assertEquals(AsyncHttpClientConfigDefaults.defaultHashedWheelTimerSize(), 512); testIntegerSystemProperty("hashedWheelTimerSize", "defaultHashedWheelTimerSize", "512"); diff --git a/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java b/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java index c7d17a2569..c0957ba306 100644 --- a/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java +++ b/client/src/test/java/org/asynchttpclient/AsyncStreamHandlerTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; import org.asynchttpclient.testserver.HttpServer; import org.asynchttpclient.testserver.HttpTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.util.Arrays; @@ -69,7 +69,7 @@ private String getTargetUrl() { return server.getHttpUrl() + "/foo/bar"; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getWithOnHeadersReceivedAbort() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -85,7 +85,7 @@ public State onHeadersReceived(HttpHeaders headers) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStreamPOSTTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -127,7 +127,7 @@ public String onCompleted() { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStreamInterruptTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -168,7 +168,7 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStreamFutureTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -220,7 +220,7 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStreamThrowableRefusedTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -253,7 +253,7 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStreamReusePOSTTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -336,7 +336,7 @@ public String onCompleted() { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncStream302RedirectWithBody() throws Throwable { withClient(config().setFollowRedirect(true)).run(client -> withServer(server).run(server -> { @@ -358,7 +358,7 @@ public void asyncStream302RedirectWithBody() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 3000) public void asyncStreamJustStatusLine() throws Throwable { withClient().run(client -> @@ -429,7 +429,7 @@ public Integer onCompleted() { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncOptionsTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -463,7 +463,7 @@ public String onCompleted() { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void closeConnectionTest() throws Throwable { withClient().run(client -> withServer(server).run(server -> { diff --git a/client/src/test/java/org/asynchttpclient/AsyncStreamLifecycleTest.java b/client/src/test/java/org/asynchttpclient/AsyncStreamLifecycleTest.java index 9b290f82ed..61e3a4d118 100644 --- a/client/src/test/java/org/asynchttpclient/AsyncStreamLifecycleTest.java +++ b/client/src/test/java/org/asynchttpclient/AsyncStreamLifecycleTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.AsyncContext; import jakarta.servlet.http.HttpServletRequest; @@ -23,6 +22,8 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import java.io.IOException; import java.io.PrintWriter; @@ -33,12 +34,12 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import static org.asynchttpclient.Dsl.asyncHttpClient; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; /** * Tests default asynchronous life cycle. @@ -46,7 +47,11 @@ * @author Hubert Iwaniuk */ public class AsyncStreamLifecycleTest extends AbstractBasicTest { - private static final ExecutorService executorService = Executors.newFixedThreadPool(2); + // One thread, so the two parts are written in order. + private static final ExecutorService executorService = Executors.newSingleThreadExecutor(); + + // Counted down by the client on its first body part. The server writes the second part only after that. + private volatile CountDownLatch firstPartReceived = new CountDownLatch(1); @Override @AfterAll @@ -66,34 +71,33 @@ public void handle(String s, Request request, HttpServletRequest req, final Http final PrintWriter writer = resp.getWriter(); executorService.submit(() -> { try { - Thread.sleep(100); + logger.info("Delivering part1."); + writer.write("part1"); + writer.flush(); + if (!firstPartReceived.await(TIMEOUT, TimeUnit.SECONDS)) { + logger.error("Client never received part1."); + } + logger.info("Delivering part2."); + writer.write("part2"); + writer.flush(); } catch (InterruptedException e) { - logger.error("Failed to sleep for 100 ms.", e); + Thread.currentThread().interrupt(); + logger.error("Interrupted while waiting for part1 to be received.", e); + } finally { + asyncContext.complete(); } - logger.info("Delivering part1."); - writer.write("part1"); - writer.flush(); - }); - executorService.submit(() -> { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - logger.error("Failed to sleep for 200 ms.", e); - } - logger.info("Delivering part2."); - writer.write("part2"); - writer.flush(); - asyncContext.complete(); }); request.setHandled(true); } }; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void testStream() throws Exception { + firstPartReceived = new CountDownLatch(1); try (AsyncHttpClient ahc = asyncHttpClient()) { - final AtomicBoolean err = new AtomicBoolean(false); + final AtomicReference thrown = new AtomicReference<>(); final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); final AtomicBoolean status = new AtomicBoolean(false); final AtomicInteger headers = new AtomicInteger(0); @@ -101,8 +105,9 @@ public void testStream() throws Exception { ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build(), new AsyncHandler() { @Override public void onThrowable(Throwable t) { - fail("Got throwable.", t); - err.set(true); + // Recorded, not asserted: NettyResponseFuture.abort swallows anything thrown here. + thrown.set(t); + latch.countDown(); } @Override @@ -111,6 +116,7 @@ public State onBodyPartReceived(HttpResponseBodyPart e) throws Exception { String s = new String(e.getBodyPartBytes()); logger.info("got part: {}", s); queue.put(s); + firstPartReceived.countDown(); } return State.CONTINUE; } @@ -136,13 +142,14 @@ public Object onCompleted() { } }); - assertTrue(latch.await(1, TimeUnit.SECONDS), "Latch failed."); - assertFalse(err.get()); - assertEquals(queue.size(), 2); - assertTrue(queue.contains("part1")); - assertTrue(queue.contains("part2")); + // The latch also fires on failure, so check for one before looking at the parts. + assertTrue(latch.await(TIMEOUT, TimeUnit.SECONDS), () -> "Latch failed. Received so far: " + queue); + assertNull(thrown.get(), () -> "Got throwable: " + thrown.get()); + assertEquals(2, queue.size()); + assertEquals("part1", queue.poll()); + assertEquals("part2", queue.poll()); assertTrue(status.get()); - assertEquals(headers.get(), 1); + assertEquals(1, headers.get()); } } } diff --git a/client/src/test/java/org/asynchttpclient/AuthTimeoutTest.java b/client/src/test/java/org/asynchttpclient/AuthTimeoutTest.java index 2ae7ea279c..05ca6ccf1c 100644 --- a/client/src/test/java/org/asynchttpclient/AuthTimeoutTest.java +++ b/client/src/test/java/org/asynchttpclient/AuthTimeoutTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -24,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.asynchttpclient.test.ExtendedDigestAuthenticator; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.OutputStream; @@ -79,7 +79,7 @@ public void tearDownGlobal() throws Exception { server2.stop(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { execute(client, true, false).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS); @@ -88,7 +88,7 @@ public void basicAuthTimeoutTest() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicPreemptiveAuthTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { execute(client, true, true).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS); @@ -97,7 +97,7 @@ public void basicPreemptiveAuthTimeoutTest() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { execute(client, false, false).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS); @@ -107,28 +107,28 @@ public void digestAuthTimeoutTest() throws Throwable { } @Disabled - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestPreemptiveAuthTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { assertThrows(TimeoutException.class, () -> execute(client, false, true).get(LONG_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS)); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthFutureTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { assertThrows(TimeoutException.class, () -> execute(client, true, false).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS)); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicPreemptiveAuthFutureTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { assertThrows(TimeoutException.class, () -> execute(client, true, true).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS)); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthFutureTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { assertThrows(TimeoutException.class, () -> execute(client, false, false).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS)); @@ -136,7 +136,7 @@ public void digestAuthFutureTimeoutTest() throws Throwable { } @Disabled - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestPreemptiveAuthFutureTimeoutTest() throws Throwable { try (AsyncHttpClient client = newClient()) { assertThrows(TimeoutException.class, () -> execute(client, false, true).get(SHORT_FUTURE_TIMEOUT, TimeUnit.MILLISECONDS)); diff --git a/client/src/test/java/org/asynchttpclient/BasicAuthTest.java b/client/src/test/java/org/asynchttpclient/BasicAuthTest.java index af1ee7b57a..6d57d4d155 100644 --- a/client/src/test/java/org/asynchttpclient/BasicAuthTest.java +++ b/client/src/test/java/org/asynchttpclient/BasicAuthTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -26,6 +25,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -106,7 +106,7 @@ public AbstractHandler configureHandler() throws Exception { return new SimpleHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet(getTargetUrl()) @@ -119,7 +119,7 @@ public void basicAuthTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirectAndBasicAuthTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setFollowRedirect(true).setMaxRedirects(10))) { Future f = client.prepareGet(getTargetUrl2()) @@ -132,7 +132,7 @@ public void redirectAndBasicAuthTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basic401Test() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()) @@ -179,7 +179,7 @@ public Integer onCompleted() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthTestPreemptiveTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { // send the request to the no-auth endpoint to be able to verify the @@ -195,7 +195,7 @@ public void basicAuthTestPreemptiveTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthNegativeTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet(getTargetUrl()) @@ -208,7 +208,7 @@ public void basicAuthNegativeTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthInputStreamTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePost(getTargetUrl()) @@ -224,7 +224,7 @@ public void basicAuthInputStreamTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthFileTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePost(getTargetUrl()) @@ -240,7 +240,7 @@ public void basicAuthFileTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthAsyncConfigTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setRealm(basicAuthRealm(USER, ADMIN)))) { Future f = client.preparePost(getTargetUrl()) @@ -255,7 +255,7 @@ public void basicAuthAsyncConfigTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicAuthFileNoKeepAliveTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setKeepAlive(false))) { @@ -272,7 +272,7 @@ public void basicAuthFileNoKeepAliveTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void noneAuthTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm(basicAuthRealm(USER, ADMIN).build()); diff --git a/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpTest.java b/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpTest.java index 6845152d85..b053e30f14 100644 --- a/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpTest.java +++ b/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -28,6 +27,7 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -94,7 +94,7 @@ public void tearDownGlobal() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nonPreemptiveProxyAuthWithPlainHttpTarget() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { String targetUrl = "http://localhost:" + httpPort + "/foo/bar"; diff --git a/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpsTest.java b/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpsTest.java index 51d24af7c4..ed1b0b2600 100644 --- a/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpsTest.java +++ b/client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpsTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.Realm.AuthScheme; @@ -25,6 +24,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -110,7 +110,7 @@ public void tearDownGlobal() throws Exception { proxy.stop(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nonPreemptiveProxyAuthWithHttpsTarget() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setUseInsecureTrustManager(true))) { String targetUrl = "https://localhost:" + httpPort + "/foo/bar"; diff --git a/client/src/test/java/org/asynchttpclient/BasicHttpTest.java b/client/src/test/java/org/asynchttpclient/BasicHttpTest.java index 0e0cff044b..9abd612d79 100755 --- a/client/src/test/java/org/asynchttpclient/BasicHttpTest.java +++ b/client/src/test/java/org/asynchttpclient/BasicHttpTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; @@ -34,6 +33,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import javax.net.ssl.SSLException; import java.io.ByteArrayInputStream; @@ -107,7 +107,7 @@ private String getTargetUrl() { return server.getHttpUrl() + "/foo/bar"; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void generatedAcceptEncodingKeepsHttp1Spelling() throws Exception { server.enqueueEcho(); try (AsyncHttpClient client = asyncHttpClient(config().setCompressionEnforced(true))) { @@ -119,7 +119,7 @@ public void generatedAcceptEncodingKeepsHttp1Spelling() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getRootUrl() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -131,7 +131,7 @@ public void getRootUrl() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getUrlWithPathWithoutQuery() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -142,7 +142,7 @@ public void getUrlWithPathWithoutQuery() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getUrlWithPathWithQuery() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -156,7 +156,7 @@ public void getUrlWithPathWithQuery() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getUrlWithPathWithQueryParams() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -167,7 +167,7 @@ public void getUrlWithPathWithQueryParams() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getResponseBody() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -195,7 +195,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getWithHeaders() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -220,7 +220,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postWithHeadersAndFormParams() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -250,7 +250,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postChineseChar() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -280,7 +280,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void headHasEmptyBody() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -298,12 +298,12 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nullSchemeThrowsNPE() throws Throwable { assertThrows(IllegalArgumentException.class, () -> withClient().run(client -> client.prepareGet("gatling.io").execute())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void jettyRespondsWithChunkedTransferEncoding() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -320,7 +320,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getWithCookies() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -344,7 +344,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void defaultRequestBodyEncodingIsUtf8() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -356,7 +356,7 @@ public void defaultRequestBodyEncodingIsUtf8() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postFormParametersAsBodyString() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -388,7 +388,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postFormParametersAsBodyStream() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -419,7 +419,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void putFormParametersAsBodyStream() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -450,7 +450,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postSingleStringPart() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -469,7 +469,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postWithBody() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -485,7 +485,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getVirtualHost() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -504,7 +504,7 @@ public void getVirtualHost() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void cancelledFutureThrowsCancellationException() throws Throwable { assertThrows(CancellationException.class, () -> { withClient().run(client -> @@ -524,7 +524,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void futureTimeOutThrowsTimeoutException() throws Throwable { assertThrows(TimeoutException.class, () -> { withClient().run(client -> @@ -544,7 +544,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void connectFailureThrowsConnectException() throws Throwable { assertThrows(ConnectException.class, () -> { withClient().run(client -> { @@ -562,7 +562,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void connectFailureNotifiesHandlerWithConnectException() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -586,7 +586,7 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void unknownHostThrowsUnknownHostException() throws Throwable { assertThrows(UnknownHostException.class, () -> { withClient().run(client -> @@ -604,7 +604,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getEmptyBody() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -615,7 +615,7 @@ public void getEmptyBody() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getEmptyBodyNotifiesHandler() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -635,7 +635,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void exceptionInOnCompletedGetNotifiedToOnThrowable() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -665,7 +665,7 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void exceptionInOnCompletedGetNotifiedToFuture() throws Throwable { assertThrows(IllegalStateException.class, () -> { withClient().run(client -> @@ -691,7 +691,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void configTimeoutNotifiesOnThrowableAndFuture() throws Throwable { assertThrows(TimeoutException.class, () -> { withClient(config().setRequestTimeout(Duration.ofSeconds(1))).run(client -> @@ -736,7 +736,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void configRequestTimeoutHappensInDueTime() throws Throwable { assertThrows(TimeoutException.class, () -> { withClient(config().setRequestTimeout(Duration.ofSeconds(1))).run(client -> @@ -758,7 +758,7 @@ public void configRequestTimeoutHappensInDueTime() throws Throwable { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getProperPathAndQueryString() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -774,7 +774,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void connectionIsReusedForSequentialRequests() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -813,7 +813,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void reachingMaxRedirectThrowsMaxRedirectException() throws Throwable { assertThrows(MaxRedirectException.class, () -> { withClient(config().setMaxRedirects(1).setFollowRedirect(true)).run(client -> @@ -840,7 +840,7 @@ public void onThrowable(Throwable t) { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nonBlockingNestedRequestsFromIoThreadAreFine() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -875,7 +875,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void optionsIsSupported() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -886,7 +886,7 @@ public void optionsIsSupported() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void cancellingFutureNotifiesOnThrowableWithCancellationException() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -913,14 +913,14 @@ public void onThrowable(Throwable t) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getShouldAllowBody() throws Throwable { withClient().run(client -> withServer(server).run(server -> client.prepareGet(getTargetUrl()).setBody("Boo!").execute())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void malformedUriThrowsException() throws Throwable { assertThrows(IllegalArgumentException.class, () -> { withClient().run(client -> @@ -928,7 +928,7 @@ public void malformedUriThrowsException() throws Throwable { }); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void emptyResponseBodyBytesAreEmpty() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -939,7 +939,7 @@ public void emptyResponseBodyBytesAreEmpty() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void newConnectionEventsAreFired() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -967,7 +967,7 @@ public void newConnectionEventsAreFired() throws Throwable { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void requestingPlainHttpEndpointOverHttpsThrowsSslException() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -982,7 +982,7 @@ public void requestingPlainHttpEndpointOverHttpsThrowsSslException() throws Thro })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postUnboundedInputStreamAsBodyStream() throws Throwable { withClient().run(client -> withServer(server).run(server -> { @@ -1016,7 +1016,7 @@ public Response onCompleted(Response response) { })); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postInputStreamWithContentLengthAsBodyGenerator() throws Throwable { withClient().run(client -> withServer(server).run(server -> { diff --git a/client/src/test/java/org/asynchttpclient/BasicHttpsTest.java b/client/src/test/java/org/asynchttpclient/BasicHttpsTest.java index f932836b5a..82c1e3e6fa 100644 --- a/client/src/test/java/org/asynchttpclient/BasicHttpsTest.java +++ b/client/src/test/java/org/asynchttpclient/BasicHttpsTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.channel.KeepAliveStrategy; import org.asynchttpclient.test.EventCollectingHandler; @@ -23,6 +22,7 @@ import org.asynchttpclient.testserver.HttpTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import javax.net.ssl.SSLHandshakeException; @@ -64,7 +64,7 @@ private String getTargetUrl() { return server.getHttpsUrl() + "/foo/bar"; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postFileOverHttps() throws Throwable { logger.debug(">>> postBodyOverHttps"); withClient(config().setSslEngineFactory(createSslEngineFactory())).run(client -> @@ -79,7 +79,7 @@ public void postFileOverHttps() throws Throwable { logger.debug("<<< postBodyOverHttps"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postLargeFileOverHttps() throws Throwable { logger.debug(">>> postLargeFileOverHttps"); withClient(config().setSslEngineFactory(createSslEngineFactory())).run(client -> @@ -94,7 +94,7 @@ public void postLargeFileOverHttps() throws Throwable { logger.debug("<<< postLargeFileOverHttps"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleSequentialPostRequestsOverHttps() throws Throwable { logger.debug(">>> multipleSequentialPostRequestsOverHttps"); withClient(config().setSslEngineFactory(createSslEngineFactory())).run(client -> @@ -112,7 +112,7 @@ public void multipleSequentialPostRequestsOverHttps() throws Throwable { logger.debug("<<< multipleSequentialPostRequestsOverHttps"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleConcurrentPostRequestsOverHttpsWithDisabledKeepAliveStrategy() throws Throwable { logger.debug(">>> multipleConcurrentPostRequestsOverHttpsWithDisabledKeepAliveStrategy"); @@ -136,7 +136,7 @@ public void multipleConcurrentPostRequestsOverHttpsWithDisabledKeepAliveStrategy logger.debug("<<< multipleConcurrentPostRequestsOverHttpsWithDisabledKeepAliveStrategy"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void reconnectAfterFailedCertificationPath() throws Throwable { logger.debug(">>> reconnectAfterFailedCertificationPath"); @@ -167,7 +167,7 @@ public void reconnectAfterFailedCertificationPath() throws Throwable { logger.debug("<<< reconnectAfterFailedCertificationPath"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 2000) public void failInstantlyIfNotAllowedSelfSignedCertificate() throws Throwable { logger.debug(">>> failInstantlyIfNotAllowedSelfSignedCertificate"); @@ -185,7 +185,7 @@ public void failInstantlyIfNotAllowedSelfSignedCertificate() throws Throwable { logger.debug("<<< failInstantlyIfNotAllowedSelfSignedCertificate"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testNormalEventsFired() throws Throwable { logger.debug(">>> testNormalEventsFired"); diff --git a/client/src/test/java/org/asynchttpclient/ByteBufferCapacityTest.java b/client/src/test/java/org/asynchttpclient/ByteBufferCapacityTest.java index a65cd79139..59ae5cb5b8 100644 --- a/client/src/test/java/org/asynchttpclient/ByteBufferCapacityTest.java +++ b/client/src/test/java/org/asynchttpclient/ByteBufferCapacityTest.java @@ -12,12 +12,12 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -38,7 +38,7 @@ public AbstractHandler configureHandler() throws Exception { return new BasicHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicByteBufferTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { File largeFile = createTempFile(1024 * 100 * 10); diff --git a/client/src/test/java/org/asynchttpclient/ComplexClientTest.java b/client/src/test/java/org/asynchttpclient/ComplexClientTest.java index 089be3d6ad..b8d531e5d3 100644 --- a/client/src/test/java/org/asynchttpclient/ComplexClientTest.java +++ b/client/src/test/java/org/asynchttpclient/ComplexClientTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.util.concurrent.TimeUnit; @@ -24,7 +24,7 @@ public class ComplexClientTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleRequestsTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { String body = "hello there"; @@ -49,7 +49,7 @@ public void multipleRequestsTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void urlWithoutSlashTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { String body = "hello there"; diff --git a/client/src/test/java/org/asynchttpclient/CookieStoreTest.java b/client/src/test/java/org/asynchttpclient/CookieStoreTest.java index 1864ad01a4..ff6a777fce 100644 --- a/client/src/test/java/org/asynchttpclient/CookieStoreTest.java +++ b/client/src/test/java/org/asynchttpclient/CookieStoreTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.cookie.ClientCookieDecoder; import io.netty.handler.codec.http.cookie.ClientCookieEncoder; import io.netty.handler.codec.http.cookie.Cookie; @@ -25,6 +24,7 @@ import org.asynchttpclient.uri.Uri; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +52,7 @@ public void tearDownGlobal() { System.out.println("--Stop"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { addCookieWithEmptyPath(); dontReturnCookieForAnotherDomain(); diff --git a/client/src/test/java/org/asynchttpclient/CustomRemoteAddressTest.java b/client/src/test/java/org/asynchttpclient/CustomRemoteAddressTest.java index 437446f388..d1cf7126ee 100755 --- a/client/src/test/java/org/asynchttpclient/CustomRemoteAddressTest.java +++ b/client/src/test/java/org/asynchttpclient/CustomRemoteAddressTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.util.internal.SocketUtils; import org.asynchttpclient.test.TestUtils.AsyncCompletionHandlerAdapter; import org.asynchttpclient.testserver.HttpServer; import org.asynchttpclient.testserver.HttpTest; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static java.util.concurrent.TimeUnit.SECONDS; import static org.asynchttpclient.Dsl.get; @@ -43,7 +43,7 @@ public void stop() throws Throwable { server.close(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void getRootUrlWithCustomRemoteAddress() throws Throwable { withClient().run(client -> withServer(server).run(server -> { diff --git a/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java b/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java index 2e7ea386b9..3fd73a1ba8 100644 --- a/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java +++ b/client/src/test/java/org/asynchttpclient/DefaultAsyncHttpClientTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.channel.DefaultEventLoopGroup; import io.netty.channel.EventLoopGroup; import io.netty.channel.MultiThreadIoEventLoopGroup; @@ -34,6 +33,7 @@ import org.asynchttpclient.cookie.CookieStore; import org.asynchttpclient.cookie.ThreadSafeCookieStore; import org.asynchttpclient.testserver.HttpServer; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.api.condition.OS; @@ -59,7 +59,7 @@ public class DefaultAsyncHttpClientTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testNativeTransportWithEpollOnly() throws Exception { AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(true) @@ -67,7 +67,7 @@ public void testNativeTransportWithEpollOnly() throws Exception { assertRequestSucceedsAndEventLoopGroupIs(config, EpollEventLoopGroup.class); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testNativeTransportWithoutEpollOnly() throws Exception { AsyncHttpClientConfig config = config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(false) @@ -75,7 +75,7 @@ public void testNativeTransportWithoutEpollOnly() throws Exception { assertRequestSucceedsAndEventLoopGroupIs(config, MultiThreadIoEventLoopGroup.class); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.MAC) public void testNativeTransportKQueueOnMacOs() throws Exception { AsyncHttpClientConfig config = config().setUseNativeTransport(true) @@ -83,38 +83,38 @@ public void testNativeTransportKQueueOnMacOs() throws Exception { assertRequestSucceedsAndEventLoopGroupIs(config, KQueueEventLoopGroup.class); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExternalNioEventLoopGroup() throws Exception { assertRequestSucceedsWith(new MultiThreadIoEventLoopGroup(1, NioIoHandler.newFactory())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExternalDeprecatedNioEventLoopGroup() throws Exception { assertRequestSucceedsWith(new NioEventLoopGroup(1)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testExternalEpollEventLoopGroup() throws Exception { assumeTrue(Epoll.isAvailable(), "epoll is not available"); assertRequestSucceedsWith(new MultiThreadIoEventLoopGroup(1, EpollIoHandler.newFactory())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testExternalIoUringEventLoopGroup() throws Exception { assumeTrue(IoUring.isAvailable(), "io_uring is not available"); assertRequestSucceedsWith(new MultiThreadIoEventLoopGroup(1, IoUringIoHandler.newFactory())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.MAC) public void testExternalKQueueEventLoopGroup() throws Exception { assumeTrue(KQueue.isAvailable(), "kqueue is not available"); assertRequestSucceedsWith(new MultiThreadIoEventLoopGroup(1, KQueueIoHandler.newFactory())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExternalEventLoopGroupOfUnknownTransportIsRejected() throws Exception { EventLoopGroup eventLoopGroup = new DefaultEventLoopGroup(1); try { @@ -149,7 +149,7 @@ private static void assertRequestSucceedsAndEventLoopGroupIs(AsyncHttpClientConf } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testNativeTransportFallsBackToNioWhenNativeUnavailable() throws IOException { // Requesting native transport must never fail client construction: when no native transport is @@ -169,7 +169,7 @@ public void testNativeTransportFallsBackToNioWhenNativeUnavailable() throws IOEx } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @EnabledOnOs(OS.LINUX) public void testAutoSelectsNativeTransportByDefaultWhenAvailable() throws IOException { AsyncHttpClientConfig config = config().build(); @@ -184,17 +184,17 @@ public void testAutoSelectsNativeTransportByDefaultWhenAvailable() throws IOExce } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUseOnlyEpollNativeTransportButNativeTransportIsDisabled() { assertThrows(IllegalArgumentException.class, () -> config().setUseNativeTransport(false).setUseOnlyEpollNativeTransport(true).build()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUseOnlyEpollNativeTransportAndNativeTransportIsEnabled() { assertDoesNotThrow(() -> config().setUseNativeTransport(true).setUseOnlyEpollNativeTransport(true).build()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWithSharedNettyTimerShouldScheduleCookieEvictionOnlyOnce() throws IOException { Timer nettyTimerMock = mock(Timer.class); CookieStore cookieStore = new ThreadSafeCookieStore(); @@ -208,7 +208,7 @@ public void testWithSharedNettyTimerShouldScheduleCookieEvictionOnlyOnce() throw } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWitDefaultConfigShouldScheduleCookieEvictionForEachAHC() throws IOException { AsyncHttpClientConfig config1 = config().build(); try (AsyncHttpClient client1 = asyncHttpClient(config1)) { @@ -220,7 +220,7 @@ public void testWitDefaultConfigShouldScheduleCookieEvictionForEachAHC() throws } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWithSharedCookieStoreButNonSharedTimerShouldScheduleCookieEvictionForFirstAHC() throws IOException { CookieStore cookieStore = new ThreadSafeCookieStore(); Timer nettyTimerMock1 = mock(Timer.class); @@ -248,7 +248,7 @@ public void testWithSharedCookieStoreButNonSharedTimerShouldScheduleCookieEvicti } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWithSharedCookieStoreButNonSharedTimerShouldReScheduleCookieEvictionWhenFirstInstanceGetClosed() throws IOException { CookieStore cookieStore = new ThreadSafeCookieStore(); Timer nettyTimerMock1 = mock(Timer.class); @@ -272,7 +272,7 @@ public void testWithSharedCookieStoreButNonSharedTimerShouldReScheduleCookieEvic } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDisablingCookieStore() throws IOException { AsyncHttpClientConfig config = config() .setCookieStore(null).build(); diff --git a/client/src/test/java/org/asynchttpclient/DigestAuthRfc7616Test.java b/client/src/test/java/org/asynchttpclient/DigestAuthRfc7616Test.java index bba50b5a3c..d92721ebeb 100644 --- a/client/src/test/java/org/asynchttpclient/DigestAuthRfc7616Test.java +++ b/client/src/test/java/org/asynchttpclient/DigestAuthRfc7616Test.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -24,7 +23,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Map; @@ -53,13 +54,19 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override public AbstractHandler configureHandler() throws Exception { return new StaleNonceHandler(); } // Phase 2: Stale nonce handling - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void staleNonceRetry() throws Exception { server.stop(); server = new Server(); @@ -80,7 +87,7 @@ public void staleNonceRetry() throws Exception { } // Phase 5: Multiple challenges - select best algorithm - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleChallengesSelectsBest() throws Exception { server.stop(); server = new Server(); @@ -103,7 +110,7 @@ public void multipleChallengesSelectsBest() throws Exception { } // Phase 7: Authentication-Info with nextnonce - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void authenticationInfoNextnonce() throws Exception { server.stop(); server = new Server(); diff --git a/client/src/test/java/org/asynchttpclient/DigestAuthTest.java b/client/src/test/java/org/asynchttpclient/DigestAuthTest.java index 8bdf56c68c..2e770030ee 100644 --- a/client/src/test/java/org/asynchttpclient/DigestAuthTest.java +++ b/client/src/test/java/org/asynchttpclient/DigestAuthTest.java @@ -11,7 +11,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -20,7 +19,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Map; @@ -57,12 +58,18 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override public AbstractHandler configureHandler() throws Exception { return new SimpleHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -75,7 +82,7 @@ public void digestAuthTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthTestWithoutScheme() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -88,7 +95,7 @@ public void digestAuthTestWithoutScheme() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthNegativeTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -100,7 +107,7 @@ public void digestAuthNegativeTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthSha256Test() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -116,7 +123,7 @@ public void digestAuthSha256Test() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void digestAuthSha512_256Test() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') diff --git a/client/src/test/java/org/asynchttpclient/DigestMutualAuthTest.java b/client/src/test/java/org/asynchttpclient/DigestMutualAuthTest.java index 57b7814f0a..dc5e694b6f 100644 --- a/client/src/test/java/org/asynchttpclient/DigestMutualAuthTest.java +++ b/client/src/test/java/org/asynchttpclient/DigestMutualAuthTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -25,7 +24,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -64,12 +65,18 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override public AbstractHandler configureHandler() throws Exception { return new RspAuthHandler(false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void validRspAuthIsAccepted() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -89,7 +96,7 @@ public void validRspAuthIsAccepted() throws Exception { * that realm is computed over the wrong {@code uri} and cannot match what the server signed. Verification * has to use the parameters actually sent. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void validRspAuthIsAcceptedAcrossSameOriginRedirect() throws Exception { restartServer(new RedirectingRspAuthHandler()); @@ -113,7 +120,7 @@ public void validRspAuthIsAcceptedAcrossSameOriginRedirect() throws Exception { * {@code uri} at all and an expected rspauth derived from it hashes {@code H(":")}. An honest server must * not be rejected for that. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void preemptiveDigestIsNotSpuriouslyRejected() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -132,7 +139,7 @@ public void preemptiveDigestIsNotSpuriouslyRejected() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void invalidRspAuthIsRejected() throws Exception { // Server completes the digest handshake but returns an rspauth it could not have computed without the // shared secret. RFC 7616 §3.5 requires the client to consider the exchange unsuccessful. @@ -163,7 +170,7 @@ public void invalidRspAuthIsRejected() throws Exception { * longer be authenticated against. {@code auth,auth-int} is unaffected, because auth is preferred and * its rspauth is verified. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void anAuthIntOnlyChallengeIsNotAnsweredWithAuthInt() throws Exception { restartServer(new AuthIntRspAuthHandler()); @@ -188,7 +195,7 @@ public void anAuthIntOnlyChallengeIsNotAnsweredWithAuthInt() throws Exception { * stripped case-sensitively, so it reached the digest pool intact, threw, and was reported as "cannot * verify" — a one-word opt-out of mutual authentication that any server could take. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void invalidRspAuthIsRejectedWhateverTheSpellingOfTheAlgorithm() throws Exception { for (String spelling : new String[]{"MD5-SESS", "MD5-Sess", "MD5-sess", "SHA-256-SESS"}) { restartServer(new SessRspAuthHandler(spelling, true)); @@ -211,7 +218,7 @@ public void invalidRspAuthIsRejectedWhateverTheSpellingOfTheAlgorithm() throws E * session-variant server must still be accepted, so the spellings above are genuinely being verified * rather than uniformly rejected. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void validSessionVariantRspAuthIsAccepted() throws Exception { for (String spelling : new String[]{"MD5-SESS", "MD5-sess", "SHA-256-SESS"}) { restartServer(new SessRspAuthHandler(spelling, false)); diff --git a/client/src/test/java/org/asynchttpclient/EofTerminatedTest.java b/client/src/test/java/org/asynchttpclient/EofTerminatedTest.java index b63412df5f..b3678bdab8 100644 --- a/client/src/test/java/org/asynchttpclient/EofTerminatedTest.java +++ b/client/src/test/java/org/asynchttpclient/EofTerminatedTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaderValues; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -23,6 +22,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; @@ -45,7 +45,7 @@ public AbstractHandler configureHandler() throws Exception { return gzipHandler; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testEolTerminatedResponse() throws Exception { try (AsyncHttpClient ahc = asyncHttpClient(config().setMaxRequestRetry(0))) { ahc.executeRequest(ahc.prepareGet(getTargetUrl()).setHeader(ACCEPT_ENCODING, HttpHeaderValues.GZIP_DEFLATE).setHeader(CONNECTION, HttpHeaderValues.CLOSE).build()) diff --git a/client/src/test/java/org/asynchttpclient/ErrorResponseTest.java b/client/src/test/java/org/asynchttpclient/ErrorResponseTest.java index 59b6a07c0a..219ffd0f26 100644 --- a/client/src/test/java/org/asynchttpclient/ErrorResponseTest.java +++ b/client/src/test/java/org/asynchttpclient/ErrorResponseTest.java @@ -16,12 +16,12 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.OutputStream; @@ -46,7 +46,7 @@ public AbstractHandler configureHandler() throws Exception { return new ErrorHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryParameters() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + "/foo").addHeader("Accepts", "*/*").execute(); diff --git a/client/src/test/java/org/asynchttpclient/Expect100ContinueTest.java b/client/src/test/java/org/asynchttpclient/Expect100ContinueTest.java index f604feeeb8..45d439a5c3 100644 --- a/client/src/test/java/org/asynchttpclient/Expect100ContinueTest.java +++ b/client/src/test/java/org/asynchttpclient/Expect100ContinueTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaderValues; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Future; @@ -43,7 +43,7 @@ public AbstractHandler configureHandler() throws Exception { return new ZeroCopyHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void Expect100Continue() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePut("http://localhost:" + port1 + '/') diff --git a/client/src/test/java/org/asynchttpclient/FollowingThreadTest.java b/client/src/test/java/org/asynchttpclient/FollowingThreadTest.java index 9b742db4fe..752c143435 100644 --- a/client/src/test/java/org/asynchttpclient/FollowingThreadTest.java +++ b/client/src/test/java/org/asynchttpclient/FollowingThreadTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.io.IOException; @@ -40,7 +40,7 @@ public class FollowingThreadTest extends AbstractBasicTest { private static final int COUNT = 10; - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 30 * 1000) public void testFollowRedirect() throws InterruptedException { diff --git a/client/src/test/java/org/asynchttpclient/Head302Test.java b/client/src/test/java/org/asynchttpclient/Head302Test.java index 7a81dad762..7859ca2320 100644 --- a/client/src/test/java/org/asynchttpclient/Head302Test.java +++ b/client/src/test/java/org/asynchttpclient/Head302Test.java @@ -15,11 +15,11 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -42,7 +42,7 @@ public AbstractHandler configureHandler() throws Exception { return new Head302handler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHEAD302() throws Exception { AsyncHttpClientConfig clientConfig = new DefaultAsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); try (AsyncHttpClient client = asyncHttpClient(clientConfig)) { diff --git a/client/src/test/java/org/asynchttpclient/HttpToHttpsRedirectTest.java b/client/src/test/java/org/asynchttpclient/HttpToHttpsRedirectTest.java index 5795165343..862e953f3f 100644 --- a/client/src/test/java/org/asynchttpclient/HttpToHttpsRedirectTest.java +++ b/client/src/test/java/org/asynchttpclient/HttpToHttpsRedirectTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -23,7 +22,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Enumeration; @@ -55,8 +56,14 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } - @RepeatedIfExceptionsTest(repeats = 5) - // FIXME find a way to make this threadsafe, other, set @RepeatedIfExceptionsTest(repeats = 5)(singleThreaded = true) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test + // FIXME find a way to make this threadsafe public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { httpToHttpsRedirect(); httpToHttpsProperConfig(); @@ -64,7 +71,7 @@ public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { } // @Disabled - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void httpToHttpsRedirect() throws Exception { redirectDone.getAndSet(false); @@ -81,7 +88,7 @@ public void httpToHttpsRedirect() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void httpToHttpsProperConfig() throws Exception { redirectDone.getAndSet(false); @@ -104,7 +111,7 @@ public void httpToHttpsProperConfig() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void relativeLocationUrl() throws Exception { redirectDone.getAndSet(false); diff --git a/client/src/test/java/org/asynchttpclient/IdleStateHandlerTest.java b/client/src/test/java/org/asynchttpclient/IdleStateHandlerTest.java index f229ca5abe..bb10bf1cc6 100644 --- a/client/src/test/java/org/asynchttpclient/IdleStateHandlerTest.java +++ b/client/src/test/java/org/asynchttpclient/IdleStateHandlerTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -23,7 +22,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -47,7 +48,13 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test public void idleStateTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setPooledConnectionIdleTimeout(Duration.ofSeconds(10)))) { c.prepareGet(getTargetUrl()).execute().get(); diff --git a/client/src/test/java/org/asynchttpclient/ListenableFutureTest.java b/client/src/test/java/org/asynchttpclient/ListenableFutureTest.java index fb51bf551b..430dd4b0b3 100644 --- a/client/src/test/java/org/asynchttpclient/ListenableFutureTest.java +++ b/client/src/test/java/org/asynchttpclient/ListenableFutureTest.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -25,7 +25,7 @@ public class ListenableFutureTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testListenableFuture() throws Exception { final AtomicInteger statusCode = new AtomicInteger(500); try (AsyncHttpClient ahc = asyncHttpClient()) { @@ -45,7 +45,7 @@ public void testListenableFuture() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testListenableFutureAfterCompletion() throws Exception { final CountDownLatch latch = new CountDownLatch(1); @@ -59,7 +59,7 @@ public void testListenableFutureAfterCompletion() throws Exception { latch.await(10, TimeUnit.SECONDS); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testListenableFutureBeforeAndAfterCompletion() throws Exception { final CountDownLatch latch = new CountDownLatch(2); diff --git a/client/src/test/java/org/asynchttpclient/MultipleHeaderTest.java b/client/src/test/java/org/asynchttpclient/MultipleHeaderTest.java index 6414f6e4f5..e5c90003fc 100644 --- a/client/src/test/java/org/asynchttpclient/MultipleHeaderTest.java +++ b/client/src/test/java/org/asynchttpclient/MultipleHeaderTest.java @@ -12,11 +12,11 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import javax.net.ServerSocketFactory; import java.io.BufferedReader; @@ -88,7 +88,7 @@ public void tearDownGlobal() throws Exception { serverSocket.close(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMultipleOtherHeaders() throws Exception { final String[] xffHeaders = {null, null}; @@ -142,7 +142,7 @@ public Void onCompleted() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMultipleEntityHeaders() throws Exception { final String[] clHeaders = {null, null}; diff --git a/client/src/test/java/org/asynchttpclient/NonAsciiContentLengthTest.java b/client/src/test/java/org/asynchttpclient/NonAsciiContentLengthTest.java index 0d2aa562ce..4ad426b1bd 100644 --- a/client/src/test/java/org/asynchttpclient/NonAsciiContentLengthTest.java +++ b/client/src/test/java/org/asynchttpclient/NonAsciiContentLengthTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletInputStream; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; @@ -21,7 +20,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -65,7 +66,13 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques port1 = connector.getLocalPort(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test public void testNonAsciiContentLength() throws Exception { execute("test"); execute("\u4E00"); // Unicode CJK ideograph for one diff --git a/client/src/test/java/org/asynchttpclient/ParamEncodingTest.java b/client/src/test/java/org/asynchttpclient/ParamEncodingTest.java index dcd27d46de..b8ff7d0d19 100644 --- a/client/src/test/java/org/asynchttpclient/ParamEncodingTest.java +++ b/client/src/test/java/org/asynchttpclient/ParamEncodingTest.java @@ -15,12 +15,12 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Future; @@ -33,7 +33,7 @@ public class ParamEncodingTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testParameters() throws Exception { String value = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKQLMNOPQRSTUVWXYZ1234567809`~!@#$%^&*()_+-=,.<>/?;:'\"[]{}\\| "; diff --git a/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java b/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java index f8541833b5..9b4118b25b 100644 --- a/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java +++ b/client/src/test/java/org/asynchttpclient/PerRequestRelative302Test.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -24,7 +23,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.ConnectException; @@ -72,7 +73,13 @@ public void setUpGlobal() throws Exception { port2 = findFreePort(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test // FIXME threadsafe public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { redirected302Test(); @@ -81,7 +88,7 @@ public void runAllSequentiallyBecauseNotThreadSafe() throws Exception { redirected302InvalidTest(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirected302Test() throws Exception { isSet.getAndSet(false); try (AsyncHttpClient c = asyncHttpClient()) { @@ -97,7 +104,7 @@ public void redirected302Test() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void notRedirected302Test() throws Exception { isSet.getAndSet(false); try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { @@ -117,7 +124,7 @@ private static String getBaseUrl(Uri uri) { return url.substring(0, url.lastIndexOf(':') + String.valueOf(port).length() + 1); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirected302InvalidTest() throws Exception { isSet.getAndSet(false); Exception e = null; @@ -134,7 +141,7 @@ public void redirected302InvalidTest() throws Exception { assertTrue(cause.getMessage().contains(":" + port2)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void relativeLocationUrl() throws Exception { isSet.getAndSet(false); diff --git a/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java b/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java index bee7d0b676..becd9fc6a7 100644 --- a/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java +++ b/client/src/test/java/org/asynchttpclient/PerRequestTimeoutTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.AsyncContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -63,7 +63,7 @@ public AbstractHandler configureHandler() throws Exception { return new SlowHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRequestTimeout() throws IOException { try (AsyncHttpClient client = asyncHttpClient()) { Future responseFuture = client.prepareGet(getTargetUrl()) @@ -81,7 +81,7 @@ public void testRequestTimeout() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testReadTimeout() throws IOException { try (AsyncHttpClient client = asyncHttpClient(config().setReadTimeout(Duration.ofMillis(100)))) { Future responseFuture = client.prepareGet(getTargetUrl()).execute(); @@ -97,7 +97,7 @@ public void testReadTimeout() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofMillis(100)))) { Future responseFuture = client.prepareGet(getTargetUrl()) @@ -113,7 +113,7 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGlobalRequestTimeout() throws IOException { try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofMillis(100)))) { Future responseFuture = client.prepareGet(getTargetUrl()).execute(); @@ -129,7 +129,7 @@ public void testGlobalRequestTimeout() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGlobalIdleTimeout() throws IOException { final long[] times = {-1, -1}; diff --git a/client/src/test/java/org/asynchttpclient/PostRedirectGetTest.java b/client/src/test/java/org/asynchttpclient/PostRedirectGetTest.java index ae752760b8..909fe2c99f 100644 --- a/client/src/test/java/org/asynchttpclient/PostRedirectGetTest.java +++ b/client/src/test/java/org/asynchttpclient/PostRedirectGetTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.filter.FilterContext; import org.asynchttpclient.filter.ResponseFilter; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Future; @@ -40,27 +40,27 @@ public AbstractHandler configureHandler() throws Exception { return new PostRedirectGetHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postRedirectGet302Test() throws Exception { doTestPositive(302); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postRedirectGet302StrictTest() throws Exception { doTestNegative(302, true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postRedirectGet303Test() throws Exception { doTestPositive(303); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postRedirectGet301Test() throws Exception { doTestPositive(301); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postRedirectGet307Test() throws Exception { doTestNegative(307, false); } diff --git a/client/src/test/java/org/asynchttpclient/PostWithQueryStringTest.java b/client/src/test/java/org/asynchttpclient/PostWithQueryStringTest.java index a78ef4a848..9c122cffa5 100644 --- a/client/src/test/java/org/asynchttpclient/PostWithQueryStringTest.java +++ b/client/src/test/java/org/asynchttpclient/PostWithQueryStringTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.ServletInputStream; import jakarta.servlet.ServletOutputStream; @@ -23,6 +22,7 @@ import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Future; @@ -40,7 +40,7 @@ */ public class PostWithQueryStringTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postWithQueryString() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePost("http://localhost:" + port1 + "/?a=b").setBody("abc".getBytes()).execute(); @@ -50,7 +50,7 @@ public void postWithQueryString() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postWithNullQueryParam() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePost("http://localhost:" + port1 + "/?a=b&c&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { @@ -70,7 +70,7 @@ public State onStatusReceived(final HttpResponseStatus status) throws Exception } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void postWithEmptyParamsQueryString() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePost("http://localhost:" + port1 + "/?a=b&c=&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { diff --git a/client/src/test/java/org/asynchttpclient/QueryParametersTest.java b/client/src/test/java/org/asynchttpclient/QueryParametersTest.java index fd71cc1b95..4f9a7458b8 100644 --- a/client/src/test/java/org/asynchttpclient/QueryParametersTest.java +++ b/client/src/test/java/org/asynchttpclient/QueryParametersTest.java @@ -15,12 +15,12 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.URLDecoder; @@ -46,7 +46,7 @@ public AbstractHandler configureHandler() throws Exception { return new QueryStringHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryParameters() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1).addQueryParam("a", "1").addQueryParam("b", "2").execute(); @@ -58,7 +58,7 @@ public void testQueryParameters() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUrlRequestParametersEncoding() throws Exception { String URL = getTargetUrl() + "?q="; String REQUEST_PARAM = "github github \ngithub"; @@ -72,7 +72,7 @@ public void testUrlRequestParametersEncoding() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void urlWithColonTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { String query = "test:colon:"; diff --git a/client/src/test/java/org/asynchttpclient/RC1KTest.java b/client/src/test/java/org/asynchttpclient/RC1KTest.java index 36f9bf1b91..83fd7f05d1 100644 --- a/client/src/test/java/org/asynchttpclient/RC1KTest.java +++ b/client/src/test/java/org/asynchttpclient/RC1KTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -25,6 +24,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.io.IOException; @@ -59,6 +59,8 @@ public void setUpGlobal() throws Exception { for (int i = 0; i < SRV_COUNT; i++) { Server server = new Server(); ServerConnector connector = addHttpConnector(server); + // The default backlog of 50 overflows under this burst, and Windows then refuses connections. + connector.setAcceptQueueSize(C1K); server.setHandler(configureHandler()); server.start(); servers[i] = server; @@ -91,7 +93,7 @@ public void handle(String s, Request r, HttpServletRequest req, HttpServletRespo }; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 10 * 60 * 1000) public void rc10kProblem() throws Exception { try (AsyncHttpClient ahc = asyncHttpClient(config().setMaxConnectionsPerHost(C1K).setKeepAlive(true))) { diff --git a/client/src/test/java/org/asynchttpclient/RealmTest.java b/client/src/test/java/org/asynchttpclient/RealmTest.java index c564b31d2d..590def0a8c 100644 --- a/client/src/test/java/org/asynchttpclient/RealmTest.java +++ b/client/src/test/java/org/asynchttpclient/RealmTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.uri.Uri; import org.asynchttpclient.util.StringUtils; import org.junit.jupiter.api.Test; @@ -31,7 +30,7 @@ public class RealmTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testClone() { Realm orig = basicAuthRealm("user", "pass").setCharset(UTF_16) .setUsePreemptiveAuth(true) @@ -48,12 +47,12 @@ public void testClone() { assertEquals(clone.getScheme(), orig.getScheme()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOldDigestEmptyString() throws Exception { testOldDigest(""); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOldDigestNull() throws Exception { testOldDigest(null); } @@ -80,7 +79,7 @@ private void testOldDigest(String qop) throws Exception { assertEquals(orig.getResponse(), expectedResponse); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testStrongDigest() throws Exception { String user = "user"; String pass = "pass"; @@ -106,7 +105,7 @@ public void testStrongDigest() throws Exception { assertEquals(orig.getResponse(), expectedResponse); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAuthIntDigestKeepsMethodAndUriInA2() throws Exception { String user = "user"; String pass = "pass"; diff --git a/client/src/test/java/org/asynchttpclient/RedirectBodyTest.java b/client/src/test/java/org/asynchttpclient/RedirectBodyTest.java index 07c1d26417..9855c4e1db 100644 --- a/client/src/test/java/org/asynchttpclient/RedirectBodyTest.java +++ b/client/src/test/java/org/asynchttpclient/RedirectBodyTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import jakarta.servlet.http.HttpServletRequest; @@ -30,6 +29,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; @@ -46,7 +46,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import static java.nio.charset.StandardCharsets.UTF_8; import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION; @@ -63,6 +65,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -146,7 +149,7 @@ public void handle(String pathInContext, Request request, HttpServletRequest htt }; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular301LosesBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -159,7 +162,7 @@ public void regular301LosesBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular302LosesBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -172,7 +175,7 @@ public void regular302LosesBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular302StrictKeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true).setStrict302Handling(true))) { String body = "hello there"; @@ -185,7 +188,7 @@ public void regular302StrictKeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular303SwitchesToGetAndLosesBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -198,7 +201,7 @@ public void regular303SwitchesToGetAndLosesBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular307KeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -211,7 +214,7 @@ public void regular307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void regular308KeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -224,22 +227,22 @@ public void regular308KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query301KeepsMethodAndBody() throws Exception { queryRedirectKeepsMethodAndBody(301, false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query302KeepsMethodAndBody() throws Exception { queryRedirectKeepsMethodAndBody(302, false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query302StrictKeepsMethodAndBody() throws Exception { queryRedirectKeepsMethodAndBody(302, true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query303SwitchesToGetAndDropsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -257,17 +260,17 @@ public void query303SwitchesToGetAndDropsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query307KeepsMethodAndBody() throws Exception { queryRedirectKeepsMethodAndBody(307, false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query308KeepsMethodAndBody() throws Exception { queryRedirectKeepsMethodAndBody(308, false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query301KeepsRepeatableBodyGenerator() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { byte[] body = "hello there".getBytes(UTF_8); @@ -285,7 +288,7 @@ public void query301KeepsRepeatableBodyGenerator() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void query301WithNonRepeatableBodyGeneratorFailsPromptly() throws Exception { try (InputStream body = new FilterInputStream(new ByteArrayInputStream(REDIRECT_BODY)) { @Override @@ -311,7 +314,7 @@ public synchronized void reset() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void put301WithNonRepeatableBodyGeneratorFailsPromptly() throws Exception { try (InputStream body = new FilterInputStream(new ByteArrayInputStream(REDIRECT_BODY)) { @Override @@ -419,7 +422,7 @@ public void nonPost301And302KeepMethodAndBody(String method, int statusCode) thr } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void put301AcrossDifferentHostsKeepsMethodAndBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { String body = "hello there"; @@ -462,7 +465,7 @@ public void callerAddedRedirectStatusKeepsMethodAndBody(String method) throws Ex } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirectPreservesPerRequestSettings() throws Exception { Duration readTimeout = Duration.ofSeconds(7); long rangeOffset = 41L; @@ -492,7 +495,7 @@ public FilterContext filter(FilterContext ctx) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void bodylessRedirectPreservesPerRequestSettings() throws Exception { Duration readTimeout = Duration.ofSeconds(7); long rangeOffset = 41L; @@ -522,7 +525,7 @@ public FilterContext filter(FilterContext ctx) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void compositeByteArray307KeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { byte[] first = "redirect ".getBytes(UTF_8); @@ -534,7 +537,7 @@ public void compositeByteArray307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void byteBuf307KeepsBody() throws Exception { ByteBuf body = Unpooled.wrappedBuffer(REDIRECT_BODY); try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { @@ -547,7 +550,7 @@ public void byteBuf307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void resettableInputStream307KeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { Response response = execute307(c.preparePost(getTargetUrl()).setBody(new ByteArrayInputStream(REDIRECT_BODY))); @@ -556,7 +559,7 @@ public void resettableInputStream307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void inputStream307PreservesExplicitContentLength() throws Exception { try (InputStream body = new ByteArrayInputStream(REDIRECT_BODY); AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { @@ -570,7 +573,7 @@ public void inputStream307PreservesExplicitContentLength() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void inputStreamBodyGenerator307PreservesExplicitContentLength() throws Exception { try (InputStream body = new ByteArrayInputStream(REDIRECT_BODY); AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { @@ -584,7 +587,7 @@ public void inputStreamBodyGenerator307PreservesExplicitContentLength() throws E } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nonResettableInputStream307FailsPromptly() throws Exception { try (InputStream body = new FilterInputStream(new ByteArrayInputStream(REDIRECT_BODY)) { @Override @@ -606,7 +609,7 @@ public synchronized void reset() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void fileInputStream307FailsPromptly() throws Exception { Path bodyFile = Files.createTempFile("ahc-redirect-stream-", ".bin"); try { @@ -624,7 +627,7 @@ public void fileInputStream307FailsPromptly() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void file307KeepsBody() throws Exception { Path body = Files.createTempFile("ahc-redirect-body-", ".bin"); try { @@ -639,16 +642,45 @@ public void file307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void vanishedFile307FailsPromptly() throws Exception { Path body = Files.createTempFile("ahc-redirect-vanished-", ".bin"); try { Files.write(body, REDIRECT_BODY); - fileToDeleteBeforeRedirect = body; - try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { - ExecutionException thrown = assertThrows(ExecutionException.class, - () -> execute307(c.preparePost(getTargetUrl()).setBody(body.toFile()))); + // Deleted here, not in the server handler: Windows cannot delete a file the client still has open. + // The 307 only arrives after the whole body was sent, and by then the client has closed the file. + // Not true for /deferred-redirect, nor with TLS or disableZeroCopy. + AtomicBoolean vanished = new AtomicBoolean(); + AtomicReference vanishFailure = new AtomicReference<>(); + ResponseFilter vanisher = new ResponseFilter() { + @Override + public FilterContext filter(FilterContext ctx) { + HttpResponseStatus status = ctx.getResponseStatus(); + if (status != null && status.getStatusCode() == 307) { + try { + if (Files.deleteIfExists(body)) { + vanished.set(true); + } + } catch (IOException e) { + vanishFailure.set(e); + } + } + return ctx; + } + }; + + try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true).addResponseFilter(vanisher))) { + ExecutionException thrown = null; + try { + execute307(c.preparePost(getTargetUrl()).setBody(body.toFile())); + } catch (ExecutionException e) { + thrown = e; + } + assertNull(vanishFailure.get(), "request body file should be deletable once the region is released"); + assertTrue(vanished.get(), "the 307 never reached the response filter"); + assertNotNull(thrown, "the redirect replay should have failed once the body vanished"); + // NettyFileBody rejects a missing file too, so the type and message must be checked. IOException cause = assertInstanceOf(IOException.class, thrown.getCause()); assertEquals("Redirect request body file " + body.toAbsolutePath() + " is not a file or does not exist", cause.getMessage()); @@ -658,7 +690,7 @@ public void vanishedFile307FailsPromptly() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void coexistingFileAndByteArray308UsesByteArray() throws Exception { Path file = Files.createTempFile("ahc-redirect-precedence-", ".bin"); try { @@ -680,7 +712,7 @@ public void coexistingFileAndByteArray308UsesByteArray() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void coexistingMultipartStreamAndByteArray307UsesByteArray() throws Exception { try (InputStream unusedPart = new ByteArrayInputStream("unused part".getBytes(UTF_8)); AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { @@ -693,7 +725,7 @@ public void coexistingMultipartStreamAndByteArray307UsesByteArray() throws Excep } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void formParams307KeepBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { Response response = c.preparePost(getTargetUrl()) @@ -706,7 +738,7 @@ public void formParams307KeepBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipart307KeepsBody() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { Response response = c.preparePost(getTargetUrl()) @@ -719,7 +751,7 @@ public void multipart307KeepsBody() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void inputStreamMultipart307FailsPromptly() throws Exception { Path bodyFile = Files.createTempFile("ahc-redirect-multipart-", ".bin"); try { diff --git a/client/src/test/java/org/asynchttpclient/RedirectConnectionUsageTest.java b/client/src/test/java/org/asynchttpclient/RedirectConnectionUsageTest.java index 01b37b86cd..95605f4077 100644 --- a/client/src/test/java/org/asynchttpclient/RedirectConnectionUsageTest.java +++ b/client/src/test/java/org/asynchttpclient/RedirectConnectionUsageTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -23,7 +22,9 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.OutputStream; @@ -48,8 +49,9 @@ public class RedirectConnectionUsageTest extends AbstractBasicTest { private String baseUrl; private String servletEndpointRedirectUrl; + @Override @BeforeEach - public void setUp() throws Exception { + public void setUpGlobal() throws Exception { server = new Server(); ServerConnector connector = addHttpConnector(server); @@ -65,10 +67,16 @@ public void setUp() throws Exception { servletEndpointRedirectUrl = baseUrl + "/redirect"; } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + /** * Tests that after a redirect the final url in the response reflect the redirect */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetRedirectFinalUrl() throws Exception { AsyncHttpClientConfig config = config() diff --git a/client/src/test/java/org/asynchttpclient/Relative302Test.java b/client/src/test/java/org/asynchttpclient/Relative302Test.java index d88528129a..a52e2f4f7b 100644 --- a/client/src/test/java/org/asynchttpclient/Relative302Test.java +++ b/client/src/test/java/org/asynchttpclient/Relative302Test.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -24,7 +23,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.ConnectException; @@ -70,7 +71,13 @@ public void setUpGlobal() throws Exception { port2 = findFreePort(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test public void testAllSequentiallyBecauseNotThreadSafe() throws Exception { redirected302Test(); redirected302InvalidTest(); @@ -78,7 +85,7 @@ public void testAllSequentiallyBecauseNotThreadSafe() throws Exception { relativePathRedirectTest(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirected302Test() throws Exception { isSet.getAndSet(false); @@ -93,7 +100,7 @@ public void redirected302Test() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void redirected302InvalidTest() throws Exception { isSet.getAndSet(false); @@ -111,7 +118,7 @@ public void redirected302InvalidTest() throws Exception { assertTrue(cause.getMessage().contains(":" + port2)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void absolutePathRedirectTest() throws Exception { isSet.getAndSet(false); @@ -128,7 +135,7 @@ public void absolutePathRedirectTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void relativePathRedirectTest() throws Exception { isSet.getAndSet(false); diff --git a/client/src/test/java/org/asynchttpclient/RequestBuilderTest.java b/client/src/test/java/org/asynchttpclient/RequestBuilderTest.java index 8a3206d082..36dfe5e32a 100644 --- a/client/src/test/java/org/asynchttpclient/RequestBuilderTest.java +++ b/client/src/test/java/org/asynchttpclient/RequestBuilderTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; @@ -43,7 +42,7 @@ public class RequestBuilderTest { private static final String SAFE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-_*."; private static final String HEX_CHARS = "0123456789ABCDEF"; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testEncodesQueryParameters() { String[] values = {"abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKQLMNOPQRSTUVWXYZ", "1234567890", "1234567890", "`~!@#$%^&*()", "`~!@#$%^&*()", "_+-=,.<>/?", "_+-=,.<>/?", ";:'\"[]{}\\| ", ";:'\"[]{}\\| "}; @@ -78,7 +77,7 @@ public void testEncodesQueryParameters() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChaining() { Request request = get("http://foo.com").addQueryParam("x", "value").build(); Request request2 = request.toBuilder().build(); @@ -86,7 +85,7 @@ public void testChaining() { assertEquals(request2.getUri(), request.getUri()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testParsesQueryParams() { Request request = get("http://foo.com/?param1=value1").addQueryParam("param2", "value2").build(); @@ -97,21 +96,21 @@ public void testParsesQueryParams() { assertEquals(params.get(1), new Param("param2", "value2")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUserProvidedRequestMethod() { Request req = new RequestBuilder("ABC").setUrl("http://foo.com").build(); assertEquals(req.getMethod(), "ABC"); assertEquals(req.getUrl(), "http://foo.com"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPercentageEncodedUserInfo() { final Request req = get("http://hello:wor%20ld@foo.com").build(); assertEquals(req.getMethod(), "GET"); assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testContentTypeCharsetToBodyEncoding() { final Request req = get("http://localhost").setHeader("Content-Type", "application/json; charset=utf-8").build(); assertEquals(req.getCharset(), UTF_8); @@ -119,14 +118,14 @@ public void testContentTypeCharsetToBodyEncoding() { assertEquals(req2.getCharset(), UTF_8); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultMethod() { RequestBuilder requestBuilder = new RequestBuilder(); String defaultMethodName = HttpMethod.GET.name(); assertEquals(requestBuilder.method, defaultMethodName, "Default HTTP method should be " + defaultMethodName); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSetHeaders() { RequestBuilder requestBuilder = new RequestBuilder(); assertTrue(requestBuilder.headers.isEmpty(), "Headers should be empty by default."); @@ -138,7 +137,7 @@ public void testSetHeaders() { assertEquals(requestBuilder.headers.get("Content-Type"), "application/json", "header value incorrect"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAddOrReplaceCookies() { RequestBuilder requestBuilder = new RequestBuilder(); Cookie cookie = new DefaultCookie("name", "value"); @@ -172,7 +171,7 @@ public void testAddOrReplaceCookies() { assertEquals(requestBuilder.cookies.size(), 2, "cookie size must be 2 after adding 1 more cookie i.e. cookie3"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAddIfUnsetCookies() { RequestBuilder requestBuilder = new RequestBuilder(); Cookie cookie = new DefaultCookie("name", "value"); @@ -206,7 +205,7 @@ public void testAddIfUnsetCookies() { assertEquals(requestBuilder.cookies.size(), 2, "cookie size must be 2 after adding 1 more cookie i.e. cookie3"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSettingQueryParamsBeforeUrlShouldNotProduceNPE() { RequestBuilder requestBuilder = new RequestBuilder(); requestBuilder.setQueryParams(singletonList(new Param("key", "value"))); @@ -215,7 +214,7 @@ public void testSettingQueryParamsBeforeUrlShouldNotProduceNPE() { assertEquals(request.getUrl(), "http://localhost?key=value"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSettingHeadersUsingMapWithStringKeys() { Map> headers = new HashMap<>(); headers.put("X-Forwarded-For", singletonList("10.0.0.1")); @@ -227,7 +226,7 @@ public void testSettingHeadersUsingMapWithStringKeys() { assertEquals(request.getHeaders().get("X-Forwarded-For"), "10.0.0.1"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUserSetTextPlainContentTypeShouldNotBeModified() { Request request = post("http://localhost/test") .setHeader("Content-Type", "text/plain") @@ -239,7 +238,7 @@ public void testUserSetTextPlainContentTypeShouldNotBeModified() { assertFalse(contentType.contains("charset"), "Charset should not be added to user-specified Content-Type"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUserSetTextXmlContentTypeShouldNotBeModified() { Request request = post("http://localhost/test") .setHeader("Content-Type", "text/xml") @@ -250,7 +249,7 @@ public void testUserSetTextXmlContentTypeShouldNotBeModified() { assertEquals("text/xml", contentType, "Content-Type should not be modified when user explicitly sets it"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUserSetTextHtmlContentTypeShouldNotBeModified() { Request request = post("http://localhost/test") .setHeader("Content-Type", "text/html") @@ -261,7 +260,7 @@ public void testUserSetTextHtmlContentTypeShouldNotBeModified() { assertEquals("text/html", contentType, "Content-Type should not be modified when user explicitly sets it"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUserSetContentTypeWithCharsetShouldBePreserved() { Request request = post("http://localhost/test") .setHeader("Content-Type", "text/xml; charset=ISO-8859-1") @@ -274,7 +273,7 @@ public void testUserSetContentTypeWithCharsetShouldBePreserved() { assertFalse(contentType.contains("UTF-8"), "UTF-8 should not be added"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testApplicationJsonContentTypeShouldNotBeModified() { Request request = post("http://localhost/test") .setHeader("Content-Type", "application/json") @@ -286,7 +285,7 @@ public void testApplicationJsonContentTypeShouldNotBeModified() { assertFalse(contentType.contains("charset"), "Charset should not be added to application/json"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAddHeaderContentTypeShouldNotBeModified() { Request request = post("http://localhost/test") .addHeader("Content-Type", "text/plain") @@ -297,7 +296,7 @@ public void testAddHeaderContentTypeShouldNotBeModified() { assertEquals("text/plain", contentType, "Content-Type set via addHeader should not be modified"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSetHeadersWithHttpHeadersShouldLockContentType() { HttpHeaders httpHeaders = new DefaultHttpHeaders(); httpHeaders.set("Content-Type", "text/plain"); @@ -311,7 +310,7 @@ public void testSetHeadersWithHttpHeadersShouldLockContentType() { assertEquals("text/plain", contentType, "Content-Type set via setHeaders(HttpHeaders) should not be modified"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSetHeadersWithMapShouldLockContentType() { Map> headerMap = new HashMap<>(); headerMap.put("Content-Type", singletonList("text/plain")); @@ -325,7 +324,7 @@ public void testSetHeadersWithMapShouldLockContentType() { assertEquals("text/plain", contentType, "Content-Type set via setHeaders(Map) should not be modified"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSetSingleHeadersShouldLockContentType() { Map headerMap = new HashMap<>(); headerMap.put("Content-Type", "text/plain"); @@ -339,7 +338,7 @@ public void testSetSingleHeadersShouldLockContentType() { assertEquals("text/plain", contentType, "Content-Type set via setSingleHeaders should not be modified"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testClearHeadersShouldResetContentTypeLock() { Request request = post("http://localhost/test") .setHeader("Content-Type", "text/plain") @@ -352,7 +351,7 @@ public void testClearHeadersShouldResetContentTypeLock() { assertEquals("text/xml", contentType, "Content-Type should still be preserved after clear and re-set"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPrototypeRequestShouldPreserveContentType() { Request original = post("http://localhost/test") .setHeader("Content-Type", "text/plain") @@ -369,7 +368,7 @@ public void testPrototypeRequestShouldPreserveContentType() { assertEquals("text/plain", contentType, "Content-Type should be preserved from prototype"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRequestBuilderFromPrototypeShouldPreserveContentType() { Request original = post("http://localhost/test") .setHeader("Content-Type", "text/plain") @@ -382,7 +381,7 @@ public void testRequestBuilderFromPrototypeShouldPreserveContentType() { assertEquals("text/plain", contentType, "Content-Type should be preserved from prototype via RequestBuilder"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCaseInsensitiveContentTypeHeader() { Request request = post("http://localhost/test") .setHeader("content-type", "text/plain") @@ -393,7 +392,7 @@ public void testCaseInsensitiveContentTypeHeader() { assertEquals("text/plain", contentType, "Content-Type should be matched case-insensitively"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSetHeaderWithIterableShouldLockContentType() { Request request = post("http://localhost/test") .setHeader("Content-Type", singletonList("text/plain")) @@ -404,7 +403,7 @@ public void testSetHeaderWithIterableShouldLockContentType() { assertEquals("text/plain", contentType, "Content-Type set via setHeader(Iterable) should not be modified"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAddHeaderWithIterableShouldLockContentType() { Request request = post("http://localhost/test") .addHeader("Content-Type", singletonList("text/plain")) diff --git a/client/src/test/java/org/asynchttpclient/RetryRequestTest.java b/client/src/test/java/org/asynchttpclient/RetryRequestTest.java index 07e9f2ca86..b9c589537e 100644 --- a/client/src/test/java/org/asynchttpclient/RetryRequestTest.java +++ b/client/src/test/java/org/asynchttpclient/RetryRequestTest.java @@ -12,13 +12,13 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.exception.RemotelyClosedException; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.OutputStream; @@ -40,7 +40,7 @@ public AbstractHandler configureHandler() throws Exception { return new SlowAndBigHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMaxRetry() { try (AsyncHttpClient ahc = asyncHttpClient(config().setMaxRequestRetry(0))) { ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build()).get(); diff --git a/client/src/test/java/org/asynchttpclient/ScramAuthTest.java b/client/src/test/java/org/asynchttpclient/ScramAuthTest.java index 8e4c60afcd..002e778ab4 100644 --- a/client/src/test/java/org/asynchttpclient/ScramAuthTest.java +++ b/client/src/test/java/org/asynchttpclient/ScramAuthTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.scram.ScramEngine; @@ -24,7 +23,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -60,12 +61,18 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override public AbstractHandler configureHandler() throws Exception { return new ScramAuthHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_fullExchange() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -78,7 +85,7 @@ public void testScramSha256_fullExchange() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_wrongPassword() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -90,7 +97,7 @@ public void testScramSha256_wrongPassword() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_maxIterationCount() throws Exception { // Server uses 4096 iterations, client max is 100 — should fail try (AsyncHttpClient client = asyncHttpClient()) { @@ -107,7 +114,7 @@ public void testScramSha256_maxIterationCount() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_missingAuthInfo() throws Exception { // Test with handler that doesn't send Authentication-Info server.stop(); @@ -128,7 +135,7 @@ public void testScramSha256_missingAuthInfo() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_malformedBase64InData() throws Exception { server.stop(); server = new Server(); @@ -148,7 +155,7 @@ public void testScramSha256_malformedBase64InData() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_invalidServerSignatureIsRejected() throws Exception { // Server completes the handshake but returns a ServerSignature it could not have computed without // the shared secret. RFC 7804 §5 requires the client to consider the exchange unsuccessful. @@ -169,7 +176,7 @@ public void testScramSha256_invalidServerSignatureIsRejected() throws Exception } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_quotedDataAttribute() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.prepareGet("http://localhost:" + port1 + '/') @@ -183,7 +190,7 @@ public void testScramSha256_quotedDataAttribute() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testScramSha256_proxyFullExchange() throws Exception { server.stop(); server = new Server(); diff --git a/client/src/test/java/org/asynchttpclient/ThreadNameTest.java b/client/src/test/java/org/asynchttpclient/ThreadNameTest.java index a6a151aa99..b17cd9e0b6 100644 --- a/client/src/test/java/org/asynchttpclient/ThreadNameTest.java +++ b/client/src/test/java/org/asynchttpclient/ThreadNameTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.util.Arrays; import java.util.Random; @@ -46,7 +46,7 @@ private static Thread[] getThreads() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testThreadName() throws Exception { String threadPoolName = "ahc-" + (new Random().nextLong() & 0x7fffffffffffffffL); try (AsyncHttpClient client = asyncHttpClient(config().setThreadPoolName(threadPoolName))) { diff --git a/client/src/test/java/org/asynchttpclient/channel/ConnectionPoolTest.java b/client/src/test/java/org/asynchttpclient/channel/ConnectionPoolTest.java index 878a047d14..89cc5b4c29 100644 --- a/client/src/test/java/org/asynchttpclient/channel/ConnectionPoolTest.java +++ b/client/src/test/java/org/asynchttpclient/channel/ConnectionPoolTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.channel; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncCompletionHandlerBase; @@ -26,6 +25,7 @@ import org.asynchttpclient.test.EventCollectingHandler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.ThrowingSupplier; import java.time.Duration; @@ -61,7 +61,7 @@ public class ConnectionPoolTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMaxTotalConnections() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setKeepAlive(true).setMaxConnections(1))) { String url = getTargetUrl(); @@ -82,7 +82,7 @@ public Response get() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMaxTotalConnectionsException() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setKeepAlive(true).setMaxConnections(1))) { String url = getTargetUrl(); @@ -108,7 +108,7 @@ public void testMaxTotalConnectionsException() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void asyncDoGetKeepAliveHandlerTest_channelClosedDoesNotFail() throws Exception { for (int i = 0; i < 10; i++) { try (AsyncHttpClient client = asyncHttpClient()) { @@ -162,7 +162,7 @@ public void onThrowable(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleMaxConnectionOpenTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setKeepAlive(true).setConnectTimeout(Duration.ofSeconds(5)).setMaxConnections(1))) { String body = "hello there"; @@ -179,7 +179,7 @@ public void multipleMaxConnectionOpenTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void multipleMaxConnectionOpenTestWithQuery() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setKeepAlive(true).setConnectTimeout(Duration.ofSeconds(5)).setMaxConnections(1))) { String body = "hello there"; @@ -195,7 +195,7 @@ public void multipleMaxConnectionOpenTestWithQuery() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncHandlerOnThrowableTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final AtomicInteger count = new AtomicInteger(); @@ -229,7 +229,7 @@ public Response onCompleted(Response response) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void nonPoolableConnectionReleaseSemaphoresTest() throws Throwable { RequestBuilder request = get(getTargetUrl()).setHeader("Connection", "close"); @@ -245,7 +245,7 @@ public void nonPoolableConnectionReleaseSemaphoresTest() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPooledEventsFired() throws Exception { RequestBuilder request = get("http://localhost:" + port1 + "/Test"); diff --git a/client/src/test/java/org/asynchttpclient/channel/MaxConnectionsInThreadsTest.java b/client/src/test/java/org/asynchttpclient/channel/MaxConnectionsInThreadsTest.java index d82aa08c41..3fdac9794c 100644 --- a/client/src/test/java/org/asynchttpclient/channel/MaxConnectionsInThreadsTest.java +++ b/client/src/test/java/org/asynchttpclient/channel/MaxConnectionsInThreadsTest.java @@ -16,7 +16,6 @@ */ package org.asynchttpclient.channel; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -29,7 +28,9 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +63,13 @@ public void setUpGlobal() throws Exception { port1 = connector.getLocalPort(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test public void testMaxConnectionsWithinThreads() throws Exception { String[] urls = {getTargetUrl(), getTargetUrl()}; diff --git a/client/src/test/java/org/asynchttpclient/channel/MaxTotalConnectionTest.java b/client/src/test/java/org/asynchttpclient/channel/MaxTotalConnectionTest.java index 345ce9818f..de40f0594e 100644 --- a/client/src/test/java/org/asynchttpclient/channel/MaxTotalConnectionTest.java +++ b/client/src/test/java/org/asynchttpclient/channel/MaxTotalConnectionTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient.channel; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncCompletionHandlerBase; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.ListenableFuture; import org.asynchttpclient.Response; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -38,7 +38,7 @@ public class MaxTotalConnectionTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMaxTotalConnectionsExceedingException() throws IOException { String[] urls = {getTargetUrl(), String.format("http://localhost:%d/foo/test", port2)}; @@ -74,7 +74,7 @@ public void testMaxTotalConnectionsExceedingException() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMaxTotalConnections() throws Exception { String[] urls = {getTargetUrl(), String.format("http://localhost:%d/foo/test", port2)}; diff --git a/client/src/test/java/org/asynchttpclient/filter/FilterTest.java b/client/src/test/java/org/asynchttpclient/filter/FilterTest.java index fba6c4ec01..a252831e15 100644 --- a/client/src/test/java/org/asynchttpclient/filter/FilterTest.java +++ b/client/src/test/java/org/asynchttpclient/filter/FilterTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.filter; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -21,6 +20,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; @@ -47,7 +47,7 @@ public String getTargetUrl() { return String.format("http://localhost:%d/foo/test", port1); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().addRequestFilter(new ThrottleRequestFilter(100)))) { Response response = c.preparePost(getTargetUrl()).execute().get(); @@ -56,7 +56,7 @@ public void basicTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void loadThrottleTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().addRequestFilter(new ThrottleRequestFilter(10)))) { List> futures = new ArrayList<>(); @@ -72,14 +72,14 @@ public void loadThrottleTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void maxConnectionsText() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().addRequestFilter(new ThrottleRequestFilter(0, 1000)))) { assertThrows(Exception.class, () -> client.preparePost(getTargetUrl()).execute().get()); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicResponseFilterTest() throws Exception { ResponseFilter responseFilter = new ResponseFilter() { @@ -96,7 +96,7 @@ public FilterContext filter(FilterContext ctx) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void replayResponseFilterTest() throws Exception { final AtomicBoolean replay = new AtomicBoolean(true); ResponseFilter responseFilter = new ResponseFilter() { @@ -119,7 +119,7 @@ public FilterContext filter(FilterContext ctx) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void replayStatusCodeResponseFilterTest() throws Exception { final AtomicBoolean replay = new AtomicBoolean(true); ResponseFilter responseFilter = new ResponseFilter() { @@ -142,7 +142,7 @@ public FilterContext filter(FilterContext ctx) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void replayHeaderResponseFilterTest() throws Exception { final AtomicBoolean replay = new AtomicBoolean(true); ResponseFilter responseFilter = new ResponseFilter() { diff --git a/client/src/test/java/org/asynchttpclient/handler/BodyDeferringAsyncHandlerTest.java b/client/src/test/java/org/asynchttpclient/handler/BodyDeferringAsyncHandlerTest.java index 1705dcc636..b7313b5bc0 100644 --- a/client/src/test/java/org/asynchttpclient/handler/BodyDeferringAsyncHandlerTest.java +++ b/client/src/test/java/org/asynchttpclient/handler/BodyDeferringAsyncHandlerTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.handler; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -27,6 +26,7 @@ import org.asynchttpclient.handler.BodyDeferringAsyncHandler.BodyDeferringInputStream; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.OutputStream; @@ -65,7 +65,7 @@ private static AsyncHttpClientConfig getAsyncHttpClientConfig() { return config().setMaxRequestRetry(0).setRequestTimeout(Duration.ofSeconds(10)).build(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void deferredSimple() throws Exception { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()); @@ -91,7 +91,7 @@ public void deferredSimple() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void deferredSimpleWithFailure() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder requestBuilder = client.prepareGet(getTargetUrl()).addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); @@ -118,7 +118,26 @@ public void deferredSimpleWithFailure() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + // Joining the future first guarantees the body failure is recorded before getResponse() is called. + @Test + public void deferredResponseIsReturnedWhenTheBodyFailsFirst() throws Exception { + try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { + BoundRequestBuilder requestBuilder = client.prepareGet(getTargetUrl()).addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); + + CountingOutputStream cos = new CountingOutputStream(); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); + Future f = requestBuilder.execute(bdah); + + assertThrows(ExecutionException.class, f::get); + + Response resp = bdah.getResponse(); + assertNotNull(resp); + assertEquals(HttpServletResponse.SC_OK, resp.getStatusCode()); + assertEquals(String.valueOf(CONTENT_LENGTH_VALUE), resp.getHeader(CONTENT_LENGTH)); + } + } + + @Test public void deferredInputStreamTrick() throws Exception { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()); @@ -151,7 +170,7 @@ public void deferredInputStreamTrick() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void deferredInputStreamTrickWithFailure() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); @@ -178,7 +197,7 @@ public void deferredInputStreamTrickWithFailure() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void deferredInputStreamTrickWithCloseConnectionAndRetry() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(config().setMaxRequestRetry(1).setRequestTimeout(Duration.ofSeconds(10)).build())) { BoundRequestBuilder r = client.prepareGet(getTargetUrl()).addHeader("X-CLOSE-CONNECTION", Boolean.TRUE.toString()); @@ -205,7 +224,7 @@ public void deferredInputStreamTrickWithCloseConnectionAndRetry() throws Throwab } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testConnectionRefused() throws Exception { int newPortWithoutAnyoneListening = findFreePort(); try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { @@ -218,7 +237,7 @@ public void testConnectionRefused() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPipedStreams() throws Exception { try (AsyncHttpClient client = asyncHttpClient(getAsyncHttpClientConfig())) { PipedOutputStream pout = new PipedOutputStream(); diff --git a/client/src/test/java/org/asynchttpclient/handler/resumable/PropertiesBasedResumableProcessorTest.java b/client/src/test/java/org/asynchttpclient/handler/resumable/PropertiesBasedResumableProcessorTest.java index d8c1bd4f29..882cf0d814 100644 --- a/client/src/test/java/org/asynchttpclient/handler/resumable/PropertiesBasedResumableProcessorTest.java +++ b/client/src/test/java/org/asynchttpclient/handler/resumable/PropertiesBasedResumableProcessorTest.java @@ -12,7 +12,7 @@ */ package org.asynchttpclient.handler.resumable; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.util.Map; @@ -23,7 +23,7 @@ */ public class PropertiesBasedResumableProcessorTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSaveLoad() { PropertiesBasedResumableProcessor processor = new PropertiesBasedResumableProcessor(); processor.put("http://localhost/test.url", 15L); @@ -37,7 +37,7 @@ public void testSaveLoad() { assertEquals(Long.valueOf(50L), map.get("http://localhost/test2.url")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRemove() { PropertiesBasedResumableProcessor processor = new PropertiesBasedResumableProcessor(); processor.put("http://localhost/test.url", 15L); diff --git a/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableAsyncHandlerTest.java b/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableAsyncHandlerTest.java index e142587576..ef1874ffc7 100644 --- a/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableAsyncHandlerTest.java +++ b/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableAsyncHandlerTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.handler.resumable; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import org.asynchttpclient.AsyncHandler; @@ -22,6 +21,7 @@ import org.asynchttpclient.Request; import org.asynchttpclient.Response; import org.asynchttpclient.uri.Uri; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.ByteBuffer; @@ -44,7 +44,7 @@ public class ResumableAsyncHandlerTest { public static final byte[] T = new byte[0]; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAdjustRange() { MapResumableProcessor processor = new MapResumableProcessor(); @@ -62,7 +62,7 @@ public void testAdjustRange() { assertEquals("bytes=5000-", rangeHeader); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnStatusReceivedOkStatus() throws Exception { MapResumableProcessor processor = new MapResumableProcessor(); ResumableAsyncHandler handler = new ResumableAsyncHandler(processor); @@ -73,7 +73,7 @@ public void testOnStatusReceivedOkStatus() throws Exception { assertEquals(AsyncHandler.State.CONTINUE, state, "Status should be CONTINUE for a OK response"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnStatusReceived206Status() throws Exception { MapResumableProcessor processor = new MapResumableProcessor(); ResumableAsyncHandler handler = new ResumableAsyncHandler(processor); @@ -84,7 +84,7 @@ public void testOnStatusReceived206Status() throws Exception { assertEquals(AsyncHandler.State.CONTINUE, state, "Status should be CONTINUE for a 'Partial Content' response"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnStatusReceivedOkStatusWithDecoratedAsyncHandler() throws Exception { HttpResponseStatus mockResponseStatus = mock(HttpResponseStatus.class); when(mockResponseStatus.getStatusCode()).thenReturn(200); @@ -101,7 +101,7 @@ public void testOnStatusReceivedOkStatusWithDecoratedAsyncHandler() throws Excep assertEquals(State.CONTINUE, state, "State returned should be equal to the one returned from decoratedAsyncHandler"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnStatusReceived500Status() throws Exception { MapResumableProcessor processor = new MapResumableProcessor(); ResumableAsyncHandler handler = new ResumableAsyncHandler(processor); @@ -112,7 +112,7 @@ public void testOnStatusReceived500Status() throws Exception { assertEquals(AsyncHandler.State.ABORT, state, "State should be ABORT for Internal Server Error status"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnBodyPartReceived() throws Exception { ResumableAsyncHandler handler = new ResumableAsyncHandler(); HttpResponseBodyPart bodyPart = mock(HttpResponseBodyPart.class); @@ -123,7 +123,7 @@ public void testOnBodyPartReceived() throws Exception { assertEquals(AsyncHandler.State.CONTINUE, state, "State should be CONTINUE for a successful onBodyPartReceived"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnBodyPartReceivedWithResumableListenerThrowsException() throws Exception { ResumableAsyncHandler handler = new ResumableAsyncHandler(); @@ -137,7 +137,7 @@ public void testOnBodyPartReceivedWithResumableListenerThrowsException() throws "State should be ABORT if the resumableListener threw an exception in onBodyPartReceived"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnBodyPartReceivedWithDecoratedAsyncHandler() throws Exception { HttpResponseBodyPart bodyPart = mock(HttpResponseBodyPart.class); when(bodyPart.getBodyPartBytes()).thenReturn(new byte[0]); @@ -161,7 +161,7 @@ public void testOnBodyPartReceivedWithDecoratedAsyncHandler() throws Exception { assertEquals(State.CONTINUE, state, "State should be equal to the state returned from decoratedAsyncHandler"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnHeadersReceived() throws Exception { ResumableAsyncHandler handler = new ResumableAsyncHandler(); HttpHeaders responseHeaders = new DefaultHttpHeaders(); @@ -169,7 +169,7 @@ public void testOnHeadersReceived() throws Exception { assertEquals(AsyncHandler.State.CONTINUE, status, "State should be CONTINUE for a successful onHeadersReceived"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnHeadersReceivedWithDecoratedAsyncHandler() throws Exception { HttpHeaders responseHeaders = new DefaultHttpHeaders(); @@ -182,7 +182,7 @@ public void testOnHeadersReceivedWithDecoratedAsyncHandler() throws Exception { assertEquals(State.CONTINUE, status, "State should be equal to the state returned from decoratedAsyncHandler"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnHeadersReceivedContentLengthMinus() throws Exception { ResumableAsyncHandler handler = new ResumableAsyncHandler(); HttpHeaders responseHeaders = new DefaultHttpHeaders(); diff --git a/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableRandomAccessFileListenerTest.java b/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableRandomAccessFileListenerTest.java index b8a176b605..165c32c427 100644 --- a/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableRandomAccessFileListenerTest.java +++ b/client/src/test/java/org/asynchttpclient/handler/resumable/ResumableRandomAccessFileListenerTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.handler.resumable; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.RandomAccessFile; @@ -26,7 +26,7 @@ public class ResumableRandomAccessFileListenerTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnBytesReceivedBufferHasArray() throws IOException { RandomAccessFile file = mock(RandomAccessFile.class); ResumableRandomAccessFileListener listener = new ResumableRandomAccessFileListener(file); @@ -36,7 +36,7 @@ public void testOnBytesReceivedBufferHasArray() throws IOException { verify(file).write(array, 0, 4); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testOnBytesReceivedBufferHasNoArray() throws IOException { RandomAccessFile file = mock(RandomAccessFile.class); ResumableRandomAccessFileListener listener = new ResumableRandomAccessFileListener(file); diff --git a/client/src/test/java/org/asynchttpclient/netty/EventPipelineTest.java b/client/src/test/java/org/asynchttpclient/netty/EventPipelineTest.java index 2a95230368..fb58c67d24 100644 --- a/client/src/test/java/org/asynchttpclient/netty/EventPipelineTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/EventPipelineTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -20,6 +19,7 @@ import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; +import org.junit.jupiter.api.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -33,7 +33,7 @@ public class EventPipelineTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncPipelineTest() throws Exception { Consumer httpAdditionalPipelineInitializer = channel -> channel.pipeline() .addBefore("inflater", "copyEncodingHeader", new CopyEncodingHandler()); diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java index 100900b4b4..fc1f8531f7 100644 --- a/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/NettyAsyncResponseTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultHttpHeaders; @@ -45,7 +44,7 @@ public class NettyAsyncResponseTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCookieParseExpires() { // e.g. "Tue, 27 Oct 2015 12:54:24 GMT"; SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); @@ -64,7 +63,7 @@ public void testCookieParseExpires() { assertTrue(cookie.maxAge() >= 58 && cookie.maxAge() <= 60); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCookieParseMaxAge() { final String cookieDef = "efmembercheck=true; max-age=60; path=/; domain=.eclipse.org"; @@ -77,7 +76,7 @@ public void testCookieParseMaxAge() { assertEquals(60, cookie.maxAge()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCookieParseWeirdExpiresValue() { final String cookieDef = "efmembercheck=true; expires=60; path=/; domain=.eclipse.org"; HttpHeaders responseHeaders = new DefaultHttpHeaders().add(SET_COOKIE, cookieDef); @@ -90,7 +89,7 @@ public void testCookieParseWeirdExpiresValue() { assertEquals(Long.MIN_VALUE, cookie.maxAge()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetResponseBodyAsByteBuffer() { List bodyParts = new LinkedList<>(); bodyParts.add(new LazyResponseBodyPart(Unpooled.wrappedBuffer("Hello ".getBytes()), false)); diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java index 484b074a3c..7568684a1a 100644 --- a/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/NettyConnectionResetByPeerTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import io.github.nettyplus.leakdetector.junit.NettyLeakDetectorExtension; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.DefaultAsyncHttpClient; import org.asynchttpclient.DefaultAsyncHttpClientConfig; import org.asynchttpclient.RequestBuilder; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import java.io.IOException; @@ -46,7 +46,7 @@ public void setUp() { resettingServerAddress = createResettingServer(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAsyncHttpClientConnectionResetByPeer() throws InterruptedException { DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder() .setRequestTimeout(Duration.ofMillis(1500)) diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyRequestThrottleTimeoutTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyRequestThrottleTimeoutTest.java index eade766201..e7d9c842c5 100644 --- a/client/src/test/java/org/asynchttpclient/netty/NettyRequestThrottleTimeoutTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/NettyRequestThrottleTimeoutTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.AsyncContext; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -23,6 +22,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -48,7 +48,7 @@ public AbstractHandler configureHandler() throws Exception { return new SlowHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRequestTimeout() throws IOException { final Semaphore requestThrottle = new Semaphore(1); final int samples = 10; diff --git a/client/src/test/java/org/asynchttpclient/netty/NettyResponseFutureTest.java b/client/src/test/java/org/asynchttpclient/netty/NettyResponseFutureTest.java index 5f4f5b4965..d120ea1e5b 100644 --- a/client/src/test/java/org/asynchttpclient/netty/NettyResponseFutureTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/NettyResponseFutureTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.channel.embedded.EmbeddedChannel; import org.asynchttpclient.AsyncHandler; import org.asynchttpclient.Request; @@ -44,7 +43,7 @@ public class NettyResponseFutureTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCancel() { AsyncHandler asyncHandler = mock(AsyncHandler.class); NettyResponseFuture nettyResponseFuture = new NettyResponseFuture<>(null, asyncHandler, null, 3, null, null, null); @@ -54,7 +53,7 @@ public void testCancel() { assertTrue(nettyResponseFuture.isCancelled(), "isCancelled should return true for a cancelled Future"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCancelOnAlreadyCancelled() { AsyncHandler asyncHandler = mock(AsyncHandler.class); NettyResponseFuture nettyResponseFuture = new NettyResponseFuture<>(null, asyncHandler, null, 3, null, null, null); @@ -64,7 +63,7 @@ public void testCancelOnAlreadyCancelled() { assertTrue(nettyResponseFuture.isCancelled(), "isCancelled should return true for a cancelled Future"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetContentThrowsCancellationExceptionIfCancelled() throws Exception { AsyncHandler asyncHandler = mock(AsyncHandler.class); NettyResponseFuture nettyResponseFuture = new NettyResponseFuture<>(null, asyncHandler, null, 3, null, null, null); @@ -72,7 +71,7 @@ public void testGetContentThrowsCancellationExceptionIfCancelled() throws Except assertThrows(CancellationException.class, () -> nettyResponseFuture.get(), "A CancellationException must have occurred by now as 'cancel' was called before 'get'"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGet() throws Exception { @SuppressWarnings("unchecked") AsyncHandler asyncHandler = mock(AsyncHandler.class); @@ -84,7 +83,7 @@ public void testGet() throws Exception { assertEquals(value, result, "The Future should return the value given by asyncHandler#onCompleted"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetThrowsExceptionThrownByAsyncHandler() throws Exception { AsyncHandler asyncHandler = mock(AsyncHandler.class); when(asyncHandler.onCompleted()).thenThrow(new RuntimeException()); @@ -94,7 +93,7 @@ public void testGetThrowsExceptionThrownByAsyncHandler() throws Exception { "An ExecutionException must have occurred by now as asyncHandler threw an exception in 'onCompleted'"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetThrowsExceptionOnAbort() throws Exception { AsyncHandler asyncHandler = mock(AsyncHandler.class); NettyResponseFuture nettyResponseFuture = new NettyResponseFuture<>(null, asyncHandler, null, 3, null, null, null); diff --git a/client/src/test/java/org/asynchttpclient/netty/RetryNonBlockingIssueTest.java b/client/src/test/java/org/asynchttpclient/netty/RetryNonBlockingIssueTest.java index 60313166a1..1a747af99c 100644 --- a/client/src/test/java/org/asynchttpclient/netty/RetryNonBlockingIssueTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/RetryNonBlockingIssueTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; @@ -28,7 +27,9 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.time.Duration; @@ -62,6 +63,12 @@ public void setUpGlobal() throws Exception { port1 = connector.getLocalPort(); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override protected String getTargetUrl() { return String.format("http://localhost:%d/", port1); @@ -75,7 +82,7 @@ private ListenableFuture testMethodRequest(AsyncHttpClient client, int return client.executeRequest(r); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRetryNonBlocking() throws Exception { AsyncHttpClientConfig config = config() .setKeepAlive(true) @@ -103,7 +110,7 @@ public void testRetryNonBlocking() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRetryNonBlockingAsyncConnect() throws Exception { AsyncHttpClientConfig config = config() .setKeepAlive(true) diff --git a/client/src/test/java/org/asynchttpclient/netty/TimeToLiveIssueTest.java b/client/src/test/java/org/asynchttpclient/netty/TimeToLiveIssueTest.java index a2916248d7..c33dedae15 100644 --- a/client/src/test/java/org/asynchttpclient/netty/TimeToLiveIssueTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/TimeToLiveIssueTest.java @@ -12,13 +12,13 @@ */ package org.asynchttpclient.netty; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Request; import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.Response; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.concurrent.Future; @@ -30,7 +30,7 @@ public class TimeToLiveIssueTest extends AbstractBasicTest { @Disabled("https://github.com/AsyncHttpClient/async-http-client/issues/1113") - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testTTLBug() throws Throwable { // The purpose of this test is to reproduce two issues: // 1) Connections that are rejected by the pool are not closed and eventually use all available sockets. diff --git a/client/src/test/java/org/asynchttpclient/netty/channel/ConnectFailureRetryTest.java b/client/src/test/java/org/asynchttpclient/netty/channel/ConnectFailureRetryTest.java new file mode 100644 index 0000000000..69f27b85d0 --- /dev/null +++ b/client/src/test/java/org/asynchttpclient/netty/channel/ConnectFailureRetryTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2026 AsyncHttpClient Project. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asynchttpclient.netty.channel; + +import io.netty.channel.Channel; +import io.netty.resolver.AbstractAddressResolver; +import io.netty.resolver.AddressResolver; +import io.netty.resolver.AddressResolverGroup; +import io.netty.util.concurrent.EventExecutor; +import io.netty.util.concurrent.Promise; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.commons.io.IOUtils; +import org.asynchttpclient.AbstractBasicTest; +import org.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.Response; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.asynchttpclient.Dsl.asyncHttpClient; +import static org.asynchttpclient.Dsl.config; +import static org.asynchttpclient.test.TestUtils.findFreePort; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * A refused connect is retried, and the retry sends the body exactly once. + */ +public class ConnectFailureRetryTest extends AbstractBasicTest { + + private static final String BODY = "connect-retry-body"; + + private final AtomicInteger requestsReceived = new AtomicInteger(); + private final AtomicInteger bodiesReceived = new AtomicInteger(); + + @Override + public AbstractHandler configureHandler() { + return new CountingEchoHandler(); + } + + @Test + public void refusedConnectIsRetriedOnTheNextResolution() throws Exception { + requestsReceived.set(0); + // First resolution: a closed port. Later ones: the live server. Only a retry can succeed. + SwitchingResolverGroup resolverGroup = new SwitchingResolverGroup(findFreePort(), port1); + try { + try (AsyncHttpClient client = asyncHttpClient(config() + .setAddressResolverGroup(resolverGroup) + .setMaxRequestRetry(1))) { + Response response = client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + assertEquals(200, response.getStatusCode()); + assertEquals(2, resolverGroup.resolutions(), "the refused connect was not retried"); + assertEquals(1, requestsReceived.get(), "the refused attempt must not have reached the server"); + } + } finally { + resolverGroup.close(); + } + } + + @Test + public void refusedConnectReplaysThePostBodyExactlyOnce() throws Exception { + requestsReceived.set(0); + bodiesReceived.set(0); + SwitchingResolverGroup resolverGroup = new SwitchingResolverGroup(findFreePort(), port1); + try { + try (AsyncHttpClient client = asyncHttpClient(config() + .setAddressResolverGroup(resolverGroup) + .setMaxRequestRetry(1))) { + ConnectCountingHandler handler = new ConnectCountingHandler(); + Response response = client.preparePost(getTargetUrl()) + .setBody(BODY) + .execute(handler) + .get(TIMEOUT, TimeUnit.SECONDS); + assertEquals(200, response.getStatusCode()); + assertEquals(BODY, response.getResponseBody()); + assertEquals(1, requestsReceived.get(), "the request was sent more than once"); + assertEquals(1, bodiesReceived.get(), "the body was sent more than once"); + assertEquals(1, handler.connectSuccesses.get(), "a written request was replayed"); + assertEquals(1, handler.connectFailures.get(), "the refused attempt was not counted"); + } + } finally { + resolverGroup.close(); + } + } + + private static final class ConnectCountingHandler extends AsyncCompletionHandler { + + private final AtomicInteger connectSuccesses = new AtomicInteger(); + private final AtomicInteger connectFailures = new AtomicInteger(); + + @Override + public void onTcpConnectSuccess(InetSocketAddress remoteAddress, Channel connection) { + connectSuccesses.incrementAndGet(); + } + + @Override + public void onTcpConnectFailure(InetSocketAddress remoteAddress, Throwable cause) { + connectFailures.incrementAndGet(); + } + + @Override + public Response onCompleted(Response response) { + return response; + } + } + + private final class CountingEchoHandler extends AbstractHandler { + + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException { + requestsReceived.incrementAndGet(); + String body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); + if (!body.isEmpty()) { + bodiesReceived.incrementAndGet(); + } + response.setStatus(200); + response.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8)); + response.getOutputStream().flush(); + baseRequest.setHandled(true); + } + } + + // Refusing address first, then the live one. + private static final class SwitchingResolverGroup extends AddressResolverGroup { + + private final AtomicInteger resolutions = new AtomicInteger(); + private final int firstPort; + private final int remainingPort; + + SwitchingResolverGroup(int firstPort, int remainingPort) { + this.firstPort = firstPort; + this.remainingPort = remainingPort; + } + + int resolutions() { + return resolutions.get(); + } + + @Override + protected AddressResolver newResolver(EventExecutor executor) { + return new AbstractAddressResolver(executor, InetSocketAddress.class) { + + @Override + protected boolean doIsResolved(InetSocketAddress address) { + return !address.isUnresolved(); + } + + @Override + protected void doResolve(InetSocketAddress unresolvedAddress, Promise promise) { + promise.setSuccess(next()); + } + + @Override + protected void doResolveAll(InetSocketAddress unresolvedAddress, Promise> promise) { + promise.setSuccess(Collections.singletonList(next())); + } + }; + } + + private InetSocketAddress next() { + int port = resolutions.getAndIncrement() == 0 ? firstPort : remainingPort; + return new InetSocketAddress(InetAddress.getLoopbackAddress(), port); + } + } +} diff --git a/client/src/test/java/org/asynchttpclient/netty/channel/SemaphoreTest.java b/client/src/test/java/org/asynchttpclient/netty/channel/SemaphoreTest.java index e56755aac4..0dbd4e0fa3 100644 --- a/client/src/test/java/org/asynchttpclient/netty/channel/SemaphoreTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/channel/SemaphoreTest.java @@ -15,10 +15,8 @@ */ package org.asynchttpclient.netty.channel; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.exception.TooManyConnectionsException; import org.asynchttpclient.exception.TooManyConnectionsPerHostException; -import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.Timeout; @@ -28,6 +26,7 @@ import java.io.IOException; import java.util.List; import java.util.Objects; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -51,9 +50,6 @@ public class SemaphoreTest { static final int CHECK_ACQUIRE_TIME__PERMITS = 10; static final int CHECK_ACQUIRE_TIME__TIMEOUT = 100; - static final int NON_DETERMINISTIC__INVOCATION_COUNT = 10; - static final int NON_DETERMINISTIC__SUCCESS_PERCENT = 70; - private final Object PK = new Object(); public Object[][] permitsAndRunnersCount() { @@ -112,20 +108,21 @@ private void allSemaphoresCheckPermitCount(ConnectionSemaphore semaphore, int pe assertEquals(runnerCount - acquired, tooManyConnectionsCount); } - @RepeatedTest(NON_DETERMINISTIC__INVOCATION_COUNT) - @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) + // Keep these @Timeout values small: they are the only check that an acquire ever times out. + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) public void maxConnectionCheckAcquireTime() { checkAcquireTime(new MaxConnectionSemaphore(CHECK_ACQUIRE_TIME__PERMITS, CHECK_ACQUIRE_TIME__TIMEOUT)); } - @RepeatedTest(NON_DETERMINISTIC__INVOCATION_COUNT) - @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) public void perHostCheckAcquireTime() { checkAcquireTime(new PerHostConnectionSemaphore(CHECK_ACQUIRE_TIME__PERMITS, CHECK_ACQUIRE_TIME__TIMEOUT)); } - @RepeatedTest(NON_DETERMINISTIC__INVOCATION_COUNT) - @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) public void combinedCheckAcquireTime() { checkAcquireTime(new CombinedConnectionSemaphore(CHECK_ACQUIRE_TIME__PERMITS, CHECK_ACQUIRE_TIME__PERMITS, @@ -136,28 +133,83 @@ private void checkAcquireTime(ConnectionSemaphore semaphore) { List runners = IntStream.range(0, CHECK_ACQUIRE_TIME__PERMITS * 2) .mapToObj(i -> new SemaphoreRunner(semaphore, PK)) .collect(Collectors.toList()); - long acquireStartTime = System.currentTimeMillis(); runners.forEach(SemaphoreRunner::acquire); runners.forEach(SemaphoreRunner::await); - long timeToAcquire = System.currentTimeMillis() - acquireStartTime; - assertTrue(timeToAcquire >= CHECK_ACQUIRE_TIME__TIMEOUT - 50, "Semaphore acquired too soon: " + timeToAcquire + " ms"); //Lower Bound - assertTrue(timeToAcquire <= CHECK_ACQUIRE_TIME__TIMEOUT + 300, "Semaphore acquired too late: " + timeToAcquire + " ms"); //Upper Bound + long acquired = runners.stream().map(SemaphoreRunner::getAcquireException) + .filter(Objects::isNull) + .count(); + assertEquals(CHECK_ACQUIRE_TIME__PERMITS, acquired); + + for (SemaphoreRunner runner : runners) { + Exception acquireException = runner.getAcquireException(); + if (acquireException == null) { + continue; + } + assertTrue(acquireException instanceof IOException, "unexpected acquire failure: " + acquireException); + // Lower bound only. An upper bound would measure the machine, not the semaphore. The 50 ms + // slack covers CombinedConnectionSemaphore splitting its budget in whole milliseconds. + assertTrue(runner.getAcquireTime() >= CHECK_ACQUIRE_TIME__TIMEOUT - 50, + "Semaphore gave up after " + runner.getAcquireTime() + " ms, before its " + + CHECK_ACQUIRE_TIME__TIMEOUT + " ms acquire timeout"); + } + } + + // ---- a waiting acquire completes on release, not on its own timeout ---- + + // Far longer than the @Timeout below, so waiting it out cannot pass. + static final int WAKE_ON_RELEASE__ACQUIRE_TIMEOUT = 30_000; + + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) + public void maxConnectionWaitingAcquireWakesOnRelease() throws Exception { + waitingAcquireWakesOnRelease(new MaxConnectionSemaphore(1, WAKE_ON_RELEASE__ACQUIRE_TIMEOUT)); + } + + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) + public void perHostWaitingAcquireWakesOnRelease() throws Exception { + waitingAcquireWakesOnRelease(new PerHostConnectionSemaphore(1, WAKE_ON_RELEASE__ACQUIRE_TIMEOUT)); + } + + @Test + @Timeout(unit = TimeUnit.SECONDS, value = 5) + public void combinedWaitingAcquireWakesOnRelease() throws Exception { + waitingAcquireWakesOnRelease(new CombinedConnectionSemaphore(1, 1, WAKE_ON_RELEASE__ACQUIRE_TIMEOUT)); + } + + private void waitingAcquireWakesOnRelease(ConnectionSemaphore semaphore) throws Exception { + semaphore.acquireChannelLock(PK); // consume the only permit + CountDownLatch acquireStarted = new CountDownLatch(1); + ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + Future waitingAcquire = executor.submit(() -> { + acquireStarted.countDown(); + semaphore.acquireChannelLock(PK); + return null; + }); + acquireStarted.await(); + + semaphore.releaseChannelLock(PK); + waitingAcquire.get(1, TimeUnit.SECONDS); + } finally { + executor.shutdownNow(); + } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) public void maxConnectionCheckRelease() throws IOException { checkRelease(new MaxConnectionSemaphore(1, 0)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) public void perHostCheckRelease() throws IOException { checkRelease(new PerHostConnectionSemaphore(1, 0)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 1000) public void combinedCheckRelease() throws IOException { checkRelease(new CombinedConnectionSemaphore(1, 1, 0)); diff --git a/client/src/test/java/org/asynchttpclient/netty/future/StackTraceInspectorTest.java b/client/src/test/java/org/asynchttpclient/netty/future/StackTraceInspectorTest.java new file mode 100644 index 0000000000..c9aff90ed9 --- /dev/null +++ b/client/src/test/java/org/asynchttpclient/netty/future/StackTraceInspectorTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2026 AsyncHttpClient Project. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.asynchttpclient.netty.future; + +import io.netty.channel.ConnectTimeoutException; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.BindException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.NoRouteToHostException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.channels.UnresolvedAddressException; + +import static org.asynchttpclient.test.TestUtils.findFreePort; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * A refused connect must be recoverable on every JDK and transport, and nothing else reported through the + * same wrapper may be. + */ +public class StackTraceInspectorTest { + + private static final long CONNECT_WAIT_MILLIS = 5000; + + @Test + public void refusedNioConnectIsRecoverable() throws Exception { + assertTrue(StackTraceInspector.recoverOnNettyDisconnectException(annotated(refusedNioConnect()))); + } + + // Native transports report a ConnectException with no sun.nio.ch frame. + @Test + public void refusedNativeTransportConnectIsRecoverable() { + ConnectException refused = thrownHere("finishConnect(..) failed with error(-111): Connection refused"); + for (StackTraceElement element : refused.getStackTrace()) { + assertFalse(element.getClassName().startsWith("sun.nio.ch"), "fixture must carry no NIO frame"); + } + assertTrue(StackTraceInspector.recoverOnNettyDisconnectException(annotated(refused))); + } + + // NoRouteToHostException is not a ConnectException, so only the frame probes match it. The running JDK + // produces just one of the two frames (checkConnect up to JDK 12, pollConnect after), hence the fake stacks. + @Test + public void unreachablePeerReportedFromConnectCompletionIsRecoverable() { + assertTrue(StackTraceInspector.recoverOnNettyDisconnectException( + unreachablePeer("sun.nio.ch.SocketChannelImpl", "checkConnect"))); + assertTrue(StackTraceInspector.recoverOnNettyDisconnectException( + unreachablePeer("sun.nio.ch.Net", "pollConnect"))); + } + + // ConnectTimeoutException extends ConnectException: retrying it would multiply the connect timeout. + @Test + public void connectTimeoutIsNotRecoverable() { + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException( + new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:1"))); + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException( + annotated(new ConnectTimeoutException("connection timed out: localhost/127.0.0.1:1")))); + } + + // NettyChannelConnector wraps every failure in a ConnectException, so the wrapper's type must not count. + @Test + public void wrappedNonConnectFailuresAreNotRecoverable() { + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException(annotated(new BindException("Address already in use")))); + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException(annotated(new UnresolvedAddressException()))); + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException(annotated(new IllegalStateException("boom")))); + assertFalse(StackTraceInspector.recoverOnNettyDisconnectException(new ConnectException("no cause to inspect"))); + } + + @Test + public void closedChannelIsRecoverable() { + assertTrue(StackTraceInspector.recoverOnNettyDisconnectException(new ClosedChannelException())); + } + + // Same shape as Netty's AnnotatedConnectException: empty stack trace, the original as cause. + private static ConnectException annotated(Throwable cause) { + ConnectException wrapper = new ConnectException(cause.getMessage() + ": localhost/127.0.0.1:1"); + wrapper.initCause(cause); + wrapper.setStackTrace(new StackTraceElement[0]); + return wrapper; + } + + // Netty annotates it, then NettyChannelConnector wraps it in a ConnectException. + private static ConnectException unreachablePeer(String className, String methodName) { + NoRouteToHostException original = new NoRouteToHostException("No route to host"); + original.setStackTrace(new StackTraceElement[]{ + new StackTraceElement(className, methodName, null, -2), + new StackTraceElement("io.netty.channel.socket.nio.NioSocketChannel", "doFinishConnect", "NioSocketChannel.java", 330)}); + NoRouteToHostException nettyAnnotated = new NoRouteToHostException(original.getMessage() + ": localhost/127.0.0.1:1"); + nettyAnnotated.initCause(original); + nettyAnnotated.setStackTrace(new StackTraceElement[0]); + return annotated(nettyAnnotated); + } + + private static ConnectException thrownHere(String message) { + try { + throw new ConnectException(message); + } catch (ConnectException e) { + return e; + } + } + + // A real refused non-blocking connect, so the frames are whatever this JDK produces. + private static ConnectException refusedNioConnect() throws IOException { + int closedPort = findFreePort(); + try (SocketChannel channel = SocketChannel.open(); Selector selector = Selector.open()) { + channel.configureBlocking(false); + channel.register(selector, SelectionKey.OP_CONNECT); + channel.connect(new InetSocketAddress("127.0.0.1", closedPort)); + selector.select(CONNECT_WAIT_MILLIS); + try { + channel.finishConnect(); + } catch (ConnectException e) { + return e; + } + return fail("connect to closed port " + closedPort + " neither failed nor was refused in " + + CONNECT_WAIT_MILLIS + "ms"); + } + } +} diff --git a/client/src/test/java/org/asynchttpclient/netty/timeout/TimeoutsHolderTest.java b/client/src/test/java/org/asynchttpclient/netty/timeout/TimeoutsHolderTest.java index ac67b5f1b9..13180203c2 100644 --- a/client/src/test/java/org/asynchttpclient/netty/timeout/TimeoutsHolderTest.java +++ b/client/src/test/java/org/asynchttpclient/netty/timeout/TimeoutsHolderTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.netty.timeout; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncCompletionHandler; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.DefaultAsyncHttpClientConfig; @@ -24,6 +23,7 @@ import org.asynchttpclient.Response; import org.asynchttpclient.channel.ChannelPoolPartitioning; import org.asynchttpclient.netty.NettyResponseFuture; +import org.junit.jupiter.api.Test; import java.time.Duration; @@ -46,7 +46,7 @@ public class TimeoutsHolderTest { // deadline lands within a few milliseconds of itself rather than exactly on it. private static final long TOLERANCE_MS = 30; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void anAbsoluteDeadlineStaysWhereTheExchangeStarted() throws Exception { NettyResponseFuture future = exchange(true); @@ -58,7 +58,7 @@ public void anAbsoluteDeadlineStaysWhereTheExchangeStarted() throws Exception { "the second hop moved the deadline by " + (secondHop - firstHop) + " ms"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aPerAttemptTimeoutGivesTheSecondHopItsOwnBudget() throws Exception { NettyResponseFuture future = exchange(false); @@ -71,7 +71,7 @@ public void aPerAttemptTimeoutGivesTheSecondHopItsOwnBudget() throws Exception { + (secondHop - firstHop) + " ms"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void anExchangeThatOutranItsDeadlineHasNothingLeft() throws Exception { // A budget this small is spent by the time the sleep is over, so the next hop has nothing to run in. NettyResponseFuture future = exchange(true); @@ -81,7 +81,7 @@ public void anExchangeThatOutranItsDeadlineHasNothingLeft() throws Exception { "a spent deadline should leave nothing to send a further hop with"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void aPerAttemptExchangeIsNotBoundedAsAWhole() throws Exception { // Asserted on the deadline the holder computes rather than on the budget: per attempt there is no // exchange-wide budget to run out of, so the arithmetic is not what the answer rests on. diff --git a/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java b/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java index 0bce17d4c7..de65430dbd 100644 --- a/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java +++ b/client/src/test/java/org/asynchttpclient/ntlm/NtlmTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.ntlm; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -80,24 +79,24 @@ public void testUnicodeLittleUnmarkedEncoding() { assertArrayEquals("Test @ テスト".getBytes(unicodeLittleUnmarked), "Test @ テスト".getBytes(utf16le)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void lazyNTLMAuthTest() throws Exception { ntlmAuthTest(realmBuilderBase()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void preemptiveNTLMAuthTest() throws Exception { ntlmAuthTest(realmBuilderBase().setUsePreemptiveAuth(true)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType1Msg() { NtlmEngine engine = new NtlmEngine(); String message = engine.generateType1Msg(); assertEquals(message, "TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==", "Incorrect type1 message generated"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType3MsgThrowsExceptionWhenChallengeTooShort() { NtlmEngine engine = new NtlmEngine(); assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation", @@ -105,7 +104,7 @@ public void testGenerateType3MsgThrowsExceptionWhenChallengeTooShort() { "An NtlmEngineException must have occurred as challenge length is too short"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType3MsgThrowsExceptionWhenChallengeDoesNotFollowCorrectFormat() { NtlmEngine engine = new NtlmEngine(); assertThrows(NtlmEngineException.class, () -> NtlmEngine.generateType3Msg("username", "password", "localhost", "workstation", @@ -113,7 +112,7 @@ public void testGenerateType3MsgThrowsExceptionWhenChallengeDoesNotFollowCorrect "An NtlmEngineException must have occurred as challenge length is too short"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType3MsgThworsExceptionWhenType2IndicatorNotPresent() throws IOException { try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { buf.write("NTLMSSP".getBytes(StandardCharsets.US_ASCII)); @@ -130,7 +129,7 @@ public void testGenerateType3MsgThworsExceptionWhenType2IndicatorNotPresent() th } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType3MsgThrowsExceptionWhenUnicodeSupportNotIndicated() throws IOException { try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { buf.write("NTLMSSP".getBytes(StandardCharsets.US_ASCII)); @@ -157,13 +156,13 @@ public void testGenerateType3MsgThrowsExceptionWhenUnicodeSupportNotIndicated() } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType2Msg() { Type2Message type2Message = new Type2Message("TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA=="); assertEquals(40, type2Message.getMessageLength(), "This is a sample challenge that should return 40"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGenerateType3Msg() throws IOException { try (ByteArrayOutputStream buf = new ByteArrayOutputStream()) { buf.write("NTLMSSP".getBytes(StandardCharsets.US_ASCII)); @@ -192,7 +191,7 @@ public void testGenerateType3Msg() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWriteULong() { // test different combinations so that different positions in the byte array will be written byte[] buffer = new byte[4]; diff --git a/client/src/test/java/org/asynchttpclient/proxy/CustomHeaderProxyTest.java b/client/src/test/java/org/asynchttpclient/proxy/CustomHeaderProxyTest.java index 3448bcae7e..b700f8ee71 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/CustomHeaderProxyTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/CustomHeaderProxyTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -31,6 +30,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; @@ -83,7 +83,7 @@ public void tearDownGlobal() throws Exception { server2.stop(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpProxy() throws Exception { AsyncHttpClientConfig config = config() .setFollowRedirect(true) diff --git a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyBasicTest.java b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyBasicTest.java index 29876708e0..c0fe5587aa 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyBasicTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyBasicTest.java @@ -15,9 +15,9 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.channel.ChannelPoolPartitioning; import org.asynchttpclient.uri.Uri; +import org.junit.jupiter.api.Test; import static org.asynchttpclient.Dsl.proxyServer; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -29,7 +29,7 @@ */ public class HttpsProxyBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpsProxyTypeConfiguration() throws Exception { // Test that HTTPS proxy type can be configured correctly ProxyServer.Builder builder = proxyServer("proxy.example.com", 8080) @@ -45,7 +45,7 @@ public void testHttpsProxyTypeConfiguration() throws Exception { assertEquals("proxy.example.com", proxy.getHost()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpsProxyTypeDefaultSecuredPort() { // Test HTTPS proxy type with default secured port ProxyServer proxy = proxyServer("proxy.example.com", 8080) @@ -56,7 +56,7 @@ public void testHttpsProxyTypeDefaultSecuredPort() { assertEquals(true, proxy.getProxyType().isHttp()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChannelPoolPartitioningWithHttpsProxy() { // Test that HTTPS proxy creates correct partition keys for connection pooling ProxyServer httpsProxy = proxyServer("proxy.example.com", 8080) @@ -75,7 +75,7 @@ public void testChannelPoolPartitioningWithHttpsProxy() { assertTrue(partitionKey.toString().contains("HTTPS")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChannelPoolPartitioningHttpsProxyHttpTarget() { // Test HTTPS proxy with HTTP target - should use normal port ProxyServer httpsProxy = proxyServer("proxy.example.com", 8080) @@ -94,7 +94,7 @@ public void testChannelPoolPartitioningHttpsProxyHttpTarget() { assertTrue(partitionKey.toString().contains("HTTPS")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChannelPoolPartitioningWithHttpProxy() { // Test that HTTP proxy creates correct partition keys for connection pooling ProxyServer httpProxy = proxyServer("proxy.example.com", 8080) diff --git a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyIntegrationTest.java b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyIntegrationTest.java index ef4614ba19..9e2ac1ea5c 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyIntegrationTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyIntegrationTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -37,6 +36,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -196,7 +196,7 @@ public void testProxyTimeoutConfiguration(String testName, ProxyType proxyType) } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChannelPoolPartitioningWithHttpsProxy() throws Exception { // Test that HTTPS proxy creates correct partition keys for connection pooling ProxyServer httpsProxy = proxyServer("proxy.example.com", 8080) @@ -215,7 +215,7 @@ public void testChannelPoolPartitioningWithHttpsProxy() throws Exception { assertTrue(partitionKey.toString().contains("HTTPS")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testChannelPoolPartitioningWithHttpProxy() throws Exception { // Test that HTTP proxy creates correct partition keys for connection pooling ProxyServer httpProxy = proxyServer("proxy.example.com", 8080) diff --git a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTest.java b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTest.java index 26c0850dee..64b714d058 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -34,6 +33,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -272,7 +272,7 @@ public void testClosedConnectionWithProxy(String testName, ProxyType proxyType) } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpsProxyType() throws Exception { // Test that HTTPS proxy type can be configured and behaves correctly ProxyServer.Builder builder = proxyServer("localhost", port1) @@ -286,7 +286,7 @@ public void testHttpsProxyType() throws Exception { assertEquals(443, proxy.getSecuredPort()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpsProxyWithSecuredPortOnly() throws Exception { // Test HTTPS proxy using only secured port (typical configuration) try (AsyncHttpClient client = asyncHttpClient(config().setFollowRedirect(true).setUseInsecureTrustManager(true))) { @@ -300,7 +300,7 @@ public void testHttpsProxyWithSecuredPortOnly() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testHttpsProxyWithAuthentication() throws Exception { // Test HTTPS proxy with custom headers (simulating authentication) try (AsyncHttpClient client = asyncHttpClient(config().setFollowRedirect(true).setUseInsecureTrustManager(true))) { diff --git a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTestcontainersIntegrationTest.java b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTestcontainersIntegrationTest.java index 2107d74ce2..1346aa294d 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTestcontainersIntegrationTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/HttpsProxyTestcontainersIntegrationTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; @@ -114,7 +113,7 @@ static void stopContainer() { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testHttpProxyToHttpTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing HTTP proxy to HTTP target"); @@ -133,7 +132,7 @@ public void testHttpProxyToHttpTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testHttpsProxyToHttpTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing HTTPS proxy to HTTP target"); @@ -153,7 +152,7 @@ public void testHttpsProxyToHttpTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testHttpProxyToHttpsTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing HTTP proxy to HTTPS target"); @@ -173,7 +172,7 @@ public void testHttpProxyToHttpsTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testHttpsProxyToHttpsTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing HTTPS proxy to HTTPS target - validates issue #1907 fix"); diff --git a/client/src/test/java/org/asynchttpclient/proxy/NTLMProxyTest.java b/client/src/test/java/org/asynchttpclient/proxy/NTLMProxyTest.java index d3e5b54c7d..922e201636 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/NTLMProxyTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/NTLMProxyTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -26,6 +25,7 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.Future; @@ -44,7 +44,7 @@ public AbstractHandler configureHandler() throws Exception { return new NTLMProxyHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void ntlmProxyTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { org.asynchttpclient.Request request = get("http://localhost").setProxyServer(ntlmProxy()).build(); diff --git a/client/src/test/java/org/asynchttpclient/proxy/ProxyTest.java b/client/src/test/java/org/asynchttpclient/proxy/ProxyTest.java index 73d7f6a598..756446c8b7 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/ProxyTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/ProxyTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; @@ -31,6 +30,7 @@ import org.asynchttpclient.testserver.SocksProxy; import org.asynchttpclient.util.ProxyUtils; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.ConnectException; @@ -71,7 +71,7 @@ public AbstractHandler configureHandler() throws Exception { return new ProxyHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRequestLevelProxy() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { String target = "http://localhost:1234/"; @@ -83,7 +83,7 @@ public void testRequestLevelProxy() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void asyncDoPostProxyTest() throws Throwable { try (AsyncHttpClient client = asyncHttpClient(config().setProxyServer(proxyServer("localhost", port2).build()))) { HttpHeaders h = new DefaultHttpHeaders(); @@ -113,7 +113,7 @@ public void onThrowable(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGlobalProxy() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setProxyServer(proxyServer("localhost", port1)))) { String target = "http://localhost:1234/"; @@ -125,7 +125,7 @@ public void testGlobalProxy() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testBothProxies() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setProxyServer(proxyServer("localhost", port1 - 1)))) { String target = "http://localhost:1234/"; @@ -137,7 +137,7 @@ public void testBothProxies() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testNonProxyHost() { // // should avoid, it's in non-proxy hosts Request req = get("http://somewhere.com/foo").build(); @@ -155,7 +155,7 @@ public void testNonProxyHost() { assertTrue(proxyServer.isIgnoredForHost(req.getUri().getHost())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testNonProxyHostsRequestOverridesConfig() throws Exception { ProxyServer configProxy = proxyServer("localhost", port1 - 1).build(); ProxyServer requestProxy = proxyServer("localhost", port1).setNonProxyHost("localhost").build(); @@ -167,7 +167,7 @@ public void testNonProxyHostsRequestOverridesConfig() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRequestNonProxyHost() throws Exception { ProxyServer proxy = proxyServer("localhost", port1 - 1).setNonProxyHost("localhost").build(); try (AsyncHttpClient client = asyncHttpClient()) { @@ -180,7 +180,7 @@ public void testRequestNonProxyHost() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void runSequentiallyBecauseNotThreadSafe() throws Exception { testProxyProperties(); testIgnoreProxyPropertiesByDefault(); @@ -189,7 +189,7 @@ public void runSequentiallyBecauseNotThreadSafe() throws Exception { testUseProxySelector(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testProxyProperties() throws IOException, ExecutionException, TimeoutException, InterruptedException { // FIXME not threadsafe! Properties originalProps = new Properties(); @@ -216,7 +216,7 @@ public void testProxyProperties() throws IOException, ExecutionException, Timeou } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIgnoreProxyPropertiesByDefault() throws IOException, TimeoutException, InterruptedException { // FIXME not threadsafe! Properties originalProps = new Properties(); @@ -235,7 +235,7 @@ public void testIgnoreProxyPropertiesByDefault() throws IOException, TimeoutExce } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testProxyActivationProperty() throws IOException, ExecutionException, TimeoutException, InterruptedException { // FIXME not threadsafe! Properties originalProps = new Properties(); @@ -262,7 +262,7 @@ public void testProxyActivationProperty() throws IOException, ExecutionException } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWildcardNonProxyHosts() throws IOException, TimeoutException, InterruptedException { // FIXME not threadsafe! Properties originalProps = new Properties(); @@ -281,7 +281,7 @@ public void testWildcardNonProxyHosts() throws IOException, TimeoutException, In } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUseProxySelector() throws IOException, ExecutionException, TimeoutException, InterruptedException { ProxySelector originalProxySelector = ProxySelector.getDefault(); ProxySelector.setDefault(new ProxySelector() { @@ -317,7 +317,7 @@ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void runSocksProxy() throws Exception { SocksProxy socksProxy = new SocksProxy(60000); new Thread(() -> { diff --git a/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTest.java b/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTest.java index 4af5fb4891..ff3fd0eeb2 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.Response; @@ -58,7 +57,7 @@ private static int findFreePort() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSocks4ProxyWithHttp() throws Exception { SocksProxy socksProxy = new SocksProxy(60000); new Thread(() -> { diff --git a/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTestcontainersIntegrationTest.java b/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTestcontainersIntegrationTest.java index 4c07456ff3..d13b96691b 100644 --- a/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTestcontainersIntegrationTest.java +++ b/client/src/test/java/org/asynchttpclient/proxy/SocksProxyTestcontainersIntegrationTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.proxy; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.Response; @@ -126,7 +125,7 @@ static void stopContainer() { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testSocks4ProxyToHttpTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing SOCKS4 proxy to HTTP target"); @@ -145,7 +144,7 @@ public void testSocks4ProxyToHttpTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testSocks5ProxyToHttpTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing SOCKS5 proxy to HTTP target"); @@ -164,7 +163,7 @@ public void testSocks5ProxyToHttpTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testSocks4ProxyToHttpsTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing SOCKS4 proxy to HTTPS target - validates issue #1913 fix"); @@ -184,7 +183,7 @@ public void testSocks4ProxyToHttpsTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testSocks5ProxyToHttpsTarget() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing SOCKS5 proxy to HTTPS target - validates issue #1913 fix"); @@ -204,7 +203,7 @@ public void testSocks5ProxyToHttpsTarget() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void testIssue1913ReproductionWithRealProxy() throws Exception { assumeTrue(dockerAvailable, "Docker is not available - skipping test"); LOGGER.info("Testing exact issue #1913 reproduction with real SOCKS proxy"); diff --git a/client/src/test/java/org/asynchttpclient/request/body/BodyChunkTest.java b/client/src/test/java/org/asynchttpclient/request/body/BodyChunkTest.java index b33eb382ed..a002348e6a 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/BodyChunkTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/BodyChunkTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.AsyncHttpClientConfig; import org.asynchttpclient.RequestBuilder; import org.asynchttpclient.Response; import org.asynchttpclient.request.body.generator.InputStreamBodyGenerator; +import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.time.Duration; @@ -36,7 +36,7 @@ public class BodyChunkTest extends AbstractBasicTest { private static final String MY_MESSAGE = "my message"; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void negativeContentTypeTest() throws Exception { AsyncHttpClientConfig config = config() diff --git a/client/src/test/java/org/asynchttpclient/request/body/ChunkingTest.java b/client/src/test/java/org/asynchttpclient/request/body/ChunkingTest.java index 8fc32e08d2..7c10e4f170 100755 --- a/client/src/test/java/org/asynchttpclient/request/body/ChunkingTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/ChunkingTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.Unpooled; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; @@ -23,6 +22,7 @@ import org.asynchttpclient.request.body.generator.FeedableBodyGenerator; import org.asynchttpclient.request.body.generator.InputStreamBodyGenerator; import org.asynchttpclient.request.body.generator.UnboundedQueueFeedableBodyGenerator; +import org.junit.jupiter.api.Test; import java.io.BufferedInputStream; import java.io.InputStream; @@ -44,22 +44,22 @@ public class ChunkingTest extends AbstractBasicTest { // So we can just test the returned data is the image, // and doesn't contain the chunked delimiters. - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testBufferLargerThanFileWithStreamBodyGenerator() throws Throwable { doTestWithInputStreamBodyGenerator(new BufferedInputStream(Files.newInputStream(LARGE_IMAGE_FILE.toPath()), 400000)); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testBufferSmallThanFileWithStreamBodyGenerator() throws Throwable { doTestWithInputStreamBodyGenerator(new BufferedInputStream(Files.newInputStream(LARGE_IMAGE_FILE.toPath()))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDirectFileWithStreamBodyGenerator() throws Throwable { doTestWithInputStreamBodyGenerator(Files.newInputStream(LARGE_IMAGE_FILE.toPath())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDirectFileWithFeedableBodyGenerator() throws Throwable { doTestWithFeedableBodyGenerator(Files.newInputStream(LARGE_IMAGE_FILE.toPath())); } diff --git a/client/src/test/java/org/asynchttpclient/request/body/EmptyBodyTest.java b/client/src/test/java/org/asynchttpclient/request/body/EmptyBodyTest.java index ca3ac69300..96e0b819c0 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/EmptyBodyTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/EmptyBodyTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -28,6 +27,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.concurrent.CountDownLatch; @@ -55,7 +55,7 @@ public AbstractHandler configureHandler() throws Exception { return new NoBodyResponseHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testEmptyBody() throws IOException { try (AsyncHttpClient ahc = asyncHttpClient()) { final AtomicBoolean err = new AtomicBoolean(false); @@ -118,7 +118,7 @@ public Object onCompleted() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutEmptyBody() throws Exception { try (AsyncHttpClient ahc = asyncHttpClient()) { Response response = ahc.preparePut(getTargetUrl()).setBody("String").execute().get(); diff --git a/client/src/test/java/org/asynchttpclient/request/body/FilePartLargeFileTest.java b/client/src/test/java/org/asynchttpclient/request/body/FilePartLargeFileTest.java index 4cf1d2ee4e..bbe211aaab 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/FilePartLargeFileTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/FilePartLargeFileTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -22,6 +21,7 @@ import org.asynchttpclient.request.body.multipart.FilePart; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -62,7 +62,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H }; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutImageFile() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofMinutes(10)))) { Response response = client.preparePut(getTargetUrl()) @@ -73,7 +73,7 @@ public void testPutImageFile() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutLargeTextFile() throws Exception { File file = createTempFile(1024 * 1024); diff --git a/client/src/test/java/org/asynchttpclient/request/body/InputStreamPartLargeFileTest.java b/client/src/test/java/org/asynchttpclient/request/body/InputStreamPartLargeFileTest.java index e0fdfcbbdd..a5eb18c03e 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/InputStreamPartLargeFileTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/InputStreamPartLargeFileTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -25,6 +24,7 @@ import org.asynchttpclient.request.body.multipart.InputStreamPart; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.BufferedInputStream; import java.io.File; @@ -68,7 +68,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H }; } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutImageFile() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofMinutes(10)))) { InputStream inputStream = new BufferedInputStream(new FileInputStream(LARGE_IMAGE_FILE)); @@ -78,7 +78,7 @@ public void testPutImageFile() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutImageFileUnknownSize() throws Exception { try (AsyncHttpClient client = asyncHttpClient(config().setRequestTimeout(Duration.ofMinutes(10)))) { InputStream inputStream = new BufferedInputStream(new FileInputStream(LARGE_IMAGE_FILE)); @@ -88,7 +88,7 @@ public void testPutImageFileUnknownSize() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutLargeTextFile() throws Exception { File file = createTempFile(1024 * 1024); InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); @@ -101,7 +101,7 @@ public void testPutLargeTextFile() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutLargeTextFileUnknownSize() throws Exception { File file = createTempFile(1024 * 1024); InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); diff --git a/client/src/test/java/org/asynchttpclient/request/body/InputStreamTest.java b/client/src/test/java/org/asynchttpclient/request/body/InputStreamTest.java index 55cff4323d..4a77868a1b 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/InputStreamTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/InputStreamTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; @@ -27,6 +26,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -44,7 +44,7 @@ public AbstractHandler configureHandler() throws Exception { return new InputStreamHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testInvalidInputStream() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { diff --git a/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java b/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java index 3260604d3f..3a7e880705 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/PutByteBufTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import jakarta.servlet.http.HttpServletRequest; @@ -22,6 +21,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.Charset; @@ -44,12 +44,12 @@ private void put(String message) throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutSmallBody() throws Exception { put("Hello Test"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutBigBody() throws Exception { byte[] array = new byte[2048]; Arrays.fill(array, (byte) 97); diff --git a/client/src/test/java/org/asynchttpclient/request/body/PutFileTest.java b/client/src/test/java/org/asynchttpclient/request/body/PutFileTest.java index 30100f6586..3e8a1cf58a 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/PutFileTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/PutFileTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.AbstractBasicTest; @@ -20,6 +19,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -41,12 +41,12 @@ private void put(int fileSize) throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutLargeFile() throws Exception { put(1024 * 1024); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testPutSmallFile() throws Exception { put(1024); } diff --git a/client/src/test/java/org/asynchttpclient/request/body/TransferListenerTest.java b/client/src/test/java/org/asynchttpclient/request/body/TransferListenerTest.java index e4cffadd0f..1001275482 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/TransferListenerTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/TransferListenerTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -25,6 +24,7 @@ import org.asynchttpclient.request.body.generator.FileBodyGenerator; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -49,7 +49,7 @@ public AbstractHandler configureHandler() throws Exception { return new BasicHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicGetTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { final AtomicReference throwable = new AtomicReference<>(); @@ -104,7 +104,7 @@ public void onThrowable(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicPutFileTest() throws Exception { final AtomicReference throwable = new AtomicReference<>(); final AtomicReference hSent = new AtomicReference<>(); @@ -164,7 +164,7 @@ public void onThrowable(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void basicPutFileBodyGeneratorTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final AtomicReference throwable = new AtomicReference<>(); diff --git a/client/src/test/java/org/asynchttpclient/request/body/ZeroCopyFileTest.java b/client/src/test/java/org/asynchttpclient/request/body/ZeroCopyFileTest.java index 374c1e121d..9e079f7499 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/ZeroCopyFileTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/ZeroCopyFileTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.handler.codec.http.HttpHeaders; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -27,6 +26,7 @@ import org.asynchttpclient.Response; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; @@ -48,7 +48,7 @@ */ public class ZeroCopyFileTest extends AbstractBasicTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void zeroCopyPostTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final AtomicBoolean headerSent = new AtomicBoolean(false); @@ -82,7 +82,7 @@ public Response onCompleted(Response response) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void zeroCopyPutTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { Future f = client.preparePut("http://localhost:" + port1 + '/').setBody(SIMPLE_TEXT_FILE).execute(); @@ -98,7 +98,7 @@ public AbstractHandler configureHandler() throws Exception { return new ZeroCopyHandler(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void zeroCopyFileTest() throws Exception { File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); tmp.deleteOnExit(); @@ -138,7 +138,7 @@ public Response onCompleted() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void zeroCopyFileWithBodyManipulationTest() throws Exception { File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); tmp.deleteOnExit(); diff --git a/client/src/test/java/org/asynchttpclient/request/body/generator/ByteArrayBodyGeneratorTest.java b/client/src/test/java/org/asynchttpclient/request/body/generator/ByteArrayBodyGeneratorTest.java index 81da4d7341..82585a48a5 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/generator/ByteArrayBodyGeneratorTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/generator/ByteArrayBodyGeneratorTest.java @@ -12,11 +12,11 @@ */ package org.asynchttpclient.request.body.generator; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.asynchttpclient.request.body.Body; import org.asynchttpclient.request.body.Body.BodyState; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Random; @@ -31,7 +31,7 @@ public class ByteArrayBodyGeneratorTest { private final Random random = new Random(); private static final int CHUNK_SIZE = 1024 * 8; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSingleRead() throws IOException { final int srcArraySize = CHUNK_SIZE - 1; final byte[] srcArray = new byte[srcArraySize]; @@ -54,7 +54,7 @@ public void testSingleRead() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMultipleReads() throws IOException { final int srcArraySize = 3 * CHUNK_SIZE + 42; final byte[] srcArray = new byte[srcArraySize]; diff --git a/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java b/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java index 7c2a3579bf..2a6d38f902 100755 --- a/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/generator/FeedableBodyGeneratorTest.java @@ -15,12 +15,12 @@ */ package org.asynchttpclient.request.body.generator; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.asynchttpclient.request.body.Body; import org.asynchttpclient.request.body.Body.BodyState; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -40,14 +40,14 @@ public void setUp() { feedableBodyGenerator.setListener(listener); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void feedNotifiesListener() throws Exception { feedableBodyGenerator.feed(Unpooled.EMPTY_BUFFER, false); feedableBodyGenerator.feed(Unpooled.EMPTY_BUFFER, true); assertEquals(2, listener.getCalls()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void readingBytesReturnsFedContentWithoutChunkBoundaries() throws Exception { byte[] content = "Test123".getBytes(StandardCharsets.US_ASCII); @@ -65,7 +65,7 @@ public void readingBytesReturnsFedContentWithoutChunkBoundaries() throws Excepti } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void returnZeroToSuspendStreamWhenNothingIsInQueue() throws Exception { byte[] content = "Test123".getBytes(StandardCharsets.US_ASCII); diff --git a/client/src/test/java/org/asynchttpclient/request/body/generator/InputStreamBodyGeneratorTest.java b/client/src/test/java/org/asynchttpclient/request/body/generator/InputStreamBodyGeneratorTest.java index ed8b79f466..406d4d3d00 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/generator/InputStreamBodyGeneratorTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/generator/InputStreamBodyGeneratorTest.java @@ -15,11 +15,11 @@ */ package org.asynchttpclient.request.body.generator; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.asynchttpclient.request.body.Body; import org.asynchttpclient.request.body.Body.BodyState; +import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,7 +38,7 @@ public class InputStreamBodyGeneratorTest { private static final int CHUNK_SIZE = 1024 * 8; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void streamsAllBytesAcrossMultipleReads() throws IOException { final byte[] src = new byte[3 * CHUNK_SIZE + 42]; new Random().nextBytes(src); @@ -62,7 +62,7 @@ public void streamsAllBytesAcrossMultipleReads() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void singleReadDrainsASmallStream() throws IOException { final byte[] src = new byte[CHUNK_SIZE - 100]; // fits in one writable region, so one read drains it new Random().nextBytes(src); @@ -80,7 +80,7 @@ public void singleReadDrainsASmallStream() throws IOException { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void emptyStreamStopsImmediately() throws IOException { Body body = new InputStreamBodyGenerator(new ByteArrayInputStream(new byte[0])).createBody(); ByteBuf chunkBuffer = Unpooled.buffer(CHUNK_SIZE); @@ -96,7 +96,7 @@ public void emptyStreamStopsImmediately() throws IOException { // Locks the removal of the old "writableBytes() - 10" margin: with a writable region of 10 or fewer bytes the // margin made the transfer length 0 (or negative), so it silently STOPped without writing / threw. The stream // must now still be drained through a tiny target buffer. - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void smallWritableRegionStillTransfers() throws IOException { final byte[] src = new byte[25]; new Random().nextBytes(src); diff --git a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBasicAuthTest.java b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBasicAuthTest.java index 73fdcaa70d..e29ded8a72 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBasicAuthTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBasicAuthTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.request.body.multipart; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AbstractBasicTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.BasicAuthTest; @@ -24,7 +23,9 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.File; import java.util.function.Function; @@ -56,6 +57,12 @@ public void setUpGlobal() throws Exception { logger.info("Local HTTP server started successfully"); } + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + @Override public AbstractHandler configureHandler() throws Exception { return new BasicAuthTest.SimpleHandler(); @@ -72,12 +79,12 @@ private void expectHttpResponse(Function rb, 401); } - @RepeatedIfExceptionsTest(repeats = 3) + @Test public void unauthorizedNonPreemptiveRealmCausesServerToCloseSocket() throws Throwable { expectHttpResponse(rb -> rb.setRealm(basicAuthRealm(USER, "NOT-ADMIN")), 401); } @@ -96,12 +103,12 @@ private void expectSuccess(Function f) } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void authorizedPreemptiveRealmWorks() throws Exception { expectSuccess(rb -> rb.setRealm(basicAuthRealm(USER, ADMIN).setUsePreemptiveAuth(true))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void authorizedNonPreemptiveRealmWorksWithExpectContinue() throws Exception { expectSuccess(rb -> rb.setRealm(basicAuthRealm(USER, ADMIN)).setHeader(EXPECT, CONTINUE)); } diff --git a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBodyTest.java b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBodyTest.java index 7230948377..5ae23bcdfa 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBodyTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartBodyTest.java @@ -15,13 +15,13 @@ */ package org.asynchttpclient.request.body.multipart; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.EmptyHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import org.asynchttpclient.request.body.Body.BodyState; +import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -151,7 +151,7 @@ public int write(ByteBuffer src) { return transferred.get(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void transferWithCopy() throws Exception { for (int bufferLength = 1; bufferLength < MAX_MULTIPART_CONTENT_LENGTH_ESTIMATE + 1; bufferLength++) { try (MultipartBody multipartBody = buildMultipart()) { @@ -161,7 +161,7 @@ public void transferWithCopy() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void transferZeroCopy() throws Exception { for (int bufferLength = 1; bufferLength < MAX_MULTIPART_CONTENT_LENGTH_ESTIMATE + 1; bufferLength++) { try (MultipartBody multipartBody = buildMultipart()) { @@ -237,7 +237,7 @@ private static byte[] drain(MultipartBody body, BoundedChannel target, int maxIt * A target that refuses writes must not cost bytes and must not spin. Sweeps the chunk size so the * refusal lands at a different offset each time, including mid-part and mid-boundary. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void transferZeroCopyToTargetThatRefusesWrites() { // A part that spins on a refusing target never returns, so bound the whole sweep in wall time: // that is the shape issue #2216 took, and an assertion cannot observe it from the inside. @@ -267,7 +267,7 @@ public void transferZeroCopyToTargetThatRefusesWrites() { * A stream that hands over exactly its declared length must finish without the part reading again for * EOF. Socket-backed streams have nothing more to give and would block that extra read forever. */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void inputStreamPartFinishesOnDeclaredLengthWithoutWaitingForEof() { assertTimeoutPreemptively(Duration.ofSeconds(30), () -> { byte[] content = "declared length, no EOF to follow".getBytes(UTF_8); @@ -315,7 +315,7 @@ public synchronized int read(byte[] b, int off, int len) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void finishingChunkReportsStopAndCarriesAllBytes() throws Exception { try (MultipartBody multipartBody = buildMultipart()) { // A buffer large enough for the whole body: the single transferTo that writes the last bytes must diff --git a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java index 695f6c1a06..6ffe979599 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/multipart/MultipartUploadTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.request.body.multipart; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -30,7 +29,9 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,8 +67,9 @@ */ public class MultipartUploadTest extends AbstractBasicTest { + @Override @BeforeEach - public void setUp() throws Exception { + public void setUpGlobal() throws Exception { server = new Server(); ServerConnector connector = addHttpConnector(server); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); @@ -77,7 +79,13 @@ public void setUp() throws Exception { port1 = connector.getLocalPort(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Override + @AfterEach + public void tearDownGlobal() throws Exception { + super.tearDownGlobal(); + } + + @Test public void testSendingSmallFilesAndByteArray() throws Exception { String expectedContents = "filecontent: hello"; String expectedContents2 = "gzipcontent: hello"; @@ -159,12 +167,12 @@ private void sendEmptyFile0(boolean disableZeroCopy) throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void sendEmptyFile() throws Exception { sendEmptyFile0(true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void sendEmptyFileZeroCopy() throws Exception { sendEmptyFile0(false); } @@ -181,12 +189,12 @@ private void sendEmptyFileInputStream(boolean disableZeroCopy) throws Exception } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendEmptyFileInputStream() throws Exception { sendEmptyFileInputStream(true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendEmptyFileInputStreamZeroCopy() throws Exception { sendEmptyFileInputStream(false); } @@ -212,22 +220,22 @@ private void sendFileInputStream(boolean useContentLength, boolean disableZeroCo } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendFileInputStreamUnknownContentLength() throws Exception { sendFileInputStream(false, true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendFileInputStreamZeroCopyUnknownContentLength() throws Exception { sendFileInputStream(false, false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendFileInputStreamKnownContentLength() throws Exception { sendFileInputStream(true, true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSendFileInputStreamZeroCopyKnownContentLength() throws Exception { sendFileInputStream(true, false); } diff --git a/client/src/test/java/org/asynchttpclient/request/body/multipart/part/MultipartPartTest.java b/client/src/test/java/org/asynchttpclient/request/body/multipart/part/MultipartPartTest.java index ab88d45528..8f271ee7d9 100644 --- a/client/src/test/java/org/asynchttpclient/request/body/multipart/part/MultipartPartTest.java +++ b/client/src/test/java/org/asynchttpclient/request/body/multipart/part/MultipartPartTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.request.body.multipart.part; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.handler.codec.http.DefaultHttpHeaders; @@ -28,6 +27,7 @@ import org.asynchttpclient.request.body.multipart.StringPart; import org.asynchttpclient.request.body.multipart.part.PartVisitor.CounterPartVisitor; import org.asynchttpclient.test.TestUtils; +import org.junit.jupiter.api.Test; import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; @@ -41,7 +41,7 @@ public class MultipartPartTest { public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitStart() { TestFileLikePart fileLikePart = new TestFileLikePart("Name"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, new byte[10])) { @@ -51,7 +51,7 @@ public void testVisitStart() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitStartZeroSizedByteArray() { TestFileLikePart fileLikePart = new TestFileLikePart("Name"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -61,7 +61,7 @@ public void testVisitStartZeroSizedByteArray() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitDispositionHeaderWithoutFileName() { TestFileLikePart fileLikePart = new TestFileLikePart("Name"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -72,7 +72,7 @@ public void testVisitDispositionHeaderWithoutFileName() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitDispositionHeaderWithFileName() { TestFileLikePart fileLikePart = new TestFileLikePart("baPart", null, null, null, null, "fileName"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -83,7 +83,7 @@ public void testVisitDispositionHeaderWithFileName() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitDispositionHeaderWithoutName() { // with fileName TestFileLikePart fileLikePart = new TestFileLikePart(null, null, null, null, null, "fileName"); @@ -95,7 +95,7 @@ public void testVisitDispositionHeaderWithoutName() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitDispositionHeaderEscapesNameAndFileName() { TestFileLikePart fileLikePart = new TestFileLikePart("na\"me\r\nX-Injected: 1", null, null, null, null, "ev\"il\r\nfilename"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -112,7 +112,7 @@ public void testVisitDispositionHeaderEscapesNameAndFileName() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitContentTypeHeaderWithCharset() { TestFileLikePart fileLikePart = new TestFileLikePart(null, "application/test", UTF_8, null, null); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -123,7 +123,7 @@ public void testVisitContentTypeHeaderWithCharset() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitContentTypeHeaderWithoutCharset() { TestFileLikePart fileLikePart = new TestFileLikePart(null, "application/test"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -134,7 +134,7 @@ public void testVisitContentTypeHeaderWithoutCharset() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitTransferEncodingHeader() { TestFileLikePart fileLikePart = new TestFileLikePart(null, null, null, null, "transferEncoding"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -145,7 +145,7 @@ public void testVisitTransferEncodingHeader() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitContentIdHeader() { TestFileLikePart fileLikePart = new TestFileLikePart(null, null, null, "contentId"); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -156,7 +156,7 @@ public void testVisitContentIdHeader() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitCustomHeadersWhenNoCustomHeaders() { TestFileLikePart fileLikePart = new TestFileLikePart(null); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -167,7 +167,7 @@ public void testVisitCustomHeadersWhenNoCustomHeaders() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitCustomHeaders() { TestFileLikePart fileLikePart = new TestFileLikePart(null); fileLikePart.addCustomHeader("custom-header", "header-value"); @@ -178,7 +178,7 @@ public void testVisitCustomHeaders() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitEndOfHeaders() { TestFileLikePart fileLikePart = new TestFileLikePart(null); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -188,7 +188,7 @@ public void testVisitEndOfHeaders() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitPreContent() { TestFileLikePart fileLikePart = new TestFileLikePart("Name", "application/test", UTF_8, "contentId", "transferEncoding", "fileName"); fileLikePart.addCustomHeader("custom-header", "header-value"); @@ -199,7 +199,7 @@ public void testVisitPreContent() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testVisitPostContents() { TestFileLikePart fileLikePart = new TestFileLikePart(null); try (TestMultipartPart multipartPart = new TestMultipartPart(fileLikePart, EMPTY_BYTE_ARRAY)) { @@ -209,7 +209,7 @@ public void testVisitPostContents() { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void transferToShouldWriteStringPart() throws Exception { String text = FileUtils.readFileToString(TestUtils.resourceAsFile("test_sample_message.eml"), UTF_8); diff --git a/client/src/test/java/org/asynchttpclient/spnego/SpnegoEngineTest.java b/client/src/test/java/org/asynchttpclient/spnego/SpnegoEngineTest.java index 523ca40c84..e8cbd8b75b 100644 --- a/client/src/test/java/org/asynchttpclient/spnego/SpnegoEngineTest.java +++ b/client/src/test/java/org/asynchttpclient/spnego/SpnegoEngineTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.spnego; -import io.github.artsok.RepeatedIfExceptionsTest; import org.apache.commons.io.FileUtils; import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer; import org.asynchttpclient.AbstractBasicTest; @@ -82,7 +81,7 @@ public void startServers() throws Exception { FileUtils.copyInputStreamToFile(SpnegoEngine.class.getResourceAsStream("/kerberos.jaas"), loginConfig); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSpnegoGenerateTokenWithUsernamePassword() throws Exception { SpnegoEngine spnegoEngine = new SpnegoEngine("alice", "alice", @@ -110,7 +109,7 @@ public void testSpnegoGenerateTokenWithNullPasswordFail() { assertThrows(SpnegoEngineException.class, () -> spnegoEngine.generateToken("localhost"), "No password provided"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSpnegoGenerateTokenWithUsernamePasswordFail() throws Exception { SpnegoEngine spnegoEngine = new SpnegoEngine("alice", "wrong password", @@ -123,7 +122,7 @@ public void testSpnegoGenerateTokenWithUsernamePasswordFail() throws Exception { assertThrows(SpnegoEngineException.class, () -> spnegoEngine.generateToken("localhost")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSpnegoGenerateTokenWithCustomLoginConfig() throws Exception { Map loginConfig = new HashMap<>(); loginConfig.put("useKeyTab", "true"); @@ -146,7 +145,7 @@ public void testSpnegoGenerateTokenWithCustomLoginConfig() throws Exception { assertTrue(token.startsWith("YII")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetCompleteServicePrincipalName() throws Exception { { SpnegoEngine spnegoEngine = new SpnegoEngine(null, diff --git a/client/src/test/java/org/asynchttpclient/uri/UriParserTest.java b/client/src/test/java/org/asynchttpclient/uri/UriParserTest.java index 1e314f56db..d9d448dfa2 100644 --- a/client/src/test/java/org/asynchttpclient/uri/UriParserTest.java +++ b/client/src/test/java/org/asynchttpclient/uri/UriParserTest.java @@ -15,7 +15,7 @@ */ package org.asynchttpclient.uri; -import io.github.artsok.RepeatedIfExceptionsTest; +import org.junit.jupiter.api.Test; import java.net.URI; @@ -42,78 +42,78 @@ private static void validateAgainstRelativeURI(Uri uriContext, String urlContext assertUriEquals(parser, URI.create(urlContext).resolve(URI.create(url))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUrlWithPathAndQuery() { validateAgainstAbsoluteURI("http://example.com:8080/test?q=1"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testFragmentTryingToTrickAuthorityAsBasicAuthCredentials() { validateAgainstAbsoluteURI("http://1.2.3.4:81#@5.6.7.8:82/aaa/b?q=xxx"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUrlHasLeadingAndTrailingWhiteSpace() { String url = " http://user@example.com:8080/test?q=1 "; final UriParser parser = UriParser.parse(null, url); assertUriEquals(parser, URI.create(url.trim())); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testResolveAbsoluteUriAgainstContext() { Uri context = new Uri("https", null, "example.com", 80, "/path", "", null); validateAgainstRelativeURI(context, "https://example.com:80/path", "http://example.com/path"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRootRelativePath() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "/relativeUrl"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCurrentDirRelativePath() { Uri context = new Uri("https", null, "example.com", 80, "/foo/bar", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/foo/bar?q=2", "relativeUrl"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testFragmentOnly() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "#test"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUrlWithQuery() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "/relativePath?q=3"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUrlWithQueryOnly() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "?q=3"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeURLWithDots() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "./relative/./url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeURLWithTwoEmbeddedDots() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "./relative/../url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeURLWithTwoTrailingDots() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "./relative/url/.."); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeURLWithOneTrailingDot() { Uri context = new Uri("https", null, "example.com", 80, "/path", "q=2", null); validateAgainstRelativeURI(context, "https://example.com:80/path?q=2", "./relative/url/."); diff --git a/client/src/test/java/org/asynchttpclient/uri/UriTest.java b/client/src/test/java/org/asynchttpclient/uri/UriTest.java index ba1da7aa69..8634e45de8 100644 --- a/client/src/test/java/org/asynchttpclient/uri/UriTest.java +++ b/client/src/test/java/org/asynchttpclient/uri/UriTest.java @@ -15,8 +15,8 @@ */ package org.asynchttpclient.uri; -import io.github.artsok.RepeatedIfExceptionsTest; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import java.net.URI; @@ -45,136 +45,136 @@ private static void validateAgainstRelativeURI(String context, String url) { assertUriEquals(Uri.create(Uri.create(context), url), URI.create(context).resolve(URI.create(url))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testSimpleParsing() { validateAgainstAbsoluteURI("https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRootRelativeURIWithRootContext() { validateAgainstRelativeURI("https://graph.facebook.com", "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRootRelativeURIWithNonRootContext() { validateAgainstRelativeURI("https://graph.facebook.com/foo/bar", "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testNonRootRelativeURIWithNonRootContext() { validateAgainstRelativeURI("https://graph.facebook.com/foo/bar", "750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } @Disabled - @RepeatedIfExceptionsTest(repeats = 5) + @Test // FIXME weird: java.net.URI#getPath return "750198471659552/accounts/test-users" without a "/"?! public void testNonRootRelativeURIWithRootContext() { validateAgainstRelativeURI("https://graph.facebook.com", "750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testAbsoluteURIWithContext() { validateAgainstRelativeURI("https://hello.com/foo/bar", "https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithDots() { validateAgainstRelativeURI("https://hello.com/level1/level2/", "../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithDotsAboveRoot() { validateAgainstRelativeURI("https://hello.com/level1", "../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithAbsoluteDots() { validateAgainstRelativeURI("https://hello.com/level1/", "/../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDots() { validateAgainstRelativeURI("https://hello.com/level1/level2/", "../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDotsAboveRoot() { validateAgainstRelativeURI("https://hello.com/level1/level2", "../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithAbsoluteConsecutiveDots() { validateAgainstRelativeURI("https://hello.com/level1/level2/", "/../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDotsFromRoot() { validateAgainstRelativeURI("https://hello.com/", "../../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDotsFromRootResource() { validateAgainstRelativeURI("https://hello.com/level1", "../../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDotsFromSubrootResource() { validateAgainstRelativeURI("https://hello.com/level1/level2", "../../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithConsecutiveDotsFromLevel3Resource() { validateAgainstRelativeURI("https://hello.com/level1/level2/level3", "../../../other/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testRelativeUriWithNoScheme() { validateAgainstRelativeURI("https://hello.com/level1", "//world.org/content/img.png"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testCreateAndToUrl() { String url = "https://hello.com/level1/level2/level3"; Uri uri = Uri.create(url); assertEquals(url, uri.toUrl(), "url used to create uri and url returned from toUrl do not match"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToUrlWithUserInfoPortPathAndQuery() { Uri uri = new Uri("http", "user", "example.com", 44, "/path/path2", "query=4", null); assertEquals("http://user@example.com:44/path/path2?query=4", uri.toUrl(), "toUrl returned incorrect url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryWithNonRootPath() { Uri uri = Uri.create("http://hello.com/foo?query=value"); assertEquals("/foo", uri.getPath()); assertEquals("query=value", uri.getQuery()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryWithNonRootPathAndTrailingSlash() { Uri uri = Uri.create("http://hello.com/foo/?query=value"); assertEquals("/foo/", uri.getPath()); assertEquals("query=value", uri.getQuery()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryWithRootPath() { Uri uri = Uri.create("http://hello.com?query=value"); assertEquals("", uri.getPath()); assertEquals("query=value", uri.getQuery()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testQueryWithRootPathAndTrailingSlash() { Uri uri = Uri.create("http://hello.com/?query=value"); assertEquals("/", uri.getPath()); assertEquals("query=value", uri.getQuery()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWithNewScheme() { Uri uri = new Uri("http", "user", "example.com", 44, "/path/path2", "query=4", null); Uri newUri = uri.withNewScheme("https"); @@ -182,7 +182,7 @@ public void testWithNewScheme() { assertEquals("https://user@example.com:44/path/path2?query=4", newUri.toUrl(), "toUrl returned incorrect url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testUpperCaseSchemeIsSecured() { Uri uri = new Uri("HTTPS", null, "example.com", -1, "/", null, null); Uri.validateSupportedScheme(uri); @@ -195,7 +195,7 @@ public void testUpperCaseSchemeIsSecured() { assertTrue(wss.isWebSocket()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testMixedCaseSchemeIsNormalized() { Uri uri = new Uri("HtTp", "user", "example.com", 44, "/path", "query=4", null); assertEquals("http", uri.getScheme()); @@ -204,7 +204,7 @@ public void testMixedCaseSchemeIsNormalized() { assertTrue(uri.withNewScheme("HTTPS").isSecured()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testWithNewQuery() { Uri uri = new Uri("http", "user", "example.com", 44, "/path/path2", "query=4", null); Uri newUri = uri.withNewQuery("query2=10&query3=20"); @@ -212,21 +212,21 @@ public void testWithNewQuery() { assertEquals("http://user@example.com:44/path/path2?query2=10&query3=20", newUri.toUrl(), "toUrl returned incorrect url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToRelativeUrl() { Uri uri = new Uri("http", "user", "example.com", 44, "/path/path2", "query=4", null); String relativeUrl = uri.toRelativeUrl(); assertEquals("/path/path2?query=4", relativeUrl, "toRelativeUrl returned incorrect url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToRelativeUrlWithEmptyPath() { Uri uri = new Uri("http", "user", "example.com", 44, null, "query=4", null); String relativeUrl = uri.toRelativeUrl(); assertEquals("/?query=4", relativeUrl, "toRelativeUrl returned incorrect url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetSchemeDefaultPortHttpScheme() { String url = "https://hello.com/level1/level2/level3"; Uri uri = Uri.create(url); @@ -237,7 +237,7 @@ public void testGetSchemeDefaultPortHttpScheme() { assertEquals(80, uri2.getSchemeDefaultPort(), "schema default port should be 80 for http url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetSchemeDefaultPortWebSocketScheme() { String url = "wss://hello.com/level1/level2/level3"; Uri uri = Uri.create(url); @@ -248,7 +248,7 @@ public void testGetSchemeDefaultPortWebSocketScheme() { assertEquals(80, uri2.getSchemeDefaultPort(), "schema default port should be 80 for ws url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetExplicitPort() { String url = "http://hello.com/level1/level2/level3"; Uri uri = Uri.create(url); @@ -259,7 +259,7 @@ public void testGetExplicitPort() { assertEquals(8080, uri2.getExplicitPort(), "getExplicitPort should return the port given in the url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testEquals() { String url = "http://user@hello.com:8080/level1/level2/level3?q=1"; Uri createdUri = Uri.create(url); @@ -267,7 +267,7 @@ public void testEquals() { assertEquals(createdUri, constructedUri, "The equals method returned false for two equal urls"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test void testFragment() { String url = "http://user@hello.com:8080/level1/level2/level3?q=1"; String fragment = "foo"; @@ -278,13 +278,13 @@ void testFragment() { assertEquals(urlWithFragment, uri.toFullUrl(), "toFullUrl should return with fragment"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test void testRelativeFragment() { Uri uri = Uri.create(Uri.create("http://user@hello.com:8080"), "/level1/level2/level3?q=1#foo"); assertEquals("foo", uri.getFragment(), "fragment should be kept when computing a relative url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsWebsocket() { String url = "http://user@hello.com:8080/level1/level2/level3?q=1"; Uri uri = Uri.create(url); @@ -303,74 +303,74 @@ public void testIsWebsocket() { assertTrue(uri.isWebSocket(), "isWebSocket should return true for wss url"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void creatingUriWithDefinedSchemeAndHostWorks() { Uri.create("http://localhost"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void creatingUriWithMissingSchemeThrowsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> Uri.create("localhost")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void creatingUriWithMissingHostThrowsIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> Uri.create("http://")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetAuthority() { Uri uri = Uri.create("http://stackoverflow.com/questions/17814461/jacoco-maven-testng-0-test-coverage"); assertEquals("stackoverflow.com:80", uri.getAuthority(), "Incorrect authority returned from getAuthority"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetAuthorityWithPortInUrl() { Uri uri = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); assertEquals("stackoverflow.com:8443", uri.getAuthority(), "Incorrect authority returned from getAuthority"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetBaseUrl() { Uri uri = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); assertEquals("http://stackoverflow.com:8443", uri.getBaseUrl(), "Incorrect base URL returned from getBaseURL"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsSameBaseUrlReturnsFalseWhenPortDifferent() { Uri uri1 = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); Uri uri2 = Uri.create("http://stackoverflow.com:8442/questions/1057564/pretty-git-branch-graphs"); assertFalse(uri1.isSameBase(uri2), "Base URLs should be different, but true was returned from isSameBase"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsSameBaseUrlReturnsFalseWhenSchemeDifferent() { Uri uri1 = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); Uri uri2 = Uri.create("ws://stackoverflow.com:8443/questions/1057564/pretty-git-branch-graphs"); assertFalse(uri1.isSameBase(uri2), "Base URLs should be different, but true was returned from isSameBase"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsSameBaseUrlReturnsFalseWhenHostDifferent() { Uri uri1 = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); Uri uri2 = Uri.create("http://example.com:8443/questions/1057564/pretty-git-branch-graphs"); assertFalse(uri1.isSameBase(uri2), "Base URLs should be different, but true was returned from isSameBase"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsSameBaseUrlReturnsTrueWhenOneUriHasDefaultPort() { Uri uri1 = Uri.create("http://stackoverflow.com:80/questions/17814461/jacoco-maven-testng-0-test-coverage"); Uri uri2 = Uri.create("http://stackoverflow.com/questions/1057564/pretty-git-branch-graphs"); assertTrue(uri1.isSameBase(uri2), "Base URLs should be same, but false was returned from isSameBase"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetPathWhenPathIsNonEmpty() { Uri uri = Uri.create("http://stackoverflow.com:8443/questions/17814461/jacoco-maven-testng-0-test-coverage"); assertEquals("/questions/17814461/jacoco-maven-testng-0-test-coverage", uri.getNonEmptyPath(), "Incorrect path returned from getNonEmptyPath"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetPathWhenPathIsEmpty() { Uri uri = Uri.create("http://stackoverflow.com"); assertEquals("/", uri.getNonEmptyPath(), "Incorrect path returned from getNonEmptyPath"); @@ -381,7 +381,7 @@ public void testGetPathWhenPathIsEmpty() { * the older {@code getNonEmptyPath() + (query != null ? "?" + query : "")} concatenation; this locks in * that the two are byte-identical for representative origin-form request targets (no wire change). */ - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToRelativeUrlMatchesLegacyPathConcat() { for (String url : new String[]{ "http://example.com", // empty path @@ -397,20 +397,20 @@ public void testToRelativeUrlMatchesLegacyPathConcat() { "toRelativeUrl() must equal the legacy :path concatenation for " + url); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToUrlWithoutUserInfoDropsOnlyTheUserInfo() { Uri uri = Uri.create("https://user:pw@example.com:8443/secret/path?token=abc"); assertEquals("https://example.com:8443/secret/path?token=abc", uri.toUrlWithoutUserInfo()); assertTrue(uri.toUrl().contains("user:pw")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testToUrlWithoutUserInfoReturnsTheMemoisedUrlWhenThereIsNone() { Uri uri = Uri.create("https://example.com/path?q=1"); assertSame(uri.toUrl(), uri.toUrlWithoutUserInfo()); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testIsSameBaseFoldsHostCaseButOnlyInAscii() { Uri lower = Uri.create("https://example.com/a"); assertTrue(lower.isSameBase(Uri.create("https://EXAMPLE.com/b"))); diff --git a/client/src/test/java/org/asynchttpclient/util/HttpUtilsTest.java b/client/src/test/java/org/asynchttpclient/util/HttpUtilsTest.java index eda97ffa4c..06414d864e 100644 --- a/client/src/test/java/org/asynchttpclient/util/HttpUtilsTest.java +++ b/client/src/test/java/org/asynchttpclient/util/HttpUtilsTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.util; -import io.github.artsok.RepeatedIfExceptionsTest; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.asynchttpclient.DefaultAsyncHttpClientConfig; @@ -23,6 +22,7 @@ import org.asynchttpclient.Param; import org.asynchttpclient.Request; import org.asynchttpclient.uri.Uri; +import org.junit.jupiter.api.Test; import java.net.URLEncoder; import java.nio.ByteBuffer; @@ -52,44 +52,44 @@ private static String toUsAsciiString(ByteBuffer buf) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExtractCharsetWithoutQuotes() { Charset charset = HttpUtils.extractContentTypeCharsetAttribute("text/html; charset=iso-8859-1"); assertEquals(ISO_8859_1, charset); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExtractCharsetWithSingleQuotes() { Charset charset = HttpUtils.extractContentTypeCharsetAttribute("text/html; charset='iso-8859-1'"); assertEquals(ISO_8859_1, charset); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExtractCharsetWithDoubleQuotes() { Charset charset = HttpUtils.extractContentTypeCharsetAttribute("text/html; charset=\"iso-8859-1\""); assertEquals(ISO_8859_1, charset); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExtractCharsetWithDoubleQuotesAndSpaces() { Charset charset = HttpUtils.extractContentTypeCharsetAttribute("text/html; charset= \"iso-8859-1\" "); assertEquals(ISO_8859_1, charset); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testExtractCharsetFallsBackToUtf8() { Charset charset = HttpUtils.extractContentTypeCharsetAttribute(APPLICATION_JSON.toString()); assertNull(charset); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetHostHeader() { Uri uri = Uri.create("https://stackoverflow.com/questions/1057564/pretty-git-branch-graphs"); String hostHeader = HttpUtils.hostHeader(uri); assertEquals("stackoverflow.com", hostHeader, "Incorrect hostHeader returned"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testDefaultFollowRedirect() { Request request = Dsl.get("https://shieldblaze.com").setVirtualHost("shieldblaze.com").setFollowRedirect(false).build(); DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder().build(); @@ -97,7 +97,7 @@ public void testDefaultFollowRedirect() { assertFalse(followRedirect, "Default value of redirect should be false"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetFollowRedirectInRequest() { Request request = Dsl.get("https://stackoverflow.com/questions/1057564").setFollowRedirect(true).build(); DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder().build(); @@ -105,7 +105,7 @@ public void testGetFollowRedirectInRequest() { assertTrue(followRedirect, "Follow redirect must be true as set in the request"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetFollowRedirectInConfig() { Request request = Dsl.get("https://stackoverflow.com/questions/1057564").build(); DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); @@ -113,7 +113,7 @@ public void testGetFollowRedirectInConfig() { assertTrue(followRedirect, "Follow redirect should be equal to value specified in config when not specified in request"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testGetFollowRedirectPriorityGivenToRequest() { Request request = Dsl.get("https://stackoverflow.com/questions/1057564").setFollowRedirect(false).build(); DefaultAsyncHttpClientConfig config = new DefaultAsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); @@ -121,7 +121,7 @@ public void testGetFollowRedirectPriorityGivenToRequest() { assertFalse(followRedirect, "Follow redirect value set in request should be given priority"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void testComputeMultipartBoundary() { String allowed = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; Set boundaries = new HashSet<>(); @@ -146,42 +146,42 @@ private static void formUrlEncoding(Charset charset) throws Exception { assertEquals(ahcString, jdkString); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void formUrlEncodingShouldSupportUtf8Charset() throws Exception { formUrlEncoding(UTF_8); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void formUrlEncodingShouldSupportNonUtf8Charset() throws Exception { formUrlEncoding(Charset.forName("GBK")); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForPlainUriWithImplicitPort() { assertEquals("http://foo.com", HttpUtils.originHeader(Uri.create("ws://foo.com/bar"))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForPlainUriWithDefaultPort() { assertEquals("http://foo.com", HttpUtils.originHeader(Uri.create("ws://foo.com:80/bar"))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForPlainUriWithNonDefaultPort() { assertEquals("http://foo.com:81", HttpUtils.originHeader(Uri.create("ws://foo.com:81/bar"))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForSecuredUriWithImplicitPort() { assertEquals("https://foo.com", HttpUtils.originHeader(Uri.create("wss://foo.com/bar"))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForSecuredUriWithDefaultPort() { assertEquals("https://foo.com", HttpUtils.originHeader(Uri.create("wss://foo.com:443/bar"))); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test public void computeOriginForSecuredUriWithNonDefaultPort() { assertEquals("https://foo.com:444", HttpUtils.originHeader(Uri.create("wss://foo.com:444/bar"))); } diff --git a/client/src/test/java/org/asynchttpclient/ws/AbstractBasicWebSocketTest.java b/client/src/test/java/org/asynchttpclient/ws/AbstractBasicWebSocketTest.java index 4e1ea362de..81ef9c4160 100644 --- a/client/src/test/java/org/asynchttpclient/ws/AbstractBasicWebSocketTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/AbstractBasicWebSocketTest.java @@ -18,12 +18,18 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import static org.asynchttpclient.test.TestUtils.addHttpConnector; +import static org.junit.jupiter.api.Assertions.assertTrue; public abstract class AbstractBasicWebSocketTest extends AbstractBasicTest { + private int serversStarted; + private int serversStopped; + @Override @BeforeEach public void setUpGlobal() throws Exception { @@ -31,17 +37,31 @@ public void setUpGlobal() throws Exception { ServerConnector connector = addHttpConnector(server); server.setHandler(configureHandler()); server.start(); + serversStarted++; port1 = connector.getLocalPort(); logger.info("Local HTTP server started successfully"); } + // An override does not inherit @AfterAll. Without this annotation no server is ever stopped. @Override + @AfterEach public void tearDownGlobal() throws Exception { if (server != null) { server.stop(); + serversStopped++; } } + @AfterAll + public void assertEveryStartedServerWasStopped() { + // >= because ProxyTunnellingTest starts its own servers but stops them through this class. + assertTrue(serversStopped >= serversStarted, + "started " + serversStarted + " Jetty servers but stopped only " + serversStopped + + "; a lifecycle override most likely dropped its annotation"); + // For subclasses with their own setUpGlobal, which the counter above never sees. + assertTrue(server == null || server.isStopped(), "a Jetty server was still running at class end"); + } + @Override protected String getTargetUrl() { return String.format("ws://localhost:%d/", port1); diff --git a/client/src/test/java/org/asynchttpclient/ws/ByteMessageTest.java b/client/src/test/java/org/asynchttpclient/ws/ByteMessageTest.java index a265376494..2f4be6b075 100644 --- a/client/src/test/java/org/asynchttpclient/ws/ByteMessageTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/ByteMessageTest.java @@ -12,11 +12,13 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import static org.asynchttpclient.Dsl.asyncHttpClient; @@ -64,17 +66,20 @@ public void onBinaryFrame(byte[] frame, boolean finalFragment, int rsv) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoByte() throws Exception { echoByte0(false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoByteCompressed() throws Exception { echoByte0(true); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoTwoMessagesTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final CountDownLatch latch = new CountDownLatch(2); @@ -120,7 +125,8 @@ public void onBinaryFrame(byte[] frame, boolean finalFragment, int rsv) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoOnOpenMessagesTest() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final CountDownLatch latch = new CountDownLatch(2); @@ -165,7 +171,8 @@ public void onBinaryFrame(byte[] frame, boolean finalFragment, int rsv) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoFragments() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { final CountDownLatch latch = new CountDownLatch(1); diff --git a/client/src/test/java/org/asynchttpclient/ws/CloseCodeReasonMessageTest.java b/client/src/test/java/org/asynchttpclient/ws/CloseCodeReasonMessageTest.java index 94064953f8..21709c4452 100644 --- a/client/src/test/java/org/asynchttpclient/ws/CloseCodeReasonMessageTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/CloseCodeReasonMessageTest.java @@ -12,11 +12,11 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.testserver.HttpServer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.io.IOException; @@ -47,7 +47,7 @@ public void stopPlainServer() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onCloseWithCode() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -63,7 +63,7 @@ public void onCloseWithCode() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onCloseWithCodeServerClose() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -77,7 +77,7 @@ public void onCloseWithCodeServerClose() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void getWebSocketThrowsException() throws Throwable { final CountDownLatch latch = new CountDownLatch(1); @@ -105,7 +105,7 @@ public void onError(Throwable t) { latch.await(); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void wrongStatusCode() throws Exception { try (AsyncHttpClient client = asyncHttpClient()) { @@ -135,7 +135,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void wrongProtocolCode() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -188,6 +188,7 @@ public void onClose(WebSocket websocket, int code, String reason) { @Override public void onError(Throwable t) { t.printStackTrace(); + text.set("onError-" + t); latch.countDown(); } } diff --git a/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java b/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java index ce9cda3dc4..98130f1e32 100644 --- a/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/ProxyTunnellingTest.java @@ -15,7 +15,6 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; import org.asynchttpclient.proxy.ProxyServer; import org.eclipse.jetty.proxy.ConnectHandler; @@ -27,6 +26,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.util.concurrent.CountDownLatch; @@ -56,23 +56,25 @@ public void setUpGlobal() throws Exception { @Override @AfterAll public void tearDownGlobal() throws Exception { - server.stop(); - server2.stop(); + cleanup(); } + // The servers are created inside the test body and may be null here. @AfterEach public void cleanup() throws Exception { super.tearDownGlobal(); - server2.stop(); + if (server2 != null) { + server2.stop(); + } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoWSText() throws Exception { runTest(false); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoWSSText() throws Exception { runTest(true); diff --git a/client/src/test/java/org/asynchttpclient/ws/RedirectTest.java b/client/src/test/java/org/asynchttpclient/ws/RedirectTest.java index c0581d9a00..8c25d8c75a 100644 --- a/client/src/test/java/org/asynchttpclient/ws/RedirectTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/RedirectTest.java @@ -12,7 +12,6 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.asynchttpclient.AsyncHttpClient; @@ -22,6 +21,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.io.IOException; @@ -36,8 +36,9 @@ public class RedirectTest extends AbstractBasicWebSocketTest { + @Override @BeforeEach - public void setUpGlobals() throws Exception { + public void setUpGlobal() throws Exception { server = new Server(); ServerConnector connector1 = addHttpConnector(server); ServerConnector connector2 = addHttpConnector(server); @@ -60,7 +61,7 @@ public void handle(String s, Request request, HttpServletRequest httpServletRequ logger.info("Local HTTP server started successfully"); } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void testRedirectToWSResource() throws Exception { try (AsyncHttpClient c = asyncHttpClient(config().setFollowRedirect(true))) { diff --git a/client/src/test/java/org/asynchttpclient/ws/TextMessageTest.java b/client/src/test/java/org/asynchttpclient/ws/TextMessageTest.java index 3d5b19e813..0452b12f87 100644 --- a/client/src/test/java/org/asynchttpclient/ws/TextMessageTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/TextMessageTest.java @@ -12,8 +12,8 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.net.ConnectException; @@ -30,7 +30,7 @@ public class TextMessageTest extends AbstractBasicWebSocketTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onOpen() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -61,7 +61,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onEmptyListenerTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -75,7 +75,7 @@ public void onEmptyListenerTest() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onFailureTest() throws Throwable { try (AsyncHttpClient c = asyncHttpClient()) { @@ -87,7 +87,7 @@ public void onFailureTest() throws Throwable { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onTimeoutCloseTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -118,7 +118,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void onClose() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -151,7 +151,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoText() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -189,7 +189,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoDoubleListenerText() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -249,7 +249,8 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoTwoMessagesTest() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { final CountDownLatch latch = new CountDownLatch(2); @@ -286,7 +287,8 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoFragments() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { final CountDownLatch latch = new CountDownLatch(1); @@ -324,7 +326,7 @@ public void onError(Throwable t) { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void echoTextAndThenClose() throws Throwable { try (AsyncHttpClient c = asyncHttpClient()) { diff --git a/client/src/test/java/org/asynchttpclient/ws/WebSocketRedirectRefusalTest.java b/client/src/test/java/org/asynchttpclient/ws/WebSocketRedirectRefusalTest.java index 0d5d8c9a46..f832ec18b0 100644 --- a/client/src/test/java/org/asynchttpclient/ws/WebSocketRedirectRefusalTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/WebSocketRedirectRefusalTest.java @@ -25,7 +25,6 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -47,9 +46,6 @@ /** * {@code wss} to {@code ws} is a cleartext downgrade, and RFC 6455 section 4.1 leaves a client free not to * follow it. The WebSocket path reaches the same interceptor as HTTP. - *

- * Both fixture methods are re-annotated because the base class drops the annotation when it overrides - * {@code tearDownGlobal}, so declaring only half the pair starts a server per test and stops none. */ public class WebSocketRedirectRefusalTest extends AbstractBasicWebSocketTest { @@ -78,14 +74,6 @@ public void handle(String path, Request request, HttpServletRequest servletReque port2 = secure.getLocalPort(); } - @Override - @AfterEach - public void tearDownGlobal() throws Exception { - if (server != null) { - server.stop(); - } - } - @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void downgradeToCleartextIsRefused() throws Exception { diff --git a/client/src/test/java/org/asynchttpclient/ws/WebSocketWriteFutureTest.java b/client/src/test/java/org/asynchttpclient/ws/WebSocketWriteFutureTest.java index e0edc54998..2c56f76ebb 100644 --- a/client/src/test/java/org/asynchttpclient/ws/WebSocketWriteFutureTest.java +++ b/client/src/test/java/org/asynchttpclient/ws/WebSocketWriteFutureTest.java @@ -15,19 +15,27 @@ */ package org.asynchttpclient.ws; -import io.github.artsok.RepeatedIfExceptionsTest; import org.asynchttpclient.AsyncHttpClient; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; +import java.nio.channels.ClosedChannelException; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import static org.asynchttpclient.Dsl.asyncHttpClient; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * The {@code *ExpectFailure} tests wait for {@code onClose}, which fires just before the channel closes. That + * is enough on {@code ws://}: the send is queued behind the close on the same event loop. Not verified for TLS. + */ public class WebSocketWriteFutureTest extends AbstractBasicWebSocketTest { - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendTextMessage() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -35,19 +43,20 @@ public void sendTextMessage() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendTextMessageExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendTextFrame("TEXT").get(10, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendTextFrame("TEXT").get(TIMEOUT, TimeUnit.SECONDS))); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendByteMessage() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -55,19 +64,20 @@ public void sendByteMessage() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendByteMessageExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendBinaryFrame("BYTES".getBytes()).get(10, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendBinaryFrame("BYTES".getBytes()).get(TIMEOUT, TimeUnit.SECONDS))); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendPingMessage() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -75,19 +85,20 @@ public void sendPingMessage() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendPingMessageExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendPingFrame("PING".getBytes()).get(10, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendPingFrame("PING".getBytes()).get(TIMEOUT, TimeUnit.SECONDS))); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendPongMessage() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -95,19 +106,20 @@ public void sendPongMessage() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void sendPongMessageExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendPongFrame("PONG".getBytes()).get(1, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendPongFrame("PONG".getBytes()).get(TIMEOUT, TimeUnit.SECONDS))); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void streamBytes() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { @@ -115,19 +127,21 @@ public void streamBytes() throws Exception { } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void streamBytesExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendBinaryFrame("STREAM".getBytes(), true, 0).get(1, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendBinaryFrame("STREAM".getBytes(), true, 0).get(TIMEOUT, TimeUnit.SECONDS))); } } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void streamText() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { getWebSocket(c).sendTextFrame("STREAM", true, 0).get(1, TimeUnit.SECONDS); @@ -135,17 +149,23 @@ public void streamText() throws Exception { } - @RepeatedIfExceptionsTest(repeats = 5) + @Test + @Timeout(unit = TimeUnit.MILLISECONDS, value = 60000) public void streamTextExpectFailure() throws Exception { try (AsyncHttpClient c = asyncHttpClient()) { CountDownLatch closeLatch = new CountDownLatch(1); WebSocket websocket = getWebSocket(c, closeLatch); websocket.sendCloseFrame(); - closeLatch.await(1, TimeUnit.SECONDS); - assertThrows(Exception.class, () -> websocket.sendTextFrame("STREAM", true, 0).get(1, TimeUnit.SECONDS)); + assertTrue(closeLatch.await(TIMEOUT, TimeUnit.SECONDS), "the close handshake never completed"); + assertClosedChannel(assertThrows(ExecutionException.class, + () -> websocket.sendTextFrame("STREAM", true, 0).get(TIMEOUT, TimeUnit.SECONDS))); } } + private static void assertClosedChannel(ExecutionException e) { + assertInstanceOf(ClosedChannelException.class, e.getCause()); + } + private WebSocket getWebSocket(final AsyncHttpClient c) throws Exception { return c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().build()).get(); }