From df84c0ef363eae57ce859ea25c7414dca6ee8061 Mon Sep 17 00:00:00 2001 From: Daniel Kec Date: Thu, 29 Jun 2023 21:53:28 +0200 Subject: [PATCH] Flaky h2 bookstore test #7097 (#7137) --- tests/apps/bookstore/bookstore-se/pom.xml | 34 +-- .../helidon/tests/apps/bookstore/se/Main.java | 26 +-- .../src/main/resources/application.yaml | 3 +- .../src/main/resources/logging.properties | 2 +- .../tests/apps/bookstore/se/Http2SslTest.java | 197 +++++++++++------- .../tests/apps/bookstore/se/MainTest.java | 127 ++++++----- .../tests/apps/bookstore/se/SslTest.java | 114 ++++++---- .../tests/apps/bookstore/se/TestServer.java | 114 +++------- 8 files changed, 327 insertions(+), 290 deletions(-) diff --git a/tests/apps/bookstore/bookstore-se/pom.xml b/tests/apps/bookstore/bookstore-se/pom.xml index 872f87cf8c4..4222e744442 100644 --- a/tests/apps/bookstore/bookstore-se/pom.xml +++ b/tests/apps/bookstore/bookstore-se/pom.xml @@ -91,6 +91,12 @@ helidon-tests-apps-bookstore-common ${project.version} + + io.helidon.nima.testing.junit5 + + helidon-nima-testing-junit5-webserver + test + org.junit.jupiter junit-jupiter-api @@ -101,12 +107,6 @@ hamcrest-all test - - com.squareup.okhttp3 - okhttp - 3.14.1 - test - @@ -128,13 +128,21 @@ --enable-preview - - - org.apache.maven.plugins - maven-surefire-plugin - - --enable-preview - + + + default-testCompile + + + + --enable-preview + --add-modules + java.net.http + + + + diff --git a/tests/apps/bookstore/bookstore-se/src/main/java/io/helidon/tests/apps/bookstore/se/Main.java b/tests/apps/bookstore/bookstore-se/src/main/java/io/helidon/tests/apps/bookstore/se/Main.java index 0e251982113..79404313df7 100644 --- a/tests/apps/bookstore/bookstore-se/src/main/java/io/helidon/tests/apps/bookstore/se/Main.java +++ b/tests/apps/bookstore/bookstore-se/src/main/java/io/helidon/tests/apps/bookstore/se/Main.java @@ -73,6 +73,19 @@ static WebServer startServer() { * @return the created {@link WebServer} instance */ static WebServer startServer(boolean ssl, boolean http2, boolean compression) { + WebServerConfig.Builder serverBuilder = WebServerConfig.builder(); + setupServer(serverBuilder, ssl); + + WebServer server = serverBuilder.build(); + server.start(); + String url = (ssl ? "https" : "http") + "://localhost:" + server.port() + SERVICE_PATH; + System.out.println("WEB server is up! " + url + " [ssl=" + ssl + ", http2=" + http2 + + ", compression=" + compression + "]"); + + return server; + } + + static void setupServer(WebServerConfig.Builder serverBuilder, boolean ssl) { // load logging configuration LogConfig.configureRuntime(); @@ -80,22 +93,11 @@ static WebServer startServer(boolean ssl, boolean http2, boolean compression) { Config config = Config.create(); // Build server config based on params - var serverBuilder = WebServer.builder() + serverBuilder .addRouting(createRouting(config)) .config(config.get("server")) .update(it -> configureJsonSupport(it, config)) .update(it -> configureSsl(it, ssl)); - // .enableCompression(compression); - - configureJsonSupport(serverBuilder, config); - - WebServer server = serverBuilder.build(); - server.start(); - String url = (ssl ? "https" : "http") + "://localhost:" + server.port() + SERVICE_PATH; - System.out.println("WEB server is up! " + url + " [ssl=" + ssl + ", http2=" + http2 - + ", compression=" + compression + "]"); - - return server; } static JsonLibrary getJsonLibrary(Config config) { diff --git a/tests/apps/bookstore/bookstore-se/src/main/resources/application.yaml b/tests/apps/bookstore/bookstore-se/src/main/resources/application.yaml index 2b1cf32d5a0..065524e5869 100644 --- a/tests/apps/bookstore/bookstore-se/src/main/resources/application.yaml +++ b/tests/apps/bookstore/bookstore-se/src/main/resources/application.yaml @@ -18,7 +18,8 @@ app: json-library: jsonp server: - port: 8080 + # Random port + port: -1 host: 0.0.0.0 # ssl: diff --git a/tests/apps/bookstore/bookstore-se/src/main/resources/logging.properties b/tests/apps/bookstore/bookstore-se/src/main/resources/logging.properties index da72a9a8201..dd9a4296e2d 100644 --- a/tests/apps/bookstore/bookstore-se/src/main/resources/logging.properties +++ b/tests/apps/bookstore/bookstore-se/src/main/resources/logging.properties @@ -31,4 +31,4 @@ java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$ #io.helidon.config.level=INFO #io.helidon.security.level=INFO #io.helidon.common.level=INFO -#io.netty.level=INFO +#io.helidon.nima.level=ALL diff --git a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/Http2SslTest.java b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/Http2SslTest.java index 46742c0fe48..e1be9981732 100644 --- a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/Http2SslTest.java +++ b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/Http2SslTest.java @@ -16,26 +16,25 @@ package io.helidon.tests.apps.bookstore.se; +import io.helidon.common.configurable.ThreadPoolSupplier; +import io.helidon.nima.testing.junit5.webserver.ServerTest; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; +import io.helidon.nima.webserver.WebServer; +import io.helidon.nima.webserver.WebServerConfig; +import org.junit.jupiter.api.Test; + +import javax.net.ssl.SSLContext; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; -import io.helidon.common.configurable.ThreadPoolSupplier; - -import io.helidon.nima.webserver.WebServer; -import okhttp3.OkHttpClient; -import okhttp3.Protocol; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import static io.helidon.tests.apps.bookstore.se.TestServer.APPLICATION_JSON; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.fail; @@ -43,21 +42,25 @@ /** * Tests SSL/TLS with HTTP 2 upgrades and compression. */ -@Disabled("https://github.com/helidon-io/helidon/issues/7097") +@ServerTest public class Http2SslTest { - private static WebServer webServer; - private static OkHttpClient client; - - @BeforeAll - public static void startServer() throws Exception { - webServer = TestServer.start(true, true, true); - client = TestServer.newOkHttpClient(true, true); + private static HttpClient client; + private final URI baseSslUri; + + public Http2SslTest(WebServer server) throws Exception { + SSLContext sslContext = TestServer.setupSSLTrust(); + baseSslUri = URI.create("https://localhost:" + server.port()); + client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .sslContext(sslContext) + .connectTimeout(Duration.ofSeconds(5)) + .build(); } - @AfterAll - public static void stopServer() throws Exception { - TestServer.stop(webServer); + @SetUpServer + static void server(WebServerConfig.Builder server) { + Main.setupServer(server, true); } @Test @@ -72,34 +75,48 @@ public void testHelloWorldHttp2SslCompression() throws Exception { @Test public void testHelloWorldHttp2SslPostFirst() throws Exception { - Request.Builder builder = TestServer.newRequestBuilder(webServer, "/books", true); - Request postBook = builder.post( - RequestBody.create(APPLICATION_JSON, TestServer.getBookAsJson())).build(); - try (Response postBookRes = client.newCall(postBook).execute()) { - assertThat(postBookRes.code(), is(200)); - assertThat(postBookRes.protocol(), is(Protocol.HTTP_2)); - } - - builder = TestServer.newRequestBuilder(webServer, "/books/123456", true); - Request deleteBook = builder.delete().build(); - try (Response deleteBookRes = client.newCall(deleteBook).execute()) { - assertThat(deleteBookRes.code(), is(200)); - assertThat(deleteBookRes.protocol(), is(Protocol.HTTP_2)); - } + HttpRequest postBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", "gzip") + .POST(HttpRequest.BodyPublishers.ofString(TestServer.getBookAsJson())) + .build(); + + var postBookRes = client.send(postBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(postBookRes.statusCode(), is(200)); + assertThat(postBookRes.version(), is(HttpClient.Version.HTTP_2)); + + HttpRequest deleteBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", "gzip") + .DELETE() + .build(); + + var deleteBookRes = client.send(deleteBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(deleteBookRes.statusCode(), is(200)); + assertThat(deleteBookRes.version(), is(HttpClient.Version.HTTP_2)); + } @Test public void testHelloWorldHttp2SslConcurrent() throws Exception { ExecutorService executor = ThreadPoolSupplier.create("test-thread-pool").get(); - Request.Builder builder = TestServer.newRequestBuilder(webServer, "/books", true); - Request getBooks = builder.build(); - List> tasks = Collections.nCopies(10, () -> client.newCall(getBooks).execute()); + HttpRequest getBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", "gzip") + .GET() + .build(); + + List>> tasks = + Collections.nCopies(10, () -> client.send(getBookReq, HttpResponse.BodyHandlers.ofString())); executor.invokeAll(tasks).forEach(f -> { try { - Response r = f.get(1, TimeUnit.SECONDS); - assertThat(r.code(), is(200)); - assertThat(r.protocol(), is(Protocol.HTTP_2)); + HttpResponse r = f.get(1, TimeUnit.SECONDS); + assertThat(r.statusCode(), is(200)); + assertThat(r.version(), is(HttpClient.Version.HTTP_2)); } catch (Exception e) { fail(e); } @@ -107,39 +124,61 @@ public void testHelloWorldHttp2SslConcurrent() throws Exception { } private void testHelloWorld(boolean compression) throws Exception { - Request.Builder builder = TestServer.newRequestBuilder(webServer, "/books", true, compression); - - Request getBooks = builder.build(); - try (Response getBooksRes = client.newCall(getBooks).execute()) { - assertThat(getBooksRes.code(), is(200)); - assertThat(getBooksRes.protocol(), is(Protocol.HTTP_2)); - } - - Request postBook = builder.post( - RequestBody.create(APPLICATION_JSON, TestServer.getBookAsJson())).build(); - try (Response postBookRes = client.newCall(postBook).execute()) { - assertThat(postBookRes.code(), is(200)); - assertThat(postBookRes.protocol(), is(Protocol.HTTP_2)); - } - - builder = TestServer.newRequestBuilder(webServer, "/books/123456", true, compression); - Request getBook = builder.build(); - try (Response getBookRes = client.newCall(getBook).execute()) { - assertThat(getBookRes.code(), is(200)); - assertThat(getBookRes.protocol(), is(Protocol.HTTP_2)); - } - - Request deleteBook = builder.delete().build(); - try (Response deleteBookRes = client.newCall(deleteBook).execute()) { - assertThat(deleteBookRes.code(), is(200)); - assertThat(deleteBookRes.protocol(), is(Protocol.HTTP_2)); - - } - - Request getNoBook = builder.build(); - try (Response getNoBookRes = client.newCall(getNoBook).execute()) { - assertThat(getNoBookRes.code(), is(404)); - assertThat(getNoBookRes.protocol(), is(Protocol.HTTP_2)); - } + HttpRequest getBooksReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", compression ? "gzip" : "none") + .GET() + .build(); + + var getBooksRes = client.send(getBooksReq, HttpResponse.BodyHandlers.ofString()); + assertThat(getBooksRes.statusCode(), is(200)); + assertThat(getBooksRes.version(), is(HttpClient.Version.HTTP_2)); + + HttpRequest postBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", compression ? "gzip" : "none") + .POST(HttpRequest.BodyPublishers.ofString(TestServer.getBookAsJson())) + .build(); + + var postBookRes = client.send(postBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(postBookRes.statusCode(), is(200)); + assertThat(postBookRes.version(), is(HttpClient.Version.HTTP_2)); + + HttpRequest getBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", compression ? "gzip" : "none") + .GET() + .build(); + + var getBookRes = client.send(getBookReq, HttpResponse.BodyHandlers.ofString()); + + assertThat(getBookRes.statusCode(), is(200)); + assertThat(getBookRes.version(), is(HttpClient.Version.HTTP_2)); + + HttpRequest deleteBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", compression ? "gzip" : "none") + .DELETE() + .build(); + + var deleteBookRes = client.send(deleteBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(deleteBookRes.statusCode(), is(200)); + assertThat(deleteBookRes.version(), is(HttpClient.Version.HTTP_2)); + + HttpRequest getNoBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .version(HttpClient.Version.HTTP_2) + .setHeader("Accept-Encoding", compression ? "gzip" : "none") + .GET() + .build(); + + var getNoBookRes = client.send(getNoBookReq, HttpResponse.BodyHandlers.ofString()); + + assertThat(getNoBookRes.statusCode(), is(404)); + assertThat(getNoBookRes.version(), is(HttpClient.Version.HTTP_2)); } } diff --git a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/MainTest.java b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/MainTest.java index d6c2288c099..8a8436bcd32 100644 --- a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/MainTest.java +++ b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/MainTest.java @@ -16,77 +16,98 @@ package io.helidon.tests.apps.bookstore.se; - +import io.helidon.nima.testing.junit5.webserver.ServerTest; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; import io.helidon.nima.webserver.WebServer; +import io.helidon.nima.webserver.WebServerConfig; import jakarta.json.Json; import jakarta.json.JsonObject; import jakarta.json.JsonReader; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import static io.helidon.tests.apps.bookstore.se.TestServer.APPLICATION_JSON; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; +@ServerTest public class MainTest { - private static WebServer webServer; - private static OkHttpClient client; + private static HttpClient client; + private final URI baseUri; - @BeforeAll - public static void startServer() throws Exception { - webServer = TestServer.start(false, false, false); - client = TestServer.newOkHttpClient(false, false); + public MainTest(WebServer server) throws Exception { + baseUri = URI.create("http://localhost:" + server.port()); + client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_1_1) + .connectTimeout(Duration.ofSeconds(5)) + .build(); } - @AfterAll - public static void stopServer() throws Exception { - TestServer.stop(webServer); + @SetUpServer + static void server(WebServerConfig.Builder server) { + Main.setupServer(server, false); } @Test public void testHelloWorld() throws Exception { - Request.Builder builder = TestServer.newRequestBuilder(webServer, "/books", false); - - Request getBooks = builder.build(); - try (Response getBooksRes = client.newCall(getBooks).execute()) { - assertThat(getBooksRes.code(), is(200)); - assertThat(getBooksRes.header("content-length"), notNullValue()); - String body = getBooksRes.body().string(); - assertThat(body, is("[]")); - } - - Request postBook = builder.post( - RequestBody.create(APPLICATION_JSON, TestServer.getBookAsJson())).build(); - try (Response postBookRes = client.newCall(postBook).execute()) { - assertThat(postBookRes.code(), is(200)); - } - - builder = TestServer.newRequestBuilder(webServer, "/books/123456", false); - Request getBook = builder.build(); - try (Response getBookRes = client.newCall(getBook).execute()) { - assertThat(getBookRes.code(), is(200)); - assertThat(getBookRes.header("content-length"), notNullValue()); - JsonReader jsonReader = Json.createReader(getBookRes.body().byteStream()); - JsonObject jsonObject = jsonReader.readObject(); - assertThat("Checking if correct ISBN", jsonObject.getString("isbn"), - is("123456")); - } - - Request deleteBook = builder.delete().build(); - try (Response deleteBookRes = client.newCall(deleteBook).execute()) { - assertThat(deleteBookRes.code(), is(200)); - } - - Request getNoBook = builder.build(); - try (Response getNoBookRes = client.newCall(getNoBook).execute()) { - assertThat(getNoBookRes.code(), is(404)); - } + HttpRequest getBooksReq = HttpRequest.newBuilder() + .uri(baseUri.resolve("/books")) + .GET() + .build(); + + var getBooksRes = client.send(getBooksReq, HttpResponse.BodyHandlers.ofString()); + assertThat(getBooksRes.statusCode(), is(200)); + assertThat(getBooksRes.version(), is(HttpClient.Version.HTTP_1_1)); + assertThat(getBooksRes.headers().firstValue("content-length").orElse(null), notNullValue()); + assertThat(getBooksRes.body(), is("[]")); + + HttpRequest postBookReq = HttpRequest.newBuilder() + .uri(baseUri.resolve("/books")) + .POST(HttpRequest.BodyPublishers.ofString(TestServer.getBookAsJson())) + .build(); + + var postBookRes = client.send(postBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(postBookRes.statusCode(), is(200)); + assertThat(postBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest getBookReq = HttpRequest.newBuilder() + .uri(baseUri.resolve("/books/123456")) + .GET() + .build(); + + var getBookRes = client.send(getBookReq, HttpResponse.BodyHandlers.ofInputStream()); + + assertThat(getBookRes.statusCode(), is(200)); + assertThat(getBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + assertThat(getBooksRes.headers().firstValue("content-length").orElse(null), notNullValue()); + JsonReader jsonReader = Json.createReader(getBookRes.body()); + JsonObject jsonObject = jsonReader.readObject(); + assertThat("Checking if correct ISBN", jsonObject.getString("isbn"), is("123456")); + + + HttpRequest deleteBookReq = HttpRequest.newBuilder() + .uri(baseUri.resolve("/books/123456")) + .DELETE() + .build(); + + var deleteBookRes = client.send(deleteBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(deleteBookRes.statusCode(), is(200)); + assertThat(deleteBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest getNoBookReq = HttpRequest.newBuilder() + .uri(baseUri.resolve("/books/123456")) + .GET() + .build(); + + var getNoBookRes = client.send(getNoBookReq, HttpResponse.BodyHandlers.ofString()); + + assertThat(getNoBookRes.statusCode(), is(404)); + assertThat(getNoBookRes.version(), is(HttpClient.Version.HTTP_1_1)); } } diff --git a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/SslTest.java b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/SslTest.java index bb04aa02d21..b5fccc81753 100644 --- a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/SslTest.java +++ b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/SslTest.java @@ -16,68 +16,94 @@ package io.helidon.tests.apps.bookstore.se; +import io.helidon.nima.testing.junit5.webserver.ServerTest; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; import io.helidon.nima.webserver.WebServer; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; +import io.helidon.nima.webserver.WebServerConfig; import org.junit.jupiter.api.Test; -import static io.helidon.tests.apps.bookstore.se.TestServer.APPLICATION_JSON; +import javax.net.ssl.SSLContext; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; /** * Tests SSL/TLS with HTTP 1.1. */ +@ServerTest public class SslTest { - private static WebServer webServer; - private static OkHttpClient client; + private static HttpClient client; + private final URI baseSslUri; - @BeforeAll - public static void startServer() throws Exception { - webServer = TestServer.start(true, false, false); - client = TestServer.newOkHttpClient(true, false); + public SslTest(WebServer server) throws Exception { + SSLContext sslContext = TestServer.setupSSLTrust(); + baseSslUri = URI.create("https://localhost:" + server.port()); + client = HttpClient.newBuilder() + .sslContext(sslContext) + .version(HttpClient.Version.HTTP_1_1) + .connectTimeout(Duration.ofSeconds(5)) + .build(); } - @AfterAll - public static void stopServer() throws Exception { - TestServer.stop(webServer); + @SetUpServer + static void server(WebServerConfig.Builder server) { + Main.setupServer(server, true); } @Test public void testHelloWorldSsl() throws Exception { - Request.Builder builder = TestServer.newRequestBuilder(webServer, "/books", true); - - Request getBooks = builder.build(); - try (Response getBooksRes = client.newCall(getBooks).execute()) { - assertThat(getBooksRes.code(), is(200)); - } - - Request postBook = builder.post( - RequestBody.create(APPLICATION_JSON, TestServer.getBookAsJson())).build(); - try (Response postBookRes = client.newCall(postBook).execute()) { - assertThat(postBookRes.code(), is(200)); - } - - builder = TestServer.newRequestBuilder(webServer, "/books/123456", true); - Request getBook = builder.build(); - try (Response getBookRes = client.newCall(getBook).execute()) { - assertThat(getBookRes.code(), is(200)); - } - - Request deleteBook = builder.delete().build(); - try (Response deleteBookRes = client.newCall(deleteBook).execute()) { - assertThat(deleteBookRes.code(), is(200)); - } - - Request getNoBook = builder.build(); - try (Response getNoBookRes = client.newCall(getNoBook).execute()) { - assertThat(getNoBookRes.code(), is(404)); - } + HttpRequest getBooksReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .GET() + .build(); + + var getBooksRes = client.send(getBooksReq, HttpResponse.BodyHandlers.ofString()); + assertThat(getBooksRes.statusCode(), is(200)); + assertThat(getBooksRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest postBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books")) + .POST(HttpRequest.BodyPublishers.ofString(TestServer.getBookAsJson())) + .build(); + + var postBookRes = client.send(postBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(postBookRes.statusCode(), is(200)); + assertThat(postBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest getBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .GET() + .build(); + + var getBookRes = client.send(getBookReq, HttpResponse.BodyHandlers.ofString()); + + assertThat(getBookRes.statusCode(), is(200)); + assertThat(getBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest deleteBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .DELETE() + .build(); + + var deleteBookRes = client.send(deleteBookReq, HttpResponse.BodyHandlers.ofString()); + assertThat(deleteBookRes.statusCode(), is(200)); + assertThat(deleteBookRes.version(), is(HttpClient.Version.HTTP_1_1)); + + HttpRequest getNoBookReq = HttpRequest.newBuilder() + .uri(baseSslUri.resolve("/books/123456")) + .GET() + .build(); + + var getNoBookRes = client.send(getNoBookReq, HttpResponse.BodyHandlers.ofString()); + + assertThat(getNoBookRes.statusCode(), is(404)); + assertThat(getNoBookRes.version(), is(HttpClient.Version.HTTP_1_1)); } } diff --git a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/TestServer.java b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/TestServer.java index 7e10fb06d66..1f33945d13b 100644 --- a/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/TestServer.java +++ b/tests/apps/bookstore/bookstore-se/src/test/java/io/helidon/tests/apps/bookstore/se/TestServer.java @@ -16,69 +16,55 @@ package io.helidon.tests.apps.bookstore.se; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; +import io.helidon.nima.testing.junit5.webserver.SetUpServer; +import io.helidon.nima.webserver.WebServerConfig; + +import javax.net.ssl.*; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.net.URL; +import java.net.Socket; import java.security.SecureRandom; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.List; import java.util.stream.Collectors; -import io.helidon.nima.webserver.WebServer; -import okhttp3.Interceptor; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Protocol; -import okhttp3.Request; -import okhttp3.Response; -import org.junit.jupiter.api.Assertions; - /** * Utility class to start the Helidon server with options. */ class TestServer { - static final MediaType APPLICATION_JSON = MediaType.parse("application/json"); - - private static X509TrustManager TRUST_MANAGER = new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; + private static final X509TrustManager NOOP_TRUST_MANAGER = new X509ExtendedTrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) + throws CertificateException { } - public void checkClientTrusted(X509Certificate[] certs, String authType) { + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) + throws CertificateException { } - public void checkServerTrusted(X509Certificate[] certs, String authType) { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) + throws CertificateException { } - }; - - static WebServer start(boolean ssl, boolean http2, boolean compression) throws Exception { - WebServer webServer = Main.startServer(ssl, http2, compression); - long timeout = 2000; // 2 seconds should be enough to start the server - long now = System.currentTimeMillis(); + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws + CertificateException { + } - while (!webServer.isRunning()) { - Thread.sleep(100); - if ((System.currentTimeMillis() - now) > timeout) { - Assertions.fail("Failed to start webserver"); - } + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; } - return webServer; - } + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } - static void stop(WebServer webServer) throws Exception { - if (webServer != null) { - webServer.stop(); + public void checkServerTrusted(X509Certificate[] certs, String authType) { } - } + }; static String getBookAsJson() throws Exception { try (InputStream is = TestServer.class.getClassLoader().getResourceAsStream("book.json")) { @@ -92,53 +78,7 @@ static String getBookAsJson() throws Exception { static SSLContext setupSSLTrust() throws Exception { SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[] { TRUST_MANAGER }, new SecureRandom()); + sslContext.init(null, new TrustManager[] {NOOP_TRUST_MANAGER}, new SecureRandom()); return sslContext; } - - static Request.Builder newRequestBuilder(WebServer webServer, String path, boolean ssl) throws Exception { - return newRequestBuilder(webServer, path, ssl, false); - } - - static Request.Builder newRequestBuilder(WebServer webServer, String path, boolean ssl, boolean compression) - throws Exception { - URL url = new URL((ssl ? "https" : "http") + "://localhost:" + webServer.port() + path); - Request.Builder builder = new Request.Builder().url(url); - builder.addHeader("Accept-Encoding", compression ? "gzip" : "none"); - return builder; - } - - static class LoggingInterceptor implements Interceptor { - @Override - public Response intercept(Interceptor.Chain chain) throws IOException { - Request request = chain.request(); - - long t1 = System.nanoTime(); - System.out.println(String.format("Sending request %s %s on %s%n%s", - request.method(), request.url(), chain.connection(), request.headers())); - - Response response = chain.proceed(request); - - long t2 = System.nanoTime(); - System.out.println(String.format("Received response %d for %s in %.1fms%nProtocol is %s%n%s", - response.code(), response.request().url(), (t2 - t1) / 1e6d, response.protocol(), - response.headers())); - - return response; - } - } - - static OkHttpClient newOkHttpClient(boolean ssl, boolean http2) throws Exception { - OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() - .addNetworkInterceptor(new LoggingInterceptor()) - .retryOnConnectionFailure(false) - .protocols(http2 ? Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1) - : List.of(Protocol.HTTP_1_1)); - if (ssl) { - SSLContext sslContext = setupSSLTrust(); - clientBuilder.sslSocketFactory(sslContext.getSocketFactory(), TRUST_MANAGER); - clientBuilder.hostnameVerifier((host, session) -> host.equals("localhost")); - } - return clientBuilder.build(); - } }