Browse Source

Add response headers to FeignException (#1452)

* Add response headers to FeignException

* Test coverage

* Small format issues

* Mistyping: unmodified -> unmodifiable
pull/1463/head
Witalij Berdinskich 3 years ago committed by GitHub
parent
commit
4a309e1a55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      core/pom.xml
  2. 173
      core/src/main/java/feign/FeignException.java
  3. 19
      core/src/main/java/feign/Response.java
  4. 41
      core/src/main/java/feign/Util.java
  5. 5
      core/src/test/java/feign/AsyncFeignTest.java
  6. 8
      core/src/test/java/feign/FeignBuilderTest.java
  7. 43
      core/src/test/java/feign/FeignExceptionTest.java
  8. 8
      core/src/test/java/feign/FeignTest.java
  9. 6
      core/src/test/java/feign/FeignUnderAsyncTest.java
  10. 23
      core/src/test/java/feign/ResponseTest.java
  11. 89
      core/src/test/java/feign/UtilTest.java
  12. 13
      core/src/test/java/feign/client/AbstractClientTest.java
  13. 5
      hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java
  14. 34
      jaxrs2/src/test/java/feign/jaxrs2/JAXRSClientTest.java
  15. 4
      micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java

8
core/pom.xml

@ -29,6 +29,7 @@ @@ -29,6 +29,7 @@
<properties>
<main.basedir>${project.basedir}/..</main.basedir>
<hamcrest.version>1.3</hamcrest.version>
</properties>
<dependencies>
@ -63,6 +64,13 @@ @@ -63,6 +64,13 @@
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

173
core/src/main/java/feign/FeignException.java

@ -22,12 +22,12 @@ import java.nio.ByteBuffer; @@ -22,12 +22,12 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static feign.Util.UTF_8;
import static feign.Util.checkNotNull;
import static feign.Util.*;
import static java.lang.String.format;
/**
@ -40,6 +40,7 @@ public class FeignException extends RuntimeException { @@ -40,6 +40,7 @@ public class FeignException extends RuntimeException {
private static final long serialVersionUID = 0;
private int status;
private byte[] responseBody;
private Map<String, Collection<String>> responseHeaders;
private Request request;
protected FeignException(int status, String message, Throwable cause) {
@ -48,10 +49,12 @@ public class FeignException extends RuntimeException { @@ -48,10 +49,12 @@ public class FeignException extends RuntimeException {
this.request = null;
}
protected FeignException(int status, String message, Throwable cause, byte[] responseBody) {
protected FeignException(int status, String message, Throwable cause, byte[] responseBody,
Map<String, Collection<String>> responseHeaders) {
super(message, cause);
this.status = status;
this.responseBody = responseBody;
this.responseHeaders = caseInsensitiveCopyOf(responseHeaders);
this.request = null;
}
@ -61,10 +64,12 @@ public class FeignException extends RuntimeException { @@ -61,10 +64,12 @@ public class FeignException extends RuntimeException {
this.request = null;
}
protected FeignException(int status, String message, byte[] responseBody) {
protected FeignException(int status, String message, byte[] responseBody,
Map<String, Collection<String>> responseHeaders) {
super(message);
this.status = status;
this.responseBody = responseBody;
this.responseHeaders = caseInsensitiveCopyOf(responseHeaders);
this.request = null;
}
@ -75,10 +80,11 @@ public class FeignException extends RuntimeException { @@ -75,10 +80,11 @@ public class FeignException extends RuntimeException {
}
protected FeignException(int status, String message, Request request, Throwable cause,
byte[] responseBody) {
byte[] responseBody, Map<String, Collection<String>> responseHeaders) {
super(message, cause);
this.status = status;
this.responseBody = responseBody;
this.responseHeaders = caseInsensitiveCopyOf(responseHeaders);
this.request = checkRequestNotNull(request);
}
@ -88,10 +94,12 @@ public class FeignException extends RuntimeException { @@ -88,10 +94,12 @@ public class FeignException extends RuntimeException {
this.request = checkRequestNotNull(request);
}
protected FeignException(int status, String message, Request request, byte[] responseBody) {
protected FeignException(int status, String message, Request request, byte[] responseBody,
Map<String, Collection<String>> responseHeaders) {
super(message);
this.status = status;
this.responseBody = responseBody;
this.responseHeaders = caseInsensitiveCopyOf(responseHeaders);
this.request = checkRequestNotNull(request);
}
@ -126,6 +134,13 @@ public class FeignException extends RuntimeException { @@ -126,6 +134,13 @@ public class FeignException extends RuntimeException {
return Optional.of(ByteBuffer.wrap(this.responseBody));
}
public Map<String, Collection<String>> responseHeaders() {
if (this.responseHeaders == null) {
return Collections.emptyMap();
}
return responseHeaders;
}
public Request request() {
return this.request;
}
@ -148,7 +163,8 @@ public class FeignException extends RuntimeException { @@ -148,7 +163,8 @@ public class FeignException extends RuntimeException {
format("%s reading %s %s", cause.getMessage(), request.httpMethod(), request.url()),
request,
cause,
request.body());
request.body(),
request.headers());
}
public static FeignException errorStatus(String methodKey, Response response) {
@ -166,20 +182,21 @@ public class FeignException extends RuntimeException { @@ -166,20 +182,21 @@ public class FeignException extends RuntimeException {
.withMethodKey(methodKey)
.withBody(body).build();
return errorStatus(response.status(), message, response.request(), body);
return errorStatus(response.status(), message, response.request(), body, response.headers());
}
private static FeignException errorStatus(int status,
String message,
Request request,
byte[] body) {
byte[] body,
Map<String, Collection<String>> headers) {
if (isClientError(status)) {
return clientErrorStatus(status, message, request, body);
return clientErrorStatus(status, message, request, body, headers);
}
if (isServerError(status)) {
return serverErrorStatus(status, message, request, body);
return serverErrorStatus(status, message, request, body, headers);
}
return new FeignException(status, message, request, body);
return new FeignException(status, message, request, body, headers);
}
private static boolean isClientError(int status) {
@ -189,32 +206,33 @@ public class FeignException extends RuntimeException { @@ -189,32 +206,33 @@ public class FeignException extends RuntimeException {
private static FeignClientException clientErrorStatus(int status,
String message,
Request request,
byte[] body) {
byte[] body,
Map<String, Collection<String>> headers) {
switch (status) {
case 400:
return new BadRequest(message, request, body);
return new BadRequest(message, request, body, headers);
case 401:
return new Unauthorized(message, request, body);
return new Unauthorized(message, request, body, headers);
case 403:
return new Forbidden(message, request, body);
return new Forbidden(message, request, body, headers);
case 404:
return new NotFound(message, request, body);
return new NotFound(message, request, body, headers);
case 405:
return new MethodNotAllowed(message, request, body);
return new MethodNotAllowed(message, request, body, headers);
case 406:
return new NotAcceptable(message, request, body);
return new NotAcceptable(message, request, body, headers);
case 409:
return new Conflict(message, request, body);
return new Conflict(message, request, body, headers);
case 410:
return new Gone(message, request, body);
return new Gone(message, request, body, headers);
case 415:
return new UnsupportedMediaType(message, request, body);
return new UnsupportedMediaType(message, request, body, headers);
case 429:
return new TooManyRequests(message, request, body);
return new TooManyRequests(message, request, body, headers);
case 422:
return new UnprocessableEntity(message, request, body);
return new UnprocessableEntity(message, request, body, headers);
default:
return new FeignClientException(status, message, request, body);
return new FeignClientException(status, message, request, body, headers);
}
}
@ -225,20 +243,21 @@ public class FeignException extends RuntimeException { @@ -225,20 +243,21 @@ public class FeignException extends RuntimeException {
private static FeignServerException serverErrorStatus(int status,
String message,
Request request,
byte[] body) {
byte[] body,
Map<String, Collection<String>> headers) {
switch (status) {
case 500:
return new InternalServerError(message, request, body);
return new InternalServerError(message, request, body, headers);
case 501:
return new NotImplemented(message, request, body);
return new NotImplemented(message, request, body, headers);
case 502:
return new BadGateway(message, request, body);
return new BadGateway(message, request, body, headers);
case 503:
return new ServiceUnavailable(message, request, body);
return new ServiceUnavailable(message, request, body, headers);
case 504:
return new GatewayTimeout(message, request, body);
return new GatewayTimeout(message, request, body, headers);
default:
return new FeignServerException(status, message, request, body);
return new FeignServerException(status, message, request, body, headers);
}
}
@ -252,127 +271,145 @@ public class FeignException extends RuntimeException { @@ -252,127 +271,145 @@ public class FeignException extends RuntimeException {
}
public static class FeignClientException extends FeignException {
public FeignClientException(int status, String message, Request request, byte[] body) {
super(status, message, request, body);
public FeignClientException(int status, String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(status, message, request, body, headers);
}
}
public static class BadRequest extends FeignClientException {
public BadRequest(String message, Request request, byte[] body) {
super(400, message, request, body);
public BadRequest(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(400, message, request, body, headers);
}
}
public static class Unauthorized extends FeignClientException {
public Unauthorized(String message, Request request, byte[] body) {
super(401, message, request, body);
public Unauthorized(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(401, message, request, body, headers);
}
}
public static class Forbidden extends FeignClientException {
public Forbidden(String message, Request request, byte[] body) {
super(403, message, request, body);
public Forbidden(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(403, message, request, body, headers);
}
}
public static class NotFound extends FeignClientException {
public NotFound(String message, Request request, byte[] body) {
super(404, message, request, body);
public NotFound(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(404, message, request, body, headers);
}
}
public static class MethodNotAllowed extends FeignClientException {
public MethodNotAllowed(String message, Request request, byte[] body) {
super(405, message, request, body);
public MethodNotAllowed(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(405, message, request, body, headers);
}
}
public static class NotAcceptable extends FeignClientException {
public NotAcceptable(String message, Request request, byte[] body) {
super(406, message, request, body);
public NotAcceptable(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(406, message, request, body, headers);
}
}
public static class Conflict extends FeignClientException {
public Conflict(String message, Request request, byte[] body) {
super(409, message, request, body);
public Conflict(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(409, message, request, body, headers);
}
}
public static class Gone extends FeignClientException {
public Gone(String message, Request request, byte[] body) {
super(410, message, request, body);
public Gone(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(410, message, request, body, headers);
}
}
public static class UnsupportedMediaType extends FeignClientException {
public UnsupportedMediaType(String message, Request request, byte[] body) {
super(415, message, request, body);
public UnsupportedMediaType(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(415, message, request, body, headers);
}
}
public static class TooManyRequests extends FeignClientException {
public TooManyRequests(String message, Request request, byte[] body) {
super(429, message, request, body);
public TooManyRequests(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(429, message, request, body, headers);
}
}
public static class UnprocessableEntity extends FeignClientException {
public UnprocessableEntity(String message, Request request, byte[] body) {
super(422, message, request, body);
public UnprocessableEntity(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(422, message, request, body, headers);
}
}
public static class FeignServerException extends FeignException {
public FeignServerException(int status, String message, Request request, byte[] body) {
super(status, message, request, body);
public FeignServerException(int status, String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(status, message, request, body, headers);
}
}
public static class InternalServerError extends FeignServerException {
public InternalServerError(String message, Request request, byte[] body) {
super(500, message, request, body);
public InternalServerError(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(500, message, request, body, headers);
}
}
public static class NotImplemented extends FeignServerException {
public NotImplemented(String message, Request request, byte[] body) {
super(501, message, request, body);
public NotImplemented(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(501, message, request, body, headers);
}
}
public static class BadGateway extends FeignServerException {
public BadGateway(String message, Request request, byte[] body) {
super(502, message, request, body);
public BadGateway(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(502, message, request, body, headers);
}
}
public static class ServiceUnavailable extends FeignServerException {
public ServiceUnavailable(String message, Request request, byte[] body) {
super(503, message, request, body);
public ServiceUnavailable(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(503, message, request, body, headers);
}
}
public static class GatewayTimeout extends FeignServerException {
public GatewayTimeout(String message, Request request, byte[] body) {
super(504, message, request, body);
public GatewayTimeout(String message, Request request, byte[] body,
Map<String, Collection<String>> headers) {
super(504, message, request, body, headers);
}
}

19
core/src/main/java/feign/Response.java

@ -13,11 +13,11 @@ @@ -13,11 +13,11 @@
*/
package feign;
import static feign.Util.*;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static feign.Util.*;
/**
* An immutable response to an http invocation which only returns string content.
@ -35,9 +35,7 @@ public final class Response implements Closeable { @@ -35,9 +35,7 @@ public final class Response implements Closeable {
this.status = builder.status;
this.request = builder.request;
this.reason = builder.reason; // nullable
this.headers = (builder.headers != null)
? Collections.unmodifiableMap(caseInsensitiveCopyOf(builder.headers))
: new LinkedHashMap<>();
this.headers = caseInsensitiveCopyOf(builder.headers);
this.body = builder.body; // nullable
}
@ -360,17 +358,4 @@ public final class Response implements Closeable { @@ -360,17 +358,4 @@ public final class Response implements Closeable {
}
private static Map<String, Collection<String>> caseInsensitiveCopyOf(Map<String, Collection<String>> headers) {
Map<String, Collection<String>> result =
new TreeMap<String, Collection<String>>(String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, Collection<String>> entry : headers.entrySet()) {
String headerName = entry.getKey();
if (!result.containsKey(headerName)) {
result.put(headerName.toLowerCase(Locale.ROOT), new LinkedList<String>());
}
result.get(headerName).addAll(entry.getValue());
}
return result;
}
}

41
core/src/main/java/feign/Util.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/**
* Copyright 2012-2020 The Feign Authors
* Copyright 2012-2021 The Feign 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
@ -30,15 +30,7 @@ import java.nio.ByteBuffer; @@ -30,15 +30,7 @@ import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@ -360,4 +352,33 @@ public class Util { @@ -360,4 +352,33 @@ public class Util {
public static boolean isBlank(String value) {
return value == null || value.isEmpty();
}
/**
* Copy entire map of string collection.
*
* The copy is unmodifiable map of unmodifiable collections.
*
* @param map string collection map
* @return copy of the map or an empty map if the map is null.
*/
public static Map<String, Collection<String>> caseInsensitiveCopyOf(Map<String, Collection<String>> map) {
if (map == null) {
return Collections.emptyMap();
}
Map<String, Collection<String>> result =
new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
String key = entry.getKey();
if (!result.containsKey(key)) {
result.put(key.toLowerCase(Locale.ROOT), new LinkedList<>());
}
result.get(key).addAll(entry.getValue());
}
result.replaceAll((key, value) -> Collections.unmodifiableCollection(value));
return Collections.unmodifiableMap(result);
}
}

