You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by sa...@apache.org on 2019/01/09 21:06:37 UTC

[geode] branch develop updated: GEODE-5787: support dunit VM bounce on Windows (#2563)

This is an automated email from the ASF dual-hosted git repository.

sai_boorlagadda pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new ed723a0  GEODE-5787: support dunit VM bounce on Windows (#2563)
ed723a0 is described below

commit ed723a0d187f06ab590c175f8ca1e0cc260815b2
Author: Sai Boorlagadda <sa...@gmail.com>
AuthorDate: Wed Jan 9 13:06:25 2019 -0800

    GEODE-5787: support dunit VM bounce on Windows (#2563)
---
 .../cli/commands/DeployWithGroupsDUnitTest.java    |   7 -
 .../java/org/apache/geode/test/dunit/Host.java     |  12 +-
 .../main/java/org/apache/geode/test/dunit/VM.java  | 146 +++++++++++----------
 .../{ProcessHolder.java => ChildVMLauncher.java}   |  43 +-----
 .../geode/test/dunit/internal/DUnitHost.java       |  21 ++-
 .../geode/test/dunit/internal/DUnitLauncher.java   |   5 +
 .../geode/test/dunit/internal/ProcessHolder.java   |   5 +
 .../geode/test/dunit/internal/ProcessManager.java  |  55 +++-----
 .../geode/test/dunit/internal/RemoteDUnitVM.java   |   2 +-
 .../geode/test/dunit/rules/ClusterStartupRule.java |  32 +----
 .../geode/test/junit/rules/ClientCacheRule.java    |   8 +-
 11 files changed, 142 insertions(+), 194 deletions(-)

diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java
index d7f9223..abdff44 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java
+++ b/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/DeployWithGroupsDUnitTest.java
@@ -15,10 +15,8 @@
 package org.apache.geode.management.internal.cli.commands;
 
 import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.internal.lang.SystemUtils.isWindows;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.Assume.assumeFalse;
 
 import java.io.File;
 import java.io.Serializable;
@@ -41,7 +39,6 @@ import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolde
  * @since GemFire 7.0
  */
 @SuppressWarnings("serial")
-
 public class DeployWithGroupsDUnitTest implements Serializable {
   private static final String GROUP1 = "Group1";
   private static final String GROUP2 = "Group2";
@@ -201,8 +198,6 @@ public class DeployWithGroupsDUnitTest implements Serializable {
 
   @Test
   public void deployJarToAllServersWithRestart() {
-    // TODO: Ignore on windows until GEODE-5787
-    assumeFalse(isWindows());
     // Deploy a jar to all servers
     gfshConnector.executeAndAssertThat("deploy --jar=" + jar1).statusIsSuccess();
     String resultString = gfshConnector.getGfshOutput();
@@ -231,8 +226,6 @@ public class DeployWithGroupsDUnitTest implements Serializable {
 
   @Test
   public void undeployJarFromAllServersWithRestart() throws Exception {
-    // TODO: Ignore on windows until GEODE-5787
-    assumeFalse(isWindows());
     // Deploy a jar to all servers
     gfshConnector.executeAndAssertThat("deploy --jar=" + jar1).statusIsSuccess();
     String resultString = gfshConnector.getGfshOutput();
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/Host.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/Host.java
index be99201..9821b19c 100755
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/Host.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/Host.java
@@ -18,6 +18,8 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.geode.test.dunit.internal.ChildVMLauncher;
+import org.apache.geode.test.dunit.internal.ProcessHolder;
 import org.apache.geode.test.dunit.internal.RemoteDUnitVMIF;
 import org.apache.geode.test.version.VersionManager;
 
@@ -162,8 +164,9 @@ public abstract class Host implements Serializable {
   /**
    * Adds a VM to this {@code Host} with the given process id and client record.
    */
-  protected void addVM(int vmid, RemoteDUnitVMIF client) {
-    VM vm = new VM(this, vmid, client);
+  protected void addVM(int vmid, RemoteDUnitVMIF client, ProcessHolder processHolder,
+      ChildVMLauncher childVMLauncher) {
+    VM vm = new VM(this, vmid, client, processHolder, childVMLauncher);
     vms.add(vm);
   }
 
@@ -175,8 +178,9 @@ public abstract class Host implements Serializable {
     locator = l;
   }
 
-  protected void addLocator(int vmid, RemoteDUnitVMIF client) {
-    setLocator(new VM(this, vmid, client));
+  protected void addLocator(int vmid, RemoteDUnitVMIF client, ProcessHolder processHolder,
+      ChildVMLauncher childVMLauncher) {
+    setLocator(new VM(this, vmid, client, processHolder, childVMLauncher));
   }
 
   @Override
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/VM.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/VM.java
index 572d058..ad670d7 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/VM.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/VM.java
@@ -17,16 +17,20 @@ package org.apache.geode.test.dunit;
 import static org.apache.geode.test.dunit.internal.DUnitLauncher.NUM_VMS;
 
 import java.io.File;
-import java.io.PrintWriter;
+import java.io.IOException;
 import java.io.Serializable;
-import java.io.StringWriter;
+import java.rmi.NotBoundException;
 import java.rmi.RemoteException;
 import java.util.List;
 import java.util.concurrent.Callable;
 
+import org.apache.logging.log4j.Logger;
+
+import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.test.dunit.internal.BounceResult;
+import org.apache.geode.test.dunit.internal.ChildVMLauncher;
 import org.apache.geode.test.dunit.internal.MethodInvokerResult;
+import org.apache.geode.test.dunit.internal.ProcessHolder;
 import org.apache.geode.test.dunit.internal.RemoteDUnitVMIF;
 import org.apache.geode.test.dunit.internal.StandAloneDUnitEnv;
 import org.apache.geode.test.version.VersionManager;
@@ -37,6 +41,8 @@ import org.apache.geode.test.version.VersionManager;
 @SuppressWarnings("serial,unused")
 public class VM implements Serializable {
 
+  private static final Logger logger = LogService.getLogger();
+
   public static final int CONTROLLER_VM = -1;
 
   public static final int DEFAULT_VM_COUNT = NUM_VMS;
@@ -56,6 +62,10 @@ public class VM implements Serializable {
   /** The state of this VM */
   private volatile boolean available;
 
+  private transient volatile ProcessHolder processHolder;
+
+  private transient ChildVMLauncher childVMLauncher;
+
   /**
    * Returns the {@code VM} identity. For {@link StandAloneDUnitEnv} the number returned is a
    * zero-based sequence representing the order in with the DUnit {@code VM}s were launched.
@@ -146,15 +156,19 @@ public class VM implements Serializable {
   /**
    * Creates a new {@code VM} that runs on a given host with a given process id.
    */
-  public VM(final Host host, final int id, final RemoteDUnitVMIF client) {
-    this(host, VersionManager.CURRENT_VERSION, id, client);
+  public VM(final Host host, final int id, final RemoteDUnitVMIF client,
+      final ProcessHolder processHolder, final ChildVMLauncher childVMLauncher) {
+    this(host, VersionManager.CURRENT_VERSION, id, client, processHolder, childVMLauncher);
   }
 
-  public VM(final Host host, final String version, final int id, final RemoteDUnitVMIF client) {
+  public VM(final Host host, final String version, final int id, final RemoteDUnitVMIF client,
+      final ProcessHolder processHolder, final ChildVMLauncher childVMLauncher) {
     this.host = host;
     this.id = id;
     this.version = version;
     this.client = client;
+    this.processHolder = processHolder;
+    this.childVMLauncher = childVMLauncher;
     available = true;
   }
 
@@ -202,7 +216,8 @@ public class VM implements Serializable {
    */
   @Deprecated
   public <V> V invoke(final Class<?> targetClass, final String methodName) {
-    return invoke(targetClass, methodName, new Object[0]);
+    checkAvailability(targetClass.getName(), methodName);
+    return executeMethodOnClass(targetClass, methodName, new Object[0]);
   }
 
   /**
@@ -234,20 +249,8 @@ public class VM implements Serializable {
    */
   @Deprecated
   public <V> V invoke(final Class<?> targetClass, final String methodName, final Object[] args) {
-    if (!available) {
-      throw new RMIException(this, targetClass.getName(), methodName,
-          new IllegalStateException("VM not available: " + this));
-    }
-
-    MethodInvokerResult result = execute(targetClass, methodName, args);
-
-    if (!result.exceptionOccurred()) {
-      return (V) result.getResult();
-
-    } else {
-      throw new RMIException(this, targetClass.getName(), methodName, result.getException(),
-          result.getStackTrace());
-    }
+    checkAvailability(targetClass.getName(), methodName);
+    return executeMethodOnClass(targetClass, methodName, args);
   }
 
   /**
@@ -345,7 +348,8 @@ public class VM implements Serializable {
    * @see SerializableRunnable
    */
   public void invoke(final String name, final SerializableRunnableIF runnable) {
-    invoke(new NamedRunnable(name, runnable), "run");
+    checkAvailability(NamedRunnable.class.getName(), "run");
+    executeMethodOnObject(new NamedRunnable(name, runnable), "run", new Object[0]);
   }
 
   /**
@@ -357,7 +361,8 @@ public class VM implements Serializable {
    * @see SerializableRunnable
    */
   public void invoke(final SerializableRunnableIF runnable) {
-    invoke(runnable, "run");
+    checkAvailability(runnable.getClass().getName(), "run");
+    executeMethodOnObject(runnable, "run", new Object[0]);
   }
 
   /**
@@ -369,7 +374,8 @@ public class VM implements Serializable {
    * @see SerializableCallable
    */
   public <V> V invoke(final String name, final SerializableCallableIF<V> callable) {
-    return invoke(new NamedCallable<>(name, callable), "call");
+    checkAvailability(NamedCallable.class.getName(), "call");
+    return executeMethodOnObject(new NamedCallable<>(name, callable), "call", new Object[0]);
   }
 
   /**
@@ -380,7 +386,8 @@ public class VM implements Serializable {
    * @see SerializableCallable
    */
   public <V> V invoke(final SerializableCallableIF<V> callable) {
-    return invoke(callable, "call");
+    checkAvailability(callable.getClass().getName(), "call");
+    return executeMethodOnObject(callable, "call", new Object[0]);
   }
 
   /**
@@ -398,7 +405,8 @@ public class VM implements Serializable {
    */
   @Deprecated
   public <V> V invoke(final Object targetObject, final String methodName) {
-    return invoke(targetObject, methodName, new Object[0]);
+    checkAvailability(targetObject.getClass().getName(), methodName);
+    return executeMethodOnObject(targetObject, methodName, new Object[0]);
   }
 
   /**
@@ -417,20 +425,8 @@ public class VM implements Serializable {
    */
   @Deprecated
   public <V> V invoke(final Object targetObject, final String methodName, final Object[] args) {
-    if (!available) {
-      throw new RMIException(this, targetObject.getClass().getName(), methodName,
-          new IllegalStateException("VM not available: " + this));
-    }
-
-    MethodInvokerResult result = execute(targetObject, methodName, args);
-
-    if (!result.exceptionOccurred()) {
-      return (V) result.getResult();
-
-    } else {
-      throw new RMIException(this, targetObject.getClass().getName(), methodName,
-          result.getException(), result.getStackTrace());
-    }
+    checkAvailability(targetObject.getClass().getName(), methodName);
+    return executeMethodOnObject(targetObject, methodName, args);
   }
 
   /**
@@ -481,28 +477,40 @@ public class VM implements Serializable {
   }
 
   private synchronized void bounce(final String targetVersion, boolean force) {
-    if (!available) {
-      throw new RMIException(this, getClass().getName(), "bounceVM",
-          new IllegalStateException("VM not available: " + this));
-    }
+    checkAvailability(getClass().getName(), "bounceVM");
 
+    logger.info("Bouncing {} old pid is {}", id, getPid());
     available = false;
-
     try {
-      BounceResult result = DUnitEnv.get().bounce(targetVersion, id, force);
-      id = result.getNewId();
-      client = result.getNewClient();
+      if (force) {
+        processHolder.killForcibly();
+      } else {
+        SerializableRunnableIF runnable = () -> new Thread(() -> {
+          try {
+            // sleep before exit so that the rmi call is returned
+            Thread.sleep(100);
+            System.exit(0);
+          } catch (InterruptedException e) {
+            logger.error("VM bounce thread interrupted before exiting.", e);
+          }
+        }).start();
+        executeMethodOnObject(runnable, "run", new Object[0]);
+      }
+      processHolder.waitFor();
+      processHolder = childVMLauncher.launchVM(targetVersion, id, true);
       version = targetVersion;
+      client = childVMLauncher.getStub(id);
       available = true;
+      logger.info("Bounced {} new pid is {}", id, getPid());
+    } catch (InterruptedException | IOException | NotBoundException e) {
+      throw new Error("Unable to restart VM " + id, e);
+    }
+  }
 
-    } catch (UnsupportedOperationException e) {
-      available = true;
-      throw e;
-
-    } catch (RemoteException e) {
-      StringWriter sw = new StringWriter();
-      e.printStackTrace(new PrintWriter(sw, true));
-      throw new RMIException(this, getClass().getName(), "bounceVM", e, sw.toString());
+  private void checkAvailability(String className, String methodName) {
+    if (!available) {
+      throw new RMIException(this, className, methodName,
+          new IllegalStateException("VM not available: " + this));
     }
   }
 
@@ -516,26 +524,32 @@ public class VM implements Serializable {
         + (VersionManager.isCurrentVersion(version) ? "" : (" with version " + version));
   }
 
-  private MethodInvokerResult execute(final Class<?> targetClass, final String methodName,
+  private <V> V executeMethodOnObject(final Object targetObject, final String methodName,
       final Object[] args) {
     try {
-      return client.executeMethodOnClass(targetClass.getName(), methodName, args);
+      MethodInvokerResult result = client.executeMethodOnObject(targetObject, methodName, args);
+      if (result.exceptionOccurred()) {
+        throw new RMIException(this, targetObject.getClass().getName(), methodName,
+            result.getException(), result.getStackTrace());
+      }
+      return (V) result.getResult();
     } catch (RemoteException exception) {
-      throw new RMIException(this, targetClass.getName(), methodName, exception);
+      throw new RMIException(this, targetObject.getClass().getName(), methodName, exception);
     }
   }
 
-  private MethodInvokerResult execute(final Object targetObject, final String methodName,
+  private <V> V executeMethodOnClass(final Class<?> targetClass, final String methodName,
       final Object[] args) {
     try {
-      if (args == null) {
-        return client.executeMethodOnObject(targetObject, methodName);
-      } else {
-        return client.executeMethodOnObject(targetObject, methodName, args);
+      MethodInvokerResult result =
+          client.executeMethodOnClass(targetClass.getName(), methodName, args);
+      if (result.exceptionOccurred()) {
+        throw new RMIException(this, targetClass.getName(), methodName, result.getException(),
+            result.getStackTrace());
       }
+      return (V) result.getResult();
     } catch (RemoteException exception) {
-      throw new RMIException(this, targetObject.getClass().getName(), methodName, exception);
+      throw new RMIException(this, targetClass.getName(), methodName, exception);
     }
   }
-
 }
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ChildVMLauncher.java
similarity index 52%
copy from geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java
copy to geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ChildVMLauncher.java
index 15d022a..a161bd5 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ChildVMLauncher.java
@@ -14,43 +14,14 @@
  */
 package org.apache.geode.test.dunit.internal;
 
-import java.io.InputStream;
+import java.io.IOException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
 
-public class ProcessHolder {
-  private final Process process;
-  private volatile boolean killed = false;
+public interface ChildVMLauncher {
 
-  public ProcessHolder(Process process) {
-    this.process = process;
-  }
+  ProcessHolder launchVM(String version, int vmNum, boolean bouncedVM)
+      throws IOException;
 
-  public void kill() {
-    this.killed = true;
-    process.destroy();
-  }
-
-  public void killForcibly() {
-    this.killed = true;
-    process.destroyForcibly();
-  }
-
-  public void waitFor() throws InterruptedException {
-    process.waitFor();
-  }
-
-  public InputStream getErrorStream() {
-    return process.getErrorStream();
-  }
-
-  public InputStream getInputStream() {
-    return process.getInputStream();
-  }
-
-  public boolean isKilled() {
-    return killed;
-  }
-
-  public boolean isAlive() {
-    return !killed && process.isAlive();
-  }
+  RemoteDUnitVMIF getStub(int i) throws RemoteException, NotBoundException, InterruptedException;
 }
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitHost.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitHost.java
index 947a055..651377e 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitHost.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitHost.java
@@ -27,18 +27,13 @@ import org.apache.geode.test.version.VersionManager;
 class DUnitHost extends Host {
   private static final long serialVersionUID = -8034165624503666383L;
 
-  /**
-   * VM ID for the VM to use for the debugger.
-   */
-  private static final int DEBUGGING_VM_NUM = -1;
-
   private final transient VM debuggingVM;
 
   private transient ProcessManager processManager;
 
   public DUnitHost(String hostName, ProcessManager processManager) throws RemoteException {
     super(hostName);
-    this.debuggingVM = new VM(this, -1, new RemoteDUnitVM());
+    this.debuggingVM = new VM(this, -1, new RemoteDUnitVM(), null, null);
     this.processManager = processManager;
   }
 
@@ -46,10 +41,12 @@ class DUnitHost extends Host {
       throws AccessException, RemoteException, NotBoundException, InterruptedException {
     for (int i = 0; i < numVMs; i++) {
       RemoteDUnitVMIF remote = processManager.getStub(i);
-      addVM(i, remote);
+      ProcessHolder processHolder = processManager.getProcessHolder(i);
+      addVM(i, remote, processHolder, processManager);
     }
 
-    addLocator(DUnitLauncher.LOCATOR_VM_NUM, processManager.getStub(DUnitLauncher.LOCATOR_VM_NUM));
+    addLocator(DUnitLauncher.LOCATOR_VM_NUM, processManager.getStub(DUnitLauncher.LOCATOR_VM_NUM),
+        processManager.getProcessHolder(DUnitLauncher.LOCATOR_VM_NUM), processManager);
 
     addHost(this);
   }
@@ -65,7 +62,7 @@ class DUnitHost extends Host {
    */
   @Override
   public VM getVM(int n) {
-    if (n < getVMCount() && n != DEBUGGING_VM_NUM) {
+    if (n < getVMCount() && n != DUnitLauncher.DEBUGGING_VM_NUM) {
       VM current = super.getVM(n);
       return getVM(current.getVersion(), n);
     } else {
@@ -75,7 +72,7 @@ class DUnitHost extends Host {
 
   @Override
   public VM getVM(String version, int n) {
-    if (n == DEBUGGING_VM_NUM) {
+    if (n == DUnitLauncher.DEBUGGING_VM_NUM) {
       // for ease of debugging, pass -1 to get the local VM
       return debuggingVM;
     }
@@ -101,13 +98,13 @@ class DUnitHost extends Host {
         processManager.waitForVMs(DUnitLauncher.STARTUP_TIMEOUT);
 
         for (int i = oldVMCount; i < n; i++) {
-          addVM(i, processManager.getStub(i));
+          addVM(i, processManager.getStub(i), processManager.getProcessHolder(i), processManager);
         }
 
         // now create the one we really want
         processManager.launchVM(version, n, false);
         processManager.waitForVMs(DUnitLauncher.STARTUP_TIMEOUT);
-        addVM(n, processManager.getStub(n));
+        addVM(n, processManager.getStub(n), processManager.getProcessHolder(n), processManager);
 
       } catch (IOException | InterruptedException | NotBoundException e) {
         throw new RuntimeException("Could not dynamically launch vm + " + n, e);
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitLauncher.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitLauncher.java
index 4ed724b..0606108 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitLauncher.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/DUnitLauncher.java
@@ -94,6 +94,11 @@ public class DUnitLauncher {
   public static int NUM_VMS = 4;
 
   /**
+   * VM ID for the VM to use for the debugger.
+   */
+  static final int DEBUGGING_VM_NUM = -1;
+
+  /**
    * VM ID for the VM to use for the locator.
    */
   static final int LOCATOR_VM_NUM = -2;
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java
index 15d022a..f85b0bd 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessHolder.java
@@ -15,6 +15,7 @@
 package org.apache.geode.test.dunit.internal;
 
 import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
 
 public class ProcessHolder {
   private final Process process;
@@ -38,6 +39,10 @@ public class ProcessHolder {
     process.waitFor();
   }
 
+  public void waitFor(long timeout, TimeUnit unit) throws InterruptedException {
+    process.waitFor(timeout, unit);
+  }
+
   public InputStream getErrorStream() {
     return process.getErrorStream();
   }
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessManager.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessManager.java
index c4fa0b2..32ab6c8 100755
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessManager.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/ProcessManager.java
@@ -25,7 +25,6 @@ import java.io.InputStreamReader;
 import java.io.PrintStream;
 import java.lang.management.ManagementFactory;
 import java.lang.management.RuntimeMXBean;
-import java.rmi.AccessException;
 import java.rmi.NotBoundException;
 import java.rmi.RemoteException;
 import java.rmi.registry.Registry;
@@ -44,7 +43,7 @@ import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.version.VersionManager;
 
-public class ProcessManager {
+class ProcessManager implements ChildVMLauncher {
   private int namingPort;
   private Map<Integer, ProcessHolder> processes = new HashMap<>();
   private File log4jConfig;
@@ -64,8 +63,12 @@ public class ProcessManager {
     launchVM(VersionManager.CURRENT_VERSION, vmNum, false);
   }
 
-  public synchronized void launchVM(String version, int vmNum, boolean bouncedVM)
+  @Override
+  public synchronized ProcessHolder launchVM(String version, int vmNum, boolean bouncedVM)
       throws IOException {
+    if (bouncedVM) {
+      processes.remove(vmNum);
+    }
     if (processes.containsKey(vmNum)) {
       throw new IllegalStateException("VM " + vmNum + " is already running.");
     }
@@ -100,6 +103,7 @@ public class ProcessManager {
       processes.put(vmNum, holder);
       linkStreams(version, vmNum, holder, holder.getErrorStream(), System.err);
       linkStreams(version, vmNum, holder, holder.getInputStream(), System.out);
+      return holder;
     } catch (RuntimeException | Error t) {
       t.printStackTrace();
       throw t;
@@ -133,6 +137,7 @@ public class ProcessManager {
     return false;
   }
 
+  @Deprecated
   public synchronized void bounce(String version, int vmNum, boolean force) {
     if (!processes.containsKey(vmNum)) {
       throw new IllegalStateException("No such process " + vmNum);
@@ -156,6 +161,7 @@ public class ProcessManager {
       final InputStream in, final PrintStream out) {
     final String vmName = "[" + VM.getVMName(version, vmNum) + "] ";
     Thread ioTransport = new Thread() {
+      @Override
       public void run() {
         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
         try {
@@ -345,6 +351,10 @@ public class ProcessManager {
     this.notifyAll();
   }
 
+  public synchronized boolean waitForVMs() throws InterruptedException {
+    return waitForVMs(DUnitLauncher.STARTUP_TIMEOUT);
+  }
+
   public synchronized boolean waitForVMs(long timeout) throws InterruptedException {
     long end = System.currentTimeMillis() + timeout;
     while (pendingVMs > 0) {
@@ -358,48 +368,19 @@ public class ProcessManager {
     return true;
   }
 
+  @Override
   public RemoteDUnitVMIF getStub(int i)
-      throws AccessException, RemoteException, NotBoundException, InterruptedException {
+      throws RemoteException, NotBoundException, InterruptedException {
     return getStub(VersionManager.CURRENT_VERSION, i);
   }
 
   public RemoteDUnitVMIF getStub(String version, int i)
-      throws AccessException, RemoteException, NotBoundException, InterruptedException {
+      throws RemoteException, NotBoundException, InterruptedException {
     waitForVMs(DUnitLauncher.STARTUP_TIMEOUT);
     return (RemoteDUnitVMIF) registry.lookup("vm" + i);
   }
 
-  private static class VersionedVMNumber {
-    String version;
-    int number;
-
-    VersionedVMNumber(String version, int number) {
-      this.version = version;
-      this.number = number;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (o == null || getClass() != o.getClass()) {
-        return false;
-      }
-
-      VersionedVMNumber that = (VersionedVMNumber) o;
-
-      if (number != that.number) {
-        return false;
-      }
-      return version.equals(that.version);
-    }
-
-    @Override
-    public int hashCode() {
-      int result = version.hashCode();
-      result = 31 * result + number;
-      return result;
-    }
+  public ProcessHolder getProcessHolder(int i) {
+    return processes.get(i);
   }
 }
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/RemoteDUnitVM.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/RemoteDUnitVM.java
index 46b7f86..04ff222 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/RemoteDUnitVM.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/RemoteDUnitVM.java
@@ -22,7 +22,7 @@ import org.apache.logging.log4j.Logger;
 
 import org.apache.geode.internal.logging.LogService;
 
-public class RemoteDUnitVM extends UnicastRemoteObject implements RemoteDUnitVMIF {
+class RemoteDUnitVM extends UnicastRemoteObject implements RemoteDUnitVMIF {
   private static final Logger logger = LogService.getLogger();
 
   RemoteDUnitVM() throws RemoteException {
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java
index 058cb88..56f6f56 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/ClusterStartupRule.java
@@ -17,7 +17,6 @@ package org.apache.geode.test.dunit.rules;
 
 import static org.apache.commons.lang3.SystemUtils.isJavaVersionAtLeast;
 import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
 import static org.apache.geode.test.dunit.Host.getHost;
 import static org.apache.geode.test.dunit.internal.DUnitLauncher.NUM_VMS;
 
@@ -38,13 +37,11 @@ import org.junit.rules.ExternalResource;
 import org.apache.geode.cache.client.ClientCache;
 import org.apache.geode.cache.client.ClientCacheFactory;
 import org.apache.geode.cache.server.CacheServer;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
 import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.test.dunit.DUnitEnv;
 import org.apache.geode.test.dunit.Host;
 import org.apache.geode.test.dunit.IgnoredException;
-import org.apache.geode.test.dunit.RMIException;
 import org.apache.geode.test.dunit.SerializableConsumerIF;
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.internal.DUnitLauncher;
@@ -329,34 +326,11 @@ public class ClusterStartupRule extends ExternalResource implements Serializable
   }
 
   /**
-   * this crashes the VM hosting the member/client. It removes the VM from the occupied VM list
-   * so that we can ignore it at cleanup.
+   * this crashes the VM hosting the member/client.
    */
   public void crashVM(int index) {
-    VMProvider member = occupiedVMs.remove(index);
-    member.invokeAsync(() -> {
-      if (InternalDistributedSystem.shutdownHook != null) {
-        Runtime.getRuntime().removeShutdownHook(InternalDistributedSystem.shutdownHook);
-      }
-      System.exit(1);
-    });
-
-    // wait till member is not reachable anymore.
-    await().until(() -> {
-      try {
-        member.invoke(() -> {
-        });
-      } catch (RMIException e) {
-        return true;
-      }
-      return false;
-    });
-
-    // delete the lingering files under this vm
-    Arrays.stream(member.getVM().getWorkingDirectory().listFiles())
-        .forEach(FileUtils::deleteQuietly);
-
-    member.getVM().bounce();
+    VMProvider member = occupiedVMs.get(index);
+    member.getVM().bounceForcibly();
   }
 
   public File getWorkingDirRoot() {
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/junit/rules/ClientCacheRule.java b/geode-dunit/src/main/java/org/apache/geode/test/junit/rules/ClientCacheRule.java
index 605de66..dbcfd8c 100644
--- a/geode-dunit/src/main/java/org/apache/geode/test/junit/rules/ClientCacheRule.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/junit/rules/ClientCacheRule.java
@@ -130,8 +130,12 @@ public class ClientCacheRule extends SerializableExternalResource {
 
   @Override
   public void after() {
-    if (cache != null) {
-      cache.close();
+    try {
+      if (cache != null) {
+        cache.close();
+      }
+    } catch (Exception ignored) {
+      // ignored
     }
     // this will clean up the SocketCreators created in this VM so that it won't contaminate
     // future tests