3232import java .util .concurrent .atomic .AtomicBoolean ;
3333import java .util .concurrent .atomic .AtomicInteger ;
3434import java .util .stream .IntStream ;
35+ import org .assertj .core .api .CompletableFutureAssert ;
3536import org .assertj .core .api .SoftAssertions ;
3637import org .assertj .core .api .junit .jupiter .InjectSoftAssertions ;
3738import org .assertj .core .api .junit .jupiter .SoftAssertionsExtension ;
@@ -86,26 +87,27 @@ public void simpleTests() throws Exception {
8687 .describedAs ("initialDelay %s" , initialDelay )
8788 .isTrue ();
8889 cancelable .cancel ();
89- soft .assertThat (cancelable .completionStage ())
90- .failsWithin (asyncTimeout )
91- .withThrowableThat ()
92- .isInstanceOf (CancellationException .class );
90+ cancelledAssert (soft .assertThat (cancelable .completionStage ()));
9391 }
9492
9593 // .cancel() before execution
9694 var cancelable = executor .schedulePeriodic (() -> {}, Duration .ofHours (12 ));
9795 cancelable .cancel ();
98- soft .assertThat (cancelable .completionStage ())
99- .failsWithin (asyncTimeout )
100- .withThrowableThat ()
101- .isInstanceOf (CancellationException .class );
96+ cancelledAssert (soft .assertThat (cancelable .completionStage ()));
10297
10398 cancelable = executor .schedule (() -> {}, Duration .ofHours (12 ));
10499 cancelable .cancel ();
105- soft .assertThat (cancelable .completionStage ())
106- .failsWithin (asyncTimeout )
107- .withThrowableThat ()
108- .isInstanceOf (CancellationException .class );
100+ cancelledAssert (soft .assertThat (cancelable .completionStage ()));
101+ }
102+
103+ private void cancelledAssert (CompletableFutureAssert <?> assertion ) {
104+ assertion .satisfiesAnyOf (
105+ completionStage ->
106+ assertThat (completionStage )
107+ .failsWithin (asyncTimeout )
108+ .withThrowableThat ()
109+ .isInstanceOf (CancellationException .class ),
110+ completionStage -> assertThat (completionStage ).succeedsWithin (asyncTimeout ));
109111 }
110112
111113 @ Test
@@ -120,7 +122,7 @@ public void applicationScopedInvocation() {
120122 public void submitMany () {
121123 int numTasks = 50 ;
122124 var sem = new Semaphore (0 );
123- var completables =
125+ var completableFutures =
124126 IntStream .range (0 , numTasks )
125127 .mapToObj (
126128 i ->
@@ -135,19 +137,19 @@ public void submitMany() {
135137 .map (CompletionStage ::toCompletableFuture )
136138 .toList ();
137139
138- soft .assertThat (completables ).noneMatch (CompletableFuture ::isDone );
140+ soft .assertThat (completableFutures ).noneMatch (CompletableFuture ::isDone );
139141
140142 sem .release (numTasks );
141143
142- soft .assertThat (completables )
144+ soft .assertThat (completableFutures )
143145 .allSatisfy (cf -> assertThat (cf ).succeedsWithin (asyncTimeout ).isEqualTo ("foo" ));
144146 }
145147
146148 @ Test
147149 public void submitManyFailing () {
148150 int numTasks = 50 ;
149151 var sem = new Semaphore (0 );
150- var completables =
152+ var completableFutures =
151153 IntStream .range (0 , numTasks )
152154 .mapToObj (
153155 i ->
@@ -162,18 +164,27 @@ public void submitManyFailing() {
162164 .map (CompletionStage ::toCompletableFuture )
163165 .toList ();
164166
165- soft .assertThat (completables ).noneMatch (CompletableFuture ::isDone );
167+ soft .assertThat (completableFutures ).noneMatch (CompletableFuture ::isDone );
166168
167169 sem .release (numTasks );
168170
169- soft .assertThat (completables ).allSatisfy (cf -> assertThat (cf ).failsWithin (asyncTimeout ));
171+ soft .assertThat (completableFutures )
172+ .allSatisfy (
173+ cf ->
174+ assertThat (cf )
175+ .failsWithin (asyncTimeout )
176+ .withThrowableThat ()
177+ .isInstanceOf (ExecutionException .class )
178+ .havingCause ()
179+ .isInstanceOf (RuntimeException .class )
180+ .withMessage ("FAILED" ));
170181 }
171182
172183 @ Test
173184 public void scheduleMany () {
174185 var numTasks = 50 ;
175186 var sem = new Semaphore (0 );
176- var completables =
187+ var completableFutures =
177188 IntStream .range (0 , numTasks )
178189 .mapToObj (
179190 i ->
@@ -189,11 +200,11 @@ public void scheduleMany() {
189200 .map (CompletionStage ::toCompletableFuture )
190201 .toList ();
191202
192- soft .assertThat (completables ).noneMatch (CompletableFuture ::isDone );
203+ soft .assertThat (completableFutures ).noneMatch (CompletableFuture ::isDone );
193204
194205 sem .release (numTasks );
195206
196- soft .assertThat (completables )
207+ soft .assertThat (completableFutures )
197208 .allSatisfy (cf -> assertThat (cf ).succeedsWithin (asyncTimeout ).isEqualTo ("foo" ));
198209 }
199210
@@ -218,7 +229,7 @@ public void periodic(int failAfter) {
218229 var dontFail = failAfter == Integer .MAX_VALUE ;
219230 var numTasks = 50 ;
220231 var stop = new AtomicBoolean ();
221- var completables =
232+ var completableFutures =
222233 IntStream .range (0 , numTasks )
223234 .mapToObj (
224235 i -> {
@@ -254,11 +265,11 @@ public void periodic(int failAfter) {
254265
255266 var iterations = dontFail ? 10 : (failAfter + 1 );
256267 for (int i = 0 ; i < iterations ; i ++) {
257- soft .assertThat (completables ).noneMatch (c -> c .f .isDone ());
268+ soft .assertThat (completableFutures ).noneMatch (c -> c .f .isDone ());
258269
259- completables .forEach (t -> t .before .release ());
270+ completableFutures .forEach (t -> t .before .release ());
260271
261- assertThat (completables )
272+ assertThat (completableFutures )
262273 .describedAs ("iteration %d" , i )
263274 .allSatisfy (
264275 t -> assertThat (t .after .tryAcquire (asyncTimeout .toMillis (), MILLISECONDS )).isTrue ());
@@ -267,31 +278,38 @@ public void periodic(int failAfter) {
267278 stop .set (true );
268279
269280 if (dontFail ) {
270- completables .forEach (t -> t .c .cancel ());
281+ completableFutures .forEach (t -> t .c .cancel ());
271282 }
272283
273- soft .assertThat (completables ).allMatch (t -> t .runs .get () == iterations );
284+ soft .assertThat (completableFutures ).allMatch (t -> t .runs .get () == iterations );
274285
275286 // Just in case the periodic tasks get called again, let those run
276- completables .forEach (s -> s .before .release (1000 ));
287+ completableFutures .forEach (s -> s .before .release (1000 ));
277288
278- soft .assertThat (completables )
289+ soft .assertThat (completableFutures )
279290 .allSatisfy (
280- t ->
291+ t -> {
292+ if (dontFail ) {
293+ cancelledAssert (assertThat (t .f ));
294+ } else {
281295 assertThat (t .f )
282296 .completesExceptionallyWithin (asyncTimeout )
283297 .withThrowableThat ()
284- .isInstanceOf (
285- dontFail ? CancellationException .class : ExecutionException .class ));
286-
287- soft .assertThat (completables ).allMatch (t -> t .f .isDone ());
298+ .isInstanceOf (ExecutionException .class )
299+ .havingCause ()
300+ .isInstanceOf (RuntimeException .class )
301+ .withMessage ("FAILED" );
302+ }
303+ });
304+
305+ soft .assertThat (completableFutures ).allMatch (t -> t .f .isDone ());
288306 if (dontFail ) {
289- soft .assertThat (completables ).allMatch (t -> t .f .isCancelled ());
307+ soft .assertThat (completableFutures ).allMatch (t -> t .f .isCancelled ());
290308 } else {
291- soft .assertThat (completables ).noneMatch (t -> t .f .isCancelled ());
309+ soft .assertThat (completableFutures ).noneMatch (t -> t .f .isCancelled ());
292310 }
293311 // cancellation is still an exceptional completion
294- soft .assertThat (completables ).allMatch (t -> t .f .isCompletedExceptionally ());
312+ soft .assertThat (completableFutures ).allMatch (t -> t .f .isCompletedExceptionally ());
295313 }
296314
297315 protected abstract void threadAssertion ();
0 commit comments