--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/offline/DelegatingHttpClient.java Thu Jan 18 11:26:39 2018 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import java.io.IOException;
+import java.net.Authenticator;
+import java.net.CookieHandler;
+import java.net.ProxySelector;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpResponse;
+
+/**
+ * An HttpClient that delegates all its operations to the given client.
+ */
+public class DelegatingHttpClient extends HttpClient {
+
+ private final HttpClient client;
+
+ public DelegatingHttpClient(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Optional<CookieHandler> cookieHandler() {
+ return client.cookieHandler();
+ }
+
+ @Override
+ public Redirect followRedirects() {
+ return client.followRedirects();
+ }
+
+ @Override
+ public Optional<ProxySelector> proxy() {
+ return client.proxy();
+ }
+
+ @Override
+ public SSLContext sslContext() {
+ return client.sslContext();
+ }
+
+ @Override
+ public SSLParameters sslParameters() {
+ return client.sslParameters();
+ }
+
+ @Override
+ public Optional<Authenticator> authenticator() {
+ return client.authenticator();
+ }
+
+ @Override
+ public Version version() {
+ return client.version();
+ }
+
+ @Override
+ public Optional<Executor> executor() {
+ return client.executor();
+ }
+
+ @Override
+ public <T> HttpResponse<T> send(HttpRequest request,
+ HttpResponse.BodyHandler<T> responseBodyHandler)
+ throws IOException, InterruptedException {
+ return client.send(request, responseBodyHandler);
+ }
+
+ @Override
+ public <T> CompletableFuture<HttpResponse<T>>
+ sendAsync(HttpRequest request,
+ HttpResponse.BodyHandler<T> responseBodyHandler) {
+ return client.sendAsync(request, responseBodyHandler);
+ }
+
+ @Override
+ public <T> CompletableFuture<HttpResponse<T>>
+ sendAsync(HttpRequest request,
+ HttpResponse.BodyHandler<T> responseBodyHandler,
+ HttpResponse.PushPromiseHandler<T> pushPromiseHandler) {
+ return client.sendAsync(request, responseBodyHandler, pushPromiseHandler);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/offline/FixedHttpHeaders.java Thu Jan 18 11:26:39 2018 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import jdk.incubator.http.HttpHeaders;
+
+/**
+ * An HttpHeaders consisting of the given name value pairs.
+ */
+public class FixedHttpHeaders extends HttpHeaders {
+
+ private final Map<String, List<String>> map =
+ new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+ @Override
+ public Map<String, List<String>> map() {
+ return map;
+ }
+
+ /**
+ * Creates an HttpHeaders of the given name value pairs.
+ */
+ public static HttpHeaders of(String... params) {
+ Objects.requireNonNull(params);
+ if ((params.length & 0x1) != 0)
+ throw new IllegalArgumentException("odd number of params");
+ FixedHttpHeaders headers = new FixedHttpHeaders();
+ for (int i = 0; i < params.length; i += 2) {
+ String name = params[i];
+ String value = params[i + 1];
+ headers.map.computeIfAbsent(name, k -> new ArrayList<>(1))
+ .add(value);
+ }
+ return headers;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/offline/FixedHttpResponse.java Thu Jan 18 11:26:39 2018 +0000
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.net.ssl.SSLParameters;
+import java.net.URI;
+import java.util.Optional;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpHeaders;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpResponse;
+
+/**
+ * An HttpResponse consisting of the given state.
+ */
+public class FixedHttpResponse<T> extends HttpResponse<T> {
+
+ private final int statusCode;
+ private final HttpRequest request;
+ private final HttpHeaders headers;
+ private final T body;
+ private final SSLParameters sslParameters;
+ private final URI uri;
+ private final HttpClient.Version version;
+
+ public FixedHttpResponse(int statusCode,
+ HttpRequest request,
+ HttpHeaders headers,
+ T body,
+ SSLParameters sslParameters,
+ URI uri,
+ HttpClient.Version version) {
+ this.statusCode = statusCode;
+ this.request = request;
+ this.headers = headers;
+ this.body = body;
+ this.sslParameters = sslParameters;
+ this.uri = uri;
+ this.version = version;
+ }
+
+ @Override
+ public int statusCode() {
+ return statusCode;
+ }
+
+ @Override
+ public HttpRequest request() {
+ return request;
+ }
+
+ @Override
+ public Optional<HttpResponse<T>> previousResponse() {
+ return Optional.empty();
+ }
+
+ @Override
+ public HttpHeaders headers() {
+ return headers;
+ }
+
+ @Override
+ public T body() {
+ return body;
+ }
+
+ @Override
+ public SSLParameters sslParameters() {
+ return sslParameters;
+ }
+
+ @Override
+ public URI uri() {
+ return uri;
+ }
+
+ @Override
+ public HttpClient.Version version() {
+ return version;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ return sb.append(super.toString()).append(" [ ")
+ .append("status code: ").append(statusCode)
+ .append(", request: ").append(request)
+ .append(", headers: ").append(headers)
+ .append(" ]")
+ .toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/offline/FixedResponseHttpClient.java Thu Jan 18 11:26:39 2018 +0000
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Flow;
+import java.util.concurrent.SubmissionPublisher;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpHeaders;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpResponse;
+import jdk.incubator.http.HttpResponse.BodyHandler;
+import jdk.incubator.http.HttpResponse.BodySubscriber;
+import jdk.incubator.http.HttpResponse.PushPromiseHandler;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.nio.ByteBuffer.wrap;
+
+/**
+ * An HttpClient that returns a given fixed response.
+ * Suitable for testing where network connections are to be avoided.
+ */
+public class FixedResponseHttpClient extends DelegatingHttpClient {
+ private final ByteBuffer responseBodyBytes;
+ private final int responseStatusCode;
+ private final HttpHeaders responseHeaders;
+
+ private FixedResponseHttpClient(HttpClient.Builder builder,
+ int responseStatusCode,
+ HttpHeaders responseHeaders,
+ ByteBuffer responseBodyBytes) {
+ super(builder.build());
+ this.responseStatusCode = responseStatusCode;
+ this.responseHeaders = responseHeaders;
+ this.responseBodyBytes = responseBodyBytes;
+ }
+
+ /**
+ * Creates a new HttpClient that returns a fixed response,
+ * constructed from the given values, for every request sent.
+ */
+ public static HttpClient createClientFrom(HttpClient.Builder builder,
+ int responseStatusCode,
+ HttpHeaders responseHeaders,
+ String responseBody) {
+ return new FixedResponseHttpClient(builder,
+ responseStatusCode,
+ responseHeaders,
+ wrap(responseBody.getBytes(UTF_8)));
+ }
+
+ /**
+ * Creates a new HttpClient that returns a fixed response,
+ * constructed from the given values, for every request sent.
+ */
+ public static HttpClient createClientFrom(HttpClient.Builder builder,
+ int responseStatusCode,
+ HttpHeaders responseHeaders,
+ Path path) {
+ try {
+ return new FixedResponseHttpClient(builder,
+ responseStatusCode,
+ responseHeaders,
+ wrap(Files.readAllBytes(path)));
+ } catch (IOException ioe) {
+ throw new UncheckedIOException(ioe);
+ }
+ }
+
+ /**
+ * Creates a new HttpClient that returns a fixed response,
+ * constructed from the given values, for every request sent.
+ */
+ public static HttpClient createClientFrom(HttpClient.Builder builder,
+ int responseStatusCode,
+ HttpHeaders responseHeaders,
+ byte[] responseBody) {
+ return new FixedResponseHttpClient(builder,
+ responseStatusCode,
+ responseHeaders,
+ wrap(responseBody));
+ }
+
+ private static final ByteBuffer ECHO_SENTINAL = ByteBuffer.wrap(new byte[] {});
+
+ /**
+ * Creates a new HttpClient that returns a fixed response,
+ * constructed from the given values, for every request sent.
+ */
+ public static HttpClient createEchoClient(HttpClient.Builder builder,
+ int responseStatusCode,
+ HttpHeaders responseHeaders) {
+ return new FixedResponseHttpClient(builder,
+ responseStatusCode,
+ responseHeaders,
+ ECHO_SENTINAL);
+ }
+
+ @Override
+ public <T> CompletableFuture<HttpResponse<T>>
+ sendAsync(HttpRequest request, BodyHandler<T> responseBodyHandler) {
+ return sendAsync(request, responseBodyHandler, null);
+ }
+
+ @Override
+ public <T> HttpResponse<T> send(HttpRequest request,
+ BodyHandler<T> responseBodyHandler)
+ throws IOException, InterruptedException {
+ return sendAsync(request, responseBodyHandler).join(); // unwrap exceptions if needed
+ }
+
+ @Override
+ public <T> CompletableFuture<HttpResponse<T>>
+ sendAsync(HttpRequest request,
+ BodyHandler<T> responseBodyHandler,
+ PushPromiseHandler<T> pushPromiseHandler) {
+ List<ByteBuffer> responseBody = List.of(responseBodyBytes.duplicate());
+
+ // Push promises can be mocked too, if needed
+
+ Optional<HttpRequest.BodyPublisher> obp = request.bodyPublisher();
+ if (obp.isPresent()) {
+ ConsumingSubscriber subscriber = new ConsumingSubscriber();
+ obp.get().subscribe(subscriber);
+ if (responseBodyBytes == ECHO_SENTINAL) {
+ responseBody = subscriber.buffers;
+ }
+ }
+
+ BodySubscriber<T> bodySubscriber =
+ responseBodyHandler.apply(responseStatusCode, responseHeaders);
+ SubmissionPublisher<List<ByteBuffer>> publisher = new SubmissionPublisher<>();
+ publisher.subscribe(bodySubscriber);
+ publisher.submit(responseBody);
+ publisher.close();
+
+ CompletableFuture<HttpResponse<T>> cf = new CompletableFuture<>();
+ bodySubscriber.getBody().whenComplete((body, throwable) -> {
+ if (body != null)
+ cf.complete(new FixedHttpResponse<>(
+ responseStatusCode,
+ request,
+ responseHeaders,
+ body,
+ this.sslParameters(),
+ request.uri(),
+ request.version().orElse(Version.HTTP_2)));
+ else
+ cf.completeExceptionally(throwable);
+ }
+ );
+
+ return cf;
+ }
+
+ /**
+ * A Subscriber that demands and consumes all the Publishers data,
+ * after which makes it directly available.
+ */
+ private static class ConsumingSubscriber implements Flow.Subscriber<ByteBuffer> {
+ final List<ByteBuffer> buffers = Collections.synchronizedList(new ArrayList<>());
+
+ @Override
+ public void onSubscribe(Flow.Subscription subscription) {
+ subscription.request(Long.MAX_VALUE);
+ }
+
+ @Override public void onNext(ByteBuffer item) {
+ buffers.add(item.duplicate());
+ }
+
+ @Override public void onError(Throwable throwable) { assert false : "Unexpected"; }
+
+ @Override public void onComplete() { /* do nothing */ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/httpclient/offline/OfflineTesting.java Thu Jan 18 11:26:39 2018 +0000
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Demonstrates how to achieve testing without network connections
+ * @build FixedHttpHeaders DelegatingHttpClient FixedHttpResponse FixedResponseHttpClient
+ * @run testng/othervm OfflineTesting
+ */
+
+import java.io.IOException;
+import java.net.URI;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpResponse;
+import org.testng.annotations.Test;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static jdk.incubator.http.HttpRequest.BodyPublisher.fromString;
+import static jdk.incubator.http.HttpResponse.BodyHandler.asByteArray;
+import static jdk.incubator.http.HttpResponse.BodyHandler.asString;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+public class OfflineTesting {
+
+ private static HttpClient getClient() {
+ // be sure to return the appropriate client when testing
+ //return HttpClient.newHttpClient();
+ return FixedResponseHttpClient.createClientFrom(
+ HttpClient.newBuilder(),
+ 200,
+ FixedHttpHeaders.of("Server", "nginx",
+ "Content-Type", "text/html"),
+ "A response message");
+ }
+
+ @Test
+ public void testResponseAsString() {
+ HttpClient client = getClient();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://openjdk.java.net/"))
+ .build();
+
+ client.sendAsync(request, asString())
+ .thenAccept(response -> {
+ System.out.println("response: " + response);
+ assertEquals(response.statusCode(), 200);
+ assertTrue(response.headers().firstValue("Server").isPresent());
+ assertEquals(response.body(), "A response message"); } )
+ .join();
+ }
+
+ @Test
+ public void testResponseAsByteArray() {
+ HttpClient client = getClient();
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://openjdk.java.net/"))
+ .build();
+
+ client.sendAsync(request, asByteArray())
+ .thenAccept(response -> {
+ System.out.println("response: " + response);
+ assertEquals(response.statusCode(), 200);
+ assertTrue(response.headers().firstValue("Content-Type").isPresent());
+ assertEquals(response.body(), "A response message".getBytes(UTF_8)); } )
+ .join();
+ }
+
+ @Test
+ public void testFileNotFound() {
+ //HttpClient client = HttpClient.newHttpClient();
+ HttpClient client = FixedResponseHttpClient.createClientFrom(
+ HttpClient.newBuilder(),
+ 404,
+ FixedHttpHeaders.of("Connection", "keep-alive",
+ "Content-Length", "162",
+ "Content-Type", "text/html",
+ "Date", "Mon, 15 Jan 2018 15:01:16 GMT",
+ "Server", "nginx"),
+ "<html>\n" +
+ "<head><title>404 Not Found</title></head>\n" +
+ "<body bgcolor=\"white\">\n" +
+ "<center><h1>404 Not Found</h1></center>\n" +
+ "<hr><center>nginx</center>\n" +
+ "</body>\n" +
+ "</html>");
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://openjdk.java.net/notFound"))
+ .build();
+
+ client.sendAsync(request, asString())
+ .thenAccept(response -> {
+ assertEquals(response.statusCode(), 404);
+ response.headers().firstValue("Content-Type")
+ .ifPresentOrElse(type -> assertEquals(type, "text/html"),
+ () -> fail("Content-Type not present"));
+ assertTrue(response.body().contains("404 Not Found")); } )
+ .join();
+ }
+
+ @Test
+ public void testEcho() {
+ HttpClient client = FixedResponseHttpClient.createEchoClient(
+ HttpClient.newBuilder(),
+ 200,
+ FixedHttpHeaders.of("Connection", "keep-alive"));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://openjdk.java.net/echo"))
+ .POST(fromString("Hello World"))
+ .build();
+
+ client.sendAsync(request, asString())
+ .thenAccept(response -> {
+ System.out.println("response: " + response);
+ assertEquals(response.statusCode(), 200);
+ assertEquals(response.body(), "Hello World"); } )
+ .join();
+ }
+
+ @Test
+ public void testEchoBlocking() throws IOException, InterruptedException {
+ HttpClient client = FixedResponseHttpClient.createEchoClient(
+ HttpClient.newBuilder(),
+ 200,
+ FixedHttpHeaders.of("Connection", "keep-alive"));
+
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(URI.create("http://openjdk.java.net/echo"))
+ .POST(fromString("Hello chegar!!"))
+ .build();
+
+ HttpResponse<String> response = client.send(request, asString());
+ System.out.println("response: " + response);
+ assertEquals(response.statusCode(), 200);
+ assertEquals(response.body(), "Hello chegar!!");
+ }
+}