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.verify; 22 import static org.testng.Assert.expectThrows; 23 24 import com.android.compatibility.common.util.SafeCleanerRule.Dumper; 25 26 import com.google.common.collect.ImmutableList; 27 28 import org.junit.AssumptionViolatedException; 29 import org.junit.Test; 30 import org.junit.runner.Description; 31 import org.junit.runner.RunWith; 32 import org.junit.runners.model.Statement; 33 import org.mockito.Mock; 34 import org.mockito.junit.MockitoJUnitRunner; 35 36 import java.util.List; 37 import java.util.concurrent.Callable; 38 39 @RunWith(MockitoJUnitRunner.class) 40 public class SafeCleanerRuleTest { 41 42 private static class FailureStatement extends Statement { 43 private final Throwable mThrowable; 44 45 FailureStatement(Throwable t) { 46 mThrowable = t; 47 } 48 49 @Override 50 public void evaluate() throws Throwable { 51 throw mThrowable; 52 } 53 } 54 55 private final Description mDescription = Description.createSuiteDescription("Whatever"); 56 private final RuntimeException mRuntimeException = new RuntimeException("D'OH!"); 57 58 @Mock private Dumper mDumper; 59 60 // Use mocks for objects that don't throw any exception. 61 @Mock private ThrowingRunnable mGoodGuyRunner1; 62 @Mock private ThrowingRunnable mGoodGuyRunner2; 63 @Mock private Callable<List<Throwable>> mGoodGuyExtraExceptions1; 64 @Mock private Callable<List<Throwable>> mGoodGuyExtraExceptions2; 65 @Mock private Statement mGoodGuyStatement; 66 67 @Test 68 public void testEmptyRule_testPass() throws Throwable { 69 final SafeCleanerRule rule = new SafeCleanerRule(); 70 rule.apply(mGoodGuyStatement, mDescription).evaluate(); 71 } 72 73 @Test 74 public void testEmptyRule_testFails() throws Throwable { 75 final SafeCleanerRule rule = new SafeCleanerRule(); 76 final Throwable actualException = expectThrows(RuntimeException.class, 77 () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate()); 78 assertThat(actualException).isSameAs(mRuntimeException); 79 } 80 81 @Test 82 public void testEmptyRule_testFails_withDumper() throws Throwable { 83 final SafeCleanerRule rule = new SafeCleanerRule().setDumper(mDumper); 84 final Throwable actualException = expectThrows(RuntimeException.class, 85 () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate()); 86 assertThat(actualException).isSameAs(mRuntimeException); 87 verify(mDumper).dump("Whatever", actualException); 88 } 89 90 @Test 91 public void testOnlyTestFails() throws Throwable { 92 final SafeCleanerRule rule = new SafeCleanerRule() 93 .run(mGoodGuyRunner1) 94 .add(mGoodGuyExtraExceptions1); 95 final Throwable actualException = expectThrows(RuntimeException.class, 96 () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate()); 97 assertThat(actualException).isSameAs(mRuntimeException); 98 verify(mGoodGuyRunner1).run(); 99 verify(mGoodGuyExtraExceptions1).call(); 100 } 101 102 @Test 103 public void testOnlyTestFails_withDumper() throws Throwable { 104 final SafeCleanerRule rule = new SafeCleanerRule() 105 .setDumper(mDumper) 106 .run(mGoodGuyRunner1) 107 .add(mGoodGuyExtraExceptions1); 108 final Throwable actualException = expectThrows(RuntimeException.class, 109 () -> rule.apply(new FailureStatement(mRuntimeException), mDescription).evaluate()); 110 assertThat(actualException).isSameAs(mRuntimeException); 111 verify(mGoodGuyRunner1).run(); 112 verify(mGoodGuyExtraExceptions1).call(); 113 verify(mDumper).dump("Whatever", actualException); 114 } 115 116 @Test 117 public void testTestPass_oneRunnerFails() throws Throwable { 118 final SafeCleanerRule rule = new SafeCleanerRule() 119 .run(mGoodGuyRunner1) 120 .run(() -> { throw mRuntimeException; }) 121 .run(mGoodGuyRunner2) 122 .add(mGoodGuyExtraExceptions1); 123 final Throwable actualException = expectThrows(RuntimeException.class, 124 () -> rule.apply(mGoodGuyStatement, mDescription).evaluate()); 125 assertThat(actualException).isSameAs(mRuntimeException); 126 verify(mGoodGuyRunner1).run(); 127 verify(mGoodGuyRunner2).run(); 128 verify(mGoodGuyExtraExceptions1).call(); 129 } 130 131 @Test 132 public void testTestPass_oneRunnerFails_withDumper() throws Throwable { 133 final SafeCleanerRule rule = new SafeCleanerRule() 134 .setDumper(mDumper) 135 .run(mGoodGuyRunner1) 136 .run(() -> { 137 throw mRuntimeException; 138 }) 139 .run(mGoodGuyRunner2) 140 .add(mGoodGuyExtraExceptions1); 141 final Throwable actualException = expectThrows(RuntimeException.class, 142 () -> rule.apply(mGoodGuyStatement, mDescription).evaluate()); 143 assertThat(actualException).isSameAs(mRuntimeException); 144 verify(mGoodGuyRunner1).run(); 145 verify(mGoodGuyRunner2).run(); 146 verify(mGoodGuyExtraExceptions1).call(); 147 verify(mDumper).dump("Whatever", actualException); 148 } 149 150 @Test 151 public void testTestPass_oneExtraExceptionThrownAsCallable() throws Throwable { 152 final SafeCleanerRule rule = new SafeCleanerRule() 153 .run(mGoodGuyRunner1) 154 .add(mRuntimeException) 155 .add(mGoodGuyExtraExceptions1) 156 .run(mGoodGuyRunner2); 157 final Throwable actualException = expectThrows(RuntimeException.class, 158 () -> rule.apply(mGoodGuyStatement, mDescription).evaluate()); 159 assertThat(actualException).isSameAs(mRuntimeException); 160 verify(mGoodGuyRunner1).run(); 161 verify(mGoodGuyRunner2).run(); 162 verify(mGoodGuyExtraExceptions1).call(); 163 } 164 165 @Test 166 public void testTestPass_oneExtraExceptionThrown() throws Throwable { 167 final SafeCleanerRule rule = new SafeCleanerRule() 168 .run(mGoodGuyRunner1) 169 .add(() -> { 170 return ImmutableList.of(mRuntimeException); 171 }) 172 .add(mGoodGuyExtraExceptions1) 173 .run(mGoodGuyRunner2); 174 final Throwable actualException = expectThrows(RuntimeException.class, 175 () -> rule.apply(mGoodGuyStatement, mDescription).evaluate()); 176 assertThat(actualException).isSameAs(mRuntimeException); 177 verify(mGoodGuyRunner1).run(); 178 verify(mGoodGuyRunner2).run(); 179 verify(mGoodGuyExtraExceptions1).call(); 180 } 181 182 @Test 183 public void testTestPass_oneExtraExceptionThrown_withDumper() throws Throwable { 184 final SafeCleanerRule rule = new SafeCleanerRule() 185 .setDumper(mDumper) 186 .run(mGoodGuyRunner1) 187 .add(() -> { return ImmutableList.of(mRuntimeException); }) 188 .add(mGoodGuyExtraExceptions1) 189 .run(mGoodGuyRunner2); 190 final Throwable actualException = expectThrows(RuntimeException.class, 191 () -> rule.apply(mGoodGuyStatement, mDescription).evaluate()); 192 assertThat(actualException).isSameAs(mRuntimeException); 193 verify(mGoodGuyRunner1).run(); 194 verify(mGoodGuyRunner2).run(); 195 verify(mGoodGuyExtraExceptions1).call(); 196 verify(mDumper).dump("Whatever", actualException); 197 } 198 199 @Test 200 public void testThrowTheKitchenSinkAKAEverybodyThrows() throws Throwable { 201 final Exception extra1 = new Exception("1"); 202 final Exception extra2 = new Exception("2"); 203 final Exception extra3 = new Exception("3"); 204 final Error error1 = new Error("one"); 205 final Error error2 = new Error("two"); 206 final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?"); 207 final SafeCleanerRule rule = new SafeCleanerRule() 208 .run(mGoodGuyRunner1) 209 .add(mGoodGuyExtraExceptions1) 210 .add(mRuntimeException) 211 .add(() -> { 212 return ImmutableList.of(extra1, extra2); 213 }) 214 .run(() -> { 215 throw error1; 216 }) 217 .run(mGoodGuyRunner2) 218 .add(() -> { 219 return ImmutableList.of(extra3); 220 }) 221 .add(mGoodGuyExtraExceptions2) 222 .run(() -> { 223 throw error2; 224 }); 225 226 final SafeCleanerRule.MultipleExceptions actualException = expectThrows( 227 SafeCleanerRule.MultipleExceptions.class, 228 () -> rule.apply(new FailureStatement(testException), mDescription).evaluate()); 229 assertThat(actualException.getThrowables()) 230 .containsExactly(testException, mRuntimeException, error1, error2, extra1, extra2, 231 extra3) 232 .inOrder(); 233 verify(mGoodGuyRunner1).run(); 234 verify(mGoodGuyRunner2).run(); 235 verify(mGoodGuyExtraExceptions1).call(); 236 } 237 238 @Test 239 public void testIgnoreAssumptionViolatedException() throws Throwable { 240 final AssumptionViolatedException ave = new AssumptionViolatedException( 241 "tis an assumption violation"); 242 final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?"); 243 final SafeCleanerRule rule = new SafeCleanerRule() 244 .run(mGoodGuyRunner1) 245 .add(mRuntimeException) 246 .run(() -> { 247 throw ave; 248 }); 249 250 final SafeCleanerRule.MultipleExceptions actualException = expectThrows( 251 SafeCleanerRule.MultipleExceptions.class, 252 () -> rule.apply(new FailureStatement(testException), mDescription).evaluate()); 253 assertThat(actualException.getThrowables()) 254 .containsExactly(testException, mRuntimeException) 255 .inOrder(); 256 verify(mGoodGuyRunner1).run(); 257 } 258 259 @Test 260 public void testThrowTheKitchenSinkAKAEverybodyThrows_withDumper() throws Throwable { 261 final Exception extra1 = new Exception("1"); 262 final Exception extra2 = new Exception("2"); 263 final Exception extra3 = new Exception("3"); 264 final Exception extra4 = new Exception("4"); 265 final Error error1 = new Error("one"); 266 final Error error2 = new Error("two"); 267 final RuntimeException testException = new RuntimeException("TEST, Y U NO PASS?"); 268 final SafeCleanerRule rule = new SafeCleanerRule() 269 .setDumper(mDumper) 270 .run(mGoodGuyRunner1) 271 .add(mGoodGuyExtraExceptions1) 272 .add(() -> { 273 return ImmutableList.of(extra1, extra2); 274 }) 275 .run(() -> { 276 throw error1; 277 }) 278 .run(mGoodGuyRunner2) 279 .add(() -> { return ImmutableList.of(extra3); }) 280 .add(mGoodGuyExtraExceptions2) 281 .run(() -> { 282 throw error2; 283 }) 284 .run(() -> { 285 throw extra4; 286 }); 287 288 final SafeCleanerRule.MultipleExceptions actualException = expectThrows( 289 SafeCleanerRule.MultipleExceptions.class, 290 () -> rule.apply(new FailureStatement(testException), mDescription).evaluate()); 291 assertThat(actualException.getThrowables()) 292 .containsExactly(testException, error1, error2, extra4, extra1, extra2, extra3) 293 .inOrder(); 294 verify(mGoodGuyRunner1).run(); 295 verify(mGoodGuyRunner2).run(); 296 verify(mGoodGuyExtraExceptions1).call(); 297 verify(mDumper).dump("Whatever", actualException); 298 } 299 } 300