1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 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 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.utils; 17 18 import static org.assertj.core.api.Assertions.assertThat; 19 import static org.assertj.core.api.Assertions.assertThatThrownBy; 20 import static org.junit.Assert.fail; 21 22 import java.util.concurrent.CancellationException; 23 import java.util.concurrent.CompletableFuture; 24 import java.util.concurrent.CompletionException; 25 import java.util.concurrent.ExecutorService; 26 import java.util.concurrent.Executors; 27 import org.junit.AfterClass; 28 import org.junit.BeforeClass; 29 import org.junit.Test; 30 31 public class CompletableFutureUtilsTest { 32 private static ExecutorService executors; 33 34 @BeforeClass setup()35 public static void setup() { 36 executors = Executors.newFixedThreadPool(2); 37 } 38 39 @AfterClass tearDown()40 public static void tearDown() { 41 executors.shutdown(); 42 } 43 44 @Test(timeout = 1000) testForwardException()45 public void testForwardException() { 46 CompletableFuture src = new CompletableFuture(); 47 CompletableFuture dst = new CompletableFuture(); 48 49 Exception e = new RuntimeException("BOOM"); 50 51 CompletableFutureUtils.forwardExceptionTo(src, dst); 52 53 src.completeExceptionally(e); 54 55 try { 56 dst.join(); 57 fail(); 58 } catch (Throwable t) { 59 assertThat(t.getCause()).isEqualTo(e); 60 } 61 } 62 63 @Test(timeout = 1000) forwardResultTo_srcCompletesSuccessfully_shouldCompleteDstFuture()64 public void forwardResultTo_srcCompletesSuccessfully_shouldCompleteDstFuture() { 65 CompletableFuture<String> src = new CompletableFuture<>(); 66 CompletableFuture<String> dst = new CompletableFuture<>(); 67 68 CompletableFuture<String> returnedFuture = CompletableFutureUtils.forwardResultTo(src, dst, executors); 69 assertThat(returnedFuture).isEqualTo(src); 70 71 src.complete("foobar"); 72 assertThat(dst.join()).isEqualTo("foobar"); 73 } 74 75 @Test(timeout = 1000) forwardResultTo_srcCompletesExceptionally_shouldCompleteDstFuture()76 public void forwardResultTo_srcCompletesExceptionally_shouldCompleteDstFuture() { 77 CompletableFuture<String> src = new CompletableFuture<>(); 78 CompletableFuture<String> dst = new CompletableFuture<>(); 79 80 RuntimeException exception = new RuntimeException("foobar"); 81 CompletableFutureUtils.forwardResultTo(src, dst, executors); 82 83 src.completeExceptionally(exception); 84 assertThatThrownBy(dst::join).hasCause(exception); 85 } 86 87 @Test(timeout = 1000) forwardTransformedResultTo_srcCompletesSuccessfully_shouldCompleteDstFuture()88 public void forwardTransformedResultTo_srcCompletesSuccessfully_shouldCompleteDstFuture() { 89 CompletableFuture<Integer> src = new CompletableFuture<>(); 90 CompletableFuture<String> dst = new CompletableFuture<>(); 91 92 CompletableFuture<Integer> returnedFuture = CompletableFutureUtils.forwardTransformedResultTo(src, dst, String::valueOf); 93 assertThat(returnedFuture).isSameAs(src); 94 95 src.complete(123); 96 assertThat(dst.join()).isEqualTo("123"); 97 } 98 99 @Test(timeout = 1000) forwardTransformedResultTo_srcCompletesExceptionally_shouldCompleteDstFuture()100 public void forwardTransformedResultTo_srcCompletesExceptionally_shouldCompleteDstFuture() { 101 CompletableFuture<Integer> src = new CompletableFuture<>(); 102 CompletableFuture<String> dst = new CompletableFuture<>(); 103 104 RuntimeException exception = new RuntimeException("foobar"); 105 CompletableFutureUtils.forwardTransformedResultTo(src, dst, String::valueOf); 106 107 src.completeExceptionally(exception); 108 assertThatThrownBy(dst::join).hasCause(exception); 109 } 110 111 @Test(timeout = 1000) anyFail_shouldCompleteWhenAnyFutureFails()112 public void anyFail_shouldCompleteWhenAnyFutureFails() { 113 RuntimeException exception = new RuntimeException("blah"); 114 CompletableFuture[] completableFutures = new CompletableFuture[2]; 115 completableFutures[0] = new CompletableFuture(); 116 completableFutures[1] = new CompletableFuture(); 117 118 CompletableFuture<Void> anyFail = CompletableFutureUtils.anyFail(completableFutures); 119 completableFutures[0] = CompletableFuture.completedFuture("test"); 120 completableFutures[1].completeExceptionally(exception); 121 assertThatThrownBy(anyFail::join).hasCause(exception); 122 } 123 124 @Test(timeout = 1000) anyFail_shouldNotCompleteWhenAllFuturesSucceed()125 public void anyFail_shouldNotCompleteWhenAllFuturesSucceed() { 126 CompletableFuture[] completableFutures = new CompletableFuture[2]; 127 completableFutures[0] = new CompletableFuture(); 128 completableFutures[1] = new CompletableFuture(); 129 130 CompletableFuture<Void> anyFail = CompletableFutureUtils.anyFail(completableFutures); 131 completableFutures[0] = CompletableFuture.completedFuture("test"); 132 completableFutures[1] = CompletableFuture.completedFuture("test"); 133 assertThat(anyFail.isDone()).isFalse(); 134 } 135 136 @Test(timeout = 1000) allOfExceptionForwarded_anyFutureFails_shouldForwardExceptionToOthers()137 public void allOfExceptionForwarded_anyFutureFails_shouldForwardExceptionToOthers() { 138 RuntimeException exception = new RuntimeException("blah"); 139 CompletableFuture[] completableFutures = new CompletableFuture[2]; 140 completableFutures[0] = new CompletableFuture(); 141 completableFutures[1] = new CompletableFuture(); 142 143 CompletableFuture<Void> resultFuture = CompletableFutureUtils.allOfExceptionForwarded(completableFutures); 144 completableFutures[0].completeExceptionally(exception); 145 146 assertThatThrownBy(resultFuture::join).hasCause(exception); 147 assertThatThrownBy(completableFutures[1]::join).hasCause(exception); 148 } 149 150 @Test(timeout = 1000) allOfExceptionForwarded_allFutureSucceed_shouldComplete()151 public void allOfExceptionForwarded_allFutureSucceed_shouldComplete() { 152 RuntimeException exception = new RuntimeException("blah"); 153 CompletableFuture[] completableFutures = new CompletableFuture[2]; 154 completableFutures[0] = new CompletableFuture(); 155 completableFutures[1] = new CompletableFuture(); 156 157 CompletableFuture<Void> resultFuture = CompletableFutureUtils.allOfExceptionForwarded(completableFutures); 158 completableFutures[0].complete("test"); 159 completableFutures[1].complete("test"); 160 161 assertThat(resultFuture.isDone()).isTrue(); 162 assertThat(resultFuture.isCompletedExceptionally()).isFalse(); 163 } 164 165 @Test(timeout = 1000) joinLikeSync_completesExceptionally_throwsUnderlyingException()166 public void joinLikeSync_completesExceptionally_throwsUnderlyingException() { 167 Exception e = new RuntimeException("BOOM"); 168 CompletableFuture future = new CompletableFuture(); 169 future.completeExceptionally(e); 170 171 assertThatThrownBy(() -> CompletableFutureUtils.joinLikeSync(future)) 172 .hasSuppressedException(new RuntimeException("Task failed.")) 173 .isEqualTo(e); 174 } 175 176 @Test(timeout = 1000) joinLikeSync_completesExceptionallyChecked_throwsCompletionException()177 public void joinLikeSync_completesExceptionallyChecked_throwsCompletionException() { 178 Exception e = new Exception("BOOM"); 179 CompletableFuture future = new CompletableFuture(); 180 future.completeExceptionally(e); 181 182 assertThatThrownBy(() -> CompletableFutureUtils.joinLikeSync(future)) 183 .hasNoSuppressedExceptions() 184 .hasCause(e) 185 .isInstanceOf(CompletionException.class); 186 } 187 188 @Test(timeout = 1000) joinLikeSync_completesExceptionallyWithError_throwsError()189 public void joinLikeSync_completesExceptionallyWithError_throwsError() { 190 Error e = new Error("BOOM"); 191 CompletableFuture future = new CompletableFuture(); 192 future.completeExceptionally(e); 193 194 assertThatThrownBy(() -> CompletableFutureUtils.joinLikeSync(future)) 195 .hasNoSuppressedExceptions() 196 .isEqualTo(e); 197 } 198 199 @Test(timeout = 1000) joinLikeSync_canceled_throwsCancellationException()200 public void joinLikeSync_canceled_throwsCancellationException() { 201 Exception e = new Exception("BOOM"); 202 CompletableFuture future = new CompletableFuture(); 203 future.cancel(false); 204 205 assertThatThrownBy(() -> CompletableFutureUtils.joinLikeSync(future)) 206 .hasNoSuppressedExceptions() 207 .hasNoCause() 208 .isInstanceOf(CancellationException.class); 209 }} 210