From 034cd65aa52f8cba5172c51116638c72f56d3aa8 Mon Sep 17 00:00:00 2001 From: Oleg Kalnichevski Date: Wed, 19 Jun 2024 17:06:45 +0200 Subject: [PATCH] Redesign of test server APIs and integration test setup --- ...ractHttpAsyncClientAuthenticationTest.java | 169 +++----- .../AbstractHttpAsyncFundamentalsTest.java | 59 ++- .../async/AbstractHttpAsyncRedirectsTest.java | 394 +++++++++-------- .../AbstractHttpReactiveFundamentalsTest.java | 75 ++-- .../async/AbstractIntegrationTestBase.java | 84 ++-- .../testing/async/HttpIntegrationTests.java | 78 ++-- .../hc/client5/testing/async/TestH2Async.java | 19 +- .../testing/async/TestH2AsyncMinimal.java | 19 +- .../testing/async/TestH2AsyncRedirect.java | 22 +- .../async/TestH2ClientAuthentication.java | 65 +-- .../client5/testing/async/TestH2Reactive.java | 19 +- .../testing/async/TestH2ReactiveMinimal.java | 20 +- .../client5/testing/async/TestHttp1Async.java | 48 +-- .../testing/async/TestHttp1AsyncMinimal.java | 29 +- .../async/TestHttp1AsyncRedirects.java | 69 ++- .../TestHttp1AsyncStatefulConnManagement.java | 38 +- .../async/TestHttp1ClientAuthentication.java | 86 +--- .../testing/async/TestHttp1Reactive.java | 43 +- .../async/TestHttp1ReactiveMinimal.java | 31 +- .../async/TestHttp1RequestReExecution.java | 32 +- .../TestHttpAsyncMinimalTlsHandshake.java | 43 +- .../async/TestHttpAsyncProtocolPolicy.java | 35 +- .../async/extension/ClientProtocolLevel.java | 34 ++ .../H2OnlyMinimalTestClientBuilder.java | 82 ++++ .../extension/H2OnlyTestClientBuilder.java | 136 ++++++ .../extension/MinimalTestClientBuilder.java | 111 +++++ .../async/extension/ServerProtocolLevel.java | 34 ++ .../extension/StandardTestClientBuilder.java | 174 ++++++++ .../async/extension/TestAsyncClient.java | 117 ++++++ .../extension/TestAsyncClientBuilder.java | 106 +++++ .../async/extension/TestAsyncResources.java | 219 +++------- .../async/extension/TestAsyncServer.java | 101 +++++ .../extension/TestAsyncServerBootstrap.java | 133 ++++++ .../hc/client5/testing/fluent/TestFluent.java | 95 ++--- .../sync/AbstractIntegrationTestBase.java | 81 ++++ .../sync/TestBasicConnectionManager.java | 40 +- .../sync/TestClientAuthentication.java | 292 ++++++------- .../sync/TestClientRequestExecution.java | 89 ++-- .../sync/TestConnectionManagement.java | 75 ++-- .../testing/sync/TestConnectionReuse.java | 124 ++---- .../testing/sync/TestContentCodings.java | 133 +++--- .../testing/sync/TestCookieVirtualHost.java | 86 ++-- .../sync/TestIdleConnectionEviction.java | 25 +- .../TestMinimalClientRequestExecution.java | 33 +- .../client5/testing/sync/TestRedirects.java | 396 +++++++++--------- .../sync/TestStatefulConnManagement.java | 56 ++- .../sync/extension/ClientProtocolLevel.java | 34 ++ .../extension/MinimalTestClientBuilder.java | 83 ++++ .../extension/StandardTestClientBuilder.java | 159 +++++++ .../testing/sync/extension/TestClient.java | 77 ++++ .../sync/extension/TestClientBuilder.java | 94 +++++ .../sync/extension/TestClientResources.java | 133 ++---- .../testing/sync/extension/TestServer.java | 67 +++ .../sync/extension/TestServerBootstrap.java | 123 ++++++ .../impl/classic/CloseableHttpResponse.java | 7 +- 55 files changed, 3060 insertions(+), 1966 deletions(-) create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ClientProtocolLevel.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyMinimalTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/MinimalTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ServerProtocolLevel.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/StandardTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClient.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServer.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServerBootstrap.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/AbstractIntegrationTestBase.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/ClientProtocolLevel.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/MinimalTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/StandardTestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClient.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientBuilder.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServer.java create mode 100644 httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServerBootstrap.java diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthenticationTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthenticationTest.java index f9867fde5..75a27f582 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthenticationTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthenticationTest.java @@ -36,10 +36,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; import java.util.stream.Collectors; -import org.apache.hc.client5.http.AuthenticationStrategy; import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; @@ -52,73 +50,44 @@ import org.apache.hc.client5.http.auth.StandardAuthScheme; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.auth.BasicAuthCache; import org.apache.hc.client5.http.impl.auth.BasicScheme; import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.BasicTestAuthenticator; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.client5.testing.auth.Authenticator; import org.apache.hc.client5.testing.auth.BearerAuthenticationHandler; -import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.HttpRequestInterceptor; import org.apache.hc.core5.http.HttpResponse; -import org.apache.hc.core5.http.HttpResponseInterceptor; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Lookup; import org.apache.hc.core5.http.config.Registry; import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; import org.apache.hc.core5.http.support.BasicResponseBuilder; import org.apache.hc.core5.net.URIAuthority; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public abstract class AbstractHttpAsyncClientAuthenticationTest extends AbstractIntegrationTestBase { +public abstract class AbstractHttpAsyncClientAuthenticationTest extends AbstractIntegrationTestBase { - public AbstractHttpAsyncClientAuthenticationTest(final URIScheme scheme) { - super(scheme); - } - - abstract protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception; - - protected H2TestServer startServer() throws Exception { - return startServer(requestHandler -> new AuthenticatingAsyncDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm"))); - } - - interface TestClientBuilder { - - TestClientBuilder setDefaultAuthSchemeRegistry(Lookup authSchemeRegistry); - - TestClientBuilder setTargetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy); - - TestClientBuilder addResponseInterceptor(HttpResponseInterceptor responseInterceptor); - - TestClientBuilder addRequestInterceptor(HttpRequestInterceptor requestInterceptor); - - } - - abstract protected T startClientCustom(final Consumer clientCustomizer) throws Exception; - - T startClient() throws Exception { - return startClientCustom(c -> {}); + public AbstractHttpAsyncClientAuthenticationTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { + super(scheme, clientProtocolLevel, serverProtocolLevel); } @Test public void testBasicAuthenticationNoCreds() throws Exception { - final H2TestServer server = startServer(); - server.register("*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); + configureServer(bootstrap -> bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); final HttpClientContext context = HttpClientContext.create(); @@ -138,11 +107,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -164,11 +132,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -191,11 +158,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -218,11 +184,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -244,11 +209,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -272,12 +236,12 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); final DefaultAuthenticationStrategy authStrategy = Mockito.spy(new DefaultAuthenticationStrategy()); - final T client = startClientCustom(builder -> builder.setTargetAuthenticationStrategy(authStrategy)); + configureClient(builder -> builder.setTargetAuthenticationStrategy(authStrategy)); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); context.setCredentialsProvider(CredentialsProviderBuilder.create() @@ -299,17 +263,17 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); final DefaultAuthenticationStrategy authStrategy = Mockito.spy(new DefaultAuthenticationStrategy()); final Queue responseQueue = new ConcurrentLinkedQueue<>(); - final T client = startClientCustom(builder -> builder + configureClient(builder -> builder .setTargetAuthenticationStrategy(authStrategy) - .addResponseInterceptor((response, entity, context) + .addResponseInterceptorFirst((response, entity, context) -> responseQueue.add(BasicResponseBuilder.copy(response).build()))); + final TestAsyncClient client = startClient(); final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create() .add(target, "test", "test".toCharArray()) @@ -364,11 +328,10 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest bootstrap.register("*", AsyncEchoHandler::new)); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute(SimpleRequestBuilder.get() @@ -396,17 +359,18 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest new AuthenticatingAsyncDecorator(exchangeHandler, authenticator) { + final HttpHost target = startServer(); + configureServer(bootstrap -> bootstrap + .register("*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new AuthenticatingAsyncDecorator(exchangeHandler, authenticator) { - @Override - protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { - unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE); - unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\""); - } + @Override + protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { + unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE); + unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\""); + } - }); - server.register("*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); + })); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -425,7 +389,9 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest builder.setDefaultAuthSchemeRegistry(authSchemeRegistry)); + configureClient(builder -> builder.setDefaultAuthSchemeRegistry(authSchemeRegistry)); + final TestAsyncClient client = startClient(); + final RequestConfig config = RequestConfig.custom() .setTargetPreferredAuthSchemes(Collections.singletonList("MyBasic")) @@ -448,18 +414,19 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) { + final HttpHost target = startServer(); + configureServer(bootstrap -> bootstrap + .register("*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) { - @Override - protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { - unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid"); - } + @Override + protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { + unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid"); + } - }); - server.register("*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); + })); - final T client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -489,15 +456,17 @@ public abstract class AbstractHttpAsyncClientAuthenticationTest - new AuthenticatingAsyncDecorator( - requestHandler, - new BearerAuthenticationHandler(), - new BasicTestAuthenticator(token, "test realm"))); - server.register("*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); - final T client = startClient(); + final HttpHost target = startServer(); + configureServer(bootstrap -> bootstrap + .register("*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingAsyncDecorator( + requestHandler, + new BearerAuthenticationHandler(), + new BasicTestAuthenticator(token, "test realm")))); + + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); final HttpClientContext context1 = HttpClientContext.create(); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java index 05f818b3e..4b0d40ac9 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncFundamentalsTest.java @@ -40,8 +40,10 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHost; @@ -53,26 +55,22 @@ import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer; import org.apache.hc.core5.http.nio.support.BasicRequestProducer; import org.apache.hc.core5.http.nio.support.BasicResponseConsumer; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; -public abstract class AbstractHttpAsyncFundamentalsTest extends AbstractIntegrationTestBase { +public abstract class AbstractHttpAsyncFundamentalsTest extends AbstractIntegrationTestBase { - protected AbstractHttpAsyncFundamentalsTest(final URIScheme scheme) { - super(scheme); + protected AbstractHttpAsyncFundamentalsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { + super(scheme, clientProtocolLevel, serverProtocolLevel); } - abstract protected H2TestServer startServer() throws Exception; - - abstract protected T startClient() throws Exception; - @Test public void testSequentialGetRequests() throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); + for (int i = 0; i < 3; i++) { final Future future = client.execute( SimpleRequestBuilder.get() @@ -90,10 +88,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); + final TestAsyncClient client = startClient(); for (int i = 0; i < 3; i++) { final Future future = client.execute( SimpleRequestBuilder.head() @@ -110,10 +107,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest bootstrap.register("/echo/*", AsyncEchoHandler::new)); + final HttpHost target = startServer(); + final TestAsyncClient client = startClient(); for (int i = 0; i < 3; i++) { final byte[] b1 = new byte[1024]; final Random rnd = new Random(System.currentTimeMillis()); @@ -133,10 +129,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest bootstrap.register("/echo/*", AsyncEchoHandler::new)); + final HttpHost target = startServer(); + final TestAsyncClient client = startClient(); final byte[] b1 = new byte[1024]; final Random rnd = new Random(System.currentTimeMillis()); rnd.nextBytes(b1); @@ -165,10 +160,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); + final TestAsyncClient client = startClient(); final int requestNum = 50; final AtomicInteger count = new AtomicInteger(requestNum); final Queue resultQueue = new ConcurrentLinkedQueue<>(); @@ -233,10 +227,9 @@ public abstract class AbstractHttpAsyncFundamentalsTest bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); + final TestAsyncClient client = startClient(); final Future future = client.execute( SimpleRequestBuilder.get() .setHttpHost(target) diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java index 0f9d97356..4d4b0952d 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncRedirectsTest.java @@ -41,13 +41,15 @@ import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.cookie.BasicCookieStore; import org.apache.hc.client5.http.cookie.CookieStore; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.OldPathRedirectResolver; -import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; +import org.apache.hc.client5.testing.async.extension.TestAsyncServer; +import org.apache.hc.client5.testing.async.extension.TestAsyncServerBootstrap; import org.apache.hc.client5.testing.redirect.Redirect; -import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpException; @@ -55,48 +57,31 @@ import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; -import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; import org.apache.hc.core5.http.protocol.HttpCoreContext; -import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.net.URIBuilder; -import org.apache.hc.core5.reactor.IOReactorConfig; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.util.TimeValue; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public abstract class AbstractHttpAsyncRedirectsTest extends AbstractIntegrationTestBase { +public abstract class AbstractHttpAsyncRedirectsTest extends AbstractIntegrationTestBase { - private final HttpVersion version; - - public AbstractHttpAsyncRedirectsTest(final URIScheme scheme, final HttpVersion version) { - super(scheme); - this.version = version; + public AbstractHttpAsyncRedirectsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { + super(scheme, clientProtocolLevel, serverProtocolLevel); } - abstract protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception; - - protected H2TestServer startServer() throws Exception { - return startServer(null); - } - - abstract protected T startClient() throws Exception; - @Test public void testBasicRedirect300() throws Exception { - final H2TestServer server = startServer(exchangeHandler -> new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES))); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES)))); + final HttpHost target = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -115,13 +100,14 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY)))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -141,13 +127,14 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -167,19 +154,20 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.startsWith("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); - } - return null; - })); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); + } + return null; + }))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -198,13 +186,15 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER)))); - final T client = startClient(); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -224,19 +214,19 @@ public abstract class AbstractHttpAsyncRedirectsTest new AbstractSimpleServerExchangeHandler() { + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .register("/oldlocation/*", () -> new AbstractSimpleServerExchangeHandler() { - @Override - protected SimpleHttpResponse handle(final SimpleHttpRequest request, - final HttpCoreContext context) throws HttpException { - return SimpleHttpResponse.create(HttpStatus.SC_NOT_MODIFIED, (String) null); - } - }); - final HttpHost target = targetHost(); + @Override + protected SimpleHttpResponse handle(final SimpleHttpRequest request, + final HttpCoreContext context) throws HttpException { + return SimpleHttpResponse.create(HttpStatus.SC_NOT_MODIFIED, (String) null); + } + })); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -255,19 +245,19 @@ public abstract class AbstractHttpAsyncRedirectsTest new AbstractSimpleServerExchangeHandler() { + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .register("/oldlocation/*", () -> new AbstractSimpleServerExchangeHandler() { - @Override - protected SimpleHttpResponse handle(final SimpleHttpRequest request, - final HttpCoreContext context) throws HttpException { - return SimpleHttpResponse.create(HttpStatus.SC_USE_PROXY, (String) null); - } - }); - final HttpHost target = targetHost(); + @Override + protected SimpleHttpResponse handle(final SimpleHttpRequest request, + final HttpCoreContext context) throws HttpException { + return SimpleHttpResponse.create(HttpStatus.SC_USE_PROXY, (String) null); + } + })); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -286,13 +276,14 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT)))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -312,14 +303,15 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", - HttpStatus.SC_MOVED_TEMPORARILY))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(true) @@ -337,14 +329,15 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", - HttpStatus.SC_MOVED_TEMPORARILY))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY)))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(false) @@ -363,14 +356,14 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_TEMPORARY_REDIRECT))); + configureServer(bootstrap -> bootstrap + .register("/echo/*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_TEMPORARY_REDIRECT)))); + final HttpHost target = startServer(); - server.register("/echo/*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -391,14 +384,14 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER))); + configureServer(bootstrap -> bootstrap + .register("/echo/*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER)))); + final HttpHost target = startServer(); - server.register("/echo/*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( @@ -419,21 +412,21 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.startsWith("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); - } - return null; - })); + } + return null; + }))); + final HttpHost target = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); @@ -454,21 +447,21 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/random/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/random/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); - } - return null; - })); + } + return null; + }))); + final HttpHost target = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); @@ -489,20 +482,21 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/oldlocation/")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation/")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); - } - return null; - })); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + } + return null; + }))); + final HttpHost target = startServer(); - final T client = startClient(); + final TestAsyncClient client = startClient(); final ExecutionException exception = Assertions.assertThrows(ExecutionException.class, () -> { final Future future = client.execute( @@ -517,20 +511,20 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/oldlocation/")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation/")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); + } + return null; + }))); + final HttpHost target = startServer(); - } - return null; - })); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); + final TestAsyncClient client = startClient(); final ExecutionException exception = Assertions.assertThrows(ExecutionException.class, () -> { final Future future = client.execute( @@ -545,16 +539,16 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); final CookieStore cookieStore = new BasicCookieStore(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); - - final T client = startClient(); - final HttpClientContext context = HttpClientContext.create(); context.setCookieStore(cookieStore); @@ -584,38 +578,34 @@ public abstract class AbstractHttpAsyncRedirectsTest new RedirectingAsyncDecorator( - exchangeHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/oldlocation")) { - final URI location = new URIBuilder(requestUri) - .setHttpHost(redirectTarget) - .setPath("/random/100") - .build(); - return new Redirect(HttpStatus.SC_MOVED_PERMANENTLY, location.toString()); - } - return null; - })); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + final URI location = new URIBuilder(requestUri) + .setHttpHost(redirectTarget) + .setPath("/random/100") + .build(); + return new Redirect(HttpStatus.SC_MOVED_PERMANENTLY, location.toString()); + } + return null; + }))); + final HttpHost target = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + final TestAsyncClient client = startClient(); - final T client = startClient(); - - final HttpClientContext context = HttpClientContext.create(); + final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute( SimpleRequestBuilder.get() .setHttpHost(target) diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpReactiveFundamentalsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpReactiveFundamentalsTest.java index 04b8cafb9..1d2df6cd3 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpReactiveFundamentalsTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpReactiveFundamentalsTest.java @@ -51,8 +51,10 @@ import java.util.concurrent.atomic.AtomicReference; import io.reactivex.rxjava3.core.Flowable; import io.reactivex.rxjava3.schedulers.Schedulers; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHost; @@ -64,7 +66,6 @@ import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder; import org.apache.hc.core5.reactive.ReactiveEntityProducer; import org.apache.hc.core5.reactive.ReactiveResponseConsumer; import org.apache.hc.core5.reactive.ReactiveServerExchangeHandler; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.testing.reactive.Reactive3TestUtils; import org.apache.hc.core5.testing.reactive.Reactive3TestUtils.StreamDescription; import org.apache.hc.core5.testing.reactive.ReactiveEchoProcessor; @@ -76,24 +77,20 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import org.reactivestreams.Publisher; -public abstract class AbstractHttpReactiveFundamentalsTest extends AbstractIntegrationTestBase { +public abstract class AbstractHttpReactiveFundamentalsTest extends AbstractIntegrationTestBase { - public AbstractHttpReactiveFundamentalsTest(final URIScheme scheme) { - super(scheme); + public AbstractHttpReactiveFundamentalsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { + super(scheme, clientProtocolLevel, serverProtocolLevel); } - abstract protected H2TestServer startServer() throws Exception; - - abstract protected T startClient() throws Exception; - @Test @Timeout(value = 60_000, unit = MILLISECONDS) public void testSequentialGetRequests() throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", () -> - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap + .register("/random/*", () -> new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); for (int i = 0; i < 3; i++) { final ReactiveResponseConsumer consumer = new ReactiveResponseConsumer(); @@ -112,11 +109,11 @@ public abstract class AbstractHttpReactiveFundamentalsTest - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/random/*", () -> + new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); for (int i = 0; i < 3; i++) { final ReactiveResponseConsumer consumer = new ReactiveResponseConsumer(); @@ -134,11 +131,11 @@ public abstract class AbstractHttpReactiveFundamentalsTest - new ReactiveServerExchangeHandler(new ReactiveEchoProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/echo/*", () -> + new ReactiveServerExchangeHandler(new ReactiveEchoProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); for (int i = 0; i < 3; i++) { final byte[] b1 = new byte[1024]; final Random rnd = new Random(System.currentTimeMillis()); @@ -164,11 +161,11 @@ public abstract class AbstractHttpReactiveFundamentalsTest - new ReactiveServerExchangeHandler(new ReactiveEchoProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/echo/*", () -> + new ReactiveServerExchangeHandler(new ReactiveEchoProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); final int reqCount = 500; final int maxSize = 128 * 1024; @@ -213,11 +210,11 @@ public abstract class AbstractHttpReactiveFundamentalsTest - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/random/*", () -> + new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); final int requestNum = 50; final AtomicInteger count = new AtomicInteger(requestNum); final Queue>> resultQueue = new ConcurrentLinkedQueue<>(); @@ -275,11 +272,11 @@ public abstract class AbstractHttpReactiveFundamentalsTest - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); - final T client = startClient(); + configureServer(bootstrap -> bootstrap.register("/random/*", () -> + new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); + + final TestAsyncClient client = startClient(); final AsyncRequestProducer request = AsyncRequestBuilder.get(target + "/random/boom").build(); final ReactiveResponseConsumer consumer = new ReactiveResponseConsumer(); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractIntegrationTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractIntegrationTestBase.java index 3e80e3e86..09867e97a 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractIntegrationTestBase.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractIntegrationTestBase.java @@ -27,24 +27,18 @@ package org.apache.hc.client5.testing.async; +import java.net.InetSocketAddress; import java.util.function.Consumer; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder; -import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; -import org.apache.hc.client5.http.impl.async.MinimalH2AsyncClient; -import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; -import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; -import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; +import org.apache.hc.client5.testing.async.extension.TestAsyncClientBuilder; import org.apache.hc.client5.testing.async.extension.TestAsyncResources; -import org.apache.hc.core5.function.Decorator; +import org.apache.hc.client5.testing.async.extension.TestAsyncServer; +import org.apache.hc.client5.testing.async.extension.TestAsyncServerBootstrap; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.http.protocol.HttpProcessor; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.extension.RegisterExtension; @@ -55,68 +49,40 @@ public abstract class AbstractIntegrationTestBase { @RegisterExtension private final TestAsyncResources testResources; - protected AbstractIntegrationTestBase(final URIScheme scheme) { - this.testResources = new TestAsyncResources(scheme, TIMEOUT); + protected AbstractIntegrationTestBase(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { + this.testResources = new TestAsyncResources(scheme, clientProtocolLevel, serverProtocolLevel, TIMEOUT); } public URIScheme scheme() { return testResources.scheme(); } - public H2TestServer startServer( - final H2Config h2Config, - final HttpProcessor httpProcessor, - final Decorator exchangeHandlerDecorator) throws Exception { - return testResources.startServer(h2Config, httpProcessor, exchangeHandlerDecorator); + public ServerProtocolLevel getServerProtocolLevel() { + return testResources.getServerProtocolLevel(); } - public H2TestServer startServer( - final Http1Config http1Config, - final HttpProcessor httpProcessor, - final Decorator exchangeHandlerDecorator) throws Exception { - return testResources.startServer(http1Config, httpProcessor, exchangeHandlerDecorator); + public ClientProtocolLevel getClientProtocolLevel() { + return testResources.getClientProtocolLevel(); } - public HttpHost targetHost() { - return testResources.targetHost(); + public void configureServer(final Consumer serverCustomizer) { + testResources.configureServer(serverCustomizer); } - public CloseableHttpAsyncClient startClient( - final Consumer connManagerCustomizer, - final Consumer clientCustomizer) throws Exception { - return testResources.startClient(connManagerCustomizer, clientCustomizer); + public HttpHost startServer() throws Exception { + final TestAsyncServer server = testResources.server(); + final InetSocketAddress inetSocketAddress = server.start(); + return new HttpHost(testResources.scheme().id, "localhost", inetSocketAddress.getPort()); } - public CloseableHttpAsyncClient startClient( - final Consumer clientCustomizer) throws Exception { - return testResources.startClient(clientCustomizer); + public void configureClient(final Consumer clientCustomizer) { + testResources.configureClient(clientCustomizer); } - public PoolingAsyncClientConnectionManager connManager() { - return testResources.connManager(); - } - - public CloseableHttpAsyncClient startH2Client( - final Consumer clientCustomizer) throws Exception { - return testResources.startH2Client(clientCustomizer); - } - - public MinimalHttpAsyncClient startMinimalClient( - final Http1Config http1Config, - final H2Config h2Config, - final Consumer connManagerCustomizer) throws Exception { - return testResources.startMinimalClient(http1Config, h2Config, connManagerCustomizer); - } - - public MinimalHttpAsyncClient startMinimalH2Client( - final Http1Config http1Config, - final H2Config h2Config, - final Consumer connManagerCustomizer) throws Exception { - return testResources.startMinimalClient(http1Config, h2Config, connManagerCustomizer); - } - - public MinimalH2AsyncClient startMinimalH2Client(final H2Config h2Config) throws Exception { - return testResources.startMinimalH2Client(h2Config); + public TestAsyncClient startClient() throws Exception { + final TestAsyncClient client = testResources.client(); + client.start(); + return client; } } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/HttpIntegrationTests.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/HttpIntegrationTests.java index 452919c4d..df5da9203 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/HttpIntegrationTests.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/HttpIntegrationTests.java @@ -173,44 +173,44 @@ public class HttpIntegrationTests { } - @Nested - @DisplayName("Client authentication (HTTP/1.1)") - public class AuthenticationHttp1 extends TestHttp1ClientAuthentication { - - public AuthenticationHttp1() throws Exception { - super(URIScheme.HTTP); - } - - } - - @Nested - @DisplayName("Client authentication (HTTP/1.1, TLS)") - public class AuthenticationHttp1Tls extends TestHttp1ClientAuthentication { - - public AuthenticationHttp1Tls() throws Exception { - super(URIScheme.HTTPS); - } - - } - - @Nested - @DisplayName("Client authentication (HTTP/2)") - public class AuthenticationH2 extends TestH2ClientAuthentication { - - public AuthenticationH2() throws Exception { - super(URIScheme.HTTP); - } - - } - - @Nested - @DisplayName("Client authentication (HTTP/2, TLS)") - public class AuthenticationH2Tls extends TestH2ClientAuthentication { - - public AuthenticationH2Tls() throws Exception { - super(URIScheme.HTTPS); - } - - } +// @Nested +// @DisplayName("Client authentication (HTTP/1.1)") +// public class AuthenticationHttp1 extends TestHttp1ClientAuthentication { +// +// public AuthenticationHttp1() throws Exception { +// super(URIScheme.HTTP); +// } +// +// } +// +// @Nested +// @DisplayName("Client authentication (HTTP/1.1, TLS)") +// public class AuthenticationHttp1Tls extends TestHttp1ClientAuthentication { +// +// public AuthenticationHttp1Tls() throws Exception { +// super(URIScheme.HTTPS); +// } +// +// } +// @Nested +// @DisplayName("Client authentication (HTTP/2)") +// public class AuthenticationH2 extends TestH2ClientAuthentication { +// +// public AuthenticationH2() throws Exception { +// super(URIScheme.HTTP); +// } +// +// } +// +// @Nested +// @DisplayName("Client authentication (HTTP/2, TLS)") +// public class AuthenticationH2Tls extends TestH2ClientAuthentication { +// +// public AuthenticationH2Tls() throws Exception { +// super(URIScheme.HTTPS); +// } +// +// } +// } \ No newline at end of file diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java index e6485229c..148df77a7 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Async.java @@ -26,25 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2Async extends AbstractHttpAsyncFundamentalsTest { +public abstract class TestH2Async extends AbstractHttpAsyncFundamentalsTest { public TestH2Async(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(H2Config.DEFAULT, null, null); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startH2Client(b -> {}); + super(scheme, ClientProtocolLevel.H2_ONLY, ServerProtocolLevel.H2_ONLY); } } \ No newline at end of file diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncMinimal.java index 81785aa34..0b1c1cea8 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncMinimal.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncMinimal.java @@ -26,25 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import org.apache.hc.client5.http.impl.async.MinimalH2AsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2AsyncMinimal extends AbstractHttpAsyncFundamentalsTest { +public abstract class TestH2AsyncMinimal extends AbstractHttpAsyncFundamentalsTest { public TestH2AsyncMinimal(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(H2Config.DEFAULT, null, null); - } - - @Override - protected MinimalH2AsyncClient startClient() throws Exception { - return startMinimalH2Client(H2Config.DEFAULT); + super(scheme, ClientProtocolLevel.MINIMAL_H2_ONLY, ServerProtocolLevel.H2_ONLY); } } \ No newline at end of file diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java index 78d7aebd5..b2a08ad7c 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2AsyncRedirect.java @@ -26,28 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.core5.function.Decorator; -import org.apache.hc.core5.http.HttpVersion; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2AsyncRedirect extends AbstractHttpAsyncRedirectsTest { +public abstract class TestH2AsyncRedirect extends AbstractHttpAsyncRedirectsTest { public TestH2AsyncRedirect(final URIScheme scheme) { - super(scheme, HttpVersion.HTTP_2); - } - - @Override - protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception { - return startServer(H2Config.DEFAULT, null, exchangeHandlerDecorator); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startH2Client(b -> {}); + super(scheme, ClientProtocolLevel.H2_ONLY, ServerProtocolLevel.H2_ONLY); } } \ No newline at end of file diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java index af0f21a40..f5ffb8742 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ClientAuthentication.java @@ -26,71 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import java.util.function.Consumer; - -import org.apache.hc.client5.http.AuthenticationStrategy; -import org.apache.hc.client5.http.auth.AuthSchemeFactory; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder; -import org.apache.hc.core5.function.Decorator; -import org.apache.hc.core5.http.HttpRequestInterceptor; -import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Lookup; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2ClientAuthentication extends AbstractHttpAsyncClientAuthenticationTest { +public abstract class TestH2ClientAuthentication extends AbstractHttpAsyncClientAuthenticationTest { public TestH2ClientAuthentication(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception { - return startServer(H2Config.DEFAULT, null, exchangeHandlerDecorator); - } - - @Override - protected CloseableHttpAsyncClient startClientCustom(final Consumer clientCustomizer) throws Exception { - - return startH2Client(new Consumer() { - - @Override - public void accept(final H2AsyncClientBuilder builder) { - - clientCustomizer.accept(new TestClientBuilder() { - - @Override - public TestClientBuilder setDefaultAuthSchemeRegistry(final Lookup authSchemeRegistry) { - builder.setDefaultAuthSchemeRegistry(authSchemeRegistry); - return this; - } - - @Override - public TestClientBuilder setTargetAuthenticationStrategy(final AuthenticationStrategy targetAuthStrategy) { - builder.setTargetAuthenticationStrategy(targetAuthStrategy); - return this; - } - - @Override - public TestClientBuilder addResponseInterceptor(final HttpResponseInterceptor responseInterceptor) { - builder.addResponseInterceptorLast(responseInterceptor); - return this; - } - - @Override - public TestClientBuilder addRequestInterceptor(final HttpRequestInterceptor requestInterceptor) { - builder.addRequestInterceptorFirst(requestInterceptor); - return this; - } - - }); - - } - - }); + super(scheme, ClientProtocolLevel.H2_ONLY, ServerProtocolLevel.H2_ONLY); } } \ No newline at end of file diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java index 50d940335..81b748e3c 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2Reactive.java @@ -26,25 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2Reactive extends AbstractHttpReactiveFundamentalsTest { +public abstract class TestH2Reactive extends AbstractHttpReactiveFundamentalsTest { public TestH2Reactive(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(H2Config.DEFAULT, null, null); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startH2Client(b -> {}); + super(scheme, ClientProtocolLevel.H2_ONLY, ServerProtocolLevel.H2_ONLY); } } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ReactiveMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ReactiveMinimal.java index ffaf9104f..8fe7ce12b 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ReactiveMinimal.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestH2ReactiveMinimal.java @@ -26,26 +26,14 @@ */ package org.apache.hc.client5.testing.async; -import org.apache.hc.client5.http.impl.async.MinimalH2AsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; -public abstract class TestH2ReactiveMinimal extends AbstractHttpReactiveFundamentalsTest { +public abstract class TestH2ReactiveMinimal extends AbstractHttpReactiveFundamentalsTest { public TestH2ReactiveMinimal(final URIScheme scheme) { - super(scheme); + super(scheme, ClientProtocolLevel.MINIMAL_H2_ONLY, ServerProtocolLevel.H2_ONLY); } - @Override - protected H2TestServer startServer() throws Exception { - return startServer(H2Config.DEFAULT, null, null); - } - - @Override - protected MinimalH2AsyncClient startClient() throws Exception { - return startMinimalH2Client(H2Config.DEFAULT); - } - - } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java index 3e20f86ad..9c85e4421 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Async.java @@ -40,42 +40,33 @@ import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.http.HeaderElements; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -public abstract class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest { +public abstract class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest { public TestHttp1Async(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(Http1Config.DEFAULT, null, null); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startClient(b -> {}); + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } @ParameterizedTest(name = "{displayName}; concurrent connections: {0}") @ValueSource(ints = {5, 1, 20}) public void testSequentialGetRequestsCloseConnection(final int concurrentConns) throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); - final PoolingAsyncClientConnectionManager connManager = connManager(); + final TestAsyncClient client = startClient(); + + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); connManager.setDefaultMaxPerRoute(concurrentConns); connManager.setMaxTotal(100); for (int i = 0; i < 3; i++) { @@ -96,12 +87,12 @@ public abstract class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); - final PoolingAsyncClientConnectionManager connManager = connManager(); + final TestAsyncClient client = startClient(); + + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); final Future future1 = client.execute( SimpleRequestBuilder.get() .setHttpHost(target) @@ -148,12 +139,11 @@ public abstract class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); - final PoolingAsyncClientConnectionManager connManager = connManager(); + final TestAsyncClient client = startClient(); + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); connManager.setDefaultMaxPerRoute(1); connManager.setMaxTotal(1); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncMinimal.java index e801b410a..7d6302a57 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncMinimal.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncMinimal.java @@ -36,49 +36,34 @@ import java.util.concurrent.TimeUnit; import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.Method; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.nio.AsyncClientEndpoint; import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer; import org.apache.hc.core5.http.nio.support.BasicRequestProducer; import org.apache.hc.core5.http.nio.support.BasicResponseConsumer; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; -public abstract class TestHttp1AsyncMinimal extends AbstractHttpAsyncFundamentalsTest { +public abstract class TestHttp1AsyncMinimal extends AbstractHttpAsyncFundamentalsTest { public TestHttp1AsyncMinimal(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(Http1Config.DEFAULT, null, null); - } - - @Override - protected MinimalHttpAsyncClient startClient() throws Exception { - return startMinimalClient( - Http1Config.DEFAULT, - H2Config.DEFAULT, - b -> {}); + super(scheme, ClientProtocolLevel.MINIMAL, ServerProtocolLevel.STANDARD); } @Test public void testConcurrentPostRequestsSameEndpoint() throws Exception { - final H2TestServer server = startServer(); - server.register("/echo/*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/echo/*", AsyncEchoHandler::new)); + final HttpHost target = startServer(); - final MinimalHttpAsyncClient client = startClient(); + final MinimalHttpAsyncClient client = startClient().getImplementation(); final byte[] b1 = new byte[1024]; final Random rnd = new Random(System.currentTimeMillis()); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java index 77d47461e..4a143a75d 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncRedirects.java @@ -32,55 +32,43 @@ import java.util.concurrent.Future; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.OldPathRedirectResolver; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.client5.testing.redirect.Redirect; -import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; -import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.message.BasicHeader; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** * Redirection test cases. */ -public abstract class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest { +public abstract class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirectsTest { public TestHttp1AsyncRedirects(final URIScheme scheme) { - super(scheme, HttpVersion.HTTP_1_1); - } - - @Override - protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception { - return startServer(Http1Config.DEFAULT, null, exchangeHandlerDecorator); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startClient(b -> {}); + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } @Test public void testBasicRedirect300NoKeepAlive() throws Exception { - final H2TestServer server = startServer(exchangeHandler -> new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, - Redirect.ConnControl.CLOSE))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, + Redirect.ConnControl.CLOSE)))); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute(SimpleRequestBuilder.get() @@ -98,14 +86,15 @@ public abstract class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirects @Test public void testBasicRedirect301NoKeepAlive() throws Exception { - final H2TestServer server = startServer(exchangeHandler -> new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, - Redirect.ConnControl.CLOSE))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, + Redirect.ConnControl.CLOSE)))); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute(SimpleRequestBuilder.get() @@ -124,18 +113,20 @@ public abstract class TestHttp1AsyncRedirects extends AbstractHttpAsyncRedirects @Test public void testDefaultHeadersRedirect() throws Exception { - final H2TestServer server = startServer(exchangeHandler -> new RedirectingAsyncDecorator( - exchangeHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, - Redirect.ConnControl.CLOSE))); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", AsyncRandomHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> new RedirectingAsyncDecorator( + exchangeHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY, + Redirect.ConnControl.CLOSE)))); + final HttpHost target = startServer(); final List
defaultHeaders = new ArrayList<>(1); defaultHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, "my-test-client")); - final CloseableHttpAsyncClient client = startClient(builder -> builder + configureClient(builder -> builder .setDefaultHeaders(defaultHeaders) ); + final TestAsyncClient client = startClient(); final HttpClientContext context = HttpClientContext.create(); final Future future = client.execute(SimpleRequestBuilder.get() diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java index 04880fe57..56ab02303 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1AsyncStatefulConnManagement.java @@ -34,6 +34,9 @@ import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.EndpointDetails; import org.apache.hc.core5.http.HttpException; @@ -41,28 +44,21 @@ import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpCoreContext; import org.apache.hc.core5.net.URIAuthority; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTestBase { public TestHttp1AsyncStatefulConnManagement() { - super(URIScheme.HTTP); - } - - protected H2TestServer startServer() throws Exception { - return startServer(Http1Config.DEFAULT, null, null); + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } @Test public void testStatefulConnections() throws Exception { - final H2TestServer server = startServer(); - server.register("*", () -> new AbstractSimpleServerExchangeHandler() { + configureServer(bootstrap -> bootstrap.register("*", () -> new AbstractSimpleServerExchangeHandler() { @Override protected SimpleHttpResponse handle( @@ -72,13 +68,14 @@ public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTes response.setBody("Whatever", ContentType.TEXT_PLAIN); return response; } - }); + })); + final HttpHost target = startServer(); - final HttpHost target = targetHost(); - - final CloseableHttpAsyncClient client = startClient(builer -> builer + configureClient(builder -> builder .setUserTokenHandler((route, context) -> context.getAttribute("user"))); + final TestAsyncClient client = startClient(); + final int workerCount = 2; final int requestCount = 5; @@ -177,8 +174,7 @@ public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTes @Test public void testRouteSpecificPoolRecylcing() throws Exception { - final H2TestServer server = startServer(); - server.register("*", () -> new AbstractSimpleServerExchangeHandler() { + configureServer(bootstrap -> bootstrap.register("*", () -> new AbstractSimpleServerExchangeHandler() { @Override protected SimpleHttpResponse handle( @@ -188,17 +184,19 @@ public class TestHttp1AsyncStatefulConnManagement extends AbstractIntegrationTes response.setBody("Whatever", ContentType.TEXT_PLAIN); return response; } - }); + })); + final HttpHost target = startServer(); // This tests what happens when a maxed connection pool needs // to kill the last idle connection to a route to build a new // one to the same route. - final HttpHost target = targetHost(); - - final CloseableHttpAsyncClient client = startClient(builer -> builer + configureClient(builder -> builder .setUserTokenHandler((route, context) -> context.getAttribute("user"))); - final PoolingAsyncClientConnectionManager connManager = connManager(); + + final TestAsyncClient client = startClient(); + + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); final int maxConn = 2; // We build a client with 2 max active // connections, and 2 max per route. diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java index 00702a64b..6489d11bc 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ClientAuthentication.java @@ -27,103 +27,49 @@ package org.apache.hc.client5.testing.async; import java.util.concurrent.Future; -import java.util.function.Consumer; -import org.apache.hc.client5.http.AuthenticationStrategy; import org.apache.hc.client5.http.async.methods.SimpleHttpRequest; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; -import org.apache.hc.client5.http.auth.AuthSchemeFactory; import org.apache.hc.client5.http.auth.AuthScope; import org.apache.hc.client5.http.auth.CredentialsProvider; import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.BasicTestAuthenticator; -import org.apache.hc.core5.function.Decorator; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.http.HeaderElements; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; -import org.apache.hc.core5.http.HttpRequestInterceptor; import org.apache.hc.core5.http.HttpResponse; -import org.apache.hc.core5.http.HttpResponseInterceptor; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.config.Lookup; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -public abstract class TestHttp1ClientAuthentication extends AbstractHttpAsyncClientAuthenticationTest { +public abstract class TestHttp1ClientAuthentication extends AbstractHttpAsyncClientAuthenticationTest { public TestHttp1ClientAuthentication(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer(final Decorator exchangeHandlerDecorator) throws Exception { - return startServer(Http1Config.DEFAULT, null, exchangeHandlerDecorator); - } - - @Override - protected CloseableHttpAsyncClient startClientCustom(final Consumer clientCustomizer) throws Exception { - - return startClient(new Consumer() { - - @Override - public void accept(final HttpAsyncClientBuilder builder) { - - clientCustomizer.accept(new TestClientBuilder() { - - @Override - public TestClientBuilder setDefaultAuthSchemeRegistry(final Lookup authSchemeRegistry) { - builder.setDefaultAuthSchemeRegistry(authSchemeRegistry); - return this; - } - - @Override - public TestClientBuilder setTargetAuthenticationStrategy(final AuthenticationStrategy targetAuthStrategy) { - builder.setTargetAuthenticationStrategy(targetAuthStrategy); - return this; - } - - @Override - public TestClientBuilder addResponseInterceptor(final HttpResponseInterceptor responseInterceptor) { - builder.addResponseInterceptorLast(responseInterceptor); - return this; - } - - @Override - public TestClientBuilder addRequestInterceptor(final HttpRequestInterceptor requestInterceptor) { - builder.addRequestInterceptorFirst(requestInterceptor); - return this; - } - - }); - - } - - }); + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } @Test public void testBasicAuthenticationSuccessNonPersistentConnection() throws Exception { - final H2TestServer server = startServer(exchangeHandler -> - new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) { + final HttpHost target = startServer(); + configureServer(bootstrap -> bootstrap + .register("*", AsyncEchoHandler::new) + .setExchangeHandlerDecorator(exchangeHandler -> + new AuthenticatingAsyncDecorator(exchangeHandler, new BasicTestAuthenticator("test:test", "test realm")) { - @Override - protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { - unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE); - } - }); - server.register("*", AsyncEchoHandler::new); - final HttpHost target = targetHost(); + @Override + protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) { + unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE); + } + })); - final CloseableHttpAsyncClient client = startClient(); + final TestAsyncClient client = startClient(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java index e0d6fe336..7e9864374 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1Reactive.java @@ -36,18 +36,19 @@ import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; import org.apache.hc.client5.http.impl.async.HttpAsyncClients; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.http.HeaderElements; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.nio.AsyncRequestProducer; import org.apache.hc.core5.http.nio.support.AsyncRequestBuilder; import org.apache.hc.core5.reactive.ReactiveResponseConsumer; import org.apache.hc.core5.reactive.ReactiveServerExchangeHandler; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.testing.reactive.ReactiveRandomProcessor; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; @@ -56,33 +57,23 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.reactivestreams.Publisher; -public abstract class TestHttp1Reactive extends AbstractHttpReactiveFundamentalsTest { +public abstract class TestHttp1Reactive extends AbstractHttpReactiveFundamentalsTest { public TestHttp1Reactive(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(Http1Config.DEFAULT, null, null); - } - - @Override - protected CloseableHttpAsyncClient startClient() throws Exception { - return startClient(b -> {}); + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } @ParameterizedTest(name = "{displayName}; concurrent connections: {0}") @ValueSource(ints = {5, 1, 20}) @Timeout(value = 60_000, unit = MILLISECONDS) public void testSequentialGetRequestsCloseConnection(final int concurrentConns) throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", () -> - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", () -> + new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); - final PoolingAsyncClientConnectionManager connManager = connManager(); + final TestAsyncClient client = startClient(); + + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); connManager.setDefaultMaxPerRoute(concurrentConns); connManager.setMaxTotal(100); @@ -109,13 +100,13 @@ public abstract class TestHttp1Reactive extends AbstractHttpReactiveFundamentals @Test @Timeout(value = 60_000, unit = MILLISECONDS) public void testSharedPool() throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", () -> - new ReactiveServerExchangeHandler(new ReactiveRandomProcessor())); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", () -> + new ReactiveServerExchangeHandler(new ReactiveRandomProcessor()))); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(); - final PoolingAsyncClientConnectionManager connManager = connManager(); + final TestAsyncClient client = startClient(); + + final PoolingAsyncClientConnectionManager connManager = client.getConnectionManager(); final AsyncRequestProducer request1 = AsyncRequestBuilder.get(target + "/random/2048").build(); final ReactiveResponseConsumer consumer1 = new ReactiveResponseConsumer(); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ReactiveMinimal.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ReactiveMinimal.java index 1992fa519..18caa1cd2 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ReactiveMinimal.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1ReactiveMinimal.java @@ -36,52 +36,37 @@ import java.util.concurrent.TimeUnit; import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.Method; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.nio.AsyncClientEndpoint; import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers; import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityConsumer; import org.apache.hc.core5.http.nio.support.BasicRequestProducer; import org.apache.hc.core5.http.nio.support.BasicResponseConsumer; -import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.reactive.ReactiveServerExchangeHandler; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.testing.reactive.ReactiveEchoProcessor; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; -public abstract class TestHttp1ReactiveMinimal extends AbstractHttpReactiveFundamentalsTest { +public abstract class TestHttp1ReactiveMinimal extends AbstractHttpReactiveFundamentalsTest { public TestHttp1ReactiveMinimal(final URIScheme scheme) { - super(scheme); - } - - @Override - protected H2TestServer startServer() throws Exception { - return startServer(Http1Config.DEFAULT, null, null); - } - - @Override - protected MinimalHttpAsyncClient startClient() throws Exception { - return startMinimalClient( - Http1Config.DEFAULT, - H2Config.DEFAULT, - b -> {}); + super(scheme, ClientProtocolLevel.MINIMAL, ServerProtocolLevel.STANDARD); } @Test public void testConcurrentPostRequestsSameEndpoint() throws Exception { - final H2TestServer server = startServer(); - server.register("/echo/*", () -> - new ReactiveServerExchangeHandler(new ReactiveEchoProcessor())); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/echo/*", () -> + new ReactiveServerExchangeHandler(new ReactiveEchoProcessor()))); + final HttpHost target = startServer(); - final MinimalHttpAsyncClient client = startClient(); + final MinimalHttpAsyncClient client = startClient().getImplementation(); final byte[] b1 = new byte[1024]; final Random rnd = new Random(System.currentTimeMillis()); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java index 50294e9bb..c877ed8c4 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttp1RequestReExecution.java @@ -34,25 +34,27 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.function.Resolver; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpRequest; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.apache.hc.core5.util.TimeValue; import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public abstract class TestHttp1RequestReExecution extends AbstractIntegrationTestBase { public TestHttp1RequestReExecution(final URIScheme scheme) { - super(scheme); + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); } - protected H2TestServer startServer() throws Exception { + @BeforeEach + public void setup() { final Resolver serviceAvailabilityResolver = new Resolver() { private final AtomicInteger count = new AtomicInteger(0); @@ -65,18 +67,18 @@ public abstract class TestHttp1RequestReExecution extends AbstractIntegrationTes }; - return startServer(Http1Config.DEFAULT, null, handler -> - new ServiceUnavailableAsyncDecorator(handler, serviceAvailabilityResolver)); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(handler -> new ServiceUnavailableAsyncDecorator(handler, serviceAvailabilityResolver))); } @Test public void testGiveUpAfterOneRetry() throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(builder -> builder + configureClient(builder -> builder .setRetryStrategy(new DefaultHttpRequestRetryStrategy(1, TimeValue.ofSeconds(1)))); + final TestAsyncClient client = startClient(); final Future future = client.execute( SimpleRequestBuilder.get() @@ -90,12 +92,12 @@ public abstract class TestHttp1RequestReExecution extends AbstractIntegrationTes @Test public void testDoNotGiveUpEasily() throws Exception { - final H2TestServer server = startServer(); - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); - final CloseableHttpAsyncClient client = startClient(builder -> builder + configureClient(builder -> builder .setRetryStrategy(new DefaultHttpRequestRetryStrategy(5, TimeValue.ofSeconds(1)))); + final TestAsyncClient client = startClient(); final Future future = client.execute( SimpleRequestBuilder.get() diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimalTlsHandshake.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimalTlsHandshake.java index 86545fce9..ae3133ccf 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimalTlsHandshake.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncMinimalTlsHandshake.java @@ -29,18 +29,17 @@ package org.apache.hc.client5.testing.async; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; import javax.net.ssl.SSLException; import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; -import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.nio.AsyncClientEndpoint; -import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.ssl.SSLContexts; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -48,26 +47,19 @@ import org.junit.jupiter.api.Test; public class TestHttpAsyncMinimalTlsHandshake extends AbstractIntegrationTestBase { public TestHttpAsyncMinimalTlsHandshake() { - super(URIScheme.HTTPS); - } - - protected MinimalHttpAsyncClient startMinimalClient( - final Consumer connManagerCustomizer) throws Exception { - return startMinimalClient( - Http1Config.DEFAULT, - H2Config.DEFAULT, - connManagerCustomizer); + super(URIScheme.HTTPS, ClientProtocolLevel.MINIMAL, ServerProtocolLevel.STANDARD); } @Test public void testSuccessfulTlsHandshake() throws Exception { - startServer(Http1Config.DEFAULT, null, null); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final int maxConnNo = 2; - final MinimalHttpAsyncClient client = startMinimalClient(builder -> builder - .setMaxConnPerRoute(maxConnNo) - .setMaxConnTotal(maxConnNo)); + final PoolingAsyncClientConnectionManager connectionManager = startClient().getConnectionManager(); + connectionManager.setDefaultMaxPerRoute(maxConnNo); + connectionManager.setMaxTotal(maxConnNo); + + final MinimalHttpAsyncClient client = startClient().getImplementation(); for (int i = 0; i < maxConnNo + 1; i++) { final Future endpointLease = client.lease(target, null); @@ -78,14 +70,17 @@ public class TestHttpAsyncMinimalTlsHandshake extends AbstractIntegrationTestBas @Test public void testTlsHandshakeFailure() throws Exception { - startServer(Http1Config.DEFAULT, null, null); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); + + configureClient(builder -> + builder.setTlsStrategy(new DefaultClientTlsStrategy(SSLContexts.createDefault()))); final int maxConnNo = 2; - final MinimalHttpAsyncClient client = startMinimalClient(builder -> builder - .setTlsStrategy(new DefaultClientTlsStrategy(SSLContexts.createDefault())) - .setMaxConnPerRoute(maxConnNo) - .setMaxConnTotal(maxConnNo)); + final PoolingAsyncClientConnectionManager connectionManager = startClient().getConnectionManager(); + connectionManager.setDefaultMaxPerRoute(maxConnNo); + connectionManager.setMaxTotal(maxConnNo); + + final MinimalHttpAsyncClient client = startClient().getImplementation(); for (int i = 0; i < maxConnNo + 1; i++) { final Future endpointLease = client.lease(target, null); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncProtocolPolicy.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncProtocolPolicy.java index aceeca195..743d21f0a 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncProtocolPolicy.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/TestHttpAsyncProtocolPolicy.java @@ -34,15 +34,14 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.hc.client5.http.async.methods.SimpleHttpResponse; import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder; import org.apache.hc.client5.http.config.TlsConfig; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.testing.async.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.async.extension.ServerProtocolLevel; +import org.apache.hc.client5.testing.async.extension.TestAsyncClient; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpVersion; import org.apache.hc.core5.http.ProtocolVersion; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http2.HttpVersionPolicy; -import org.apache.hc.core5.http2.config.H2Config; -import org.apache.hc.core5.testing.nio.H2TestServer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Test; @@ -51,31 +50,23 @@ public abstract class TestHttpAsyncProtocolPolicy extends AbstractIntegrationTes private final HttpVersion version; public TestHttpAsyncProtocolPolicy(final URIScheme scheme, final HttpVersion version) { - super(scheme); + super(scheme, ClientProtocolLevel.STANDARD, version == HttpVersion.HTTP_2 ? ServerProtocolLevel.H2_ONLY : ServerProtocolLevel.STANDARD); this.version = version; } @Test public void testRequestContext() throws Exception { - final H2TestServer server; - if (version.greaterEquals(HttpVersion.HTTP_2)) { - server = startServer(H2Config.DEFAULT, null, null); - } else { - server = startServer(Http1Config.DEFAULT, null, null); - } - server.register("/random/*", AsyncRandomHandler::new); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); + final HttpHost target = startServer(); final AtomicReference versionRef = new AtomicReference<>(); - final CloseableHttpAsyncClient client = startClient( - builder -> builder - .setDefaultTlsConfig(TlsConfig.custom() - .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1) - .build()), - builder -> builder - .addRequestInterceptorFirst((request, entity, context) -> - versionRef.set(context.getProtocolVersion()) - )); + configureClient(builder -> builder + .setDefaultTlsConfig(TlsConfig.custom() + .setVersionPolicy(version.greaterEquals(HttpVersion.HTTP_2) ? HttpVersionPolicy.FORCE_HTTP_2 : HttpVersionPolicy.FORCE_HTTP_1) + .build()) + .addRequestInterceptorFirst((request, entity, context) -> + versionRef.set(context.getProtocolVersion()))); + final TestAsyncClient client = startClient(); final Future future = client.execute( SimpleRequestBuilder.get() diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ClientProtocolLevel.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ClientProtocolLevel.java new file mode 100644 index 000000000..8e439efec --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ClientProtocolLevel.java @@ -0,0 +1,34 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +public enum ClientProtocolLevel { + + STANDARD, H2_ONLY, MINIMAL, MINIMAL_H2_ONLY + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyMinimalTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyMinimalTestClientBuilder.java new file mode 100644 index 000000000..e90f5e87c --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyMinimalTestClientBuilder.java @@ -0,0 +1,82 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +final class H2OnlyMinimalTestClientBuilder implements TestAsyncClientBuilder { + + private Timeout timeout; + private TlsStrategy tlsStrategy; + private H2Config h2Config; + + public H2OnlyMinimalTestClientBuilder() { + } + + @Override + public TestAsyncClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestAsyncClientBuilder setTlsStrategy(final TlsStrategy tlsStrategy) { + this.tlsStrategy = tlsStrategy; + return this; + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.MINIMAL_H2_ONLY; + } + + @Override + public TestAsyncClientBuilder setH2Config(final H2Config h2Config) { + this.h2Config = h2Config; + return this; + } + + @Override + public TestAsyncClient build() throws Exception { + final CloseableHttpAsyncClient client = HttpAsyncClients.createHttp2Minimal( + h2Config, + IOReactorConfig.custom() + .setSoTimeout(timeout) + .build(), + tlsStrategy != null ? tlsStrategy : new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); + return new TestAsyncClient(client, null); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyTestClientBuilder.java new file mode 100644 index 000000000..e70452d63 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/H2OnlyTestClientBuilder.java @@ -0,0 +1,136 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.util.Collection; + +import org.apache.hc.client5.http.AuthenticationStrategy; +import org.apache.hc.client5.http.auth.AuthSchemeFactory; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.config.Lookup; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +final class H2OnlyTestClientBuilder implements TestAsyncClientBuilder { + + private final H2AsyncClientBuilder clientBuilder; + + private Timeout timeout; + private TlsStrategy tlsStrategy; + private H2Config h2Config; + + public H2OnlyTestClientBuilder() { + this.clientBuilder = H2AsyncClientBuilder.create(); + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.H2_ONLY; + } + + @Override + public TestAsyncClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestAsyncClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorFirst(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorLast(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorFirst(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addRequestInterceptorLast(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorLast(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder setTlsStrategy(final TlsStrategy tlsStrategy) { + this.tlsStrategy = tlsStrategy; + return this; + } + + @Override + public TestAsyncClientBuilder setH2Config(final H2Config h2Config) { + this.h2Config = h2Config; + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultHeaders(final Collection defaultHeaders) { + this.clientBuilder.setDefaultHeaders(defaultHeaders); + return this; + } + + @Override + public TestAsyncClientBuilder setTargetAuthenticationStrategy(final AuthenticationStrategy targetAuthStrategy) { + this.clientBuilder.setTargetAuthenticationStrategy(targetAuthStrategy); + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup authSchemeRegistry) { + this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry); + return this; + } + + @Override + public TestAsyncClient build() throws Exception { + final CloseableHttpAsyncClient client = clientBuilder + .setTlsStrategy(tlsStrategy != null ? tlsStrategy : new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) + .setIOReactorConfig(IOReactorConfig.custom() + .setSoTimeout(timeout) + .build()) + .setH2Config(h2Config) + .build(); + return new TestAsyncClient(client, null); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/MinimalTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/MinimalTestClientBuilder.java new file mode 100644 index 000000000..2c939ee1c --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/MinimalTestClientBuilder.java @@ -0,0 +1,111 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +final class MinimalTestClientBuilder implements TestAsyncClientBuilder { + + private final PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder; + + private Timeout timeout; + private TlsStrategy tlsStrategy; + private Http1Config http1Config; + private H2Config h2Config; + + public MinimalTestClientBuilder() { + this.connectionManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create(); + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.MINIMAL; + } + + @Override + public TestAsyncClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestAsyncClientBuilder setTlsStrategy(final TlsStrategy tlsStrategy) { + this.tlsStrategy = tlsStrategy; + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultTlsConfig(final TlsConfig tlsConfig) { + this.connectionManagerBuilder.setDefaultTlsConfig(tlsConfig); + return this; + } + + @Override + public TestAsyncClientBuilder setHttp1Config(final Http1Config http1Config) { + this.http1Config = http1Config; + return this; + } + + @Override + public TestAsyncClientBuilder setH2Config(final H2Config h2Config) { + this.h2Config = h2Config; + return this; + } + + @Override + public TestAsyncClient build() throws Exception { + final PoolingAsyncClientConnectionManager connectionManager = connectionManagerBuilder + .setTlsStrategy(tlsStrategy != null ? tlsStrategy : new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) + .setDefaultConnectionConfig(ConnectionConfig.custom() + .setSocketTimeout(timeout) + .setConnectTimeout(timeout) + .build()) + .build(); + final CloseableHttpAsyncClient client = HttpAsyncClients.createMinimal( + h2Config, + http1Config, + IOReactorConfig.custom() + .setSoTimeout(timeout) + .build(), + connectionManager); + return new TestAsyncClient(client, connectionManager); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ServerProtocolLevel.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ServerProtocolLevel.java new file mode 100644 index 000000000..3a5690727 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/ServerProtocolLevel.java @@ -0,0 +1,34 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +public enum ServerProtocolLevel { + + STANDARD, H2_ONLY + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/StandardTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/StandardTestClientBuilder.java new file mode 100644 index 000000000..88807d1cb --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/StandardTestClientBuilder.java @@ -0,0 +1,174 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.util.Collection; + +import org.apache.hc.client5.http.AuthenticationStrategy; +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +import org.apache.hc.client5.http.UserTokenHandler; +import org.apache.hc.client5.http.auth.AuthSchemeFactory; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.config.Lookup; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.util.Timeout; + +final class StandardTestClientBuilder implements TestAsyncClientBuilder { + + private final PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder; + private final HttpAsyncClientBuilder clientBuilder; + + private Timeout timeout; + private TlsStrategy tlsStrategy; + + public StandardTestClientBuilder() { + this.connectionManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create(); + this.clientBuilder = HttpAsyncClientBuilder.create(); + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.STANDARD; + } + + @Override + public TestAsyncClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestAsyncClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorFirst(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorLast(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorFirst(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder addRequestInterceptorLast(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorLast(interceptor); + return this; + } + + @Override + public TestAsyncClientBuilder setTlsStrategy(final TlsStrategy tlsStrategy) { + this.tlsStrategy = tlsStrategy; + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultTlsConfig(final TlsConfig tlsConfig) { + this.connectionManagerBuilder.setDefaultTlsConfig(tlsConfig); + return this; + } + + @Override + public TestAsyncClientBuilder setHttp1Config(final Http1Config http1Config) { + this.clientBuilder.setHttp1Config(http1Config); + return this; + } + + @Override + public TestAsyncClientBuilder setH2Config(final H2Config h2Config) { + this.clientBuilder.setH2Config(h2Config); + return this; + } + + @Override + public TestAsyncClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) { + this.clientBuilder.setUserTokenHandler(userTokenHandler); + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultHeaders(final Collection defaultHeaders) { + this.clientBuilder.setDefaultHeaders(defaultHeaders); + return this; + } + + @Override + public TestAsyncClientBuilder setRetryStrategy(final HttpRequestRetryStrategy retryStrategy) { + this.clientBuilder.setRetryStrategy(retryStrategy); + return this; + } + + @Override + public TestAsyncClientBuilder setTargetAuthenticationStrategy(final AuthenticationStrategy targetAuthStrategy) { + this.clientBuilder.setTargetAuthenticationStrategy(targetAuthStrategy); + return this; + } + + @Override + public TestAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup authSchemeRegistry) { + this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry); + return this; + } + + @Override + public TestAsyncClient build() throws Exception { + final PoolingAsyncClientConnectionManager connectionManager = connectionManagerBuilder + .setTlsStrategy(tlsStrategy != null ? tlsStrategy : new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) + .setDefaultConnectionConfig(ConnectionConfig.custom() + .setSocketTimeout(timeout) + .setConnectTimeout(timeout) + .build()) + .build(); + final CloseableHttpAsyncClient client = clientBuilder + .setIOReactorConfig(IOReactorConfig.custom() + .setSoTimeout(timeout) + .build()) + .setConnectionManager(connectionManager) + .build(); + return new TestAsyncClient(client, connectionManager); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClient.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClient.java new file mode 100644 index 000000000..41543fd6a --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClient.java @@ -0,0 +1,117 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.io.IOException; +import java.util.concurrent.Future; + +import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; +import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; +import org.apache.hc.core5.concurrent.FutureCallback; +import org.apache.hc.core5.function.Supplier; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.nio.AsyncPushConsumer; +import org.apache.hc.core5.http.nio.AsyncRequestProducer; +import org.apache.hc.core5.http.nio.AsyncResponseConsumer; +import org.apache.hc.core5.http.nio.HandlerFactory; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.reactor.IOReactorStatus; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.Asserts; +import org.apache.hc.core5.util.TimeValue; + +public class TestAsyncClient extends CloseableHttpAsyncClient { + + private final CloseableHttpAsyncClient client; + private final PoolingAsyncClientConnectionManager connectionManager; + + public TestAsyncClient(final CloseableHttpAsyncClient client, + final PoolingAsyncClientConnectionManager connectionManager) { + this.client = Args.notNull(client, "Client"); + this.connectionManager = connectionManager; + } + + @Override + public void close(final CloseMode closeMode) { + client.close(closeMode); + } + + @Override + public void close() throws IOException { + client.close(); + } + + @Override + public void start() { + client.start(); + } + + @Override + public IOReactorStatus getStatus() { + return client.getStatus(); + } + + @Override + public void awaitShutdown(final TimeValue waitTime) throws InterruptedException { + client.awaitShutdown(waitTime); + } + + @Override + public void initiateShutdown() { + client.initiateShutdown(); + } + + @Override + protected Future doExecute(final HttpHost target, + final AsyncRequestProducer requestProducer, + final AsyncResponseConsumer responseConsumer, + final HandlerFactory pushHandlerFactory, + final HttpContext context, + final FutureCallback callback) { + return client.execute(target, requestProducer, responseConsumer, pushHandlerFactory, context, callback); + } + + @Override + public void register(final String hostname, + final String uriPattern, + final Supplier supplier) { + client.register(hostname, uriPattern, supplier); + } + + @SuppressWarnings("unchecked") + public T getImplementation() { + return (T) client; + } + + public PoolingAsyncClientConnectionManager getConnectionManager() { + Asserts.check(connectionManager != null, "Connection manager is not available"); + return connectionManager; + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClientBuilder.java new file mode 100644 index 000000000..43276ec2f --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncClientBuilder.java @@ -0,0 +1,106 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.util.Collection; + +import org.apache.hc.client5.http.AuthenticationStrategy; +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +import org.apache.hc.client5.http.UserTokenHandler; +import org.apache.hc.client5.http.auth.AuthSchemeFactory; +import org.apache.hc.client5.http.config.TlsConfig; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.config.Lookup; +import org.apache.hc.core5.http.nio.ssl.TlsStrategy; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.util.Timeout; + +public interface TestAsyncClientBuilder { + + ClientProtocolLevel getProtocolLevel(); + + TestAsyncClientBuilder setTimeout(Timeout soTimeout); + + default TestAsyncClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) { + return this; + } + + default TestAsyncClientBuilder addResponseInterceptorLast(HttpResponseInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder addRequestInterceptorFirst(HttpRequestInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder addRequestInterceptorLast(HttpRequestInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setTlsStrategy(TlsStrategy tlsStrategy) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setDefaultTlsConfig(TlsConfig tlsConfig) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setHttp1Config(Http1Config http1Config) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setH2Config(H2Config http1Config) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setUserTokenHandler(UserTokenHandler userTokenHandler) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setDefaultHeaders(Collection defaultHeaders) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setRetryStrategy(HttpRequestRetryStrategy retryStrategy) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setTargetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestAsyncClientBuilder setDefaultAuthSchemeRegistry(Lookup authSchemeRegistry) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + TestAsyncClient build() throws Exception; + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncResources.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncResources.java index 49a411e74..115d353a5 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncResources.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncResources.java @@ -27,81 +27,63 @@ package org.apache.hc.client5.testing.async.extension; -import java.net.InetSocketAddress; import java.util.function.Consumer; -import org.apache.hc.client5.http.config.ConnectionConfig; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.client5.http.impl.async.H2AsyncClientBuilder; -import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; -import org.apache.hc.client5.http.impl.async.HttpAsyncClients; -import org.apache.hc.client5.http.impl.async.MinimalH2AsyncClient; -import org.apache.hc.client5.http.impl.async.MinimalHttpAsyncClient; -import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; -import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; -import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; -import org.apache.hc.client5.testing.SSLTestContexts; import org.apache.hc.client5.testing.sync.extension.TestClientResources; -import org.apache.hc.core5.function.Decorator; -import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; -import org.apache.hc.core5.http.protocol.HttpProcessor; -import org.apache.hc.core5.http2.config.H2Config; import org.apache.hc.core5.io.CloseMode; -import org.apache.hc.core5.reactor.IOReactorConfig; -import org.apache.hc.core5.testing.nio.H2TestServer; +import org.apache.hc.core5.util.Asserts; import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.Timeout; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TestAsyncResources implements BeforeEachCallback, AfterEachCallback { +public class TestAsyncResources implements AfterEachCallback { private static final Logger LOG = LoggerFactory.getLogger(TestClientResources.class); private final URIScheme scheme; - private final Timeout timeout; + private final ClientProtocolLevel clientProtocolLevel; + private final ServerProtocolLevel serverProtocolLevel; + private final TestAsyncServerBootstrap serverBootstrap; + private final TestAsyncClientBuilder clientBuilder; - private H2TestServer server; - private InetSocketAddress socketAddress; - private PoolingAsyncClientConnectionManager connManager; - private CloseableHttpAsyncClient client; + private TestAsyncServer server; + private TestAsyncClient client; - public TestAsyncResources(final URIScheme scheme, final Timeout timeout) { - this.scheme = scheme; - this.timeout = timeout; - } - - @Override - public void beforeEach(final ExtensionContext extensionContext) throws Exception { - LOG.debug("Starting up test server"); - server = new H2TestServer( - IOReactorConfig.custom() - .setSoTimeout(timeout) - .build(), - scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, - null, - null); + public TestAsyncResources(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel, final Timeout timeout) { + this.scheme = scheme != null ? scheme : URIScheme.HTTP; + this.clientProtocolLevel = clientProtocolLevel != null ? clientProtocolLevel : ClientProtocolLevel.STANDARD; + this.serverProtocolLevel = serverProtocolLevel != null ? serverProtocolLevel : ServerProtocolLevel.STANDARD; + this.serverBootstrap = new TestAsyncServerBootstrap(this.scheme, this.serverProtocolLevel) + .setTimeout(timeout); + switch (this.clientProtocolLevel) { + case STANDARD: + this.clientBuilder = new StandardTestClientBuilder(); + break; + case H2_ONLY: + this.clientBuilder = new H2OnlyTestClientBuilder(); + break; + case MINIMAL_H2_ONLY: + this.clientBuilder = new H2OnlyMinimalTestClientBuilder(); + break; + case MINIMAL: + this.clientBuilder = new MinimalTestClientBuilder(); + break; + default: + this.clientBuilder = new StandardTestClientBuilder(); + } + this.clientBuilder.setTimeout(timeout); } @Override public void afterEach(final ExtensionContext extensionContext) throws Exception { LOG.debug("Shutting down test server"); - if (client != null) { client.close(CloseMode.GRACEFUL); } - - if (connManager != null) { - connManager.close(CloseMode.IMMEDIATE); - } - if (server != null) { server.shutdown(TimeValue.ofSeconds(5)); } @@ -111,125 +93,36 @@ public class TestAsyncResources implements BeforeEachCallback, AfterEachCallback return this.scheme; } - public H2TestServer startServer( - final H2Config h2Config, - final HttpProcessor httpProcessor, - final Decorator exchangeHandlerDecorator) throws Exception { - Assertions.assertNotNull(server); - socketAddress = server.start(httpProcessor, exchangeHandlerDecorator, h2Config); + public ServerProtocolLevel getServerProtocolLevel() { + return serverProtocolLevel; + } + + public ClientProtocolLevel getClientProtocolLevel() { + return clientProtocolLevel; + } + + public void configureServer(final Consumer serverCustomizer) { + Asserts.check(server == null, "Server is already running and cannot be changed"); + serverCustomizer.accept(serverBootstrap); + } + + public TestAsyncServer server() throws Exception { + if (server == null) { + server = serverBootstrap.build(); + } return server; } - public H2TestServer startServer( - final Http1Config http1Config, - final HttpProcessor httpProcessor, - final Decorator exchangeHandlerDecorator) throws Exception { - Assertions.assertNotNull(server); - socketAddress = server.start(httpProcessor, exchangeHandlerDecorator, http1Config); - return server; - } - - public HttpHost targetHost() { - Assertions.assertNotNull(socketAddress); - return new HttpHost(scheme.id, "localhost", socketAddress.getPort()); - } - - public CloseableHttpAsyncClient startClient( - final Consumer connManagerCustomizer, - final Consumer clientCustomizer) throws Exception { - Assertions.assertNull(connManager); - Assertions.assertNull(client); - - final PoolingAsyncClientConnectionManagerBuilder connManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create(); - connManagerBuilder.setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - connManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setSocketTimeout(timeout) - .setConnectTimeout(timeout) - .build()); - connManagerCustomizer.accept(connManagerBuilder); - - connManager = connManagerBuilder.build(); - - final HttpAsyncClientBuilder clientBuilder = HttpAsyncClientBuilder.create() - .setConnectionManager(connManager) - .setIOReactorConfig(IOReactorConfig.custom() - .setSoTimeout(timeout) - .build()); - + public void configureClient(final Consumer clientCustomizer) { + Asserts.check(client == null, "Client is already running and cannot be changed"); clientCustomizer.accept(clientBuilder); - client = clientBuilder.build(); - client.start(); + } + + public TestAsyncClient client() throws Exception { + if (client == null) { + client = clientBuilder.build(); + } return client; } - public CloseableHttpAsyncClient startClient( - final Consumer clientCustomizer) throws Exception { - return startClient(b -> { - }, clientCustomizer); - } - - public PoolingAsyncClientConnectionManager connManager() { - Assertions.assertNotNull(connManager); - return connManager; - } - - public CloseableHttpAsyncClient startH2Client( - final Consumer clientCustomizer) throws Exception { - Assertions.assertNull(connManager); - Assertions.assertNull(client); - - final H2AsyncClientBuilder clientBuilder = H2AsyncClientBuilder.create(); - clientBuilder.setIOReactorConfig(IOReactorConfig.custom() - .setSoTimeout(timeout) - .build()); - clientBuilder.setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - clientCustomizer.accept(clientBuilder); - client = clientBuilder.build(); - client.start(); - return client; - } - - public MinimalHttpAsyncClient startMinimalClient( - final Http1Config http1Config, - final H2Config h2Config, - final Consumer connManagerCustomizer) throws Exception { - Assertions.assertNull(connManager); - Assertions.assertNull(client); - - final PoolingAsyncClientConnectionManagerBuilder connManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create(); - connManagerBuilder.setTlsStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - connManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setSocketTimeout(timeout) - .setConnectTimeout(timeout) - .build()); - connManagerCustomizer.accept(connManagerBuilder); - - connManager = connManagerBuilder.build(); - - final MinimalHttpAsyncClient minimal = HttpAsyncClients.createMinimal( - h2Config, - http1Config, - IOReactorConfig.custom() - .setSoTimeout(timeout) - .build(), - connManager); - client = minimal; - client.start(); - return minimal; - } - - public MinimalH2AsyncClient startMinimalH2Client(final H2Config h2Config) throws Exception { - Assertions.assertNull(client); - - final MinimalH2AsyncClient minimal = HttpAsyncClients.createHttp2Minimal( - h2Config, - IOReactorConfig.custom() - .setSoTimeout(timeout) - .build(), - new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - client = minimal; - client.start(); - return minimal; - } - } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServer.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServer.java new file mode 100644 index 000000000..27c134e87 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServer.java @@ -0,0 +1,101 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.net.InetSocketAddress; +import java.util.Set; +import java.util.concurrent.Future; + +import org.apache.hc.core5.function.Decorator; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; +import org.apache.hc.core5.http.protocol.HttpProcessor; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorStatus; +import org.apache.hc.core5.reactor.ListenerEndpoint; +import org.apache.hc.core5.testing.nio.H2TestServer; +import org.apache.hc.core5.util.TimeValue; + +public class TestAsyncServer { + + private final H2TestServer server; + private final H2Config h2Config; + private final Http1Config http1Config; + private final HttpProcessor httpProcessor; + private final Decorator exchangeHandlerDecorator; + + TestAsyncServer( + final H2TestServer server, + final H2Config h2Config, + final Http1Config http1Config, + final HttpProcessor httpProcessor, + final Decorator exchangeHandlerDecorator) { + this.server = server; + this.h2Config = h2Config; + this.http1Config = http1Config; + this.httpProcessor = httpProcessor; + this.exchangeHandlerDecorator = exchangeHandlerDecorator; + } + + public Future listen(final InetSocketAddress address) { + return server.listen(address); + } + + public Set getEndpoints() { + return server.getEndpoints(); + } + + public IOReactorStatus getStatus() { + return server.getStatus(); + } + + public void awaitShutdown(final TimeValue waitTime) throws InterruptedException { + server.awaitShutdown(waitTime); + } + + public void initiateShutdown() { + server.initiateShutdown(); + } + + public void shutdown(final TimeValue graceTime) { + server.shutdown(graceTime); + } + + public void close() throws Exception { + server.close(); + } + + public InetSocketAddress start() throws Exception { + if (http1Config == null) { + return server.start(httpProcessor, exchangeHandlerDecorator, h2Config); + } else { + return server.start(httpProcessor, exchangeHandlerDecorator, http1Config); + } + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServerBootstrap.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServerBootstrap.java new file mode 100644 index 000000000..2e518112f --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/extension/TestAsyncServerBootstrap.java @@ -0,0 +1,133 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.async.extension; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.function.Decorator; +import org.apache.hc.core5.function.Supplier; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler; +import org.apache.hc.core5.http.nio.AsyncServerRequestHandler; +import org.apache.hc.core5.http.nio.support.BasicServerExchangeHandler; +import org.apache.hc.core5.http.protocol.HttpProcessor; +import org.apache.hc.core5.http2.config.H2Config; +import org.apache.hc.core5.reactor.IOReactorConfig; +import org.apache.hc.core5.testing.nio.H2TestServer; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.Timeout; + +public class TestAsyncServerBootstrap { + + static final class HandlerEntry { + + final String hostname; + final String uriPattern; + final T handler; + + public HandlerEntry(final String hostname, final String uriPattern, final T handler) { + this.hostname = hostname; + this.uriPattern = uriPattern; + this.handler = handler; + } + + public HandlerEntry(final String uriPattern, final T handler) { + this(null, uriPattern, handler); + } + + } + + private final URIScheme scheme; + private final ServerProtocolLevel serverProtocolLevel; + + private final List>> handlerList; + private Timeout timeout; + private HttpProcessor httpProcessor; + private Decorator exchangeHandlerDecorator; + + public TestAsyncServerBootstrap(final URIScheme scheme, final ServerProtocolLevel serverProtocolLevel) { + this.scheme = scheme != null ? scheme : URIScheme.HTTP; + this.serverProtocolLevel = serverProtocolLevel != null ? serverProtocolLevel : ServerProtocolLevel.STANDARD; + this.handlerList = new ArrayList<>(); + } + + public ServerProtocolLevel getProtocolLevel() { + return serverProtocolLevel; + } + + public TestAsyncServerBootstrap register(final String uriPattern, final Supplier supplier) { + Args.notNull(uriPattern, "URI pattern"); + Args.notNull(supplier, "Exchange handler supplier"); + handlerList.add(new HandlerEntry<>(uriPattern, supplier)); + return this; + } + + public TestAsyncServerBootstrap register( + final String uriPattern, + final AsyncServerRequestHandler requestHandler) { + return register(uriPattern, () -> new BasicServerExchangeHandler<>(requestHandler)); + } + + public TestAsyncServerBootstrap setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + public TestAsyncServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) { + this.httpProcessor = httpProcessor; + return this; + } + + public TestAsyncServerBootstrap setExchangeHandlerDecorator(final Decorator exchangeHandlerDecorator) { + this.exchangeHandlerDecorator = exchangeHandlerDecorator; + return this; + } + + public TestAsyncServer build() throws Exception { + final H2TestServer server = new H2TestServer( + IOReactorConfig.custom() + .setSoTimeout(timeout) + .build(), + scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, + null, + null); + for (final HandlerEntry> entry: handlerList) { + server.register(entry.uriPattern, entry.handler); + } + return new TestAsyncServer( + server, + serverProtocolLevel == ServerProtocolLevel.H2_ONLY ? H2Config.DEFAULT : null, + serverProtocolLevel == ServerProtocolLevel.STANDARD ? Http1Config.DEFAULT : null, + httpProcessor, + exchangeHandlerDecorator); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java index cb3378f41..c97aefbde 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/fluent/TestFluent.java @@ -27,6 +27,7 @@ package org.apache.hc.client5.testing.fluent; import java.io.File; +import java.net.InetSocketAddress; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -34,7 +35,9 @@ import org.apache.hc.client5.http.ClientProtocolException; import org.apache.hc.client5.http.HttpResponseException; import org.apache.hc.client5.http.fluent.Content; import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.TestServer; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.HttpHost; @@ -42,7 +45,6 @@ import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; -import org.apache.hc.core5.testing.classic.ClassicTestServer; import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -54,52 +56,51 @@ public class TestFluent { public static final Timeout TIMEOUT = Timeout.ofMinutes(1); @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); - - public HttpHost targetHost() { - return testResources.targetHost(); - } + private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, ClientProtocolLevel.STANDARD, TIMEOUT); @BeforeEach public void setUp() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("/", (request, response, context) -> - response.setEntity(new StringEntity("All is well", ContentType.TEXT_PLAIN))); - server.registerHandler("/echo", (request, response, context) -> { - HttpEntity responseEntity = null; - final HttpEntity requestEntity = request.getEntity(); - if (requestEntity != null) { - final String contentTypeStr = requestEntity.getContentType(); - final ContentType contentType = contentTypeStr == null ? ContentType.DEFAULT_TEXT : ContentType.parse(contentTypeStr); - if (ContentType.TEXT_PLAIN.getMimeType().equals(contentType.getMimeType())) { - responseEntity = new StringEntity( - EntityUtils.toString(requestEntity), ContentType.TEXT_PLAIN); - } - } - if (responseEntity == null) { - responseEntity = new StringEntity("echo", ContentType.TEXT_PLAIN); - } - response.setEntity(responseEntity); - }); - - // Handler for large content large message - server.registerHandler("/large-message", (request, response, context) -> { - final String largeContent = generateLargeString(10000); // Large content string - response.setEntity(new StringEntity(largeContent, ContentType.TEXT_PLAIN)); - }); - - // Handler for large content large message with error - server.registerHandler("/large-message-error", (request, response, context) -> { - final String largeContent = generateLargeString(10000); // Large content string - response.setCode(HttpStatus.SC_REDIRECTION); - response.setEntity(new StringEntity(largeContent, ContentType.TEXT_PLAIN)); - }); + testResources.configureServer(bootstrap -> bootstrap + .register("/", (request, response, context) -> + response.setEntity(new StringEntity("All is well", ContentType.TEXT_PLAIN))) + .register("/echo", (request, response, context) -> { + HttpEntity responseEntity = null; + final HttpEntity requestEntity = request.getEntity(); + if (requestEntity != null) { + final String contentTypeStr = requestEntity.getContentType(); + final ContentType contentType = contentTypeStr == null ? ContentType.DEFAULT_TEXT : ContentType.parse(contentTypeStr); + if (ContentType.TEXT_PLAIN.getMimeType().equals(contentType.getMimeType())) { + responseEntity = new StringEntity( + EntityUtils.toString(requestEntity), ContentType.TEXT_PLAIN); + } + } + if (responseEntity == null) { + responseEntity = new StringEntity("echo", ContentType.TEXT_PLAIN); + } + response.setEntity(responseEntity); + }) + // Handler for large content large message + .register("/large-message", (request, response, context) -> { + final String largeContent = generateLargeString(10000); // Large content string + response.setEntity(new StringEntity(largeContent, ContentType.TEXT_PLAIN)); + }) + // Handler for large content large message with error + .register("/large-message-error", (request, response, context) -> { + final String largeContent = generateLargeString(10000); // Large content string + response.setCode(HttpStatus.SC_REDIRECTION); + response.setEntity(new StringEntity(largeContent, ContentType.TEXT_PLAIN)); + })); + } + public HttpHost startServer() throws Exception { + final TestServer server = testResources.server(); + final InetSocketAddress inetSocketAddress = server.start(); + return new HttpHost(testResources.scheme().id, "localhost", inetSocketAddress.getPort()); } @Test public void testGetRequest() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final String message = Request.get(baseURL + "/").execute().returnContent().asString(); Assertions.assertEquals("All is well", message); @@ -107,7 +108,7 @@ public class TestFluent { @Test public void testGetRequestByName() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final String message = Request.create("GET", baseURL + "/").execute().returnContent().asString(); Assertions.assertEquals("All is well", message); @@ -115,7 +116,7 @@ public class TestFluent { @Test public void testGetRequestByNameWithURI() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final String message = Request.create("GET", new URI(baseURL + "/")).execute().returnContent().asString(); Assertions.assertEquals("All is well", message); @@ -123,7 +124,7 @@ public class TestFluent { @Test public void testGetRequestFailure() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); Assertions.assertThrows(ClientProtocolException.class, () -> Request.get(baseURL + "/boom").execute().returnContent().asString()); @@ -131,7 +132,7 @@ public class TestFluent { @Test public void testPostRequest() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final String message1 = Request.post(baseURL + "/echo") .bodyString("what is up?", ContentType.TEXT_PLAIN) @@ -145,7 +146,7 @@ public class TestFluent { @Test public void testContentAsStringWithCharset() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final Content content = Request.post(baseURL + "/echo").bodyByteArray("Ü".getBytes(StandardCharsets.UTF_8)).execute() .returnContent(); @@ -156,7 +157,7 @@ public class TestFluent { @Test public void testConnectionRelease() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); for (int i = 0; i < 20; i++) { Request.get(baseURL + "/").execute().returnContent(); @@ -183,7 +184,7 @@ public class TestFluent { @Test public void testLargeResponse() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); final Content content = Request.get(baseURL + "/large-message").execute().returnContent(); @@ -192,7 +193,7 @@ public class TestFluent { @Test public void testLargeResponseError() throws Exception { - final HttpHost target = targetHost(); + final HttpHost target = startServer(); final String baseURL = "http://localhost:" + target.getPort(); try { diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/AbstractIntegrationTestBase.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/AbstractIntegrationTestBase.java new file mode 100644 index 000000000..85bf42774 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/AbstractIntegrationTestBase.java @@ -0,0 +1,81 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync; + +import java.net.InetSocketAddress; +import java.util.function.Consumer; + +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; +import org.apache.hc.client5.testing.sync.extension.TestClientBuilder; +import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.TestServer; +import org.apache.hc.client5.testing.sync.extension.TestServerBootstrap; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.util.Timeout; +import org.junit.jupiter.api.extension.RegisterExtension; + +public abstract class AbstractIntegrationTestBase { + + public static final Timeout TIMEOUT = Timeout.ofMinutes(1); + + @RegisterExtension + private TestClientResources testResources; + + protected AbstractIntegrationTestBase(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel) { + this.testResources = new TestClientResources(scheme, clientProtocolLevel, TIMEOUT); + } + + public URIScheme scheme() { + return testResources.scheme(); + } + + public ClientProtocolLevel getClientProtocolLevel() { + return testResources.getClientProtocolLevel(); + } + + public void configureServer(final Consumer serverCustomizer) { + testResources.configureServer(serverCustomizer); + } + + public HttpHost startServer() throws Exception { + final TestServer server = testResources.server(); + final InetSocketAddress inetSocketAddress = server.start(); + return new HttpHost(testResources.scheme().id, "localhost", inetSocketAddress.getPort()); + } + + public void configureClient(final Consumer clientCustomizer) { + testResources.configureClient(clientCustomizer); + } + + public TestClient client() throws Exception { + return testResources.client(); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestBasicConnectionManager.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestBasicConnectionManager.java index 1d29bc8e0..3c7b13e04 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestBasicConnectionManager.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestBasicConnectionManager.java @@ -27,35 +27,31 @@ package org.apache.hc.client5.testing.sync; import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; import org.apache.hc.client5.testing.classic.RandomHandler; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -public class TestBasicConnectionManager { +public class TestBasicConnectionManager extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); + public TestBasicConnectionManager() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); + } @Test public void testBasics() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient(builder -> builder - .setConnectionManager(new BasicHttpClientConnectionManager()) - ); + configureClient(builder -> builder + .setConnectionManager(new BasicHttpClientConnectionManager())); + final TestClient client = client(); final HttpGet get = new HttpGet("/random/1024"); client.execute(target, get, response -> { @@ -67,13 +63,13 @@ public class TestBasicConnectionManager { @Test public void testConnectionStillInUse() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient(builder -> builder - .setConnectionManager(new BasicHttpClientConnectionManager()) - ); + configureClient(builder -> builder + .setConnectionManager(new BasicHttpClientConnectionManager())); + final TestClient client = client(); final HttpGet get1 = new HttpGet("/random/1024"); client.executeOpen(target, get1, null); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java index 97596a7f1..c52677eab 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java @@ -58,15 +58,15 @@ import org.apache.hc.client5.http.impl.auth.BasicAuthCache; import org.apache.hc.client5.http.impl.auth.BasicScheme; import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory; import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.BasicTestAuthenticator; import org.apache.hc.client5.testing.auth.Authenticator; import org.apache.hc.client5.testing.auth.BearerAuthenticationHandler; import org.apache.hc.client5.testing.classic.AuthenticatingDecorator; import org.apache.hc.client5.testing.classic.EchoHandler; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; +import org.apache.hc.client5.testing.sync.extension.TestServerBootstrap; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.HeaderElements; @@ -77,10 +77,8 @@ import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; import org.apache.hc.core5.http.config.Registry; import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.impl.HttpProcessors; import org.apache.hc.core5.http.io.HttpRequestHandler; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.InputStreamEntity; @@ -88,62 +86,42 @@ import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.support.BasicResponseBuilder; import org.apache.hc.core5.net.URIAuthority; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mockito; /** * Unit tests for automatic client authentication. */ -public abstract class TestClientAuthentication { - - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources; +public abstract class TestClientAuthentication extends AbstractIntegrationTestBase { protected TestClientAuthentication(final URIScheme scheme) { - this.testResources = new TestClientResources(scheme, TIMEOUT); + super(scheme, ClientProtocolLevel.STANDARD); } - public URIScheme scheme() { - return testResources.scheme(); + public void configureServerWithBasicAuth(final Authenticator authenticator, + final Consumer serverCustomizer) throws IOException { + configureServer(bootstrap -> { + bootstrap.setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingDecorator(requestHandler, authenticator)); + serverCustomizer.accept(bootstrap); + }); } - public ClassicTestServer startServer(final Authenticator authenticator) throws IOException { - return testResources.startServer( - null, - null, - requestHandler -> new AuthenticatingDecorator(requestHandler, authenticator)); - } - - public ClassicTestServer startServer() throws IOException { - return startServer(new BasicTestAuthenticator("test:test", "test realm")); - } - - public CloseableHttpClient startClient(final Consumer clientCustomizer) throws Exception { - return testResources.startClient(clientCustomizer); - } - - public CloseableHttpClient startClient() throws Exception { - return testResources.startClient(builder -> {}); - } - - public HttpHost targetHost() { - return testResources.targetHost(); + public void configureServerWithBasicAuth(final Consumer serverCustomizer) throws IOException { + configureServerWithBasicAuth( + new BasicTestAuthenticator("test:test", "test realm"), + serverCustomizer); } @Test public void testBasicAuthenticationNoCreds() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -163,11 +141,11 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationFailure() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -189,11 +167,11 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationSuccess() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet httpget = new HttpGet("/"); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -214,11 +192,11 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationSuccessOnNonRepeatablePutExpectContinue() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final RequestConfig config = RequestConfig.custom() .setExpectContinueEnabled(true) @@ -227,8 +205,8 @@ public abstract class TestClientAuthentication { httpput.setConfig(config); httpput.setEntity(new InputStreamEntity( new ByteArrayInputStream( - new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ), - -1, null)); + new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9}), + -1, null)); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); Mockito.when(credsProvider.getCredentials(Mockito.any(), Mockito.any())) @@ -245,19 +223,19 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationFailureOnNonRepeatablePutDontExpectContinue() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final RequestConfig config = RequestConfig.custom().setExpectContinueEnabled(false).build(); final HttpPut httpput = new HttpPut("/"); httpput.setConfig(config); httpput.setEntity(new InputStreamEntity( new ByteArrayInputStream( - new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ), - -1, null)); + new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9}), + -1, null)); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -276,11 +254,11 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationSuccessOnRepeatablePost() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpPost httppost = new HttpPost("/"); httppost.setEntity(new StringEntity("some important stuff", StandardCharsets.US_ASCII)); @@ -304,16 +282,16 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationFailureOnNonRepeatablePost() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpPost httppost = new HttpPost("/"); httppost.setEntity(new InputStreamEntity( new ByteArrayInputStream( - new byte[] { 0,1,2,3,4,5,6,7,8,9 }), -1, null)); + new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), -1, null)); final HttpClientContext context = HttpClientContext.create(); context.setRequestConfig(RequestConfig.custom() @@ -335,17 +313,18 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationCredentialsCaching() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); final DefaultAuthenticationStrategy authStrategy = Mockito.spy(new DefaultAuthenticationStrategy()); final Queue responseQueue = new ConcurrentLinkedQueue<>(); - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .setTargetAuthenticationStrategy(authStrategy) .addResponseInterceptorLast((response, entity, context) -> responseQueue.add(BasicResponseBuilder.copy(response).build()))); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); context.setCredentialsProvider(CredentialsProviderBuilder.create() @@ -372,17 +351,18 @@ public abstract class TestClientAuthentication { @Test public void testBasicAuthenticationCredentialsCachingByPathPrefix() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); final DefaultAuthenticationStrategy authStrategy = Mockito.spy(new DefaultAuthenticationStrategy()); final Queue responseQueue = new ConcurrentLinkedQueue<>(); - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .setTargetAuthenticationStrategy(authStrategy) .addResponseInterceptorLast((response, entity, context) -> responseQueue.add(BasicResponseBuilder.copy(response).build()))); + final TestClient client = client(); final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create() .add(target, "test", "test".toCharArray()) @@ -393,7 +373,7 @@ public abstract class TestClientAuthentication { context.setAuthCache(authCache); context.setCredentialsProvider(credentialsProvider); - for (final String requestPath: new String[] {"/blah/a", "/blah/b?huh", "/blah/c", "/bl%61h/%61"}) { + for (final String requestPath : new String[]{"/blah/a", "/blah/b?huh", "/blah/c", "/bl%61h/%61"}) { final HttpGet httpget = new HttpGet(requestPath); client.execute(target, httpget, context, response -> { final HttpEntity entity1 = response.getEntity(); @@ -415,7 +395,7 @@ public abstract class TestClientAuthentication { authCache.clear(); Mockito.reset(authStrategy); - for (final String requestPath: new String[] {"/blah/a", "/yada/a", "/blah/blah/", "/buh/a"}) { + for (final String requestPath : new String[]{"/blah/a", "/yada/a", "/blah/blah/", "/buh/a"}) { final HttpGet httpget = new HttpGet(requestPath); client.execute(target, httpget, context, response -> { final HttpEntity entity1 = response.getEntity(); @@ -436,7 +416,7 @@ public abstract class TestClientAuthentication { @Test public void testAuthenticationCredentialsCachingReAuthenticationOnDifferentRealm() throws Exception { - final ClassicTestServer server = startServer(new Authenticator() { + configureServerWithBasicAuth(new Authenticator() { @Override public boolean authenticate(final URIAuthority authority, final String requestUri, final String credentials) { @@ -460,15 +440,15 @@ public abstract class TestClientAuthentication { } } - }); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + }, bootstrap -> bootstrap.register("*", new EchoHandler())); + final HttpHost target = startServer(); final DefaultAuthenticationStrategy authStrategy = Mockito.spy(new DefaultAuthenticationStrategy()); - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .setTargetAuthenticationStrategy(authStrategy) ); + final TestClient client = client(); final CredentialsProvider credsProvider = CredentialsProviderBuilder.create() .add(new AuthScope(target, "this realm", null), "test", "this".toCharArray()) @@ -513,12 +493,12 @@ public abstract class TestClientAuthentication { @Test public void testAuthenticationUserinfoInRequest() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); - final HttpGet httpget = new HttpGet("http://test:test@" + target.toHostString() + "/"); + final TestClient client = client(); + final HttpGet httpget = new HttpGet("http://test:test@" + target.toHostString() + "/"); final HttpClientContext context = HttpClientContext.create(); Assertions.assertThrows(ClientProtocolException.class, () -> client.execute(target, httpget, context, response -> null)); @@ -527,11 +507,12 @@ public abstract class TestClientAuthentication { @Test public void testPreemptiveAuthentication() throws Exception { final Authenticator authenticator = Mockito.spy(new BasicTestAuthenticator("test:test", "test realm")); - final ClassicTestServer server = startServer(authenticator); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(authenticator, + bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final BasicScheme basicScheme = new BasicScheme(); basicScheme.initPreemptive(new UsernamePasswordCredentials("test", "test".toCharArray())); @@ -555,11 +536,12 @@ public abstract class TestClientAuthentication { @Test public void testPreemptiveAuthenticationFailure() throws Exception { final Authenticator authenticator = Mockito.spy(new BasicTestAuthenticator("test:test", "test realm")); - final ClassicTestServer server = startServer(authenticator); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServerWithBasicAuth(authenticator, + bootstrap -> bootstrap + .register("*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final AuthCache authCache = new BasicAuthCache(); @@ -602,11 +584,11 @@ public abstract class TestClientAuthentication { @Test public void testAuthenticationTargetAsProxy() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("*", new ProxyAuthHandler()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap + .register("*", new ProxyAuthHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient(builder -> {}); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -623,22 +605,22 @@ public abstract class TestClientAuthentication { @Test public void testConnectionCloseAfterAuthenticationSuccess() throws Exception { - final ClassicTestServer server = testResources.startServer( - Http1Config.DEFAULT, - HttpProcessors.server(), - requestHandler -> new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) { + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) { - @Override - protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { - unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE); - } + @Override + protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { + unauthorized.addHeader(HttpHeaders.CONNECTION, HeaderElements.CLOSE); + } - } - ); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + } + ) + .register("*", new EchoHandler())); - final CloseableHttpClient client = startClient(); + final HttpHost target = startServer(); + + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = CredentialsProviderBuilder.create() @@ -701,28 +683,29 @@ public abstract class TestClientAuthentication { } }; - final ClassicTestServer server = testResources.startServer( - Http1Config.DEFAULT, - HttpProcessors.server(), - requestHandler -> new AuthenticatingDecorator(requestHandler, authenticator) { + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingDecorator(requestHandler, authenticator) { - @Override - protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { - unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE); - unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\""); - } + @Override + protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { + unauthorized.removeHeaders(HttpHeaders.WWW_AUTHENTICATE); + unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\""); + } - } - ); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + } + ) + .register("*", new EchoHandler())); - final CloseableHttpClient client = startClient(builder -> builder + final HttpHost target = startServer(); + + configureClient(builder -> builder .setDefaultAuthSchemeRegistry(authSchemeRegistry) - .setDefaultCredentialsProvider(credsProvider) ); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credsProvider); for (int i = 0; i < 10; i++) { final HttpGet httpget = new HttpGet("/"); httpget.setConfig(config); @@ -738,22 +721,22 @@ public abstract class TestClientAuthentication { @Test public void testAuthenticationFallback() throws Exception { - final ClassicTestServer server = testResources.startServer( - Http1Config.DEFAULT, - HttpProcessors.server(), - requestHandler -> new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) { + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingDecorator(requestHandler, new BasicTestAuthenticator("test:test", "test realm")) { - @Override - protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { - unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid"); - } + @Override + protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) { + unauthorized.addHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.DIGEST + " realm=\"test realm\" invalid"); + } - } - ); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + } + ) + .register("*", new EchoHandler())); - final CloseableHttpClient client = startClient(); + final HttpHost target = startServer(); + + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); @@ -784,17 +767,18 @@ public abstract class TestClientAuthentication { buf.append(CHARS.charAt(secureRandom.nextInt(CHARS.length() - 1))); } final String token = buf.toString(); - final ClassicTestServer server = testResources.startServer( - Http1Config.DEFAULT, - HttpProcessors.server(), - requestHandler -> new AuthenticatingDecorator( - requestHandler, - new BearerAuthenticationHandler(), - new BasicTestAuthenticator(token, "test realm"))); - server.registerHandler("*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> + new AuthenticatingDecorator( + requestHandler, + new BearerAuthenticationHandler(), + new BasicTestAuthenticator(token, "test realm")) + ) + .register("*", new EchoHandler())); - final CloseableHttpClient client = startClient(); + final HttpHost target = startServer(); + + final TestClient client = client(); final CredentialsProvider credsProvider = Mockito.mock(CredentialsProvider.class); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java index 537fd9c54..57bf594d2 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientRequestExecution.java @@ -33,17 +33,16 @@ import java.util.Random; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; import org.apache.hc.client5.http.HttpRequestRetryStrategy; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.RedirectLocations; import org.apache.hc.client5.http.utils.URIUtils; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.Header; @@ -64,46 +63,18 @@ import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicClassicHttpRequest; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.net.URIBuilder; -import org.apache.hc.core5.testing.classic.ClassicTestServer; import org.apache.hc.core5.util.TimeValue; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Client protocol handling tests. */ -public abstract class TestClientRequestExecution { +public abstract class TestClientRequestExecution extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources; - - protected TestClientRequestExecution(final URIScheme scheme) { - this.testResources = new TestClientResources(scheme, TIMEOUT); - } - - public URIScheme scheme() { - return testResources.scheme(); - } - - public ClassicTestServer startServer() throws IOException { - return testResources.startServer(null, null, null); - } - - public CloseableHttpClient startClient(final Consumer clientCustomizer) throws Exception { - return testResources.startClient(clientCustomizer); - } - - public CloseableHttpClient startClient() throws Exception { - return testResources.startClient(builder -> {}); - } - - public HttpHost targetHost() { - return testResources.targetHost(); + public TestClientRequestExecution(final URIScheme scheme) { + super(scheme, ClientProtocolLevel.STANDARD); } private static class SimpleService implements HttpRequestHandler { @@ -161,9 +132,8 @@ public abstract class TestClientRequestExecution { @Test public void testAutoGeneratedHeaders() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new SimpleService()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); final HttpRequestInterceptor interceptor = (request, entityDetails, context) -> request.addHeader("my-header", "stuff"); @@ -196,11 +166,12 @@ public abstract class TestClientRequestExecution { }; - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .addRequestInterceptorFirst(interceptor) .setRequestExecutor(new FaultyHttpRequestExecutor("Oppsie")) .setRetryStrategy(requestRetryStrategy) ); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); @@ -221,9 +192,8 @@ public abstract class TestClientRequestExecution { @Test public void testNonRepeatableEntity() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new SimpleService()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); final HttpRequestRetryStrategy requestRetryStrategy = new HttpRequestRetryStrategy() { @@ -254,10 +224,11 @@ public abstract class TestClientRequestExecution { }; - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .setRequestExecutor(new FaultyHttpRequestExecutor("a message showing that this failed")) .setRetryStrategy(requestRetryStrategy) ); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); @@ -272,11 +243,10 @@ public abstract class TestClientRequestExecution { @Test public void testNonCompliantURI() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new SimpleService()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", "{{|boom|}}"); @@ -293,11 +263,10 @@ public abstract class TestClientRequestExecution { @Test public void testRelativeRequestURIWithFragment() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new SimpleService()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet httpget = new HttpGet("/stuff#blahblah"); final HttpClientContext context = HttpClientContext.create(); @@ -314,11 +283,10 @@ public abstract class TestClientRequestExecution { @Test public void testAbsoluteRequestURIWithFragment() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new SimpleService()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final URI uri = new URIBuilder() .setHost(target.getHostName()) @@ -347,13 +315,12 @@ public abstract class TestClientRequestExecution { @Test @Disabled("Fails intermittently with GitHub Actions") public void testRequestCancellation() throws Exception { startServer(); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnPerRoute(1) - .setMaxConnTotal(1), - builder -> {}); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(1); + connManager.setDefaultMaxPerRoute(1); final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); try { diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java index 8d366d3a6..d77ca68ca 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionManagement.java @@ -32,13 +32,14 @@ import java.util.concurrent.TimeoutException; import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.config.ConnectionConfig; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.io.ConnectionEndpoint; import org.apache.hc.client5.http.io.LeaseRequest; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.testing.classic.RandomHandler; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.HttpException; @@ -56,24 +57,21 @@ import org.apache.hc.core5.http.protocol.RequestContent; import org.apache.hc.core5.http.protocol.RequestTargetHost; import org.apache.hc.core5.pool.PoolConcurrencyPolicy; import org.apache.hc.core5.pool.PoolReusePolicy; -import org.apache.hc.core5.testing.classic.ClassicTestServer; import org.apache.hc.core5.util.TimeValue; import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Tests for {@code PoolingHttpClientConnectionManager} that do require a server * to communicate with. */ -public class TestConnectionManagement { +public class TestConnectionManagement extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); + public TestConnectionManagement() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); + } ConnectionEndpoint.RequestExecutor exec; @@ -97,30 +95,17 @@ public class TestConnectionManagement { }; } - public ClassicTestServer startServer() throws IOException { - return testResources.startServer(null, null, null); - } - - public CloseableHttpClient startClient() throws Exception { - return testResources.startClient(b -> {}, b -> {}); - } - - public HttpHost targetHost() { - return testResources.targetHost(); - } - /** * Tests releasing and re-using a connection after a response is read. */ @Test public void testReleaseConnection() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - startClient(); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); connManager.setMaxTotal(1); final HttpRoute route = new HttpRoute(target, null, false); @@ -178,13 +163,12 @@ public class TestConnectionManagement { */ @Test public void testReleaseConnectionWithTimeLimits() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - startClient(); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); connManager.setMaxTotal(1); final HttpRoute route = new HttpRoute(target, null, false); @@ -250,11 +234,9 @@ public class TestConnectionManagement { @Test public void testCloseExpiredIdleConnections() throws Exception { - startServer(); - final HttpHost target = targetHost(); - startClient(); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final HttpHost target = startServer(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); connManager.setMaxTotal(1); final HttpRoute route = new HttpRoute(target, null, false); @@ -292,22 +274,21 @@ public class TestConnectionManagement { @Test public void testCloseExpiredTTLConnections() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - testResources.startClient( - builder -> builder + configureClient(builder -> builder + .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT) .setConnPoolPolicy(PoolReusePolicy.LIFO) .setDefaultConnectionConfig(ConnectionConfig.custom() .setTimeToLive(TimeValue.ofMilliseconds(100)) .build()) - .setMaxConnTotal(1), - builder -> {} - ); + .build())); + final TestClient client = client(); - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); connManager.setMaxTotal(1); final HttpRoute route = new HttpRoute(target, null, false); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionReuse.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionReuse.java index 6029d2574..37017a0f2 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionReuse.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestConnectionReuse.java @@ -39,7 +39,8 @@ import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.testing.classic.RandomHandler; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ContentType; import org.apache.hc.core5.http.EntityDetails; @@ -55,39 +56,25 @@ import org.apache.hc.core5.http.impl.HttpProcessors; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.InputStreamEntity; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.http.protocol.HttpProcessor; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -public class TestConnectionReuse { +public class TestConnectionReuse extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); - - public HttpHost targetHost() { - return testResources.targetHost(); + public TestConnectionReuse() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); } @Test public void testReuseOfPersistentConnections() throws Exception { - final ClassicTestServer server = testResources.startServer( null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(5) - .setMaxConnPerRoute(5), - builder -> { - } - ); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(5); final WorkerThread[] workers = new WorkerThread[10]; for (int i = 0; i < workers.length; i++) { @@ -117,19 +104,14 @@ public class TestConnectionReuse { @Test public void testReuseOfPersistentConnectionsWithStreamedRequestAndResponse() throws Exception { - final ClassicTestServer server = testResources.startServer( null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(5) - .setMaxConnPerRoute(5), - builder -> { - } - ); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(5); final WorkerThread[] workers = new WorkerThread[10]; for (int i = 0; i < workers.length; i++) { @@ -176,21 +158,16 @@ public class TestConnectionReuse { @Test public void testReuseOfClosedConnections() throws Exception { - final HttpProcessor httpproc = HttpProcessors.customServer(null) - .add(new AlwaysCloseConn()) - .build(); - final ClassicTestServer server = testResources.startServer( null, httpproc, null); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setHttpProcessor(HttpProcessors.customServer(null) + .add(new AlwaysCloseConn()) + .build())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(5) - .setMaxConnPerRoute(5), - builder -> { - } - ); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(5); final WorkerThread[] workers = new WorkerThread[10]; for (int i = 0; i < workers.length; i++) { @@ -220,19 +197,14 @@ public class TestConnectionReuse { @Test public void testReuseOfAbortedConnections() throws Exception { - final ClassicTestServer server = testResources.startServer( null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(5) - .setMaxConnPerRoute(5), - builder -> { - } - ); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(5); + connManager.setDefaultMaxPerRoute(5); final WorkerThread[] workers = new WorkerThread[10]; for (int i = 0; i < workers.length; i++) { @@ -262,23 +234,17 @@ public class TestConnectionReuse { @Test public void testKeepAliveHeaderRespected() throws Exception { - final HttpProcessor httpproc = HttpProcessors.customServer(null) - .add(new ResponseKeepAlive()) - .build(); - final ClassicTestServer server = testResources.startServer( null, httpproc, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); - - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(1) - .setMaxConnPerRoute(1), - builder -> { - } - ); - - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + configureServer(bootstrap -> bootstrap + .setHttpProcessor(HttpProcessors.customServer(null) + .add(new ResponseKeepAlive()) + .build()) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); + connManager.setMaxTotal(1); + connManager.setDefaultMaxPerRoute(1); client.execute(target, new HttpGet("/random/2000"), response -> { EntityUtils.consume(response.getEntity()); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestContentCodings.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestContentCodings.java index 211ce9b08..3127b245f 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestContentCodings.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestContentCodings.java @@ -38,16 +38,15 @@ import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.function.Consumer; import java.util.zip.Deflater; import java.util.zip.GZIPOutputStream; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.HeaderElement; @@ -61,46 +60,18 @@ import org.apache.hc.core5.http.io.entity.InputStreamEntity; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.MessageSupport; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Test case for how Content Codings are processed. By default, we want to do the right thing and * require no intervention from the user of HttpClient, but we still want to let clients do their * own thing if they so wish. */ -public abstract class TestContentCodings { - - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources; +public abstract class TestContentCodings extends AbstractIntegrationTestBase { protected TestContentCodings(final URIScheme scheme) { - this.testResources = new TestClientResources(scheme, TIMEOUT); - } - - public URIScheme scheme() { - return testResources.scheme(); - } - - public ClassicTestServer startServer() throws IOException { - return testResources.startServer(null, null, null); - } - - public CloseableHttpClient startClient(final Consumer clientCustomizer) throws Exception { - return testResources.startClient(clientCustomizer); - } - - public CloseableHttpClient startClient() throws Exception { - return testResources.startClient(builder -> {}); - } - - public HttpHost targetHost() { - return testResources.targetHost(); + super(scheme, ClientProtocolLevel.STANDARD); } /** @@ -112,24 +83,24 @@ public abstract class TestContentCodings { */ @Test public void testResponseWithNoContent() throws Exception { - final ClassicTestServer server = startServer(); - server.registerHandler("*", new HttpRequestHandler() { + configureServer(bootstrap -> bootstrap + .register("*", new HttpRequestHandler() { - /** - * {@inheritDoc} - */ - @Override - public void handle( - final ClassicHttpRequest request, - final ClassicHttpResponse response, - final HttpContext context) throws HttpException, IOException { - response.setCode(HttpStatus.SC_NO_CONTENT); - } - }); + /** + * {@inheritDoc} + */ + @Override + public void handle( + final ClassicHttpRequest request, + final ClassicHttpResponse response, + final HttpContext context) throws HttpException, IOException { + response.setCode(HttpStatus.SC_NO_CONTENT); + } + })); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -149,12 +120,12 @@ public abstract class TestContentCodings { public void testDeflateSupportForServerReturningRfc1950Stream() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false)); + configureServer(bootstrap -> bootstrap + .register("*", createDeflateEncodingRequestHandler(entityText, false))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -174,12 +145,12 @@ public abstract class TestContentCodings { public void testDeflateSupportForServerReturningRfc1951Stream() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true)); + configureServer(bootstrap -> bootstrap + .register("*", createDeflateEncodingRequestHandler(entityText, true))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -198,12 +169,12 @@ public abstract class TestContentCodings { public void testGzipSupport() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createGzipEncodingRequestHandler(entityText)); + configureServer(bootstrap -> bootstrap + .register("*", createGzipEncodingRequestHandler(entityText))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -223,13 +194,13 @@ public abstract class TestContentCodings { public void testThreadSafetyOfContentCodings() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createGzipEncodingRequestHandler(entityText)); + configureServer(bootstrap -> bootstrap + .register("*", createGzipEncodingRequestHandler(entityText))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final TestClient client = client(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); /* * Create a load of workers which will access the resource. Half will use the default @@ -273,12 +244,12 @@ public abstract class TestContentCodings { public void testHttpEntityWriteToForGzip() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createGzipEncodingRequestHandler(entityText)); + configureServer(bootstrap -> bootstrap + .register("*", createGzipEncodingRequestHandler(entityText))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -294,12 +265,12 @@ public abstract class TestContentCodings { public void testHttpEntityWriteToForDeflate() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createDeflateEncodingRequestHandler(entityText, true)); + configureServer(bootstrap -> bootstrap + .register("*", createDeflateEncodingRequestHandler(entityText, true))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); client.execute(target, request, response -> { @@ -314,12 +285,12 @@ public abstract class TestContentCodings { public void gzipResponsesWorkWithBasicResponseHandler() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createGzipEncodingRequestHandler(entityText)); + configureServer(bootstrap -> bootstrap + .register("*", createGzipEncodingRequestHandler(entityText))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); final String response = client.execute(target, request, new BasicHttpClientResponseHandler()); @@ -330,12 +301,12 @@ public abstract class TestContentCodings { public void deflateResponsesWorkWithBasicResponseHandler() throws Exception { final String entityText = "Hello, this is some plain text coming back."; - final ClassicTestServer server = startServer(); - server.registerHandler("*", createDeflateEncodingRequestHandler(entityText, false)); + configureServer(bootstrap -> bootstrap + .register("*", createDeflateEncodingRequestHandler(entityText, false))); - final HttpHost target = targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet request = new HttpGet("/some-resource"); final String response = client.execute(target, request, new BasicHttpClientResponseHandler()); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestCookieVirtualHost.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestCookieVirtualHost.java index 195c89ebb..ff63fe28d 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestCookieVirtualHost.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestCookieVirtualHost.java @@ -33,75 +33,71 @@ import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.cookie.BasicCookieStore; import org.apache.hc.client5.http.cookie.Cookie; import org.apache.hc.client5.http.cookie.CookieStore; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.protocol.HttpClientContext; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.message.BasicHeader; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * This class tests cookie matching when using Virtual Host. */ -public class TestCookieVirtualHost { +public class TestCookieVirtualHost extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); + public TestCookieVirtualHost() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); + } @Test public void testCookieMatchingWithVirtualHosts() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandlerVirtual("app.mydomain.fr", "*", (request, response, context) -> { + configureServer(bootstrap -> bootstrap + .register("app.mydomain.fr", "*", (request, response, context) -> { - final int n = Integer.parseInt(request.getFirstHeader("X-Request").getValue()); - switch (n) { - case 1: - // Assert Host is forwarded from URI - Assertions.assertEquals("app.mydomain.fr", request - .getFirstHeader("Host").getValue()); + final int n = Integer.parseInt(request.getFirstHeader("X-Request").getValue()); + switch (n) { + case 1: + // Assert Host is forwarded from URI + Assertions.assertEquals("app.mydomain.fr", request + .getFirstHeader("Host").getValue()); - response.setCode(HttpStatus.SC_OK); - // Respond with Set-Cookie on virtual host domain. This - // should be valid. - response.addHeader(new BasicHeader("Set-Cookie", - "name1=value1; domain=mydomain.fr; path=/")); - break; + response.setCode(HttpStatus.SC_OK); + // Respond with Set-Cookie on virtual host domain. This + // should be valid. + response.addHeader(new BasicHeader("Set-Cookie", + "name1=value1; domain=mydomain.fr; path=/")); + break; - case 2: - // Assert Host is still forwarded from URI - Assertions.assertEquals("app.mydomain.fr", request - .getFirstHeader("Host").getValue()); + case 2: + // Assert Host is still forwarded from URI + Assertions.assertEquals("app.mydomain.fr", request + .getFirstHeader("Host").getValue()); - // We should get our cookie back. - Assertions.assertNotNull(request.getFirstHeader("Cookie"), "We must get a cookie header"); - response.setCode(HttpStatus.SC_OK); - break; + // We should get our cookie back. + Assertions.assertNotNull(request.getFirstHeader("Cookie"), "We must get a cookie header"); + response.setCode(HttpStatus.SC_OK); + break; - case 3: - // Assert Host is forwarded from URI - Assertions.assertEquals("app.mydomain.fr", request - .getFirstHeader("Host").getValue()); + case 3: + // Assert Host is forwarded from URI + Assertions.assertEquals("app.mydomain.fr", request + .getFirstHeader("Host").getValue()); - response.setCode(HttpStatus.SC_OK); - break; - default: - Assertions.fail("Unexpected value: " + n); - break; - } - }); + response.setCode(HttpStatus.SC_OK); + break; + default: + Assertions.fail("Unexpected value: " + n); + break; + } + })); - final HttpHost target = testResources.targetHost(); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient(b -> {}); + final TestClient client = client(); final CookieStore cookieStore = new BasicCookieStore(); final HttpClientContext context = HttpClientContext.create(); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestIdleConnectionEviction.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestIdleConnectionEviction.java index dc2d26435..1b4e93205 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestIdleConnectionEviction.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestIdleConnectionEviction.java @@ -35,32 +35,29 @@ import org.apache.hc.client5.http.impl.IdleConnectionEvictor; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.testing.classic.RandomHandler; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.testing.classic.ClassicTestServer; import org.apache.hc.core5.util.TimeValue; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -public class TestIdleConnectionEviction { +public class TestIdleConnectionEviction extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); + public TestIdleConnectionEviction() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); + } @Test public void testIdleConnectionEviction() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = testResources.startClient(b -> {}); + final TestClient client = client(); - final PoolingHttpClientConnectionManager connManager = testResources.connManager(); + final PoolingHttpClientConnectionManager connManager = client.getConnectionManager(); connManager.setDefaultMaxPerRoute(10); connManager.setMaxTotal(50); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMinimalClientRequestExecution.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMinimalClientRequestExecution.java index 1681a4bdc..77c433285 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMinimalClientRequestExecution.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestMinimalClientRequestExecution.java @@ -32,9 +32,9 @@ import java.util.Locale; import java.util.Set; import org.apache.hc.client5.http.classic.methods.HttpGet; -import org.apache.hc.client5.http.impl.classic.MinimalHttpClient; import org.apache.hc.client5.http.protocol.HttpClientContext; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.Header; @@ -47,29 +47,18 @@ import org.apache.hc.core5.http.io.HttpRequestHandler; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Client protocol handling tests. */ -public abstract class TestMinimalClientRequestExecution { - - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources; +public abstract class TestMinimalClientRequestExecution extends AbstractIntegrationTestBase { protected TestMinimalClientRequestExecution(final URIScheme scheme) { - this.testResources = new TestClientResources(scheme, TIMEOUT); + super(scheme, ClientProtocolLevel.MINIMAL); } - public URIScheme scheme() { - return testResources.scheme(); - } private static class SimpleService implements HttpRequestHandler { public SimpleService() { @@ -89,11 +78,10 @@ public abstract class TestMinimalClientRequestExecution { @Test public void testNonCompliantURIWithContext() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("*", new SimpleService()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); - final MinimalHttpClient client = testResources.startMinimalClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); for (int i = 0; i < 10; i++) { @@ -121,11 +109,10 @@ public abstract class TestMinimalClientRequestExecution { @Test public void testNonCompliantURIWithoutContext() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("*", new SimpleService()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); - final MinimalHttpClient client = testResources.startMinimalClient(); + final TestClient client = client(); for (int i = 0; i < 10; i++) { final HttpGet request = new HttpGet("/"); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java index a881d1750..f576cf891 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestRedirects.java @@ -33,7 +33,6 @@ import java.net.URI; import java.util.Collections; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.function.Consumer; import org.apache.hc.client5.http.CircularRedirectException; import org.apache.hc.client5.http.ClientProtocolException; @@ -43,8 +42,6 @@ import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.cookie.BasicCookieStore; import org.apache.hc.client5.http.cookie.CookieStore; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; import org.apache.hc.client5.http.protocol.HttpClientContext; import org.apache.hc.client5.http.protocol.RedirectLocations; @@ -53,7 +50,8 @@ import org.apache.hc.client5.testing.classic.EchoHandler; import org.apache.hc.client5.testing.classic.RandomHandler; import org.apache.hc.client5.testing.classic.RedirectingDecorator; import org.apache.hc.client5.testing.redirect.Redirect; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.function.Decorator; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.Header; @@ -69,59 +67,31 @@ import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.message.BasicHeader; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.http.protocol.HttpProcessor; import org.apache.hc.core5.net.URIBuilder; -import org.apache.hc.core5.testing.classic.ClassicTestServer; -import org.apache.hc.core5.util.Timeout; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Redirection test cases. */ -public abstract class TestRedirects { - - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); - - @RegisterExtension - private TestClientResources testResources; +public abstract class TestRedirects extends AbstractIntegrationTestBase { protected TestRedirects(final URIScheme scheme) { - this.testResources = new TestClientResources(scheme, TIMEOUT); - } - - public URIScheme scheme() { - return testResources.scheme(); - } - - public ClassicTestServer startServer(final HttpProcessor httpProcessor, - final Decorator handlerDecorator) throws IOException { - return testResources.startServer(null, httpProcessor, handlerDecorator); - } - - public CloseableHttpClient startClient(final Consumer clientCustomizer) throws Exception { - return testResources.startClient(clientCustomizer); - } - - public CloseableHttpClient startClient() throws Exception { - return testResources.startClient(builder -> {}); - } - - public HttpHost targetHost() { - return testResources.targetHost(); + super(scheme, ClientProtocolLevel.STANDARD); } @Test public void testBasicRedirect300() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES))) + .register("/random/*", new RandomHandler()) + ); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); @@ -141,14 +111,16 @@ public abstract class TestRedirects { @Test public void testBasicRedirect300NoKeepAlive() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, - Redirect.ConnControl.CLOSE))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MULTIPLE_CHOICES, + Redirect.ConnControl.CLOSE))) + .register("/random/*", new RandomHandler()) + ); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); @@ -169,13 +141,14 @@ public abstract class TestRedirects { @Test public void testBasicRedirect301() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_PERMANENTLY))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); @@ -200,13 +173,14 @@ public abstract class TestRedirects { @Test public void testBasicRedirect302() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/50"); @@ -225,19 +199,20 @@ public abstract class TestRedirects { @Test public void testBasicRedirect302NoLocation() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.startsWith("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); - } - return null; - })); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, null); + } + return null; + })) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); @@ -255,13 +230,14 @@ public abstract class TestRedirects { @Test public void testBasicRedirect303() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_SEE_OTHER))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/123"); @@ -279,16 +255,15 @@ public abstract class TestRedirects { @Test public void testBasicRedirect304() throws Exception { - final ClassicTestServer server = startServer(null ,null); - server.registerHandler("/oldlocation/*", (request, response, context) -> { - response.setCode(HttpStatus.SC_NOT_MODIFIED); - response.addHeader(HttpHeaders.LOCATION, "/random/100"); - }); + configureServer(bootstrap -> bootstrap + .register("/oldlocation/*", (request, response, context) -> { + response.setCode(HttpStatus.SC_NOT_MODIFIED); + response.addHeader(HttpHeaders.LOCATION, "/random/100"); + }) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); - - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/stuff"); @@ -310,16 +285,15 @@ public abstract class TestRedirects { @Test public void testBasicRedirect305() throws Exception { - final ClassicTestServer server = startServer(null ,null); - server.registerHandler("/oldlocation/*", (request, response, context) -> { - response.setCode(HttpStatus.SC_USE_PROXY); - response.addHeader(HttpHeaders.LOCATION, "/random/100"); - }); + configureServer(bootstrap -> bootstrap + .register("/oldlocation/*", (request, response, context) -> { + response.setCode(HttpStatus.SC_USE_PROXY); + response.addHeader(HttpHeaders.LOCATION, "/random/100"); + }) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); - - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/stuff"); @@ -341,13 +315,14 @@ public abstract class TestRedirects { @Test public void testBasicRedirect307() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_TEMPORARY_REDIRECT))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/123"); @@ -365,14 +340,15 @@ public abstract class TestRedirects { @Test public void testMaxRedirectCheck() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", - HttpStatus.SC_MOVED_TEMPORARILY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(true) .setMaxRedirects(5) @@ -387,14 +363,16 @@ public abstract class TestRedirects { @Test public void testCircularRedirect() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", - HttpStatus.SC_MOVED_TEMPORARILY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/circular-oldlocation/", "/circular-oldlocation/", + HttpStatus.SC_MOVED_TEMPORARILY))) + .register("/random/*", new RandomHandler())); - final CloseableHttpClient client = startClient(); + final HttpHost target = startServer(); + + final TestClient client = client(); final RequestConfig config = RequestConfig.custom() .setCircularRedirectsAllowed(false) .build(); @@ -408,13 +386,14 @@ public abstract class TestRedirects { @Test public void testPostRedirectSeeOther() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER))); - server.registerHandler("/echo/*", new EchoHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/echo", HttpStatus.SC_SEE_OTHER))) + .register("/echo/*", new EchoHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpPost httppost = new HttpPost("/oldlocation/stuff"); @@ -434,19 +413,21 @@ public abstract class TestRedirects { @Test public void testRelativeRedirect() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.startsWith("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.startsWith("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/random/100"); - } - return null; - })); server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + } + return null; + })) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/stuff"); @@ -464,20 +445,21 @@ public abstract class TestRedirects { @Test public void testRelativeRedirect2() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/random/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/random/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "100"); - } - return null; - })); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + } + return null; + })) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/random/oldlocation"); @@ -495,20 +477,21 @@ public abstract class TestRedirects { @Test public void testRejectBogusRedirectLocation() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "xxx://bogus"); - } - return null; - })); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + } + return null; + })) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet httpget = new HttpGet("/oldlocation"); final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () -> @@ -518,20 +501,21 @@ public abstract class TestRedirects { @Test public void testRejectInvalidRedirectLocation() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - requestUri -> { - final String path = requestUri.getPath(); - if (path.equals("/oldlocation")) { - return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + requestUri -> { + final String path = requestUri.getPath(); + if (path.equals("/oldlocation")) { + return new Redirect(HttpStatus.SC_MOVED_TEMPORARILY, "/newlocation/?p=I have spaces"); - } - return null; - })); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + } + return null; + })) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpGet httpget = new HttpGet("/oldlocation"); final ClientProtocolException exception = Assertions.assertThrows(ClientProtocolException.class, () -> @@ -541,13 +525,14 @@ public abstract class TestRedirects { @Test public void testRedirectWithCookie() throws Exception { - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final CookieStore cookieStore = new BasicCookieStore(); final BasicClientCookie cookie = new BasicClientCookie("name", "value"); @@ -577,16 +562,18 @@ public abstract class TestRedirects { @Test public void testDefaultHeadersRedirect() throws Exception { - final CloseableHttpClient client = startClient(builder -> builder + configureClient(builder -> builder .setDefaultHeaders(Collections.singletonList(new BasicHeader(HttpHeaders.USER_AGENT, "my-test-client"))) ); - final ClassicTestServer server = startServer(null, requestHandler -> new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(requestHandler -> new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY))) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); @@ -608,33 +595,34 @@ public abstract class TestRedirects { @Test public void testCompressionHeaderRedirect() throws Exception { final Queue values = new ConcurrentLinkedQueue<>(); - final ClassicTestServer server = startServer(null, new Decorator() { - - @Override - public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { - return new RedirectingDecorator( - requestHandler, - new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)) { + configureServer(bootstrap -> bootstrap + .setExchangeHandlerDecorator(new Decorator() { @Override - public void handle(final ClassicHttpRequest request, - final ResponseTrigger responseTrigger, - final HttpContext context) throws HttpException, IOException { - final Header header = request.getHeader(HttpHeaders.ACCEPT_ENCODING); - if (header != null) { - values.add(header.getValue()); - } - super.handle(request, responseTrigger, context); + public HttpServerRequestHandler decorate(final HttpServerRequestHandler requestHandler) { + return new RedirectingDecorator( + requestHandler, + new OldPathRedirectResolver("/oldlocation", "/random", HttpStatus.SC_MOVED_TEMPORARILY)) { + + @Override + public void handle(final ClassicHttpRequest request, + final ResponseTrigger responseTrigger, + final HttpContext context) throws HttpException, IOException { + final Header header = request.getHeader(HttpHeaders.ACCEPT_ENCODING); + if (header != null) { + values.add(header.getValue()); + } + super.handle(request, responseTrigger, context); + } + + }; } - }; - } + }) + .register("/random/*", new RandomHandler())); + final HttpHost target = startServer(); - }); - server.registerHandler("/random/*", new RandomHandler()); - final HttpHost target = targetHost(); - - final CloseableHttpClient client = startClient(); + final TestClient client = client(); final HttpClientContext context = HttpClientContext.create(); final HttpGet httpget = new HttpGet("/oldlocation/100"); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestStatefulConnManagement.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestStatefulConnManagement.java index d31f50dce..d4451d5e5 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestStatefulConnManagement.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestStatefulConnManagement.java @@ -31,8 +31,10 @@ import java.io.IOException; import org.apache.hc.client5.http.UserTokenHandler; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.protocol.HttpClientContext; -import org.apache.hc.client5.testing.sync.extension.TestClientResources; +import org.apache.hc.client5.testing.sync.extension.ClientProtocolLevel; +import org.apache.hc.client5.testing.sync.extension.TestClient; import org.apache.hc.core5.http.ClassicHttpRequest; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.EndpointDetails; @@ -44,22 +46,20 @@ import org.apache.hc.core5.http.io.HttpRequestHandler; import org.apache.hc.core5.http.io.entity.EntityUtils; import org.apache.hc.core5.http.io.entity.StringEntity; import org.apache.hc.core5.http.protocol.HttpContext; -import org.apache.hc.core5.testing.classic.ClassicTestServer; import org.apache.hc.core5.util.Timeout; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; /** * Test cases for state-ful connections. */ -public class TestStatefulConnManagement { +public class TestStatefulConnManagement extends AbstractIntegrationTestBase { - public static final Timeout TIMEOUT = Timeout.ofMinutes(1); public static final Timeout LONG_TIMEOUT = Timeout.ofMinutes(3); - @RegisterExtension - private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT); + public TestStatefulConnManagement() { + super(URIScheme.HTTP, ClientProtocolLevel.STANDARD); + } private static class SimpleService implements HttpRequestHandler { @@ -80,9 +80,9 @@ public class TestStatefulConnManagement { @Test public void testStatefulConnections() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("*", new SimpleService()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap + .register("*", new SimpleService())); + final HttpHost target = startServer(); final int workerCount = 5; final int requestCount = 5; @@ -92,13 +92,13 @@ public class TestStatefulConnManagement { return id; }; - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(workerCount) - .setMaxConnPerRoute(workerCount), - builder -> builder - .setUserTokenHandler(userTokenHandler) - ); + configureClient(builder -> builder + .setUserTokenHandler(userTokenHandler)); + final TestClient client = client(); + + final PoolingHttpClientConnectionManager connectionManager = client.getConnectionManager(); + connectionManager.setMaxTotal(workerCount); + connectionManager.setDefaultMaxPerRoute(workerCount); final HttpClientContext[] contexts = new HttpClientContext[workerCount]; final HttpWorker[] workers = new HttpWorker[workerCount]; @@ -194,9 +194,8 @@ public class TestStatefulConnManagement { @Test public void testRouteSpecificPoolRecylcing() throws Exception { - final ClassicTestServer server = testResources.startServer(null, null, null); - server.registerHandler("*", new SimpleService()); - final HttpHost target = testResources.targetHost(); + configureServer(bootstrap -> bootstrap.register("*", new SimpleService())); + final HttpHost target = startServer(); // This tests what happens when a maxed connection pool needs // to kill the last idle connection to a route to build a new @@ -204,16 +203,13 @@ public class TestStatefulConnManagement { final int maxConn = 2; + configureClient(builder -> builder + .setUserTokenHandler((route, context) -> context.getAttribute("user"))); + final TestClient client = client(); - final UserTokenHandler userTokenHandler = (route, context) -> context.getAttribute("user"); - - final CloseableHttpClient client = testResources.startClient( - builder -> builder - .setMaxConnTotal(maxConn) - .setMaxConnPerRoute(maxConn), - builder -> builder - .setUserTokenHandler(userTokenHandler) - ); + final PoolingHttpClientConnectionManager connectionManager = client.getConnectionManager(); + connectionManager.setMaxTotal(maxConn); + connectionManager.setDefaultMaxPerRoute(maxConn); // Bottom of the pool : a *keep alive* connection to Route 1. final HttpContext context1 = HttpClientContext.create(); @@ -232,7 +228,7 @@ public class TestStatefulConnManagement { // Send a very simple HTTP get (it MUST be simple, no auth, no proxy, no 302, no 401, ...) // Send it to another route. Must be a keepalive. final HttpContext context2 = HttpClientContext.create(); - client.execute(new HttpHost("127.0.0.1", server.getPort()), new HttpGet("/"), context2, response -> { + client.execute(new HttpHost("127.0.0.1", target.getPort()), new HttpGet("/"), context2, response -> { EntityUtils.consume(response.getEntity()); return null; }); diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/ClientProtocolLevel.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/ClientProtocolLevel.java new file mode 100644 index 000000000..53000d5cd --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/ClientProtocolLevel.java @@ -0,0 +1,34 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +public enum ClientProtocolLevel { + + STANDARD, MINIMAL + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/MinimalTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/MinimalTestClientBuilder.java new file mode 100644 index 000000000..bc7686eb9 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/MinimalTestClientBuilder.java @@ -0,0 +1,83 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.classic.MinimalHttpClient; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.util.Timeout; + +final class MinimalTestClientBuilder implements TestClientBuilder { + + private Timeout timeout; + + private HttpClientConnectionManager connectionManager; + + public MinimalTestClientBuilder() { + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.MINIMAL; + } + + @Override + public TestClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestClientBuilder setConnectionManager(final HttpClientConnectionManager connectionManager) { + this.connectionManager = connectionManager; + return this; + } + + @Override + public TestClient build() throws Exception { + final HttpClientConnectionManager connectionManagerCopy = connectionManager != null ? connectionManager : + PoolingHttpClientConnectionManagerBuilder.create() + .setTlsSocketStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) + .setDefaultSocketConfig(SocketConfig.custom() + .setSoTimeout(timeout) + .build()) + .setDefaultConnectionConfig(ConnectionConfig.custom() + .setConnectTimeout(timeout) + .build()) + .build(); + + final MinimalHttpClient minimalClient = HttpClients.createMinimal(connectionManagerCopy); + return new TestClient(minimalClient, connectionManagerCopy); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/StandardTestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/StandardTestClientBuilder.java new file mode 100644 index 000000000..378737858 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/StandardTestClientBuilder.java @@ -0,0 +1,159 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import java.util.Collection; + +import org.apache.hc.client5.http.AuthenticationStrategy; +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +import org.apache.hc.client5.http.UserTokenHandler; +import org.apache.hc.client5.http.auth.AuthSchemeFactory; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.config.Lookup; +import org.apache.hc.core5.http.impl.io.HttpRequestExecutor; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.util.Timeout; + +final class StandardTestClientBuilder implements TestClientBuilder { + + private final HttpClientBuilder clientBuilder; + + private Timeout timeout; + + private HttpClientConnectionManager connectionManager; + + public StandardTestClientBuilder() { + this.clientBuilder = HttpClientBuilder.create(); + } + + @Override + public ClientProtocolLevel getProtocolLevel() { + return ClientProtocolLevel.STANDARD; + } + + @Override + public TestClientBuilder setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + @Override + public TestClientBuilder setConnectionManager(final HttpClientConnectionManager connectionManager) { + this.connectionManager = connectionManager; + return this; + } + + @Override + public TestClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorFirst(interceptor); + return this; + } + + @Override + public TestClientBuilder addResponseInterceptorLast(final HttpResponseInterceptor interceptor) { + this.clientBuilder.addResponseInterceptorLast(interceptor); + return this; + } + + @Override + public TestClientBuilder addRequestInterceptorFirst(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorFirst(interceptor); + return this; + } + + @Override + public TestClientBuilder addRequestInterceptorLast(final HttpRequestInterceptor interceptor) { + this.clientBuilder.addRequestInterceptorLast(interceptor); + return this; + } + + @Override + public TestClientBuilder setUserTokenHandler(final UserTokenHandler userTokenHandler) { + this.clientBuilder.setUserTokenHandler(userTokenHandler); + return this; + } + + @Override + public TestClientBuilder setDefaultHeaders(final Collection defaultHeaders) { + this.clientBuilder.setDefaultHeaders(defaultHeaders); + return this; + } + + @Override + public TestClientBuilder setRetryStrategy(final HttpRequestRetryStrategy retryStrategy) { + this.clientBuilder.setRetryStrategy(retryStrategy); + return this; + } + + @Override + public TestClientBuilder setTargetAuthenticationStrategy(final AuthenticationStrategy targetAuthStrategy) { + this.clientBuilder.setTargetAuthenticationStrategy(targetAuthStrategy); + return this; + } + + @Override + public TestClientBuilder setDefaultAuthSchemeRegistry(final Lookup authSchemeRegistry) { + this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry); + return this; + } + + @Override + public TestClientBuilder setRequestExecutor(final HttpRequestExecutor requestExec) { + this.clientBuilder.setRequestExecutor(requestExec); + return this; + } + + @Override + public TestClient build() throws Exception { + final HttpClientConnectionManager connectionManagerCopy = connectionManager != null ? connectionManager : + PoolingHttpClientConnectionManagerBuilder.create() + .setTlsSocketStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())) + .setDefaultSocketConfig(SocketConfig.custom() + .setSoTimeout(timeout) + .build()) + .setDefaultConnectionConfig(ConnectionConfig.custom() + .setConnectTimeout(timeout) + .build()) + .build(); + + final CloseableHttpClient client = clientBuilder + .setConnectionManager(connectionManagerCopy) + .build(); + return new TestClient(client, connectionManagerCopy); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClient.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClient.java new file mode 100644 index 000000000..e17e845c7 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClient.java @@ -0,0 +1,77 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import java.io.IOException; + +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.util.Args; + +public class TestClient extends CloseableHttpClient { + + private final CloseableHttpClient client; + private final HttpClientConnectionManager connectionManager; + + public TestClient(final CloseableHttpClient client, + final HttpClientConnectionManager connectionManager) { + this.client = Args.notNull(client, "Client"); + this.connectionManager = Args.notNull(connectionManager, "Connection manager"); + } + + @Override + public void close(final CloseMode closeMode) { + client.close(closeMode); + } + + @Override + public void close() throws IOException { + client.close(); + } + + @Override + protected CloseableHttpResponse doExecute(final HttpHost target, final ClassicHttpRequest request, final HttpContext context) throws IOException { + return CloseableHttpResponse.adapt(client.executeOpen(target, request, context)); + } + + @SuppressWarnings("unchecked") + public T getImplementation() { + return (T) client; + } + + @SuppressWarnings("unchecked") + public T getConnectionManager() { + return (T) connectionManager; + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientBuilder.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientBuilder.java new file mode 100644 index 000000000..27a0381eb --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientBuilder.java @@ -0,0 +1,94 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import java.util.Collection; + +import org.apache.hc.client5.http.AuthenticationStrategy; +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +import org.apache.hc.client5.http.UserTokenHandler; +import org.apache.hc.client5.http.auth.AuthSchemeFactory; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpRequestInterceptor; +import org.apache.hc.core5.http.HttpResponseInterceptor; +import org.apache.hc.core5.http.config.Lookup; +import org.apache.hc.core5.http.impl.io.HttpRequestExecutor; +import org.apache.hc.core5.util.Timeout; + +public interface TestClientBuilder { + + ClientProtocolLevel getProtocolLevel(); + + TestClientBuilder setTimeout(Timeout soTimeout); + + TestClientBuilder setConnectionManager(HttpClientConnectionManager connManager); + + default TestClientBuilder addResponseInterceptorFirst(final HttpResponseInterceptor interceptor) { + return this; + } + + default TestClientBuilder addResponseInterceptorLast(HttpResponseInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder addRequestInterceptorFirst(HttpRequestInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder addRequestInterceptorLast(HttpRequestInterceptor interceptor) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setUserTokenHandler(UserTokenHandler userTokenHandler) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setDefaultHeaders(Collection defaultHeaders) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setRetryStrategy(HttpRequestRetryStrategy retryStrategy) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setTargetAuthenticationStrategy(AuthenticationStrategy targetAuthStrategy) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setDefaultAuthSchemeRegistry(Lookup authSchemeRegistry) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + default TestClientBuilder setRequestExecutor(HttpRequestExecutor requestExec) { + throw new UnsupportedOperationException("Operation not supported by " + getProtocolLevel()); + } + + TestClient build() throws Exception; + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientResources.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientResources.java index fd8f0000a..64758f58b 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientResources.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestClientResources.java @@ -27,59 +27,46 @@ package org.apache.hc.client5.testing.sync.extension; -import java.io.IOException; import java.util.function.Consumer; -import org.apache.hc.client5.http.config.ConnectionConfig; -import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; -import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.classic.HttpClients; -import org.apache.hc.client5.http.impl.classic.MinimalHttpClient; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy; -import org.apache.hc.client5.testing.SSLTestContexts; -import org.apache.hc.core5.function.Decorator; -import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.Http1Config; -import org.apache.hc.core5.http.io.HttpServerRequestHandler; -import org.apache.hc.core5.http.io.SocketConfig; -import org.apache.hc.core5.http.protocol.HttpProcessor; import org.apache.hc.core5.io.CloseMode; -import org.apache.hc.core5.testing.classic.ClassicTestServer; +import org.apache.hc.core5.util.Asserts; import org.apache.hc.core5.util.Timeout; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class TestClientResources implements BeforeEachCallback, AfterEachCallback { +public class TestClientResources implements AfterEachCallback { private static final Logger LOG = LoggerFactory.getLogger(TestClientResources.class); private final URIScheme scheme; private final Timeout timeout; + private final ClientProtocolLevel clientProtocolLevel; + private final TestServerBootstrap serverBootstrap; + private final TestClientBuilder clientBuilder; - private ClassicTestServer server; + private TestServer server; private PoolingHttpClientConnectionManager connManager; - private CloseableHttpClient client; + private TestClient client; - public TestClientResources(final URIScheme scheme, final Timeout timeout) { - this.scheme = scheme; + public TestClientResources(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final Timeout timeout) { + this.scheme = scheme != null ? scheme : URIScheme.HTTP; this.timeout = timeout; - } - - @Override - public void beforeEach(final ExtensionContext extensionContext) throws Exception { - LOG.debug("Starting up test server"); - server = new ClassicTestServer( - scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, - SocketConfig.custom() - .setSoTimeout(timeout) - .build()); + this.clientProtocolLevel = clientProtocolLevel != null ? clientProtocolLevel : ClientProtocolLevel.STANDARD; + this.serverBootstrap = new TestServerBootstrap(this.scheme) + .setTimeout(this.timeout); + switch (this.clientProtocolLevel) { + case MINIMAL: + this.clientBuilder = new MinimalTestClientBuilder(); + break; + default: + this.clientBuilder = new StandardTestClientBuilder(); + } + this.clientBuilder.setTimeout(timeout); } @Override @@ -103,72 +90,32 @@ public class TestClientResources implements BeforeEachCallback, AfterEachCallbac return this.scheme; } - public ClassicTestServer startServer( - final Http1Config http1Config, - final HttpProcessor httpProcessor, - final Decorator handlerDecorator) throws IOException { - Assertions.assertNotNull(server); - server.start(http1Config, httpProcessor, handlerDecorator); + public ClientProtocolLevel getClientProtocolLevel() { + return clientProtocolLevel; + } + + public void configureServer(final Consumer serverCustomizer) { + Asserts.check(server == null, "Server is already running and cannot be changed"); + serverCustomizer.accept(serverBootstrap); + } + + public TestServer server() throws Exception { + if (server == null) { + server = serverBootstrap.build(); + } return server; } - public HttpHost targetHost() { - Assertions.assertNotNull(server); - return new HttpHost(scheme.id, "localhost", server.getPort()); + public void configureClient(final Consumer clientCustomizer) { + Asserts.check(client == null, "Client is already running and cannot be changed"); + clientCustomizer.accept(clientBuilder); } - public CloseableHttpClient startClient( - final Consumer connManagerCustomizer, - final Consumer clientCustomizer) throws Exception { - Assertions.assertNull(connManager); - Assertions.assertNull(client); - - final PoolingHttpClientConnectionManagerBuilder connManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create(); - connManagerBuilder.setTlsSocketStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - connManagerBuilder.setDefaultSocketConfig(SocketConfig.custom() - .setSoTimeout(timeout) - .build()); - connManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setConnectTimeout(timeout) - .build()); - connManagerCustomizer.accept(connManagerBuilder); - - connManager = connManagerBuilder.build(); - - final HttpClientBuilder clientBuilder = HttpClientBuilder.create() - .setConnectionManager(connManager); - clientCustomizer.accept(clientBuilder); - client = clientBuilder.build(); + public TestClient client() throws Exception { + if (client == null) { + client = clientBuilder.build(); + } return client; } - public MinimalHttpClient startMinimalClient() throws Exception { - Assertions.assertNull(connManager); - Assertions.assertNull(client); - - final PoolingHttpClientConnectionManagerBuilder connManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create(); - connManagerBuilder.setTlsSocketStrategy(new DefaultClientTlsStrategy(SSLTestContexts.createClientSSLContext())); - connManagerBuilder.setDefaultSocketConfig(SocketConfig.custom() - .setSoTimeout(timeout) - .build()); - connManagerBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setConnectTimeout(timeout) - .build()); - connManager = connManagerBuilder.build(); - - final MinimalHttpClient minimalClient = HttpClients.createMinimal(connManager); - client = minimalClient; - return minimalClient; - } - - public CloseableHttpClient startClient( - final Consumer clientCustomizer) throws Exception { - return startClient(b -> {}, clientCustomizer); - } - - public PoolingHttpClientConnectionManager connManager() { - Assertions.assertNotNull(connManager); - return connManager; - } - } diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServer.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServer.java new file mode 100644 index 000000000..7c0f69421 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServer.java @@ -0,0 +1,67 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import java.io.IOException; +import java.net.InetSocketAddress; + +import org.apache.hc.core5.function.Decorator; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.io.HttpServerRequestHandler; +import org.apache.hc.core5.http.protocol.HttpProcessor; +import org.apache.hc.core5.io.CloseMode; +import org.apache.hc.core5.testing.classic.ClassicTestServer; + +public class TestServer { + + private final ClassicTestServer server; + private final Http1Config http1Config; + private final HttpProcessor httpProcessor; + private final Decorator exchangeHandlerDecorator; + + TestServer( + final ClassicTestServer server, + final Http1Config http1Config, + final HttpProcessor httpProcessor, + final Decorator exchangeHandlerDecorator) { + this.server = server; + this.http1Config = http1Config; + this.httpProcessor = httpProcessor; + this.exchangeHandlerDecorator = exchangeHandlerDecorator; + } + + public void shutdown(final CloseMode closeMode) { + server.shutdown(closeMode); + } + + public InetSocketAddress start() throws IOException { + server.start(http1Config, httpProcessor, exchangeHandlerDecorator); + return new InetSocketAddress(server.getInetAddress(), server.getPort()); + } + +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServerBootstrap.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServerBootstrap.java new file mode 100644 index 000000000..51de842ab --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/extension/TestServerBootstrap.java @@ -0,0 +1,123 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.testing.sync.extension; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.client5.testing.SSLTestContexts; +import org.apache.hc.core5.function.Decorator; +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.http.config.Http1Config; +import org.apache.hc.core5.http.io.HttpRequestHandler; +import org.apache.hc.core5.http.io.HttpServerRequestHandler; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.http.protocol.HttpProcessor; +import org.apache.hc.core5.testing.classic.ClassicTestServer; +import org.apache.hc.core5.util.Args; +import org.apache.hc.core5.util.Timeout; + +public class TestServerBootstrap { + + static final class HandlerEntry { + + final String hostname; + final String uriPattern; + final T handler; + + public HandlerEntry(final String hostname, final String uriPattern, final T handler) { + this.hostname = hostname; + this.uriPattern = uriPattern; + this.handler = handler; + } + + public HandlerEntry(final String uriPattern, final T handler) { + this(null, uriPattern, handler); + } + + } + + private final URIScheme scheme; + + private final List> handlerList; + private Timeout timeout; + private HttpProcessor httpProcessor; + private Decorator exchangeHandlerDecorator; + + public TestServerBootstrap(final URIScheme scheme) { + this.scheme = scheme != null ? scheme : URIScheme.HTTP; + this.handlerList = new ArrayList<>(); + } + + public TestServerBootstrap register(final String uriPattern, final HttpRequestHandler requestHandler) { + return register(null, uriPattern, requestHandler); + } + + public TestServerBootstrap register(final String hostname, final String uriPattern, final HttpRequestHandler requestHandler) { + Args.notNull(uriPattern, "URI pattern"); + Args.notNull(requestHandler, "Exchange handler"); + handlerList.add(new HandlerEntry<>(hostname, uriPattern, requestHandler)); + return this; + } + + public TestServerBootstrap setTimeout(final Timeout timeout) { + this.timeout = timeout; + return this; + } + + public TestServerBootstrap setHttpProcessor(final HttpProcessor httpProcessor) { + this.httpProcessor = httpProcessor; + return this; + } + + public TestServerBootstrap setExchangeHandlerDecorator(final Decorator exchangeHandlerDecorator) { + this.exchangeHandlerDecorator = exchangeHandlerDecorator; + return this; + } + + public TestServer build() throws Exception { + final ClassicTestServer server = new ClassicTestServer( + scheme == URIScheme.HTTPS ? SSLTestContexts.createServerSSLContext() : null, + SocketConfig.custom() + .setSoTimeout(timeout) + .build()); + for (final HandlerEntry entry: handlerList) { + if (entry.hostname != null) { + server.registerHandlerVirtual(entry.hostname, entry.uriPattern, entry.handler); + } else { + server.registerHandler(entry.uriPattern, entry.handler); + } + } + return new TestServer( + server, + Http1Config.DEFAULT, + httpProcessor, + exchangeHandlerDecorator); + } + +} diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponse.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponse.java index a936d069f..e01b58f9b 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponse.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/CloseableHttpResponse.java @@ -32,6 +32,7 @@ import java.util.Iterator; import java.util.Locale; import org.apache.hc.client5.http.classic.ExecRuntime; +import org.apache.hc.core5.annotation.Internal; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.HttpEntity; @@ -49,7 +50,11 @@ public final class CloseableHttpResponse implements ClassicHttpResponse { private final ClassicHttpResponse response; private final ExecRuntime execRuntime; - static CloseableHttpResponse adapt(final ClassicHttpResponse response) { + /** + * @since 5.4 + */ + @Internal + public static CloseableHttpResponse adapt(final ClassicHttpResponse response) { if (response == null) { return null; }