5
core/src/test/java/feign/AsyncFeignTest.java

@ -560,8 +560,9 @@ public class AsyncFeignTest { @@ -560,8 +560,9 @@ public class AsyncFeignTest {
.client(new AsyncClient.Default<>((request, options) -> response, execs))
.target(TestInterfaceAsync.class, "http://localhost:" + server.getPort());
assertEquals(Collections.singletonList("http://bar.com"),
unwrap(api.response()).headers().get("Location"));
assertThat(unwrap(api.response()).headers()).hasEntrySatisfying("Location", value -> {
assertThat(value).contains("http://bar.com");
});
execs.shutdown();
}

8
core/src/test/java/feign/FeignBuilderTest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/**
* Copyright 2012-2020 The Feign Authors
* Copyright 2012-2021 The Feign 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
@ -121,9 +121,9 @@ public class FeignBuilderTest { @@ -121,9 +121,9 @@ public class FeignBuilderTest {
Response response = noFollowApi.defaultMethodPassthrough();
assertThat(response.status()).isEqualTo(302);
assertThat(response.headers().getOrDefault("Location", null))
.isNotNull()
.isEqualTo(Collections.singletonList("/"));
assertThat(response.headers()).hasEntrySatisfying("Location", value -> {
assertThat(value).contains("/");
});
server.enqueue(new MockResponse().setResponseCode(302).addHeader("Location", "/"));
server.enqueue(new MockResponse().setResponseCode(200));

43
core/src/test/java/feign/FeignExceptionTest.java

@ -110,6 +110,35 @@ public class FeignExceptionTest { @@ -110,6 +110,35 @@ public class FeignExceptionTest {
.isNotEqualTo("[400] during [GET] to [/home] [methodKey]: [response]");
}
@Test
public void canGetResponseHeadersFromException() {
Request request = Request.create(
Request.HttpMethod.GET,
"/home",
Collections.emptyMap(),
"data".getBytes(StandardCharsets.UTF_8),
StandardCharsets.UTF_8,
null);
Map<String, Collection<String>> responseHeaders = new HashMap<>();
responseHeaders.put("Content-Type", Collections.singletonList("text/plain"));
responseHeaders.put("Cookie", Arrays.asList("cookie1", "cookie2"));
Response response = Response.builder()
.request(request)
.body("some text", StandardCharsets.UTF_8)
.headers(responseHeaders)
.build();
FeignException exception = FeignException.errorStatus("methodKey", response);
assertThat(exception.responseHeaders())
.hasEntrySatisfying("Content-Type", value -> {
assertThat(value).contains("text/plain");
}).hasEntrySatisfying("Cookie", value -> {
assertThat(value).contains("cookie1", "cookie2");
});
}
@Test(expected = NullPointerException.class)
public void nullRequestShouldThrowNPEwThrowable() {
new Derived(404, "message", null, new Throwable());
@ -117,7 +146,7 @@ public class FeignExceptionTest { @@ -117,7 +146,7 @@ public class FeignExceptionTest {
@Test(expected = NullPointerException.class)
public void nullRequestShouldThrowNPEwThrowableAndBytes() {
new Derived(404, "message", null, new Throwable(), new byte[1]);
new Derived(404, "message", null, new Throwable(), new byte[1], Collections.emptyMap());
}
@Test(expected = NullPointerException.class)
@ -127,7 +156,7 @@ public class FeignExceptionTest { @@ -127,7 +156,7 @@ public class FeignExceptionTest {
@Test(expected = NullPointerException.class)
public void nullRequestShouldThrowNPEwBytes() {
new Derived(404, "message", null, new byte[1]);
new Derived(404, "message", null, new byte[1], Collections.emptyMap());
}
static class Derived extends FeignException {
@ -136,16 +165,18 @@ public class FeignExceptionTest { @@ -136,16 +165,18 @@ public class FeignExceptionTest {
super(status, message, request, cause);
}
public Derived(int status, String message, Request request, Throwable cause, byte[] content) {
super(status, message, request, cause, content);
public Derived(int status, String message, Request request, Throwable cause, byte[] content,
Map<String, Collection<String>> headers) {
super(status, message, request, cause, content, headers);
}
public Derived(int status, String message, Request request) {
super(status, message, request);
}
public Derived(int status, String message, Request request, byte[] content) {
super(status, message, request, content);
public Derived(int status, String message, Request request, byte[] content,
Map<String, Collection<String>> headers) {
super(status, message, request, content, headers);
}
}

8
core/src/test/java/feign/FeignTest.java

@ -43,9 +43,8 @@ import static feign.ExceptionPropagationPolicy.UNWRAP; @@ -43,9 +43,8 @@ import static feign.ExceptionPropagationPolicy.UNWRAP;
import static feign.Util.UTF_8;
import static feign.assertj.MockWebServerAssertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@SuppressWarnings("deprecation")
public class FeignTest {
@ -637,8 +636,9 @@ public class FeignTest { @@ -637,8 +636,9 @@ public class FeignTest {
.client((request, options) -> response)
.target(TestInterface.class, "http://localhost:" + server.getPort());
assertEquals(api.response().headers().get("Location"),
Collections.singletonList("http://bar.com"));
assertThat(api.response().headers()).hasEntrySatisfying("Location", value -> {
assertThat(value).contains("http://bar.com");
});
}
private static class MockRetryer implements Retryer {

6
core/src/test/java/feign/FeignUnderAsyncTest.java

@ -49,7 +49,6 @@ import java.util.NoSuchElementException; @@ -49,7 +49,6 @@ import java.util.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import static feign.ExceptionPropagationPolicy.*;
import static feign.Util.*;
import static feign.assertj.MockWebServerAssertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
@ -541,8 +540,9 @@ public class FeignUnderAsyncTest { @@ -541,8 +540,9 @@ public class FeignUnderAsyncTest {
.client(new AsyncClient.Default<>((request, options) -> response, execs))
.target(TestInterface.class, "http://localhost:" + server.getPort());
assertEquals(api.response().headers().get("Location"),
Collections.singletonList("http://bar.com"));
assertThat(api.response().headers()).hasEntrySatisfying("Location", value -> {
assertThat(value).contains("http://bar.com");
});
execs.shutdown();
}

23
core/src/test/java/feign/ResponseTest.java

@ -14,17 +14,10 @@ @@ -14,17 +14,10 @@
package feign;
import feign.Request.HttpMethod;
import java.nio.charset.StandardCharsets;
import org.assertj.core.util.Lists;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import static feign.assertj.FeignAssertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
@SuppressWarnings("deprecation")
public class ResponseTest {
@ -53,8 +46,12 @@ public class ResponseTest { @@ -53,8 +46,12 @@ public class ResponseTest {
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.body(new byte[0])
.build();
assertThat(response.headers().get("content-type")).isEqualTo(valueList);
assertThat(response.headers().get("Content-Type")).isEqualTo(valueList);
assertThat(response.headers())
.hasEntrySatisfying("content-type", value -> {
assertThat(value).contains("application/json");
}).hasEntrySatisfying("Content-Type", value -> {
assertThat(value).contains("application/json");
});
}
@Test
@ -70,9 +67,9 @@ public class ResponseTest { @@ -70,9 +67,9 @@ public class ResponseTest {
.body(new byte[0])
.build();
List<String> expectedHeaderValue =
Arrays.asList("Cookie-A=Value", "Cookie-B=Value", "Cookie-C=Value");
assertThat(response.headers()).containsOnly(entry(("set-cookie"), expectedHeaderValue));
assertThat(response.headers()).hasEntrySatisfying("set-cookie", value -> {
assertThat(value).contains("Cookie-A=Value", "Cookie-B=Value", "Cookie-C=Value");
});
}
@Test

89
core/src/test/java/feign/UtilTest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/**
* Copyright 2012-2020 The Feign Authors
* Copyright 2012-2021 The Feign 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
@ -13,25 +13,18 @@ @@ -13,25 +13,18 @@
*/
package feign;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.rules.ExpectedException;
import org.junit.Test;
import java.io.Reader;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import feign.codec.Decoder;
import static feign.Util.emptyToNull;
import static feign.Util.removeValues;
import static feign.Util.resolveLastTypeParameter;
import static feign.Util.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class UtilTest {
@ -163,7 +156,7 @@ public class UtilTest { @@ -163,7 +156,7 @@ public class UtilTest {
// Act
final Object retval = Util.checkNotNull(reference, errorMessageTemplate, errorMessageArgs);
// Assert result
Assert.assertEquals(new Integer(0), retval);
assertEquals(new Integer(0), retval);
}
@Test
@ -185,7 +178,7 @@ public class UtilTest { @@ -185,7 +178,7 @@ public class UtilTest {
// Act
final String retval = Util.emptyToNull(string);
// Assert result
Assert.assertEquals("AAAAAAAA", retval);
assertEquals("AAAAAAAA", retval);
}
@Test
@ -195,7 +188,7 @@ public class UtilTest { @@ -195,7 +188,7 @@ public class UtilTest {
// Act
final String retval = Util.emptyToNull(string);
// Assert result
Assert.assertNull(retval);
assertNull(retval);
}
@Test
@ -205,7 +198,7 @@ public class UtilTest { @@ -205,7 +198,7 @@ public class UtilTest {
// Act
final boolean retval = Util.isBlank(value);
// Assert result
Assert.assertEquals(false, retval);
assertEquals(false, retval);
}
@Test
@ -215,7 +208,7 @@ public class UtilTest { @@ -215,7 +208,7 @@ public class UtilTest {
// Act
final boolean retval = Util.isBlank(value);
// Assert result
Assert.assertEquals(true, retval);
assertEquals(true, retval);
}
@Test
@ -225,7 +218,7 @@ public class UtilTest { @@ -225,7 +218,7 @@ public class UtilTest {
// Act
final boolean retval = Util.isNotBlank(value);
// Assert result
Assert.assertEquals(false, retval);
assertEquals(false, retval);
}
@Test
@ -235,15 +228,63 @@ public class UtilTest { @@ -235,15 +228,63 @@ public class UtilTest {
// Act
final boolean retval = Util.isNotBlank(value);
// Assert result
Assert.assertEquals(true, retval);
assertEquals(true, retval);
}
@Test
public void caseInsensitiveCopyOfMap() {
// Arrange
Map<String, Collection<String>> sourceMap = new HashMap<>();
sourceMap.put("First", Arrays.asList("abc", "qwerty", "xyz"));
sourceMap.put("camelCase", Collections.singleton("123"));
// Act
Map<String, Collection<String>> actualMap = caseInsensitiveCopyOf(sourceMap);
// Assert result
assertThat(actualMap)
.hasEntrySatisfying("First", value -> {
assertThat(value).contains("xyz", "abc", "qwerty");
}).hasEntrySatisfying("first", value -> {
assertThat(value).contains("xyz", "abc", "qwerty");
}).hasEntrySatisfying("CAMELCASE", value -> {
assertThat(value).contains("123");
}).hasEntrySatisfying("camelcase", value -> {
assertThat(value).contains("123");
});
}
@Test
public void copyIsUnmodifiable() {
// Arrange
Map<String, Collection<String>> sourceMap = new HashMap<>();
sourceMap.put("First", Arrays.asList("abc", "qwerty", "xyz"));
sourceMap.put("camelCase", Collections.singleton("123"));
// Act
Map<String, Collection<String>> unmodifiableMap = caseInsensitiveCopyOf(sourceMap);
// Assert result
assertThatThrownBy(() -> unmodifiableMap.put("new", Collections.singleton("223322")))
.isInstanceOf(UnsupportedOperationException.class);
assertThatThrownBy(() -> unmodifiableMap.get("camelCase").clear())
.isInstanceOf(UnsupportedOperationException.class);
}
@Test
public void nullMap() {
// Act
Map<String, Collection<String>> actualMap = caseInsensitiveCopyOf(null);
// Assert result
assertThat(actualMap)
.isNotNull()
.isEmpty();
}
interface LastTypeParameter {
final List<String> LIST_STRING = null;
final Parameterized<List<String>> PARAMETERIZED_LIST_STRING = null;
final Parameterized<? extends List<String>> PARAMETERIZED_WILDCARD_LIST_STRING = null;
final ParameterizedDecoder<List<String>> PARAMETERIZED_DECODER_LIST_STRING = null;
final ParameterizedDecoder<?> PARAMETERIZED_DECODER_UNBOUND = null;
List<String> LIST_STRING = null;
Parameterized<List<String>> PARAMETERIZED_LIST_STRING = null;
Parameterized<? extends List<String>> PARAMETERIZED_WILDCARD_LIST_STRING = null;
ParameterizedDecoder<List<String>> PARAMETERIZED_DECODER_LIST_STRING = null;
ParameterizedDecoder<?> PARAMETERIZED_DECODER_UNBOUND = null;
}
interface ParameterizedDecoder<T extends List<String>> extends Decoder {

13
core/src/test/java/feign/client/AbstractClientTest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/**
* Copyright 2012-2020 The Feign Authors
* Copyright 2012-2021 The Feign 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
@ -14,8 +14,7 @@ @@ -14,8 +14,7 @@
package feign.client;
import static feign.Util.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.*;
import static org.junit.Assert.assertEquals;
import feign.Client;
import feign.CollectionFormat;
@ -89,8 +88,12 @@ public abstract class AbstractClientTest { @@ -89,8 +88,12 @@ public abstract class AbstractClientTest {
assertThat(response.status()).isEqualTo(200);
assertThat(response.reason()).isEqualTo("OK");
assertThat(response.headers())
.containsEntry("Content-Length", Collections.singletonList("3"))
.containsEntry("Foo", Collections.singletonList("Bar"));
.hasEntrySatisfying("Content-Length", value -> {
assertThat(value).contains("3");
})
.hasEntrySatisfying("Foo", value -> {
assertThat(value).contains("Bar");
});
assertThat(response.body().asInputStream())
.hasSameContentAs(new ByteArrayInputStream("foo".getBytes(UTF_8)));

5
hc5/src/test/java/feign/hc5/AsyncApacheHttp5ClientTest.java

@ -509,8 +509,9 @@ public class AsyncApacheHttp5ClientTest { @@ -509,8 +509,9 @@ public class AsyncApacheHttp5ClientTest {
.client(new AsyncClient.Default<>((request, options) -> response, execs))
.target(TestInterfaceAsync.class, "http://localhost:" + server.getPort());
assertEquals(Collections.singletonList("http://bar.com"),
unwrap(api.response()).headers().get("Location"));
assertThat(unwrap(api.response()).headers()).hasEntrySatisfying("Location", value -> {
assertThat(value).contains("http://bar.com");
});
execs.shutdown();
}

34
jaxrs2/src/test/java/feign/jaxrs2/JAXRSClientTest.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/**
* Copyright 2012-2020 The Feign Authors
* Copyright 2012-2021 The Feign 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
@ -13,31 +13,22 @@ @@ -13,31 +13,22 @@
*/
package feign.jaxrs2;
import static feign.Util.UTF_8;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import feign.Feign;
import feign.*;
import feign.Feign.Builder;
import feign.Headers;
import feign.RequestLine;
import feign.Response;
import feign.Util;
import feign.assertj.MockWebServerAssertions;
import feign.client.AbstractClientTest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collections;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.ProcessingException;
import feign.jaxrs.JAXRSContract;
import okhttp3.mockwebserver.MockResponse;
import org.assertj.core.data.MapEntry;
import org.junit.Assume;
import org.junit.Test;
import javax.ws.rs.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collections;
import static feign.Util.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
/**
* Tests client-specific behavior, such as ensuring Content-Length is sent when specified.
@ -102,8 +93,11 @@ public class JAXRSClientTest extends AbstractClientTest { @@ -102,8 +93,11 @@ public class JAXRSClientTest extends AbstractClientTest {
assertThat(response.status()).isEqualTo(200);
assertThat(response.reason()).isEqualTo("OK");
assertThat(response.headers())
.containsEntry("Content-Length", asList("3"))
.containsEntry("Foo", asList("Bar"));
.hasEntrySatisfying("Content-Length", value -> {
assertThat(value).contains("3");
}).hasEntrySatisfying("Foo", value -> {
assertThat(value).contains("Bar");
});
assertThat(response.body().asInputStream())
.hasSameContentAs(new ByteArrayInputStream("foo".getBytes(UTF_8)));

4
micrometer/src/test/java/feign/micrometer/AbstractMetricsTestBase.java

@ -89,7 +89,7 @@ public abstract class AbstractMetricsTestBase<MR, METRIC_ID, METRIC> { @@ -89,7 +89,7 @@ public abstract class AbstractMetricsTestBase<MR, METRIC_ID, METRIC> {
final SimpleSource source = Feign.builder()
.client((request, options) -> {
notFound.set(new FeignException.NotFound("test", request, null));
notFound.set(new FeignException.NotFound("test", request, null, null));
throw notFound.get();
})
.addCapability(createMetricCapability())
@ -117,7 +117,7 @@ public abstract class AbstractMetricsTestBase<MR, METRIC_ID, METRIC> { @@ -117,7 +117,7 @@ public abstract class AbstractMetricsTestBase<MR, METRIC_ID, METRIC> {
.client(new MockClient()
.ok(HttpMethod.GET, "/get", "1234567890abcde"))
.decoder((response, type) -> {
notFound.set(new FeignException.NotFound("test", response.request(), null));
notFound.set(new FeignException.NotFound("test", response.request(), null, null));
throw notFound.get();
})
.addCapability(createMetricCapability())

Loading…
Cancel
Save