![JAR search and dependency download from the Maven repository](/logo.png)
feign.mock.MockClient Maven / Gradle / Ivy
/**
* Copyright (C) 2016 Marvin Herman Froeder ([email protected])
*
* 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 feign.mock;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import feign.Client;
import feign.Request;
import feign.Response;
import feign.Util;
public class MockClient implements Client {
class RequestResponse {
private final RequestKey requestKey;
private final Response.Builder responseBuilder;
public RequestResponse(RequestKey requestKey, Response.Builder responseBuilder) {
this.requestKey = requestKey;
this.responseBuilder = responseBuilder;
}
}
public static final Map> EMPTY_HEADERS = Collections.emptyMap();
private final List responses = new ArrayList<>();
private final Map> requests = new HashMap<>();
private boolean sequential;
private Iterator responseIterator;
public MockClient() {
}
public MockClient(boolean sequential) {
this.sequential = sequential;
}
@Override
public synchronized Response execute(Request request, Request.Options options) throws IOException {
RequestKey requestKey = RequestKey.create(request);
Response.Builder responseBuilder;
if (sequential) {
responseBuilder = executeSequential(requestKey);
} else {
responseBuilder = executeAny(request, requestKey);
}
return responseBuilder
.request(request)
.build();
}
private Response.Builder executeSequential(RequestKey requestKey) {
Response.Builder responseBuilder;
if (responseIterator == null) {
responseIterator = responses.iterator();
}
if (!responseIterator.hasNext()) {
throw new VerificationAssertionError("Received excessive request %s", requestKey);
}
RequestResponse expectedRequestResponse = responseIterator.next();
if (!expectedRequestResponse.requestKey.equalsExtended(requestKey)) {
throw new VerificationAssertionError("Expected %s, but was %s", expectedRequestResponse.requestKey, requestKey);
}
responseBuilder = expectedRequestResponse.responseBuilder;
return responseBuilder;
}
private Response.Builder executeAny(Request request, RequestKey requestKey) {
Response.Builder responseBuilder;
if (requests.containsKey(requestKey)) {
requests.get(requestKey).add(request);
} else {
requests.put(requestKey, new ArrayList<>(Arrays.asList(request)));
}
responseBuilder = getResponseBuilder(request, requestKey);
return responseBuilder;
}
private Response.Builder getResponseBuilder(Request request, RequestKey requestKey) {
Response.Builder responseBuilder = null;
for (RequestResponse requestResponse : responses) {
if (requestResponse.requestKey.equalsExtended(requestKey)) {
responseBuilder = requestResponse.responseBuilder;
// Don't break here, last one should win to be compatible with previous
// releases of this library!
}
}
if (responseBuilder == null) {
responseBuilder = Response.builder()
.status(HttpURLConnection.HTTP_NOT_FOUND)
.reason("Not mocker")
.headers(request.headers());
}
return responseBuilder;
}
public MockClient ok(HttpMethod method, String url, InputStream responseBody) throws IOException {
return ok(RequestKey.builder(method, url).build(), responseBody);
}
public MockClient ok(HttpMethod method, String url, String responseBody) {
return ok(RequestKey.builder(method, url).build(), responseBody);
}
public MockClient ok(HttpMethod method, String url, byte[] responseBody) {
return ok(RequestKey.builder(method, url).build(), responseBody);
}
public MockClient ok(HttpMethod method, String url) {
return ok(RequestKey.builder(method, url).build());
}
public MockClient ok(RequestKey requestKey, InputStream responseBody) throws IOException {
return ok(requestKey, Util.toByteArray(responseBody));
}
public MockClient ok(RequestKey requestKey, String responseBody) {
return ok(requestKey, responseBody.getBytes(StandardCharsets.UTF_8));
}
public MockClient ok(RequestKey requestKey, byte[] responseBody) {
return add(requestKey, HttpURLConnection.HTTP_OK, responseBody);
}
public MockClient ok(RequestKey requestKey) {
return ok(requestKey, (byte[]) null);
}
public MockClient add(HttpMethod method, String url, int status, InputStream responseBody) throws IOException {
return add(RequestKey.builder(method, url).build(), status, responseBody);
}
public MockClient add(HttpMethod method, String url, int status, String responseBody) {
return add(RequestKey.builder(method, url).build(), status, responseBody);
}
public MockClient add(HttpMethod method, String url, int status, byte[] responseBody) {
return add(RequestKey.builder(method, url).build(), status, responseBody);
}
public MockClient add(HttpMethod method, String url, int status) {
return add(RequestKey.builder(method, url).build(), status);
}
/**
* @param response
*
* - the status defaults to 0, not 200!
* - the internal feign-code requires the headers to be set
*
*/
public MockClient add(HttpMethod method, String url, Response.Builder response) {
return add(RequestKey.builder(method, url).build(), response);
}
public MockClient add(RequestKey requestKey, int status, InputStream responseBody) throws IOException {
return add(requestKey, status, Util.toByteArray(responseBody));
}
public MockClient add(RequestKey requestKey, int status, String responseBody) {
return add(requestKey, status, responseBody.getBytes(StandardCharsets.UTF_8));
}
public MockClient add(RequestKey requestKey, int status, byte[] responseBody) {
return add(requestKey, Response.builder()
.status(status)
.reason("Mocked")
.headers(EMPTY_HEADERS)
.body(responseBody));
}
public MockClient add(RequestKey requestKey, int status) {
return add(requestKey, status, (byte[]) null);
}
public MockClient add(RequestKey requestKey, Response.Builder response) {
responses.add(new RequestResponse(requestKey, response));
return this;
}
public MockClient add(HttpMethod method, String url, Response response) {
return this.add(method, url, response.toBuilder());
}
public MockClient noContent(HttpMethod method, String url) {
return add(method, url, HttpURLConnection.HTTP_NO_CONTENT);
}
public Request verifyOne(HttpMethod method, String url) {
return verifyTimes(method, url, 1).get(0);
}
public List verifyTimes(final HttpMethod method, final String url, final int times) {
if (times < 0) {
throw new IllegalArgumentException("times must be a non negative number");
}
if (times == 0) {
verifyNever(method, url);
return Collections.emptyList();
}
RequestKey requestKey = RequestKey.builder(method, url).build();
if (!requests.containsKey(requestKey)) {
throw new VerificationAssertionError("Wanted: '%s' but never invoked!", requestKey);
}
List result = requests.get(requestKey);
if (result.size() != times) {
throw new VerificationAssertionError("Wanted: '%s' to be invoked: '%s' times but got: '%s'!",
requestKey, times, result.size());
}
return result;
}
public void verifyNever(HttpMethod method, String url) {
RequestKey requestKey = RequestKey.builder(method, url).build();
if (requests.containsKey(requestKey)) {
throw new VerificationAssertionError("Do not wanted: '%s' but was invoked!", requestKey);
}
}
/**
* To be called in an @After method:
*
* @After
* public void tearDown() {
* mockClient.verifyStatus();
* }
*
*/
public void verifyStatus() {
if (sequential) {
boolean unopenedIterator = responseIterator == null && !responses.isEmpty();
if (unopenedIterator || responseIterator.hasNext()) {
throw new VerificationAssertionError("More executions were expected");
}
}
}
public void resetRequests() {
requests.clear();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy