/* * * Copyright 2013 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.netflix.niws.client.http; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.net.URI; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; import com.google.common.collect.Lists; import com.netflix.client.ClientException; import com.netflix.client.ClientFactory; import com.netflix.client.config.CommonClientConfigKey; import com.netflix.client.config.DefaultClientConfigImpl; import com.netflix.client.http.HttpRequest; import com.netflix.client.http.HttpRequest.Verb; import com.netflix.client.http.HttpResponse; import com.netflix.client.testutil.MockHttpServer; import com.netflix.config.ConfigurationManager; import com.netflix.http4.MonitoredConnectionManager; import com.netflix.http4.NFHttpClient; import com.netflix.http4.NFHttpClientFactory; import com.netflix.loadbalancer.AvailabilityFilteringRule; import com.netflix.loadbalancer.BaseLoadBalancer; import com.netflix.loadbalancer.DummyPing; import com.netflix.loadbalancer.Server; import com.netflix.loadbalancer.ServerStats; public class RetryTest { @ClassRule public static MockHttpServer server = new MockHttpServer() ; private RestClient client; private BaseLoadBalancer lb; private NFHttpClient httpClient; private MonitoredConnectionManager connectionPoolManager; private static Server localServer; @BeforeClass public static void init() throws Exception { // PackagesResourceConfig resourceConfig = new PackagesResourceConfig("com.netflix.niws.client.http"); localServer = new Server("localhost", server.getServerPort()); } @Before public void beforeTest() { ConfigurationManager.getConfigInstance().setProperty("RetryTest.ribbon.NFLoadBalancerClassName", BaseLoadBalancer.class.getName()); ConfigurationManager.getConfigInstance().setProperty("RetryTest.ribbon.client.NFLoadBalancerPingClassName", DummyPing.class.getName()); ConfigurationManager.getConfigInstance().setProperty("RetryTest.ribbon.ReadTimeout", "1000"); ConfigurationManager.getConfigInstance().setProperty("RetryTest.ribbon." + CommonClientConfigKey.ConnectTimeout, "500"); ConfigurationManager.getConfigInstance().setProperty("RetryTest.ribbon." + CommonClientConfigKey.OkToRetryOnAllOperations, "true"); client = (RestClient) ClientFactory.getNamedClient("RetryTest"); lb = (BaseLoadBalancer) client.getLoadBalancer(); lb.setServersList(Lists.newArrayList(localServer)); httpClient = NFHttpClientFactory.getNamedNFHttpClient("RetryTest"); connectionPoolManager = (MonitoredConnectionManager) httpClient.getConnectionManager(); client.setMaxAutoRetries(0); client.setMaxAutoRetriesNextServer(0); client.setOkToRetryOnAllOperations(false); lb.setServersList(Lists.newArrayList(localServer)); // reset the server index lb.setRule(new AvailabilityFilteringRule()); lb.getLoadBalancerStats().getSingleServerStat(localServer).clearSuccessiveConnectionFailureCount(); } @Test public void testThrottled() throws Exception { URI localUrl = new URI("/status?code=503"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 0)); fail("Exception expected"); } catch (ClientException e) { assertNotNull(e); } assertEquals(1, lb.getLoadBalancerStats().getSingleServerStat(localServer).getSuccessiveConnectionFailureCount()); } @Test public void testThrottledWithRetrySameServer() throws Exception { URI localUrl = new URI("/status?code=503"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl .getEmptyConfig() .set(CommonClientConfigKey.MaxAutoRetries, 1) .set(CommonClientConfigKey.MaxAutoRetriesNextServer, 0)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } assertEquals(2, lb.getLoadBalancerStats().getSingleServerStat(localServer).getSuccessiveConnectionFailureCount()); } @Test public void testThrottledWithRetryNextServer() throws Exception { int connectionCount = connectionPoolManager.getConnectionsInPool(); URI localUrl = new URI("/status?code=503"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } assertEquals(3, lb.getLoadBalancerStats().getSingleServerStat(localServer).getSuccessiveConnectionFailureCount()); System.out.println("Initial connections count " + connectionCount); System.out.println("Final connections count " + connectionPoolManager.getConnectionsInPool()); // should be no connection leak assertTrue(connectionPoolManager.getConnectionsInPool() <= connectionCount + 1); } @Test public void testReadTimeout() throws Exception { URI localUrl = new URI("/noresponse"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } assertEquals(3, lb.getLoadBalancerStats().getSingleServerStat(localServer).getSuccessiveConnectionFailureCount()); } @Test public void testReadTimeoutWithRetriesNextServe() throws Exception { URI localUrl = new URI("/noresponse"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } assertEquals(3, lb.getLoadBalancerStats().getSingleServerStat(localServer).getSuccessiveConnectionFailureCount()); } @Test public void postReadTimeout() throws Exception { URI localUrl = new URI("/noresponse"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).verb(Verb.POST).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } ServerStats stats = lb.getLoadBalancerStats().getSingleServerStat(localServer); assertEquals(1, stats.getSuccessiveConnectionFailureCount()); } @Test public void testRetriesOnPost() throws Exception { URI localUrl = new URI("/noresponse"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).verb(Verb.POST).setRetriable(true).build(); try { client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } ServerStats stats = lb.getLoadBalancerStats().getSingleServerStat(localServer); assertEquals(3, stats.getSuccessiveConnectionFailureCount()); } @Test public void testRetriesOnPostWithConnectException() throws Exception { URI localUrl = new URI("/status?code=503"); lb.setServersList(Lists.newArrayList(localServer)); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).verb(Verb.POST).setRetriable(true).build(); try { HttpResponse response = client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); fail("Exception expected"); } catch (ClientException e) { // NOPMD } ServerStats stats = lb.getLoadBalancerStats().getSingleServerStat(localServer); assertEquals(3, stats.getSuccessiveConnectionFailureCount()); } @Test public void testSuccessfulRetries() throws Exception { lb.setServersList(Lists.newArrayList(new Server("localhost:12987"), new Server("localhost:12987"), localServer)); URI localUrl = new URI("/ok"); HttpRequest request = HttpRequest.newBuilder().uri(localUrl).queryParams("name", "ribbon").build(); try { HttpResponse response = client.executeWithLoadBalancer(request, DefaultClientConfigImpl.getEmptyConfig().set(CommonClientConfigKey.MaxAutoRetriesNextServer, 2)); assertEquals(200, response.getStatus()); } catch (ClientException e) { fail("Unexpected exception"); } ServerStats stats = lb.getLoadBalancerStats().getSingleServerStat(new Server("localhost:12987")); assertEquals(1, stats.getSuccessiveConnectionFailureCount()); } }