From bf7624315f6680bc944c15c32d18119663ded2bc Mon Sep 17 00:00:00 2001
From: Tim Yates
Date: Mon, 6 Feb 2023 12:35:01 +0000
Subject: [PATCH] test: add octet stream serialization to the TCK (#8712)
Inspired by https://github.com/micronaut-projects/micronaut-aws/issues/1545
---
.../http/server/tck/AssertionUtils.java | 4 +-
.../http/server/tck/BodyAssertion.java | 116 ++++++++++++++----
.../server/tck/HttpResponseAssertion.java | 10 +-
.../http/server/tck/tests/MiscTest.java | 1 -
.../http/server/tck/tests/OctetTest.java | 70 +++++++++++
5 files changed, 172 insertions(+), 29 deletions(-)
create mode 100644 http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/OctetTest.java
diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/AssertionUtils.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/AssertionUtils.java
index 6dd2bb26073..873e083952e 100644
--- a/http-server-tck/src/main/java/io/micronaut/http/server/tck/AssertionUtils.java
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/AssertionUtils.java
@@ -98,9 +98,9 @@ public static void assertDoesNotThrow(@NonNull ServerUnderTest server,
assertion.getResponseConsumer().ifPresent(httpResponseConsumer -> httpResponseConsumer.accept(response));
}
- private static void assertBody(@NonNull HttpResponse response, @Nullable BodyAssertion bodyAssertion) {
+ private static void assertBody(@NonNull HttpResponse response, @Nullable BodyAssertion bodyAssertion) {
if (bodyAssertion != null) {
- Optional bodyOptional = response.getBody(String.class);
+ Optional bodyOptional = response.getBody(bodyAssertion.getBodyType());
assertTrue(bodyOptional.isPresent());
bodyOptional.ifPresent(bodyAssertion::evaluate);
}
diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/BodyAssertion.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/BodyAssertion.java
index 71355557883..e37021054ad 100644
--- a/http-server-tck/src/main/java/io/micronaut/http/server/tck/BodyAssertion.java
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/BodyAssertion.java
@@ -17,37 +17,69 @@
import io.micronaut.core.annotation.Experimental;
-import java.util.function.BiFunction;
+import java.util.Arrays;
+import java.util.function.BiPredicate;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
- * HTTP Reponse's body assertions.
+ * HTTP Response's body assertions.
+ *
+ * @param The body type
*/
@Experimental
-public final class BodyAssertion {
- private final String expected;
- private final BiFunction evaluator;
+public final class BodyAssertion {
+
+ private final Class bodyType;
+ private final T expected;
+ private final BiPredicate evaluator;
- private BodyAssertion(String expected, BiFunction evaluator) {
+ private BodyAssertion(Class bodyType, T expected, BiPredicate evaluator) {
+ this.bodyType = bodyType;
this.expected = expected;
this.evaluator = evaluator;
}
+ /**
+ * @return a Builder;
+ */
+ public static BodyAssertion.Builder builder() {
+ return new BodyAssertion.Builder();
+ }
+
/**
* Evaluates the HTTP Response Body.
+ *
* @param body The HTTP Response Body
*/
- public void evaluate(String body) {
- assertTrue(this.evaluator.apply(expected, body));
+ @SuppressWarnings("java:S5960") // Assertion is the whole point of this method
+ public void evaluate(T body) {
+ assertTrue(this.evaluator.test(expected, body));
+ }
+
+ /**
+ * @return The expected body type
+ */
+ public Class getBodyType() {
+ return bodyType;
}
/**
+ * The interface for typed BodyAssertion Builders.
*
- * @return a Builder;
+ * @param The body type
*/
- public static BodyAssertion.Builder builder() {
- return new BodyAssertion.Builder();
+ public interface AssertionBuilder {
+
+ /**
+ * @return a body assertion which verifiers the HTTP Response's body contains the expected body
+ */
+ BodyAssertion contains();
+
+ /**
+ * @return a body assertion which verifiers the HTTP Response's body is equals to the expected body
+ */
+ BodyAssertion equals();
}
/**
@@ -55,32 +87,74 @@ public static BodyAssertion.Builder builder() {
*/
public static class Builder {
- private String body;
+ /**
+ * @param expected Expected Body
+ * @return The Builder
+ */
+ public AssertionBuilder body(String expected) {
+ return new StringBodyAssertionBuilder(expected);
+ }
/**
- *
* @param expected Expected Body
* @return The Builder
*/
- public Builder body(String expected) {
+ public AssertionBuilder body(byte[] expected) {
+ return new ByteArrayBodyAssertionBuilder(expected);
+ }
+ }
+
+ /**
+ * String BodyAssertion Builder.
+ */
+ public static class StringBodyAssertionBuilder extends BodyAssertion.Builder implements AssertionBuilder {
+
+ private final String body;
+
+ public StringBodyAssertionBuilder(String expected) {
+ this.body = expected;
+ }
+
+ /**
+ * @return a body assertion which verifiers the HTTP Response's body contains the expected body
+ */
+ public BodyAssertion contains() {
+ return new BodyAssertion<>(String.class, this.body, (required, received) -> received.contains(required));
+ }
+
+ /**
+ * @return a body assertion which verifiers the HTTP Response's body is equals to the expected body
+ */
+ public BodyAssertion equals() {
+ return new BodyAssertion<>(String.class, this.body, (required, received) -> received.equals(required));
+ }
+ }
+
+ /**
+ * Byte Array BodyAssertion Builder.
+ */
+ public static class ByteArrayBodyAssertionBuilder extends BodyAssertion.Builder implements BodyAssertion.AssertionBuilder {
+
+ private final byte[] body;
+
+ public ByteArrayBodyAssertionBuilder(byte[] expected) {
this.body = expected;
- return this;
}
/**
- *
* @return a body assertion which verifiers the HTTP Response's body contains the expected body
*/
- public BodyAssertion contains() {
- return new BodyAssertion(this.body, (expected, body) -> body.contains(expected));
+ public BodyAssertion contains() {
+ return new BodyAssertion<>(byte[].class, this.body, (required, received) -> {
+ throw new AssertionError("Not implemented yet!");
+ });
}
/**
- *
* @return a body assertion which verifiers the HTTP Response's body is equals to the expected body
*/
- public BodyAssertion equals() {
- return new BodyAssertion(this.body, (expected, body) -> body.equals(expected));
+ public BodyAssertion equals() {
+ return new BodyAssertion<>(byte[].class, this.body, (required, received) -> Arrays.equals(received, required));
}
}
}
diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/HttpResponseAssertion.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/HttpResponseAssertion.java
index 0ec962345b8..1b39cdfb938 100644
--- a/http-server-tck/src/main/java/io/micronaut/http/server/tck/HttpResponseAssertion.java
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/HttpResponseAssertion.java
@@ -36,14 +36,14 @@
public final class HttpResponseAssertion {
private final HttpStatus httpStatus;
private final Map headers;
- private final BodyAssertion bodyAssertion;
+ private final BodyAssertion bodyAssertion;
@Nullable
private final Consumer> responseConsumer;
private HttpResponseAssertion(HttpStatus httpStatus,
Map headers,
- BodyAssertion bodyAssertion,
+ BodyAssertion bodyAssertion,
@Nullable Consumer> responseConsumer) {
this.httpStatus = httpStatus;
this.headers = headers;
@@ -77,7 +77,7 @@ public Map getHeaders() {
* @return Expected HTTP Response body
*/
- public BodyAssertion getBody() {
+ public BodyAssertion getBody() {
return bodyAssertion;
}
@@ -95,7 +95,7 @@ public static HttpResponseAssertion.Builder builder() {
public static class Builder {
private HttpStatus httpStatus;
private Map headers;
- private BodyAssertion bodyAssertion;
+ private BodyAssertion bodyAssertion;
private Consumer> responseConsumer;
@@ -148,7 +148,7 @@ public Builder body(String containsBody) {
* @param bodyAssertion Response Body Assertion
* @return HTTP Response Assertion Builder
*/
- public Builder body(BodyAssertion bodyAssertion) {
+ public Builder body(BodyAssertion bodyAssertion) {
this.bodyAssertion = bodyAssertion;
return this;
}
diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/MiscTest.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/MiscTest.java
index 5e665b41c0a..a7104d96e4f 100644
--- a/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/MiscTest.java
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/MiscTest.java
@@ -38,7 +38,6 @@
import java.util.Collections;
import java.util.Map;
-
@SuppressWarnings({
"java:S5960", // We're allowed assertions, as these are used in tests only
"checkstyle:MissingJavadocType",
diff --git a/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/OctetTest.java b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/OctetTest.java
new file mode 100644
index 00000000000..5778c8c1e42
--- /dev/null
+++ b/http-server-tck/src/main/java/io/micronaut/http/server/tck/tests/OctetTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017-2022 original authors
+ *
+ * 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
+ *
+ * https://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.micronaut.http.server.tck.tests;
+
+import io.micronaut.context.annotation.Requires;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.HttpStatus;
+import io.micronaut.http.MediaType;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import io.micronaut.http.server.tck.AssertionUtils;
+import io.micronaut.http.server.tck.BodyAssertion;
+import io.micronaut.http.server.tck.HttpResponseAssertion;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.stream.IntStream;
+
+import static io.micronaut.http.server.tck.TestScenario.asserts;
+
+@SuppressWarnings({
+ "java:S5960", // We're allowed assertions, as these are used in tests only
+ "checkstyle:MissingJavadocType",
+ "checkstyle:DesignForExtension"
+})
+public class OctetTest {
+
+ public static final String SPEC_NAME = "OctetTest";
+
+ @Test
+ void canReadOctetEncodedData() throws IOException {
+ asserts(SPEC_NAME,
+ HttpRequest.GET("/octets"),
+ (server, request) -> AssertionUtils.assertDoesNotThrow(server, request, HttpResponseAssertion.builder()
+ .status(HttpStatus.OK)
+ .body(BodyAssertion.builder().body(OctetController.BODY_BYTES).equals())
+ .build()));
+ }
+
+ @Controller("/octets")
+ @Requires(property = "spec.name", value = SPEC_NAME)
+ static class OctetController {
+
+ static final byte[] BODY_BYTES = IntStream.iterate(1, i -> i + 1)
+ .limit(256)
+ .map(i -> (byte) i)
+ .collect(ByteArrayOutputStream::new, ByteArrayOutputStream::write, (a, b) -> a.write(b.toByteArray(), 0, b.size()))
+ .toByteArray();
+
+ @Get(produces = MediaType.APPLICATION_OCTET_STREAM)
+ HttpResponse byteArray() {
+ return HttpResponse.ok(BODY_BYTES);
+ }
+ }
+}