RetryingRequestExecutor implements RequestExecutor { public Response execute(Request request) throws Exception { RetryHandler retryHandler = request.getMethodConfig().getRetryHandler(); RequestException exception = null; Response response; int attemptCount = 1; do { Disposables.dispose(exception); response = null; try { response = delegate.execute(request); if(response.getStatusCode() >= minErrorStatusCode) { exception = new RequestException("Request failed - status code: " + response.getStatusCode(), response); }else{ return response; } } catch (RequestException e) { exception = e; } }while(retryHandler.retry(exception, ++attemptCount)); if(response != null) { return response; } throw exception; } RetryingRequestExecutor(RequestExecutor delegate, int minErrorStatusCode); Response execute(Request request);  }
@Test public void executeShouldRetryUntilSuccessUsingRetryHandler() throws Exception { RequestException requestException1 = mock(RequestException.class); RequestException requestException2 = mock(RequestException.class); when(retryHandler.retry(requestException1, 2)).thenReturn(true); when(retryHandler.retry(requestException2, 3)).thenReturn(true); when(mockRequestExecutor.execute(request)).thenThrow(requestException1, requestException2).thenReturn(expected); Response actual = toTest.execute(request); assertSame(expected, actual); verify(requestException1).dispose(); verify(requestException2).dispose(); }
@Test public void executeShouldRetryUntilRetryHandlerReturnsFalseAndRethrowLastException() throws Exception { RequestException requestException1 = mock(RequestException.class); RequestException requestException2 = mock(RequestException.class); when(retryHandler.retry(requestException1, 2)).thenReturn(true); when(retryHandler.retry(requestException2, 3)).thenReturn(false); when(mockRequestExecutor.execute(request)).thenThrow(requestException1, requestException2); try { toTest.execute(request); } catch (Exception e) { assertSame(requestException2, e); verify(requestException1).dispose(); verifyNoMoreInteractions(requestException2); } }
@Test public void executeShouldRetryAndFailIfStatusCodeIsGreaterThan400() throws Exception { RequestException requestException1 = mock(RequestException.class); ArgumentCaptor<RequestException> requestException2 = ArgumentCaptor.forClass(RequestException.class); Response badResponse = mock(Response.class); when(badResponse.getStatusCode()).thenReturn(123); when(retryHandler.retry(requestException1, 2)).thenReturn(true); when(retryHandler.retry(requestException2.capture(), eq(3))).thenReturn(false); when(mockRequestExecutor.execute(request)).thenThrow(requestException1).thenReturn(badResponse); try { toTest.execute(request); } catch (Exception e) { assertSame(requestException2.getValue(), e); assertSame(badResponse, requestException2.getValue().getResponse()); assertEquals("", requestException2.getValue().getMessage()); verify(requestException1).dispose(); verifyNoMoreInteractions(requestException2); } }
@Test public void executeShouldRetryIfStatusCodeIsGreaterThan400AndReturnResponseIsRetryIsSuccess() throws Exception { RequestException requestException1 = mock(RequestException.class); ArgumentCaptor<RequestException> requestException2 = ArgumentCaptor.forClass(RequestException.class); Response badResponse = mock(Response.class); when(badResponse.getStatusCode()).thenReturn(123); when(retryHandler.retry(requestException1, 2)).thenReturn(true); when(retryHandler.retry(requestException2.capture(), eq(3))).thenReturn(true); when(mockRequestExecutor.execute(request)).thenThrow(requestException1).thenReturn(badResponse, expected); Response actual = toTest.execute(request); assertSame(expected, actual); verify(requestException1).dispose(); }
@Test public void executeShouldCancelAllIfDelegateThrowUnexpectedException() throws Exception { Exception expected = mock(Exception.class); when(mockRequestExecutor.execute(request)).thenThrow(expected); try { toTest.execute(request); } catch (Exception e) { assertSame(expected, e); } }