diff options
Diffstat (limited to 'guava-tests/test/com/google/common/util/concurrent/FuturesTest.java')
-rw-r--r-- | guava-tests/test/com/google/common/util/concurrent/FuturesTest.java | 693 |
1 files changed, 137 insertions, 556 deletions
diff --git a/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java b/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java index 44e759b..ea9a3da 100644 --- a/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java +++ b/guava-tests/test/com/google/common/util/concurrent/FuturesTest.java @@ -23,12 +23,10 @@ import static com.google.common.util.concurrent.Futures.getUnchecked; import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static com.google.common.util.concurrent.Futures.successfulAsList; -import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.easymock.EasyMock.expect; -import static org.truth0.Truth.ASSERT; +import static org.junit.contrib.truth.Truth.ASSERT; import com.google.common.base.Function; import com.google.common.base.Functions; @@ -37,7 +35,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import com.google.common.testing.ClassSanityTester; +import com.google.common.testing.NullPointerTester; import com.google.common.util.concurrent.ForwardingFuture.SimpleForwardingFuture; import junit.framework.AssertionFailedError; @@ -56,12 +54,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.logging.Handler; -import java.util.logging.LogRecord; import javax.annotation.Nullable; @@ -127,27 +122,6 @@ public class FuturesTest extends TestCase { } } - public void testImmediateFailedFuture_cancellationException() throws Exception { - CancellationException exception = new CancellationException(); - ListenableFuture<String> future = - Futures.immediateFailedFuture(exception); - - try { - future.get(0L, TimeUnit.MILLISECONDS); - fail("This call was supposed to throw an ExecutionException"); - } catch (ExecutionException expected) { - // This is good and expected - assertSame(exception, expected.getCause()); - assertFalse(future.isCancelled()); - } - } - - public void testImmediateCancelledFuture() throws Exception { - ListenableFuture<String> future = - Futures.immediateCancelledFuture(); - assertTrue(future.isCancelled()); - } - private static class MyException extends Exception {} public void testImmediateCheckedFuture() throws Exception { @@ -220,61 +194,6 @@ public class FuturesTest extends TestCase { assertSame(barChild, bar); } - public void testTransform_ListenableFuture_cancelPropagatesToInput() throws Exception { - SettableFuture<Foo> input = SettableFuture.create(); - AsyncFunction<Foo, Bar> function = new AsyncFunction<Foo, Bar>() { - @Override public ListenableFuture<Bar> apply(Foo unused) { - fail("Unexpeted call to apply."); - return null; - } - }; - assertTrue(Futures.transform(input, function).cancel(false)); - assertTrue(input.isCancelled()); - assertFalse(input.wasInterrupted()); - } - - public void testTransform_ListenableFuture_interruptPropagatesToInput() - throws Exception { - SettableFuture<Foo> input = SettableFuture.create(); - AsyncFunction<Foo, Bar> function = new AsyncFunction<Foo, Bar>() { - @Override public ListenableFuture<Bar> apply(Foo unused) { - fail("Unexpeted call to apply."); - return null; - } - }; - assertTrue(Futures.transform(input, function).cancel(true)); - assertTrue(input.isCancelled()); - assertTrue(input.wasInterrupted()); - } - - public void testTransform_ListenableFuture_cancelPropagatesToAsyncOutput() - throws Exception { - ListenableFuture<Foo> immediate = Futures.immediateFuture(new Foo()); - final SettableFuture<Bar> secondary = SettableFuture.create(); - AsyncFunction<Foo, Bar> function = new AsyncFunction<Foo, Bar>() { - @Override public ListenableFuture<Bar> apply(Foo unused) { - return secondary; - } - }; - assertTrue(Futures.transform(immediate, function).cancel(false)); - assertTrue(secondary.isCancelled()); - assertFalse(secondary.wasInterrupted()); - } - - public void testTransform_ListenableFuture_interruptPropagatesToAsyncOutput() - throws Exception { - ListenableFuture<Foo> immediate = Futures.immediateFuture(new Foo()); - final SettableFuture<Bar> secondary = SettableFuture.create(); - AsyncFunction<Foo, Bar> function = new AsyncFunction<Foo, Bar>() { - @Override public ListenableFuture<Bar> apply(Foo unused) { - return secondary; - } - }; - assertTrue(Futures.transform(immediate, function).cancel(true)); - assertTrue(secondary.isCancelled()); - assertTrue(secondary.wasInterrupted()); - } - /** * {@link ListenableFuture} variant of * {@link #testTransformValueRemainsMemoized_Future()}. @@ -463,28 +382,6 @@ public class FuturesTest extends TestCase { assertEquals(2, spy.getApplyCount()); } - public void testLazyTransform_exception() throws Exception { - final RuntimeException exception = new RuntimeException("deliberate"); - Function<Integer, String> function = new Function<Integer, String>() { - @Override public String apply(Integer input) { - throw exception; - } - }; - Future<String> transformed = Futures.lazyTransform(Futures.immediateFuture(1), function); - try { - transformed.get(); - fail(); - } catch (ExecutionException expected) { - assertSame(exception, expected.getCause()); - } - try { - transformed.get(1, TimeUnit.SECONDS); - fail(); - } catch (ExecutionException expected) { - assertSame(exception, expected.getCause()); - } - } - private static class FunctionSpy<I, O> implements Function<I, O> { private int applyCount; private final Function<I, O> delegate; @@ -504,150 +401,6 @@ public class FuturesTest extends TestCase { } } - @SuppressWarnings("unchecked") - public void testWithFallback_inputDoesNotRaiseException() throws Exception { - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - ListenableFuture<Integer> originalFuture = Futures.immediateFuture(7); - - mocksControl.replay(); - ListenableFuture<Integer> faultToleranteFuture = Futures.withFallback(originalFuture, fallback); - assertEquals(7, faultToleranteFuture.get().intValue()); - mocksControl.verify(); - } - - @SuppressWarnings("unchecked") - public void testWithFallback_inputRaisesException() throws Exception { - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - RuntimeException raisedException = new RuntimeException(); - expect(fallback.create(raisedException)).andReturn(Futures.immediateFuture(20)); - ListenableFuture<Integer> failingFuture = Futures.immediateFailedFuture(raisedException); - - mocksControl.replay(); - ListenableFuture<Integer> faultToleranteFuture = Futures.withFallback(failingFuture, fallback); - assertEquals(20, faultToleranteFuture.get().intValue()); - mocksControl.verify(); - } - - public void testWithFallback_fallbackGeneratesRuntimeException() throws Exception { - RuntimeException expectedException = new RuntimeException(); - runExpectedExceptionFallbackTest(expectedException, false); - } - - public void testWithFallback_fallbackGeneratesCheckedException() throws Exception { - Exception expectedException = new Exception() {}; - runExpectedExceptionFallbackTest(expectedException, false); - } - - @SuppressWarnings("unchecked") - public void testWithFallback_fallbackGeneratesError() throws Exception { - Error error = new Error("deliberate"); - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - RuntimeException raisedException = new RuntimeException(); - expect(fallback.create(raisedException)).andThrow(error); - ListenableFuture<Integer> failingFuture = Futures.immediateFailedFuture(raisedException); - mocksControl.replay(); - try { - Futures.withFallback(failingFuture, fallback); - fail("An Exception should have been thrown!"); - } catch (Error expected) { - assertSame(error, expected); - } - mocksControl.verify(); - } - - public void testWithFallback_fallbackReturnsRuntimeException() throws Exception { - RuntimeException expectedException = new RuntimeException(); - runExpectedExceptionFallbackTest(expectedException, true); - } - - public void testWithFallback_fallbackReturnsCheckedException() throws Exception { - Exception expectedException = new Exception() {}; - runExpectedExceptionFallbackTest(expectedException, true); - } - - @SuppressWarnings("unchecked") - private void runExpectedExceptionFallbackTest( - Throwable expectedException, boolean wrapInFuture) throws Exception { - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - RuntimeException raisedException = new RuntimeException(); - if (!wrapInFuture) { - // Exception is thrown in the body of the "fallback" method. - expect(fallback.create(raisedException)).andThrow(expectedException); - } else { - // Exception is wrapped in a future and returned. - expect(fallback.create(raisedException)).andReturn( - Futures.<Integer>immediateFailedFuture(expectedException)); - } - - ListenableFuture<Integer> failingFuture = Futures.immediateFailedFuture(raisedException); - - mocksControl.replay(); - ListenableFuture<Integer> faultToleranteFuture = Futures.withFallback(failingFuture, fallback); - try { - faultToleranteFuture.get(); - fail("An Exception should have been thrown!"); - } catch (ExecutionException ee) { - assertSame(expectedException, ee.getCause()); - } - mocksControl.verify(); - } - - public void testWithFallback_fallbackNotReady() throws Exception { - ListenableFuture<Integer> primary = immediateFailedFuture(new Exception()); - final SettableFuture<Integer> secondary = SettableFuture.create(); - FutureFallback<Integer> fallback = new FutureFallback<Integer>() { - @Override - public ListenableFuture<Integer> create(Throwable t) { - return secondary; - } - }; - ListenableFuture<Integer> derived = Futures.withFallback(primary, fallback); - secondary.set(1); - assertEquals(1, (int) derived.get()); - } - - @SuppressWarnings("unchecked") - public void testWithFallback_resultInterruptedBeforeFallback() throws Exception { - SettableFuture<Integer> primary = SettableFuture.create(); - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - - mocksControl.replay(); - ListenableFuture<Integer> derived = Futures.withFallback(primary, fallback); - derived.cancel(true); - assertTrue(primary.isCancelled()); - assertTrue(primary.wasInterrupted()); - mocksControl.verify(); - } - - @SuppressWarnings("unchecked") - public void testWithFallback_resultCancelledBeforeFallback() throws Exception { - SettableFuture<Integer> primary = SettableFuture.create(); - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - - mocksControl.replay(); - ListenableFuture<Integer> derived = Futures.withFallback(primary, fallback); - derived.cancel(false); - assertTrue(primary.isCancelled()); - assertFalse(primary.wasInterrupted()); - mocksControl.verify(); - } - - @SuppressWarnings("unchecked") - public void testWithFallback_resultCancelledAfterFallback() throws Exception { - SettableFuture<Integer> secondary = SettableFuture.create(); - FutureFallback<Integer> fallback = mocksControl.createMock(FutureFallback.class); - RuntimeException raisedException = new RuntimeException(); - expect(fallback.create(raisedException)).andReturn(secondary); - ListenableFuture<Integer> failingFuture = Futures.immediateFailedFuture(raisedException); - - mocksControl.replay(); - ListenableFuture<Integer> derived = Futures.withFallback(failingFuture, fallback); - derived.cancel(false); - assertTrue(secondary.isCancelled()); - assertFalse(secondary.wasInterrupted()); - mocksControl.verify(); - } - public void testTransform_genericsWildcard_AsyncFunction() throws Exception { ListenableFuture<?> nullFuture = Futures.immediateFuture(null); ListenableFuture<?> chainedFuture = @@ -680,108 +433,74 @@ public class FuturesTest extends TestCase { assertSame(barChild, bar); } - public void testTransform_asyncFunction_timeout() - throws InterruptedException, ExecutionException { - AsyncFunction<String, Integer> function = constantAsyncFunction(Futures.immediateFuture(1)); - ListenableFuture<Integer> future = Futures.transform( - SettableFuture.<String>create(), function); - try { - future.get(1, TimeUnit.MILLISECONDS); - fail(); - } catch (TimeoutException expected) {} + public void testTransform_delegatesBlockingGet_AsyncFunction() throws Exception { + performAsyncFunctionTransformedFutureDelgationTest(0, null); } - public void testTransform_asyncFunction_error() { - final Error error = new Error("deliberate"); - AsyncFunction<String, Integer> function = new AsyncFunction<String, Integer>() { - @Override public ListenableFuture<Integer> apply(String input) { - throw error; - } - }; - SettableFuture<String> inputFuture = SettableFuture.create(); - Futures.transform(inputFuture, function); - try { - inputFuture.set("value"); - } catch (Error expected) { - assertSame(error, expected); - return; - } - fail("should have thrown error"); - } - - public void testTransform_asyncFunction_cancelledWhileApplyingFunction() - throws InterruptedException, ExecutionException { - final CountDownLatch inFunction = new CountDownLatch(1); - final CountDownLatch functionDone = new CountDownLatch(1); - final SettableFuture<Integer> resultFuture = SettableFuture.create(); - AsyncFunction<String, Integer> function = new AsyncFunction<String, Integer>() { - @Override public ListenableFuture<Integer> apply(String input) throws Exception { - inFunction.countDown(); - functionDone.await(); - return resultFuture; - } - }; - SettableFuture<String> inputFuture = SettableFuture.create(); - ListenableFuture<Integer> future = Futures.transform( - inputFuture, function, Executors.newSingleThreadExecutor()); - inputFuture.set("value"); - inFunction.await(); - future.cancel(false); - functionDone.countDown(); - try { - future.get(); - fail(); - } catch (CancellationException expected) {} - try { - resultFuture.get(); - fail(); - } catch (CancellationException expected) {} + public void testTransform_delegatesTimedGet_AsyncFunction() throws Exception { + performAsyncFunctionTransformedFutureDelgationTest(25, TimeUnit.SECONDS); } - public void testDereference_genericsWildcard() throws Exception { - ListenableFuture<?> inner = Futures.immediateFuture(null); - ListenableFuture<ListenableFuture<?>> outer = - Futures.<ListenableFuture<?>>immediateFuture(inner); - ListenableFuture<?> dereferenced = Futures.dereference(outer); - assertNull(dereferenced.get()); - } + private void performAsyncFunctionTransformedFutureDelgationTest( + long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + final Foo foo = new Foo(); + MockRequiresGetCallFuture<Foo> fooFuture = + new MockRequiresGetCallFuture<Foo>(foo); + + Bar bar = new Bar(); + final MockRequiresGetCallFuture<Bar> barFuture = + new MockRequiresGetCallFuture<Bar>(bar); + AsyncFunction<Foo, Bar> function = + new AsyncFunction<Foo, Bar>() { + @Override public ListenableFuture<Bar> apply(Foo from) { + assertSame(foo, from); + return barFuture; + } + }; - public void testDereference_genericsHierarchy() throws Exception { - FooChild fooChild = new FooChild(); - ListenableFuture<FooChild> inner = Futures.immediateFuture(fooChild); - ListenableFuture<ListenableFuture<FooChild>> outer = Futures.immediateFuture(inner); - ListenableFuture<Foo> dereferenced = Futures.<Foo>dereference(outer); - assertSame(fooChild, dereferenced.get()); + ListenableFuture<Bar> chainFuture = Futures.transform(fooFuture, function); + Bar theBar; + if (unit != null) { + theBar = chainFuture.get(timeout, unit); + } else { + theBar = chainFuture.get(); + } + assertSame(bar, theBar); + assertTrue(fooFuture.getWasGetCalled()); + assertTrue(barFuture.getWasGetCalled()); } - public void testDereference_resultCancelsOuter() throws Exception { - ListenableFuture<ListenableFuture<Foo>> outer = SettableFuture.create(); - ListenableFuture<Foo> dereferenced = Futures.dereference(outer); - dereferenced.cancel(true); - assertTrue(outer.isCancelled()); - } + /** + * A mock listenable future that requires the caller invoke + * either form of get() before the future will make its value + * available or invoke listeners. + */ + private static class MockRequiresGetCallFuture<T> extends AbstractFuture<T> { - public void testDereference_resultCancelsInner() throws Exception { - ListenableFuture<Foo> inner = SettableFuture.create(); - ListenableFuture<ListenableFuture<Foo>> outer = Futures.immediateFuture(inner); - ListenableFuture<Foo> dereferenced = Futures.dereference(outer); - dereferenced.cancel(true); - assertTrue(inner.isCancelled()); - } + private final T value; + private boolean getWasCalled; - public void testDereference_outerCancelsResult() throws Exception { - ListenableFuture<ListenableFuture<Foo>> outer = SettableFuture.create(); - ListenableFuture<Foo> dereferenced = Futures.dereference(outer); - outer.cancel(true); - assertTrue(dereferenced.isCancelled()); - } + MockRequiresGetCallFuture(T value) { + this.value = value; + } - public void testDereference_innerCancelsResult() throws Exception { - ListenableFuture<Foo> inner = SettableFuture.create(); - ListenableFuture<ListenableFuture<Foo>> outer = Futures.immediateFuture(inner); - ListenableFuture<Foo> dereferenced = Futures.dereference(outer); - inner.cancel(true); - assertTrue(dereferenced.isCancelled()); + @Override public T get() throws InterruptedException, ExecutionException { + set(value); + getWasCalled = true; + return super.get(); + } + + @Override public T get(long timeout, TimeUnit unit) + throws TimeoutException, ExecutionException, InterruptedException { + set(value); + getWasCalled = true; + return super.get(timeout, unit); + } + + boolean getWasGetCalled() { + return getWasCalled; + } } /** @@ -840,7 +559,7 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(DATA1, DATA2, DATA3).inOrder(); + ASSERT.that(results).hasContentsInOrder(DATA1, DATA2, DATA3); } public void testAllAsList_emptyList() throws Exception { @@ -916,27 +635,6 @@ public class FuturesTest extends TestCase { } } - public void testAllAsList_error() throws Exception { - Error error = new Error("deliberate"); - SettableFuture<String> future1 = SettableFuture.create(); - ListenableFuture<String> future2 = Futures.immediateFuture("results"); - ListenableFuture<List<String>> compound = Futures.allAsList(ImmutableList.of(future1, future2)); - - try { - future1.setException(error); - } catch (Error expected) { - assertSame(error, expected); - try { - compound.get(); - } catch (ExecutionException ee) { - assertSame(error, ee.getCause()); - return; - } - fail("Expected error not set in compound future."); - } - fail("Expected error not thrown"); - } - public void testAllAsList_cancelled() throws Exception { SingleCallListener listener = new SingleCallListener(); SettableFuture<String> future1 = SettableFuture.create(); @@ -960,34 +658,22 @@ public class FuturesTest extends TestCase { } } - public void testAllAsList_resultCancelled() throws Exception { - SettableFuture<String> future1 = SettableFuture.create(); - SettableFuture<String> future2 = SettableFuture.create(); - @SuppressWarnings("unchecked") // array is never modified - ListenableFuture<List<String>> compound = - Futures.allAsList(future1, future2); - - future2.set(DATA2); - assertFalse(compound.isDone()); - assertTrue(compound.cancel(false)); - assertTrue(compound.isCancelled()); - assertTrue(future1.isCancelled()); - assertFalse(future1.wasInterrupted()); - } + public void testAllAsList_buggyInputFutures() throws Exception { + final Foo foo1 = new Foo(); + MockRequiresGetCallFuture<Foo> foo1Future = + new MockRequiresGetCallFuture<Foo>(foo1); + final Foo foo2 = new Foo(); + MockRequiresGetCallFuture<Foo> foo2Future = + new MockRequiresGetCallFuture<Foo>(foo2); - public void testAllAsList_resultInterrupted() throws Exception { - SettableFuture<String> future1 = SettableFuture.create(); - SettableFuture<String> future2 = SettableFuture.create(); @SuppressWarnings("unchecked") // array is never modified - ListenableFuture<List<String>> compound = - Futures.allAsList(future1, future2); + ListenableFuture<List<Foo>> compound = + Futures.allAsList(foo1Future, foo2Future); - future2.set(DATA2); assertFalse(compound.isDone()); - assertTrue(compound.cancel(true)); - assertTrue(compound.isCancelled()); - assertTrue(future1.isCancelled()); - assertTrue(future1.wasInterrupted()); + ASSERT.that(compound.get()).hasContentsAnyOrder(foo1, foo2); + assertTrue(foo1Future.getWasGetCalled()); + assertTrue(foo2Future.getWasGetCalled()); } /** @@ -1021,10 +707,10 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(DATA1, DATA2, DATA3).inOrder(); + ASSERT.that(results).hasContentsInOrder(DATA1, DATA2, DATA3); } - private static String createCombinedResult(Integer i, Boolean b) { + private String createCombinedResult(Integer i, Boolean b) { return "-" + i + "-" + b; } @@ -1441,7 +1127,7 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(DATA1, DATA2, DATA3).inOrder(); + ASSERT.that(results).hasContentsInOrder(DATA1, DATA2, DATA3); } public void testSuccessfulAsList_emptyList() throws Exception { @@ -1484,7 +1170,7 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(null, DATA2).inOrder(); + ASSERT.that(results).hasContentsInOrder(null, DATA2); } public void testSuccessfulAsList_totalFailure() throws Exception { @@ -1505,7 +1191,7 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(null, null).inOrder(); + ASSERT.that(results).hasContentsInOrder(null, null); } public void testSuccessfulAsList_cancelled() throws Exception { @@ -1526,108 +1212,7 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(null, DATA2).inOrder(); - } - - public void testSuccessfulAsList_resultCancelled() throws Exception { - SettableFuture<String> future1 = SettableFuture.create(); - SettableFuture<String> future2 = SettableFuture.create(); - @SuppressWarnings("unchecked") // array is never modified - ListenableFuture<List<String>> compound = - Futures.successfulAsList(future1, future2); - - future2.set(DATA2); - assertFalse(compound.isDone()); - assertTrue(compound.cancel(false)); - assertTrue(compound.isCancelled()); - assertTrue(future1.isCancelled()); - assertFalse(future1.wasInterrupted()); - } - - public void testSuccessfulAsList_resultCancelledRacingInputDone() - throws Exception { - /* - * The IllegalStateException that we're testing for is caught by - * ExecutionList and logged rather than allowed to propagate. We need to - * turn that back into a failure. - */ - Handler throwingHandler = new Handler() { - @Override public void publish(@Nullable LogRecord record) { - AssertionFailedError error = new AssertionFailedError(); - error.initCause(record.getThrown()); - throw error; - } - - @Override public void flush() {} - - @Override public void close() {} - }; - - ExecutionList.log.addHandler(throwingHandler); - try { - doTestSuccessfulAsList_resultCancelledRacingInputDone(); - } finally { - ExecutionList.log.removeHandler(throwingHandler); - } - } - - private static void doTestSuccessfulAsList_resultCancelledRacingInputDone() - throws Exception { - // Simple (combined.cancel -> input.cancel -> setOneValue): - Futures.successfulAsList(ImmutableList.of(SettableFuture.create())) - .cancel(true); - - /* - * Complex (combined.cancel -> input.cancel -> other.set -> setOneValue), - * to show that this isn't just about problems with the input future we just - * cancelled: - */ - final SettableFuture<String> future1 = SettableFuture.create(); - final SettableFuture<String> future2 = SettableFuture.create(); - @SuppressWarnings("unchecked") // array is never modified - ListenableFuture<List<String>> compound = - Futures.successfulAsList(future1, future2); - - future1.addListener(new Runnable() { - @Override public void run() { - assertTrue(future1.isCancelled()); - /* - * This test relies on behavior that's unspecified but currently - * guaranteed by the implementation: Cancellation of inputs is - * performed in the order they were provided to the constructor. Verify - * that as a sanity check: - */ - assertFalse(future2.isCancelled()); - // Now attempt to trigger the exception: - future2.set(DATA2); - } - }, sameThreadExecutor()); - assertTrue(compound.cancel(false)); - assertTrue(compound.isCancelled()); - assertTrue(future1.isCancelled()); - assertFalse(future2.isCancelled()); - - try { - compound.get(); - fail("Expected exception not thrown"); - } catch (CancellationException e) { - // Expected - } - } - - public void testSuccessfulAsList_resultInterrupted() throws Exception { - SettableFuture<String> future1 = SettableFuture.create(); - SettableFuture<String> future2 = SettableFuture.create(); - @SuppressWarnings("unchecked") // array is never modified - ListenableFuture<List<String>> compound = - Futures.successfulAsList(future1, future2); - - future2.set(DATA2); - assertFalse(compound.isDone()); - assertTrue(compound.cancel(true)); - assertTrue(compound.isCancelled()); - assertTrue(future1.isCancelled()); - assertTrue(future1.wasInterrupted()); + ASSERT.that(results).hasContentsInOrder(null, DATA2); } public void testSuccessfulAsList_mixed() throws Exception { @@ -1652,7 +1237,25 @@ public class FuturesTest extends TestCase { assertTrue(listener.wasCalled()); List<String> results = compound.get(); - ASSERT.that(results).has().allOf(null, null, DATA3).inOrder(); + ASSERT.that(results).hasContentsInOrder(null, null, DATA3); + } + + public void testSuccessfulAsList_buggyInputFutures() throws Exception { + final Foo foo1 = new Foo(); + MockRequiresGetCallFuture<Foo> foo1Future = + new MockRequiresGetCallFuture<Foo>(foo1); + final Foo foo2 = new Foo(); + MockRequiresGetCallFuture<Foo> foo2Future = + new MockRequiresGetCallFuture<Foo>(foo2); + + @SuppressWarnings("unchecked") // array is never modified + ListenableFuture<List<Foo>> compound = + Futures.successfulAsList(foo1Future, foo2Future); + + assertFalse(compound.isDone()); + ASSERT.that(compound.get()).hasContentsAnyOrder(foo1, foo2); + assertTrue(foo1Future.getWasGetCalled()); + assertTrue(foo2Future.getWasGetCalled()); } private static class TestException extends Exception { @@ -1882,8 +1485,20 @@ public class FuturesTest extends TestCase { private static final Future<String> FAILED_FUTURE_OTHER_THROWABLE = immediateFailedFuture(OTHER_THROWABLE); private static final Error ERROR = new Error("mymessage"); - private static final Future<String> FAILED_FUTURE_ERROR = - immediateFailedFuture(ERROR); + private static final Future<String> FAILED_FUTURE_ERROR; + /* + * We can't write "= immediateFailedFuture(ERROR)" because setException + * rethrows the error.... + */ + static { + SettableFuture<String> f = SettableFuture.create(); + try { + f.setException(ERROR); + } catch (Error e) { + assertEquals(e, ERROR); + } + FAILED_FUTURE_ERROR = f; + } private static final Future<String> RUNTIME_EXCEPTION_FUTURE = new SimpleForwardingFuture<String>(FAILED_FUTURE_CHECKED_EXCEPTION) { @Override public String get() { @@ -1904,10 +1519,9 @@ public class FuturesTest extends TestCase { } public void testGetUntimed_interrupted() { - SettableFuture<String> future = SettableFuture.create(); Thread.currentThread().interrupt(); try { - get(future, TwoArgConstructorException.class); + get(immediateFuture("foo"), TwoArgConstructorException.class); fail(); } catch (TwoArgConstructorException expected) { assertTrue(expected.getCause() instanceof InterruptedException); @@ -1976,24 +1590,6 @@ public class FuturesTest extends TestCase { } } - public void testGetUntimed_badExceptionConstructor_wrapsOriginalChecked() throws Exception { - try { - get(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithBadConstructor.class); - fail(); - } catch (IllegalArgumentException expected) { - assertSame(CHECKED_EXCEPTION, expected.getCause()); - } - } - - public void testGetUntimed_withGoodAndBadExceptionConstructor() throws Exception { - try { - get(FAILED_FUTURE_CHECKED_EXCEPTION, ExceptionWithGoodAndBadConstructor.class); - fail(); - } catch (ExceptionWithGoodAndBadConstructor expected) { - assertSame(CHECKED_EXCEPTION, expected.getCause()); - } - } - // Boring timed-get tests: public void testGetTimed_success() @@ -2003,10 +1599,9 @@ public class FuturesTest extends TestCase { } public void testGetTimed_interrupted() { - SettableFuture<String> future = SettableFuture.create(); Thread.currentThread().interrupt(); try { - get(future, 0, SECONDS, TwoArgConstructorException.class); + get(immediateFuture("foo"), 0, SECONDS, TwoArgConstructorException.class); fail(); } catch (TwoArgConstructorException expected) { assertTrue(expected.getCause() instanceof InterruptedException); @@ -2089,25 +1684,6 @@ public class FuturesTest extends TestCase { } } - public void testGetTimed_badExceptionConstructor_wrapsOriginalChecked() throws Exception { - try { - get(FAILED_FUTURE_CHECKED_EXCEPTION, 1, TimeUnit.SECONDS, ExceptionWithBadConstructor.class); - fail(); - } catch (IllegalArgumentException expected) { - assertSame(CHECKED_EXCEPTION, expected.getCause()); - } - } - - public void testGetTimed_withGoodAndBadExceptionConstructor() throws Exception { - try { - get(FAILED_FUTURE_CHECKED_EXCEPTION, 1, TimeUnit.SECONDS, - ExceptionWithGoodAndBadConstructor.class); - fail(); - } catch (ExceptionWithGoodAndBadConstructor expected) { - assertSame(CHECKED_EXCEPTION, expected.getCause()); - } - } - // Boring getUnchecked tests: public void testGetUnchecked_success() { @@ -2331,26 +1907,31 @@ public class FuturesTest extends TestCase { } } - private static final class ExceptionWithGoodAndBadConstructor extends Exception { - public ExceptionWithGoodAndBadConstructor(String message, Throwable cause) { - throw new RuntimeException("bad constructor"); - } - public ExceptionWithGoodAndBadConstructor(Throwable cause) { - super(cause); - } - } + public void testNullArguments() throws Exception { + NullPointerTester tester = new NullPointerTester(); + tester.setDefault(ListenableFuture.class, Futures.immediateFuture(DATA1)); + tester.setDefault(ListenableFuture[].class, + new ListenableFuture[] {Futures.immediateFuture(DATA1)}); + tester.setDefault(Future.class, Futures.immediateFuture(DATA1)); + tester.setDefault(Executor.class, MoreExecutors.sameThreadExecutor()); + tester.setDefault(Callable.class, Callables.returning(null)); + tester.setDefault(AsyncFunction.class, new AsyncFunction() { + @Override + public ListenableFuture apply(Object input) throws Exception { + return immediateFuture(DATA1); + } + }); - private static final class ExceptionWithBadConstructor extends Exception { - public ExceptionWithBadConstructor(String message, Throwable cause) { - throw new RuntimeException("bad constructor"); - } - } + FutureCallback<Object> callback = + new FutureCallback<Object>() { + @Override + public void onSuccess(Object result) {} + @Override + public void onFailure(Throwable t) {} + }; + tester.setDefault(FutureCallback.class, callback); - public void testFutures_nullChecks() throws Exception { - new ClassSanityTester() - .forAllPublicStaticMethods(Futures.class) - .thatReturn(Future.class) - .testNulls(); + tester.testAllPublicStaticMethods(Futures.class); } private static void failWithCause(Throwable cause, String message) { |