private static void assertClassifiedException(Throwable cause, ExceptionClassification exceptionClassification, int expectedRetries) { if (cause instanceof DriftApplicationException) { cause = cause.getCause(); } assertTrue(cause instanceof ClassifiedException); ClassifiedException classifiedException = (ClassifiedException) cause; assertEquals(classifiedException.getClassification(), exceptionClassification); assertRetriesFailedInformation(classifiedException, 0, expectedRetries + 1, 0); }
@Test(timeOut = 60000) public void testBasicRetriesToFailure() throws Exception { testBasicRetriesToFailure(0, true); testBasicRetriesToFailure(1, true); testBasicRetriesToFailure(5, true); testBasicRetriesToFailure(10, true); testBasicRetriesToFailure(0, false); testBasicRetriesToFailure(1, false); testBasicRetriesToFailure(5, false); testBasicRetriesToFailure(10, false); }
@Test(timeOut = 60000) public void testBasicRetriesToSuccess() throws Exception { testBasicRetriesToSuccess(0, true); testBasicRetriesToSuccess(1, true); testBasicRetriesToSuccess(3, true); testBasicRetriesToSuccess(10, true); testBasicRetriesToSuccess(0, false); testBasicRetriesToSuccess(1, false); testBasicRetriesToSuccess(3, false); testBasicRetriesToSuccess(10, false); }
private static void testExceptionFromInvokerInvoke(int expectedRetries) throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(expectedRetries + 10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, () -> { attempts.getAndIncrement(); if (attempts.get() > expectedRetries) { throw UNEXPECTED_EXCEPTION; } return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), expectedRetries + 1); assertUnexpectedException(e.getCause()); } }
}, ticker); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(retryPolicy, stat, invoker, new TestingAddressSelector(100), ticker); assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(true), NORMAL), maxRetries); assertDelays(invoker, retryPolicy, 7);
@Test(timeOut = 60000) public void testMaxRetries() throws Exception { int maxRetries = 5; RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(maxRetries), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(retryPolicy, stat, () -> { attempts.getAndIncrement(); return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), maxRetries + 1); assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(true), NORMAL), maxRetries); } stat.assertFailure(maxRetries); }
return immediateFailedFuture(createClassifiedException(true, overloaded ? OVERLOADED : DOWN)); }); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, TTransportException transportException = (TTransportException) e.getCause(); assertTrue(transportException.getMessage().startsWith("No hosts available")); assertRetriesFailedInformation(transportException, 0, 0, overloaded ? expectedRetries : 0);
private static void testBasicRetriesToSuccess(int expectedRetries, boolean wrapWithApplicationException) throws Exception { RetryPolicy retryPolicy = new RetryPolicy( new DriftClientConfig() .setMaxRetries(expectedRetries + 10) .setMinBackoffDelay(new Duration(1, SECONDS)) .setMaxBackoffDelay(new Duration(1, DAYS)) .setBackoffScaleFactor(2.0), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); MockMethodInvoker invoker = new MockMethodInvoker(() -> { int currentAttempts = attempts.getAndIncrement(); if (currentAttempts < expectedRetries) { return immediateFailedFuture(createClassifiedException(true, NORMAL, wrapWithApplicationException)); } return immediateFuture(SUCCESS); }); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(retryPolicy, stat, invoker, new TestingAddressSelector(100), systemTicker()); assertEquals(methodInvocation.get(), SUCCESS); assertEquals(attempts.get(), expectedRetries + 1); stat.assertSuccess(expectedRetries); assertDelays(invoker, retryPolicy, expectedRetries); }
@Test(timeOut = 60000) public void testFirstTrySuccess() throws Exception { TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation(RetryPolicy.NO_RETRY_POLICY, stat, () -> immediateFuture(SUCCESS)); assertEquals(methodInvocation.get(), SUCCESS); stat.assertSuccess(0); }
private static void testConnectionFailedDelay(int numberOfAddresses, int numberOfRetriesPerAddress, int expectedDelays) throws Exception { testConnectionFailedDelay(false, numberOfAddresses, numberOfRetriesPerAddress, expectedDelays); testConnectionFailedDelay(true, numberOfAddresses, numberOfRetriesPerAddress, expectedDelays); }
@Test(timeOut = 60000) public void testConnectionFailed() throws Exception { testConnectionFailed(0, 3); testConnectionFailed(1, 3); testConnectionFailed(10, 3); }
private static void assertRetriesFailedInformation(Throwable exception, int expectedFailedConnections, int expectedInvocationAttempts, int expectedOverloaded) { RetriesFailedException retriesFailedException = getRetriesFailedException(exception); assertEquals(retriesFailedException.getFailedConnections(), expectedFailedConnections); assertEquals(retriesFailedException.getInvocationAttempts(), expectedInvocationAttempts); assertEquals(retriesFailedException.getOverloadedRejects(), expectedOverloaded); }
DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, assertUnexpectedException(e.getCause());
DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(false), NORMAL), expectedRetries); assertDelays(invoker, retryPolicy, expectedRetries);
@Test(timeOut = 60000) public void testBasicRetriesToNoHosts() throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); int expectedRetries = 3; DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, new MockMethodInvoker(() -> { attempts.getAndIncrement(); return immediateFailedFuture(createClassifiedException(true, NORMAL)); }), new TestingAddressSelector(expectedRetries + 1), systemTicker()); try { methodInvocation.get(); fail("Expected exception"); } catch (ExecutionException e) { assertEquals(attempts.get(), expectedRetries + 1); assertClassifiedException(e.getCause(), new ExceptionClassification(Optional.of(true), NORMAL), expectedRetries); } stat.assertFailure(expectedRetries); }
DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( new RetryPolicy(new DriftClientConfig().setMaxRetries(100), new TestingExceptionClassifier()), new TestingMethodInvocationStat(), assertTrue(applicationException.getCause() instanceof ClassifiedException); ClassifiedException classifiedException = (ClassifiedException) applicationException.getCause(); assertRetriesFailedInformation(classifiedException, failedConnections, expectedInvocationAttempts, 0);
private static DriftMethodInvocation<?> createDriftMethodInvocation( RetryPolicy retryPolicy, TestingMethodInvocationStat stat, MockMethodInvoker invoker, AddressSelector<?> addressSelector, Ticker ticker) { return DriftMethodInvocation.createDriftMethodInvocation( invoker, METHOD_METADATA, ImmutableMap.of(), ImmutableList.of(), retryPolicy, addressSelector, Optional.empty(), stat, ticker); }
@Test public void testConnectionFailedDelay() throws Exception { testConnectionFailedDelay(0, 0, 0); testConnectionFailedDelay(1, 1, 0); testConnectionFailedDelay(10, 1, 0); testConnectionFailedDelay(1, 2, 1); testConnectionFailedDelay(2, 2, 2); testConnectionFailedDelay(10, 2, 10); testConnectionFailedDelay(10, 5, 40); }
DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, assertUnexpectedException(e.getCause());
private static void testPropagateCancel(int expectedRetries, boolean interrupt) throws Exception { RetryPolicy retryPolicy = new RetryPolicy(new DriftClientConfig().setMaxRetries(expectedRetries + 10), new TestingExceptionClassifier()); TestingMethodInvocationStat stat = new TestingMethodInvocationStat(); AtomicInteger attempts = new AtomicInteger(); TestFuture future = new TestFuture(); CountDownLatch settableFutureFetched = new CountDownLatch(1); DriftMethodInvocation<?> methodInvocation = createDriftMethodInvocation( retryPolicy, stat, () -> { attempts.getAndIncrement(); if (attempts.get() > expectedRetries) { settableFutureFetched.countDown(); return future; } return immediateFailedFuture(createClassifiedException(true, NORMAL)); }); settableFutureFetched.await(); methodInvocation.cancel(interrupt); assertTrue(future.isCancelled()); assertEquals(future.checkWasInterrupted(), interrupt); assertEquals(attempts.get(), expectedRetries + 1); }