You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by mi...@apache.org on 2019/12/10 19:11:59 UTC

[httpcomponents-client] branch HTTPCLIENT-2019 created (now 91cef76)

This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a change to branch HTTPCLIENT-2019
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git.


      at 91cef76  HTTPCLIENT-2019: Remove ServiceUnavailableRetryStrategy in favor of HttpRequestRetryStrategy

This branch includes the following new commits:

     new 91cef76  HTTPCLIENT-2019: Remove ServiceUnavailableRetryStrategy in favor of HttpRequestRetryStrategy

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[httpcomponents-client] 01/01: HTTPCLIENT-2019: Remove ServiceUnavailableRetryStrategy in favor of HttpRequestRetryStrategy

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch HTTPCLIENT-2019
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 91cef76bfbef354d9459f5b4abfdfa5fb69ab4bf
Author: Michael Osipov <mi...@apache.org>
AuthorDate: Tue Dec 10 20:11:34 2019 +0100

    HTTPCLIENT-2019: Remove ServiceUnavailableRetryStrategy in favor of HttpRequestRetryStrategy
---
 .../http/ServiceUnavailableRetryStrategy.java      |  63 ---------
 .../apache/hc/client5/http/impl/ChainElement.java  |   2 +-
 .../DefaultServiceUnavailableRetryStrategy.java    | 100 --------------
 .../http/impl/classic/HttpClientBuilder.java       |  19 ---
 .../impl/classic/ServiceUnavailableRetryExec.java  | 117 ----------------
 ...TestDefaultServiceUnavailableRetryStrategy.java |  98 --------------
 .../classic/TestServiceUnavailableRetryExec.java   | 148 ---------------------
 7 files changed, 1 insertion(+), 546 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/ServiceUnavailableRetryStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/ServiceUnavailableRetryStrategy.java
