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