Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2020 Red Hat, Inc.
*
* 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.reactiverse.junit5.web;
import io.netty.handler.codec.http.QueryStringEncoder;
import io.vertx.codegen.annotations.Fluent;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.Promise;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.multipart.MultipartForm;
import io.vertx.junit5.Checkpoint;
import io.vertx.junit5.VertxTestContext;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import static org.junit.jupiter.api.Assertions.*;
/**
* This class is a wrapper around {@link WebClient} that simplifies the creation of Http requests and the asserts on responses.
*
* @author Francesco Guardiani
*/
public class TestRequest {
HttpRequest req;
List>> requestTranformations;
List>> responseAsserts;
private TestRequest(HttpRequest req) {
this.req = req;
this.requestTranformations = new ArrayList<>();
this.responseAsserts = new ArrayList<>();
}
/**
* Add one or more transformations to the TestRequest.
* Note: this transformations are evaluated when one of the send methods is called
*
* @param transformations
* @return a reference to this, so the API can be used fluently
*/
@Fluent
@SafeVarargs
public final TestRequest with(Consumer>... transformations) {
requestTranformations.addAll(Arrays.asList(transformations));
return this;
}
/**
* Add one or more response asserts to the TestRequest.
*
* @param asserts
* @return a reference to this, so the API can be used fluently
*/
@Fluent
@SafeVarargs
public final TestRequest expect(Consumer>... asserts) {
responseAsserts.addAll(Arrays.asList(asserts));
return this;
}
/**
* Send and flag the provided checkpoint with {@link Checkpoint#flag()} when request is completed and no assertion fails
*
* @param testContext
* @param checkpoint
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> send(VertxTestContext testContext, Checkpoint checkpoint) {
return internalSend(testContext, h -> req.send(h), checkpoint::flag);
}
/**
* Send and complete test context with {@link VertxTestContext#completeNow()} when request is completed and no assertion fails
*
* @param testContext
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> send(VertxTestContext testContext) {
return internalSend(testContext, h -> req.send(h), testContext::completeNow);
}
/**
* Send and execute {@code onEnd} code block wrapped in {@link VertxTestContext#verify(VertxTestContext.ExecutionBlock)}
* when request is completed and no assertion fails
*
* @param testContext
* @param onEnd
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> send(VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd) {
return internalSend(testContext, h -> req.send(h), onEnd);
}
/**
* Send a json and flag the provided checkpoint with {@link Checkpoint#flag()} when request is completed and no assertion fails
*
* @param json
* @param testContext
* @param checkpoint
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendJson(Object json, VertxTestContext testContext, Checkpoint checkpoint) {
return internalSend(testContext, h -> req.sendJson(json, h), checkpoint::flag);
}
/**
* Send a json and complete test context with {@link VertxTestContext#completeNow()} when request is completed and no assertion fails
*
* @param json
* @param testContext
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendJson(Object json, VertxTestContext testContext) {
return internalSend(testContext, h -> req.sendJson(json, h), testContext::completeNow);
}
/**
* Send a json and execute {@code onEnd} code block wrapped in {@link VertxTestContext#verify(VertxTestContext.ExecutionBlock)}
* when request is completed and no assertion fails
*
* @param json
* @param testContext
* @param onEnd
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendJson(Object json, VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd) {
return internalSend(testContext, h -> req.sendJson(json, h), onEnd);
}
/**
* Send a {@link Buffer} and flag the provided checkpoint with {@link Checkpoint#flag()} when request is completed and no assertion fails
*
* @param buf
* @param testContext
* @param checkpoint
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendBuffer(Buffer buf, VertxTestContext testContext, Checkpoint checkpoint) {
return internalSend(testContext, h -> req.sendBuffer(buf, h), checkpoint::flag);
}
/**
* Send a {@link Buffer} and complete test context with {@link VertxTestContext#completeNow()} when request is completed and no assertion fails
*
* @param buf
* @param testContext
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendBuffer(Buffer buf, VertxTestContext testContext) {
return internalSend(testContext, h -> req.sendBuffer(buf, h), testContext::completeNow);
}
/**
* Send a {@link Buffer} and execute {@code onEnd} code block wrapped in {@link VertxTestContext#verify(VertxTestContext.ExecutionBlock)}
* when request is completed and no assertion fails
*
* @param buf
* @param testContext
* @param onEnd
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendBuffer(Buffer buf, VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd) {
return internalSend(testContext, h -> req.sendBuffer(buf, h), onEnd);
}
/**
* Send an URL Encoded form and flag the provided checkpoint with {@link Checkpoint#flag()} when request is completed and no assertion fails
*
* @param form
* @param testContext
* @param checkpoint
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendURLEncodedForm(MultiMap form, VertxTestContext testContext, Checkpoint checkpoint) {
return internalSend(testContext, h -> req.sendForm(form, h), checkpoint::flag);
}
/**
* Send an URL Encoded form and complete test context with {@link VertxTestContext#completeNow()} when request is completed and no assertion fails
*
* @param form
* @param testContext
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendURLEncodedForm(MultiMap form, VertxTestContext testContext) {
return internalSend(testContext, h -> req.sendForm(form, h), testContext::completeNow);
}
/**
* Send an URL Encoded form and execute {@code onEnd} code block wrapped in {@link VertxTestContext#verify(VertxTestContext.ExecutionBlock)}
* when request is completed and no assertion fails
*
* @param form
* @param testContext
* @param onEnd
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendURLEncodedForm(MultiMap form, VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd) {
return internalSend(testContext, h -> req.sendForm(form, h), onEnd);
}
/**
* Send a multipart form and flag the provided checkpoint with {@link Checkpoint#flag()} when request is completed and no assertion fails
*
* @param form
* @param testContext
* @param checkpoint
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendMultipartForm(MultipartForm form, VertxTestContext testContext, Checkpoint checkpoint) {
return internalSend(testContext, h -> req.sendMultipartForm(form, h), checkpoint::flag);
}
/**
* Send a multipart form and complete test context with {@link VertxTestContext#completeNow()} when request is completed and no assertion fails
*
* @param form
* @param testContext
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendMultipartForm(MultipartForm form, VertxTestContext testContext) {
return internalSend(testContext, h -> req.sendMultipartForm(form, h), testContext::completeNow);
}
/**
* Send a multipart form and execute {@code onEnd} code block wrapped in {@link VertxTestContext#verify(VertxTestContext.ExecutionBlock)}
* when request is completed and no assertion fails
*
* @param form
* @param testContext
* @param onEnd
* @return a future that will be completed when the response is ready and no response assertion fails
*/
public Future> sendMultipartForm(MultipartForm form, VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd) {
return internalSend(testContext, h -> req.sendMultipartForm(form, h), onEnd);
}
private Handler>> generateHandleResponse(VertxTestContext testContext, VertxTestContext.ExecutionBlock onEnd, Promise> fut, StackTraceElement[] stackTrace) {
return ar -> {
if (ar.failed()) {
testContext.failNow(ar.cause());
} else {
testContext.verify(() -> {
try {
this.responseAsserts.forEach(c -> c.accept(ar.result()));
} catch (AssertionError e) {
AssertionError newE = new AssertionError("Assertion error in response: " + e.getMessage(), e);
newE.setStackTrace(stackTrace);
throw newE;
}
onEnd.apply();
});
fut.complete(ar.result());
}
};
}
private Future> internalSend(VertxTestContext testContext, Consumer>>> reqSendFunction, VertxTestContext.ExecutionBlock onEnd) {
Promise> promise = Promise.promise();
this.requestTranformations.forEach(c -> c.accept(req));
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
reqSendFunction.accept(generateHandleResponse(testContext, onEnd, promise, Arrays.copyOfRange(
stackTrace,
3,
stackTrace.length
)));
return promise.future();
}
/**
* Creates a new {@link TestRequest} object with provided client, method and path
*
* @param client
* @param method
* @param path
* @return
*/
public static TestRequest testRequest(WebClient client, HttpMethod method, String path) {
return new TestRequest(client.request(method, path));
}
/**
* Wraps {@link HttpRequest} in a new {@link TestRequest}
*
* @param request
* @return
*/
public static TestRequest testRequest(HttpRequest request) {
return new TestRequest(request);
}
/**
* Add an header to the request
*
* @param key
* @param value
* @return
*/
public static Consumer> requestHeader(String key, String value) {
return req -> req.putHeader(key, value);
}
/**
*
* @param encoder
* @return
*/
public static Consumer> cookie(QueryStringEncoder encoder) {
return req -> {
try {
String rawQuery = encoder.toUri().getRawQuery();
if (rawQuery != null && !rawQuery.isEmpty()) {
req.putHeader("cookie", encoder.toUri().getRawQuery());
}
} catch (URISyntaxException e) {
e.printStackTrace();
}
};
}
public static Consumer> queryParam(String key, String value) {
return req -> req.addQueryParam(key, value);
}
public static Consumer> statusCode(int statusCode) {
return res -> assertEquals(statusCode, res.statusCode());
}
public static Consumer> statusMessage(String statusMessage) {
return res -> assertEquals(statusMessage, res.statusMessage());
}
public static Consumer> jsonBodyResponse(Object expected) {
return res -> {
String ctHeader = res.getHeader("content-type");
assertNotNull(ctHeader, "Content-type must not be null");
assertTrue(ctHeader.contains("application/json"), "Expected application/json Content-type, Actual: " + ctHeader);
Object json = Json.decodeValue(res.bodyAsBuffer());
assertEquals(expected, json);
};
}
public static Consumer> bodyResponse(Buffer expected, String expectedContentType) {
return res -> {
assertEquals(expectedContentType, res.getHeader("content-type"));
assertEquals(expected, res.bodyAsBuffer());
};
}
public static Consumer> responseHeader(String headerName, String headerValue) {
return res -> {
assertEquals(headerValue, res.getHeader(headerName));
};
}
public static Consumer> emptyResponse() {
return res -> {
assertNull(res.body());
};
}
public static String urlEncode(String s) {
try {
return URLEncoder.encode(s, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}