Skip to content

Commit

Permalink
test: add octet stream serialization to the TCK (micronaut-projects#8712
Browse files Browse the repository at this point in the history
  • Loading branch information
timyates authored Feb 6, 2023
1 parent b7a2b0b commit bf76243
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ public static <T> void assertDoesNotThrow(@NonNull ServerUnderTest server,
assertion.getResponseConsumer().ifPresent(httpResponseConsumer -> httpResponseConsumer.accept(response));
}

private static void assertBody(@NonNull HttpResponse<?> response, @Nullable BodyAssertion bodyAssertion) {
private static <T> void assertBody(@NonNull HttpResponse<?> response, @Nullable BodyAssertion<T> bodyAssertion) {
if (bodyAssertion != null) {
Optional<String> bodyOptional = response.getBody(String.class);
Optional<T> bodyOptional = response.getBody(bodyAssertion.getBodyType());
assertTrue(bodyOptional.isPresent());
bodyOptional.ifPresent(bodyAssertion::evaluate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,144 @@

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 <T> The body type
*/
@Experimental
public final class BodyAssertion {
private final String expected;
private final BiFunction<String, String, Boolean> evaluator;
public final class BodyAssertion<T> {

private final Class<T> bodyType;
private final T expected;
private final BiPredicate<T, T> evaluator;

private BodyAssertion(String expected, BiFunction<String, String, Boolean> evaluator) {
private BodyAssertion(Class<T> bodyType, T expected, BiPredicate<T, T> 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<T> getBodyType() {
return bodyType;
}

/**
* The interface for typed BodyAssertion Builders.
*
* @return a Builder;
* @param <T> The body type
*/
public static BodyAssertion.Builder builder() {
return new BodyAssertion.Builder();
public interface AssertionBuilder<T> {

/**
* @return a body assertion which verifiers the HTTP Response's body contains the expected body
*/
BodyAssertion<T> contains();

/**
* @return a body assertion which verifiers the HTTP Response's body is equals to the expected body
*/
BodyAssertion<T> equals();
}

/**
* BodyAssertion Builder.
*/
public static class Builder {

private String body;
/**
* @param expected Expected Body
* @return The Builder
*/
public AssertionBuilder<String> body(String expected) {
return new StringBodyAssertionBuilder(expected);
}

/**
*
* @param expected Expected Body
* @return The Builder
*/
public Builder body(String expected) {
public AssertionBuilder<byte[]> body(byte[] expected) {
return new ByteArrayBodyAssertionBuilder(expected);
}
}

/**
* String BodyAssertion Builder.
*/
public static class StringBodyAssertionBuilder extends BodyAssertion.Builder implements AssertionBuilder<String> {

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<String> 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<String> 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<byte[]> {

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<byte[]> 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<byte[]> equals() {
return new BodyAssertion<>(byte[].class, this.body, (required, received) -> Arrays.equals(received, required));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@
public final class HttpResponseAssertion {
private final HttpStatus httpStatus;
private final Map<String, String> headers;
private final BodyAssertion bodyAssertion;
private final BodyAssertion<?> bodyAssertion;

@Nullable
private final Consumer<HttpResponse<?>> responseConsumer;

private HttpResponseAssertion(HttpStatus httpStatus,
Map<String, String> headers,
BodyAssertion bodyAssertion,
BodyAssertion<?> bodyAssertion,
@Nullable Consumer<HttpResponse<?>> responseConsumer) {
this.httpStatus = httpStatus;
this.headers = headers;
Expand Down Expand Up @@ -77,7 +77,7 @@ public Map<String, String> getHeaders() {
* @return Expected HTTP Response body
*/

public BodyAssertion getBody() {
public BodyAssertion<?> getBody() {
return bodyAssertion;
}

Expand All @@ -95,7 +95,7 @@ public static HttpResponseAssertion.Builder builder() {
public static class Builder {
private HttpStatus httpStatus;
private Map<String, String> headers;
private BodyAssertion bodyAssertion;
private BodyAssertion<?> bodyAssertion;

private Consumer<HttpResponse<?>> responseConsumer;

Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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<byte[]> byteArray() {
return HttpResponse.ok(BODY_BYTES);
}
}
}

0 comments on commit bf76243

Please sign in to comment.