Ejemplo n.º 1
0
  /**
   * Test destroy of processes. A JavaChild is started and it starts three children. Each one is
   * then checked to be alive and listed by descendants and forcibly destroyed. After they exit they
   * should no longer be listed by descendants.
   */
  @Test
  public static void test3() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    try {
      ProcessHandle self = ProcessHandle.current();

      JavaChild p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();
      printf(" p1: %s%n", p1.getPid());

      int newChildren = 3;
      CountDownLatch spawnCount = new CountDownLatch(newChildren);
      // Spawn children and have them wait
      p1.sendAction("spawn", newChildren, "stdin");

      // Gather the PIDs from the output of the spawning 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());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      // Verify that all spawned children are alive, show up in the descendants list
      // then destroy them
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
            p.destroyForcibly();
          });
      Assert.assertEquals(processes.size(), newChildren, "Wrong number of children");

      // Wait for each of the processes to exit
      processes.forEach(
          (p, parent) -> {
            for (long retries = Utils.adjustTimeout(100L); retries > 0; retries--) {
              if (!p.isAlive()) {
                return; // not alive, go on to the next
              }
              // Wait a bit and retry
              try {
                Thread.sleep(100L);
              } catch (InterruptedException ie) {
                // try again
              }
            }
            printf(
                "Timeout waiting for exit of pid %s, parent: %s, info: %s%n", p, parent, p.info());
            Assert.fail("Process still alive: " + p);
          });
      p1.destroyForcibly();
      p1.waitFor();

      // Verify that none of the spawned children are still listed by descendants
      List<ProcessHandle> remaining = getDescendants(self);
      Assert.assertFalse(remaining.remove(p1Handle), "Child p1 should have exited");
      remaining = remaining.stream().filter(processes::containsKey).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 {
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p);
              p.destroyForcibly();
            }
          });
    }
  }
Ejemplo n.º 2
0
  /** A test for scale; launch a large number (14) of subprocesses. */
  @Test
  public static void test5() {
    ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

    int factor = 2;
    JavaChild p1 = null;
    Instant start = Instant.now();
    try {
      p1 = JavaChild.spawnJavaChild("stdin");
      ProcessHandle p1Handle = p1.toHandle();

      printf("Spawning %d x %d x %d processes, pid: %d%n", factor, factor, factor, p1.getPid());

      // Start the first tier of subprocesses
      p1.sendAction("spawn", factor, "stdin");

      // Start the second tier of subprocesses
      p1.sendAction("child", "spawn", factor, "stdin");

      // Start the third tier of subprocesses
      p1.sendAction("child", "child", "spawn", factor, "stdin");

      int newChildren = factor * (1 + factor * (1 + factor));
      CountDownLatch spawnCount = new CountDownLatch(newChildren);

      // Gather the PIDs from the output of the spawning 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());
              spawnCount.countDown();
            }
          });

      // Wait for all the subprocesses to be listed as started
      Assert.assertTrue(
          spawnCount.await(Utils.adjustTimeout(30L), TimeUnit.SECONDS),
          "Timeout waiting for processes to start");

      // Debugging; list descendants that are not expected in processes
      List<ProcessHandle> descendants = ProcessUtil.getDescendants(p1Handle);
      long count = descendants.stream().filter(ph -> !processes.containsKey(ph)).count();
      if (count > 0) {
        descendants
            .stream()
            .filter(ph -> !processes.containsKey(ph))
            .forEach(ph1 -> ProcessUtil.printProcess(ph1, "Extra process: "));
        ProcessUtil.logTaskList();
        Assert.assertEquals(0, count, "Extra processes in descendants");
      }

      Assert.assertEquals(getChildren(p1Handle).size(), factor, "expected direct children");
      count = getDescendants(p1Handle).size();
      long totalChildren = factor * factor * factor + factor * factor + factor;
      Assert.assertTrue(
          count >= totalChildren, "expected at least " + totalChildren + ", actual: " + count);

      List<ProcessHandle> subprocesses = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          subprocesses.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      p1.getOutputStream().close(); // Close stdin for the controlling p1
      p1.waitFor();
    } catch (InterruptedException | IOException ex) {
      Assert.fail("Unexpected Exception", ex);
    } finally {
      printf("Duration: %s%n", Duration.between(start, Instant.now()));
      if (p1 != null) {
        p1.destroyForcibly();
      }
      processes.forEach(
          (p, parent) -> {
            if (p.isAlive()) {
              ProcessUtil.printProcess(p, "Process Cleanup: ");
              p.destroyForcibly();
            }
          });
    }
  }
Ejemplo n.º 3
0
  /** Test counting and spawning and counting of Processes. */
  @Test
  public static void test2() {
    try {
      ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();

      ProcessHandle self = ProcessHandle.current();
      List<ProcessHandle> initialChildren = getChildren(self);
      long count = initialChildren.size();
      if (count > 0) {
        initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
      }

      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");

      // Wait for direct children to be created and save the list
      List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, spawnNew);
      Optional<Instant> p1Start = p1Handle.info().startInstant();
      for (ProcessHandle ph : subprocesses) {
        Assert.assertTrue(ph.isAlive(), "Child should be alive: " + ph);
        // Verify each child was started after the parent
        ph.info()
            .startInstant()
            .ifPresent(
                childStart ->
                    p1Start.ifPresent(
                        parentStart -> {
                          Assert.assertFalse(
                              childStart.isBefore(parentStart),
                              String.format(
                                  "Child process started before parent: child: %s, parent: %s",
                                  childStart, parentStart));
                        }));
      }

      // Each child spawns two processes and waits for commands
      int spawnNewSub = 2;
      p1.sendAction("child", "spawn", spawnNewSub, "stdin");

      // Poll until all 9 child processes exist or the timeout is reached
      int expected = 9;
      long timeout = Utils.adjustTimeout(60L);
      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<ProcessHandle> descendants = getDescendants(p1Handle);
      printf(
          " descendants:  %s%n",
          descendants.stream().map(p -> p.getPid()).collect(Collectors.toList()));

      // Verify that all spawned children show up in the descendants  List
      processes.forEach(
          (p, parent) -> {
            Assert.assertEquals(p.isAlive(), true, "Child should be alive: " + p);
            Assert.assertTrue(
                descendants.contains(p), "Spawned child should be listed in descendants: " + p);
          });

      // Closing JavaChild's InputStream will cause all children to exit
      p1.getOutputStream().close();

      for (ProcessHandle p : descendants) {
        try {
          p.onExit().get(); // wait for the child to exit
        } catch (ExecutionException e) {
          Assert.fail("waiting for process to exit", e);
        }
      }
      p1.waitFor(); // wait for spawned process to exit

      // 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);
    }
  }