package org.springframework.cloud.client.loadbalancer;
import lombok.SneakyThrows;
import org.hamcrest.MatcherAssert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.client.AsyncClientHttpRequestInterceptor;
import org.springframework.web.client.AsyncRestTemplate;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.empty;
/**
* @author Rob Worsnop
*/
public class AsyncLoadBalancerAutoConfigurationTests {
@Test
public void restTemplateGetsLoadBalancerInterceptor() {
ConfigurableApplicationContext context = init(OneRestTemplate.class);
final Map<String, AsyncRestTemplate> restTemplates = context
.getBeansOfType(AsyncRestTemplate.class);
MatcherAssert.assertThat(restTemplates, is(notNullValue()));
MatcherAssert.assertThat(restTemplates.values(), hasSize(1));
AsyncRestTemplate restTemplate = restTemplates.values().iterator().next();
MatcherAssert.assertThat(restTemplate, is(notNullValue()));
assertLoadBalanced(restTemplate);
}
private void assertLoadBalanced(AsyncRestTemplate restTemplate) {
List<AsyncClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
MatcherAssert.assertThat(interceptors, hasSize(1));
AsyncClientHttpRequestInterceptor interceptor = interceptors.get(0);
MatcherAssert.assertThat(interceptor, is(instanceOf(AsyncLoadBalancerInterceptor.class)));
}
@Test
public void multipleRestTemplates() {
ConfigurableApplicationContext context = init(TwoRestTemplates.class);
final Map<String, AsyncRestTemplate> restTemplates = context
.getBeansOfType(AsyncRestTemplate.class);
MatcherAssert.assertThat(restTemplates, is(notNullValue()));
Collection<AsyncRestTemplate> templates = restTemplates.values();
MatcherAssert.assertThat(templates, hasSize(2));
TwoRestTemplates.Two two = context.getBean(TwoRestTemplates.Two.class);
MatcherAssert.assertThat(two.loadBalanced, is(notNullValue()));
assertLoadBalanced(two.loadBalanced);
MatcherAssert.assertThat(two.nonLoadBalanced, is(notNullValue()));
MatcherAssert.assertThat(two.nonLoadBalanced.getInterceptors(), is(empty()));
}
protected ConfigurableApplicationContext init(Class<?> config) {
return new SpringApplicationBuilder().web(false)
.properties("spring.aop.proxyTargetClass=true")
.sources(config, AsyncLoadBalancerAutoConfiguration.class).run();
}
@Configuration
protected static class OneRestTemplate {
@LoadBalanced
@Bean
AsyncRestTemplate loadBalancedRestTemplate() {
return new AsyncRestTemplate();
}
@Bean
LoadBalancerClient loadBalancerClient() {
return new NoopLoadBalancerClient();
}
@Bean
LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() { return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();}
}
@Configuration
protected static class TwoRestTemplates {
@Primary
@Bean
AsyncRestTemplate restTemplate() {
return new AsyncRestTemplate();
}
@LoadBalanced
@Bean
AsyncRestTemplate loadBalancedRestTemplate() {
return new AsyncRestTemplate();
}
@Bean
LoadBalancerClient loadBalancerClient() {
return new NoopLoadBalancerClient();
}
@Configuration
protected static class Two {
@Autowired
AsyncRestTemplate nonLoadBalanced;
@Autowired
@LoadBalanced
AsyncRestTemplate loadBalanced;
}
}
private static class NoopLoadBalancerClient implements LoadBalancerClient {
private final Random random = new Random();
@Override
public ServiceInstance choose(String serviceId) {
return new DefaultServiceInstance(serviceId, serviceId,
this.random.nextInt(40000), false);
}
@Override
@SneakyThrows
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) {
return request.apply(choose(serviceId));
}
@Override
@SneakyThrows
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
return request.apply(choose(serviceId));
}
@Override
public URI reconstructURI(ServiceInstance instance, URI original) {
return DefaultServiceInstance.getUri(instance);
}
}
}