deleted file mode 100644
index 9575330..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/ServiceUnavailableRetryStrategy.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.hc.client5.http;
-
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.protocol.HttpContext;
-
-/**
- * Strategy interface that allows API users to plug in their own logic to
- * control whether or not a retry should automatically be done, how many times
- * it should be retried and so on.
- *
- * @since 4.2
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-public interface ServiceUnavailableRetryStrategy {
-
-    /**
-     * Determines if a method should be retried given the response from the target server.
-     *
-     * @param response the response from the target server
-     * @param executionCount the number of times this method has been
-     * unsuccessfully executed
-     * @param context the context for the request execution
-
-     * @return {@code true} if the method should be retried, {@code false}
-     * otherwise
-     */
-    boolean retryRequest(HttpResponse response, int executionCount, HttpContext context);
-
-    /**
-     * @return The interval between the subsequent retry in milliseconds.
-     */
-    long getRetryInterval(HttpResponse response, HttpContext context);
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
index 3c9b9fb..43c8dfb 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/ChainElement.java
@@ -34,7 +34,7 @@ package org.apache.hc.client5.http.impl;
  */
 public enum ChainElement {
 
-    REDIRECT, BACK_OFF, RETRY, RETRY_SERVICE_UNAVAILABLE, RETRY_IO_ERROR, CACHING, PROTOCOL,
+    REDIRECT, BACK_OFF, RETRY, RETRY_IO_ERROR, CACHING, PROTOCOL,
     CONNECT, MAIN_TRANSPORT
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultServiceUnavailableRetryStrategy.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultServiceUnavailableRetryStrategy.java
deleted file mode 100644
index 6c05c60..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultServiceUnavailableRetryStrategy.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.hc.client5.http.impl;
-
-import java.util.Date;
-
-import org.apache.hc.client5.http.ServiceUnavailableRetryStrategy;
-import org.apache.hc.client5.http.utils.DateUtils;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.Header;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.util.Args;
-
-/**
- * Default implementation of the {@link ServiceUnavailableRetryStrategy} interface.
- * that retries {@code 503} (Service Unavailable) responses for a fixed number of times
- * at a fixed interval.
- *
- * @since 4.2
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-public class DefaultServiceUnavailableRetryStrategy implements ServiceUnavailableRetryStrategy {
-
-    /**
-     * Maximum number of allowed retries if the server responds with a HTTP code
-     * in our retry code list. Default value is 1.
-     */
-    private final int maxRetries;
-
-    /**
-     * Retry interval between subsequent requests, in milliseconds. Default
-     * value is 1 second.
-     */
-    private final long defaultRetryInterval;
-
-    public DefaultServiceUnavailableRetryStrategy(final int maxRetries, final int defaultRetryInterval) {
-        super();
-        Args.positive(maxRetries, "Max retries");
-        Args.positive(defaultRetryInterval, "Retry interval");
-        this.maxRetries = maxRetries;
-        this.defaultRetryInterval = defaultRetryInterval;
-    }
-
-    public DefaultServiceUnavailableRetryStrategy() {
-        this(1, 1000);
-    }
-
-    @Override
-    public boolean retryRequest(final HttpResponse response, final int executionCount, final HttpContext context) {
-        return executionCount <= maxRetries && response.getCode() == HttpStatus.SC_SERVICE_UNAVAILABLE;
-    }
-
-    @Override
-    public long getRetryInterval(final HttpResponse response, final HttpContext context) {
-        final Header header = response.getFirstHeader(HttpHeaders.RETRY_AFTER);
-        if (header != null) {
-            final String value = header.getValue();
-            try {
-                return Long.parseLong(value) * 1000;
-            } catch (final NumberFormatException ignore) {
-                final Date date = DateUtils.parseDate(value);
-                if (date != null) {
-                    final long n = date.getTime() - System.currentTimeMillis();
-                    return n > 0 ? n : 0;
-                }
-            }
-        }
-        return this.defaultRetryInterval;
-    }
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
index ddb3199..c0c4a9c 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
@@ -42,7 +42,6 @@ import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
 import org.apache.hc.client5.http.HttpRequestRetryHandler;
 import org.apache.hc.client5.http.HttpRequestRetryStrategy;
 import org.apache.hc.client5.http.SchemePortResolver;
-import org.apache.hc.client5.http.ServiceUnavailableRetryStrategy;
 import org.apache.hc.client5.http.SystemDefaultDnsResolver;
 import org.apache.hc.client5.http.UserTokenHandler;
 import org.apache.hc.client5.http.auth.AuthSchemeProvider;
@@ -210,7 +209,6 @@ public class HttpClientBuilder {
     private RedirectStrategy redirectStrategy;
     private ConnectionBackoffStrategy connectionBackoffStrategy;
     private BackoffManager backoffManager;
-    private ServiceUnavailableRetryStrategy serviceUnavailStrategy;
     private Lookup<AuthSchemeProvider> authSchemeRegistry;
     private Lookup<CookieSpecProvider> cookieSpecRegistry;
     private LinkedHashMap<String, InputStreamFactory> contentDecoderMap;
@@ -583,15 +581,6 @@ public class HttpClientBuilder {
     }
 
     /**
-     * Assigns {@link ServiceUnavailableRetryStrategy} instance.
-     */
-    public final HttpClientBuilder setServiceUnavailableRetryStrategy(
-            final ServiceUnavailableRetryStrategy serviceUnavailStrategy) {
-        this.serviceUnavailStrategy = serviceUnavailStrategy;
-        return this;
-    }
-
-    /**
      * Assigns default {@link CookieStore} instance which will be used for
      * request execution if not explicitly set in the client execution context.
      */
@@ -905,14 +894,6 @@ public class HttpClientBuilder {
             }
         }
 
-        // Optionally, add service unavailable retry executor
-        final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = this.serviceUnavailStrategy;
-        if (serviceUnavailStrategyCopy != null) {
-            execChainDefinition.addFirst(
-                    new ServiceUnavailableRetryExec(serviceUnavailStrategyCopy),
-                    ChainElement.RETRY_SERVICE_UNAVAILABLE.name());
-        }
-
         // Add redirect executor, if not disabled
         if (!redirectHandlingDisabled) {
             RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ServiceUnavailableRetryExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ServiceUnavailableRetryExec.java
deleted file mode 100644
index c0c3dd3..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ServiceUnavailableRetryExec.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.hc.client5.http.impl.classic;
-
-import java.io.IOException;
-import java.io.InterruptedIOException;
-
-import org.apache.hc.client5.http.ServiceUnavailableRetryStrategy;
-import org.apache.hc.client5.http.classic.ExecChain;
-import org.apache.hc.client5.http.classic.ExecChainHandler;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.Internal;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.HttpEntity;
-import org.apache.hc.core5.http.HttpException;
-import org.apache.hc.core5.util.Args;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Request executor in the request execution chain that is responsible
- * for making a decision whether a request that received a non-2xx response
- * from the target server should be re-executed.
- * <p>
- * Further responsibilities such as communication with the opposite
- * endpoint is delegated to the next executor in the request execution
- * chain.
- * </p>
- *
- * @since 4.3
- */
-@Contract(threading = ThreadingBehavior.STATELESS)
-@Internal
-public final class ServiceUnavailableRetryExec implements ExecChainHandler {
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    private final ServiceUnavailableRetryStrategy retryStrategy;
-
-    public ServiceUnavailableRetryExec(
-            final ServiceUnavailableRetryStrategy retryStrategy) {
-        super();
-        Args.notNull(retryStrategy, "Retry strategy");
-        this.retryStrategy = retryStrategy;
-    }
-
-    @Override
-    public ClassicHttpResponse execute(
-            final ClassicHttpRequest request,
-            final ExecChain.Scope scope,
-            final ExecChain chain) throws IOException, HttpException {
-        Args.notNull(request, "HTTP request");
-        Args.notNull(scope, "Scope");
-        final String exchangeId = scope.exchangeId;
-        final HttpClientContext context = scope.clientContext;
-        ClassicHttpRequest currentRequest = request;
-        for (int c = 1;; c++) {
-            final ClassicHttpResponse response = chain.proceed(currentRequest, scope);
-            try {
-                final HttpEntity entity = request.getEntity();
-                if (entity != null && !entity.isRepeatable()) {
-                    return response;
-                }
-                if (this.retryStrategy.retryRequest(response, c, context)) {
-                    response.close();
-                    final long nextInterval = this.retryStrategy.getRetryInterval(response, context);
-                    if (nextInterval > 0) {
-                        try {
-                            if (this.log.isDebugEnabled()) {
-                                this.log.debug(exchangeId + ": wait for " + ((double) nextInterval / 1000) + " seconds" );
-                            }
-                            Thread.sleep(nextInterval);
-                        } catch (final InterruptedException e) {
-                            Thread.currentThread().interrupt();
-                            throw new InterruptedIOException();
-                        }
-                    }
-                    currentRequest = ClassicRequestCopier.INSTANCE.copy(scope.originalRequest);
-                } else {
-                    return response;
-                }
-            } catch (final RuntimeException ex) {
-                response.close();
-                throw ex;
-            }
-        }
-    }
-
-}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultServiceUnavailableRetryStrategy.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultServiceUnavailableRetryStrategy.java
deleted file mode 100644
index daa8725..0000000
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultServiceUnavailableRetryStrategy.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.impl;
-
-import java.util.Date;
-
-import org.apache.hc.client5.http.utils.DateUtils;
-import org.apache.hc.core5.http.HttpHeaders;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.message.BasicHttpResponse;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-public class TestDefaultServiceUnavailableRetryStrategy {
-
-    private DefaultServiceUnavailableRetryStrategy impl;
-
-    @Before
-    public void setup() {
-        this.impl = new DefaultServiceUnavailableRetryStrategy(3, 1234);
-    }
-
-    @Test
-    public void testBasics() throws Exception {
-        final HttpResponse response1 = new BasicHttpResponse(503, "Oppsie");
-        Assert.assertTrue(this.impl.retryRequest(response1, 1, null));
-        Assert.assertTrue(this.impl.retryRequest(response1, 2, null));
-        Assert.assertTrue(this.impl.retryRequest(response1, 3, null));
-        Assert.assertFalse(this.impl.retryRequest(response1, 4, null));
-        final HttpResponse response2 = new BasicHttpResponse(500, "Big Time Oppsie");
-        Assert.assertFalse(this.impl.retryRequest(response2, 1, null));
-
-        Assert.assertEquals(1234, this.impl.getRetryInterval(response1, null));
-    }
-
-    @Test
-    public void testRetryAfterHeaderAsLong() throws Exception {
-        final HttpResponse response = new BasicHttpResponse(503, "Oppsie");
-        response.setHeader(HttpHeaders.RETRY_AFTER, "321");
-
-        Assert.assertEquals(321000, this.impl.getRetryInterval(response, null));
-    }
-
-    @Test
-    public void testRetryAfterHeaderAsDate() throws Exception {
-        this.impl = new DefaultServiceUnavailableRetryStrategy(3, 1);
-        final HttpResponse response = new BasicHttpResponse(503, "Oppsie");
-
-        response.setHeader(HttpHeaders.RETRY_AFTER, DateUtils.formatDate(new Date(System.currentTimeMillis() + 100000L)));
-
-        Assert.assertTrue(this.impl.getRetryInterval(response, null) > 1);
-    }
-
-    @Test
-    public void testRetryAfterHeaderAsPastDate() throws Exception {
-        final HttpResponse response = new BasicHttpResponse(503, "Oppsie");
-
-        response.setHeader(HttpHeaders.RETRY_AFTER, DateUtils.formatDate(new Date(System.currentTimeMillis() - 100000L)));
-
-        Assert.assertEquals(0, this.impl.getRetryInterval(response, null));
-    }
-
-    @Test
-    public void testInvalidRetryAfterHeader() throws Exception {
-        final DefaultServiceUnavailableRetryStrategy impl = new DefaultServiceUnavailableRetryStrategy(3, 1234);
-
-        final HttpResponse response = new BasicHttpResponse(503, "Oppsie");
-        response.setHeader(HttpHeaders.RETRY_AFTER, "Stuff");
-
-        Assert.assertEquals(1234, impl.getRetryInterval(response, null));
-    }
-
-}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestServiceUnavailableRetryExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestServiceUnavailableRetryExec.java
deleted file mode 100644
index 10371c8..0000000
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestServiceUnavailableRetryExec.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-package org.apache.hc.client5.http.impl.classic;
-
-import java.io.ByteArrayInputStream;
-
-import org.apache.hc.client5.http.HttpRoute;
-import org.apache.hc.client5.http.ServiceUnavailableRetryStrategy;
-import org.apache.hc.client5.http.classic.ExecChain;
-import org.apache.hc.client5.http.classic.ExecRuntime;
-import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.classic.methods.HttpPost;
-import org.apache.hc.client5.http.entity.EntityBuilder;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
-import org.apache.hc.core5.http.ClassicHttpRequest;
-import org.apache.hc.core5.http.ClassicHttpResponse;
-import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.http.HttpResponse;
-import org.apache.hc.core5.http.protocol.HttpContext;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-@SuppressWarnings({"boxing","static-access"}) // test code
-public class TestServiceUnavailableRetryExec {
-
-    @Mock
-    private ServiceUnavailableRetryStrategy retryStrategy;
-    @Mock
-    private ExecChain chain;
-    @Mock
-    private ExecRuntime endpoint;
-
-    private ServiceUnavailableRetryExec retryExec;
-    private HttpHost target;
-
-    @Before
-    public void setup() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        retryExec = new ServiceUnavailableRetryExec(retryStrategy);
-        target = new HttpHost("localhost", 80);
-    }
-
-    @Test
-    public void testFundamentals() throws Exception {
-        final HttpRoute route = new HttpRoute(target);
-        final HttpGet request = new HttpGet("/test");
-        final HttpClientContext context = HttpClientContext.create();
-
-        final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
-
-        Mockito.when(chain.proceed(
-                Mockito.same(request),
-                Mockito.<ExecChain.Scope>any())).thenReturn(response);
-        Mockito.when(retryStrategy.retryRequest(
-                Mockito.<HttpResponse>any(),
-                Mockito.anyInt(),
-                Mockito.<HttpContext>any())).thenReturn(Boolean.TRUE, Boolean.FALSE);
-        Mockito.when(retryStrategy.getRetryInterval(
-                Mockito.<HttpResponse>any(),
-                Mockito.<HttpContext>any())).thenReturn(0L);
-
-        final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
-        retryExec.execute(request, scope, chain);
-
-        Mockito.verify(chain, Mockito.times(2)).proceed(
-                Mockito.<ClassicHttpRequest>any(),
-                Mockito.same(scope));
-        Mockito.verify(response, Mockito.times(1)).close();
-    }
-
-    @Test(expected = RuntimeException.class)
-    public void testStrategyRuntimeException() throws Exception {
-        final HttpRoute route = new HttpRoute(target);
-        final ClassicHttpRequest request = new HttpGet("/test");
-        final HttpClientContext context = HttpClientContext.create();
-
-        final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
-        Mockito.when(chain.proceed(
-                Mockito.<ClassicHttpRequest>any(),
-                Mockito.<ExecChain.Scope>any())).thenReturn(response);
-        Mockito.doThrow(new RuntimeException("Ooopsie")).when(retryStrategy).retryRequest(
-                Mockito.<HttpResponse>any(),
-                Mockito.anyInt(),
-                Mockito.<HttpContext>any());
-        final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
-        try {
-            retryExec.execute(request, scope, chain);
-        } catch (final Exception ex) {
-            Mockito.verify(response).close();
-            throw ex;
-        }
-    }
-
-    @Test
-    public void testNonRepeatableEntityResponseReturnedImmediately() throws Exception {
-        final HttpRoute route = new HttpRoute(target);
-
-        final HttpPost request = new HttpPost("/test");
-        request.setEntity(EntityBuilder.create()
-                .setStream(new ByteArrayInputStream(new byte[]{}))
-                .build());
-        final HttpClientContext context = HttpClientContext.create();
-
-        final ClassicHttpResponse response = Mockito.mock(ClassicHttpResponse.class);
-        Mockito.when(chain.proceed(
-                Mockito.<ClassicHttpRequest>any(),
-                Mockito.<ExecChain.Scope>any())).thenReturn(response);
-        Mockito.when(retryStrategy.retryRequest(
-                Mockito.<HttpResponse>any(),
-                Mockito.anyInt(),
-                Mockito.<HttpContext>any())).thenReturn(Boolean.TRUE, Boolean.FALSE);
-
-        final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, endpoint, context);
-        final ClassicHttpResponse finalResponse = retryExec.execute(request, scope, chain);
-
-        Assert.assertSame(response, finalResponse);
-        Mockito.verify(response, Mockito.times(0)).close();
-    }
-
-}