# HG changeset patch # User rriggs # Date 1442544364 14400 # Node ID b5e9f5c2464659403b7b811956d5668cfa5682d9 # Parent 52d938abd6bae0ab3e7c2fa74fdd3cd45d262631 8132735: java/lang/ProcessHandle/TreeTest failed with java.lang.AssertionError: Start with zero children Summary: Revise test to only operate on processes it spawns Reviewed-by: chegar diff -r 52d938abd6ba -r b5e9f5c24646 jdk/test/java/lang/ProcessHandle/TreeTest.java --- a/jdk/test/java/lang/ProcessHandle/TreeTest.java Thu Sep 17 22:46:02 2015 -0400 +++ b/jdk/test/java/lang/ProcessHandle/TreeTest.java Thu Sep 17 22:46:04 2015 -0400 @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -67,8 +68,6 @@ printf("self pid: %d%n", self.getPid()); printDeep(self, ""); - long count = getChildren(self).size(); - Assert.assertEquals(count, 0, "Start with zero children"); for (int i = 0; i < MAXCHILDREN; i++) { // spawn and wait for instructions @@ -124,8 +123,10 @@ spawned.stream() .map(Process::toHandle) .filter(ProcessHandle::isAlive) - .forEach(ph -> printDeep(ph, "test1 cleanup: ")); - destroyProcessTree(ProcessHandle.current()); + .forEach(ph -> { + printDeep(ph, "test1 cleanup: "); + ph.destroyForcibly(); + }); } } @@ -135,18 +136,29 @@ @Test public static void test2() { try { + ConcurrentHashMap processes = new ConcurrentHashMap<>(); + ProcessHandle self = ProcessHandle.current(); List initialChildren = getChildren(self); long count = initialChildren.size(); if (count > 0) { initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: ")); - Assert.assertEquals(count, 0, "Start with zero children (except Windows conhost.exe)"); } JavaChild p1 = JavaChild.spawnJavaChild("stdin"); ProcessHandle p1Handle = p1.toHandle(); printf(" p1 pid: %d%n", p1.getPid()); + // Gather the PIDs from the output of the spawing process + p1.forEachOutputLine((s) -> { + String[] split = s.trim().split(" "); + if (split.length == 3 && split[1].equals("spawn")) { + Long child = Long.valueOf(split[2]); + Long parent = Long.valueOf(split[0].split(":")[0]); + processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get()); + } + }); + int spawnNew = 3; p1.sendAction("spawn", spawnNew, "stdin"); @@ -160,18 +172,33 @@ int spawnNewSub = 2; p1.sendAction("child", "spawn", spawnNewSub, "stdin"); - // For each spawned child, wait for its children - for (ProcessHandle p : subprocesses) { - List grandChildren = waitForChildren(p, spawnNewSub); + // Poll until all 9 child processes exist or the timeout is reached + int expected = 9; + long timeout = jdk.testlibrary.Utils.adjustTimeout(10L); + Instant endTimeout = Instant.now().plusSeconds(timeout); + do { + Thread.sleep(200L); + printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected); + } while (processes.size() < expected && + Instant.now().isBefore(endTimeout)); + + if (processes.size() < expected) { + printf("WARNING: not all children have been started. Can't complete test.%n"); + printf(" You can try to increase the timeout or%n"); + printf(" you can try to use a faster VM (i.e. not a debug version).%n"); } + // show the complete list of children (for debug) List allChildren = getAllChildren(p1Handle); printf(" allChildren: %s%n", allChildren.stream().map(p -> p.getPid()) .collect(Collectors.toList())); - for (ProcessHandle ph : allChildren) { - Assert.assertEquals(ph.isAlive(), true, "Child should be alive: " + ph); - } + + // Verify that all spawned children show up in the allChildrenList + processes.forEach((p, parent) -> { + Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p); + Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p); + }); // Closing JavaChild's InputStream will cause all children to exit p1.getOutputStream().close(); @@ -185,15 +212,12 @@ } p1.waitFor(); // wait for spawned process to exit - List remaining = getChildren(self); - remaining.forEach(ph -> Assert.assertFalse(ph.isAlive(), + // Verify spawned processes are no longer alive + processes.forEach((ph, parent) -> Assert.assertFalse(ph.isAlive(), "process should not be alive: " + ph)); } catch (IOException | InterruptedException t) { t.printStackTrace(); throw new RuntimeException(t); - } finally { - // Cleanup any left over processes - destroyProcessTree(ProcessHandle.current()); } } @@ -202,6 +226,8 @@ */ @Test public static void test3() { + ConcurrentHashMap processes = new ConcurrentHashMap<>(); + try { ProcessHandle self = ProcessHandle.current(); @@ -209,44 +235,53 @@ ProcessHandle p1Handle = p1.toHandle(); printf(" p1: %s%n", p1.getPid()); - List subprocesses = getChildren(self); - long count = subprocesses.size(); - Assert.assertEquals(count, 1, "Wrong number of spawned children"); - int newChildren = 3; // Spawn children and have them wait p1.sendAction("spawn", newChildren, "stdin"); + // Gather the PIDs from the output of the spawing process + p1.forEachOutputLine((s) -> { + String[] split = s.trim().split(" "); + if (split.length == 3 && split[1].equals("spawn")) { + Long child = Long.valueOf(split[2]); + Long parent = Long.valueOf(split[0].split(":")[0]); + processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get()); + } + }); + // Wait for the new processes and save the list - subprocesses = waitForAllChildren(p1Handle, newChildren); - Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children"); - - p1.children().filter(TreeTest::isNotWindowsConsole) - .forEach(ProcessHandle::destroyForcibly); + List allChildren = waitForAllChildren(p1Handle, newChildren); - self.children().filter(TreeTest::isNotWindowsConsole) - .forEach(ProcessHandle::destroyForcibly); + // Verify that all spawned children are alive, show up in the allChildren list + // then destroy them + processes.forEach((p, parent) -> { + Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p); + Assert.assertTrue(allChildren.contains(p), "Spawned child should be listed in allChildren: " + p); + p.destroyForcibly(); + }); - for (ProcessHandle p : subprocesses) { + processes.forEach((p, parent) -> { while (p.isAlive()) { - Thread.sleep(100L); // It will happen but don't burn the cpu + try { + Thread.sleep(100L); // It will happen but don't burn the cpu + } catch (InterruptedException ie) { + // try again + } } - } + }); + p1.destroyForcibly(); + p1.waitFor(); List remaining = getAllChildren(self); - remaining.retainAll(subprocesses); - if (remaining.size() > 0) { - remaining.forEach(p -> printProcess(p, " remaining: ")); - Assert.fail("Subprocess(es) should have exited"); - } + remaining = remaining.stream().filter(processes::contains).collect(Collectors.toList()); + Assert.assertEquals(remaining.size(), 0, "Subprocess(es) should have exited: " + remaining); } catch (IOException ioe) { Assert.fail("Spawn of subprocess failed", ioe); } catch (InterruptedException inte) { Assert.fail("InterruptedException", inte); } finally { - // Cleanup any left over processes - destroyProcessTree(ProcessHandle.current()); + processes.forEach((p, parent) -> p.destroyForcibly()); } } @@ -302,9 +337,10 @@ @Test public static void test5() { int factor = 2; + JavaChild p1 = null; Instant start = Instant.now(); try { - JavaChild p1 = JavaChild.spawnJavaChild("stdin"); + p1 = JavaChild.spawnJavaChild("stdin"); ProcessHandle p1Handle = p1.toHandle(); printf("Spawning %d x %d x %d processes, pid: %d%n", @@ -340,7 +376,9 @@ Assert.fail("Unexpected Exception", ex); } finally { printf("Duration: %s%n", Duration.between(start, Instant.now())); - destroyProcessTree(ProcessHandle.current()); + if (p1 != null) { + p1.destroyForcibly(); + } } }