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