BackoffHelper { public <T, E extends Exception> T doUntilResult(ExceptionalSupplier<T, E> task) throws InterruptedException, BackoffStoppedException, E { T result = task.get(); return (result != null) ? result : retryWork(task); } BackoffHelper();  BackoffHelper(Amount<Long, Time> initialBackoff, Amount<Long, Time> maxBackoff);  BackoffHelper(BackoffStrategy backoffStrategy); @VisibleForTesting  BackoffHelper(Clock clock, BackoffStrategy backoffStrategy); void doUntilSuccess(final ExceptionalSupplier<Boolean, E> task); T doUntilResult(ExceptionalSupplier<T, E> task);  }
@Test public void testDoUntilResult() throws Exception { ExceptionalSupplier<String, RuntimeException> task = createMock(new Clazz<ExceptionalSupplier<String, RuntimeException>>() { }); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(0)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(0)).andReturn(42L); clock.waitFor(42L); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(42L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(42L)).andReturn(37L); clock.waitFor(37L); expect(task.get()).andReturn("jake"); control.replay(); assertEquals("jake", backoffHelper.doUntilResult(task)); control.verify(); }
@Test public void testDoUntilResultTransparentException() throws Exception { ExceptionalSupplier<String, IOException> task = createMock(new Clazz<ExceptionalSupplier<String, IOException>>() { }); IOException thrown = new IOException(); expect(task.get()).andThrow(thrown); control.replay(); try { backoffHelper.doUntilResult(task); fail("Expected exception to be bubbled"); } catch (IOException e) { assertSame(thrown, e); } control.verify(); }
@Test public void testDoUntilResultMaxSuccess() throws Exception { ExceptionalSupplier<String, RuntimeException> task = createMock(new Clazz<ExceptionalSupplier<String, RuntimeException>>() { }); BackoffHelper maxBackoffHelper = new BackoffHelper(clock, backoffStrategy); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(0L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(0)).andReturn(42L); clock.waitFor(42L); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(42L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(42L)).andReturn(37L); clock.waitFor(37L); expect(task.get()).andReturn("jake"); control.replay(); assertEquals("jake", maxBackoffHelper.doUntilResult(task)); control.verify(); }
@Test public void testDoUntilResultMaxReached() throws Exception { ExceptionalSupplier<String, RuntimeException> task = createMock(new Clazz<ExceptionalSupplier<String, RuntimeException>>() { }); BackoffHelper maxBackoffHelper = new BackoffHelper(clock, backoffStrategy); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(0L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(0)).andReturn(42L); clock.waitFor(42L); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(42L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(42L)).andReturn(37L); clock.waitFor(37L); expect(task.get()).andReturn(null); expect(backoffStrategy.shouldContinue(37L)).andReturn(false); control.replay(); try { maxBackoffHelper.doUntilResult(task); fail("Expected max retry failure"); } catch (BackoffHelper.BackoffStoppedException e) { } control.verify(); }