diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractH2AsyncFundamentalsTest.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractH2AsyncFundamentalsTest.java index 727621bde5..764c82bb47 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractH2AsyncFundamentalsTest.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractH2AsyncFundamentalsTest.java @@ -69,7 +69,13 @@ abstract class AbstractH2AsyncFundamentalsTest extends AbstractHttpAsyncFundamentalsTest { public AbstractH2AsyncFundamentalsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, final ServerProtocolLevel serverProtocolLevel) { - super(scheme, clientProtocolLevel, serverProtocolLevel); + this(scheme, clientProtocolLevel, serverProtocolLevel, false); + } + + public AbstractH2AsyncFundamentalsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, + final ServerProtocolLevel serverProtocolLevel, + final boolean useUnixDomainSocket) { + super(scheme, clientProtocolLevel, serverProtocolLevel, useUnixDomainSocket); } @Test @@ -203,4 +209,4 @@ public void cancelled() { } } -} \ No newline at end of file +} 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 aa18ed4162..fdc2fbc654 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 @@ -64,6 +64,12 @@ protected AbstractHttpAsyncFundamentalsTest(final URIScheme scheme, final Client super(scheme, clientProtocolLevel, serverProtocolLevel); } + protected AbstractHttpAsyncFundamentalsTest(final URIScheme scheme, final ClientProtocolLevel clientProtocolLevel, + final ServerProtocolLevel serverProtocolLevel, + final boolean useUnixDomainSocket) { + super(scheme, clientProtocolLevel, serverProtocolLevel, useUnixDomainSocket); + } + @Test void testSequentialGetRequests() throws Exception { configureServer(bootstrap -> bootstrap.register("/random/*", AsyncRandomHandler::new)); 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 2318f5de6d..b6fdf02a46 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 @@ -55,7 +55,11 @@ abstract class TestHttp1Async extends AbstractHttpAsyncFundamentalsTest { public TestHttp1Async(final URIScheme scheme) { - super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); + this(scheme, false); + } + + public TestHttp1Async(final URIScheme scheme, final boolean useUnixDomainSocket) { + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD, useUnixDomainSocket); } @ParameterizedTest(name = "{displayName}; concurrent connections: {0}") @@ -201,4 +205,4 @@ void testRequestCancellation() throws Exception { } } -} \ No newline at end of file +} 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 7524a23418..4b00ee0202 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 @@ -50,7 +50,11 @@ abstract class TestHttp1RequestReExecution extends AbstractIntegrationTestBase { public TestHttp1RequestReExecution(final URIScheme scheme) { - super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD); + this(scheme, false); + } + + public TestHttp1RequestReExecution(final URIScheme scheme, final boolean useUnixDomainSocket) { + super(scheme, ClientProtocolLevel.STANDARD, ServerProtocolLevel.STANDARD, useUnixDomainSocket); } @BeforeEach diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/UdsAsyncIntegrationTests.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/UdsAsyncIntegrationTests.java new file mode 100644 index 0000000000..bb2f0be083 --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/UdsAsyncIntegrationTests.java @@ -0,0 +1,68 @@ +/* + * ==================================================================== + * 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; + +import org.apache.hc.core5.http.URIScheme; +import org.apache.hc.core5.util.VersionInfo; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; + +import static org.apache.hc.core5.util.ReflectionUtils.determineJRELevel; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +class UdsAsyncIntegrationTests { + + @Nested + @DisplayName("Fundamentals (HTTP/1.1)") + class Http1 extends TestHttp1Async { + public Http1() { + super(URIScheme.HTTP, true); + checkForUdsSupport(); + } + } + + @Nested + @DisplayName("Request re-execution (HTTP/1.1)") + class Http1RequestReExecution extends TestHttp1RequestReExecution { + public Http1RequestReExecution() { + super(URIScheme.HTTP, true); + checkForUdsSupport(); + } + } + + static void checkForUdsSupport() { + assumeTrue(determineJRELevel() >= 16, "Async UDS requires Java 16+"); + final String[] components = VersionInfo + .loadVersionInfo("org.apache.hc.core5", UdsAsyncIntegrationTests.class.getClassLoader()) + .getRelease() + .split("[-.]"); + final int majorVersion = Integer.parseInt(components[0]); + final int minorVersion = Integer.parseInt(components[1]); + assumeFalse(majorVersion <= 5 && minorVersion <= 3, "Async UDS requires HttpCore 5.4+"); + } +} diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/async/TestAsyncResources.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/async/TestAsyncResources.java index 6cb512c347..d490e9eb76 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/async/TestAsyncResources.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/async/TestAsyncResources.java @@ -87,6 +87,11 @@ public void afterEach(final ExtensionContext extensionContext) { client.close(CloseMode.GRACEFUL); } if (udsProxy != null) { + // The test harness enables UDS through a default RequestConfig set on the client. If a test case + // overrides the RequestConfig on a given request, it may connect directly to the test server by mistake. + if (udsProxy.getRequestsReceived() == 0) { + throw new AssertionError("The UDS proxy did not receive any requests"); + } udsProxy.close(); } if (server != null) { diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/TestClientResources.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/TestClientResources.java index b18a11f4e1..8a78740d82 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/TestClientResources.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/TestClientResources.java @@ -76,6 +76,11 @@ public void afterEach(final ExtensionContext extensionContext) { client.close(CloseMode.GRACEFUL); } if (udsProxy != null) { + // The test harness enables UDS through a default RequestConfig set on the client. If a test case + // overrides the RequestConfig on a given request, it may connect directly to the test server by mistake. + if (udsProxy.getRequestsReceived() == 0) { + throw new AssertionError("The UDS proxy did not receive any requests"); + } udsProxy.close(); } if (server != null) { diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/UnixDomainProxyServer.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/UnixDomainProxyServer.java index 048ad41063..30fb9324c0 100644 --- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/UnixDomainProxyServer.java +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/extension/sync/UnixDomainProxyServer.java @@ -42,6 +42,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import static java.util.concurrent.CompletableFuture.supplyAsync; @@ -50,6 +51,7 @@ public final class UnixDomainProxyServer { private final ExecutorService executorService; private final Path socketPath; private final CountDownLatch serverReady = new CountDownLatch(1); + private final AtomicInteger requestsReceived = new AtomicInteger(0); private volatile AFUNIXServerSocket serverSocket; public UnixDomainProxyServer(final int port) { @@ -71,6 +73,10 @@ public Path getSocketPath() { return socketPath; } + public int getRequestsReceived() { + return requestsReceived.get(); + } + public void close() { try { serverSocket.close(); @@ -106,6 +112,7 @@ private void runUdsProxy() { private void serveRequests(final AFUNIXServerSocket server) throws IOException { while (true) { final AFUNIXSocket udsClient = server.accept(); + requestsReceived.incrementAndGet(); final Socket tcpSocket = new Socket("localhost", port); final CompletableFuture f1 = supplyAsync(() -> pipe(udsClient, tcpSocket), executorService); final CompletableFuture f2 = supplyAsync(() -> pipe(tcpSocket, udsClient), executorService); 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 8e88fd79b5..17173a4253 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 @@ -74,7 +74,11 @@ abstract class TestClientRequestExecution extends AbstractIntegrationTestBase { public TestClientRequestExecution(final URIScheme scheme) { - super(scheme, ClientProtocolLevel.STANDARD); + this(scheme, false); + } + + public TestClientRequestExecution(final URIScheme scheme, final boolean useUnixDomainSocket) { + super(scheme, ClientProtocolLevel.STANDARD, useUnixDomainSocket); } private static class SimpleService implements HttpRequestHandler { 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 44f46d10b0..6cc1791d32 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 @@ -66,7 +66,11 @@ abstract class TestContentCodings extends AbstractIntegrationTestBase { protected TestContentCodings(final URIScheme scheme) { - super(scheme, ClientProtocolLevel.STANDARD); + this(scheme, false); + } + + protected TestContentCodings(final URIScheme scheme, final boolean useUnixDomainSocket) { + super(scheme, ClientProtocolLevel.STANDARD, useUnixDomainSocket); } /** diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/UdsIntegrationTests.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/UdsIntegrationTests.java new file mode 100644 index 0000000000..75c7259bde --- /dev/null +++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/UdsIntegrationTests.java @@ -0,0 +1,60 @@ +/* + * ==================================================================== + * 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 org.apache.hc.core5.http.URIScheme; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; + +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +class UdsIntegrationTests { + @Nested + @DisplayName("Request execution (HTTP/1.1)") + class RequestExecution extends TestClientRequestExecution { + public RequestExecution() { + super(URIScheme.HTTP, true); + } + } + + @Nested + @DisplayName("Request execution (HTTP/1.1, TLS)") + class RequestExecutionTls extends TestClientRequestExecution { + public RequestExecutionTls() { + super(URIScheme.HTTPS, true); + assumeTrue(false, "HTTPS is not currently supported over Unix domain sockets"); + } + } + + @Nested + @DisplayName("Content coding (HTTP/1.1)") + class ContentCoding extends TestContentCodings { + public ContentCoding() { + super(URIScheme.HTTP, true); + } + } +}