Commit f76f294f by Dave Syer

Rename test to conform to usual pattern

parent 64fff7ed
package org.springframework.cloud.netflix.resttemplate; package org.springframework.cloud.netflix.resttemplate;
import static org.junit.Assert.assertEquals; import java.net.UnknownHostException;
import static org.junit.Assert.assertTrue; import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.net.UnknownHostException;
import java.util.Arrays; import org.apache.commons.logging.Log;
import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.apache.commons.logging.Log; import org.junit.Test;
import org.apache.commons.logging.LogFactory; import org.junit.runner.RunWith;
import org.junit.Before; import org.springframework.beans.factory.annotation.Autowired;
import org.junit.Test; import org.springframework.beans.factory.annotation.Value;
import org.junit.runner.RunWith; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.context.annotation.Bean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.client.RestTemplate;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import com.netflix.client.RetryHandler;
import org.springframework.web.client.RestTemplate; import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AvailabilityFilteringRule;
import com.netflix.client.RetryHandler; import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.AvailabilityFilteringRule; import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.LoadBalancerBuilder;
import com.netflix.loadbalancer.IPing; import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.LoadBalancerBuilder; import com.netflix.loadbalancer.ServerList;
import com.netflix.loadbalancer.LoadBalancerStats; import com.netflix.loadbalancer.ServerStats;
import com.netflix.loadbalancer.Server; import com.netflix.niws.client.http.HttpClientLoadBalancerErrorHandler;
import com.netflix.loadbalancer.ServerList;
import com.netflix.loadbalancer.ServerStats; import static org.junit.Assert.assertEquals;
import com.netflix.niws.client.http.HttpClientLoadBalancerErrorHandler; import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = RestTemplateRetryTest.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = { @SpringBootTest(classes = RestTemplateRetryTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.application.name=resttemplatetest", "spring.application.name=resttemplatetest",
"logging.level.org.springframework.cloud.netflix.resttemplate=DEBUG", "logging.level.org.springframework.cloud.netflix.resttemplate=DEBUG",
"badClients.ribbon.MaxAutoRetries=0", "badClients.ribbon.MaxAutoRetries=0",
"badClients.ribbon.OkToRetryOnAllOperations=true", "ribbon.http.client.enabled" }) "badClients.ribbon.OkToRetryOnAllOperations=true", "ribbon.http.client.enabled" })
@DirtiesContext @DirtiesContext
public class RestTemplateRetryTest { public class RestTemplateRetryTests {
final private static Log logger = LogFactory.getLog(RestTemplateRetryTest.class); final private static Log logger = LogFactory.getLog(RestTemplateRetryTests.class);
@Value("${local.server.port}") @Value("${local.server.port}")
private int port = 0; private int port = 0;
@Autowired @Autowired
private RestTemplate testClient; private RestTemplate testClient;
public RestTemplateRetryTest() { public RestTemplateRetryTests() {
} }
@Configuration @Before
@EnableAutoConfiguration public void setup() throws Exception {
@RestController // Force Ribbon configuration by making one call.
@RibbonClient(name = "badClients", configuration = LocalBadClientConfiguration.class) this.testClient.getForObject("http://badClients/ping", Integer.class);
public static class Application { }
private AtomicInteger hits = new AtomicInteger(1); @Test
private AtomicInteger retryHits = new AtomicInteger(1); public void testNullPointer() throws Exception {
@RequestMapping(method = RequestMethod.GET, value = "/ping") LoadBalancerStats stats = LocalBadClientConfiguration.balancer
public int ping() { .getLoadBalancerStats();
return 0; ServerStats badServer1Stats = stats
} .getSingleServerStat(LocalBadClientConfiguration.badServer);
ServerStats badServer2Stats = stats
@RequestMapping(method = RequestMethod.GET, value = "/good") .getSingleServerStat(LocalBadClientConfiguration.badServer2);
public int good() { ServerStats goodServerStats = stats
int lValue = this.hits.getAndIncrement(); .getSingleServerStat(LocalBadClientConfiguration.goodServer);
return lValue;
} badServer1Stats.clearSuccessiveConnectionFailureCount();
badServer2Stats.clearSuccessiveConnectionFailureCount();
@RequestMapping(method = RequestMethod.GET, value = "/timeout") long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 10;
public int timeout() throws Exception {
int lValue = this.retryHits.getAndIncrement(); // A null pointer should NOT trigger a circuit breaker.
for (int index = 0; index < 10; index++) {
// Force the good server to have 2 consecutive errors a couple of times. try {
if (lValue == 2 || lValue == 3 || lValue == 5 || lValue == 6) { this.testClient.getForObject("http://badClients/null", Integer.class);
Thread.sleep(500); }
} catch (Exception exception) {
return lValue; }
} }
logServerStats(LocalBadClientConfiguration.badServer);
@RequestMapping(method = RequestMethod.GET, value = "/null") logServerStats(LocalBadClientConfiguration.badServer2);
public int isNull() throws Exception { logServerStats(LocalBadClientConfiguration.goodServer);
throw new NullPointerException("Null");
} assertTrue(badServer1Stats.isCircuitBreakerTripped());
assertTrue(badServer2Stats.isCircuitBreakerTripped());
@LoadBalanced assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
@Bean
RestTemplate restTemplate() { // Wait for any timeout thread to finish.
return new RestTemplate();
} }
}
private void logServerStats(Server server) {
@Before LoadBalancerStats stats = LocalBadClientConfiguration.balancer
public void setup() throws Exception { .getLoadBalancerStats();
// Force Ribbon configuration by making one call. ServerStats serverStats = stats.getSingleServerStat(server);
this.testClient.getForObject("http://badClients/ping", Integer.class); logger.debug("Server : " + server.toString() + " : Total Count == "
} + serverStats.getTotalRequestsCount() + ", Failure Count == "
+ serverStats.getFailureCount() + ", Successive Connection Failure == "
@Test + serverStats.getSuccessiveConnectionFailureCount()
public void testNullPointer() throws Exception { + ", Circuit Breaker ? == " + serverStats.isCircuitBreakerTripped());
}
LoadBalancerStats stats = LocalBadClientConfiguration.balancer
.getLoadBalancerStats(); @Test
ServerStats badServer1Stats = stats public void testRestRetries() {
.getSingleServerStat(LocalBadClientConfiguration.badServer);
ServerStats badServer2Stats = stats LoadBalancerStats stats = LocalBadClientConfiguration.balancer
.getSingleServerStat(LocalBadClientConfiguration.badServer2); .getLoadBalancerStats();
ServerStats goodServerStats = stats ServerStats badServer1Stats = stats
.getSingleServerStat(LocalBadClientConfiguration.goodServer); .getSingleServerStat(LocalBadClientConfiguration.badServer);
ServerStats badServer2Stats = stats
badServer1Stats.clearSuccessiveConnectionFailureCount(); .getSingleServerStat(LocalBadClientConfiguration.badServer2);
badServer2Stats.clearSuccessiveConnectionFailureCount(); ServerStats goodServerStats = stats
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 10; .getSingleServerStat(LocalBadClientConfiguration.goodServer);
// A null pointer should NOT trigger a circuit breaker. badServer1Stats.clearSuccessiveConnectionFailureCount();
for (int index = 0; index < 10; index++) { badServer2Stats.clearSuccessiveConnectionFailureCount();
try { long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 20;
this.testClient.getForObject("http://badClients/null", Integer.class);
} int hits = 0;
catch (Exception exception) {
} for (int index = 0; index < 20; index++) {
} hits = this.testClient.getForObject("http://badClients/good", Integer.class);
logServerStats(LocalBadClientConfiguration.badServer); }
logServerStats(LocalBadClientConfiguration.badServer2);
logServerStats(LocalBadClientConfiguration.goodServer); logServerStats(LocalBadClientConfiguration.badServer);
logServerStats(LocalBadClientConfiguration.badServer2);
assertTrue(badServer1Stats.isCircuitBreakerTripped()); logServerStats(LocalBadClientConfiguration.goodServer);
assertTrue(badServer2Stats.isCircuitBreakerTripped());
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount()); assertTrue(badServer1Stats.isCircuitBreakerTripped());
assertTrue(badServer2Stats.isCircuitBreakerTripped());
// Wait for any timeout thread to finish. assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
assertEquals(20, hits);
} logger.debug("Retry Hits: " + hits);
}
private void logServerStats(Server server) {
LoadBalancerStats stats = LocalBadClientConfiguration.balancer @Test
.getLoadBalancerStats(); public void testRestRetriesWithReadTimeout() throws Exception {
ServerStats serverStats = stats.getSingleServerStat(server);
logger.debug("Server : " + server.toString() + " : Total Count == " LoadBalancerStats stats = LocalBadClientConfiguration.balancer
+ serverStats.getTotalRequestsCount() + ", Failure Count == " .getLoadBalancerStats();
+ serverStats.getFailureCount() + ", Successive Connection Failure == " ServerStats badServer1Stats = stats
+ serverStats.getSuccessiveConnectionFailureCount() .getSingleServerStat(LocalBadClientConfiguration.badServer);
+ ", Circuit Breaker ? == " + serverStats.isCircuitBreakerTripped()); ServerStats badServer2Stats = stats
} .getSingleServerStat(LocalBadClientConfiguration.badServer2);
ServerStats goodServerStats = stats
@Test .getSingleServerStat(LocalBadClientConfiguration.goodServer);
public void testRestRetries() {
badServer1Stats.clearSuccessiveConnectionFailureCount();
LoadBalancerStats stats = LocalBadClientConfiguration.balancer badServer2Stats.clearSuccessiveConnectionFailureCount();
.getLoadBalancerStats(); assertTrue(!badServer1Stats.isCircuitBreakerTripped());
ServerStats badServer1Stats = stats assertTrue(!badServer2Stats.isCircuitBreakerTripped());
.getSingleServerStat(LocalBadClientConfiguration.badServer);
ServerStats badServer2Stats = stats int hits = 0;
.getSingleServerStat(LocalBadClientConfiguration.badServer2);
ServerStats goodServerStats = stats for (int index = 0; index < 15; index++) {
.getSingleServerStat(LocalBadClientConfiguration.goodServer); hits = this.testClient.getForObject("http://badClients/timeout",
Integer.class);
badServer1Stats.clearSuccessiveConnectionFailureCount(); }
badServer2Stats.clearSuccessiveConnectionFailureCount(); logServerStats(LocalBadClientConfiguration.badServer);
long targetConnectionCount = goodServerStats.getTotalRequestsCount() + 20; logServerStats(LocalBadClientConfiguration.badServer2);
logServerStats(LocalBadClientConfiguration.goodServer);
int hits = 0;
assertTrue(badServer1Stats.isCircuitBreakerTripped());
for (int index = 0; index < 20; index++) { assertTrue(badServer2Stats.isCircuitBreakerTripped());
hits = this.testClient.getForObject("http://badClients/good", Integer.class); assertTrue(!goodServerStats.isCircuitBreakerTripped());
}
// 15 + 4 timeouts. See the endpoint for timeout conditions.
logServerStats(LocalBadClientConfiguration.badServer); assertEquals(19, hits);
logServerStats(LocalBadClientConfiguration.badServer2);
logServerStats(LocalBadClientConfiguration.goodServer); // Wait for any timeout thread to finish.
Thread.sleep(600);
assertTrue(badServer1Stats.isCircuitBreakerTripped());
assertTrue(badServer2Stats.isCircuitBreakerTripped()); }
assertEquals(targetConnectionCount, goodServerStats.getTotalRequestsCount());
assertEquals(20, hits); @Configuration
System.out.println("Retry Hits: " + hits); @EnableAutoConfiguration
} @RestController
@RibbonClient(name = "badClients", configuration = LocalBadClientConfiguration.class)
@Test public static class Application {
public void testRestRetriesWithReadTimeout() throws Exception {
private AtomicInteger hits = new AtomicInteger(1);
LoadBalancerStats stats = LocalBadClientConfiguration.balancer private AtomicInteger retryHits = new AtomicInteger(1);
.getLoadBalancerStats();
ServerStats badServer1Stats = stats @RequestMapping(method = RequestMethod.GET, value = "/ping")
.getSingleServerStat(LocalBadClientConfiguration.badServer); public int ping() {
ServerStats badServer2Stats = stats return 0;
.getSingleServerStat(LocalBadClientConfiguration.badServer2); }
ServerStats goodServerStats = stats
.getSingleServerStat(LocalBadClientConfiguration.goodServer); @RequestMapping(method = RequestMethod.GET, value = "/good")
public int good() {
badServer1Stats.clearSuccessiveConnectionFailureCount(); int lValue = this.hits.getAndIncrement();
badServer2Stats.clearSuccessiveConnectionFailureCount(); return lValue;
assertTrue(!badServer1Stats.isCircuitBreakerTripped()); }
assertTrue(!badServer2Stats.isCircuitBreakerTripped());
@RequestMapping(method = RequestMethod.GET, value = "/timeout")
int hits = 0; public int timeout() throws Exception {
int lValue = this.retryHits.getAndIncrement();
for (int index = 0; index < 15; index++) {
hits = this.testClient.getForObject("http://badClients/timeout", // Force the good server to have 2 consecutive errors a couple of times.
Integer.class); if (lValue == 2 || lValue == 3 || lValue == 5 || lValue == 6) {
} Thread.sleep(500);
logServerStats(LocalBadClientConfiguration.badServer); }
logServerStats(LocalBadClientConfiguration.badServer2); return lValue;
logServerStats(LocalBadClientConfiguration.goodServer); }
assertTrue(badServer1Stats.isCircuitBreakerTripped()); @RequestMapping(method = RequestMethod.GET, value = "/null")
assertTrue(badServer2Stats.isCircuitBreakerTripped()); public int isNull() throws Exception {
assertTrue(!goodServerStats.isCircuitBreakerTripped()); throw new NullPointerException("Null");
}
// 15 + 4 timeouts. See the endpoint for timeout conditions.
assertEquals(19, hits); @LoadBalanced
@Bean
// Wait for any timeout thread to finish. RestTemplate restTemplate() {
Thread.sleep(600); return new RestTemplate();
}
} }
} }
// Load balancer with fixed server list for "local" pointing to localhost // Load balancer with fixed server list for "local" pointing to localhost
// and some bogus servers are thrown in to test retry // and some bogus servers are thrown in to test retry
@Configuration @Configuration
class LocalBadClientConfiguration { class LocalBadClientConfiguration {
static BaseLoadBalancer balancer; static BaseLoadBalancer balancer;
static Server goodServer; static Server goodServer;
static Server badServer; static Server badServer;
static Server badServer2; static Server badServer2;
public LocalBadClientConfiguration() { public LocalBadClientConfiguration() {
} }
@Value("${local.server.port}") @Value("${local.server.port}")
private int port = 0; private int port = 0;
@Bean @Bean
public IRule loadBalancerRule() { public IRule loadBalancerRule() {
// This is a good place to try different load balancing rules and how those rules // This is a good place to try different load balancing rules and how those rules
// behave in failure // behave in failure states: BestAvailableRule, WeightedResponseTimeRule, etc
// states: BestAvailableRule, WeightedResponseTimeRule, etc
// This rule just uses a round robin and will skip servers that are in circuit
// This rule just uses a round robin and will skip servers that are in circuit // breaker state.
// breaker state. return new AvailabilityFilteringRule();
return new AvailabilityFilteringRule();
}
}
@Bean
@Bean public ILoadBalancer ribbonLoadBalancer(IClientConfig config,
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, IRule rule, IPing ping) {
ServerList<Server> serverList, IRule rule, IPing ping) {
goodServer = new Server("localhost", this.port);
goodServer = new Server("localhost", this.port); badServer = new Server("mybadhost", 10001);
badServer = new Server("mybadhost", 10001); badServer2 = new Server("localhost", -1);
badServer2 = new Server("localhost", -1);
balancer = LoadBalancerBuilder.newBuilder().withClientConfig(config)
balancer = LoadBalancerBuilder.newBuilder().withClientConfig(config) .withRule(rule).withPing(ping).buildFixedServerListLoadBalancer(
.withRule(rule).withPing(ping).buildFixedServerListLoadBalancer( Arrays.asList(badServer, badServer2, goodServer));
Arrays.asList(badServer, badServer2, goodServer)); return balancer;
return balancer; }
}
@Bean
@Bean public RetryHandler retryHandler() {
public RetryHandler retryHandler() { return new OverrideRetryHandler();
return new OverrideRetryHandler(); }
}
static class OverrideRetryHandler extends HttpClientLoadBalancerErrorHandler {
static class OverrideRetryHandler extends HttpClientLoadBalancerErrorHandler { public OverrideRetryHandler() {
public OverrideRetryHandler() { this.circuitRelated.add(UnknownHostException.class);
this.circuitRelated.add(UnknownHostException.class); this.retriable.add(UnknownHostException.class);
this.retriable.add(UnknownHostException.class); }
}
}
} }
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment