1 /* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.util.concurrent; 16 17 import static com.google.common.truth.Truth.assertThat; 18 import static com.google.common.util.concurrent.ClassPathUtil.parseJavaClassPath; 19 import static com.google.common.util.concurrent.Futures.getChecked; 20 import static com.google.common.util.concurrent.Futures.immediateFuture; 21 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.CHECKED_EXCEPTION; 22 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.ERROR; 23 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.ERROR_FUTURE; 24 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.FAILED_FUTURE_CHECKED_EXCEPTION; 25 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.FAILED_FUTURE_ERROR; 26 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.FAILED_FUTURE_OTHER_THROWABLE; 27 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.FAILED_FUTURE_UNCHECKED_EXCEPTION; 28 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.OTHER_THROWABLE; 29 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.RUNTIME_EXCEPTION; 30 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.RUNTIME_EXCEPTION_FUTURE; 31 import static com.google.common.util.concurrent.FuturesGetCheckedInputs.UNCHECKED_EXCEPTION; 32 import static java.util.concurrent.TimeUnit.SECONDS; 33 import static org.junit.Assert.assertThrows; 34 35 import com.google.common.testing.GcFinalization; 36 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithBadConstructor; 37 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithGoodAndBadConstructor; 38 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithManyConstructors; 39 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithManyConstructorsButOnlyOneThrowable; 40 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithPrivateConstructor; 41 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithSomePrivateConstructors; 42 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithWrongTypesConstructor; 43 import com.google.common.util.concurrent.FuturesGetCheckedInputs.ExceptionWithoutThrowableConstructor; 44 import com.google.common.util.concurrent.FuturesGetCheckedInputs.TwoArgConstructorException; 45 import com.google.common.util.concurrent.FuturesGetCheckedInputs.TwoArgConstructorRuntimeException; 46 import java.lang.ref.WeakReference; 47 import java.net.URLClassLoader; 48 import java.util.concurrent.CancellationException; 49 import java.util.concurrent.Future; 50 import java.util.concurrent.TimeUnit; 51 import java.util.concurrent.TimeoutException; 52 import junit.framework.TestCase; 53 54 /** Unit tests for {@link Futures#getChecked(Future, Class)}. */ 55 public class FuturesGetCheckedTest extends TestCase { 56 // Boring untimed-get tests: 57 testGetCheckedUntimed_success()58 public void testGetCheckedUntimed_success() throws TwoArgConstructorException { 59 assertEquals("foo", getChecked(immediateFuture("foo"), TwoArgConstructorException.class)); 60 } 61 testGetCheckedUntimed_interrupted()62 public void testGetCheckedUntimed_interrupted() { 63 SettableFuture<String> future = SettableFuture.create(); 64 Thread.currentThread().interrupt(); 65 try { 66 getChecked(future, TwoArgConstructorException.class); 67 fail(); 68 } catch (TwoArgConstructorException expected) { 69 assertThat(expected).hasCauseThat().isInstanceOf(InterruptedException.class); 70 assertTrue(Thread.currentThread().isInterrupted()); 71 } finally { 72 Thread.interrupted(); 73 } 74 } 75 testGetCheckedUntimed_cancelled()76 public void testGetCheckedUntimed_cancelled() throws TwoArgConstructorException { 77 SettableFuture<String> future = SettableFuture.create(); 78 future.cancel(true); 79 assertThrows( 80 CancellationException.class, () -> getChecked(future, TwoArgConstructorException.class)); 81 } 82 testGetCheckedUntimed_ExecutionExceptionChecked()83 public void testGetCheckedUntimed_ExecutionExceptionChecked() { 84 TwoArgConstructorException expected = 85 assertThrows( 86 TwoArgConstructorException.class, 87 () -> getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, TwoArgConstructorException.class)); 88 assertThat(expected).hasCauseThat().isEqualTo(CHECKED_EXCEPTION); 89 } 90 testGetCheckedUntimed_ExecutionExceptionUnchecked()91 public void testGetCheckedUntimed_ExecutionExceptionUnchecked() 92 throws TwoArgConstructorException { 93 UncheckedExecutionException expected = 94 assertThrows( 95 UncheckedExecutionException.class, 96 () -> getChecked(FAILED_FUTURE_UNCHECKED_EXCEPTION, TwoArgConstructorException.class)); 97 assertThat(expected).hasCauseThat().isEqualTo(UNCHECKED_EXCEPTION); 98 } 99 testGetCheckedUntimed_ExecutionExceptionError()100 public void testGetCheckedUntimed_ExecutionExceptionError() throws TwoArgConstructorException { 101 ExecutionError expected = 102 assertThrows( 103 ExecutionError.class, 104 () -> getChecked(FAILED_FUTURE_ERROR, TwoArgConstructorException.class)); 105 assertThat(expected).hasCauseThat().isEqualTo(ERROR); 106 } 107 testGetCheckedUntimed_ExecutionExceptionOtherThrowable()108 public void testGetCheckedUntimed_ExecutionExceptionOtherThrowable() { 109 TwoArgConstructorException expected = 110 assertThrows( 111 TwoArgConstructorException.class, 112 () -> getChecked(FAILED_FUTURE_OTHER_THROWABLE, TwoArgConstructorException.class)); 113 assertThat(expected).hasCauseThat().isEqualTo(OTHER_THROWABLE); 114 } 115 testGetCheckedUntimed_RuntimeException()116 public void testGetCheckedUntimed_RuntimeException() throws TwoArgConstructorException { 117 RuntimeException expected = 118 assertThrows( 119 RuntimeException.class, 120 () -> getChecked(RUNTIME_EXCEPTION_FUTURE, TwoArgConstructorException.class)); 121 assertEquals(RUNTIME_EXCEPTION, expected); 122 } 123 testGetCheckedUntimed_Error()124 public void testGetCheckedUntimed_Error() throws TwoArgConstructorException { 125 try { 126 getChecked(ERROR_FUTURE, TwoArgConstructorException.class); 127 } catch (Error expected) { 128 assertEquals(ERROR, expected); 129 return; 130 } 131 fail(); 132 } 133 testGetCheckedUntimed_badExceptionConstructor_failsEvenForSuccessfulInput()134 public void testGetCheckedUntimed_badExceptionConstructor_failsEvenForSuccessfulInput() 135 throws Exception { 136 assertThrows( 137 IllegalArgumentException.class, 138 () -> getChecked(immediateFuture("x"), ExceptionWithBadConstructor.class)); 139 } 140 testGetCheckedUntimed_badExceptionConstructor_wrapsOriginalChecked()141 public void testGetCheckedUntimed_badExceptionConstructor_wrapsOriginalChecked() 142 throws Exception { 143 assertThrows( 144 IllegalArgumentException.class, 145 () -> getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithBadConstructor.class)); 146 } 147 testGetCheckedUntimed_withGoodAndBadExceptionConstructor()148 public void testGetCheckedUntimed_withGoodAndBadExceptionConstructor() throws Exception { 149 ExceptionWithGoodAndBadConstructor expected = 150 assertThrows( 151 ExceptionWithGoodAndBadConstructor.class, 152 () -> 153 getChecked( 154 FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithGoodAndBadConstructor.class)); 155 assertThat(expected).hasCauseThat().isSameInstanceAs(CHECKED_EXCEPTION); 156 } 157 158 // Boring timed-get tests: 159 testGetCheckedTimed_success()160 public void testGetCheckedTimed_success() throws TwoArgConstructorException { 161 assertEquals( 162 "foo", getChecked(immediateFuture("foo"), TwoArgConstructorException.class, 0, SECONDS)); 163 } 164 testGetCheckedTimed_interrupted()165 public void testGetCheckedTimed_interrupted() { 166 SettableFuture<String> future = SettableFuture.create(); 167 Thread.currentThread().interrupt(); 168 try { 169 getChecked(future, TwoArgConstructorException.class, 0, SECONDS); 170 fail(); 171 } catch (TwoArgConstructorException expected) { 172 assertThat(expected).hasCauseThat().isInstanceOf(InterruptedException.class); 173 assertTrue(Thread.currentThread().isInterrupted()); 174 } finally { 175 Thread.interrupted(); 176 } 177 } 178 testGetCheckedTimed_cancelled()179 public void testGetCheckedTimed_cancelled() throws TwoArgConstructorException { 180 SettableFuture<String> future = SettableFuture.create(); 181 future.cancel(true); 182 assertThrows( 183 CancellationException.class, 184 () -> getChecked(future, TwoArgConstructorException.class, 0, SECONDS)); 185 } 186 testGetCheckedTimed_ExecutionExceptionChecked()187 public void testGetCheckedTimed_ExecutionExceptionChecked() { 188 TwoArgConstructorException expected = 189 assertThrows( 190 TwoArgConstructorException.class, 191 () -> 192 getChecked( 193 FAILED_FUTURE_CHECKED_EXCEPTION, TwoArgConstructorException.class, 0, SECONDS)); 194 assertThat(expected).hasCauseThat().isEqualTo(CHECKED_EXCEPTION); 195 } 196 testGetCheckedTimed_ExecutionExceptionUnchecked()197 public void testGetCheckedTimed_ExecutionExceptionUnchecked() throws TwoArgConstructorException { 198 UncheckedExecutionException expected = 199 assertThrows( 200 UncheckedExecutionException.class, 201 () -> 202 getChecked( 203 FAILED_FUTURE_UNCHECKED_EXCEPTION, 204 TwoArgConstructorException.class, 205 0, 206 SECONDS)); 207 assertThat(expected).hasCauseThat().isEqualTo(UNCHECKED_EXCEPTION); 208 } 209 testGetCheckedTimed_ExecutionExceptionError()210 public void testGetCheckedTimed_ExecutionExceptionError() throws TwoArgConstructorException { 211 ExecutionError expected = 212 assertThrows( 213 ExecutionError.class, 214 () -> getChecked(FAILED_FUTURE_ERROR, TwoArgConstructorException.class, 0, SECONDS)); 215 assertThat(expected).hasCauseThat().isEqualTo(ERROR); 216 } 217 testGetCheckedTimed_ExecutionExceptionOtherThrowable()218 public void testGetCheckedTimed_ExecutionExceptionOtherThrowable() { 219 TwoArgConstructorException expected = 220 assertThrows( 221 TwoArgConstructorException.class, 222 () -> 223 getChecked( 224 FAILED_FUTURE_OTHER_THROWABLE, TwoArgConstructorException.class, 0, SECONDS)); 225 assertThat(expected).hasCauseThat().isEqualTo(OTHER_THROWABLE); 226 } 227 testGetCheckedTimed_RuntimeException()228 public void testGetCheckedTimed_RuntimeException() throws TwoArgConstructorException { 229 RuntimeException expected = 230 assertThrows( 231 RuntimeException.class, 232 () -> 233 getChecked(RUNTIME_EXCEPTION_FUTURE, TwoArgConstructorException.class, 0, SECONDS)); 234 assertEquals(RUNTIME_EXCEPTION, expected); 235 } 236 testGetCheckedTimed_Error()237 public void testGetCheckedTimed_Error() throws TwoArgConstructorException { 238 try { 239 getChecked(ERROR_FUTURE, TwoArgConstructorException.class, 0, SECONDS); 240 } catch (Error expected) { 241 assertEquals(ERROR, expected); 242 return; 243 } 244 fail(); 245 } 246 testGetCheckedTimed_TimeoutException()247 public void testGetCheckedTimed_TimeoutException() { 248 SettableFuture<String> future = SettableFuture.create(); 249 TwoArgConstructorException expected = 250 assertThrows( 251 TwoArgConstructorException.class, 252 () -> getChecked(future, TwoArgConstructorException.class, 0, SECONDS)); 253 assertThat(expected).hasCauseThat().isInstanceOf(TimeoutException.class); 254 } 255 testGetCheckedTimed_badExceptionConstructor_failsEvenForSuccessfulInput()256 public void testGetCheckedTimed_badExceptionConstructor_failsEvenForSuccessfulInput() 257 throws Exception { 258 assertThrows( 259 IllegalArgumentException.class, 260 () -> 261 getChecked( 262 immediateFuture("x"), ExceptionWithBadConstructor.class, 1, TimeUnit.SECONDS)); 263 } 264 testGetCheckedTimed_badExceptionConstructor_wrapsOriginalChecked()265 public void testGetCheckedTimed_badExceptionConstructor_wrapsOriginalChecked() throws Exception { 266 assertThrows( 267 IllegalArgumentException.class, 268 () -> 269 getChecked( 270 FAILED_FUTURE_CHECKED_EXCEPTION, 271 ExceptionWithBadConstructor.class, 272 1, 273 TimeUnit.SECONDS)); 274 } 275 testGetCheckedTimed_withGoodAndBadExceptionConstructor()276 public void testGetCheckedTimed_withGoodAndBadExceptionConstructor() { 277 ExceptionWithGoodAndBadConstructor expected = 278 assertThrows( 279 ExceptionWithGoodAndBadConstructor.class, 280 () -> 281 getChecked( 282 FAILED_FUTURE_CHECKED_EXCEPTION, 283 ExceptionWithGoodAndBadConstructor.class, 284 1, 285 TimeUnit.SECONDS)); 286 assertThat(expected).hasCauseThat().isSameInstanceAs(CHECKED_EXCEPTION); 287 } 288 289 // Edge case tests of the exception-construction code through untimed get(): 290 291 @SuppressWarnings("FuturesGetCheckedIllegalExceptionType") testGetCheckedUntimed_exceptionClassIsRuntimeException()292 public void testGetCheckedUntimed_exceptionClassIsRuntimeException() { 293 assertThrows( 294 IllegalArgumentException.class, 295 () -> getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, TwoArgConstructorRuntimeException.class)); 296 } 297 testGetCheckedUntimed_exceptionClassSomePrivateConstructors()298 public void testGetCheckedUntimed_exceptionClassSomePrivateConstructors() { 299 assertThrows( 300 ExceptionWithSomePrivateConstructors.class, 301 () -> 302 getChecked( 303 FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithSomePrivateConstructors.class)); 304 } 305 306 @SuppressWarnings("FuturesGetCheckedIllegalExceptionType") testGetCheckedUntimed_exceptionClassNoPublicConstructor()307 public void testGetCheckedUntimed_exceptionClassNoPublicConstructor() 308 throws ExceptionWithPrivateConstructor { 309 assertThrows( 310 IllegalArgumentException.class, 311 () -> getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithPrivateConstructor.class)); 312 } 313 314 @SuppressWarnings("FuturesGetCheckedIllegalExceptionType") testGetCheckedUntimed_exceptionClassPublicConstructorWrongType()315 public void testGetCheckedUntimed_exceptionClassPublicConstructorWrongType() 316 throws ExceptionWithWrongTypesConstructor { 317 assertThrows( 318 IllegalArgumentException.class, 319 () -> 320 getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithWrongTypesConstructor.class)); 321 } 322 testGetCheckedUntimed_exceptionClassPrefersStringConstructor()323 public void testGetCheckedUntimed_exceptionClassPrefersStringConstructor() { 324 ExceptionWithManyConstructors expected = 325 assertThrows( 326 ExceptionWithManyConstructors.class, 327 () -> getChecked(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithManyConstructors.class)); 328 assertTrue(expected.usedExpectedConstructor); 329 } 330 testGetCheckedUntimed_exceptionClassUsedInitCause()331 public void testGetCheckedUntimed_exceptionClassUsedInitCause() { 332 ExceptionWithoutThrowableConstructor expected = 333 assertThrows( 334 ExceptionWithoutThrowableConstructor.class, 335 () -> 336 getChecked( 337 FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithoutThrowableConstructor.class)); 338 assertThat(expected).hasMessageThat().contains("mymessage"); 339 assertThat(expected).hasCauseThat().isEqualTo(CHECKED_EXCEPTION); 340 } 341 testPrefersConstructorWithThrowableParameter()342 public void testPrefersConstructorWithThrowableParameter() { 343 ExceptionWithManyConstructorsButOnlyOneThrowable exception = 344 assertThrows( 345 ExceptionWithManyConstructorsButOnlyOneThrowable.class, 346 () -> 347 getChecked( 348 FAILED_FUTURE_CHECKED_EXCEPTION, 349 ExceptionWithManyConstructorsButOnlyOneThrowable.class)); 350 assertThat(exception).hasMessageThat().contains("mymessage"); 351 assertThat(exception.getAntecedent()).isEqualTo(CHECKED_EXCEPTION); 352 } 353 354 // Class unloading test: 355 356 public static final class WillBeUnloadedException extends Exception {} 357 358 @AndroidIncompatible // "Parent ClassLoader may not be null"; maybe avoidable if we try? testGetChecked_classUnloading()359 public void testGetChecked_classUnloading() throws Exception { 360 WeakReference<?> classUsedByGetChecked = doTestClassUnloading(); 361 GcFinalization.awaitClear(classUsedByGetChecked); 362 } 363 364 /** 365 * Loads {@link WillBeUnloadedException} in a separate {@code ClassLoader}, calls {@code 366 * getChecked(future, WillBeUnloadedException.class)}, and returns the loader. The caller can then 367 * test that the {@code ClassLoader} can still be GCed. The test amounts to a test that {@code 368 * getChecked} holds no strong references to the class. 369 */ doTestClassUnloading()370 private WeakReference<?> doTestClassUnloading() throws Exception { 371 URLClassLoader shadowLoader = new URLClassLoader(parseJavaClassPath(), null); 372 @SuppressWarnings("unchecked") 373 Class<WillBeUnloadedException> shadowClass = 374 (Class<WillBeUnloadedException>) 375 Class.forName(WillBeUnloadedException.class.getName(), false, shadowLoader); 376 assertNotSame(shadowClass, WillBeUnloadedException.class); 377 getChecked(immediateFuture("foo"), shadowClass); 378 return new WeakReference<>(shadowLoader); 379 } 380 381 /* 382 * TODO(cpovirk): It would be great to run all these tests (including class unloading) in an 383 * environment that forces Futures.getChecked to its fallback WeakSetValidator. One awful way of 384 * doing so would be to derive a separate test library by using remove_from_jar to strip out 385 * ClassValueValidator. 386 * 387 * Fortunately, we get pretty good coverage "by accident": We run all these tests against the 388 * *backport*, where ClassValueValidator is not present. 389 */ 390 } 391