--- jsr166/src/test/tck/CompletableFutureTest.java 2016/07/03 18:58:15 1.164 +++ jsr166/src/test/tck/CompletableFutureTest.java 2016/09/21 18:01:06 1.174 @@ -32,7 +32,6 @@ import java.util.concurrent.ForkJoinPool import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeoutException; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; @@ -362,7 +361,7 @@ public class CompletableFutureTest exten checkCompletedNormally(f, "test"); } - abstract class CheckedAction { + abstract static class CheckedAction { int invocationCount = 0; final ExecutionMode m; CheckedAction(ExecutionMode m) { this.m = m; } @@ -374,7 +373,7 @@ public class CompletableFutureTest exten void assertInvoked() { assertEquals(1, invocationCount); } } - abstract class CheckedIntegerAction extends CheckedAction { + abstract static class CheckedIntegerAction extends CheckedAction { Integer value; CheckedIntegerAction(ExecutionMode m) { super(m); } void assertValue(Integer expected) { @@ -383,7 +382,7 @@ public class CompletableFutureTest exten } } - class IntegerSupplier extends CheckedAction + static class IntegerSupplier extends CheckedAction implements Supplier { final Integer value; @@ -402,7 +401,7 @@ public class CompletableFutureTest exten return (x == null) ? null : x + 1; } - class NoopConsumer extends CheckedIntegerAction + static class NoopConsumer extends CheckedIntegerAction implements Consumer { NoopConsumer(ExecutionMode m) { super(m); } @@ -412,7 +411,7 @@ public class CompletableFutureTest exten } } - class IncFunction extends CheckedIntegerAction + static class IncFunction extends CheckedIntegerAction implements Function { IncFunction(ExecutionMode m) { super(m); } @@ -430,7 +429,7 @@ public class CompletableFutureTest exten - ((y == null) ? 99 : y.intValue()); } - class SubtractAction extends CheckedIntegerAction + static class SubtractAction extends CheckedIntegerAction implements BiConsumer { SubtractAction(ExecutionMode m) { super(m); } @@ -440,7 +439,7 @@ public class CompletableFutureTest exten } } - class SubtractFunction extends CheckedIntegerAction + static class SubtractFunction extends CheckedIntegerAction implements BiFunction { SubtractFunction(ExecutionMode m) { super(m); } @@ -450,14 +449,14 @@ public class CompletableFutureTest exten } } - class Noop extends CheckedAction implements Runnable { + static class Noop extends CheckedAction implements Runnable { Noop(ExecutionMode m) { super(m); } public void run() { invoked(); } } - class FailingSupplier extends CheckedAction + static class FailingSupplier extends CheckedAction implements Supplier { final CFException ex; @@ -468,7 +467,7 @@ public class CompletableFutureTest exten } } - class FailingConsumer extends CheckedIntegerAction + static class FailingConsumer extends CheckedIntegerAction implements Consumer { final CFException ex; @@ -480,7 +479,7 @@ public class CompletableFutureTest exten } } - class FailingBiConsumer extends CheckedIntegerAction + static class FailingBiConsumer extends CheckedIntegerAction implements BiConsumer { final CFException ex; @@ -492,7 +491,7 @@ public class CompletableFutureTest exten } } - class FailingFunction extends CheckedIntegerAction + static class FailingFunction extends CheckedIntegerAction implements Function { final CFException ex; @@ -504,7 +503,7 @@ public class CompletableFutureTest exten } } - class FailingBiFunction extends CheckedIntegerAction + static class FailingBiFunction extends CheckedIntegerAction implements BiFunction { final CFException ex; @@ -516,7 +515,7 @@ public class CompletableFutureTest exten } } - class FailingRunnable extends CheckedAction implements Runnable { + static class FailingRunnable extends CheckedAction implements Runnable { final CFException ex; FailingRunnable(ExecutionMode m) { super(m); ex = new CFException(); } public void run() { @@ -525,7 +524,7 @@ public class CompletableFutureTest exten } } - class CompletableFutureInc extends CheckedIntegerAction + static class CompletableFutureInc extends CheckedIntegerAction implements Function> { CompletableFutureInc(ExecutionMode m) { super(m); } @@ -538,7 +537,7 @@ public class CompletableFutureTest exten } } - class FailingCompletableFutureFunction extends CheckedIntegerAction + static class FailingCompletableFutureFunction extends CheckedIntegerAction implements Function> { final CFException ex; @@ -3578,29 +3577,53 @@ public class CompletableFutureTest exten * copy returns a CompletableFuture that is completed normally, * with the same value, when source is. */ - public void testCopy() { + public void testCopy_normalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); CompletableFuture g = f.copy(); - checkIncomplete(f); - checkIncomplete(g); - f.complete(1); - checkCompletedNormally(f, 1); - checkCompletedNormally(g, 1); - } + if (createIncomplete) { + checkIncomplete(f); + checkIncomplete(g); + assertTrue(f.complete(v1)); + } + checkCompletedNormally(f, v1); + checkCompletedNormally(g, v1); + }} /** * copy returns a CompletableFuture that is completed exceptionally * when source is. */ - public void testCopy2() { + public void testCopy_exceptionalCompletion() { + for (boolean createIncomplete : new boolean[] { true, false }) + { + CFException ex = new CFException(); CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) f.completeExceptionally(ex); CompletableFuture g = f.copy(); - checkIncomplete(f); - checkIncomplete(g); - CFException ex = new CFException(); - f.completeExceptionally(ex); + if (createIncomplete) { + checkIncomplete(f); + checkIncomplete(g); + f.completeExceptionally(ex); + } checkCompletedExceptionally(f, ex); checkCompletedWithWrappedException(g, ex); + }} + + /** + * Completion of a copy does not complete its source. + */ + public void testCopy_oneWayPropagation() { + CompletableFuture f = new CompletableFuture<>(); + assertTrue(f.copy().complete(1)); + assertTrue(f.copy().complete(null)); + assertTrue(f.copy().cancel(true)); + assertTrue(f.copy().cancel(false)); + assertTrue(f.copy().completeExceptionally(new CFException())); + checkIncomplete(f); } /** @@ -3935,7 +3958,7 @@ public class CompletableFutureTest exten }} /** - * Minimal completion stages throw UOE for all non-CompletionStage methods + * Minimal completion stages throw UOE for most non-CompletionStage methods */ public void testMinimalCompletionStage_minimality() { if (!testImplementationDetails) return; @@ -3964,8 +3987,13 @@ public class CompletableFutureTest exten .filter((method) -> !permittedMethodSignatures.contains(toSignature.apply(method))) .collect(Collectors.toList()); - CompletionStage minimalStage = + List> stages = new ArrayList<>(); + CompletionStage min = new CompletableFuture().minimalCompletionStage(); + stages.add(min); + stages.add(min.thenApply(x -> x)); + stages.add(CompletableFuture.completedStage(1)); + stages.add(CompletableFuture.failedStage(new CFException())); List bugs = new ArrayList<>(); for (Method method : allMethods) { @@ -3981,22 +4009,90 @@ public class CompletableFutureTest exten else if (parameterTypes[i] == long.class) args[i] = 0L; } - try { - method.invoke(minimalStage, args); - bugs.add(method); - } - catch (java.lang.reflect.InvocationTargetException expected) { - if (! (expected.getCause() instanceof UnsupportedOperationException)) { + for (CompletionStage stage : stages) { + try { + method.invoke(stage, args); bugs.add(method); - // expected.getCause().printStackTrace(); } + catch (java.lang.reflect.InvocationTargetException expected) { + if (! (expected.getCause() instanceof UnsupportedOperationException)) { + bugs.add(method); + // expected.getCause().printStackTrace(); + } + } + catch (ReflectiveOperationException bad) { throw new Error(bad); } } - catch (ReflectiveOperationException bad) { throw new Error(bad); } } if (!bugs.isEmpty()) - throw new Error("Methods did not throw UOE: " + bugs.toString()); + throw new Error("Methods did not throw UOE: " + bugs); + } + + /** + * minimalStage.toCompletableFuture() gives mutable CompletableFuture + */ + public void testMinimalCompletionStage_toCompletableFuture_mutable() { + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + CompletionStage minimal = f.minimalCompletionStage(); + CompletableFuture g = minimal.toCompletableFuture(); + g.complete(v1); + checkCompletedNormally(g, v1); + checkIncomplete(f); + checkIncomplete(minimal.toCompletableFuture()); + }} + + /** + * minimalStage.toCompletableFuture().join() awaits completion + */ + public void testMinimalCompletionStage_toCompletableFuture_join() throws Exception { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); + CompletionStage minimal = f.minimalCompletionStage(); + if (createIncomplete) assertTrue(f.complete(v1)); + assertEquals(v1, minimal.toCompletableFuture().join()); + assertEquals(v1, minimal.toCompletableFuture().get()); + checkCompletedNormally(minimal.toCompletableFuture(), v1); + }} + + /** Demo utility method for external reliable toCompletableFuture */ + static CompletableFuture toCompletableFuture(CompletionStage stage) { + CompletableFuture f = new CompletableFuture<>(); + stage.handle((T t, Throwable ex) -> { + if (ex != null) f.completeExceptionally(ex); + else f.complete(t); + return null; + }); + return f; } + /** Demo utility method to join a CompletionStage */ + static T join(CompletionStage stage) { + return toCompletableFuture(stage).join(); + } + + /** + * Joining a minimal stage "by hand" works + */ + public void testMinimalCompletionStage_join_by_hand() { + for (boolean createIncomplete : new boolean[] { true, false }) + for (Integer v1 : new Integer[] { 1, null }) + { + CompletableFuture f = new CompletableFuture<>(); + CompletionStage minimal = f.minimalCompletionStage(); + CompletableFuture g = new CompletableFuture<>(); + if (!createIncomplete) assertTrue(f.complete(v1)); + minimal.thenAccept((x) -> g.complete(x)); + if (createIncomplete) assertTrue(f.complete(v1)); + g.join(); + checkCompletedNormally(g, v1); + checkCompletedNormally(f, v1); + assertEquals(v1, join(minimal)); + }} + static class Monad { static class ZeroException extends RuntimeException { public ZeroException() { super("monadic zero"); } @@ -4238,12 +4334,11 @@ public class CompletableFutureTest exten } } - /* - * Tests below currently fail in stress mode due to memory retention. - * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest tck + /** + * Reproduction recipe for: + * 8160402: Garbage retention with CompletableFuture.anyOf + * cvs update -D '2016-05-01' ./src/main/java/util/concurrent/CompletableFuture.java && ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testAnyOfGarbageRetention tck; cvs update -A */ - - /** Checks for garbage retention with anyOf. */ public void testAnyOfGarbageRetention() throws Throwable { for (Integer v : new Integer[] { 1, null }) { @@ -4257,7 +4352,12 @@ public class CompletableFutureTest exten checkCompletedNormally(CompletableFuture.anyOf(fs), v); }} - /** Checks for garbage retention with allOf. */ + /** + * Checks for garbage retention with allOf. + * + * As of 2016-07, fails with OOME: + * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testCancelledAllOfGarbageRetention tck + */ public void testCancelledAllOfGarbageRetention() throws Throwable { final int n = expensiveTests ? 100_000 : 10; CompletableFuture[] fs @@ -4268,6 +4368,21 @@ public class CompletableFutureTest exten assertTrue(CompletableFuture.allOf(fs).cancel(false)); } + /** + * Checks for garbage retention when a dependent future is + * cancelled and garbage-collected. + * 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=testCancelledGarbageRetention tck + */ + public void testCancelledGarbageRetention() throws Throwable { + final int n = expensiveTests ? 100_000 : 10; + CompletableFuture neverCompleted = new CompletableFuture<>(); + for (int i = 0; i < n; i++) + assertTrue(neverCompleted.thenRun(() -> {}).cancel(true)); + } + // static U join(CompletionStage stage) { // CompletableFuture f = new CompletableFuture<>(); // stage.whenComplete((v, ex) -> {