1 /* 2 * Copyright 2017, Google Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 package com.google.api.core; 31 32 import static com.google.common.truth.Truth.assertThat; 33 import static com.google.common.util.concurrent.MoreExecutors.directExecutor; 34 35 import com.google.common.collect.ImmutableList; 36 import java.util.List; 37 import java.util.concurrent.CancellationException; 38 import java.util.concurrent.ExecutionException; 39 import java.util.concurrent.Executor; 40 import java.util.concurrent.atomic.AtomicInteger; 41 import org.junit.Test; 42 43 public class ApiFuturesTest { 44 45 @Test testAddCallback()46 public void testAddCallback() throws Exception { 47 final AtomicInteger flag = new AtomicInteger(); 48 SettableApiFuture<Integer> future = SettableApiFuture.<Integer>create(); 49 ApiFutures.addCallback( 50 future, 51 new ApiFutureCallback<Integer>() { 52 @Override 53 public void onSuccess(Integer i) { 54 flag.set(i + 1); 55 } 56 57 @Override 58 public void onFailure(Throwable t) { 59 flag.set(-1); 60 } 61 }, 62 directExecutor()); 63 future.set(0); 64 assertThat(flag.get()).isEqualTo(1); 65 } 66 67 @Test testCatch()68 public void testCatch() throws Exception { 69 SettableApiFuture<Integer> future = SettableApiFuture.<Integer>create(); 70 ApiFuture<Integer> fallback = 71 ApiFutures.catching( 72 future, 73 Exception.class, 74 new ApiFunction<Exception, Integer>() { 75 @Override 76 public Integer apply(Exception ex) { 77 return 42; 78 } 79 }, 80 directExecutor()); 81 future.setException(new Exception()); 82 assertThat(fallback.get()).isEqualTo(42); 83 } 84 85 @Test testCatchAsync()86 public void testCatchAsync() throws Exception { 87 SettableApiFuture<Integer> future = SettableApiFuture.<Integer>create(); 88 ApiFuture<Integer> fallback = 89 ApiFutures.catchingAsync( 90 future, 91 Exception.class, 92 new ApiAsyncFunction<Exception, Integer>() { 93 @Override 94 public ApiFuture<Integer> apply(Exception ex) { 95 return ApiFutures.immediateFuture(42); 96 } 97 }, 98 directExecutor()); 99 future.setException(new Exception()); 100 assertThat(fallback.get()).isEqualTo(42); 101 } 102 103 @Test testTransform()104 public void testTransform() throws Exception { 105 SettableApiFuture<Integer> inputFuture = SettableApiFuture.<Integer>create(); 106 ApiFuture<String> transformedFuture = 107 ApiFutures.transform( 108 inputFuture, 109 new ApiFunction<Integer, String>() { 110 @Override 111 public String apply(Integer input) { 112 return input.toString(); 113 } 114 }, 115 directExecutor()); 116 inputFuture.set(6); 117 assertThat(transformedFuture.get()).isEqualTo("6"); 118 } 119 120 @Test testTransformWithExecutor()121 public void testTransformWithExecutor() throws Exception { 122 SettableApiFuture<Integer> inputFuture = SettableApiFuture.<Integer>create(); 123 final AtomicInteger counter = new AtomicInteger(0); 124 ApiFuture<String> transformedFuture = 125 ApiFutures.transform( 126 inputFuture, 127 new ApiFunction<Integer, String>() { 128 @Override 129 public String apply(Integer input) { 130 return input.toString(); 131 } 132 }, 133 new Executor() { 134 @Override 135 public void execute(Runnable command) { 136 counter.incrementAndGet(); 137 command.run(); 138 } 139 }); 140 inputFuture.set(6); 141 assertThat(transformedFuture.get()).isEqualTo("6"); 142 assertThat(counter.get()).isEqualTo(1); 143 } 144 145 @Test testAllAsList()146 public void testAllAsList() throws Exception { 147 SettableApiFuture<Integer> inputFuture1 = SettableApiFuture.<Integer>create(); 148 SettableApiFuture<Integer> inputFuture2 = SettableApiFuture.<Integer>create(); 149 ApiFuture<List<Integer>> listFuture = 150 ApiFutures.allAsList(ImmutableList.of(inputFuture1, inputFuture2)); 151 inputFuture1.set(1); 152 inputFuture2.set(2); 153 assertThat(listFuture.get()).containsExactly(1, 2).inOrder(); 154 } 155 156 @Test successfulAllAsList()157 public void successfulAllAsList() throws Exception { 158 SettableApiFuture<Integer> inputFuture1 = SettableApiFuture.<Integer>create(); 159 SettableApiFuture<Integer> inputFuture2 = SettableApiFuture.<Integer>create(); 160 ApiFuture<List<Integer>> listFuture = 161 ApiFutures.successfulAsList(ImmutableList.of(inputFuture1, inputFuture2)); 162 inputFuture1.set(1); 163 inputFuture2.setException(new Exception()); 164 assertThat(listFuture.get()).containsExactly(1, null).inOrder(); 165 } 166 167 @Test testTransformAsync()168 public void testTransformAsync() throws Exception { 169 ApiFuture<Integer> inputFuture = ApiFutures.immediateFuture(0); 170 ApiFuture<Integer> outputFuture = 171 ApiFutures.transformAsync( 172 inputFuture, 173 new ApiAsyncFunction<Integer, Integer>() { 174 @Override 175 public ApiFuture<Integer> apply(Integer input) { 176 return ApiFutures.immediateFuture(input + 1); 177 } 178 }, 179 directExecutor()); 180 assertThat(outputFuture.get()).isEqualTo(1); 181 } 182 183 @Test testTransformAsyncWithExecutor()184 public void testTransformAsyncWithExecutor() throws Exception { 185 ApiFuture<Integer> inputFuture = ApiFutures.immediateFuture(0); 186 final AtomicInteger counter = new AtomicInteger(0); 187 ApiFuture<Integer> outputFuture = 188 ApiFutures.transformAsync( 189 inputFuture, 190 new ApiAsyncFunction<Integer, Integer>() { 191 @Override 192 public ApiFuture<Integer> apply(Integer input) { 193 return ApiFutures.immediateFuture(input + 1); 194 } 195 }, 196 new Executor() { 197 @Override 198 public void execute(Runnable command) { 199 counter.incrementAndGet(); 200 command.run(); 201 } 202 }); 203 assertThat(outputFuture.get()).isEqualTo(1); 204 assertThat(counter.get()).isEqualTo(1); 205 } 206 207 @Test testImmediateFailedFuture()208 public void testImmediateFailedFuture() throws InterruptedException { 209 ApiFuture<String> future = 210 ApiFutures.immediateFailedFuture(new IllegalArgumentException("The message")); 211 IllegalArgumentException exception = null; 212 try { 213 future.get(); 214 } catch (ExecutionException e) { 215 exception = (IllegalArgumentException) e.getCause(); 216 } 217 assertThat(exception).isNotNull(); 218 assertThat(exception.getMessage()).isEqualTo("The message"); 219 } 220 221 @Test testImmediateCancelledFuture()222 public void testImmediateCancelledFuture() throws InterruptedException, ExecutionException { 223 ApiFuture<String> future = ApiFutures.immediateCancelledFuture(); 224 CancellationException exception = null; 225 try { 226 future.get(); 227 } catch (CancellationException e) { 228 exception = e; 229 } 230 assertThat(exception).isNotNull(); 231 } 232 } 233