• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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