--- jsr166/src/test/tck/CompletableFutureTest.java 2016/09/21 18:25:04 1.177 +++ jsr166/src/test/tck/CompletableFutureTest.java 2017/07/03 20:55:45 1.186 @@ -64,7 +64,7 @@ public class CompletableFutureTest exten assertNull(f.getNow(null)); } catch (Throwable fail) { threadUnexpectedException(fail); } try { - f.get(0L, SECONDS); + f.get(randomExpiredTimeout(), randomTimeUnit()); shouldThrow(); } catch (TimeoutException success) {} @@ -76,11 +76,7 @@ public class CompletableFutureTest exten try { assertEquals(value, f.join()); - } catch (Throwable fail) { threadUnexpectedException(fail); } - try { assertEquals(value, f.getNow(null)); - } catch (Throwable fail) { threadUnexpectedException(fail); } - try { assertEquals(value, f.get()); } catch (Throwable fail) { threadUnexpectedException(fail); } assertTrue(f.isDone()); @@ -93,10 +89,10 @@ public class CompletableFutureTest exten * Returns the "raw" internal exceptional completion of f, * without any additional wrapping with CompletionException. */ - Throwable exceptionalCompletion(CompletableFuture f) { - // handle (and whenComplete) can distinguish between "direct" - // and "wrapped" exceptional completion - return f.handle((U u, Throwable t) -> t).join(); + Throwable exceptionalCompletion(CompletableFuture f) { + // handle (and whenComplete and exceptionally) can distinguish + // between "direct" and "wrapped" exceptional completion + return f.handle((u, t) -> t).join(); } void checkCompletedExceptionally(CompletableFuture f, @@ -147,26 +143,26 @@ public class CompletableFutureTest exten void checkCompletedWithWrappedCFException(CompletableFuture f) { checkCompletedExceptionally(f, true, - (t) -> assertTrue(t instanceof CFException)); + t -> assertTrue(t instanceof CFException)); } void checkCompletedWithWrappedCancellationException(CompletableFuture f) { checkCompletedExceptionally(f, true, - (t) -> assertTrue(t instanceof CancellationException)); + t -> assertTrue(t instanceof CancellationException)); } void checkCompletedWithTimeoutException(CompletableFuture f) { checkCompletedExceptionally(f, false, - (t) -> assertTrue(t instanceof TimeoutException)); + t -> assertTrue(t instanceof TimeoutException)); } void checkCompletedWithWrappedException(CompletableFuture f, Throwable ex) { - checkCompletedExceptionally(f, true, (t) -> assertSame(t, ex)); + checkCompletedExceptionally(f, true, t -> assertSame(t, ex)); } void checkCompletedExceptionally(CompletableFuture f, Throwable ex) { - checkCompletedExceptionally(f, false, (t) -> assertSame(t, ex)); + checkCompletedExceptionally(f, false, t -> assertSame(t, ex)); } void checkCancelled(CompletableFuture f) { @@ -2562,28 +2558,28 @@ public class CompletableFutureTest exten // unspecified behavior - both source completions available try { - assertEquals(null, h0.join()); + assertNull(h0.join()); rs[0].assertValue(v1); } catch (CompletionException ok) { checkCompletedWithWrappedException(h0, ex); rs[0].assertNotInvoked(); } try { - assertEquals(null, h1.join()); + assertNull(h1.join()); rs[1].assertValue(v1); } catch (CompletionException ok) { checkCompletedWithWrappedException(h1, ex); rs[1].assertNotInvoked(); } try { - assertEquals(null, h2.join()); + assertNull(h2.join()); rs[2].assertValue(v1); } catch (CompletionException ok) { checkCompletedWithWrappedException(h2, ex); rs[2].assertNotInvoked(); } try { - assertEquals(null, h3.join()); + assertNull(h3.join()); rs[3].assertValue(v1); } catch (CompletionException ok) { checkCompletedWithWrappedException(h3, ex); @@ -2822,28 +2818,28 @@ public class CompletableFutureTest exten // unspecified behavior - both source completions available try { - assertEquals(null, h0.join()); + assertNull(h0.join()); rs[0].assertInvoked(); } catch (CompletionException ok) { checkCompletedWithWrappedException(h0, ex); rs[0].assertNotInvoked(); } try { - assertEquals(null, h1.join()); + assertNull(h1.join()); rs[1].assertInvoked(); } catch (CompletionException ok) { checkCompletedWithWrappedException(h1, ex); rs[1].assertNotInvoked(); } try { - assertEquals(null, h2.join()); + assertNull(h2.join()); rs[2].assertInvoked(); } catch (CompletionException ok) { checkCompletedWithWrappedException(h2, ex); rs[2].assertNotInvoked(); } try { - assertEquals(null, h3.join()); + assertNull(h3.join()); rs[3].assertInvoked(); } catch (CompletionException ok) { checkCompletedWithWrappedException(h3, ex); @@ -3238,6 +3234,7 @@ public class CompletableFutureTest exten /** * Completion methods throw NullPointerException with null arguments */ + @SuppressWarnings("FutureReturnValueIgnored") public void testNPE() { CompletableFuture f = new CompletableFuture<>(); CompletableFuture g = new CompletableFuture<>(); @@ -3257,12 +3254,12 @@ public class CompletableFutureTest exten () -> f.thenApply(null), () -> f.thenApplyAsync(null), - () -> f.thenApplyAsync((x) -> x, null), + () -> f.thenApplyAsync(x -> x, null), () -> f.thenApplyAsync(null, exec), () -> f.thenAccept(null), () -> f.thenAcceptAsync(null), - () -> f.thenAcceptAsync((x) -> {} , null), + () -> f.thenAcceptAsync(x -> {} , null), () -> f.thenAcceptAsync(null, exec), () -> f.thenRun(null), @@ -3297,18 +3294,18 @@ public class CompletableFutureTest exten () -> f.applyToEither(g, null), () -> f.applyToEitherAsync(g, null), () -> f.applyToEitherAsync(g, null, exec), - () -> f.applyToEither(nullFuture, (x) -> x), - () -> f.applyToEitherAsync(nullFuture, (x) -> x), - () -> f.applyToEitherAsync(nullFuture, (x) -> x, exec), - () -> f.applyToEitherAsync(g, (x) -> x, null), + () -> f.applyToEither(nullFuture, x -> x), + () -> f.applyToEitherAsync(nullFuture, x -> x), + () -> f.applyToEitherAsync(nullFuture, x -> x, exec), + () -> f.applyToEitherAsync(g, x -> x, null), () -> f.acceptEither(g, null), () -> f.acceptEitherAsync(g, null), () -> f.acceptEitherAsync(g, null, exec), - () -> f.acceptEither(nullFuture, (x) -> {}), - () -> f.acceptEitherAsync(nullFuture, (x) -> {}), - () -> f.acceptEitherAsync(nullFuture, (x) -> {}, exec), - () -> f.acceptEitherAsync(g, (x) -> {}, null), + () -> f.acceptEither(nullFuture, x -> {}), + () -> f.acceptEitherAsync(nullFuture, x -> {}), + () -> f.acceptEitherAsync(nullFuture, x -> {}, exec), + () -> f.acceptEitherAsync(g, x -> {}, null), () -> f.runAfterEither(g, null), () -> f.runAfterEitherAsync(g, null), @@ -3374,18 +3371,18 @@ public class CompletableFutureTest exten for (CompletableFuture src : srcs) { List> fs = new ArrayList<>(); fs.add(src.thenRunAsync(() -> {}, e)); - fs.add(src.thenAcceptAsync((z) -> {}, e)); - fs.add(src.thenApplyAsync((z) -> z, e)); + fs.add(src.thenAcceptAsync(z -> {}, e)); + fs.add(src.thenApplyAsync(z -> z, e)); fs.add(src.thenCombineAsync(src, (x, y) -> x, e)); fs.add(src.thenAcceptBothAsync(src, (x, y) -> {}, e)); fs.add(src.runAfterBothAsync(src, () -> {}, e)); - fs.add(src.applyToEitherAsync(src, (z) -> z, e)); - fs.add(src.acceptEitherAsync(src, (z) -> {}, e)); + fs.add(src.applyToEitherAsync(src, z -> z, e)); + fs.add(src.acceptEitherAsync(src, z -> {}, e)); fs.add(src.runAfterEitherAsync(src, () -> {}, e)); - fs.add(src.thenComposeAsync((z) -> null, e)); + fs.add(src.thenComposeAsync(z -> null, e)); fs.add(src.whenCompleteAsync((z, t) -> {}, e)); fs.add(src.handleAsync((z, t) -> null, e)); @@ -3418,11 +3415,11 @@ public class CompletableFutureTest exten { List> fs = new ArrayList<>(); - fs.add(complete.applyToEitherAsync(incomplete, (z) -> z, e)); - fs.add(incomplete.applyToEitherAsync(complete, (z) -> z, e)); + fs.add(complete.applyToEitherAsync(incomplete, z -> z, e)); + fs.add(incomplete.applyToEitherAsync(complete, z -> z, e)); - fs.add(complete.acceptEitherAsync(incomplete, (z) -> {}, e)); - fs.add(incomplete.acceptEitherAsync(complete, (z) -> {}, e)); + fs.add(complete.acceptEitherAsync(incomplete, z -> {}, e)); + fs.add(incomplete.acceptEitherAsync(complete, z -> {}, e)); fs.add(complete.runAfterEitherAsync(incomplete, () -> {}, e)); fs.add(incomplete.runAfterEitherAsync(complete, () -> {}, e)); @@ -3461,18 +3458,18 @@ public class CompletableFutureTest exten List> fs = new ArrayList<>(); fs.add(incomplete.thenRunAsync(() -> {}, e)); - fs.add(incomplete.thenAcceptAsync((z) -> {}, e)); - fs.add(incomplete.thenApplyAsync((z) -> z, e)); + fs.add(incomplete.thenAcceptAsync(z -> {}, e)); + fs.add(incomplete.thenApplyAsync(z -> z, e)); fs.add(incomplete.thenCombineAsync(incomplete, (x, y) -> x, e)); fs.add(incomplete.thenAcceptBothAsync(incomplete, (x, y) -> {}, e)); fs.add(incomplete.runAfterBothAsync(incomplete, () -> {}, e)); - fs.add(incomplete.applyToEitherAsync(incomplete, (z) -> z, e)); - fs.add(incomplete.acceptEitherAsync(incomplete, (z) -> {}, e)); + fs.add(incomplete.applyToEitherAsync(incomplete, z -> z, e)); + fs.add(incomplete.acceptEitherAsync(incomplete, z -> {}, e)); fs.add(incomplete.runAfterEitherAsync(incomplete, () -> {}, e)); - fs.add(incomplete.thenComposeAsync((z) -> null, e)); + fs.add(incomplete.thenComposeAsync(z -> null, e)); fs.add(incomplete.whenCompleteAsync((z, t) -> {}, e)); fs.add(incomplete.handleAsync((z, t) -> null, e)); @@ -3532,7 +3529,7 @@ public class CompletableFutureTest exten */ public void testCompletedStage() { AtomicInteger x = new AtomicInteger(0); - AtomicReference r = new AtomicReference(); + AtomicReference r = new AtomicReference<>(); CompletionStage f = CompletableFuture.completedStage(1); f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); assertEquals(x.get(), 1); @@ -3634,7 +3631,7 @@ public class CompletableFutureTest exten CompletableFuture f = new CompletableFuture<>(); CompletionStage g = f.minimalCompletionStage(); AtomicInteger x = new AtomicInteger(0); - AtomicReference r = new AtomicReference(); + AtomicReference r = new AtomicReference<>(); checkIncomplete(f); g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); f.complete(1); @@ -3651,7 +3648,7 @@ public class CompletableFutureTest exten CompletableFuture f = new CompletableFuture<>(); CompletionStage g = f.minimalCompletionStage(); AtomicInteger x = new AtomicInteger(0); - AtomicReference r = new AtomicReference(); + AtomicReference r = new AtomicReference<>(); g.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); checkIncomplete(f); CFException ex = new CFException(); @@ -3669,7 +3666,7 @@ public class CompletableFutureTest exten CFException ex = new CFException(); CompletionStage f = CompletableFuture.failedStage(ex); AtomicInteger x = new AtomicInteger(0); - AtomicReference r = new AtomicReference(); + AtomicReference r = new AtomicReference<>(); f.whenComplete((v, e) -> {if (e != null) r.set(e); else x.set(v);}); assertEquals(x.get(), 0); assertEquals(r.get(), ex); @@ -3693,7 +3690,7 @@ public class CompletableFutureTest exten public void testCompleteAsync2() { CompletableFuture f = new CompletableFuture<>(); CFException ex = new CFException(); - f.completeAsync(() -> {if (true) throw ex; return 1;}); + f.completeAsync(() -> { throw ex; }); try { f.join(); shouldThrow(); @@ -3723,7 +3720,7 @@ public class CompletableFutureTest exten CompletableFuture f = new CompletableFuture<>(); CFException ex = new CFException(); ThreadExecutor executor = new ThreadExecutor(); - f.completeAsync(() -> {if (true) throw ex; return 1;}, executor); + f.completeAsync(() -> { throw ex; }, executor); try { f.join(); shouldThrow(); @@ -3882,31 +3879,31 @@ public class CompletableFutureTest exten List, CompletableFuture>> funs = new ArrayList<>(); - funs.add((y) -> m.thenRun(y, noopRunnable)); - funs.add((y) -> m.thenAccept(y, noopConsumer)); - funs.add((y) -> m.thenApply(y, incFunction)); - - funs.add((y) -> m.runAfterEither(y, incomplete, noopRunnable)); - funs.add((y) -> m.acceptEither(y, incomplete, noopConsumer)); - funs.add((y) -> m.applyToEither(y, incomplete, incFunction)); - - funs.add((y) -> m.runAfterBoth(y, v42, noopRunnable)); - funs.add((y) -> m.runAfterBoth(v42, y, noopRunnable)); - funs.add((y) -> m.thenAcceptBoth(y, v42, new SubtractAction(m))); - funs.add((y) -> m.thenAcceptBoth(v42, y, new SubtractAction(m))); - funs.add((y) -> m.thenCombine(y, v42, new SubtractFunction(m))); - funs.add((y) -> m.thenCombine(v42, y, new SubtractFunction(m))); - - funs.add((y) -> m.whenComplete(y, (Integer r, Throwable t) -> {})); - - funs.add((y) -> m.thenCompose(y, new CompletableFutureInc(m))); - - funs.add((y) -> CompletableFuture.allOf(y)); - funs.add((y) -> CompletableFuture.allOf(y, v42)); - funs.add((y) -> CompletableFuture.allOf(v42, y)); - funs.add((y) -> CompletableFuture.anyOf(y)); - funs.add((y) -> CompletableFuture.anyOf(y, incomplete)); - funs.add((y) -> CompletableFuture.anyOf(incomplete, y)); + funs.add(y -> m.thenRun(y, noopRunnable)); + funs.add(y -> m.thenAccept(y, noopConsumer)); + funs.add(y -> m.thenApply(y, incFunction)); + + funs.add(y -> m.runAfterEither(y, incomplete, noopRunnable)); + funs.add(y -> m.acceptEither(y, incomplete, noopConsumer)); + funs.add(y -> m.applyToEither(y, incomplete, incFunction)); + + funs.add(y -> m.runAfterBoth(y, v42, noopRunnable)); + funs.add(y -> m.runAfterBoth(v42, y, noopRunnable)); + funs.add(y -> m.thenAcceptBoth(y, v42, new SubtractAction(m))); + funs.add(y -> m.thenAcceptBoth(v42, y, new SubtractAction(m))); + funs.add(y -> m.thenCombine(y, v42, new SubtractFunction(m))); + funs.add(y -> m.thenCombine(v42, y, new SubtractFunction(m))); + + funs.add(y -> m.whenComplete(y, (Integer r, Throwable t) -> {})); + + funs.add(y -> m.thenCompose(y, new CompletableFutureInc(m))); + + funs.add(y -> CompletableFuture.allOf(y)); + funs.add(y -> CompletableFuture.allOf(y, v42)); + funs.add(y -> CompletableFuture.allOf(v42, y)); + funs.add(y -> CompletableFuture.anyOf(y)); + funs.add(y -> CompletableFuture.anyOf(y, incomplete)); + funs.add(y -> CompletableFuture.anyOf(incomplete, y)); for (Function, CompletableFuture> fun : funs) { @@ -3963,12 +3960,12 @@ public class CompletableFutureTest exten public void testMinimalCompletionStage_minimality() { if (!testImplementationDetails) return; Function toSignature = - (method) -> method.getName() + Arrays.toString(method.getParameterTypes()); + method -> method.getName() + Arrays.toString(method.getParameterTypes()); Predicate isNotStatic = - (method) -> (method.getModifiers() & Modifier.STATIC) == 0; + method -> (method.getModifiers() & Modifier.STATIC) == 0; List minimalMethods = Stream.of(Object.class, CompletionStage.class) - .flatMap((klazz) -> Stream.of(klazz.getMethods())) + .flatMap(klazz -> Stream.of(klazz.getMethods())) .filter(isNotStatic) .collect(Collectors.toList()); // Methods from CompletableFuture permitted NOT to throw UOE @@ -3984,7 +3981,7 @@ public class CompletableFutureTest exten .collect(Collectors.toSet()); List allMethods = Stream.of(CompletableFuture.class.getMethods()) .filter(isNotStatic) - .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method))) + .filter(method -> !permittedMethodSignatures.contains(toSignature.apply(method))) .collect(Collectors.toList()); List> stages = new ArrayList<>(); @@ -4078,7 +4075,7 @@ public class CompletableFutureTest exten CompletableFuture f = new CompletableFuture<>(); CompletionStage minimal = f.minimalCompletionStage(); CompletableFuture g = minimal.toCompletableFuture(); - g.complete(v1); + assertTrue(g.complete(v1)); checkCompletedNormally(g, v1); checkIncomplete(f); checkIncomplete(minimal.toCompletableFuture()); @@ -4144,7 +4141,7 @@ public class CompletableFutureTest exten CompletionStage minimal = f.minimalCompletionStage(); CompletableFuture g = new CompletableFuture<>(); if (!createIncomplete) assertTrue(f.complete(v1)); - minimal.thenAccept((x) -> g.complete(x)); + minimal.thenAccept(x -> g.complete(x)); if (createIncomplete) assertTrue(f.complete(v1)); g.join(); checkCompletedNormally(g, v1); @@ -4168,7 +4165,7 @@ public class CompletableFutureTest exten static Function> compose (Function> f, Function> g) { - return (x) -> f.apply(x).thenCompose(g); + return x -> f.apply(x).thenCompose(g); } static void assertZero(CompletableFuture f) { @@ -4248,9 +4245,9 @@ public class CompletableFutureTest exten // Some mutually non-commutative functions Function> triple - = (x) -> Monad.unit(3 * x); + = x -> Monad.unit(3 * x); Function> inc - = (x) -> Monad.unit(x + 1); + = x -> Monad.unit(x + 1); // unit is a right identity: m >>= unit === m Monad.assertFutureEquals(inc.apply(5L).thenCompose(unit), @@ -4262,7 +4259,7 @@ public class CompletableFutureTest exten // associativity: (m >>= f) >>= g === m >>= ( \x -> (f x >>= g) ) Monad.assertFutureEquals( unit.apply(5L).thenCompose(inc).thenCompose(triple), - unit.apply(5L).thenCompose((x) -> inc.apply(x).thenCompose(triple))); + unit.apply(5L).thenCompose(x -> inc.apply(x).thenCompose(triple))); // The case for CompletableFuture as an additive monad is weaker... @@ -4272,7 +4269,7 @@ public class CompletableFutureTest exten // left zero: zero >>= f === zero Monad.assertZero(zero.thenCompose(inc)); // right zero: f >>= (\x -> zero) === zero - Monad.assertZero(inc.apply(5L).thenCompose((x) -> zero)); + Monad.assertZero(inc.apply(5L).thenCompose(x -> zero)); // f plus zero === f Monad.assertFutureEquals(Monad.unit(5L), @@ -4330,8 +4327,8 @@ public class CompletableFutureTest exten final AtomicInteger count = new AtomicInteger(0); for (int i = 0; i < n; i++) { head.thenRun(() -> count.getAndIncrement()); - head.thenAccept((x) -> count.getAndIncrement()); - head.thenApply((x) -> count.getAndIncrement()); + head.thenAccept(x -> count.getAndIncrement()); + head.thenApply(x -> count.getAndIncrement()); head.runAfterBoth(complete, () -> count.getAndIncrement()); head.thenAcceptBoth(complete, (x, y) -> count.getAndIncrement()); @@ -4341,11 +4338,11 @@ public class CompletableFutureTest exten complete.thenCombine(head, (x, y) -> count.getAndIncrement()); head.runAfterEither(new CompletableFuture(), () -> count.getAndIncrement()); - head.acceptEither(new CompletableFuture(), (x) -> count.getAndIncrement()); - head.applyToEither(new CompletableFuture(), (x) -> count.getAndIncrement()); + head.acceptEither(new CompletableFuture(), x -> count.getAndIncrement()); + head.applyToEither(new CompletableFuture(), x -> count.getAndIncrement()); new CompletableFuture().runAfterEither(head, () -> count.getAndIncrement()); - new CompletableFuture().acceptEither(head, (x) -> count.getAndIncrement()); - new CompletableFuture().applyToEither(head, (x) -> count.getAndIncrement()); + new CompletableFuture().acceptEither(head, x -> count.getAndIncrement()); + new CompletableFuture().applyToEither(head, x -> count.getAndIncrement()); } head.complete(null); assertEquals(5 * 3 * n, count.get()); @@ -4362,11 +4359,11 @@ public class CompletableFutureTest exten f.complete(null); f = new CompletableFuture<>(); - f.acceptEither(incomplete, (x) -> {}); + f.acceptEither(incomplete, x -> {}); f.complete(null); f = new CompletableFuture<>(); - f.applyToEither(incomplete, (x) -> x); + f.applyToEither(incomplete, x -> x); f.complete(null); f = new CompletableFuture<>(); @@ -4380,11 +4377,11 @@ public class CompletableFutureTest exten f.complete(null); f = new CompletableFuture<>(); - incomplete.acceptEither(f, (x) -> {}); + incomplete.acceptEither(f, x -> {}); f.complete(null); f = new CompletableFuture<>(); - incomplete.applyToEither(f, (x) -> x); + incomplete.applyToEither(f, x -> x); f.complete(null); f = new CompletableFuture<>(); @@ -4442,6 +4439,22 @@ public class CompletableFutureTest exten assertTrue(neverCompleted.thenRun(() -> {}).cancel(true)); } + /** + * Checks for garbage retention when MinimalStage.toCompletableFuture() + * is invoked many times. + * 8161600: Garbage retention when source CompletableFutures are never completed + * + * As of 2016-07, fails with OOME: + * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testToCompletableFutureGarbageRetention tck + */ + public void testToCompletableFutureGarbageRetention() throws Throwable { + final int n = expensiveTests ? 900_000 : 10; + CompletableFuture neverCompleted = new CompletableFuture<>(); + CompletionStage minimal = neverCompleted.minimalCompletionStage(); + for (int i = 0; i < n; i++) + assertTrue(minimal.toCompletableFuture().cancel(true)); + } + // static U join(CompletionStage stage) { // CompletableFuture f = new CompletableFuture<>(); // stage.whenComplete((v, ex) -> {