package com.bazaarvoice.ostrich.retry;
import com.bazaarvoice.ostrich.RetryPolicy;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class ExponentialBackoffRetryTest {
@Test(expected = IllegalArgumentException.class)
public void testNegativeNumberOfTimes() {
new ExponentialBackoffRetry(-1, 1, 1, TimeUnit.MILLISECONDS);
}
@Test(expected = IllegalArgumentException.class)
public void testNegativeBaseSleepTime() {
new ExponentialBackoffRetry(1, -1, 1, TimeUnit.MILLISECONDS);
}
@Test(expected = IllegalArgumentException.class)
public void testNegativeMaxSleepTime() {
new ExponentialBackoffRetry(1, 1, -1, TimeUnit.MILLISECONDS);
}
@Test(expected = IllegalArgumentException.class)
public void testZeroNAttempts() {
RetryPolicy retry = new ExponentialBackoffRetry(0, 0, 0, TimeUnit.MILLISECONDS);
retry.allowRetry(0, 0);
}
@Test
public void testRetryMaxZeroAttempts() {
RetryPolicy retry = new ExponentialBackoffRetry(0, 0, 0, TimeUnit.MILLISECONDS);
assertFalse(retry.allowRetry(1, 0));
}
@Test
public void testRetryMaxOneAttempt() {
RetryPolicy retry = new ExponentialBackoffRetry(1, 0, 0, TimeUnit.MILLISECONDS);
assertFalse(retry.allowRetry(1, 0));
}
@Test
public void testRetryMaxTwoAttempts() {
RetryPolicy retry = new ExponentialBackoffRetry(2, 0, 0, TimeUnit.MILLISECONDS);
assertTrue(retry.allowRetry(1, 0));
assertFalse(retry.allowRetry(2, 0));
}
@Test
public void testBaseSleepTimeUnits() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 20, 1000, TimeUnit.SECONDS);
long sleepTimeMs = retry.getSleepTimeMs(1, 0);
assertBetween(TimeUnit.SECONDS.toMillis(20), sleepTimeMs, TimeUnit.SECONDS.toMillis(40));
}
@Test
public void testMaxSleepTimeUnits() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 50, 20, TimeUnit.SECONDS);
long sleepTimeMs = retry.getSleepTimeMs(1, 0);
assertBetween(TimeUnit.SECONDS.toMillis(10), sleepTimeMs, TimeUnit.SECONDS.toMillis(20));
}
@Test
public void testFirstRetrySleepTime() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 20, 1000, TimeUnit.MILLISECONDS);
long sleepTimeMs = retry.getSleepTimeMs(1, 0);
assertBetween(20, sleepTimeMs, 40);
}
@Test
public void testSecondRetrySleepTime() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 20, 1000, TimeUnit.MILLISECONDS);
long sleepTimeMs = retry.getSleepTimeMs(2, 0);
assertBetween(40, sleepTimeMs, 80);
}
@Test
public void testRetryBaseMoreThanMaxSleepTime() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 60, 50, TimeUnit.MILLISECONDS);
long sleepTimeMs = retry.getSleepTimeMs(1, 0);
Assert.assertEquals(50, sleepTimeMs);
}
@Test
public void testMinRetrySleepTime() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 10, 50, TimeUnit.MILLISECONDS);
for (int i = 1; i <= 10; i++) {
long sleepTimeMs = retry.getSleepTimeMs(i, 0);
assertTrue(sleepTimeMs >= Math.min(10 * (1 << (i - 1)), 25));
}
}
@Test
public void testMaxRetrySleepTime() {
SleepingRetry retry = new ExponentialBackoffRetry(10, 10, 50, TimeUnit.MILLISECONDS);
for (int i = 1; i <= 10; i++) {
long sleepTimeMs = retry.getSleepTimeMs(i, 0);
assertTrue(sleepTimeMs <= 50);
}
}
/** Asserts expectedLowerBound <= actual <= expectedUpperBound. */
private void assertBetween(long expectedLowerBound, long actual, long expectedUpperBound) {
assertTrue("Expected: " + expectedLowerBound + " <= " + actual, expectedLowerBound <= actual);
assertTrue("Expected: " + expectedUpperBound + " >= " + actual, expectedUpperBound >= actual);
}
}