1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.compatibility.common.util; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.doThrow; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.verify; 24 import static org.testng.Assert.assertThrows; 25 import static org.testng.Assert.expectThrows; 26 27 import org.junit.Test; 28 import org.junit.runner.Description; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.model.Statement; 31 import org.mockito.Mock; 32 import org.mockito.junit.MockitoJUnitRunner; 33 34 @RunWith(MockitoJUnitRunner.class) 35 public class RetryRuleTest { 36 37 private final Description mDescription = Description.createSuiteDescription("Whatever"); 38 39 private static final RetryableException sRetryableException = 40 new RetryableException("Y U NO RETRY?"); 41 42 private static class RetryableStatement<T extends Exception> extends Statement { 43 private final int mNumberFailures; 44 private int mNumberCalls; 45 private final T mException; 46 47 RetryableStatement(int numberFailures, T exception) { 48 mNumberFailures = numberFailures; 49 mException = exception; 50 } 51 52 @Override 53 public void evaluate() throws Throwable { 54 mNumberCalls++; 55 if (mNumberCalls <= mNumberFailures) { 56 throw mException; 57 } 58 } 59 60 @Override 61 public String toString() { 62 return "RetryableStatement: failures=" + mNumberFailures + ", calls=" + mNumberCalls; 63 } 64 } 65 66 private @Mock Statement mMockStatement; 67 68 @Test 69 public void testInvalidConstructor() throws Throwable { 70 assertThrows(IllegalArgumentException.class, () -> new RetryRule(-1)); 71 } 72 73 @Test 74 public void testPassOnRetryableException() throws Throwable { 75 final RetryRule rule = new RetryRule(1); 76 rule.apply(new RetryableStatement<RetryableException>(1, sRetryableException), mDescription) 77 .evaluate(); 78 } 79 80 @Test 81 public void testPassOnRetryableExceptionWithTimeout() throws Throwable { 82 final Timeout timeout = new Timeout("YOUR TIME IS GONE", 1, 2, 10); 83 final RetryableException exception = new RetryableException(timeout, "Y U NO?"); 84 85 final RetryRule rule = new RetryRule(1); 86 rule.apply(new RetryableStatement<RetryableException>(1, exception), mDescription) 87 .evaluate(); 88 89 // Assert timeout was increased 90 assertThat(timeout.ms()).isEqualTo(2); 91 } 92 93 @Test 94 public void testFailOnRetryableException() throws Throwable { 95 final RetryRule rule = new RetryRule(1); 96 97 final RetryableException actualException = expectThrows(RetryableException.class, 98 () -> rule.apply(new RetryableStatement<RetryableException>(2, sRetryableException), 99 mDescription).evaluate()); 100 101 assertThat(actualException).isSameAs(sRetryableException); 102 } 103 104 @Test 105 public void testPassWhenDisabledAndStatementPass() throws Throwable { 106 final RetryRule rule = new RetryRule(0); 107 108 rule.apply(mMockStatement, mDescription).evaluate(); 109 110 verify(mMockStatement, times(1)).evaluate(); 111 } 112 113 @Test 114 public void testFailWhenDisabledAndStatementThrowsRetryableException() throws Throwable { 115 final RetryableException exception = new RetryableException("Y U NO?"); 116 final RetryRule rule = new RetryRule(0); 117 doThrow(exception).when(mMockStatement).evaluate(); 118 119 final RetryableException actualException = expectThrows(RetryableException.class, 120 () -> rule.apply(mMockStatement, mDescription).evaluate()); 121 122 assertThat(actualException).isSameAs(exception); 123 verify(mMockStatement, times(1)).evaluate(); 124 } 125 126 @Test 127 public void testFailWhenDisabledAndStatementThrowsNonRetryableException() throws Throwable { 128 final RuntimeException exception = new RuntimeException("Y U NO?"); 129 final RetryRule rule = new RetryRule(0); 130 doThrow(exception).when(mMockStatement).evaluate(); 131 132 final RuntimeException actualException = expectThrows(RuntimeException.class, 133 () -> rule.apply(mMockStatement, mDescription).evaluate()); 134 135 assertThat(actualException).isSameAs(exception); 136 verify(mMockStatement, times(1)).evaluate(); 137 } 138 } 139