geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bschucha...@apache.org
Subject [4/6] geode git commit: GEODE-1965 Create backward-compatibility unit test framework
Date Tue, 24 Jan 2017 19:30:50 GMT
http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeDUnitTest.java
new file mode 100644
index 0000000..369bc3b
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/rollingupgrade/RollingUpgradeDUnitTest.java
@@ -0,0 +1,1051 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.cache.rollingupgrade;
+
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache30.CacheSerializableRunnable;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.internal.FileUtil;
+import org.apache.geode.internal.Version;
+import org.apache.geode.test.dunit.DistributedTestUtils;
+import org.apache.geode.test.dunit.Host;
+import org.apache.geode.test.dunit.IgnoredException;
+import org.apache.geode.test.dunit.Invoke;
+import org.apache.geode.test.dunit.LogWriterUtils;
+import org.apache.geode.test.dunit.NetworkUtils;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
+import org.apache.geode.test.dunit.standalone.DUnitLauncher;
+import org.apache.geode.test.dunit.standalone.VersionManager;
+import org.apache.geode.test.junit.categories.BackwardCompatibilityTest;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * RollingUpgrade dunit tests are distributed among subclasses of RollingUpgradeDUnitTest to avoid
+ * spurious "hangs" being declared by Hydra.
+ *
+ * This test will not run properly in eclipse at this point due to having to bounce vms Currently,
+ * bouncing vms is necessary because we are starting gemfire with different class loaders and the
+ * class loaders are lingering (possibly due to daemon threads - the vm itself is still running)
+ * 
+ * Note: to run in eclipse, I had to copy over the jg-magic-map.txt file into my GEMFIRE_OUTPUT
+ * location, in the same directory as #MagicNumberReader otherwise the two systems were unable to
+ * talk to one another due to one using a magic number and the other not. Also turnOffBounce will
+ * need to be set to true so that bouncing a vm doesn't lead to a NPE.
+ * 
+ * @author jhuynh
+ */
+
+@Category({DistributedTest.class, BackwardCompatibilityTest.class})
+@RunWith(Parameterized.class)
+@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
+public class RollingUpgradeDUnitTest extends JUnit4DistributedTestCase {
+
+  @Parameterized.Parameters
+  public static Collection<String> data() {
+    return VersionManager.getInstance().getVersionsWithoutCurrent();
+  }
+
+  private File[] testingDirs = new File[3];
+
+  private static String diskDir = "RollingUpgradeDUnitTest";
+
+  // Each vm will have a cache object
+  private static Object cache;
+
+  // the old version of Geode we're testing against
+  private String oldVersion;
+
+  private void deleteVMFiles() throws Exception {
+    System.out.println("deleting files in vm" + VM.getCurrentVMNum());
+    File pwd = new File(".");
+    for (File entry : pwd.listFiles()) {
+      try {
+        FileUtil.delete(entry);
+      } catch (Exception e) {
+        System.out.println("Could not delete " + entry + ": " + e.getMessage());
+      }
+    }
+  }
+
+  private void deleteWorkingDirFiles() throws Exception {
+    Invoke.invokeInEveryVM("delete files", () -> deleteVMFiles());
+  }
+
+  @Override
+  public void postSetUp() throws Exception {
+    deleteWorkingDirFiles();
+    IgnoredException.addIgnoredException(
+        "cluster configuration service not available|ConflictingPersistentDataException");
+  }
+
+  public RollingUpgradeDUnitTest(String version) {
+    oldVersion = version;
+  }
+
+  @Test
+  public void testRollServersOnReplicatedRegion_dataserializable() throws Exception {
+    doTestRollAll("replicate", "dataserializable", oldVersion);
+  }
+
+  @Test
+  public void testRollServersOnPartitionedRegion_dataserializable() throws Exception {
+    doTestRollAll("partitionedRedundant", "dataserializable", oldVersion);
+  }
+
+  @Test
+  public void testRollServersOnPersistentRegion_dataserializable() throws Exception {
+    doTestRollAll("persistentReplicate", "dataserializable", oldVersion);
+  }
+
+
+  // We start an "old" locator and old servers
+  // We roll the locator
+  // Now we roll all the servers from old to new
+  public void doTestRollAll(String regionType, String objectType, String startingVersion)
+      throws Exception {
+    final Host host = Host.getHost(0);
+    VM server1 = host.getVM(startingVersion, 0);
+    VM server2 = host.getVM(startingVersion, 1);
+    VM server3 = host.getVM(startingVersion, 2);
+    VM locator = host.getVM(startingVersion, 3);
+
+
+    String regionName = "aRegion";
+    String shortcutName = RegionShortcut.REPLICATE.name();
+    if (regionType.equals("replicate")) {
+      shortcutName = RegionShortcut.REPLICATE.name();
+    } else if ((regionType.equals("partitionedRedundant"))) {
+      shortcutName = RegionShortcut.PARTITION_REDUNDANT.name();
+    } else if ((regionType.equals("persistentReplicate"))) {
+      shortcutName = RegionShortcut.PARTITION_PERSISTENT.name();
+      for (int i = 0; i < testingDirs.length; i++) {
+        testingDirs[i] = new File(diskDir, "diskStoreVM_" + String.valueOf(host.getVM(i).getPid()))
+            .getAbsoluteFile();
+        if (!testingDirs[i].exists()) {
+          System.out.println(" Creating diskdir for server: " + i);
+          testingDirs[i].mkdirs();
+        }
+      }
+    }
+
+    int[] locatorPorts = AvailablePortHelper.getRandomAvailableTCPPorts(1);
+    String hostName = NetworkUtils.getServerHostName(host);
+    String locatorString = getLocatorString(locatorPorts);
+    final Properties locatorProps = new Properties();
+    // configure all class loaders for each vm
+
+    try {
+      locator.invoke(invokeStartLocator(hostName, locatorPorts[0], getTestMethodName(),
+          locatorString, locatorProps));
+      invokeRunnableInVMs(invokeCreateCache(getSystemProperties(locatorPorts)), server1, server2,
+          server3);
+
+      // create region
+      if ((regionType.equals("persistentReplicate"))) {
+        for (int i = 0; i < testingDirs.length; i++) {
+          CacheSerializableRunnable runnable =
+              invokeCreatePersistentReplicateRegion(regionName, testingDirs[i]);
+          invokeRunnableInVMs(runnable, host.getVM(i));
+        }
+      } else {
+        invokeRunnableInVMs(invokeCreateRegion(regionName, shortcutName), server1, server2,
+            server3);
+      }
+
+      putAndVerify(objectType, server1, regionName, 0, 10, server2, server3);
+      locator = rollLocatorToCurrent(locator, hostName, locatorPorts[0], getTestMethodName(),
+          locatorString);
+
+      server1 = rollServerToCurrentAndCreateRegion(server1, regionType, testingDirs[0],
+          shortcutName, regionName, locatorPorts);
+      verifyValues(objectType, regionName, 0, 10, server1);
+      putAndVerify(objectType, server1, regionName, 5, 15, server2, server3);
+      putAndVerify(objectType, server2, regionName, 10, 20, server1, server3);
+
+      server2 = rollServerToCurrentAndCreateRegion(server2, regionType, testingDirs[1],
+          shortcutName, regionName, locatorPorts);
+      verifyValues(objectType, regionName, 0, 10, server2);
+      putAndVerify(objectType, server2, regionName, 15, 25, server1, server3);
+      putAndVerify(objectType, server3, regionName, 20, 30, server2, server3);
+
+      server3 = rollServerToCurrentAndCreateRegion(server3, regionType, testingDirs[2],
+          shortcutName, regionName, locatorPorts);
+      verifyValues(objectType, regionName, 0, 10, server3);
+      putAndVerify(objectType, server3, regionName, 15, 25, server1, server2);
+      putAndVerify(objectType, server1, regionName, 20, 30, server1, server2, server3);
+
+
+    } finally {
+      invokeRunnableInVMs(true, invokeStopLocator(), locator);
+      invokeRunnableInVMs(true, invokeCloseCache(), server1, server2, server3);
+      if ((regionType.equals("persistentReplicate"))) {
+        deleteDiskStores();
+      }
+    }
+  }
+
+  // ******** TEST HELPER METHODS ********/
+  private void putAndVerify(String objectType, VM putter, String regionName, int start, int end,
+      VM check1, VM check2, VM check3) throws Exception {
+    if (objectType.equals("strings")) {
+      putStringsAndVerify(putter, regionName, start, end, check1, check2, check3);
+    } else if (objectType.equals("serializable")) {
+      putSerializableAndVerify(putter, regionName, start, end, check1, check2, check3);
+    } else if (objectType.equals("dataserializable")) {
+      putDataSerializableAndVerify(putter, regionName, start, end, check1, check2, check3);
+    } else {
+      throw new Error("Not a valid test object type");
+    }
+  }
+
+  // ******** TEST HELPER METHODS ********/
+  private void putAndVerify(String objectType, VM putter, String regionName, int start, int end,
+      VM check1, VM check2) throws Exception {
+    if (objectType.equals("strings")) {
+      putStringsAndVerify(putter, regionName, start, end, check1, check2);
+    } else if (objectType.equals("serializable")) {
+      putSerializableAndVerify(putter, regionName, start, end, check1, check2);
+    } else if (objectType.equals("dataserializable")) {
+      putDataSerializableAndVerify(putter, regionName, start, end, check1, check2);
+    } else {
+      throw new Error("Not a valid test object type");
+    }
+  }
+
+  private void putStringsAndVerify(VM putter, final String regionName, final int start,
+      final int end, VM... vms) {
+    for (int i = start; i < end; i++) {
+      putter.invoke(invokePut(regionName, "" + i, "VALUE(" + i + ")"));
+    }
+
+    threadSleep();
+
+    // verify present in others
+    for (VM vm : vms) {
+      vm.invoke(invokeAssertEntriesEqual(regionName, start, end));
+    }
+  }
+
+  private void putSerializableAndVerify(VM putter, String regionName, int start, int end,
+      VM... vms) {
+    for (int i = start; i < end; i++) {
+      putter.invoke(invokePut(regionName, "" + i, new Properties()));
+    }
+
+    threadSleep();
+
+    // verify present in others
+    for (VM vm : vms) {
+      vm.invoke(invokeAssertEntriesExist(regionName, start, end));
+    }
+  }
+
+  private void putDataSerializableAndVerify(VM putter, String regionName, int start, int end,
+      VM... vms) throws Exception {
+    for (int i = start; i < end; i++) {
+      Class aClass = Thread.currentThread().getContextClassLoader()
+          .loadClass("org.apache.geode.cache.ExpirationAttributes");
+      Constructor constructor = aClass.getConstructor(int.class);
+      Object testDataSerializable = constructor.newInstance(i);
+      putter.invoke(invokePut(regionName, "" + i, testDataSerializable));
+    }
+
+    threadSleep();
+
+    // verify present in others
+    for (VM vm : vms) {
+      vm.invoke(invokeAssertEntriesExist(regionName, start, end));
+    }
+  }
+
+  private void verifyValues(String objectType, String regionName, int start, int end, VM... vms) {
+    threadSleep();
+    if (objectType.equals("strings")) {
+      for (VM vm : vms) {
+        vm.invoke(invokeAssertEntriesEqual(regionName, start, end));
+      }
+    } else if (objectType.equals("serializable")) {
+      for (VM vm : vms) {
+        vm.invoke(invokeAssertEntriesExist(regionName, start, end));
+      }
+    } else if (objectType.equals("dataserializable")) {
+      for (VM vm : vms) {
+        vm.invoke(invokeAssertEntriesExist(regionName, start, end));
+      }
+    }
+  }
+
+  // Oddly the puts will return and for some reason the other vms have yet to recieve or process the
+  // put?
+  private void threadSleep() {
+    try {
+      Thread.sleep(250);
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+    }
+  }
+
+  private void query(String queryString, int numExpectedResults, VM... vms) {
+    for (VM vm : vms) {
+      vm.invoke(invokeAssertQueryResults(queryString, numExpectedResults));
+    }
+  }
+
+  private void invokeRunnableInVMs(CacheSerializableRunnable runnable, VM... vms) throws Exception {
+    for (VM vm : vms) {
+      vm.invoke(runnable);
+    }
+  }
+
+  // Used to close cache and make sure we attempt on all vms even if some do not have a cache
+  private void invokeRunnableInVMs(boolean catchErrors, CacheSerializableRunnable runnable,
+      VM... vms) throws Exception {
+    for (VM vm : vms) {
+      try {
+        vm.invoke(runnable);
+      } catch (Exception e) {
+        if (!catchErrors) {
+          throw e;
+        }
+      }
+    }
+  }
+
+  private VM rollServerToCurrent(VM oldServer, int[] locatorPorts) throws Exception {
+    // Roll the server
+    oldServer.invoke(invokeCloseCache());
+    VM rollServer = Host.getHost(0).getVM(oldServer.getPid()); // gets a vm with the current version
+    rollServer.invoke(invokeCreateCache(locatorPorts == null ? getSystemPropertiesPost71()
+        : getSystemPropertiesPost71(locatorPorts)));
+    rollServer.invoke(invokeAssertVersion(Version.CURRENT_ORDINAL));
+    return rollServer;
+  }
+
+  /*
+   * @param rollServer
+   * 
+   * @param createRegionMethod
+   * 
+   * @param regionName
+   * 
+   * @param locatorPorts if null, uses dunit locator
+   * 
+   * @throws Exception
+   */
+  private void rollServerToCurrentAndCreateRegion(VM rollServer, String shortcutName,
+      String regionName, int[] locatorPorts) throws Exception {
+    rollServerToCurrent(rollServer, locatorPorts);
+    // recreate region on "rolled" server
+    invokeRunnableInVMs(invokeCreateRegion(regionName, shortcutName), rollServer);
+    rollServer.invoke(invokeRebalance());
+  }
+
+  private VM rollServerToCurrentAndCreateRegion(VM oldServer, String regionType, File diskdir,
+      String shortcutName, String regionName, int[] locatorPorts) throws Exception {
+    VM rollServer = rollServerToCurrent(oldServer, locatorPorts);
+    // recreate region on "rolled" server
+    if ((regionType.equals("persistentReplicate"))) {
+      CacheSerializableRunnable runnable =
+          invokeCreatePersistentReplicateRegion(regionName, diskdir);
+      invokeRunnableInVMs(runnable, rollServer);
+    } else {
+      invokeRunnableInVMs(invokeCreateRegion(regionName, shortcutName), rollServer);
+    }
+    rollServer.invoke(invokeRebalance());
+    return rollServer;
+  }
+
+  private VM rollLocatorToCurrent(VM oldLocator, final String serverHostName, final int port,
+      final String testName, final String locatorString) throws Exception {
+    // Roll the locator
+    oldLocator.invoke(invokeStopLocator());
+    VM rollLocator = Host.getHost(0).getVM(oldLocator.getPid()); // gets a VM with current version
+    final Properties props = new Properties();
+    props.setProperty(DistributionConfig.ENABLE_CLUSTER_CONFIGURATION_NAME, "false");
+    rollLocator.invoke(invokeStartLocator(serverHostName, port, testName, locatorString, props));
+    return rollLocator;
+  }
+
+  // Due to licensing changes
+  public Properties getSystemPropertiesPost71() {
+    Properties props = getSystemProperties();
+    return props;
+  }
+
+  // Due to licensing changes
+  public Properties getSystemPropertiesPost71(int[] locatorPorts) {
+    Properties props = getSystemProperties(locatorPorts);
+    return props;
+  }
+
+  public Properties getSystemProperties() {
+    Properties props = DistributedTestUtils.getAllDistributedSystemProperties(new Properties());
+    props.remove("disable-auto-reconnect");
+    props.remove(DistributionConfig.OFF_HEAP_MEMORY_SIZE_NAME);
+    props.remove(DistributionConfig.LOCK_MEMORY_NAME);
+    return props;
+  }
+
+  public Properties getSystemProperties(int[] locatorPorts) {
+    Properties p = new Properties();
+    String locatorString = getLocatorString(locatorPorts);
+    p.setProperty("locators", locatorString);
+    p.setProperty("mcast-port", "0");
+    return p;
+  }
+
+  public Properties getClientSystemProperties() {
+    Properties p = new Properties();
+    p.setProperty("mcast-port", "0");
+    return p;
+  }
+
+  public static String getLocatorString(int locatorPort) {
+    String locatorString = getDUnitLocatorAddress() + "[" + locatorPort + "]";
+    return locatorString;
+  }
+
+  public static String getLocatorString(int[] locatorPorts) {
+    String locatorString = "";
+    int numLocators = locatorPorts.length;
+    for (int i = 0; i < numLocators; i++) {
+      locatorString += getLocatorString(locatorPorts[i]);
+      if (i + 1 < numLocators) {
+        locatorString += ",";
+      }
+    }
+    return locatorString;
+  }
+
+
+  private List<URL> addFile(File file) throws MalformedURLException {
+    ArrayList<URL> urls = new ArrayList<URL>();
+    if (file.isDirectory()) {
+      // Do not want to start cache with sample code xml
+      if (file.getName().contains("SampleCode")) {
+        return urls;
+      } else {
+        File[] files = file.listFiles();
+        for (File afile : files) {
+          urls.addAll(addFile(afile));
+        }
+      }
+    } else {
+      URL url = file.toURI().toURL();
+      urls.add(url);
+    }
+    return urls;
+  }
+
+
+
+  private CacheSerializableRunnable invokeStartLocator(final String serverHostName, final int port,
+      final String testName, final String locatorsString, final Properties props) {
+    return new CacheSerializableRunnable("execute: startLocator") {
+      public void run2() {
+        try {
+          startLocator(serverHostName, port, testName, locatorsString, props);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeStartLocatorAndServer(final String serverHostName,
+      final int port, final String testName, final Properties systemProperties) {
+    return new CacheSerializableRunnable("execute: startLocator") {
+      public void run2() {
+        try {
+          systemProperties.put(DistributionConfig.START_LOCATOR_NAME,
+              "" + serverHostName + "[" + port + "]");
+          RollingUpgradeDUnitTest.cache = createCache(systemProperties);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCreateCache(final Properties systemProperties) {
+    return new CacheSerializableRunnable("execute: createCache") {
+      public void run2() {
+        try {
+          RollingUpgradeDUnitTest.cache = createCache(systemProperties);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCreateClientCache(final Properties systemProperties,
+      final String[] hosts, final int[] ports) {
+    return new CacheSerializableRunnable("execute: createClientCache") {
+      public void run2() {
+        try {
+          RollingUpgradeDUnitTest.cache = createClientCache(systemProperties, hosts, ports);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeStartCacheServer(final int port) {
+    return new CacheSerializableRunnable("execute: startCacheServer") {
+      public void run2() {
+        try {
+          startCacheServer(RollingUpgradeDUnitTest.cache, port);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeAssertVersion(final short version) {
+    return new CacheSerializableRunnable("execute: assertVersion") {
+      public void run2() {
+        try {
+          assertVersion(RollingUpgradeDUnitTest.cache, version);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCreateRegion(final String regionName,
+      final String shortcutName) {
+    return new CacheSerializableRunnable("execute: createRegion") {
+      public void run2() {
+        try {
+          createRegion(RollingUpgradeDUnitTest.cache, regionName, shortcutName);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCreatePersistentReplicateRegion(final String regionName,
+      final File diskstore) {
+    return new CacheSerializableRunnable("execute: createPersistentReplicateRegion") {
+      public void run2() {
+        try {
+          createPersistentReplicateRegion(RollingUpgradeDUnitTest.cache, regionName, diskstore);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCreateClientRegion(final String regionName,
+      final String shortcutName) {
+    return new CacheSerializableRunnable("execute: createClientRegion") {
+      public void run2() {
+        try {
+          createClientRegion(RollingUpgradeDUnitTest.cache, regionName, shortcutName);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokePut(final String regionName, final Object key,
+      final Object value) {
+    return new CacheSerializableRunnable("execute: put") {
+      public void run2() {
+        try {
+          put(RollingUpgradeDUnitTest.cache, regionName, key, value);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeAssertEntriesEqual(final String regionName,
+      final int start, final int end) {
+    return new CacheSerializableRunnable("execute: assertEntriesEqual") {
+      public void run2() {
+        try {
+          for (int i = start; i < end; i++) {
+            assertEntryEquals(RollingUpgradeDUnitTest.cache, regionName, "" + i,
+                "VALUE(" + i + ")");
+          }
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeAssertEntriesExist(final String regionName,
+      final int start, final int end) {
+    return new CacheSerializableRunnable("execute: assertEntryExists") {
+      public void run2() {
+        try {
+          for (int i = start; i < end; i++) {
+            assertEntryExists(RollingUpgradeDUnitTest.cache, regionName, "" + i);
+          }
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeStopLocator() {
+    return new CacheSerializableRunnable("execute: stopLocator") {
+      public void run2() {
+        try {
+          stopLocator();
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeCloseCache() {
+    return new CacheSerializableRunnable("execute: closeCache") {
+      public void run2() {
+        try {
+          closeCache(RollingUpgradeDUnitTest.cache);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeRebalance() {
+    return new CacheSerializableRunnable("execute: rebalance") {
+      public void run2() {
+        try {
+          rebalance(RollingUpgradeDUnitTest.cache);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  private CacheSerializableRunnable invokeAssertQueryResults(final String queryString,
+      final int numExpected) {
+    return new CacheSerializableRunnable("execute: assertQueryResults") {
+      public void run2() {
+        try {
+          assertQueryResults(RollingUpgradeDUnitTest.cache, queryString, numExpected);
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+    };
+  }
+
+  public void deleteDiskStores() throws Exception {
+    try {
+      FileUtil.delete(new File(diskDir).getAbsoluteFile());
+    } catch (IOException e) {
+      throw new Error("Error deleting files", e);
+    }
+  }
+
+  public static Object createCache(Properties systemProperties) throws Exception {
+
+    // systemProperties.put(DistributionConfig.LOG_FILE_NAME,
+    // "rollingUpgradeCacheVM" + VM.getCurrentVMNum() + ".log");
+
+    Class distConfigClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.distributed.internal.DistributionConfigImpl");
+    boolean disableConfig = true;
+    try {
+      distConfigClass.getDeclaredField("useSharedConfiguration");
+    } catch (NoSuchFieldException e) {
+      disableConfig = false;
+    }
+    if (disableConfig) {
+      systemProperties.put(DistributionConfig.USE_CLUSTER_CONFIGURATION_NAME, "false");
+    }
+
+    Class cacheFactoryClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.cache.CacheFactory");
+    Constructor constructor = cacheFactoryClass.getConstructor(Properties.class);
+    constructor.setAccessible(true);
+    Object cacheFactory = constructor.newInstance(systemProperties);
+
+    Method createMethod = cacheFactoryClass.getMethod("create");
+    createMethod.setAccessible(true);
+    Object cache = null;
+    cache = createMethod.invoke(cacheFactory);
+    return cache;
+  }
+
+  public static void startCacheServer(Object cache, int port) throws Exception {
+    Method addCacheServerMethod = cache.getClass().getMethod("addCacheServer");
+    addCacheServerMethod.setAccessible(true);
+    Object cacheServer = addCacheServerMethod.invoke(cache);
+
+    Method setPortMethod = cacheServer.getClass().getMethod("setPort", int.class);
+    setPortMethod.setAccessible(true);
+    setPortMethod.invoke(cacheServer, port);
+
+    Method startMethod = cacheServer.getClass().getMethod("start");
+    startMethod.setAccessible(true);
+    startMethod.invoke(cacheServer);
+  }
+
+  public static Object createClientCache(Properties systemProperties, String[] hosts, int[] ports)
+      throws Exception {
+    Class aClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.cache.client.ClientCacheFactory");
+    Constructor constructor = aClass.getConstructor(Properties.class);
+    constructor.setAccessible(true);
+
+    Object ccf = constructor.newInstance(systemProperties);
+    Method addPoolLocatorMethod = aClass.getMethod("addPoolLocator", String.class, int.class);
+    addPoolLocatorMethod.setAccessible(true);
+    int hostsLength = hosts.length;
+    for (int i = 0; i < hostsLength; i++) {
+      addPoolLocatorMethod.invoke(ccf, hosts[i], ports[i]);
+    }
+
+    Method createMethod = aClass.getMethod("create");
+    createMethod.setAccessible(true);
+    Object cache = createMethod.invoke(ccf);
+
+    return cache;
+  }
+
+  public static boolean assertRegionExists(Object cache, String regionName) throws Exception {
+    Object region = cache.getClass().getMethod("getRegion", String.class).invoke(cache, regionName);
+    if (region == null) {
+      throw new Error("Region: " + regionName + " does not exist");
+    }
+    return true;
+  }
+
+  public static Object getRegion(Object cache, String regionName) throws Exception {
+    return cache.getClass().getMethod("getRegion", String.class).invoke(cache, regionName);
+  }
+
+  public static boolean assertEntryEquals(Object cache, String regionName, Object key, Object value)
+      throws Exception {
+    assertRegionExists(cache, regionName);
+    Object region = getRegion(cache, regionName);
+    Object regionValue = region.getClass().getMethod("get", Object.class).invoke(region, key);
+    if (regionValue == null) {
+      System.out.println("region value does not exist for key: " + key);
+      throw new Error("Region value does not exist for key:" + key);
+    }
+    if (!regionValue.equals(value)) {
+      System.out.println("Entry for key:" + key + " does not equal value: " + value);
+      throw new Error("Entry for key:" + key + " does not equal value: " + value);
+    }
+    return true;
+  }
+
+  public static boolean assertEntryExists(Object cache, String regionName, Object key)
+      throws Exception {
+    assertRegionExists(cache, regionName);
+    Object region = getRegion(cache, regionName);
+    Object regionValue = region.getClass().getMethod("get", Object.class).invoke(region, key);
+    if (regionValue == null) {
+      System.out.println("Entry for key:" + key + " does not exist");
+      throw new Error("Entry for key:" + key + " does not exist");
+    }
+    return true;
+  }
+
+  public static Object put(Object cache, String regionName, Object key, Object value)
+      throws Exception {
+    Object region = getRegion(cache, regionName);
+    return region.getClass().getMethod("put", Object.class, Object.class).invoke(region, key,
+        value);
+  }
+
+  public static void createRegion(Object cache, String regionName, String shortcutName)
+      throws Exception {
+    Class aClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.cache.RegionShortcut");
+    Object[] enumConstants = aClass.getEnumConstants();
+    Object shortcut = null;
+    int length = enumConstants.length;
+    for (int i = 0; i < length; i++) {
+      Object constant = enumConstants[i];
+      if (((Enum) constant).name().equals(shortcutName)) {
+        shortcut = constant;
+        break;
+      }
+    }
+
+    Method createRegionFactoryMethod = cache.getClass().getMethod("createRegionFactory", aClass);
+    createRegionFactoryMethod.setAccessible(true);
+    Object regionFactory = createRegionFactoryMethod.invoke(cache, shortcut);
+    Method createMethod = regionFactory.getClass().getMethod("create", String.class);
+    createMethod.setAccessible(true);
+    createMethod.invoke(regionFactory, regionName);
+  }
+
+  public static void createPartitionedRegion(Object cache, String regionName) throws Exception {
+    createRegion(cache, regionName, RegionShortcut.PARTITION.name());
+  }
+
+  public static void createPartitionedRedundantRegion(Object cache, String regionName)
+      throws Exception {
+    createRegion(cache, regionName, RegionShortcut.PARTITION_REDUNDANT.name());
+  }
+
+  public static void createReplicatedRegion(Object cache, String regionName) throws Exception {
+    createRegion(cache, regionName, RegionShortcut.REPLICATE.name());
+  }
+
+  // Assumes a client cache is passed
+  public static void createClientRegion(Object cache, String regionName, String shortcutName)
+      throws Exception {
+    Class aClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.cache.client.ClientRegionShortcut");
+    Object[] enumConstants = aClass.getEnumConstants();
+    Object shortcut = null;
+    int length = enumConstants.length;
+    for (int i = 0; i < length; i++) {
+      Object constant = enumConstants[i];
+      if (((Enum) constant).name().equals(shortcutName)) {
+        shortcut = constant;
+        break;
+      }
+    }
+    Object clientRegionFactory = cache.getClass()
+        .getMethod("createClientRegionFactory", shortcut.getClass()).invoke(cache, shortcut);
+    clientRegionFactory.getClass().getMethod("create", String.class).invoke(clientRegionFactory,
+        regionName);
+  }
+
+  public static void createRegion(String regionName, Object regionFactory) throws Exception {
+    regionFactory.getClass().getMethod("create", String.class).invoke(regionFactory, regionName);
+  }
+
+  public static void createPersistentReplicateRegion(Object cache, String regionName,
+      File diskStore) throws Exception {
+    Object store = cache.getClass().getMethod("findDiskStore", String.class).invoke(cache, "store");
+    Class dataPolicyObject = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.cache.DataPolicy");
+    Object dataPolicy = dataPolicyObject.getField("PERSISTENT_REPLICATE").get(null);
+    if (store == null) {
+      Object dsf = cache.getClass().getMethod("createDiskStoreFactory").invoke(cache);
+      dsf.getClass().getMethod("setMaxOplogSize", long.class).invoke(dsf, 1L);
+      dsf.getClass().getMethod("setDiskDirs", File[].class).invoke(dsf,
+          new Object[] {new File[] {diskStore.getAbsoluteFile()}});
+      dsf.getClass().getMethod("create", String.class).invoke(dsf, "store");
+    }
+    Object rf = cache.getClass().getMethod("createRegionFactory").invoke(cache);
+    rf.getClass().getMethod("setDiskStoreName", String.class).invoke(rf, "store");
+    rf.getClass().getMethod("setDataPolicy", dataPolicy.getClass()).invoke(rf, dataPolicy);
+    rf.getClass().getMethod("create", String.class).invoke(rf, regionName);
+  }
+
+  public static void assertVersion(Object cache, short ordinal) throws Exception {
+    Class idmClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.distributed.internal.membership.InternalDistributedMember");
+    Method getDSMethod = cache.getClass().getMethod("getDistributedSystem");
+    getDSMethod.setAccessible(true);
+    Object ds = getDSMethod.invoke(cache);
+
+    Method getDistributedMemberMethod = ds.getClass().getMethod("getDistributedMember");
+    getDistributedMemberMethod.setAccessible(true);
+    Object member = getDistributedMemberMethod.invoke(ds);
+    Method getVersionObjectMethod = member.getClass().getMethod("getVersionObject");
+    getVersionObjectMethod.setAccessible(true);
+    Object thisVersion = getVersionObjectMethod.invoke(member);
+    Method getOrdinalMethod = thisVersion.getClass().getMethod("ordinal");
+    getOrdinalMethod.setAccessible(true);
+    short thisOrdinal = (Short) getOrdinalMethod.invoke(thisVersion);
+    if (ordinal != thisOrdinal) {
+      throw new Error(
+          "Version ordinal:" + thisOrdinal + " was not the expected ordinal of:" + ordinal);
+    }
+  }
+
+  public static void assertQueryResults(Object cache, String queryString, int numExpectedResults) {
+    try {
+      Method getQSMethod = cache.getClass().getMethod("getQueryService");
+      getQSMethod.setAccessible(true);
+      Object qs = getQSMethod.invoke(cache);
+      Method newQueryMethod = qs.getClass().getMethod("newQuery", String.class);
+      newQueryMethod.setAccessible(true);
+      Object query = newQueryMethod.invoke(qs, queryString);
+      Method executeMethod = query.getClass().getMethod("execute");
+      executeMethod.setAccessible(true);
+      Object results = executeMethod.invoke(query);
+
+      Method sizeMethod = results.getClass().getMethod("size");
+      sizeMethod.setAccessible(true);
+      int numResults = (Integer) sizeMethod.invoke(results);
+
+      if (numResults != numExpectedResults) {
+        System.out.println("Num Results was:" + numResults);
+        throw new Error("Num results:" + numResults + " != num expected:" + numExpectedResults);
+      }
+    } catch (Exception e) {
+      throw new Error("Query Exception", e);
+    }
+  }
+
+  public static void stopCacheServers(Object cache) throws Exception {
+    Method getCacheServersMethod = cache.getClass().getMethod("getCacheServers");
+    getCacheServersMethod.setAccessible(true);
+    List cacheServers = (List) getCacheServersMethod.invoke(cache);
+    Method stopMethod = null;
+    for (Object cs : cacheServers) {
+      if (stopMethod == null) {
+        stopMethod = cs.getClass().getMethod("stop");
+      }
+      stopMethod.setAccessible(true);
+      stopMethod.invoke(cs);
+    }
+  }
+
+  public static void closeCache(Object cache) throws Exception {
+    if (cache == null) {
+      return;
+    }
+    Method isClosedMethod = cache.getClass().getMethod("isClosed");
+    isClosedMethod.setAccessible(true);
+    boolean cacheClosed = (Boolean) isClosedMethod.invoke(cache);
+    if (cache != null && !cacheClosed) {
+      stopCacheServers(cache);
+      Method method = cache.getClass().getMethod("close");
+      method.setAccessible(true);
+      method.invoke(cache);
+      long startTime = System.currentTimeMillis();
+      while (!cacheClosed && System.currentTimeMillis() - startTime < 30000) {
+        try {
+          Thread.sleep(1000);
+          Method cacheClosedMethod = cache.getClass().getMethod("isClosed");
+          cacheClosedMethod.setAccessible(true);
+          cacheClosed = (Boolean) cacheClosedMethod.invoke(cache);
+        } catch (InterruptedException e) {
+          Thread.currentThread().interrupt();
+        }
+      }
+    }
+    cache = null;
+  }
+
+  public static void rebalance(Object cache) throws Exception {
+    Method getRMMethod = cache.getClass().getMethod("getResourceManager");
+    getRMMethod.setAccessible(true);
+    Object manager = getRMMethod.invoke(cache);
+
+    Method createRebalanceFactoryMethod = manager.getClass().getMethod("createRebalanceFactory");
+    createRebalanceFactoryMethod.setAccessible(true);
+    Object rebalanceFactory = createRebalanceFactoryMethod.invoke(manager);
+    Object op = null;
+    Method m = rebalanceFactory.getClass().getMethod("start");
+    m.setAccessible(true);
+    op = m.invoke(rebalanceFactory);
+
+    // Wait until the rebalance is completex
+    try {
+      Method getResultsMethod = op.getClass().getMethod("getResults");
+      getResultsMethod.setAccessible(true);
+      Object results = getResultsMethod.invoke(op);
+      Method getTotalTimeMethod = results.getClass().getMethod("getTotalTime");
+      getTotalTimeMethod.setAccessible(true);
+      System.out.println("Took " + getTotalTimeMethod.invoke(results) + " milliseconds\n");
+      Method getTotalBucketsMethod = results.getClass().getMethod("getTotalBucketTransferBytes");
+      getTotalBucketsMethod.setAccessible(true);
+      System.out.println("Transfered " + getTotalBucketsMethod.invoke(results) + "bytes\n");
+    } catch (Exception e) {
+      Thread.currentThread().interrupt();
+      throw e;
+    }
+  }
+
+  /**
+   * Starts a locator with given configuration.
+   * 
+   * @param props TODO
+   */
+  public static void startLocator(final String serverHostName, final int port,
+      final String testName, final String locatorsString, final Properties props) throws Exception {
+    props.setProperty(DistributionConfig.MCAST_PORT_NAME, "0");
+    props.setProperty(DistributionConfig.LOCATORS_NAME, locatorsString);
+    props.setProperty(DistributionConfig.LOG_LEVEL_NAME, LogWriterUtils.getDUnitLogLevel());
+
+    InetAddress bindAddr = null;
+    try {
+      bindAddr = InetAddress.getByName(serverHostName);// getServerHostName(vm.getHost()));
+    } catch (UnknownHostException uhe) {
+      throw new Error("While resolving bind address ", uhe);
+    }
+
+    File logFile = new File(testName + "-locator" + port + ".log");
+    Class locatorClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.distributed.Locator");
+    Method startLocatorAndDSMethod =
+        locatorClass.getMethod("startLocatorAndDS", int.class, File.class, InetAddress.class,
+            Properties.class, boolean.class, boolean.class, String.class);
+    startLocatorAndDSMethod.setAccessible(true);
+    startLocatorAndDSMethod.invoke(null, port, logFile, bindAddr, props, true, true, null);
+  }
+
+  public static void stopLocator() throws Exception {
+    Class internalLocatorClass = Thread.currentThread().getContextClassLoader()
+        .loadClass("org.apache.geode.distributed.internal.InternalLocator");
+    Method locatorMethod = internalLocatorClass.getMethod("getLocator");
+    locatorMethod.setAccessible(true);
+    Object locator = locatorMethod.invoke(null);
+    Method stopLocatorMethod = locator.getClass().getMethod("stop");
+    stopLocatorMethod.setAccessible(true);
+    stopLocatorMethod.invoke(locator);
+  }
+
+  /**
+   * Get the port that the standard dunit locator is listening on.
+   * 
+   * @return
+   */
+  public static String getDUnitLocatorAddress() {
+    return Host.getHost(0).getHostName();
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscBCDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscBCDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscBCDUnitTest.java
new file mode 100755
index 0000000..54367fd
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscBCDUnitTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.cache.tier.sockets;
+
+import org.apache.geode.test.dunit.standalone.VersionManager;
+import org.apache.geode.test.junit.categories.BackwardCompatibilityTest;
+import org.apache.geode.test.junit.categories.ClientServerTest;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Collection;
+
+@Category({DistributedTest.class, ClientServerTest.class, BackwardCompatibilityTest.class})
+@RunWith(Parameterized.class)
+@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
+public class ClientServerMiscBCDUnitTest extends ClientServerMiscDUnitTest {
+  @Parameterized.Parameters
+  public static Collection<String> data() {
+    return VersionManager.getInstance().getVersionsWithoutCurrent();
+  }
+
+  public ClientServerMiscBCDUnitTest(String version) {
+    super();
+    testVersion = version;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java
index 391653c..b4f3185 100755
--- a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscDUnitTest.java
@@ -14,21 +14,16 @@
  */
 package org.apache.geode.internal.cache.tier.sockets;
 
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-import static org.junit.Assert.*;
-
-import java.util.Iterator;
-import java.util.Properties;
-import java.util.Set;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import org.apache.geode.GemFireConfigException;
-import org.apache.geode.cache.client.ClientCache;
-import org.apache.geode.cache.client.ClientCacheFactory;
-import org.apache.geode.test.dunit.DistributedTestUtils;
-import org.apache.geode.test.junit.categories.ClientServerTest;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
 import org.apache.geode.GemFireIOException;
 import org.apache.geode.cache.AttributesFactory;
 import org.apache.geode.cache.Cache;
@@ -38,6 +33,7 @@ import org.apache.geode.cache.DataPolicy;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionAttributes;
 import org.apache.geode.cache.Scope;
+import org.apache.geode.cache.client.ClientCacheFactory;
 import org.apache.geode.cache.client.NoAvailableServersException;
 import org.apache.geode.cache.client.Pool;
 import org.apache.geode.cache.client.PoolManager;
@@ -54,6 +50,7 @@ import org.apache.geode.internal.cache.CacheServerImpl;
 import org.apache.geode.internal.cache.GemFireCacheImpl;
 import org.apache.geode.internal.cache.LocalRegion;
 import org.apache.geode.test.dunit.Assert;
+import org.apache.geode.test.dunit.DistributedTestUtils;
 import org.apache.geode.test.dunit.Host;
 import org.apache.geode.test.dunit.IgnoredException;
 import org.apache.geode.test.dunit.LogWriterUtils;
@@ -62,7 +59,19 @@ import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.Wait;
 import org.apache.geode.test.dunit.WaitCriterion;
 import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
+import org.apache.geode.test.dunit.standalone.VersionManager;
+import org.apache.geode.test.junit.categories.ClientServerTest;
 import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
 
 /**
  * Tests client server corner cases between Region and Pool
@@ -115,11 +124,18 @@ public class ClientServerMiscDUnitTest extends JUnit4CacheTestCase {
   final int removeRange_2Start = 7;
   final int removeRange_2End = 9;
 
+  protected String testVersion; // version for client caches for backward-compatibility
+                                // testing
+
+  public ClientServerMiscDUnitTest() {
+    testVersion = VersionManager.CURRENT_VERSION;
+  }
+
   @Override
   public final void postSetUp() throws Exception {
     host = Host.getHost(0);
-    server1 = host.getVM(0);
-    server2 = host.getVM(1);
+    server1 = host.getVM(2);
+    server2 = host.getVM(3);
   }
 
   private int initServerCache(boolean notifyBySub) {
@@ -140,16 +156,16 @@ public class ClientServerMiscDUnitTest extends JUnit4CacheTestCase {
     int port1 = initServerCache(true); // vm0
     int port2 = initServerCache2(true); // vm1
     String serverName = NetworkUtils.getServerHostName(Host.getHost(0));
-    host.getVM(2).invoke(() -> this.createClientCacheV(serverName, port1));
-    host.getVM(3).invoke(() -> this.createClientCacheV(serverName, port2));
+    host.getVM(testVersion, 0).invoke(() -> this.createClientCacheV(serverName, port1));
+    host.getVM(testVersion, 1).invoke(() -> this.createClientCacheV(serverName, port2));
     LogWriterUtils.getLogWriter()
         .info("Testing concurrent map operations from a client with a distributed region");
-    concurrentMapTest(host.getVM(2), "/" + REGION_NAME1);
-    // TODO add verification in vm3
+    concurrentMapTest(host.getVM(testVersion, 0), "/" + REGION_NAME1);
+    // TODO add verification in vm1
     LogWriterUtils.getLogWriter()
         .info("Testing concurrent map operations from a client with a partitioned region");
-    concurrentMapTest(host.getVM(2), "/" + PR_REGION_NAME);
-    // TODO add verification in vm3
+    concurrentMapTest(host.getVM(testVersion, 0), "/" + PR_REGION_NAME);
+    // TODO add verification in vm1
   }
 
   @Test
@@ -157,16 +173,16 @@ public class ClientServerMiscDUnitTest extends JUnit4CacheTestCase {
     int port1 = initServerCache(true); // vm0
     int port2 = initServerCache2(true); // vm1
     String serverName = NetworkUtils.getServerHostName(Host.getHost(0));
-    host.getVM(2).invoke(() -> this.createEmptyClientCache(serverName, port1));
-    host.getVM(3).invoke(() -> this.createClientCacheV(serverName, port2));
+    host.getVM(testVersion, 0).invoke(() -> this.createEmptyClientCache(serverName, port1));
+    host.getVM(testVersion, 1).invoke(() -> this.createClientCacheV(serverName, port2));
     LogWriterUtils.getLogWriter()
         .info("Testing concurrent map operations from a client with a distributed region");
-    concurrentMapTest(host.getVM(2), "/" + REGION_NAME1);
-    // TODO add verification in vm3
+    concurrentMapTest(host.getVM(testVersion, 0), "/" + REGION_NAME1);
+    // TODO add verification in vm1
     LogWriterUtils.getLogWriter()
         .info("Testing concurrent map operations from a client with a partitioned region");
-    concurrentMapTest(host.getVM(2), "/" + PR_REGION_NAME);
-    // TODO add verification in vm3
+    concurrentMapTest(host.getVM(testVersion, 0), "/" + PR_REGION_NAME);
+    // TODO add verification in vm1
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscSelectorDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscSelectorDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscSelectorDUnitTest.java
index e177b79..6ea9c67 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscSelectorDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/cache/tier/sockets/ClientServerMiscSelectorDUnitTest.java
@@ -15,23 +15,16 @@
 package org.apache.geode.internal.cache.tier.sockets;
 
 import org.apache.geode.test.junit.categories.ClientServerTest;
-import org.junit.experimental.categories.Category;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-import org.apache.geode.test.dunit.cache.internal.JUnit4CacheTestCase;
-import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
 import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.experimental.categories.Category;
 
 
 /**
  * Just like parent but enables server thread pool (ie. selector)
- *
- *
  */
 @Category({DistributedTest.class, ClientServerTest.class})
 public class ClientServerMiscSelectorDUnitTest extends ClientServerMiscDUnitTest {
+
   public ClientServerMiscSelectorDUnitTest() {
     super();
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/DUnitEnv.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/DUnitEnv.java b/geode-core/src/test/java/org/apache/geode/test/dunit/DUnitEnv.java
index efc196f..42ccf38 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/DUnitEnv.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/DUnitEnv.java
@@ -66,8 +66,10 @@ public abstract class DUnitEnv {
 
   public abstract int getVMID();
 
-  public abstract BounceResult bounce(int pid) throws RemoteException;
+  public abstract BounceResult bounce(String version, int pid) throws RemoteException;
 
   public abstract File getWorkingDirectory(int pid);
 
+  public abstract File getWorkingDirectory(String version, int pid);
+
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/Host.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/Host.java b/geode-core/src/test/java/org/apache/geode/test/dunit/Host.java
old mode 100644
new mode 100755
index 43cbccf..277c803
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/Host.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/Host.java
@@ -17,9 +17,12 @@ package org.apache.geode.test.dunit;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.geode.test.dunit.standalone.RemoteDUnitVMIF;
+import org.apache.geode.test.dunit.standalone.VersionManager;
 
 /**
  * <P>
@@ -93,6 +96,22 @@ public abstract class Host implements Serializable {
     }
   }
 
+  /**
+   * Reset all VMs to be using the current version of Geode. Some backward-compatibility tests will
+   * set a VM to a different version. This will ensure that all are using the current build.
+   */
+  public static void setAllVMsToCurrentVersion() {
+    int numHosts = getHostCount();
+    for (int hostIndex = 0; hostIndex < numHosts; hostIndex++) {
+      Host host = Host.getHost(hostIndex);
+      int numVMs = host.getVMCount();
+      for (int i = 0; i < numVMs; i++) {
+        host.getVM(VersionManager.CURRENT_VERSION, i);
+      }
+    }
+
+  }
+
   ///////////////////// Constructors //////////////////////
 
   /**
@@ -145,6 +164,25 @@ public abstract class Host implements Serializable {
   }
 
   /**
+   * return a collection of all VMs
+   */
+  public Set<VM> getAllVMs() {
+    return new HashSet<>(vms);
+  }
+
+  /**
+   * Returns the nth VM of the given version. Optional operation currently supported only in
+   * distributedTests.
+   * 
+   * @param version
+   * @param n
+   * @return the requested VM
+   */
+  public VM getVM(String version, int n) {
+    throw new UnsupportedOperationException("Not supported in this implementation of Host");
+  }
+
+  /**
    * Adds a VM to this <code>Host</code> with the given process id and client record.
    */
   protected void addVM(int pid, RemoteDUnitVMIF client) {

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/Invoke.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/Invoke.java b/geode-core/src/test/java/org/apache/geode/test/dunit/Invoke.java
index a09f5ff..002abd4 100755
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/Invoke.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/Invoke.java
@@ -52,8 +52,7 @@ public class Invoke {
     for (int hostIndex = 0; hostIndex < Host.getHostCount(); hostIndex++) {
       Host host = Host.getHost(hostIndex);
 
-      for (int vmIndex = 0; vmIndex < host.getVMCount(); vmIndex++) {
-        VM vm = host.getVM(vmIndex);
+      for (VM vm : host.getAllVMs()) {
         if (name != null)
           vm.invoke(name, runnable);
         else
@@ -74,8 +73,7 @@ public class Invoke {
     for (int hostIndex = 0; hostIndex < Host.getHostCount(); hostIndex++) {
       Host host = Host.getHost(hostIndex);
 
-      for (int vmIndex = 0; vmIndex < host.getVMCount(); vmIndex++) {
-        VM vm = host.getVM(vmIndex);
+      for (VM vm : host.getAllVMs()) {
         vm.invoke(targetClass, targetMethod);
       }
     }
@@ -93,8 +91,7 @@ public class Invoke {
     for (int hostIndex = 0; hostIndex < Host.getHostCount(); hostIndex++) {
       Host host = Host.getHost(hostIndex);
 
-      for (int vmIndex = 0; vmIndex < host.getVMCount(); vmIndex++) {
-        VM vm = host.getVM(vmIndex);
+      for (VM vm : host.getAllVMs()) {
         vm.invoke(targetClass, targetMethod, methodArgs);
       }
     }
@@ -116,8 +113,7 @@ public class Invoke {
     Map<VM, T> ret = new HashMap<VM, T>();
     for (int h = 0; h < Host.getHostCount(); h++) {
       Host host = Host.getHost(h);
-      for (int v = 0; v < host.getVMCount(); v++) {
-        VM vm = host.getVM(v);
+      for (VM vm : host.getAllVMs()) {
         if (name != null)
           ret.put(vm, vm.invoke(name, callable));
         else

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/VM.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/VM.java b/geode-core/src/test/java/org/apache/geode/test/dunit/VM.java
index 04d2951..6055f8b 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/VM.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/VM.java
@@ -28,6 +28,7 @@ import org.apache.geode.internal.process.ProcessUtils;
 import org.apache.geode.test.dunit.standalone.BounceResult;
 import org.apache.geode.test.dunit.standalone.RemoteDUnitVMIF;
 import org.apache.geode.test.dunit.standalone.StandAloneDUnitEnv;
+import org.apache.geode.test.dunit.standalone.VersionManager;
 
 /**
  * This class represents a Java Virtual Machine that runs on a host.
@@ -41,6 +42,9 @@ public class VM implements Serializable {
   /** The process id of this VM */
   private int pid;
 
+  /** The version of Geode used in this VM */
+  private String version;
+
   /** The hydra client for this VM */
   private RemoteDUnitVMIF client;
 
@@ -69,13 +73,32 @@ public class VM implements Serializable {
   }
 
   /**
+   * Returns the name of a VM for use in the RMI naming service or working directory on disk
+   */
+  public static String getVMName(String version, int pid) {
+    if (pid == -2) {
+      return "locator";
+    }
+    if (pid < 0 || VersionManager.isCurrentVersion(version)) {
+      return "vm" + pid;
+    } else {
+      return "vm" + pid + "_v" + version;
+    }
+  }
+
+  /**
    * Creates a new {@code VM} that runs on a given host with a given process id.
    *
    * TODO: change pid to reflect value from {@link ProcessUtils#identifyPid()}
    */
   public VM(final Host host, final int pid, final RemoteDUnitVMIF client) {
+    this(host, VersionManager.CURRENT_VERSION, pid, client);
+  }
+
+  public VM(final Host host, final String version, final int pid, final RemoteDUnitVMIF client) {
     this.host = host;
     this.pid = pid;
+    this.version = version;
     this.client = client;
     this.available = true;
   }
@@ -88,6 +111,16 @@ public class VM implements Serializable {
   }
 
   /**
+   * Returns the version of Geode used in this VM.
+   * 
+   * @see VersionManager#CURRENT_VERSION
+   * @see Host#getVM(String, int)
+   */
+  public String getVersion() {
+    return this.version;
+  }
+
+  /**
    * Returns the process id of this {@code VM}.
    */
   public int getPid() {
@@ -359,6 +392,10 @@ public class VM implements Serializable {
    *         {@code hydra.Prms#maxClientStartupWaitSec}.
    */
   public synchronized void bounce() {
+    bounce(this.version);
+  }
+
+  public synchronized void bounce(String targetVersion) {
     if (!this.available) {
       throw new RMIException(this, getClass().getName(), "bounceVM",
           new IllegalStateException("VM not available: " + this));
@@ -367,9 +404,10 @@ public class VM implements Serializable {
     this.available = false;
 
     try {
-      BounceResult result = DUnitEnv.get().bounce(this.pid);
+      BounceResult result = DUnitEnv.get().bounce(targetVersion, this.pid);
       this.pid = result.getNewPid();
       this.client = result.getNewClient();
+      this.version = targetVersion;
       this.available = true;
 
     } catch (UnsupportedOperationException e) {
@@ -386,11 +424,12 @@ public class VM implements Serializable {
   }
 
   public String toString() {
-    return "VM " + getPid() + " running on " + getHost();
+    return "VM " + getPid() + " running on " + getHost()
+        + (VersionManager.isCurrentVersion(version) ? "" : (" with version " + version));
   }
 
   public File getWorkingDirectory() {
-    return DUnitEnv.get().getWorkingDirectory(getPid());
+    return DUnitEnv.get().getWorkingDirectory(getVersion(), getPid());
   }
 
   private MethExecutorResult execute(final Class targetClass, final String methodName,

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ChildVM.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ChildVM.java b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ChildVM.java
index b85d0b5..634e09f 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ChildVM.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ChildVM.java
@@ -18,6 +18,7 @@ import java.rmi.Naming;
 
 import org.apache.geode.internal.OSProcess;
 import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
 import org.apache.geode.test.dunit.standalone.DUnitLauncher.MasterRemote;
 
@@ -43,14 +44,19 @@ public class ChildVM {
     try {
       int namingPort = Integer.getInteger(DUnitLauncher.RMI_PORT_PARAM);
       int vmNum = Integer.getInteger(DUnitLauncher.VM_NUM_PARAM);
+      String geodeVersion = System.getProperty(DUnitLauncher.VM_VERSION_PARAM);
       int pid = OSProcess.getId();
       logger.info("VM" + vmNum + " is launching" + (pid > 0 ? " with PID " + pid : ""));
+      if (!VersionManager.isCurrentVersion(geodeVersion)) {
+        logger.info("This VM is using Geode version {}", geodeVersion);
+      }
       MasterRemote holder = (MasterRemote) Naming
           .lookup("//localhost:" + namingPort + "/" + DUnitLauncher.MASTER_PARAM);
       DUnitLauncher.init(holder);
       DUnitLauncher.locatorPort = holder.getLocatorPort();
       final RemoteDUnitVM dunitVM = new RemoteDUnitVM();
-      Naming.rebind("//localhost:" + namingPort + "/vm" + vmNum, dunitVM);
+      final String name = "//localhost:" + namingPort + "/vm" + vmNum;
+      Naming.rebind(name, dunitVM);
       JUnit4DistributedTestCase.initializeBlackboard();
       holder.signalVMReady();
       // This loop is here so this VM will die even if the master is mean killed.

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java
index 8587ea5..abbfea9 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/DUnitLauncher.java
@@ -14,8 +14,15 @@
  */
 package org.apache.geode.test.dunit.standalone;
 
-import batterytest.greplogs.ExpectedStrings;
-import batterytest.greplogs.LogConsumer;
+import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.InternalLocator;
@@ -26,8 +33,6 @@ import org.apache.geode.test.dunit.DUnitEnv;
 import org.apache.geode.test.dunit.Host;
 import org.apache.geode.test.dunit.SerializableCallable;
 import org.apache.geode.test.dunit.VM;
-import hydra.MethExecutorResult;
-
 import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
@@ -37,37 +42,55 @@ import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.junit.Assert;
 
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.net.URISyntaxException;
 import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
-import java.rmi.*;
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
 import java.rmi.registry.LocateRegistry;
 import java.rmi.registry.Registry;
 import java.rmi.server.UnicastRemoteObject;
 import java.util.List;
 import java.util.Properties;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
+import batterytest.greplogs.ExpectedStrings;
+import batterytest.greplogs.LogConsumer;
+import hydra.MethExecutorResult;
 
 /**
  * A class to build a fake test configuration and launch some DUnit VMS.
- * 
+ *
  * For use within eclipse. This class completely skips hydra and just starts some vms directly,
  * creating a fake test configuration
- * 
+ *
  * Also, it's a good idea to set your working directory, because the test code a lot of files that
  * it leaves around.
  */
 public class DUnitLauncher {
 
-  /** change this to use a different log level in unit tests */
+  /**
+   * change this to use a different log level in unit tests
+   */
   public static final String logLevel = System.getProperty("logLevel", "info");
 
   public static final String LOG4J = System.getProperty("log4j.configurationFile");
 
+  /**
+   * change this to have dunit/vmX directories deleted and recreated when processes are launched
+   */
+  public static final boolean MAKE_NEW_WORKING_DIRS =
+      Boolean.getBoolean("makeNewWorkingDirsOnBounce");
+
   static int locatorPort;
 
   private static final int NUM_VMS = 4;
@@ -83,12 +106,12 @@ public class DUnitLauncher {
   public static final boolean LOCATOR_LOG_TO_DISK = Boolean.getBoolean("locatorLogToDisk");
 
   static final String MASTER_PARAM = "DUNIT_MASTER";
-  public static final String RMI_PORT_PARAM =
-      DistributionConfig.GEMFIRE_PREFIX + "DUnitLauncher.RMI_PORT";
-  static final String VM_NUM_PARAM = DistributionConfig.GEMFIRE_PREFIX + "DUnitLauncher.VM_NUM";
 
-  private static final String LAUNCHED_PROPERTY =
-      DistributionConfig.GEMFIRE_PREFIX + "DUnitLauncher.LAUNCHED";
+  public static final String RMI_PORT_PARAM = GEMFIRE_PREFIX + "DUnitLauncher.RMI_PORT";
+  static final String VM_NUM_PARAM = GEMFIRE_PREFIX + "DUnitLauncher.VM_NUM";
+  static final String VM_VERSION_PARAM = GEMFIRE_PREFIX + "DUnitLauncher.VM_VERSION";
+
+  private static final String LAUNCHED_PROPERTY = GEMFIRE_PREFIX + "DUnitLauncher.LAUNCHED";
 
   private static Master master;
 
@@ -123,6 +146,8 @@ public class DUnitLauncher {
         throw new RuntimeException("Unable to launch dunit VMS", e);
       }
     }
+
+    Host.setAllVMsToCurrentVersion();
   }
 
   /**
@@ -189,7 +214,6 @@ public class DUnitLauncher {
       }
     });
 
-
     // Create a VM for the locator
     processManager.launchVM(LOCATOR_VM_NUM);
 
@@ -202,7 +226,6 @@ public class DUnitLauncher {
 
     init(master);
 
-
     // Launch an initial set of VMs
     for (int i = 0; i < NUM_VMS; i++) {
       processManager.launchVM(i);
@@ -305,7 +328,7 @@ public class DUnitLauncher {
     addSuspectFileAppender(workspaceDir);
 
     // Free off heap memory when disconnecting from the distributed system
-    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + "free-off-heap-memory", "true");
+    System.setProperty(GEMFIRE_PREFIX + "free-off-heap-memory", "true");
 
     // indicate that this CM is controlled by the eclipse dunit.
     System.setProperty(LAUNCHED_PROPERTY, "true");
@@ -368,6 +391,7 @@ public class DUnitLauncher {
     }
   }
 
+
   public interface MasterRemote extends Remote {
     public int getLocatorPort() throws RemoteException;
 
@@ -376,6 +400,8 @@ public class DUnitLauncher {
     public void ping() throws RemoteException;
 
     public BounceResult bounce(int pid) throws RemoteException;
+
+    public BounceResult bounce(String version, int pid) throws RemoteException;
   }
 
   public static class Master extends UnicastRemoteObject implements MasterRemote {
@@ -404,13 +430,19 @@ public class DUnitLauncher {
 
     @Override
     public BounceResult bounce(int pid) {
-      processManager.bounce(pid);
+      return bounce(VersionManager.CURRENT_VERSION, pid);
+    }
+
+    @Override
+    public BounceResult bounce(String version, int pid) {
+      processManager.bounce(version, pid);
 
       try {
         if (!processManager.waitForVMs(STARTUP_TIMEOUT)) {
           throw new RuntimeException("VMs did not start up with 30 seconds");
         }
-        RemoteDUnitVMIF remote = (RemoteDUnitVMIF) registry.lookup("vm" + pid);
+        RemoteDUnitVMIF remote =
+            (RemoteDUnitVMIF) registry.lookup(VM.getVMName(VersionManager.CURRENT_VERSION, pid));
         return new BounceResult(pid, remote);
       } catch (RemoteException | NotBoundException e) {
         throw new RuntimeException("could not lookup name", e);
@@ -447,25 +479,45 @@ public class DUnitLauncher {
 
     @Override
     public VM getVM(int n) {
+      return getVM(VersionManager.CURRENT_VERSION, n);
+    }
 
+    @Override
+    public VM getVM(String version, int n) {
       if (n == DEBUGGING_VM_NUM) {
         // for ease of debugging, pass -1 to get the local VM
         return debuggingVM;
       }
 
+      if (n < getVMCount()) {
+        VM current = super.getVM(n);
+        if (!current.getVersion().equals(version)) {
+          System.out.println(
+              "Bouncing VM" + n + " from version " + current.getVersion() + " to " + version);
+          current.bounce(version);
+        }
+        return current;
+      }
+
       int oldVMCount = getVMCount();
       if (n >= oldVMCount) {
         // If we don't have a VM with that number, dynamically create it.
         try {
-          for (int i = oldVMCount; i <= n; i++) {
+          // first fill in any gaps, to keep the superclass, Host, happy
+          for (int i = oldVMCount; i < n; i++) {
             processManager.launchVM(i);
           }
           processManager.waitForVMs(STARTUP_TIMEOUT);
 
-          for (int i = oldVMCount; i <= n; i++) {
+          for (int i = oldVMCount; i < n; i++) {
             addVM(i, processManager.getStub(i));
           }
 
+          // now create the one we really want
+          processManager.launchVM(version, n, false);
+          processManager.waitForVMs(STARTUP_TIMEOUT);
+          addVM(n, processManager.getStub(n));
+
         } catch (IOException | InterruptedException | NotBoundException e) {
           throw new RuntimeException("Could not dynamically launch vm + " + n, e);
         }

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ProcessManager.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ProcessManager.java b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ProcessManager.java
index c3c33d0..dce4353 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ProcessManager.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/ProcessManager.java
@@ -38,41 +38,54 @@ import org.apache.commons.io.FileUtils;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.internal.FileUtil;
+import org.apache.geode.test.dunit.VM;
 
 /**
  *
  */
 public class ProcessManager {
   private int namingPort;
-  private Map<Integer, ProcessHolder> processes = new HashMap<Integer, ProcessHolder>();
+  private Map<Integer, ProcessHolder> processes = new HashMap<>();
   private File log4jConfig;
   private int pendingVMs;
   private Registry registry;
   private int debugPort = Integer.getInteger("dunit.debug.basePort", 0);
   private int suspendVM = Integer.getInteger("dunit.debug.suspendVM", -100);
+  private VersionManager versionManager;
 
   public ProcessManager(int namingPort, Registry registry) {
+    this.versionManager = VersionManager.getInstance();
     this.namingPort = namingPort;
     this.registry = registry;
   }
 
   public synchronized void launchVM(int vmNum) throws IOException {
-    if (processes.containsKey(vmNum)) {
-      throw new IllegalStateException("VM " + vmNum + " is already running.");
+    launchVM(VersionManager.CURRENT_VERSION, vmNum, false);
+  }
+
+  public synchronized void launchVM(String version, int vmNum, boolean bouncedVM)
+      throws IOException {
+    if (processes.containsKey(version)) {
+      throw new IllegalStateException(
+          "For version " + version + ", VM " + vmNum + " is already running.");
     }
 
-    String[] cmd = buildJavaCommand(vmNum, namingPort);
+    String[] cmd = buildJavaCommand(vmNum, namingPort, version);
     System.out.println("Executing " + Arrays.toString(cmd));
-    File workingDir = getVMDir(vmNum);
-    try {
-      FileUtil.delete(workingDir);
-    } catch (IOException e) {
-      // This delete is occasionally failing on some platforms, maybe due to a lingering
-      // process. Allow the process to be launched anyway.
-      System.err.println("Unable to delete " + workingDir + ". Currently contains "
-          + Arrays.asList(workingDir.list()));
+    File workingDir = getVMDir(version, vmNum);
+    if (!workingDir.exists()) {
+      workingDir.mkdirs();
+    } else if (!bouncedVM || DUnitLauncher.MAKE_NEW_WORKING_DIRS) {
+      try {
+        FileUtil.delete(workingDir);
+      } catch (IOException e) {
+        // This delete is occasionally failing on some platforms, maybe due to a lingering
+        // process. Allow the process to be launched anyway.
+        System.err.println("Unable to delete " + workingDir + ". Currently contains "
+            + Arrays.asList(workingDir.list()));
+      }
+      workingDir.mkdirs();
     }
-    workingDir.mkdirs();
     if (log4jConfig != null) {
       FileUtils.copyFileToDirectory(log4jConfig, workingDir);
     }
@@ -82,12 +95,18 @@ public class ProcessManager {
     pendingVMs++;
     ProcessHolder holder = new ProcessHolder(process);
     processes.put(vmNum, holder);
-    linkStreams(vmNum, holder, process.getErrorStream(), System.err);
-    linkStreams(vmNum, holder, process.getInputStream(), System.out);
+    linkStreams(version, vmNum, holder, process.getErrorStream(), System.err);
+    linkStreams(version, vmNum, holder, process.getInputStream(), System.out);
   }
 
-  public static File getVMDir(int vmNum) {
-    return new File(DUnitLauncher.DUNIT_DIR, "vm" + vmNum);
+  public void validateVersion(String version) {
+    if (!versionManager.isValidVersion(version)) {
+      throw new IllegalArgumentException("Version " + version + " is not configured for use");
+    }
+  }
+
+  public static File getVMDir(String version, int vmNum) {
+    return new File(DUnitLauncher.DUNIT_DIR, VM.getVMName(VersionManager.CURRENT_VERSION, vmNum));
   }
 
   public synchronized void killVMs() {
@@ -107,7 +126,7 @@ public class ProcessManager {
     return false;
   }
 
-  public synchronized void bounce(int vmNum) {
+  public synchronized void bounce(String version, int vmNum) {
     if (!processes.containsKey(vmNum)) {
       throw new IllegalStateException("No such process " + vmNum);
     }
@@ -115,18 +134,18 @@ public class ProcessManager {
       ProcessHolder holder = processes.remove(vmNum);
       holder.kill();
       holder.getProcess().waitFor();
-      launchVM(vmNum);
+      launchVM(version, vmNum, true);
     } catch (InterruptedException | IOException e) {
       throw new RuntimeException("Unable to restart VM " + vmNum, e);
     }
   }
 
-  private void linkStreams(final int vmNum, final ProcessHolder holder, final InputStream in,
-      final PrintStream out) {
+  private void linkStreams(final String version, final int vmNum, final ProcessHolder holder,
+      final InputStream in, final PrintStream out) {
     Thread ioTransport = new Thread() {
       public void run() {
         BufferedReader reader = new BufferedReader(new InputStreamReader(in));
-        String vmName = (vmNum == -2) ? "[locator]" : "[vm_" + vmNum + "]";
+        String vmName = "[" + VM.getVMName(version, vmNum) + "] ";
         try {
           String line = reader.readLine();
           while (line != null) {
@@ -151,9 +170,16 @@ public class ProcessManager {
     ioTransport.start();
   }
 
-  private String[] buildJavaCommand(int vmNum, int namingPort) {
+  private String[] buildJavaCommand(int vmNum, int namingPort, String version) {
     String cmd = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
-    String classPath = System.getProperty("java.class.path");
+    String dunitClasspath = System.getProperty("java.class.path");
+    String classPath;
+    if (!VersionManager.isCurrentVersion(version)) {
+      classPath = versionManager.getClasspath(version) + File.pathSeparator + dunitClasspath;
+    } else {
+      classPath = dunitClasspath;
+    }
+
     // String tmpDir = System.getProperty("java.io.tmpdir");
     String agent = getAgentString();
 
@@ -163,7 +189,7 @@ public class ProcessManager {
       debugPort++;
     }
 
-    String jdkSuspend = vmNum == suspendVM ? "y" : "n";
+    String jdkSuspend = vmNum == suspendVM ? "y" : "n"; // ignore version
     ArrayList<String> cmds = new ArrayList<String>();
     cmds.add(cmd);
     cmds.add("-classpath");
@@ -171,9 +197,12 @@ public class ProcessManager {
     cmds.add(classPath);
     cmds.add("-D" + DUnitLauncher.RMI_PORT_PARAM + "=" + namingPort);
     cmds.add("-D" + DUnitLauncher.VM_NUM_PARAM + "=" + vmNum);
+    cmds.add("-D" + DUnitLauncher.VM_VERSION_PARAM + "=" + version);
     cmds.add("-D" + DUnitLauncher.WORKSPACE_DIR_PARAM + "=" + new File(".").getAbsolutePath());
     if (vmNum >= 0) { // let the locator print a banner
-      cmds.add("-D" + InternalLocator.INHIBIT_DM_BANNER + "=true");
+      if (version.equals(VersionManager.CURRENT_VERSION)) { // enable the banner for older versions
+        cmds.add("-D" + InternalLocator.INHIBIT_DM_BANNER + "=true");
+      }
     } else {
       // most distributed unit tests were written under the assumption that network partition
       // detection is disabled, so we turn it off in the locator. Tests for network partition
@@ -293,7 +322,46 @@ public class ProcessManager {
 
   public RemoteDUnitVMIF getStub(int i)
       throws AccessException, RemoteException, NotBoundException, InterruptedException {
+    return getStub(VersionManager.CURRENT_VERSION, i);
+  }
+
+  public RemoteDUnitVMIF getStub(String version, int i)
+      throws AccessException, 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;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/be8db8b7/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/StandAloneDUnitEnv.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/StandAloneDUnitEnv.java b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/StandAloneDUnitEnv.java
index 3d554ed..1dac10c 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/StandAloneDUnitEnv.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/standalone/StandAloneDUnitEnv.java
@@ -60,13 +60,18 @@ public class StandAloneDUnitEnv extends DUnitEnv {
   }
 
   @Override
-  public BounceResult bounce(int pid) throws RemoteException {
-    return master.bounce(pid);
+  public BounceResult bounce(String version, int pid) throws RemoteException {
+    return master.bounce(version, pid);
   }
 
   @Override
   public File getWorkingDirectory(int pid) {
-    return ProcessManager.getVMDir(pid);
+    return getWorkingDirectory(VersionManager.CURRENT_VERSION, pid);
+  }
+
+  @Override
+  public File getWorkingDirectory(String version, int pid) {
+    return ProcessManager.getVMDir(version, pid);
   }
 
 }


Mime
View raw message