Merge remote-tracking branch 'origin/2.2.x'
Fixes gh-286. # Conflicts: # spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/DefaultFeignLoadBalancerConfiguration.java # spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/HttpClientFeignLoadBalancerConfiguration.java # spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/OkHttpFeignLoadBalancerConfiguration.java # spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/ribbon/FeignLoadBalancer.java # spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/ribbon/RetryableFeignLoadBalancer.java # spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/loadbalancer/FeignLoadBalancerAutoConfigurationTests.java
This commit is contained in:
@@ -18,9 +18,14 @@ package org.springframework.cloud.openfeign.loadbalancer;
|
||||
|
||||
import feign.Client;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
@@ -35,8 +40,21 @@ class DefaultFeignLoadBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnRetryNotEnabledCondition.class)
|
||||
public Client feignClient(LoadBalancerClient loadBalancerClient) {
|
||||
return new FeignBlockingLoadBalancerClient(new Client.Default(null, null), loadBalancerClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
|
||||
@ConditionalOnBean(LoadBalancedRetryFactory.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public Client feignRetryClient(LoadBalancerClient loadBalancerClient,
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory) {
|
||||
return new RetryableBlockingFeignLoadBalancerClient(new Client.Default(null, null), loadBalancerClient,
|
||||
loadBalancedRetryFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,9 +24,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.openfeign.clientconfig.HttpClientFeignConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@@ -46,9 +48,22 @@ class HttpClientFeignLoadBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnRetryNotEnabledCondition.class)
|
||||
public Client feignClient(LoadBalancerClient loadBalancerClient, HttpClient httpClient) {
|
||||
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
|
||||
return new FeignBlockingLoadBalancerClient(delegate, loadBalancerClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
|
||||
@ConditionalOnBean(LoadBalancedRetryFactory.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public Client feignRetryClient(LoadBalancerClient loadBalancerClient, HttpClient httpClient,
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory) {
|
||||
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
|
||||
return new RetryableBlockingFeignLoadBalancerClient(delegate, loadBalancerClient, loadBalancedRetryFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.openfeign.clientconfig.OkHttpFeignConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@@ -45,9 +47,22 @@ class OkHttpFeignLoadBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(OnRetryNotEnabledCondition.class)
|
||||
public Client feignClient(okhttp3.OkHttpClient okHttpClient, LoadBalancerClient loadBalancerClient) {
|
||||
OkHttpClient delegate = new OkHttpClient(okHttpClient);
|
||||
return new FeignBlockingLoadBalancerClient(delegate, loadBalancerClient);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
|
||||
@ConditionalOnBean(LoadBalancedRetryFactory.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
public Client feignRetryClient(LoadBalancerClient loadBalancerClient, okhttp3.OkHttpClient okHttpClient,
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory) {
|
||||
OkHttpClient delegate = new OkHttpClient(okHttpClient);
|
||||
return new RetryableBlockingFeignLoadBalancerClient(delegate, loadBalancerClient, loadBalancedRetryFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or 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 org.springframework.cloud.openfeign.loadbalancer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
|
||||
/**
|
||||
* A condition that verifies that {@link RetryTemplate} is on the classpath, a
|
||||
* {@link LoadBalancedRetryFactory} bean is present and
|
||||
* <code>spring.cloud.loadbalancer.retry.enabled</code> is not set to <code>false</code>.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 2.2.6
|
||||
*/
|
||||
public class OnRetryNotEnabledCondition extends AnyNestedCondition {
|
||||
|
||||
public OnRetryNotEnabledCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
|
||||
static class OnNoRetryTemplateCondition {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(LoadBalancedRetryFactory.class)
|
||||
static class OnRetryFactoryCondition {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "false")
|
||||
static class OnLoadBalancerRetryEnabledCondition {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or 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 org.springframework.cloud.openfeign.loadbalancer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
|
||||
import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRecoveryCallback;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.client.loadbalancer.RetryableRequestContext;
|
||||
import org.springframework.cloud.client.loadbalancer.RetryableStatusCodeException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.retry.RetryListener;
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||
import org.springframework.retry.policy.NeverRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link Client} implementation that provides Spring Retry support for requests
|
||||
* load-balanced with Spring Cloud LoadBalancer.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 2.2.6
|
||||
*/
|
||||
public class RetryableBlockingFeignLoadBalancerClient implements Client {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(FeignBlockingLoadBalancerClient.class);
|
||||
|
||||
private final Client delegate;
|
||||
|
||||
private final LoadBalancerClient loadBalancerClient;
|
||||
|
||||
private final LoadBalancedRetryFactory loadBalancedRetryFactory;
|
||||
|
||||
public RetryableBlockingFeignLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory) {
|
||||
this.delegate = delegate;
|
||||
this.loadBalancerClient = loadBalancerClient;
|
||||
this.loadBalancedRetryFactory = loadBalancedRetryFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request, Request.Options options) throws IOException {
|
||||
final URI originalUri = URI.create(request.url());
|
||||
String serviceId = originalUri.getHost();
|
||||
Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);
|
||||
final LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryFactory.createRetryPolicy(serviceId,
|
||||
loadBalancerClient);
|
||||
RetryTemplate retryTemplate = buildRetryTemplate(serviceId, request, retryPolicy);
|
||||
return retryTemplate.execute(context -> {
|
||||
Request feignRequest = null;
|
||||
// On retries the policy will choose the server and set it in the context
|
||||
// and extract the server and update the request being made
|
||||
if (context instanceof LoadBalancedRetryContext) {
|
||||
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
|
||||
ServiceInstance serviceInstance = lbContext.getServiceInstance();
|
||||
if (serviceInstance == null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. "
|
||||
+ "Reattempting service instance selection");
|
||||
}
|
||||
ServiceInstance previousServiceInstance = lbContext.getPreviousServiceInstance();
|
||||
DefaultRequest<RetryableRequestContext> lbRequest = new DefaultRequest<>(
|
||||
new RetryableRequestContext(previousServiceInstance, request));
|
||||
serviceInstance = loadBalancerClient.choose(serviceId, lbRequest);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Selected service instance: %s", serviceInstance));
|
||||
}
|
||||
lbContext.setServiceInstance(serviceInstance);
|
||||
}
|
||||
if (serviceInstance != null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Using service instance from LoadBalancedRetryContext: %s",
|
||||
serviceInstance));
|
||||
}
|
||||
String reconstructedUrl = loadBalancerClient.reconstructURI(serviceInstance, originalUri)
|
||||
.toString();
|
||||
feignRequest = Request.create(request.httpMethod(), reconstructedUrl, request.headers(),
|
||||
request.body(), request.charset(), request.requestTemplate());
|
||||
}
|
||||
}
|
||||
if (feignRequest == null) {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("Service instance was not resolved, executing the original request");
|
||||
}
|
||||
feignRequest = request;
|
||||
}
|
||||
Response response = delegate.execute(feignRequest, options);
|
||||
int responseStatus = response.status();
|
||||
if (retryPolicy != null && retryPolicy.retryableStatusCode(responseStatus)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Retrying on status code: %d", responseStatus));
|
||||
}
|
||||
response.close();
|
||||
throw new RetryableStatusCodeException(serviceId, responseStatus, response, URI.create(request.url()));
|
||||
}
|
||||
return response;
|
||||
}, new LoadBalancedRecoveryCallback<Response, Response>() {
|
||||
@Override
|
||||
protected Response createResponse(Response response, URI uri) {
|
||||
return response;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private RetryTemplate buildRetryTemplate(String serviceId, Request request, LoadBalancedRetryPolicy retryPolicy) {
|
||||
RetryTemplate retryTemplate = new RetryTemplate();
|
||||
BackOffPolicy backOffPolicy = this.loadBalancedRetryFactory.createBackOffPolicy(serviceId);
|
||||
retryTemplate.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
|
||||
RetryListener[] retryListeners = this.loadBalancedRetryFactory.createRetryListeners(serviceId);
|
||||
if (retryListeners != null && retryListeners.length != 0) {
|
||||
retryTemplate.setListeners(retryListeners);
|
||||
}
|
||||
|
||||
retryTemplate.setRetryPolicy(retryPolicy == null ? new NeverRetryPolicy()
|
||||
: new InterceptorRetryPolicy(toHttpRequest(request), retryPolicy, loadBalancerClient, serviceId));
|
||||
return retryTemplate;
|
||||
}
|
||||
|
||||
// Visible for Sleuth instrumentation
|
||||
public Client getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
private HttpRequest toHttpRequest(Request request) {
|
||||
return new HttpRequest() {
|
||||
@Override
|
||||
public HttpMethod getMethod() {
|
||||
return HttpMethod.resolve(request.httpMethod().name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethodValue() {
|
||||
return getMethod().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return URI.create(request.url());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
Map<String, List<String>> headers = new HashMap<>();
|
||||
Map<String, Collection<String>> feignHeaders = request.headers();
|
||||
for (String key : feignHeaders.keySet()) {
|
||||
headers.put(key, new ArrayList<>(feignHeaders.get(key)));
|
||||
}
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.putAll(headers);
|
||||
return httpHeaders;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,10 +23,9 @@ import feign.Client;
|
||||
import feign.Feign;
|
||||
import feign.Target;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@@ -36,7 +35,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -49,11 +47,11 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = FeignHttpClientUrlTests.TestConfig.class, webEnvironment = DEFINED_PORT, value = {
|
||||
"spring.application.name=feignclienturltest", "feign.hystrix.enabled=false", "feign.okhttp.enabled=false" })
|
||||
@SpringBootTest(classes = FeignHttpClientUrlTests.TestConfig.class, webEnvironment = DEFINED_PORT,
|
||||
value = { "spring.application.name=feignclienturltest", "feign.hystrix.enabled=false",
|
||||
"feign.okhttp.enabled=false", "spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class FeignHttpClientUrlTests {
|
||||
class FeignHttpClientUrlTests {
|
||||
|
||||
static int port;
|
||||
|
||||
@@ -66,35 +64,35 @@ public class FeignHttpClientUrlTests {
|
||||
@Autowired
|
||||
private BeanUrlClient beanClient;
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
port = SocketUtils.findAvailableTcpPort();
|
||||
System.setProperty("server.port", String.valueOf(port));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
@AfterAll
|
||||
public static void afterClass() {
|
||||
System.clearProperty("server.port");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUrlHttpClient() {
|
||||
assertThat(this.urlClient).as("UrlClient was null").isNotNull();
|
||||
Hello hello = this.urlClient.getHello();
|
||||
void testUrlHttpClient() {
|
||||
assertThat(urlClient).as("UrlClient was null").isNotNull();
|
||||
Hello hello = urlClient.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello("hello world 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanUrl() {
|
||||
Hello hello = this.beanClient.getHello();
|
||||
void testBeanUrl() {
|
||||
Hello hello = beanClient.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello("hello world 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeanUrlNoProtocol() {
|
||||
Hello hello = this.beanClientNoProtocol.getHello();
|
||||
Hello hello = beanClientNoProtocol.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello("hello world 1"));
|
||||
}
|
||||
@@ -174,15 +172,15 @@ public class FeignHttpClientUrlTests {
|
||||
|
||||
private String message;
|
||||
|
||||
public Hello() {
|
||||
Hello() {
|
||||
}
|
||||
|
||||
public Hello(String message) {
|
||||
Hello(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
@@ -198,12 +196,12 @@ public class FeignHttpClientUrlTests {
|
||||
return false;
|
||||
}
|
||||
Hello that = (Hello) o;
|
||||
return Objects.equals(this.message, that.message);
|
||||
return Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.message);
|
||||
return Objects.hash(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
import feign.Client;
|
||||
import feign.httpclient.ApacheHttpClient;
|
||||
import feign.okhttp.OkHttpClient;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
@@ -36,30 +36,54 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
/**
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class FeignLoadBalancerAutoConfigurationTests {
|
||||
class FeignLoadBalancerAutoConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void shouldInstantiateDefaultFeignBlockingLoadBalancerClientWhenHttpClientDisabled() {
|
||||
ConfigurableApplicationContext context = initContext("feign.httpclient.enabled=false");
|
||||
void shouldInstantiateDefaultFeignBlockingLoadBalancerClientWhenHttpClientDisabled() {
|
||||
ConfigurableApplicationContext context = initContext("feign.httpclient.enabled=false",
|
||||
"spring.cloud.loadbalancer.retry.enabled=false");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalanced(context, Client.Default.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInstantiateHttpFeignClientWhenEnabled() {
|
||||
ConfigurableApplicationContext context = initContext("spring.cloud.loadbalancer.ribbon.enabled=false");
|
||||
void shouldInstantiateHttpFeignClientWhenEnabled() {
|
||||
ConfigurableApplicationContext context = initContext("spring.cloud.loadbalancer.retry.enabled=false");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalanced(context, ApacheHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInstantiateOkHttpFeignClientWhenEnabled() {
|
||||
void shouldInstantiateOkHttpFeignClientWhenEnabled() {
|
||||
ConfigurableApplicationContext context = initContext("feign.httpclient.enabled=false",
|
||||
"feign.okhttp.enabled=true");
|
||||
"feign.okhttp.enabled=true", "spring.cloud.loadbalancer.retry.enabled=false");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalanced(context, OkHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstantiateRetryableDefaultFeignBlockingLoadBalancerClientWhenHttpClientDisabled() {
|
||||
ConfigurableApplicationContext context = initContext("spring.cloud.loadbalancer.ribbon.enabled=false",
|
||||
"feign.httpclient.enabled=false");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalancedWithRetries(context, Client.Default.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstantiateRetryableHttpFeignClientWhenEnabled() {
|
||||
ConfigurableApplicationContext context = initContext("spring.cloud.loadbalancer.ribbon.enabled=false");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalancedWithRetries(context, ApacheHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInstantiateRetryableOkHttpFeignClientWhenEnabled() {
|
||||
ConfigurableApplicationContext context = initContext("spring.cloud.loadbalancer.ribbon.enabled=false",
|
||||
"feign.httpclient.enabled=false", "feign.okhttp.enabled=true");
|
||||
assertThatOneBeanPresent(context, BlockingLoadBalancerClient.class);
|
||||
assertLoadBalancedWithRetries(context, OkHttpClient.class);
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext initContext(String... properties) {
|
||||
return new SpringApplicationBuilder().web(WebApplicationType.NONE).properties(properties)
|
||||
.sources(HttpClientConfiguration.class, LoadBalancerAutoConfiguration.class,
|
||||
@@ -79,4 +103,14 @@ public class FeignLoadBalancerAutoConfigurationTests {
|
||||
assertThat(beans.get("feignClient").getDelegate()).isInstanceOf(delegateClass);
|
||||
}
|
||||
|
||||
private void assertLoadBalancedWithRetries(ConfigurableApplicationContext context, Class delegateClass) {
|
||||
Map<String, RetryableBlockingFeignLoadBalancerClient> retryableBeans = context
|
||||
.getBeansOfType(RetryableBlockingFeignLoadBalancerClient.class);
|
||||
assertThat(retryableBeans).hasSize(1);
|
||||
Map<String, FeignBlockingLoadBalancerClient> beans = context
|
||||
.getBeansOfType(FeignBlockingLoadBalancerClient.class);
|
||||
assertThat(beans).isEmpty();
|
||||
assertThat(retryableBeans.get("feignRetryClient").getDelegate()).isInstanceOf(delegateClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or 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 org.springframework.cloud.openfeign.loadbalancer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.blocking.retry.BlockingLoadBalancedRetryPolicy;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests for {@link RetryableBlockingFeignLoadBalancerClient}. Note: the underlying
|
||||
* {@link BlockingLoadBalancerClient} is already extensively tested in the Spring Cloud
|
||||
* Commons project, so here we are only testing the interactions between
|
||||
* {@link RetryableBlockingFeignLoadBalancerClient} and its delegates.
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class RetryableBlockingFeignLoadBalancerClientTests {
|
||||
|
||||
private Client delegate = mock(Client.class);
|
||||
|
||||
private LoadBalancedRetryFactory retryFactory = mock(LoadBalancedRetryFactory.class);
|
||||
|
||||
private BlockingLoadBalancerClient loadBalancerClient = mock(BlockingLoadBalancerClient.class);
|
||||
|
||||
private LoadBalancerProperties properties = new LoadBalancerProperties();
|
||||
|
||||
private RetryableBlockingFeignLoadBalancerClient feignBlockingLoadBalancerClient = new RetryableBlockingFeignLoadBalancerClient(
|
||||
delegate, loadBalancerClient, retryFactory);
|
||||
|
||||
private ServiceInstance serviceInstance = new DefaultServiceInstance("test-a", "test", "testhost", 80, false);
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
|
||||
when(loadBalancerClient.choose(eq("test"), any())).thenReturn(serviceInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExtractServiceIdFromRequestUrl() throws IOException {
|
||||
Request request = testRequest();
|
||||
Response response = testResponse(200);
|
||||
when(delegate.execute(any(), any())).thenReturn(response);
|
||||
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
|
||||
when(loadBalancerClient.reconstructURI(serviceInstance, URI.create("http://test/path")))
|
||||
.thenReturn(URI.create("http://testhost:80/path"));
|
||||
|
||||
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
|
||||
|
||||
verify(loadBalancerClient).choose(eq("test"), any());
|
||||
verify(loadBalancerClient).reconstructURI(serviceInstance, URI.create("http://test/path"));
|
||||
|
||||
verify(delegate).execute(
|
||||
argThat((Request actualRequest) -> actualRequest.url().equals("http://testhost:80/path")), any());
|
||||
}
|
||||
|
||||
private Response testResponse(int status) {
|
||||
return Response.builder().request(testRequest()).status(status).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldExecuteOriginalRequestIfInstanceNotFound() throws IOException {
|
||||
Request request = testRequest();
|
||||
Response response = testResponse(503);
|
||||
when(loadBalancerClient.choose(eq("test"), any())).thenReturn(null);
|
||||
when(delegate.execute(any(), any())).thenReturn(response);
|
||||
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
|
||||
|
||||
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
|
||||
|
||||
verify(delegate).execute(eq(request), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRetryOnRepeatableStatusCode() throws IOException {
|
||||
properties.getRetry().getRetryableStatusCodes().add(503);
|
||||
Request request = testRequest();
|
||||
Response response = testResponse(503);
|
||||
when(delegate.execute(any(), any())).thenReturn(response);
|
||||
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
|
||||
when(loadBalancerClient.reconstructURI(serviceInstance, URI.create("http://test/path")))
|
||||
.thenReturn(URI.create("http://testhost:80/path"));
|
||||
|
||||
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
|
||||
|
||||
verify(loadBalancerClient, times(2)).reconstructURI(serviceInstance, URI.create("http://test/path"));
|
||||
verify(delegate, times(2)).execute(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldPassCorrectRequestToDelegate() throws IOException {
|
||||
Request request = testRequest();
|
||||
Request.Options options = new Request.Options();
|
||||
String url = "http://127.0.0.1/path";
|
||||
ServiceInstance serviceInstance = new DefaultServiceInstance("test-1", "test", "test-host", 8888, false);
|
||||
when(loadBalancerClient.choose(eq("test"), any())).thenReturn(serviceInstance);
|
||||
when(loadBalancerClient.reconstructURI(serviceInstance, URI.create("http://test/path")))
|
||||
.thenReturn(URI.create(url));
|
||||
Response response = testResponse(200);
|
||||
when(delegate.execute(any(), any())).thenReturn(response);
|
||||
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
|
||||
|
||||
feignBlockingLoadBalancerClient.execute(request, options);
|
||||
|
||||
ArgumentCaptor<Request> captor = ArgumentCaptor.forClass(Request.class);
|
||||
verify(delegate, times(1)).execute(captor.capture(), eq(options));
|
||||
Request actualRequest = captor.getValue();
|
||||
assertThat(actualRequest.httpMethod()).isEqualTo(Request.HttpMethod.GET);
|
||||
assertThat(actualRequest.url()).isEqualTo(url);
|
||||
assertThat(actualRequest.headers()).hasSize(1);
|
||||
assertThat(actualRequest.headers()).containsEntry(HttpHeaders.CONTENT_TYPE,
|
||||
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE));
|
||||
assertThat(new String(actualRequest.body())).isEqualTo("hello");
|
||||
}
|
||||
|
||||
private Request testRequest() {
|
||||
return testRequest("test");
|
||||
}
|
||||
|
||||
private Request testRequest(String host) {
|
||||
return Request.create(Request.HttpMethod.GET, "http://" + host + "/path", testHeaders(), "hello".getBytes(),
|
||||
StandardCharsets.UTF_8, null);
|
||||
}
|
||||
|
||||
private Map<String, Collection<String>> testHeaders() {
|
||||
Map<String, Collection<String>> feignHeaders = new HashMap<>();
|
||||
feignHeaders.put(HttpHeaders.CONTENT_TYPE, Collections.singletonList(MediaType.APPLICATION_JSON_VALUE));
|
||||
return feignHeaders;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,8 +33,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockingDetails;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -52,7 +51,6 @@ import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalance
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -63,11 +61,11 @@ import static org.mockito.Mockito.mockingDetails;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(properties = { "feign.okhttp.enabled: false" })
|
||||
@SpringBootTest(properties = { "feign.okhttp.enabled: false", "spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class ApacheHttpClientConfigurationTests {
|
||||
class ApacheHttpClientConfigurationTests {
|
||||
|
||||
@Autowired
|
||||
ApacheHttpClientConnectionManagerFactory connectionManagerFactory;
|
||||
@@ -79,18 +77,18 @@ public class ApacheHttpClientConfigurationTests {
|
||||
FeignBlockingLoadBalancerClient feignClient;
|
||||
|
||||
@Test
|
||||
public void testFactories() {
|
||||
assertThat(this.connectionManagerFactory).isInstanceOf(ApacheHttpClientConnectionManagerFactory.class);
|
||||
assertThat(this.connectionManagerFactory)
|
||||
void testFactories() {
|
||||
assertThat(connectionManagerFactory).isInstanceOf(ApacheHttpClientConnectionManagerFactory.class);
|
||||
assertThat(connectionManagerFactory)
|
||||
.isInstanceOf(ApacheHttpClientConfigurationTestApp.MyApacheHttpClientConnectionManagerFactory.class);
|
||||
assertThat(this.httpClientFactory).isInstanceOf(ApacheHttpClientFactory.class);
|
||||
assertThat(this.httpClientFactory)
|
||||
assertThat(httpClientFactory).isInstanceOf(ApacheHttpClientFactory.class);
|
||||
assertThat(httpClientFactory)
|
||||
.isInstanceOf(ApacheHttpClientConfigurationTestApp.MyApacheHttpClientFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpClientWithFeign() {
|
||||
Client delegate = this.feignClient.getDelegate();
|
||||
void testHttpClientWithFeign() {
|
||||
Client delegate = feignClient.getDelegate();
|
||||
assertThat(ApacheHttpClient.class.isInstance(delegate)).isTrue();
|
||||
ApacheHttpClient apacheHttpClient = (ApacheHttpClient) delegate;
|
||||
HttpClient httpClient = getField(apacheHttpClient, "client");
|
||||
|
||||
@@ -21,8 +21,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import feign.Client;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.MockingDetails;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -37,7 +36,6 @@ import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -46,13 +44,14 @@ import static org.mockito.Mockito.mockingDetails;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = { "feign.okhttp.enabled: true", "spring.cloud.httpclientfactories.ok.enabled: true",
|
||||
"ribbon.eureka.enabled = false", "ribbon.okhttp.enabled: true", "feign.okhttp.enabled: true",
|
||||
"ribbon.httpclient.enabled: false", "feign.httpclient.enabled: false" })
|
||||
"ribbon.httpclient.enabled: false", "feign.httpclient.enabled: false",
|
||||
"spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class OkHttpClientConfigurationTests {
|
||||
class OkHttpClientConfigurationTests {
|
||||
|
||||
@Autowired
|
||||
OkHttpClientFactory okHttpClientFactory;
|
||||
@@ -64,16 +63,16 @@ public class OkHttpClientConfigurationTests {
|
||||
FeignBlockingLoadBalancerClient feignClient;
|
||||
|
||||
@Test
|
||||
public void testFactories() {
|
||||
assertThat(this.connectionPoolFactory).isInstanceOf(OkHttpClientConnectionPoolFactory.class);
|
||||
assertThat(this.connectionPoolFactory).isInstanceOf(TestConfig.MyOkHttpClientConnectionPoolFactory.class);
|
||||
assertThat(this.okHttpClientFactory).isInstanceOf(OkHttpClientFactory.class);
|
||||
assertThat(this.okHttpClientFactory).isInstanceOf(TestConfig.MyOkHttpClientFactory.class);
|
||||
void testFactories() {
|
||||
assertThat(connectionPoolFactory).isInstanceOf(OkHttpClientConnectionPoolFactory.class);
|
||||
assertThat(connectionPoolFactory).isInstanceOf(TestConfig.MyOkHttpClientConnectionPoolFactory.class);
|
||||
assertThat(okHttpClientFactory).isInstanceOf(OkHttpClientFactory.class);
|
||||
assertThat(okHttpClientFactory).isInstanceOf(TestConfig.MyOkHttpClientFactory.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpClientWithFeign() {
|
||||
Client delegate = this.feignClient.getDelegate();
|
||||
void testHttpClientWithFeign() {
|
||||
Client delegate = feignClient.getDelegate();
|
||||
assertThat(feign.okhttp.OkHttpClient.class.isInstance(delegate)).isTrue();
|
||||
feign.okhttp.OkHttpClient okHttpClient = (feign.okhttp.OkHttpClient) delegate;
|
||||
OkHttpClient httpClient = getField(okHttpClient, "delegate");
|
||||
|
||||
@@ -19,8 +19,7 @@ package org.springframework.cloud.openfeign.valid;
|
||||
import java.util.Objects;
|
||||
|
||||
import feign.Client;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
@@ -41,7 +40,6 @@ import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
@@ -53,15 +51,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = FeignHttpClientTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
|
||||
"spring.application.name=feignclienttest", "feign.hystrix.enabled=false", "feign.okhttp.enabled=false" })
|
||||
@SpringBootTest(classes = FeignHttpClientTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||
value = { "spring.application.name=feignclienttest", "feign.hystrix.enabled=false",
|
||||
"feign.okhttp.enabled=false", "spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class FeignHttpClientTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port = 0;
|
||||
class FeignHttpClientTests {
|
||||
|
||||
@Autowired
|
||||
private TestClient testClient;
|
||||
@@ -73,32 +69,32 @@ public class FeignHttpClientTests {
|
||||
private UserClient userClient;
|
||||
|
||||
@Test
|
||||
public void testSimpleType() {
|
||||
Hello hello = this.testClient.getHello();
|
||||
void testSimpleType() {
|
||||
Hello hello = testClient.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello("hello world 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatch() {
|
||||
ResponseEntity<Void> response = this.testClient.patchHello(new Hello("foo"));
|
||||
void testPatch() {
|
||||
ResponseEntity<Void> response = testClient.patchHello(new Hello("foo"));
|
||||
assertThat(response).isNotNull();
|
||||
String header = response.getHeaders().getFirst("x-hello");
|
||||
assertThat(header).isEqualTo("hello world patch");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeignClientType() throws IllegalAccessException {
|
||||
assertThat(this.feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) this.feignClient;
|
||||
void testFeignClientType() {
|
||||
assertThat(feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) feignClient;
|
||||
Client delegate = client.getDelegate();
|
||||
assertThat(delegate).isInstanceOf(feign.httpclient.ApacheHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeignInheritanceSupport() {
|
||||
assertThat(this.userClient).as("UserClient was null").isNotNull();
|
||||
final User user = this.userClient.getUser(1);
|
||||
void testFeignInheritanceSupport() {
|
||||
assertThat(userClient).as("UserClient was null").isNotNull();
|
||||
final User user = userClient.getUser(1);
|
||||
assertThat(user).as("Returned user was null").isNotNull();
|
||||
assertThat(new User("John Smith")).as("Users were different").isEqualTo(user);
|
||||
}
|
||||
@@ -167,15 +163,15 @@ public class FeignHttpClientTests {
|
||||
|
||||
private String message;
|
||||
|
||||
public Hello() {
|
||||
Hello() {
|
||||
}
|
||||
|
||||
public Hello(String message) {
|
||||
Hello(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
@@ -191,12 +187,12 @@ public class FeignHttpClientTests {
|
||||
return false;
|
||||
}
|
||||
Hello that = (Hello) o;
|
||||
return Objects.equals(this.message, that.message);
|
||||
return Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.message);
|
||||
return Objects.hash(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -205,15 +201,15 @@ public class FeignHttpClientTests {
|
||||
|
||||
private String name;
|
||||
|
||||
public User() {
|
||||
User() {
|
||||
}
|
||||
|
||||
public User(String name) {
|
||||
User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -229,12 +225,12 @@ public class FeignHttpClientTests {
|
||||
return false;
|
||||
}
|
||||
User that = (User) o;
|
||||
return Objects.equals(this.name, that.name);
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name);
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,11 +19,9 @@ package org.springframework.cloud.openfeign.valid;
|
||||
import java.util.Objects;
|
||||
|
||||
import feign.Client;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
@@ -41,7 +39,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
@@ -53,17 +50,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = FeignOkHttpTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||
value = { "spring.application.name=feignclienttest", "feign.hystrix.enabled=false",
|
||||
"feign.httpclient.enabled=false", "feign.okhttp.enabled=true",
|
||||
"spring.cloud.httpclientfactories.ok.enabled=true" })
|
||||
"spring.cloud.httpclientfactories.ok.enabled=true", "spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class FeignOkHttpTests {
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
class FeignOkHttpTests {
|
||||
|
||||
@Autowired
|
||||
private TestClient testClient;
|
||||
@@ -75,32 +69,32 @@ public class FeignOkHttpTests {
|
||||
private UserClient userClient;
|
||||
|
||||
@Test
|
||||
public void testSimpleType() {
|
||||
Hello hello = this.testClient.getHello();
|
||||
void testSimpleType() {
|
||||
Hello hello = testClient.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello("hello world 1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatch() {
|
||||
ResponseEntity<Void> response = this.testClient.patchHello(new Hello("foo"));
|
||||
void testPatch() {
|
||||
ResponseEntity<Void> response = testClient.patchHello(new Hello("foo"));
|
||||
assertThat(response).isNotNull();
|
||||
String header = response.getHeaders().getFirst("x-hello");
|
||||
assertThat(header).isEqualTo("hello world patch");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeignClientType() throws IllegalAccessException {
|
||||
assertThat(this.feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) this.feignClient;
|
||||
void testFeignClientType() {
|
||||
assertThat(feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) feignClient;
|
||||
Client delegate = client.getDelegate();
|
||||
assertThat(delegate).isInstanceOf(feign.okhttp.OkHttpClient.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeignInheritanceSupport() {
|
||||
assertThat(this.userClient).as("UserClient was null").isNotNull();
|
||||
final User user = this.userClient.getUser(1);
|
||||
void testFeignInheritanceSupport() {
|
||||
assertThat(userClient).as("UserClient was null").isNotNull();
|
||||
final User user = userClient.getUser(1);
|
||||
assertThat(user).as("Returned user was null").isNotNull();
|
||||
assertThat(new User("John Smith")).as("Users were different").isEqualTo(user);
|
||||
}
|
||||
@@ -171,15 +165,15 @@ public class FeignOkHttpTests {
|
||||
|
||||
private String message;
|
||||
|
||||
public Hello() {
|
||||
Hello() {
|
||||
}
|
||||
|
||||
public Hello(String message) {
|
||||
Hello(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
@@ -195,12 +189,12 @@ public class FeignOkHttpTests {
|
||||
return false;
|
||||
}
|
||||
Hello that = (Hello) o;
|
||||
return Objects.equals(this.message, that.message);
|
||||
return Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.message);
|
||||
return Objects.hash(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -209,15 +203,15 @@ public class FeignOkHttpTests {
|
||||
|
||||
private String name;
|
||||
|
||||
public User() {
|
||||
User() {
|
||||
}
|
||||
|
||||
public User(String name) {
|
||||
User(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -233,12 +227,12 @@ public class FeignOkHttpTests {
|
||||
return false;
|
||||
}
|
||||
User that = (User) o;
|
||||
return Objects.equals(this.name, that.name);
|
||||
return Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.name);
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,14 +40,10 @@ import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import feign.codec.EncodeException;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
@@ -76,7 +72,6 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -87,7 +82,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -96,14 +91,15 @@ import static org.hamcrest.Matchers.instanceOf;
|
||||
* @author Halvdan Hoem Grelland
|
||||
* @author Aaron Whiteside
|
||||
* @author Darren Foong
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = ValidFeignClientTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||
value = { "spring.application.name=feignclienttest",
|
||||
"logging.level.org.springframework.cloud.openfeign.valid=DEBUG", "feign.httpclient.enabled=false",
|
||||
"feign.okhttp.enabled=false", "feign.hystrix.enabled=true" })
|
||||
"feign.okhttp.enabled=false", "feign.hystrix.enabled=true",
|
||||
"spring.cloud.loadbalancer.retry.enabled=false" })
|
||||
@DirtiesContext
|
||||
public class ValidFeignClientTests {
|
||||
class ValidFeignClientTests {
|
||||
|
||||
public static final String HELLO_WORLD_1 = "hello world 1";
|
||||
|
||||
@@ -113,12 +109,6 @@ public class ValidFeignClientTests {
|
||||
|
||||
public static final String MYHEADER2 = "myheader2";
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Value("${local.server.port}")
|
||||
private int port = 0;
|
||||
|
||||
@Autowired
|
||||
private TestClient testClient;
|
||||
|
||||
@@ -146,104 +136,104 @@ public class ValidFeignClientTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClient() {
|
||||
assertThat(this.testClient).as("testClient was null").isNotNull();
|
||||
assertThat(Proxy.isProxyClass(this.testClient.getClass())).as("testClient is not a java Proxy").isTrue();
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(this.testClient);
|
||||
void testClient() {
|
||||
assertThat(testClient).as("testClient was null").isNotNull();
|
||||
assertThat(Proxy.isProxyClass(testClient.getClass())).as("testClient is not a java Proxy").isTrue();
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(testClient);
|
||||
assertThat(invocationHandler).as("invocationHandler was null").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestMappingClassLevelPropertyReplacement() {
|
||||
Hello hello = this.testClient.getHelloUsingPropertyPlaceHolder();
|
||||
void testRequestMappingClassLevelPropertyReplacement() {
|
||||
Hello hello = testClient.getHelloUsingPropertyPlaceHolder();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello(OI_TERRA_2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleType() {
|
||||
Hello hello = this.testClient.getHello();
|
||||
Hello hello = testClient.getHello();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello(HELLO_WORLD_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptional() {
|
||||
Optional<Hello> hello = this.testClient.getOptionalHello();
|
||||
void testOptional() {
|
||||
Optional<Hello> hello = testClient.getOptionalHello();
|
||||
assertThat(hello).isNotNull().isPresent().contains(new Hello(HELLO_WORLD_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericType() {
|
||||
List<Hello> hellos = this.testClient.getHellos();
|
||||
void testGenericType() {
|
||||
List<Hello> hellos = testClient.getHellos();
|
||||
assertThat(hellos).as("hellos was null").isNotNull();
|
||||
assertThat(getHelloList()).as("hellos didn't match").isEqualTo(hellos);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestInterceptors() {
|
||||
List<String> headers = this.testClient.getHelloHeaders();
|
||||
void testRequestInterceptors() {
|
||||
List<String> headers = testClient.getHelloHeaders();
|
||||
assertThat(headers).as("headers was null").isNotNull();
|
||||
assertThat(headers.contains("myheader1value")).as("headers didn't contain myheader1value").isTrue();
|
||||
assertThat(headers.contains("myheader2value")).as("headers didn't contain myheader2value").isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderPlaceholders() {
|
||||
String header = this.testClient.getHelloHeadersPlaceholders();
|
||||
void testHeaderPlaceholders() {
|
||||
String header = testClient.getHelloHeadersPlaceholders();
|
||||
assertThat(header).as("header was null").isNotNull();
|
||||
assertThat(header).as("header was wrong").isEqualTo("myPlaceholderHeaderValue");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeignClientType() throws IllegalAccessException {
|
||||
assertThat(this.feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) this.feignClient;
|
||||
void testFeignClientType() {
|
||||
assertThat(feignClient).isInstanceOf(FeignBlockingLoadBalancerClient.class);
|
||||
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) feignClient;
|
||||
Client delegate = client.getDelegate();
|
||||
assertThat(delegate).isInstanceOf(Client.Default.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServiceId() {
|
||||
assertThat(this.testClientServiceId).as("testClientServiceId was null").isNotNull();
|
||||
final Hello hello = this.testClientServiceId.getHello();
|
||||
void testServiceId() {
|
||||
assertThat(testClientServiceId).as("testClientServiceId was null").isNotNull();
|
||||
final Hello hello = testClientServiceId.getHello();
|
||||
assertThat(hello).as("The hello response was null").isNotNull();
|
||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello(HELLO_WORLD_1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParams() {
|
||||
void testParams() {
|
||||
List<String> list = Arrays.asList("a", "1", "test");
|
||||
List<String> params = this.testClient.getParams(list);
|
||||
List<String> params = testClient.getParams(list);
|
||||
assertThat(params).as("params was null").isNotNull();
|
||||
assertThat(params.size()).as("params size was wrong").isEqualTo(list.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormattedParams() {
|
||||
void testFormattedParams() {
|
||||
List<LocalDate> list = Arrays.asList(LocalDate.of(2001, 1, 1), LocalDate.of(2018, 6, 10));
|
||||
List<LocalDate> params = this.testClient.getFormattedParams(list);
|
||||
List<LocalDate> params = testClient.getFormattedParams(list);
|
||||
assertThat(params).as("params was null").isNotNull();
|
||||
assertThat(params).as("params not converted correctly").isEqualTo(list);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoContentResponse() {
|
||||
ResponseEntity<Void> response = this.testClient.noContent();
|
||||
void testNoContentResponse() {
|
||||
ResponseEntity<Void> response = testClient.noContent();
|
||||
assertThat(response).as("response was null").isNotNull();
|
||||
assertThat(response.getStatusCode()).as("status code was wrong").isEqualTo(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeadResponse() {
|
||||
ResponseEntity<Void> response = this.testClient.head();
|
||||
void testHeadResponse() {
|
||||
ResponseEntity<Void> response = testClient.head();
|
||||
assertThat(response).as("response was null").isNotNull();
|
||||
assertThat(response.getStatusCode()).as("status code was wrong").isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpEntity() {
|
||||
HttpEntity<Hello> entity = this.testClient.getHelloEntity();
|
||||
void testHttpEntity() {
|
||||
HttpEntity<Hello> entity = testClient.getHelloEntity();
|
||||
assertThat(entity).as("entity was null").isNotNull();
|
||||
Hello hello = entity.getBody();
|
||||
assertThat(hello).as("hello was null").isNotNull();
|
||||
@@ -251,129 +241,130 @@ public class ValidFeignClientTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoreComplexHeader() {
|
||||
String response = this.testClient.moreComplexContentType("{\"value\":\"OK\"}");
|
||||
void testMoreComplexHeader() {
|
||||
String response = testClient.moreComplexContentType("{\"value\":\"OK\"}");
|
||||
assertThat(response).as("response was null").isNotNull();
|
||||
assertThat(response).as("didn't respond with {\"value\":\"OK\"}").isEqualTo("{\"value\":\"OK\"}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeNotFound() {
|
||||
ResponseEntity<String> response = this.decodingTestClient.notFound();
|
||||
void testDecodeNotFound() {
|
||||
ResponseEntity<String> response = decodingTestClient.notFound();
|
||||
assertThat(response).as("response was null").isNotNull();
|
||||
assertThat(response.getStatusCode()).as("status code was wrong").isEqualTo(HttpStatus.NOT_FOUND);
|
||||
assertThat(response.getBody()).as("response body was not null").isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalNotFound() {
|
||||
Optional<String> s = this.decodingTestClient.optional();
|
||||
void testOptionalNotFound() {
|
||||
Optional<String> s = decodingTestClient.optional();
|
||||
assertThat(s).isNotPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertingExpander() {
|
||||
assertThat(this.testClient.getToString(Arg.A)).isEqualTo(Arg.A.toString());
|
||||
assertThat(this.testClient.getToString(Arg.B)).isEqualTo(Arg.B.toString());
|
||||
void testConvertingExpander() {
|
||||
assertThat(testClient.getToString(Arg.A)).isEqualTo(Arg.A.toString());
|
||||
assertThat(testClient.getToString(Arg.B)).isEqualTo(Arg.B.toString());
|
||||
|
||||
assertThat(this.testClient.getToString(new OtherArg("foo"))).isEqualTo("bar");
|
||||
assertThat(testClient.getToString(new OtherArg("foo"))).isEqualTo("bar");
|
||||
List<OtherArg> args = new ArrayList<>();
|
||||
args.add(new OtherArg("foo"));
|
||||
args.add(new OtherArg("goo"));
|
||||
List<String> expectedResult = new ArrayList<>();
|
||||
expectedResult.add("bar");
|
||||
expectedResult.add("goo");
|
||||
assertThat(this.testClient.getToString(args)).isEqualTo(expectedResult);
|
||||
assertThat(testClient.getToString(args)).isEqualTo(expectedResult);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namedFeignClientWorks() {
|
||||
assertThat(this.namedFeignClient).as("namedFeignClient was null").isNotNull();
|
||||
void namedFeignClientWorks() {
|
||||
assertThat(namedFeignClient).as("namedFeignClient was null").isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleRequestPart() {
|
||||
String response = this.multipartClient.singlePart("abc");
|
||||
void testSingleRequestPart() {
|
||||
String response = multipartClient.singlePart("abc");
|
||||
assertThat(response).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSinglePojoRequestPart() {
|
||||
String response = this.multipartClient.singlePojoPart(new Hello(HELLO_WORLD_1));
|
||||
void testSinglePojoRequestPart() {
|
||||
String response = multipartClient.singlePojoPart(new Hello(HELLO_WORLD_1));
|
||||
assertThat(response).isEqualTo(HELLO_WORLD_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleRequestParts() {
|
||||
void testMultipleRequestParts() {
|
||||
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null, "hello".getBytes());
|
||||
String response = this.multipartClient.multipart("abc", "123", file);
|
||||
String response = multipartClient.multipart("abc", "123", file);
|
||||
assertThat(response).isEqualTo("abc123hello.bin");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplePojoRequestParts() {
|
||||
void testMultiplePojoRequestParts() {
|
||||
Hello pojo1 = new Hello(HELLO_WORLD_1);
|
||||
Hello pojo2 = new Hello(OI_TERRA_2);
|
||||
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null, "hello".getBytes());
|
||||
String response = this.multipartClient.multipartPojo("abc", "123", pojo1, pojo2, file);
|
||||
String response = multipartClient.multipartPojo("abc", "123", pojo1, pojo2, file);
|
||||
assertThat(response).isEqualTo("abc123hello world 1oi terra 2hello.bin");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestPartWithListOfMultipartFiles() {
|
||||
void testRequestPartWithListOfMultipartFiles() {
|
||||
List<MultipartFile> multipartFiles = Arrays.asList(
|
||||
new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes()),
|
||||
new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes()));
|
||||
String partNames = this.multipartClient.requestPartListOfMultipartFilesReturnsPartNames(multipartFiles);
|
||||
String partNames = multipartClient.requestPartListOfMultipartFilesReturnsPartNames(multipartFiles);
|
||||
assertThat(partNames).isEqualTo("files,files");
|
||||
String fileNames = this.multipartClient.requestPartListOfMultipartFilesReturnsFileNames(multipartFiles);
|
||||
String fileNames = multipartClient.requestPartListOfMultipartFilesReturnsFileNames(multipartFiles);
|
||||
assertThat(fileNames).contains("hello1.bin", "hello2.bin");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestPartWithListOfPojosAndListOfMultipartFiles() {
|
||||
void testRequestPartWithListOfPojosAndListOfMultipartFiles() {
|
||||
Hello pojo1 = new Hello(HELLO_WORLD_1);
|
||||
Hello pojo2 = new Hello(OI_TERRA_2);
|
||||
MockMultipartFile file1 = new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes());
|
||||
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes());
|
||||
String response = this.multipartClient.requestPartListOfPojosAndListOfMultipartFiles(
|
||||
Arrays.asList(pojo1, pojo2), Arrays.asList(file1, file2));
|
||||
String response = multipartClient.requestPartListOfPojosAndListOfMultipartFiles(Arrays.asList(pojo1, pojo2),
|
||||
Arrays.asList(file1, file2));
|
||||
assertThat(response).isEqualTo("hello world 1oi terra 2hello1.binhello2.bin");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestBodyWithSingleMultipartFile() {
|
||||
void testRequestBodyWithSingleMultipartFile() {
|
||||
String partName = UUID.randomUUID().toString();
|
||||
MockMultipartFile file1 = new MockMultipartFile(partName, "hello1.bin", null, "hello".getBytes());
|
||||
String response = this.multipartClient.requestBodySingleMultipartFile(file1);
|
||||
String response = multipartClient.requestBodySingleMultipartFile(file1);
|
||||
assertThat(response).isEqualTo(partName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestBodyWithListOfMultipartFiles() {
|
||||
void testRequestBodyWithListOfMultipartFiles() {
|
||||
MockMultipartFile file1 = new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes());
|
||||
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes());
|
||||
String response = this.multipartClient.requestBodyListOfMultipartFiles(Arrays.asList(file1, file2));
|
||||
String response = multipartClient.requestBodyListOfMultipartFiles(Arrays.asList(file1, file2));
|
||||
assertThat(response).contains("file1", "file2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestBodyWithMap() {
|
||||
void testRequestBodyWithMap() {
|
||||
MockMultipartFile file1 = new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes());
|
||||
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes());
|
||||
Map<String, Object> form = new HashMap<>();
|
||||
form.put("file1", file1);
|
||||
form.put("file2", file2);
|
||||
form.put("hello", "world");
|
||||
String response = this.multipartClient.requestBodyMap(form);
|
||||
String response = multipartClient.requestBodyMap(form);
|
||||
assertThat(response).contains("file1", "file2", "hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidMultipartFile() {
|
||||
MockMultipartFile file = new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes());
|
||||
expected.expect(instanceOf(EncodeException.class));
|
||||
this.multipartClient.invalid(file);
|
||||
void testInvalidMultipartFile() {
|
||||
assertThatExceptionOfType(EncodeException.class).isThrownBy(() -> {
|
||||
MockMultipartFile file = new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes());
|
||||
multipartClient.invalid(file);
|
||||
});
|
||||
}
|
||||
|
||||
protected enum Arg {
|
||||
@@ -525,7 +516,7 @@ public class ValidFeignClientTests {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.value;
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -765,15 +756,15 @@ public class ValidFeignClientTests {
|
||||
|
||||
private String message;
|
||||
|
||||
public Hello() {
|
||||
Hello() {
|
||||
}
|
||||
|
||||
public Hello(String message) {
|
||||
Hello(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return this.message;
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
@@ -789,12 +780,12 @@ public class ValidFeignClientTests {
|
||||
return false;
|
||||
}
|
||||
Hello that = (Hello) o;
|
||||
return Objects.equals(this.message, that.message);
|
||||
return Objects.equals(message, that.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.message);
|
||||
return Objects.hash(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user