Skip to content

Commit

Permalink
Complete Webserver HTTP routing shortcut methods (#6404)
Browse files Browse the repository at this point in the history
* Complete Webserver HTTP routing shortcut methods

* Convert Tests to ParameterizedTest
  • Loading branch information
klustria authored Mar 15, 2023
1 parent 3e4f75a commit 6623d33
Show file tree
Hide file tree
Showing 8 changed files with 932 additions and 119 deletions.
5 changes: 5 additions & 0 deletions nima/tests/integration/webserver/webserver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,52 +16,73 @@

package io.helidon.nima.tests.integration.server;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import io.helidon.common.http.Http;
import io.helidon.nima.testing.junit5.webserver.ServerTest;
import io.helidon.nima.testing.junit5.webserver.SetUpRoute;
import io.helidon.nima.testing.junit5.webserver.SetUpServer;
import io.helidon.nima.webclient.http1.Http1Client;
import io.helidon.nima.webclient.http1.Http1ClientResponse;
import io.helidon.nima.webclient.http1.Http1ClientRequest;
import io.helidon.nima.webserver.WebServer;
import io.helidon.nima.webserver.http.HttpRouting;
import io.helidon.nima.webserver.http.ServerRequest;
import io.helidon.nima.webserver.http.ServerResponse;

import static io.helidon.common.testing.http.junit5.HttpHeaderMatcher.hasHeader;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

@ServerTest
class RoutingTest {
private final Http1Client client;
class RoutingTest extends RoutingTestBase {

RoutingTest(Http1Client client) {
this.client = client;
}

@SetUpRoute
static void routing(HttpRouting.Builder router) {
router.get("/my path", (req, res) -> res.send("done"))
.get("/českáCesta", (req, res) -> res.send("done"));
}

@Test
void testRouteWithSpace() {
try (Http1ClientResponse response = client.get("/my path").request()) {

assertThat(response.status(), is(Http.Status.OK_200));

String message = response.as(String.class);
assertThat(message, is("done"));
}
}

@Test
void testRouteWithUtf8() {
try (Http1ClientResponse response = client.get("/českáCesta").request()) {

assertThat(response.status(), is(Http.Status.OK_200));

String message = response.as(String.class);
assertThat(message, is("done"));
}

@SetUpServer
static void setUp(WebServer.Builder builder) {
builder.addRouting(HttpRouting.builder()
.get("/my path", (req, res) -> res.send("done"))
.get("/českáCesta", (req, res) -> res.send("done"))
// shortcut methods with path matchers
.get("/wildcard_*", (req, res) -> res.send("wildcard_test1"))
.post("/wildcard/*", (req, res) -> res.send("wildcard_test2"))
// shortcut methods with path
.get("/get", (req, res) -> res.send("get"))
.post("/post", (req, res) -> res.send("post"))
.put("/put", (req, res) -> res.send("put"))
.delete("/delete", (req, res) -> res.send("delete"))
.head("/head", (req, res) -> res.send("head"))
.options("/options", (req, res) -> res.send("options"))
.trace("/trace", (req, res) -> res.send("trace"))
.patch("/patch", (req, res) -> res.send("patch"))
.any("/any", (req, res) -> res.send("any"))
// shortcut methods using multiple handlers
.get("/get_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("get_multi"))
.post("/post_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("post_multi"))
.put("/put_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("put_multi"))
.delete("/delete_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("delete_multi"))
.head("/head_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("head_multi"))
.options("/options_multi",
RoutingTestBase::multiHandler,
(req, res) -> res.send("options_multi"))
.trace("/trace_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("trace_multi"))
.patch("/patch_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("patch_multi"))
// shortcut methods with no path pattern
.get((req, res) -> res.send("get_catchall"))
.post((req, res) -> res.send("post_catchall"))
.put((req, res) -> res.send("put_catchall"))
.delete((req, res) -> res.send("delete_catchall"))
.head((req, res) -> res.send("head_catchall"))
.options((req, res) -> res.send("options_catchall"))
.trace((req, res) -> res.send("trace_catchall"))
.patch((req, res) -> res.send("patch_catchall")));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.nima.tests.integration.server;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;

import io.helidon.common.http.Http;
import io.helidon.nima.testing.junit5.webserver.ServerTest;
import io.helidon.nima.testing.junit5.webserver.SetUpRoute;
import io.helidon.nima.webclient.http1.Http1Client;
import io.helidon.nima.webclient.http1.Http1ClientResponse;
import io.helidon.nima.webclient.http1.Http1ClientRequest;
import io.helidon.nima.webserver.http.HttpRouting;
import io.helidon.nima.webserver.http.ServerRequest;
import io.helidon.nima.webserver.http.ServerResponse;

import static io.helidon.common.testing.http.junit5.HttpHeaderMatcher.hasHeader;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;

// Use by both RoutingTest and RulesTest to share the same test methods
class RoutingTestBase {
private static final Http.HeaderValue MULTI_HANDLER = Http.Header.createCached(
Http.Header.create("X-Multi-Handler"), "true");
static Http1Client client;
// Functions that will be used to execute http webclient shortcut methods
private static Function<String, Http1ClientRequest> get = x -> client.get(x);
private static Function<String, Http1ClientRequest> post = x -> client.post(x);
private static Function<String, Http1ClientRequest> put = x -> client.put(x);
private static Function<String, Http1ClientRequest> delete = x -> client.delete(x);
private static Function<String, Http1ClientRequest> head = x -> client.head(x);
private static Function<String, Http1ClientRequest> options = x -> client.options(x);
private static Function<String, Http1ClientRequest> trace = x -> client.trace(x);
private static Function<String, Http1ClientRequest> patch = x -> client.patch(x);

// Add header to indicate that this is a multi handler routing
static void multiHandler(ServerRequest req, ServerResponse res) {
res.headers().set(MULTI_HANDLER);
res.next();
}

@Test
void testRouteWithSpace() {
try (Http1ClientResponse response = client.get("/my path").request()) {

assertThat(response.status(), is(Http.Status.OK_200));

String message = response.as(String.class);
assertThat(message, is("done"));
}
}

@Test
void testRouteWithUtf8() {
try (Http1ClientResponse response = client.get("/českáCesta").request()) {

assertThat(response.status(), is(Http.Status.OK_200));

String message = response.as(String.class);
assertThat(message, is("done"));
}
}

@ParameterizedTest
@MethodSource("basic")
void testHttpShortcutMethods(Function<String, Http1ClientRequest> request, String path, String responseMessage) {
try (Http1ClientResponse response = request.apply(path).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
assertThat(response.as(String.class), is(responseMessage));
}
}

@ParameterizedTest
@MethodSource("withoutPathPattern")
void testHttpShortcutMethodsWithoutPathPattern(Function<String, Http1ClientRequest> request,
String path,
String responseMessage) {
try (Http1ClientResponse response = request.apply(path).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
assertThat(response.as(String.class), is(responseMessage));
}
}

@ParameterizedTest
@MethodSource("withPathMatcher")
void testHttpShortcutMethodsWithPathMatcher(Function<String, Http1ClientRequest> request,
String path,
String responseMessage) {
try (Http1ClientResponse response = request.apply(path).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
assertThat(response.as(String.class), is(responseMessage));
}
}

@ParameterizedTest
@MethodSource("withMultiHandlers")
void testHttpShortcutMethodsWithMultiHandlers(Function<String, Http1ClientRequest> request,
String path,
String responseMessage) {
try (Http1ClientResponse response = request.apply(path).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
assertThat(response.headers(), hasHeader(MULTI_HANDLER));
assertThat(response.as(String.class), is(responseMessage));
}
}

private static Stream<Arguments> basic() {
return Stream.of(
arguments(get, "/get", "get"),
arguments(post, "/post", "post"),
arguments(put, "/put", "put"),
arguments(delete, "/delete", "delete"),
arguments(head, "/head", "head"),
arguments(options, "/options", "options"),
arguments(trace, "/trace", "trace"),
arguments(patch, "/patch", "patch"),
arguments(delete, "/any", "any"),
arguments(post, "/any", "any"),
arguments(get, "/any", "any")
);
}

private static Stream<Arguments> withoutPathPattern() {
return Stream.of(
arguments(get, "/get_catchall", "get_catchall"),
arguments(post, "/post_catchall", "post_catchall"),
arguments(put, "/put_catchall", "put_catchall"),
arguments(delete, "/delete_catchall", "delete_catchall"),
arguments(head, "/head_catchall", "head_catchall"),
arguments(options, "/options_catchall", "options_catchall"),
arguments(trace, "/trace_catchall", "trace_catchall"),
arguments(patch, "/patch_catchall", "patch_catchall")
);
}

private static Stream<Arguments> withPathMatcher() {
return Stream.of(
arguments(get, "/wildcard_any", "wildcard_test1"),
arguments(post, "/wildcard/any", "wildcard_test2")
);
}

private static Stream<Arguments> withMultiHandlers() {
return Stream.of(
arguments(get, "/get_multi", "get_multi"),
arguments(post, "/post_multi", "post_multi"),
arguments(put, "/put_multi", "put_multi"),
arguments(delete, "/delete_multi", "delete_multi"),
arguments(head, "/head_multi", "head_multi"),
arguments(options, "/options_multi", "options_multi"),
arguments(trace, "/trace_multi", "trace_multi"),
arguments(patch, "/patch_multi", "patch_multi")
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.nima.tests.integration.server;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import io.helidon.common.http.Http;
import io.helidon.nima.testing.junit5.webserver.ServerTest;
import io.helidon.nima.testing.junit5.webserver.SetUpRoute;
import io.helidon.nima.webclient.http1.Http1Client;
import io.helidon.nima.webclient.http1.Http1ClientResponse;
import io.helidon.nima.webclient.http1.Http1ClientRequest;
import io.helidon.nima.webserver.http.HttpRules;
import io.helidon.nima.webserver.http.ServerRequest;
import io.helidon.nima.webserver.http.ServerResponse;

import static io.helidon.common.testing.http.junit5.HttpHeaderMatcher.hasHeader;

import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

@ServerTest
class RulesTest extends RoutingTestBase {

RulesTest(Http1Client client) {
this.client = client;
}

@SetUpRoute
static void routing(HttpRules rules) {
rules.get("/my path", (req, res) -> res.send("done"))
.get("/českáCesta", (req, res) -> res.send("done"))
// shortcut methods with path matchers
.get("/wildcard_*", (req, res) -> res.send("wildcard_test1"))
.post("/wildcard/*", (req, res) -> res.send("wildcard_test2"))
// shortcut methods with path
.get("/get", (req, res) -> res.send("get"))
.post("/post", (req, res) -> res.send("post"))
.put("/put", (req, res) -> res.send("put"))
.delete("/delete", (req, res) -> res.send("delete"))
.head("/head", (req, res) -> res.send("head"))
.options("/options", (req, res) -> res.send("options"))
.trace("/trace", (req, res) -> res.send("trace"))
.patch("/patch", (req, res) -> res.send("patch"))
.any("/any", (req, res) -> res.send("any"))
// shortcut methods using multiple handlers
.get("/get_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("get_multi"))
.post("/post_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("post_multi"))
.put("/put_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("put_multi"))
.delete("/delete_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("delete_multi"))
.head("/head_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("head_multi"))
.options("/options_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("options_multi"))
.trace("/trace_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("trace_multi"))
.patch("/patch_multi", RoutingTestBase::multiHandler, (req, res) -> res.send("patch_multi"))
// shortcut methods with no path pattern
.get((req, res) -> res.send("get_catchall"))
.post((req, res) -> res.send("post_catchall"))
.put((req, res) -> res.send("put_catchall"))
.delete((req, res) -> res.send("delete_catchall"))
.head((req, res) -> res.send("head_catchall"))
.options((req, res) -> res.send("options_catchall"))
.trace((req, res) -> res.send("trace_catchall"))
.patch((req, res) -> res.send("patch_catchall"));
}
}
Loading

0 comments on commit 6623d33

Please sign in to comment.