1 /* 2 * Copyright (C) 2011 The Guava Authors 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.google.common.util.concurrent; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.util.concurrent.Futures.addCallback; 21 import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 22 23 import com.google.common.annotations.GwtCompatible; 24 import java.util.concurrent.CancellationException; 25 import java.util.concurrent.Executor; 26 import junit.framework.TestCase; 27 import org.checkerframework.checker.nullness.qual.Nullable; 28 29 /** 30 * Test for {@link FutureCallback}. 31 * 32 * @author Anthony Zana 33 */ 34 @GwtCompatible 35 public class FutureCallbackTest extends TestCase { testSameThreadSuccess()36 public void testSameThreadSuccess() { 37 SettableFuture<String> f = SettableFuture.create(); 38 MockCallback callback = new MockCallback("foo"); 39 addCallback(f, callback, directExecutor()); 40 f.set("foo"); 41 } 42 testExecutorSuccess()43 public void testExecutorSuccess() { 44 CountingSameThreadExecutor ex = new CountingSameThreadExecutor(); 45 SettableFuture<String> f = SettableFuture.create(); 46 MockCallback callback = new MockCallback("foo"); 47 Futures.addCallback(f, callback, ex); 48 f.set("foo"); 49 assertEquals(1, ex.runCount); 50 } 51 52 // Error cases testSameThreadExecutionException()53 public void testSameThreadExecutionException() { 54 SettableFuture<String> f = SettableFuture.create(); 55 Exception e = new IllegalArgumentException("foo not found"); 56 MockCallback callback = new MockCallback(e); 57 addCallback(f, callback, directExecutor()); 58 f.setException(e); 59 } 60 testCancel()61 public void testCancel() { 62 SettableFuture<String> f = SettableFuture.create(); 63 FutureCallback<String> callback = 64 new FutureCallback<String>() { 65 private boolean called = false; 66 67 @Override 68 public void onSuccess(String result) { 69 fail("Was not expecting onSuccess() to be called."); 70 } 71 72 @Override 73 public synchronized void onFailure(Throwable t) { 74 assertFalse(called); 75 assertThat(t).isInstanceOf(CancellationException.class); 76 called = true; 77 } 78 }; 79 addCallback(f, callback, directExecutor()); 80 f.cancel(true); 81 } 82 testThrowErrorFromGet()83 public void testThrowErrorFromGet() { 84 Error error = new AssertionError("ASSERT!"); 85 ListenableFuture<String> f = UncheckedThrowingFuture.throwingError(error); 86 MockCallback callback = new MockCallback(error); 87 addCallback(f, callback, directExecutor()); 88 } 89 testRuntimeExceptionFromGet()90 public void testRuntimeExceptionFromGet() { 91 RuntimeException e = new IllegalArgumentException("foo not found"); 92 ListenableFuture<String> f = UncheckedThrowingFuture.throwingRuntimeException(e); 93 MockCallback callback = new MockCallback(e); 94 addCallback(f, callback, directExecutor()); 95 } 96 testOnSuccessThrowsRuntimeException()97 public void testOnSuccessThrowsRuntimeException() throws Exception { 98 RuntimeException exception = new RuntimeException(); 99 String result = "result"; 100 SettableFuture<String> future = SettableFuture.create(); 101 int[] successCalls = new int[1]; 102 int[] failureCalls = new int[1]; 103 FutureCallback<String> callback = 104 new FutureCallback<String>() { 105 @Override 106 public void onSuccess(String result) { 107 successCalls[0]++; 108 throw exception; 109 } 110 111 @Override 112 public void onFailure(Throwable t) { 113 failureCalls[0]++; 114 } 115 }; 116 addCallback(future, callback, directExecutor()); 117 future.set(result); 118 assertEquals(result, future.get()); 119 assertThat(successCalls[0]).isEqualTo(1); 120 assertThat(failureCalls[0]).isEqualTo(0); 121 } 122 testOnSuccessThrowsError()123 public void testOnSuccessThrowsError() throws Exception { 124 class TestError extends Error {} 125 TestError error = new TestError(); 126 String result = "result"; 127 SettableFuture<String> future = SettableFuture.create(); 128 int[] successCalls = new int[1]; 129 int[] failureCalls = new int[1]; 130 FutureCallback<String> callback = 131 new FutureCallback<String>() { 132 @Override 133 public void onSuccess(String result) { 134 successCalls[0]++; 135 throw error; 136 } 137 138 @Override 139 public void onFailure(Throwable t) { 140 failureCalls[0]++; 141 } 142 }; 143 addCallback(future, callback, directExecutor()); 144 try { 145 future.set(result); 146 fail("Should have thrown"); 147 } catch (TestError e) { 148 assertSame(error, e); 149 } 150 assertEquals(result, future.get()); 151 assertThat(successCalls[0]).isEqualTo(1); 152 assertThat(failureCalls[0]).isEqualTo(0); 153 } 154 testWildcardFuture()155 public void testWildcardFuture() { 156 SettableFuture<String> settable = SettableFuture.create(); 157 ListenableFuture<?> f = settable; 158 FutureCallback<Object> callback = 159 new FutureCallback<Object>() { 160 @Override 161 public void onSuccess(Object result) {} 162 163 @Override 164 public void onFailure(Throwable t) {} 165 }; 166 addCallback(f, callback, directExecutor()); 167 } 168 169 private class CountingSameThreadExecutor implements Executor { 170 int runCount = 0; 171 172 @Override execute(Runnable command)173 public void execute(Runnable command) { 174 command.run(); 175 runCount++; 176 } 177 } 178 179 private final class MockCallback implements FutureCallback<String> { 180 @Nullable private String value = null; 181 @Nullable private Throwable failure = null; 182 private boolean wasCalled = false; 183 MockCallback(String expectedValue)184 MockCallback(String expectedValue) { 185 this.value = expectedValue; 186 } 187 MockCallback(Throwable expectedFailure)188 public MockCallback(Throwable expectedFailure) { 189 this.failure = expectedFailure; 190 } 191 192 @Override onSuccess(String result)193 public synchronized void onSuccess(String result) { 194 assertFalse(wasCalled); 195 wasCalled = true; 196 assertEquals(value, result); 197 } 198 199 @Override onFailure(Throwable t)200 public synchronized void onFailure(Throwable t) { 201 assertFalse(wasCalled); 202 wasCalled = true; 203 assertEquals(failure, t); 204 } 205 } 206 } 207