• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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