/** * Licensed 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. */ package org.apache.aurora.common.util; import java.io.IOException; import org.apache.aurora.common.base.ExceptionalSupplier; import org.apache.aurora.common.testing.easymock.EasyMockTest; import org.junit.Before; import org.junit.Test; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; /** * @author John Sirois */ public class BackoffHelperTest extends EasyMockTest { private Clock clock; private BackoffStrategy backoffStrategy; private BackoffHelper backoffHelper; @Before public void setUp() { clock = createMock(Clock.class); backoffStrategy = createMock(BackoffStrategy.class); backoffHelper = new BackoffHelper(clock, backoffStrategy); } @Test public void testGetBackoffStrategy() { control.replay(); assertEquals(backoffStrategy, backoffHelper.getBackoffStrategy()); } @Test public void testDoUntilSuccess() throws Exception { ExceptionalSupplier<Boolean, RuntimeException> task = createMock(new Clazz<ExceptionalSupplier<Boolean, RuntimeException>>() { }); expect(task.get()).andReturn(false); expect(backoffStrategy.shouldContinue(0L)).andReturn(true); expect(backoffStrategy.calculateBackoffMs(0L)).andReturn(42L); clock.waitFor(42L); expect(task.get()).andReturn(true); control.replay(); backoffHelper.doUntilSuccess(task); control.verify(); } @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) { // expected } control.verify(); } @Test public void testDoUntilSuccessTransparentException() throws Exception { ExceptionalSupplier<Boolean, RuntimeException> task = createMock(new Clazz<ExceptionalSupplier<Boolean, RuntimeException>>() { }); IllegalArgumentException thrown = new IllegalArgumentException(); expect(task.get()).andThrow(thrown); control.replay(); try { backoffHelper.doUntilSuccess(task); fail("Expected exception to be bubbled"); } catch (IllegalArgumentException e) { assertSame(thrown, e); } control.verify(); } }