You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2015/08/21 22:29:28 UTC

[1/9] incubator-geode git commit: Add awaitility

Repository: incubator-geode
Updated Branches:
  refs/heads/feature/GEODE-217 [created] c396e94a1


Add awaitility


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/8c4c3e07
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/8c4c3e07
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/8c4c3e07

Branch: refs/heads/feature/GEODE-217
Commit: 8c4c3e07b85857a1c19956a9893a5bcec213343f
Parents: 2914567
Author: Kirk Lund <kl...@pivotal.io>
Authored: Fri Aug 14 10:21:56 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Fri Aug 14 10:21:56 2015 -0700

----------------------------------------------------------------------
 build.gradle | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8c4c3e07/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 42b4a14..729f1b0 100755
--- a/build.gradle
+++ b/build.gradle
@@ -276,6 +276,7 @@ subprojects {
     compile 'org.springframework:spring-webmvc:3.2.12.RELEASE'
 
     testCompile 'com.github.stefanbirkner:system-rules:1.9.0'
+    testCompile 'com.jayway.awaitility:awaitility:1.6.3'
     testCompile 'edu.umd.cs.mtc:multithreadedtc:1.01'
     testCompile 'junit:junit:4.12'
     testCompile 'org.mockito:mockito-core:1.10.19'


[2/9] incubator-geode git commit: Add testing frameworks for junit tests.

Posted by kl...@apache.org.
Add testing frameworks for junit tests.


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/fb5452ad
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/fb5452ad
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/fb5452ad

Branch: refs/heads/feature/GEODE-217
Commit: fb5452ad1c1a77f4ff603afef20de7ecd6fd5b3a
Parents: 8c4c3e0
Author: Kirk Lund <kl...@pivotal.io>
Authored: Sat Aug 15 17:48:04 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Sat Aug 15 17:48:04 2015 -0700

----------------------------------------------------------------------
 build.gradle | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fb5452ad/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 729f1b0..0311206 100755
--- a/build.gradle
+++ b/build.gradle
@@ -278,13 +278,19 @@ subprojects {
     testCompile 'com.github.stefanbirkner:system-rules:1.9.0'
     testCompile 'com.jayway.awaitility:awaitility:1.6.3'
     testCompile 'edu.umd.cs.mtc:multithreadedtc:1.01'
+    testCompile 'eu.codearte.catch-exception:catch-exception:1.4.4'
+    testCompile 'eu.codearte.catch-exception:catch-throwable:1.4.4'
     testCompile 'junit:junit:4.12'
+    testCompile 'org.assertj:assertj-core:2.1.0'
+    testCompile 'org.easytesting:fest-test:2.1.0'
     testCompile 'org.mockito:mockito-core:1.10.19'
     testCompile 'org.hamcrest:hamcrest-all:1.3'
     testCompile 'org.jmock:jmock:2.8.1'
     testCompile 'org.jmock:jmock-junit4:2.8.1'
     testCompile 'org.jmock:jmock-legacy:2.8.1'
-    
+    testCompile 'org.unitils:unitils:3.4.2'
+    testCompile 'pl.pragmatists:JUnitParams:1.0.4'
+
     testRuntime 'cglib:cglib:3.1'
     testRuntime 'org.objenesis:objenesis:2.1'
     testRuntime 'org.ow2.asm:asm:5.0.3'


[5/9] incubator-geode git commit: Dunit changes for JUnit 4 syntax. Refactoring to modernize API.

Posted by kl...@apache.org.
Dunit changes for JUnit 4 syntax. Refactoring to modernize API.


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/49b2913a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/49b2913a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/49b2913a

Branch: refs/heads/feature/GEODE-217
Commit: 49b2913aca753b408dac556371ea700c81d909f0
Parents: fb5452a
Author: Kirk Lund <kl...@pivotal.io>
Authored: Sat Aug 15 17:49:06 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Sat Aug 15 17:49:06 2015 -0700

----------------------------------------------------------------------
 .../gemfire/internal/util/DebuggerSupport.java  |   16 +-
 .../distributed/DistributedMemberDUnitTest.java |  399 +++---
 .../distributed/HostedLocatorsDUnitTest.java    |   70 +-
 .../distributed/MembershipTestSuite.java        |   17 +
 .../offheap/OutOfOffHeapMemoryDUnitTest.java    |   88 +-
 .../catchexception/CatchExceptionDUnitTest.java |   63 +
 .../catchexception/CatchExceptionJUnitTest.java |   95 ++
 .../com/gemstone/gemfire/test/dunit/Assert.java |   11 +
 .../gemfire/test/dunit/AsyncInvocation.java     |  206 +++
 .../gemfire/test/dunit/BounceResult.java        |   20 +
 .../gemstone/gemfire/test/dunit/DUnitEnv.java   |   68 +
 .../gemfire/test/dunit/DebuggerSupport.java     |   20 +
 .../gemfire/test/dunit/DistributedTestCase.java |  659 +++++++++
 .../test/dunit/ExpectedExceptionString.java     |  142 ++
 .../com/gemstone/gemfire/test/dunit/Host.java   |  201 +++
 .../com/gemstone/gemfire/test/dunit/Invoke.java |  146 ++
 .../com/gemstone/gemfire/test/dunit/Jitter.java |   70 +
 .../gemfire/test/dunit/RMIException.java        |  161 +++
 .../gemfire/test/dunit/RemoteDUnitVMIF.java     |   18 +
 .../gemfire/test/dunit/RepeatableRunnable.java  |   13 +
 .../test/dunit/SerializableCallable.java        |   61 +
 .../test/dunit/SerializableRunnable.java        |   83 ++
 .../test/dunit/StoppableWaitCriterion.java      |   12 +
 .../gemstone/gemfire/test/dunit/ThreadDump.java |  157 +++
 .../com/gemstone/gemfire/test/dunit/VM.java     | 1333 ++++++++++++++++++
 .../com/gemstone/gemfire/test/dunit/Wait.java   |  167 +++
 .../gemfire/test/dunit/WaitCriterion.java       |   11 +
 .../gemfire/test/dunit/cache/CacheTestCase.java |  696 +++++++++
 .../gemfire/test/dunit/standalone/ChildVM.java  |   62 +
 .../test/dunit/standalone/DUnitLauncher.java    |  416 ++++++
 .../test/dunit/standalone/ProcessManager.java   |  228 +++
 .../test/dunit/standalone/RemoteDUnitVM.java    |  136 ++
 .../dunit/standalone/StandAloneDUnitEnv.java    |   66 +
 .../test/dunit/tests/BasicDUnitTest.java        |  124 ++
 .../dunit/tests/DUnitFrameworkTestSuite.java    |   16 +
 .../gemfire/test/dunit/tests/TestFailure.java   |   37 +
 .../gemfire/test/dunit/tests/VMDUnitTest.java   |  245 ++++
 .../test/java/dunit/DistributedTestCase.java    |    6 +-
 gemfire-core/src/test/java/dunit/VM.java        |    2 -
 .../java/dunit/standalone/ProcessManager.java   |    2 +-
 .../test/junit/categories/MembershipTest.java   |    9 +
 41 files changed, 6079 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/util/DebuggerSupport.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/util/DebuggerSupport.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/util/DebuggerSupport.java
index c40df4d..f7d4fcb 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/util/DebuggerSupport.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/util/DebuggerSupport.java
@@ -8,8 +8,11 @@
 
 package com.gemstone.gemfire.internal.util;
 
-import com.gemstone.gemfire.i18n.LogWriterI18n;
+import org.apache.logging.log4j.Logger;
+
 import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.logging.log4j.LocalizedMessage;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -19,23 +22,24 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  *
  */
 public abstract class DebuggerSupport  {
+  private static final Logger logger = LogService.getLogger();
   
   /** Creates a new instance of DebuggerSupport */
   private DebuggerSupport() {
   }
   
   /** Debugger support */
-  public static void waitForJavaDebugger(LogWriterI18n logger) {
-    waitForJavaDebugger(logger, null);
+  public static void waitForJavaDebugger() {
+    waitForJavaDebugger(null);
   }
   
   @SuppressFBWarnings(value="IL_INFINITE_LOOP", justification="Endless loop is for debugging purposes.") 
-  public static void waitForJavaDebugger(LogWriterI18n logger, String extraLogMsg) {
+  public static void waitForJavaDebugger(String extraLogMsg) {
     boolean cont = false;
     String msg = ":";
     if (extraLogMsg != null)
       msg += extraLogMsg;
-    logger.severe(LocalizedStrings.DebuggerSupport_WAITING_FOR_DEBUGGER_TO_ATTACH_0, msg);
+    logger.fatal(LocalizedMessage.create(LocalizedStrings.DebuggerSupport_WAITING_FOR_DEBUGGER_TO_ATTACH_0, msg));
     boolean interrupted = false;
     while (!cont) { // set cont to true in debugger when ready to continue
       try {
@@ -50,6 +54,6 @@ public abstract class DebuggerSupport  {
     if (interrupted) {
       Thread.currentThread().interrupt();
     }
-    logger.info(LocalizedStrings.DebuggerSupport_DEBUGGER_CONTINUING);
+    logger.info(LocalizedMessage.create(LocalizedStrings.DebuggerSupport_DEBUGGER_CONTINUING));
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
index dd35794..e45b02d 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
@@ -7,16 +7,48 @@
  */
 package com.gemstone.gemfire.distributed;
 
+import static java.util.concurrent.TimeUnit.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.junit.Assume.*;
+import static com.jayway.awaitility.Awaitility.*;
+import static com.jayway.awaitility.Duration.*;
+
 import com.gemstone.gemfire.IncompatibleSystemException;
-import com.gemstone.gemfire.distributed.internal.*;
-import dunit.*;
+import com.gemstone.gemfire.distributed.internal.DM;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember;
+import com.gemstone.gemfire.internal.lang.SystemUtils;
 
 import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
 
-import com.gemstone.gemfire.distributed.internal.membership.*;
-import junit.framework.AssertionFailedError;
+import com.gemstone.gemfire.test.junit.ConditionalIgnore;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
+import com.gemstone.gemfire.test.junit.categories.MembershipTest;
+import com.gemstone.gemfire.test.junit.rules.ConditionalIgnoreRule;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RMIException;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.dunit.VM;
 
 /**
  * Tests the functionality of the {@link DistributedMember} class.
@@ -24,137 +56,132 @@ import junit.framework.AssertionFailedError;
  * @author Kirk Lund
  * @since 5.0
  */
+@SuppressWarnings("serial")
+@Category({ DistributedTest.class, MembershipTest.class })
 public class DistributedMemberDUnitTest extends DistributedTestCase {
 
-  public DistributedMemberDUnitTest(String name) {
-    super(name);
+  private Properties config;
+  
+  @Rule
+  public final transient ExpectedException expectedException = ExpectedException.none();
+  
+  @Rule
+  public final transient ConditionalIgnoreRule ignoreRule = new ConditionalIgnoreRule();
+  
+  @BeforeClass
+  public static void beforeClass() {
+    disconnectAllFromDS();
   }
   
-  protected void sleep(long millis) {
-    try {
-      Thread.sleep(millis);
-    }
-    catch (InterruptedException e) {
-      fail("interrupted");
-    }
+  @Before
+  public void setUp() {
+    this.config = createConfig();
   }
   
+  @After
+  public void tearDown() {
+    disconnectAllFromDS();
+  }
+
   /**
-   * Tests default settings.
+   * Tests default configuration values.
    */
-  public void testDefaults() {
-    Properties config = new Properties();
-    config.setProperty(DistributionConfig.MCAST_PORT_NAME, "0"); 
-    config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
-    config.setProperty(DistributionConfig.ROLES_NAME, "");
-    config.setProperty(DistributionConfig.GROUPS_NAME, "");
-    config.setProperty(DistributionConfig.NAME_NAME, "");
+  @Test
+  public void defaultConfigShouldHaveEmptyValues() {
+    // arrange
+    this.config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
+    this.config.setProperty(DistributionConfig.ROLES_NAME, "");
+    this.config.setProperty(DistributionConfig.GROUPS_NAME, "");
+    this.config.setProperty(DistributionConfig.NAME_NAME, "");
 
-    InternalDistributedSystem system = getSystem(config);
-    try {
-      assertTrue(system.getConfig().getRoles().equals(
-          DistributionConfig.DEFAULT_ROLES));
-      assertTrue(system.getConfig().getGroups().equals(
-          DistributionConfig.DEFAULT_ROLES));
-      assertTrue(system.getConfig().getName().equals(
-          DistributionConfig.DEFAULT_NAME));
+    // act
+    final InternalDistributedSystem system = getSystem(this.config);
+    final InternalDistributedMember member = system.getDistributedMember();
 
-      DM dm = system.getDistributionManager();
-      InternalDistributedMember member = dm.getDistributionManagerId();
-      
-      Set roles = member.getRoles();
-      assertEquals(0, roles.size());
-      assertEquals("", member.getName());
-      assertEquals(Collections.emptyList(), member.getGroups());
-    } 
-    finally {
-      system.disconnect();
-    }
+    // assert
+    assertThat(system.getConfig().getRoles(), is(DistributionConfig.DEFAULT_ROLES));
+    assertThat(system.getConfig().getGroups(), is(DistributionConfig.DEFAULT_ROLES));
+    assertThat(system.getConfig().getName(), is(DistributionConfig.DEFAULT_NAME));
+    
+    assertThat(member.getRoles(), is(empty()));
+    assertThat(member.getName(), isEmptyString());
+    assertThat(member.getGroups(), is(empty()));
   }
 
-  public void testNonDefaultName() {
-    Properties config = new Properties();
-    config.setProperty(DistributionConfig.MCAST_PORT_NAME, "0"); 
-    config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
-    config.setProperty(DistributionConfig.NAME_NAME, "nondefault");
+  @Test
+  public void nameShouldBeUsed() {
+    // arrange
+    this.config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
+    this.config.setProperty(DistributionConfig.NAME_NAME, "nondefault");
 
-    InternalDistributedSystem system = getSystem(config);
-    try {
-      assertEquals("nondefault", system.getConfig().getName());
+    // act
+    final InternalDistributedSystem system = getSystem(this.config);
+    final InternalDistributedMember member = system.getDistributedMember();
 
-      DM dm = system.getDistributionManager();
-      InternalDistributedMember member = dm.getDistributionManagerId();
-      
-      assertEquals("nondefault", member.getName());
-    } 
-    finally {
-      system.disconnect();
-    }
+    // assert
+    assertThat(system.getConfig().getName(), is("nondefault"));
+    assertThat(member.getName(), is("nondefault"));
   }
 
   /**
    * Tests the configuration of many Roles and groups in one vm.
    * Confirms no runtime distinction between roles and groups.
    */
-  public void testRolesInOneVM() {
-    final String rolesProp = "A,B,C";
-    final String groupsProp = "D,E,F,G";
-    final List bothList = Arrays.asList(new String[] {"A","B","C","D","E","F","G"});
+  @Test
+  public void multipleRolesAndGroupsAreUsed() {
+    // arrange
+    final String roles = "A,B,C";
+    final String groups = "D,E,F,G";
+    final List<String> rolesAndGroups = Arrays.asList((roles+","+groups).split(","));
     
-    Properties config = new Properties();
-    config.setProperty(DistributionConfig.MCAST_PORT_NAME, "0"); 
-    config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
-    config.setProperty(DistributionConfig.ROLES_NAME, rolesProp);
-    config.setProperty(DistributionConfig.GROUPS_NAME, groupsProp);
+    this.config.setProperty(DistributionConfig.LOCATORS_NAME, ""); 
+    this.config.setProperty(DistributionConfig.ROLES_NAME, roles);
+    this.config.setProperty(DistributionConfig.GROUPS_NAME, groups);
 
-    InternalDistributedSystem system = getSystem(config);
-    try {
-      assertEquals(rolesProp, system.getConfig().getRoles());
-      assertEquals(groupsProp, system.getConfig().getGroups());
-      
-      DM dm = system.getDistributionManager();
-      InternalDistributedMember member = dm.getDistributionManagerId();
-      
-      Set roles = member.getRoles();
-      assertEquals(bothList.size(), roles.size());
-      
-      for (Iterator iter = roles.iterator(); iter.hasNext();) {
-        Role role = (Role) iter.next();
-        assertTrue(bothList.contains(role.getName()));
-      }
-      
-      assertEquals(bothList, member.getGroups());
-    } 
-    finally {
-      system.disconnect();
+    // act
+    final InternalDistributedSystem system = getSystem(this.config);
+    final InternalDistributedMember member = system.getDistributedMember();
+
+    // assert
+    assertThat(system.getConfig().getRoles(), is(roles));
+    assertThat(system.getConfig().getGroups(), is(groups));
+    assertThat(member.getRoles().size(), is(rolesAndGroups.size()));
+    for (Role role : member.getRoles()) {
+      assertThat(role.getName(), isIn(rolesAndGroups));
     }
+    assertThat(member.getGroups(), is(rolesAndGroups));
   }
 
-  public void testTwoMembersSameName() {
-    disconnectFromDS(); // or assertion on # members fails when run-dunit-tests
+  @Test
+  public void secondMemberUsingSameNameShouldFail() {
     Host.getHost(0).getVM(0).invoke(new SerializableRunnable() {
       public void run() {
-        Properties config = new Properties();
+        Properties config = createConfig();
         config.setProperty(DistributionConfig.NAME_NAME, "name0");
         getSystem(config);
       }
     });
     Host.getHost(0).getVM(1).invoke(new SerializableRunnable() {
       public void run() {
-        Properties config = new Properties();
+        Properties config = createConfig();
         config.setProperty(DistributionConfig.NAME_NAME, "name1");
         getSystem(config);
       }
     });
+    
+    expectedException.expect(RMIException.class);
+    expectedException.expectCause(isA(IncompatibleSystemException.class));
+    //expectedException.expectMessage("used the same name");
+    
     Host.getHost(0).getVM(2).invoke(new SerializableRunnable() {
       public void run() {
-        Properties config = new Properties();
+        Properties config = createConfig();
         config.setProperty(DistributionConfig.NAME_NAME, "name0");
-        try {
+//        try {
           getSystem(config);
-          fail("expected IncompatibleSystemException");
-        } catch (IncompatibleSystemException expected) {
-        }
+//          fail("expected IncompatibleSystemException");
+//        } catch (IncompatibleSystemException expected) {
+//        }
       }
     });
   }
@@ -163,17 +190,15 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
    * Tests the configuration of one unique Role in each of four vms. Verifies 
    * that each vm is aware of the other vms' Roles.
    */
-  public void testRolesInAllVMs() {  
-    disconnectAllFromDS(); // or assertion on # members fails when run-dunit-tests
-
+  @Test
+  public void allMembersShouldSeeRoles() {
     // connect all four vms...
     final String[] vmRoles = new String[] {"VM_A","VM_B","VM_C","VM_D"};
     for (int i = 0; i < vmRoles.length; i++) {
       final int vm = i;
       Host.getHost(0).getVM(vm).invoke(new SerializableRunnable() {
         public void run() {
-          //disconnectFromDS();
-          Properties config = new Properties();
+          Properties config = createConfig();
           config.setProperty(DistributionConfig.ROLES_NAME, vmRoles[vm]);
           getSystem(config);
         }
@@ -189,36 +214,23 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
           assertNotNull(sys.getConfig().getRoles());
           assertTrue(sys.getConfig().getRoles().equals(vmRoles[vm]));
           
-          DM dm = sys.getDistributionManager();
-          InternalDistributedMember self = dm.getDistributionManagerId();
+          InternalDistributedMember self = sys.getDistributedMember();
           
-          Set myRoles = self.getRoles();
+          Set<Role> myRoles = self.getRoles();
           assertEquals(1, myRoles.size());
           
           Role myRole = (Role) myRoles.iterator().next();
           assertTrue(vmRoles[vm].equals(myRole.getName()));
           
-          Set members = null;
-          for (int i = 1; i <= 3; i++) {
-            try {
-              members = dm.getOtherNormalDistributionManagerIds();
-              assertEquals(3, members.size());
-              break;
-            }
-            catch (AssertionFailedError e) {
-              if (i < 3) {
-                sleep(200);
-              } else {
-                throw e;
-              }
-            }
-          }
+          with().pollInterval(TWO_HUNDRED_MILLISECONDS).await().atMost(60, SECONDS).until( numberOfOtherMembers(), equalTo(3) );
+          // used to have a for-loop here
           
-          for (Iterator iterMembers = members.iterator(); iterMembers.hasNext();) {
-            InternalDistributedMember member = (InternalDistributedMember) iterMembers.next();
-            Set roles = member.getRoles();
+          Set<InternalDistributedMember> members = sys.getDM().getOtherNormalDistributionManagerIds();
+          for (Iterator<InternalDistributedMember> iterMembers = members.iterator(); iterMembers.hasNext();) {
+            InternalDistributedMember member = iterMembers.next();
+            Set<Role> roles = member.getRoles();
             assertEquals(1, roles.size());
-            for (Iterator iterRoles = roles.iterator(); iterRoles.hasNext();) {
+            for (Iterator<Role> iterRoles = roles.iterator(); iterRoles.hasNext();) {
               Role role = (Role) iterRoles.next();
               assertTrue(!role.getName().equals(myRole.getName()));
               boolean foundRole = false;
@@ -236,26 +248,26 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
     }
   }
 
-  private static String makeOddEvenString(int vm) {
-    return ((vm % 2) == 0) ? "EVENS" : "ODDS";
-  }
-  private static String makeGroupsString(int vm) {
-    return "" + vm + ", " + makeOddEvenString(vm);
+  private Callable<Integer> numberOfOtherMembers() {
+    return new Callable<Integer>() {
+      public Integer call() throws Exception {
+        return getSystem().getDM().getOtherNormalDistributionManagerIds().size();
+      }
+    };
   }
+  
   /**
    * Tests the configuration of one unique group in each of four vms. Verifies 
    * that each vm is aware of the other vms' groups.
    */
-  public void testGroupsInAllVMs() {  
-    disconnectFromDS(); // or assertion on # members fails when run-dunit-tests
-
+  @Test
+  public void allMembersShouldSeeGroups() {  
     // connect all four vms...
     for (int i = 0; i < 4; i++) {
       final int vm = i;
       Host.getHost(0).getVM(vm).invoke(new SerializableRunnable() {
         public void run() {
-          //disconnectFromDS();
-          Properties config = new Properties();
+          final Properties config = createConfig();
           config.setProperty(DistributionConfig.GROUPS_NAME, makeGroupsString(vm));
           getSystem(config);
         }
@@ -285,7 +297,7 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
               assertEquals(3, members.size());
               break;
             }
-            catch (AssertionFailedError e) {
+            catch (AssertionError e) {
               if (i < 3) {
                 sleep(200);
               } else {
@@ -300,8 +312,8 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
           others.removeAll(dm.getOtherNormalDistributionManagerIds());
           assertEquals(1, others.size());
           // test getGroupMembers
-          HashSet<DistributedMember> evens = new HashSet<DistributedMember>();
-          HashSet<DistributedMember> odds = new HashSet<DistributedMember>();
+          Set<DistributedMember> evens = new HashSet<DistributedMember>();
+          Set<DistributedMember> odds = new HashSet<DistributedMember>();
           boolean isEvens = true;
           for (String groupName: Arrays.asList("0", "1", "2", "3")) {
             Set<DistributedMember> gm = sys.getGroupMembers(groupName);
@@ -337,74 +349,99 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
    * Changing the id can result in bad keys in JMX and can result in numerous
    * errors in Admin/JMX tests.
    */
-  public void testGetId() {
-    Properties config = new Properties();
-    config.setProperty(DistributionConfig.MCAST_PORT_NAME, "0");
-    config.setProperty(DistributionConfig.LOCATORS_NAME, "");
-    config.setProperty(DistributionConfig.NAME_NAME, "foobar");
+  @Test
+  public void getIdShouldIdentifyMember() {
+    this.config.setProperty(DistributionConfig.LOCATORS_NAME, "");
+    this.config.setProperty(DistributionConfig.NAME_NAME, "foobar");
 
-    InternalDistributedSystem system = getSystem(config);
-    try {
-
-      DM dm = system.getDistributionManager();
-      DistributedMember member = dm.getDistributionManagerId();
-      
-      assertEquals(member.getId(), system.getMemberId());
-      assertTrue(member.getId().contains("foobar"));
-    } 
-    finally {
-      system.disconnect();
-    }
+    final InternalDistributedSystem system = getSystem(this.config);
+    final DistributedMember member = system.getDistributedMember();
+    
+    assertThat(system.getMemberId(), is(member.getId()));
+    assertThat(member.getId(), containsString("foobar"));
   }
   
-  public void testFindMemberByName() {
-    disconnectAllFromDS(); // or assertion on # members fails when run-dunit-tests
-    VM vm0 = Host.getHost(0).getVM(0);
-    VM vm1 = Host.getHost(0).getVM(1);
-    VM vm2 = Host.getHost(0).getVM(2);
+  /**
+   * TODO: move to DistributedSystem DUnit Test
+   */
+  @Test
+  public void findDistributedMembersByNameShouldReturnOneMember() {
+    final VM vm0 = Host.getHost(0).getVM(0);
+    final VM vm1 = Host.getHost(0).getVM(1);
+    final VM vm2 = Host.getHost(0).getVM(2);
+    
     final DistributedMember member0 = createSystemAndGetId(vm0, "name0");
     final DistributedMember member1 = createSystemAndGetId(vm1, "name1");
     final DistributedMember member2 = createSystemAndGetId(vm2, "name2");
-    vm0.invoke(new SerializableRunnable() {
-      public void run() {
+    
+    vm0.invoke(new SerializableCallable() { // SerializableRunnable
+      public Object call() throws Exception { // public void run() 
         DistributedSystem system = getSystem();
         assertEquals(member0, system.findDistributedMember("name0"));
         assertEquals(member1, system.findDistributedMember("name1"));
         assertEquals(member2, system.findDistributedMember("name2"));
         assertNull(system.findDistributedMember("name3"));
 
-        Set<DistributedMember> members;
-        try {
-          members = system.findDistributedMembers(InetAddress.getByName(member0.getHost()));
-          HashSet expected = new HashSet();
-          expected.add(member0);
-          expected.add(member1);
-          expected.add(member2);
-          
-          //Members will contain the locator as well. Just make sure it has
-          //the members we're looking for.
-          assertTrue("Expected" + expected + " got " + members, members.containsAll(expected));
-          assertEquals(4, members.size());
-        } catch (UnknownHostException e) {
-          fail("Unable to get IpAddress", e);
-        }
+        Set<DistributedMember> members = system.findDistributedMembers(InetAddress.getByName(member0.getHost()));
+        Set<DistributedMember> expected = new HashSet<DistributedMember>();
+        expected.add(member0);
+        expected.add(member1);
+        expected.add(member2);
+        
+        // Members will contain the locator as well. Just make sure it has the members we're looking for.
+        assertTrue("Expected" + expected + " got " + members, members.containsAll(expected));
+        assertEquals(4, members.size());
+//        } catch (UnknownHostException e) {
+//          fail("Unable to get IpAddress", e);
+//        }
+        return null;
       }
     });
   }
   
-  private DistributedMember createSystemAndGetId(VM vm, final String name) {
+  @Test
+  public void linuxSpecificTest() {
+    assumeTrue(SystemUtils.isLinux());
+    // do something that is only supported on linux
+  }
+  
+  @Test
+  @ConditionalIgnore(value="#55555: summary of bug #55555", until="2016-01-01")
+  public void someBrokenTest() {
+    throw new Error("Bug #55555");
+  }
+  
+  private DistributedMember createSystemAndGetId(final VM vm, final String name) {
     return (DistributedMember) vm.invoke(new SerializableCallable("create system and get member") {
-      
       @Override
       public Object call() throws Exception {
-        Properties config = new Properties();
+        final Properties config = createConfig();
         config.setProperty(DistributionConfig.NAME_NAME, name);
-        DistributedSystem ds = getSystem(config);
+        final DistributedSystem ds = getSystem(config);
         return ds.getDistributedMember();
       }
     });
   }
+
+  private static Properties createConfig() {
+    final Properties props = new Properties();
+    props.setProperty(DistributionConfig.MCAST_PORT_NAME, "0");
+    return props;
+  }
   
-}
+  private void sleep(final long millis) {
+    try {
+      Thread.sleep(millis);
+    } catch (InterruptedException e) {
+      fail("interrupted");
+    }
+  }
   
-
+  private static String makeOddEvenString(final int vm) {
+    return ((vm % 2) == 0) ? "EVENS" : "ODDS";
+  }
+  
+  private static String makeGroupsString(final int vm) {
+    return "" + vm + ", " + makeOddEvenString(vm);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
index a0e54d5..e74e12f 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
@@ -1,5 +1,10 @@
 package com.gemstone.gemfire.distributed;
 
+import static com.jayway.awaitility.Awaitility.*;
+import static java.util.concurrent.TimeUnit.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
 import java.io.File;
 import java.util.Collection;
 import java.util.HashSet;
@@ -7,6 +12,14 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.Timeout;
+
 import com.gemstone.gemfire.distributed.AbstractLauncher.Status;
 import com.gemstone.gemfire.distributed.LocatorLauncher.Builder;
 import com.gemstone.gemfire.distributed.LocatorLauncher.LocatorState;
@@ -18,10 +31,13 @@ import com.gemstone.gemfire.internal.AvailablePortHelper;
 import com.gemstone.gemfire.internal.SocketCreator;
 import com.gemstone.gemfire.internal.util.StopWatch;
 
-import dunit.DistributedTestCase;
-import dunit.Host;
-import dunit.SerializableCallable;
-import dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
+import com.gemstone.gemfire.test.junit.categories.MembershipTest;
+import com.gemstone.gemfire.test.junit.rules.Retry;
 
 /**
  * Extracted from LocatorLauncherLocalJUnitTest.
@@ -29,26 +45,36 @@ import dunit.SerializableRunnable;
  * @author Kirk Lund
  * @since 8.0
  */
+@SuppressWarnings("serial")
+@Category({ DistributedTest.class, MembershipTest.class })
 public class HostedLocatorsDUnitTest extends DistributedTestCase {
 
-  protected static final int TIMEOUT_MILLISECONDS = 5 * 60 * 1000; // 5 minutes
+  //protected static final int TIMEOUT_MILLISECONDS = 5 * 60 * 1000; // 5 minutes
 
   protected transient volatile int locatorPort;
   protected transient volatile LocatorLauncher launcher;
   
+  @Rule // not serializable and yet we're setting/clearing in other JVMs
+  public final transient RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+  
+  @Rule
+  public final transient Timeout globalTimeout = Timeout.seconds(2 * 60 * 1000);
+  
+  @Rule
+  public final transient Retry retry = new Retry(2);
+  
+  @Before
   public void setUp() throws Exception {
     disconnectAllFromDS();
   }
   
-  public void tearDown2() throws Exception {
+  @After
+  public void tearDown() throws Exception {
     disconnectAllFromDS();
   }
   
-  public HostedLocatorsDUnitTest(String name) {
-    super(name);
-  }
-
-  public void testGetAllHostedLocators() throws Exception {
+  @Test
+  public void getAllHostedLocators() throws Exception {
     final InternalDistributedSystem system = getSystem();
     final String dunitLocator = system.getConfig().getLocators();
     assertNotNull(dunitLocator);
@@ -79,7 +105,8 @@ public class HostedLocatorsDUnitTest extends DistributedTestCase {
     
             launcher = builder.build();
             assertEquals(Status.ONLINE, launcher.start().getStatus());
-            waitForLocatorToStart(launcher, TIMEOUT_MILLISECONDS, 10, true);
+            //was: waitForLocatorToStart(launcher, TIMEOUT_MILLISECONDS, 10, true);
+            with().pollInterval(10, MILLISECONDS).await().atMost(5, MINUTES).until( isLocatorStarted() );
             return null;
           } finally {
             System.clearProperty("gemfire.locators");
@@ -154,6 +181,23 @@ public class HostedLocatorsDUnitTest extends DistributedTestCase {
     }
   }
 
+  @Test
+  public void unreliableTestWithRaceConditions() {
+    count++;
+    if (count < 2) {
+      assertThat(count, is(2)); // doomed to fail
+    }
+  }
+  
+  private Callable<Boolean> isLocatorStarted() {
+    return new Callable<Boolean>() {
+      public Boolean call() throws Exception {
+        final LocatorState LocatorState = launcher.status();
+        return (LocatorState != null && Status.ONLINE.equals(LocatorState.getStatus()));
+      }
+    };
+  }
+  
   protected void waitForLocatorToStart(final LocatorLauncher launcher, int timeout, int interval, boolean throwOnTimeout) throws Exception {
     assertEventuallyTrue("waiting for process to start: " + launcher.status(), new Callable<Boolean>() {
       @Override
@@ -176,4 +220,6 @@ public class HostedLocatorsDUnitTest extends DistributedTestCase {
     }
     assertTrue(message, done);
   }
+  
+  private static int count = 0;
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/MembershipTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/MembershipTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/MembershipTestSuite.java
new file mode 100755
index 0000000..c96bf43
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/MembershipTestSuite.java
@@ -0,0 +1,17 @@
+package com.gemstone.gemfire.distributed;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  DistributedMemberDUnitTest.class,
+  HostedLocatorsDUnitTest.class,
+})
+/**
+ * Suite of tests for Membership.
+ * 
+ * @author Kirk Lund
+ */
+public class MembershipTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
index a7921ee..644d82c 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
@@ -1,16 +1,23 @@
 package com.gemstone.gemfire.internal.offheap;
 
+import static com.gemstone.gemfire.test.dunit.ExpectedExceptionString.*;
+import static com.gemstone.gemfire.test.dunit.Invoke.*;
+import static com.gemstone.gemfire.test.dunit.Wait.*;
+import static org.junit.Assert.*;
+
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.logging.log4j.Logger;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import com.gemstone.gemfire.OutOfOffHeapMemoryException;
 import com.gemstone.gemfire.cache.Cache;
 import com.gemstone.gemfire.cache.Region;
 import com.gemstone.gemfire.cache.RegionShortcut;
-import com.gemstone.gemfire.cache30.CacheTestCase;
 import com.gemstone.gemfire.distributed.DistributedSystem;
 import com.gemstone.gemfire.distributed.DistributedSystemDisconnectedException;
 import com.gemstone.gemfire.distributed.internal.DistributionConfig;
@@ -21,49 +28,33 @@ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
 import com.gemstone.gemfire.internal.cache.OffHeapTestUtil;
 import com.gemstone.gemfire.internal.logging.LogService;
 import com.gemstone.gemfire.internal.util.StopWatch;
+import com.gemstone.gemfire.test.dunit.cache.CacheTestCase;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
 
-import dunit.Host;
-import dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.dunit.WaitCriterion;
 
 /**
  * Test behavior of region when running out of off-heap memory.
  * 
  * @author Kirk Lund
  */
-@SuppressWarnings("serial")
+@SuppressWarnings({ "serial", "unused" })
+@Category(DistributedTest.class)
 public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
   private static final Logger logger = LogService.getLogger();
   
   protected static final AtomicReference<Cache> cache = new AtomicReference<Cache>();
   protected static final AtomicReference<DistributedSystem> system = new AtomicReference<DistributedSystem>();
   protected static final AtomicBoolean isSmallerVM = new AtomicBoolean();
-  
-  public OutOfOffHeapMemoryDUnitTest(String name) {
-    super(name);
-  }
 
-  @Override
-  public void setUp() throws Exception {
+  @Before
+  public void setUpOutOfOffHeapMemoryDUnitTest() throws Exception {
     disconnectAllFromDS();
-    super.setUp();
-    addExpectedException(OutOfOffHeapMemoryException.class.getSimpleName());
+    addExpectedExceptionString(OutOfOffHeapMemoryException.class.getSimpleName());
   }
   
-//  public static void caseSetUp() {
-//    //disconnectAllFromDS();
-//    for (int i = 0; i < Host.getHost(0).getVMCount(); i++) {
-//      Host.getHost(0).getVM(i).invoke(new SerializableRunnable() {
-//        public void run() {
-//          InternalDistributedSystem ids = InternalDistributedSystem.getAnyInstance();
-//          if (ids != null && ids.isConnected()) {
-//            logger.warn(OutOfOffHeapMemoryDUnitTest.class.getSimpleName() + " found DistributedSystem connection from previous test: {}", ids);
-//            ids.disconnect();
-//          }
-//        }
-//      });
-//    }
-//  }
-
   @Override
   public void tearDown2() throws Exception {
     final SerializableRunnable checkOrphans = new SerializableRunnable() {
@@ -83,7 +74,6 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
     }
   }
 
-  @SuppressWarnings("unused") // invoked by reflection from tearDown2()
   private static void cleanup() {
     disconnectFromDS();
     SimpleMemoryAllocatorImpl.freeOffHeapMemory();
@@ -121,6 +111,7 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
     return props;
   }
   
+  @Test
   public void testSimpleOutOfOffHeapMemoryMemberDisconnects() {
     final DistributedSystem system = getSystem();
     final Cache cache = getCache();
@@ -209,6 +200,7 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
     }
   }
   
+  @Test
   public void testOtherMembersSeeOutOfOffHeapMemoryMemberDisconnects() {
     final int vmCount = Host.getHost(0).getVMCount();
     assertEquals(4, vmCount);
@@ -301,44 +293,4 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
       });
     }
   }
-
-//  private static void foo() {
-//    final WaitCriterion waitForDisconnect = new WaitCriterion() {
-//      public boolean done() {
-//        return cache.isClosed() && !system.isConnected() && dm.isClosed();
-//      }
-//      public String description() {
-//        return "Waiting for cache, system and dm to close";
-//      }
-//    };
-//    waitForCriterion(waitForDisconnect, 10*1000, 100, true);
-//  }
-  
-  // setUp() and caseSetUp() are commented out -- they were in place because of incompatible DistributedSystem bleed over from earlier DUnit tests
-  
-//@Override
-//public void setUp() throws Exception {
-//  super.setUp();
-//  long begin = System.currentTimeMillis();
-//  Cache gfc = null;
-//  while (gfc == null) {
-//    try {
-//      gfc = getCache();
-//      break;
-//    } catch (IllegalStateException e) {
-//      if (System.currentTimeMillis() > begin+60*1000) {
-//        fail("OutOfOffHeapMemoryDUnitTest waited too long to getCache", e);
-//      } else if (e.getMessage().contains("A connection to a distributed system already exists in this VM.  It has the following configuration")) {
-//        InternalDistributedSystem ids = InternalDistributedSystem.getAnyInstance();
-//        if (ids != null && ids.isConnected()) {
-//          ids.getLogWriter().warning("OutOfOffHeapMemoryDUnitTest found DistributedSystem connection from previous test", e);
-//          ids.disconnect();
-//        }
-//      } else {
-//        throw e;
-//      }
-//    }
-//  }
-//}
-
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
new file mode 100755
index 0000000..a3fc1f1
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
@@ -0,0 +1,63 @@
+package com.gemstone.gemfire.test.catchexception;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static com.googlecode.catchexception.apis.BDDCatchException.when;
+import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
+import static org.assertj.core.api.BDDAssertions.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RMIException;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * Using Catch-Exception works well for remote exceptions and asserting details
+ * about root cause of RMIExceptions in DUnit tests.
+ */
+public class CatchExceptionDUnitTest extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+
+  private static final String REMOTE_THROW_EXCEPTION_MESSAGE = "Throwing remoteThrowException";
+
+  @Test
+  public void testRemoteInvocationWithException() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+
+    when(vm).invoke(new ThrowBasicTestException());
+
+    then(caughtException())
+        .isInstanceOf(RMIException.class)
+        .hasCause(new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE));
+  }
+  
+  protected static class ThrowBasicTestException extends SerializableCallable<Object> {
+    private static final long serialVersionUID = 1L;
+    
+    @Override
+    public Object call() throws Exception {
+      throw new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE);
+    }
+  }
+  
+  protected static class BasicTestException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public BasicTestException() {
+      super();
+    }
+    
+    public BasicTestException(String message) {
+      super(message);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
new file mode 100755
index 0000000..d197745
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
@@ -0,0 +1,95 @@
+package com.gemstone.gemfire.test.catchexception;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static com.googlecode.catchexception.apis.BDDCatchException.when;
+import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
+import static org.assertj.core.api.BDDAssertions.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+
+/**
+ * Simple unit tests exercising Catch-Exception with AssertJ, Hamcrest and JUnit.
+ */
+public class CatchExceptionJUnitTest {
+
+  @Test
+  public void catchExceptionShouldCatchException() {
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    // then: catch the exception if any is thrown
+    catchException(myList).get(1);
+    
+    // then: we expect an IndexOutOfBoundsException
+    assertThat(caughtException(), is(instanceOf(IndexOutOfBoundsException.class)));
+  }
+  
+  @Test
+  public void verifyExceptionShouldCatchException() {
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    // then: catch the exception if any is thrown
+    // then: we expect an IndexOutOfBoundsException
+    verifyException(myList, IndexOutOfBoundsException.class).get(1);
+  }
+  
+  @Test
+  public void whenShouldCatchExceptionAndUseAssertJAssertion() {
+    // given: an empty list
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    when(myList).get(1);
+
+    // then: we expect an IndexOutOfBoundsException
+    then(caughtException())
+            .isInstanceOf(IndexOutOfBoundsException.class)
+            .hasMessage("Index: 1, Size: 0")
+            .hasNoCause();
+  }
+  
+  @Test
+  public void catchExceptionShouldCatchExceptionAndUseHamcrestAssertion() {
+    // given: an empty list
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    catchException(myList).get(1);
+
+    // then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
+    assertThat(caughtException(),
+      allOf(
+        instanceOf(IndexOutOfBoundsException.class),
+        hasMessage("Index: 1, Size: 0"),
+        hasNoCause()
+      )
+    );
+  }
+  
+  @Test
+  public void shouldCatchFromThrowException() throws Exception {
+    String message = "error message";
+    
+    catchException(this).throwException(message);
+    
+    assertThat(caughtException(), is(instanceOf(Exception.class)));
+  }
+  
+  @Test
+  public void shouldVerifyFromThrowException() throws Exception {
+    String message = "error message";
+
+    verifyException(this).throwException(message);
+  }
+  
+  // fails if private
+  protected void throwException(final String message) throws Exception {
+    throw new Exception(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Assert.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Assert.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Assert.java
new file mode 100755
index 0000000..a8ce347
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Assert.java
@@ -0,0 +1,11 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public class Assert extends org.junit.Assert {
+
+  public static void fail(final String message, final Throwable cause) {
+    throw new AssertionError(cause);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/AsyncInvocation.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/AsyncInvocation.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/AsyncInvocation.java
new file mode 100644
index 0000000..0fdcd74
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/AsyncInvocation.java
@@ -0,0 +1,206 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.concurrent.TimeoutException;
+
+import com.gemstone.gemfire.InternalGemFireError;
+import com.gemstone.gemfire.SystemFailure;
+
+// @todo davidw Add the ability to get a return value back from the
+// async method call.  (Use a static ThreadLocal field that is
+// accessible from the Runnable used in VM#invoke)
+/**
+ * <P>An <code>AsyncInvocation</code> represents the invocation of a
+ * remote invocation that executes asynchronously from its caller.  An
+ * instanceof <code>AsyncInvocation</code> provides information about
+ * the invocation such as any exception that it may have thrown.</P>
+ *
+ * <P>Because it is a <code>Thread</code>, an
+ * <code>AsyncInvocation</code> can be used as follows:</P>
+ *
+ * <PRE>
+ *   AsyncInvocation ai1 = vm.invokeAsync(Test.class, "method1");
+ *   AsyncInvocation ai2 = vm.invokeAsync(Test.class, "method2");
+ *
+ *   ai1.join();
+ *   ai2.join();
+ *
+ *   assertTrue("Exception occurred while invoking " + ai1,
+ *              !ai1.exceptionOccurred());
+ *   if (ai2.exceptionOccurred()) {
+ *     throw ai2.getException();
+ *   }
+ * </PRE>
+ *
+ * @see VM#invokeAsync(Class, String)
+ */
+public class AsyncInvocation extends Thread {
+  
+  private static final ThreadLocal returnValue = new ThreadLocal();
+
+  /** The singleton the thread group */
+  private static final ThreadGroup GROUP = new AsyncInvocationGroup();
+
+  ///////////////////// Instance Fields  /////////////////////
+
+  /** An exception thrown while this async invocation ran */
+  protected volatile Throwable exception;
+
+  /** The object (or class) that is the receiver of this asyn method
+   * invocation */
+  private Object receiver;
+
+  /** The name of the method being invoked */
+  private String methodName;
+  
+  /** The returned object if any */
+  public volatile Object returnedObj = null;
+
+  //////////////////////  Constructors  //////////////////////
+
+  /**
+   * Creates a new <code>AsyncInvocation</code>
+   *
+   * @param receiver
+   *        The object or {@link Class} on which the remote method was
+   *        invoked
+   * @param methodName
+   *        The name of the method being invoked
+   * @param work
+   *        The actual invocation of the method
+   */
+  public AsyncInvocation(Object receiver, String methodName, Runnable work) {
+    super(GROUP, work, getName(receiver, methodName));
+    this.receiver = receiver;
+    this.methodName = methodName;
+    this.exception = null;
+  }
+
+  //////////////////////  Static Methods  /////////////////////
+
+  /**
+   * Returns the name of a <code>AsyncInvocation</code> based on its
+   * receiver and method name.
+   */
+  private static String getName(Object receiver, String methodName) {
+    StringBuffer sb = new StringBuffer(methodName);
+    sb.append(" invoked on ");
+    if (receiver instanceof Class) {
+      sb.append("class ");
+      sb.append(((Class) receiver).getName());
+
+    } else {
+      sb.append("an instance of ");
+      sb.append(receiver.getClass().getName());
+    }
+
+    return sb.toString();
+  }
+
+  /////////////////////  Instance Methods  ////////////////////
+
+  /**
+   * Returns the receiver of this async method invocation
+   */
+  public Object getReceiver() {
+    return this.receiver;
+  }
+
+  /**
+   * Returns the name of the method being invoked remotely
+   */
+  public String getMethodName() {
+    return this.methodName;
+  }
+
+  /**
+   * Returns whether or not an exception occurred during this async
+   * method invocation.
+   */
+  public boolean exceptionOccurred() {
+    if (this.isAlive()) {
+      throw new InternalGemFireError("Exception status not available while thread is alive.");
+    }
+    return this.exception != null;
+  }
+
+  /**
+   * Returns the exception that was thrown during this async method
+   * invocation.
+   */
+  public Throwable getException() {
+    if (this.isAlive()) {
+      throw new InternalGemFireError("Exception status not available while thread is alive.");
+    }
+    if (this.exception instanceof RMIException) {
+      return ((RMIException) this.exception).getCause();
+
+    } else {
+      return this.exception;
+    }
+  }
+
+  //////////////////////  Inner Classes  //////////////////////
+
+  /**
+   * A <code>ThreadGroup</code> that notices when an exception occurrs
+   * during an <code>AsyncInvocation</code>.
+   */
+  private static class AsyncInvocationGroup extends ThreadGroup {
+    AsyncInvocationGroup() {
+      super("Async Invocations");
+    }
+
+    public void uncaughtException(Thread t, Throwable e) {
+      if (e instanceof VirtualMachineError) {
+        SystemFailure.setFailure((VirtualMachineError)e); // don't throw
+      }
+      if (t instanceof AsyncInvocation) {
+        ((AsyncInvocation) t).exception = e;
+      }
+    }
+  }
+  
+  public Object getResult() throws Throwable {
+    join();
+    if(this.exceptionOccurred()) {
+      throw new Exception("An exception occured during async invocation", this.exception);
+    }
+    return this.returnedObj;
+  }
+  
+  public Object getResult(long waitTime) throws Throwable {
+    join(waitTime);
+    if(this.isAlive()) {
+      throw new TimeoutException();
+    }
+    if(this.exceptionOccurred()) {
+      throw new Exception("An exception occured during async invocation", this.exception);
+    }
+    return this.returnedObj;
+  }
+
+  public Object getReturnValue() {
+    if (this.isAlive()) {
+      throw new InternalGemFireError("Return value not available while thread is alive.");
+    }
+    return this.returnedObj;
+  }
+  
+  public void run()
+  {
+    super.run();
+    this.returnedObj = returnValue.get();
+    returnValue.set(null);
+  }
+
+  static void setReturnValue(Object v) {
+    returnValue.set(v);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/BounceResult.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/BounceResult.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/BounceResult.java
new file mode 100644
index 0000000..a766a2b
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/BounceResult.java
@@ -0,0 +1,20 @@
+package com.gemstone.gemfire.test.dunit;
+
+public class BounceResult {
+  private final int newPid;
+  private final RemoteDUnitVMIF newClient;
+  
+  public BounceResult(int newPid, RemoteDUnitVMIF newClient) {
+    this.newPid = newPid;
+    this.newClient = newClient;
+  }
+
+  public int getNewPid() {
+    return newPid;
+  }
+
+  public RemoteDUnitVMIF getNewClient() {
+    return newClient;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
new file mode 100644
index 0000000..96ebd7d
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
@@ -0,0 +1,68 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/**
+ * 
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.Properties;
+
+/**
+ * This class provides an abstraction over the environment
+ * that is used to run dunit. This will delegate to the hydra
+ * or to the standalone dunit launcher as needed.
+ * 
+ * Any dunit tests that rely on hydra configuration should go
+ * through here, so that we can separate them out from depending on hydra
+ * and run them on a different VM launching system.
+ *   
+ * @author dsmith
+ *
+ */
+public abstract class DUnitEnv {
+  
+  public static DUnitEnv instance = null;
+  
+  public static final DUnitEnv get() {
+    if (instance == null) {
+      try {
+        // for tests that are still being migrated to the open-source
+        // distributed unit test framework  we need to look for this
+        // old closed-source dunit environment
+        Class clazz = Class.forName("dunit.hydra.HydraDUnitEnv");
+        instance = (DUnitEnv)clazz.newInstance();
+      } catch (Exception e) {
+        throw new Error("Distributed unit test environment is not initialized");
+      }
+    }
+    return instance;
+  }
+  
+  public static void set(DUnitEnv dunitEnv) {
+    instance = dunitEnv;
+  }
+  
+  public abstract String getLocatorString();
+  
+  public abstract String getLocatorAddress();
+
+  public abstract int getLocatorPort();
+  
+  public abstract Properties getDistributedSystemProperties();
+
+  public abstract int getPid();
+
+  public abstract int getVMID();
+
+  public abstract BounceResult bounce(int pid) throws RemoteException;
+
+  public abstract File getWorkingDirectory(int pid);
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DebuggerSupport.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DebuggerSupport.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DebuggerSupport.java
new file mode 100755
index 0000000..8d57483
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DebuggerSupport.java
@@ -0,0 +1,20 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase. Enters infinite loop to allow debugger to attach.
+ */
+public class DebuggerSupport {
+
+  protected DebuggerSupport() {
+  }
+  
+  @SuppressWarnings("serial")
+  public static void attachDebugger(VM vm, final String msg) {
+    vm.invoke(new SerializableRunnable("Attach Debugger") {
+      public void run() {
+        com.gemstone.gemfire.internal.util.DebuggerSupport.
+        waitForJavaDebugger(msg);
+      } 
+    });
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
new file mode 100755
index 0000000..5eb3b0b
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
@@ -0,0 +1,659 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Invoke.*;
+import static com.gemstone.gemfire.test.dunit.Wait.*;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.logging.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+
+import com.gemstone.gemfire.admin.internal.AdminDistributedSystemImpl;
+import com.gemstone.gemfire.cache.hdfs.internal.hoplog.HoplogConfig;
+import com.gemstone.gemfire.cache.query.QueryTestUtils;
+import com.gemstone.gemfire.cache.query.internal.QueryObserverHolder;
+import com.gemstone.gemfire.cache30.GlobalLockingDUnitTest;
+import com.gemstone.gemfire.cache30.MultiVMRegionTestCase;
+import com.gemstone.gemfire.cache30.RegionTestCase;
+import com.gemstone.gemfire.distributed.DistributedSystem;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.distributed.internal.DistributionMessageObserver;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.CreationStackGenerator;
+import com.gemstone.gemfire.distributed.internal.membership.jgroup.MembershipManagerHelper;
+import com.gemstone.gemfire.internal.AvailablePort;
+import com.gemstone.gemfire.internal.InternalDataSerializer;
+import com.gemstone.gemfire.internal.InternalInstantiator;
+import com.gemstone.gemfire.internal.SocketCreator;
+import com.gemstone.gemfire.internal.admin.ClientStatsManager;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.internal.cache.InitialImageOperation;
+import com.gemstone.gemfire.internal.cache.tier.InternalBridgeMembership;
+import com.gemstone.gemfire.internal.cache.tier.sockets.CacheServerTestUtil;
+import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
+import com.gemstone.gemfire.internal.cache.tier.sockets.DataSerializerPropogationDUnitTest;
+import com.gemstone.gemfire.internal.logging.InternalLogWriter;
+import com.gemstone.gemfire.internal.logging.LogService;
+import com.gemstone.gemfire.internal.logging.ManagerLogWriter;
+import com.gemstone.gemfire.internal.logging.log4j.LogWriterLogger;
+import com.gemstone.gemfire.management.internal.cli.LogWrapper;
+import com.gemstone.org.jgroups.Event;
+import com.gemstone.org.jgroups.JChannel;
+import com.gemstone.org.jgroups.stack.IpAddress;
+import com.gemstone.org.jgroups.stack.Protocol;
+import com.gemstone.org.jgroups.util.GemFireTracer;
+
+import com.gemstone.gemfire.test.dunit.standalone.DUnitLauncher;
+
+/**
+ * This class is the superclass of all distributed unit tests.
+ *
+ * @author David Whitlock
+ */
+@SuppressWarnings({ "deprecation", "serial", "rawtypes" })
+public abstract class DistributedTestCase implements java.io.Serializable {
+  private static final Logger logger = LogService.getLogger();
+  private static final LogWriterLogger oldLogger = LogWriterLogger.create(logger);
+
+  @Rule
+  public transient TestName testNameRule = new TestName();
+  
+  public static InternalDistributedSystem system;
+  private static Class lastSystemCreatedInTest;
+  private static Properties lastSystemProperties;
+  public static volatile String testName;
+  
+  public static final boolean logPerTest = Boolean.getBoolean("dunitLogPerTest");
+
+  /**
+   * Creates a new <code>DistributedTestCase</code> test.
+   */
+  public DistributedTestCase() {
+    DUnitLauncher.launchIfNeeded();
+  }
+
+  private static void setUpCreationStackGenerator() {
+    // the following is moved from InternalDistributedSystem to fix #51058
+    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(
+    new CreationStackGenerator() {
+      @Override
+      public Throwable generateCreationStack(final DistributionConfig config) {
+        final StringBuilder sb = new StringBuilder();
+        final String[] validAttributeNames = config.getAttributeNames();
+        for (int i = 0; i < validAttributeNames.length; i++) {
+          final String attName = validAttributeNames[i];
+          final Object actualAtt = config.getAttributeObject(attName);
+          String actualAttStr = actualAtt.toString();
+          sb.append("  ");
+          sb.append(attName);
+          sb.append("=\"");
+          if (actualAtt.getClass().isArray()) {
+            actualAttStr = InternalDistributedSystem.arrayToString(actualAtt);
+          }
+          sb.append(actualAttStr);
+          sb.append("\"");
+          sb.append("\n");
+        }
+        return new Throwable("Creating distributed system with the following configuration:\n" + sb.toString());
+      }
+    });
+  }
+  
+  private static void tearDownCreationStackGenerator() {
+    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(InternalDistributedSystem.DEFAULT_CREATION_STACK_GENERATOR);
+  }
+  
+  private Class getTestClass() {
+    Class clazz = getClass();
+    while (clazz.getDeclaringClass() != null) {
+      clazz = clazz.getDeclaringClass();
+    }
+    return clazz;
+  }
+  
+  /**
+   * This finds the log level configured for the test run.  It should be used
+   * when creating a new distributed system if you want to specify a log level.
+   * 
+   * @return the dunit log-level setting
+   */
+  public static String getDUnitLogLevel() { // TODO: delete
+    Properties p = DUnitEnv.get().getDistributedSystemProperties();
+    String result = p.getProperty(DistributionConfig.LOG_LEVEL_NAME);
+    if (result == null) {
+      result = ManagerLogWriter.levelToString(DistributionConfig.DEFAULT_LOG_LEVEL);
+    }
+    return result;
+  }
+
+  public final static Properties getAllDistributedSystemProperties(Properties props) { // TODO: delete
+    Properties p = DUnitEnv.get().getDistributedSystemProperties();
+    
+    // our tests do not expect auto-reconnect to be on by default
+    if (!p.contains(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME)) {
+      p.put(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME, "true");
+    }
+        
+    for (Iterator iter = props.entrySet().iterator();
+    iter.hasNext(); ) {
+      Map.Entry entry = (Map.Entry) iter.next();
+      String key = (String) entry.getKey();
+      Object value = entry.getValue();
+      p.put(key, value);
+    }
+    return p;
+  }
+
+  public void setSystem(Properties props, DistributedSystem ds) { // TODO: delete
+    system = (InternalDistributedSystem)ds;
+    lastSystemProperties = props;
+    lastSystemCreatedInTest = getTestClass();
+  }
+  
+  /**
+   * Returns this VM's connection to the distributed system.  If
+   * necessary, the connection will be lazily created using the given
+   * <code>Properties</code>.  Note that this method uses hydra's
+   * configuration to determine the location of log files, etc.
+   * Note: "final" was removed so that WANTestBase can override this method.
+   * This was part of the xd offheap merge.
+   *
+   * @see hydra.DistributedConnectionMgr#connect
+   * @since 3.0
+   */
+  public final InternalDistributedSystem getSystem(Properties props) {
+    // Setting the default disk store name is now done in setUp
+    if (system == null) {
+      system = InternalDistributedSystem.getAnyInstance();
+    }
+    if (system == null || !system.isConnected()) {
+      // Figure out our distributed system properties
+      Properties p = getAllDistributedSystemProperties(props);
+      lastSystemCreatedInTest = getTestClass();
+      if (logPerTest) {
+        String testMethod = getTestName();
+        String testName = lastSystemCreatedInTest.getName() + '-' + testMethod;
+        String oldLogFile = p.getProperty(DistributionConfig.LOG_FILE_NAME);
+        p.put(DistributionConfig.LOG_FILE_NAME, 
+            oldLogFile.replace("system.log", testName+".log"));
+        String oldStatFile = p.getProperty(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME);
+        p.put(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, 
+            oldStatFile.replace("statArchive.gfs", testName+".gfs"));
+      }
+      system = (InternalDistributedSystem)DistributedSystem.connect(p);
+      lastSystemProperties = p;
+    } else {
+      boolean needNewSystem = false;
+      if(!getTestClass().equals(lastSystemCreatedInTest)) {
+        Properties newProps = getAllDistributedSystemProperties(props);
+        needNewSystem = !newProps.equals(lastSystemProperties);
+        if(needNewSystem) {
+          getLogWriter().info(
+              "Test class has changed and the new DS properties are not an exact match. "
+                  + "Forcing DS disconnect. Old props = "
+                  + lastSystemProperties + "new props=" + newProps);
+        }
+      } else {
+        Properties activeProps = system.getProperties();
+        for (Iterator iter = props.entrySet().iterator();
+        iter.hasNext(); ) {
+          Map.Entry entry = (Map.Entry) iter.next();
+          String key = (String) entry.getKey();
+          String value = (String) entry.getValue();
+          if (!value.equals(activeProps.getProperty(key))) {
+            needNewSystem = true;
+            getLogWriter().info("Forcing DS disconnect. For property " + key
+                                + " old value = " + activeProps.getProperty(key)
+                                + " new value = " + value);
+            break;
+          }
+        }
+      }
+      if(needNewSystem) {
+        // the current system does not meet our needs to disconnect and
+        // call recursively to get a new system.
+        getLogWriter().info("Disconnecting from current DS in order to make a new one");
+        disconnectFromDS();
+        getSystem(props);
+      }
+    }
+    return system;
+  }
+
+  /**
+   * Crash the cache in the given VM in such a way that it immediately stops communicating with
+   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
+   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
+   * 
+   * NOTE: if you use this method be sure that you clean up the VM before the end of your
+   * test with disconnectFromDS() or disconnectAllFromDS().
+   */
+  public static boolean crashDistributedSystem(VM vm) { // TODO: move
+    return (Boolean)vm.invoke(new SerializableCallable("crash distributed system") {
+      public Object call() throws Exception {
+        DistributedSystem msys = InternalDistributedSystem.getAnyInstance();
+        crashDistributedSystem(msys);
+        return true;
+      }
+    });
+  }
+  
+  /**
+   * Crash the cache in the given VM in such a way that it immediately stops communicating with
+   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
+   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
+   * 
+   * NOTE: if you use this method be sure that you clean up the VM before the end of your
+   * test with disconnectFromDS() or disconnectAllFromDS().
+   */
+  public static void crashDistributedSystem(final DistributedSystem msys) { // TODO: move
+    MembershipManagerHelper.inhibitForcedDisconnectLogging(true);
+    MembershipManagerHelper.playDead(msys);
+    JChannel c = MembershipManagerHelper.getJChannel(msys);
+    Protocol udp = c.getProtocolStack().findProtocol("UDP");
+    udp.stop();
+    udp.passUp(new Event(Event.EXIT, new RuntimeException("killing member's ds")));
+    try {
+      MembershipManagerHelper.getJChannel(msys).waitForClose();
+    }
+    catch (InterruptedException ie) {
+      Thread.currentThread().interrupt();
+      // attempt rest of work with interrupt bit set
+    }
+    MembershipManagerHelper.inhibitForcedDisconnectLogging(false);
+    WaitCriterion wc = new WaitCriterion() {
+      public boolean done() {
+        return !msys.isConnected();
+      }
+      public String description() {
+        return "waiting for distributed system to finish disconnecting: " + msys;
+      }
+    };
+//    try {
+      waitForCriterion(wc, 10000, 1000, true);
+//    } finally {
+//      dumpMyThreads(getLogWriter());
+//    }
+  }
+
+  private String getDefaultDiskStoreName() { // TODO: move
+    String vmid = System.getProperty("vmid");
+    return "DiskStore-"  + vmid + "-"+ getTestClass().getCanonicalName() + "." + getTestName();
+  }
+
+  /**
+   * Returns this VM's connection to the distributed system.  If
+   * necessary, the connection will be lazily created using the
+   * <code>Properties</code> returned by {@link
+   * #getDistributedSystemProperties}.
+   *
+   * @see #getSystem(Properties)
+   *
+   * @since 3.0
+   */
+  public final InternalDistributedSystem getSystem() {
+    return getSystem(this.getDistributedSystemProperties());
+  }
+
+  /**
+   * Returns a loner distributed system that isn't connected to other
+   * vms
+   * 
+   * @since 6.5
+   */
+  public final InternalDistributedSystem getLonerSystem() {
+    Properties props = this.getDistributedSystemProperties();
+    props.put(DistributionConfig.MCAST_PORT_NAME, "0");
+    props.put(DistributionConfig.LOCATORS_NAME, "");
+    return getSystem(props);
+  }
+  
+  /**
+   * Returns a loner distributed system in combination with enforceUniqueHost
+   * and redundancyZone properties.
+   * Added specifically to test scenario of defect #47181.
+   */
+  public final InternalDistributedSystem getLonerSystemWithEnforceUniqueHost() {
+    Properties props = this.getDistributedSystemProperties();
+    props.put(DistributionConfig.MCAST_PORT_NAME, "0");
+    props.put(DistributionConfig.LOCATORS_NAME, "");
+    props.put(DistributionConfig.ENFORCE_UNIQUE_HOST_NAME, "true");
+    props.put(DistributionConfig.REDUNDANCY_ZONE_NAME, "zone1");
+    return getSystem(props);
+  }
+
+  /**
+   * Returns an mcast distributed system that is connected to other
+   * vms using a random mcast port.
+   */
+  public final InternalDistributedSystem getMcastSystem() {
+    Properties props = this.getDistributedSystemProperties();
+    int port = AvailablePort.getRandomAvailablePort(AvailablePort.JGROUPS);
+    props.put(DistributionConfig.MCAST_PORT_NAME, ""+port);
+    props.put(DistributionConfig.MCAST_TTL_NAME, "0");
+    props.put(DistributionConfig.LOCATORS_NAME, "");
+    return getSystem(props);
+  }
+
+  /**
+   * Returns an mcast distributed system that is connected to other
+   * vms using the given mcast port.
+   */
+  public final InternalDistributedSystem getMcastSystem(int jgroupsPort) {
+    Properties props = this.getDistributedSystemProperties();
+    props.put(DistributionConfig.MCAST_PORT_NAME, ""+jgroupsPort);
+    props.put(DistributionConfig.MCAST_TTL_NAME, "0");
+    props.put(DistributionConfig.LOCATORS_NAME, "");
+    return getSystem(props);
+  }
+
+  /**
+   * Returns whether or this VM is connected to a {@link
+   * DistributedSystem}.
+   */
+  public final boolean isConnectedToDS() {
+    return system != null && system.isConnected();
+  }
+
+  /**
+   * Returns a <code>Properties</code> object used to configure a
+   * connection to a {@link
+   * com.gemstone.gemfire.distributed.DistributedSystem}.
+   * Unless overridden, this method will return an empty
+   * <code>Properties</code> object.
+   *
+   * @since 3.0
+   */
+  public Properties getDistributedSystemProperties() {
+    return new Properties();
+  }
+
+  /**
+   * Sets up the test (noop).
+   */
+  @Before
+  public final void setUpDistributedTestCase() throws Exception {
+    setUpCreationStackGenerator();
+    testName = getName();
+    System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");
+    
+    if (testName != null) {
+      GemFireCacheImpl.setDefaultDiskStoreName(getDefaultDiskStoreName());
+      String baseDefaultDiskStoreName = getTestClass().getCanonicalName() + "." + getTestName();
+      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);
+          String vmDefaultDiskStoreName = "DiskStore-" + h + "-" + v + "-" + baseDefaultDiskStoreName;
+          vm.invoke(DistributedTestCase.class, "perVMSetUp", new Object[] {testName, vmDefaultDiskStoreName});
+        }
+      }
+    }
+    System.out.println("\n\n[setup] START TEST " + getClass().getSimpleName()+"."+testName+"\n\n");
+  }
+
+  public static void perVMSetUp(String name, String defaultDiskStoreName) { // TODO: move
+    setTestName(name);
+    GemFireCacheImpl.setDefaultDiskStoreName(defaultDiskStoreName);
+    System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");    
+  }
+  
+  public static void setTestName(String name) {
+    testName = name;
+  }
+  
+  public static String getTestName() {
+    return testName;
+  }
+
+  /**
+   * For logPerTest to work, we have to disconnect from the DS, but all
+   * subclasses do not call super.tearDown(). To prevent this scenario
+   * this method has been declared final. Subclasses must now override
+   * {@link #tearDown2()} instead.
+   * @throws Exception
+   */
+  @After
+  public final void tearDownDistributedTestCase() throws Exception {
+    tearDownCreationStackGenerator();
+    tearDown2();
+    realTearDown();
+    tearDownAfter();
+  }
+
+  /**
+   * Tears down the test. This method is called by the final {@link #tearDown()} method and should be overridden to
+   * perform actual test cleanup and release resources used by the test.  The tasks executed by this method are
+   * performed before the DUnit test framework using Hydra cleans up the client VMs.
+   * <p/>
+   * @throws Exception if the tear down process and test cleanup fails.
+   * @see #tearDown
+   * @see #tearDownAfter()
+   */
+  // TODO rename this method to tearDownBefore and change the access modifier to protected!
+  public void tearDown2() throws Exception { // TODO: rename
+  }
+
+  protected void realTearDown() throws Exception {
+    if (logPerTest) {
+      disconnectFromDS();
+      invokeInEveryVM(DistributedTestCase.class, "disconnectFromDS");
+    }
+    cleanupAllVms();
+  }
+  
+  /**
+   * Tears down the test.  Performs additional tear down tasks after the DUnit tests framework using Hydra cleans up
+   * the client VMs.  This method is called by the final {@link #tearDown()} method and should be overridden to perform
+   * post tear down activities.
+   * <p/>
+   * @throws Exception if the test tear down process fails.
+   * @see #tearDown()
+   * @see #tearDown2()
+   */
+  protected void tearDownAfter() throws Exception {
+  }
+
+  public static void cleanupAllVms()
+  {
+    cleanupThisVM();
+    invokeInEveryVM(DistributedTestCase.class, "cleanupThisVM");
+    invokeInLocator(new SerializableRunnable() {
+      public void run() {
+        DistributionMessageObserver.setInstance(null);
+        unregisterInstantiatorsInThisVM();
+      }
+    });
+    DUnitLauncher.closeAndCheckForSuspects();
+  }
+
+
+  private static void cleanupThisVM() {
+    IpAddress.resolve_dns = true;
+    SocketCreator.resolve_dns = true;
+    InitialImageOperation.slowImageProcessing = 0;
+    DistributionMessageObserver.setInstance(null);
+    QueryTestUtils.setCache(null);
+    CacheServerTestUtil.clearCacheReference();
+    RegionTestCase.preSnapshotRegion = null;
+    GlobalLockingDUnitTest.region_testBug32356 = null;
+    LogWrapper.close();
+    ClientProxyMembershipID.system = null;
+    MultiVMRegionTestCase.CCRegion = null;
+    InternalBridgeMembership.unregisterAllListeners();
+    ClientStatsManager.cleanupForTests();
+    unregisterInstantiatorsInThisVM();
+    GemFireTracer.DEBUG = Boolean.getBoolean("DistributionManager.DEBUG_JAVAGROUPS");
+    Protocol.trace = GemFireTracer.DEBUG;
+    DistributionMessageObserver.setInstance(null);
+    QueryObserverHolder.reset();
+    if (InternalDistributedSystem.systemAttemptingReconnect != null) {
+      InternalDistributedSystem.systemAttemptingReconnect.stopReconnecting();
+    }
+    ExpectedExceptionString ex;
+    while((ex = ExpectedExceptionString.poll()) != null) {
+      ex.remove();
+    }
+  }
+  
+  public static void unregisterAllDataSerializersFromAllVms() // TODO: move
+  {
+    unregisterDataSerializerInThisVM();
+    invokeInEveryVM(new SerializableRunnable() {
+      public void run() {
+        unregisterDataSerializerInThisVM();
+      }
+    });
+    invokeInLocator(new SerializableRunnable() {
+      public void run() {
+        unregisterDataSerializerInThisVM();
+      }
+    });
+  }
+
+  public static void unregisterInstantiatorsInThisVM() { // TODO: move
+    // unregister all the instantiators
+    InternalInstantiator.reinitialize();
+    assertEquals(0, InternalInstantiator.getInstantiators().length);
+  }
+  
+  public static void unregisterDataSerializerInThisVM() // TODO: move
+  {
+    DataSerializerPropogationDUnitTest.successfullyLoadedTestDataSerializer = false;
+    // unregister all the Dataserializers
+    InternalDataSerializer.reinitialize();
+    // ensure that all are unregistered
+    assertEquals(0, InternalDataSerializer.getSerializers().length);
+  }
+
+
+  protected static void disconnectAllFromDS() {
+    disconnectFromDS();
+    invokeInEveryVM(DistributedTestCase.class,
+                    "disconnectFromDS");
+  }
+
+  /**
+   * Disconnects this VM from the distributed system
+   */
+  public static void disconnectFromDS() {
+    testName = null;
+    GemFireCacheImpl.testCacheXml = null;
+    if (system != null) {
+      system.disconnect();
+      system = null;
+    }
+    
+    for (;;) {
+      DistributedSystem ds = InternalDistributedSystem.getConnectedInstance();
+      if (ds == null) {
+        break;
+      }
+      try {
+        ds.disconnect();
+      }
+      catch (Exception e) {
+        // ignore
+      }
+    }
+    
+    {
+      AdminDistributedSystemImpl ads = 
+          AdminDistributedSystemImpl.getConnectedInstance();
+      if (ads != null) {// && ads.isConnected()) {
+        ads.disconnect();
+      }
+    }
+  }
+
+  /**
+   * Strip the package off and gives just the class name.
+   * Needed because of Windows file name limits.
+   */
+  private String getShortClassName() {
+    String result = this.getClass().getName();
+    int idx = result.lastIndexOf('.');
+    if (idx != -1) {
+      result = result.substring(idx+1);
+    }
+    return result;
+  }
+  
+  /** get the host name to use for a server cache in client/server dunit
+   * testing
+   * @param host
+   * @return the host name
+   */
+  public static String getServerHostName(Host host) { // TODO: move
+    return System.getProperty("gemfire.server-bind-address") != null?
+        System.getProperty("gemfire.server-bind-address")
+        : host.getHostName();
+  }
+
+  /** get the IP literal name for the current host, use this instead of  
+   * "localhost" to avoid IPv6 name resolution bugs in the JDK/machine config.
+   * @return an ip literal, this method honors java.net.preferIPvAddresses
+   */
+  public static String getIPLiteral() { // TODO: move
+    try {
+      return SocketCreator.getLocalHost().getHostAddress();
+    } catch (UnknownHostException e) {
+      throw new Error("problem determining host IP address", e);
+    }
+  }
+ 
+ 
+  /**
+   * Get the port that the standard dunit locator is listening on.
+   * @return
+   */
+  public static int getDUnitLocatorPort() { // TODO: move
+    return DUnitEnv.get().getLocatorPort();
+  }
+    
+  public String getName() {
+    return this.testNameRule.getMethodName();
+  }
+  
+  /**
+   * Returns a unique name for this test method.  It is based on the
+   * name of the class as well as the name of the method.
+   */
+  public String getUniqueName() {
+    return getClass().getSimpleName() + "_" + getName();
+  }
+
+  /**
+   * Returns a <code>LogWriter</code> for logging information
+   * @deprecated Use a static logger from the log4j2 LogService.getLogger instead.
+   */
+  @Deprecated
+  public static InternalLogWriter getLogWriter() { // TODO: delete
+    return oldLogger;
+  }
+
+  /** 
+   * Delete locator state files.  Use this after getting a random port
+   * to ensure that an old locator state file isn't picked up by the
+   * new locator you're starting.
+   * 
+   * @param ports
+   */
+  public static void deleteLocatorStateFile(final int... ports) { // TODO: move
+    for (int i=0; i<ports.length; i++) {
+      final File stateFile = new File("locator"+ports[i]+"state.dat");
+      if (stateFile.exists()) {
+        stateFile.delete();
+      }
+    }
+  }
+  
+}


[7/9] incubator-geode git commit: Test framework refactoring

Posted by kl...@apache.org.
Test framework refactoring


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/33d2c1c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/33d2c1c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/33d2c1c8

Branch: refs/heads/feature/GEODE-217
Commit: 33d2c1c86e0532f1b913f6728be85fdd2cf68782
Parents: fcd2142
Author: Kirk Lund <kl...@pivotal.io>
Authored: Fri Aug 21 13:17:45 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Fri Aug 21 13:17:45 2015 -0700

----------------------------------------------------------------------
 .../internal/lang/reflect/ReflectionUtils.java  |  41 +++++
 .../lang/reflect/ReflectionUtilsJUnitTest.java  |  78 +++++++++
 .../test/dunit/DistributedSystemSupport.java    | 102 ++++++++++++
 .../gemfire/test/dunit/NetworkSupport.java      |  23 +++
 .../test/dunit/tests/DUnitTestSuite.java        |  16 ++
 .../tests/DistributedTestNameDUnitTest.java     |  75 +++++++++
 .../gemfire/test/dunit/tests/MyTestSuite.java   |  23 +++
 .../gemfire/test/golden/GoldenTestSuite.java    |  27 ++++
 .../com/gemstone/gemfire/test/junit/Retry.java  |  17 ++
 .../gemfire/test/junit/rules/RetryRule.java     | 161 +++++++++++++++++++
 10 files changed, 563 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/main/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtils.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtils.java b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtils.java
new file mode 100755
index 0000000..0b5fee2
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtils.java
@@ -0,0 +1,41 @@
+package com.gemstone.gemfire.internal.lang.reflect;
+
+/**
+ * Utility class for helping in various reflection operations. See the 
+ * java.lang.reflect package for the classes that this class utilizes.
+ * 
+ * TODO: centralize methods from these classes to here:
+ * <li>com.gemstone.gemfire.management.internal.cli.util.spring.ReflectionUtils
+ * <li>com.gemstone.gemfire.internal.logging.LogService
+ * <li>com.gemstone.gemfire.internal.tools.gfsh.app.misc.util.ReflectionUtil
+ *  
+ * @author Kirk Lund
+ * @see com.gemstone.gemfire.internal.tools.gfsh.app.misc.util.ReflectionUtil
+ * @see com.gemstone.gemfire.internal.logging.LogService
+ * @see com.gemstone.gemfire.management.internal.cli.util.spring.ReflectionUtils
+ */
+public abstract class ReflectionUtils {
+
+  /**
+   * Gets the class name of the caller in the current stack at the given {@code depth}.
+   *
+   * @param depth a 0-based index in the current stack.
+   * @return a class name
+   */
+  public static String getClassName(final int depth) {
+    return Thread.currentThread().getStackTrace()[depth].getClassName();
+  }
+  
+  public static String getClassName() {
+    return Thread.currentThread().getStackTrace()[2].getClassName();
+  }
+  
+  public static String getMethodName(final int depth) {
+    return Thread.currentThread().getStackTrace()[depth].getMethodName();
+  }
+
+  public static String getMethodName() {
+    return Thread.currentThread().getStackTrace()[2].getMethodName();
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtilsJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtilsJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtilsJUnitTest.java
new file mode 100755
index 0000000..346dc75
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/lang/reflect/ReflectionUtilsJUnitTest.java
@@ -0,0 +1,78 @@
+package com.gemstone.gemfire.internal.lang.reflect;
+
+import static com.gemstone.gemfire.internal.lang.reflect.ReflectionUtils.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for the ReflectionUtils class.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class ReflectionUtilsJUnitTest {
+
+  @Rule
+  public TestWatcher watchman = new TestWatcher() {
+    @Override
+    protected void starting(final Description description) {
+      testClassName = description.getClassName();
+      testMethodName = description.getMethodName();
+    }
+  };
+  
+  private String testClassName;
+  private String testMethodName;
+  
+  @Test
+  public void getClassNameZeroShouldReturnReflectionUtilsClass() {
+    assertThat(getClassName(0), is(Thread.class.getName()));
+  }
+  
+  @Test
+  public void getClassNameOneShouldReturnReflectionUtilsClass() {
+    assertThat(getClassName(1), is(ReflectionUtils.class.getName()));
+  }
+  
+  @Test
+  public void getClassNameTwoShouldReturnReflectionUtilsClass() {
+    assertThat(getClassName(2), is(getClass().getName()));
+    assertThat(getClassName(2), is(this.testClassName));
+  }
+  
+  @Test
+  public void getClassNameShouldReturnReflectionUtilsClass() {
+    assertThat(getClassName(), is(getClass().getName()));
+    assertThat(getClassName(), is(this.testClassName));
+  }
+  
+  @Test
+  public void getMethodNameZeroShouldReturnGetStackTrace() {
+    assertThat(getMethodName(0), is("getStackTrace"));
+  }
+  
+  @Test
+  public void getMethodNameOneShouldReturnGetMethodName() {
+    assertThat(getMethodName(1), is("getMethodName"));
+  }
+  
+  @Test
+  public void getMethodNameTwoShouldReturnThisMethod() {
+    assertThat(getMethodName(2), is("getMethodNameTwoShouldReturnThisMethod"));
+    assertThat(getMethodName(2), is(this.testMethodName));
+  }
+  
+  @Test
+  public void getMethodNameShouldReturnThisMethod() {
+    assertThat(getMethodName(), is("getMethodNameShouldReturnThisMethod"));
+    assertThat(getMethodName(), is(this.testMethodName));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedSystemSupport.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedSystemSupport.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedSystemSupport.java
new file mode 100755
index 0000000..9c52e46
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedSystemSupport.java
@@ -0,0 +1,102 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Wait.waitForCriterion;
+
+import java.io.File;
+
+import com.gemstone.gemfire.distributed.DistributedSystem;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.distributed.internal.membership.jgroup.MembershipManagerHelper;
+import com.gemstone.org.jgroups.Event;
+import com.gemstone.org.jgroups.JChannel;
+import com.gemstone.org.jgroups.stack.Protocol;
+
+public class DistributedSystemSupport {
+
+  protected DistributedSystemSupport() {
+  }
+  
+  /**
+   * Crash the cache in the given VM in such a way that it immediately stops communicating with
+   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
+   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
+   * 
+   * NOTE: if you use this method be sure that you clean up the VM before the end of your
+   * test with disconnectFromDS() or disconnectAllFromDS().
+   */
+  public static boolean crashDistributedSystem(VM vm) { // TODO: move
+    return (Boolean)vm.invoke(new SerializableCallable("crash distributed system") {
+      public Object call() throws Exception {
+        DistributedSystem msys = InternalDistributedSystem.getAnyInstance();
+        crashDistributedSystem(msys);
+        return true;
+      }
+    });
+  }
+  
+  /**
+   * Crash the cache in the given VM in such a way that it immediately stops communicating with
+   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
+   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
+   * 
+   * NOTE: if you use this method be sure that you clean up the VM before the end of your
+   * test with disconnectFromDS() or disconnectAllFromDS().
+   */
+  public static void crashDistributedSystem(final DistributedSystem msys) { // TODO: move
+    MembershipManagerHelper.inhibitForcedDisconnectLogging(true);
+    MembershipManagerHelper.playDead(msys);
+    JChannel c = MembershipManagerHelper.getJChannel(msys);
+    Protocol udp = c.getProtocolStack().findProtocol("UDP");
+    udp.stop();
+    udp.passUp(new Event(Event.EXIT, new RuntimeException("killing member's ds")));
+    try {
+      MembershipManagerHelper.getJChannel(msys).waitForClose();
+    }
+    catch (InterruptedException ie) {
+      Thread.currentThread().interrupt();
+      // attempt rest of work with interrupt bit set
+    }
+    MembershipManagerHelper.inhibitForcedDisconnectLogging(false);
+    WaitCriterion wc = new WaitCriterion() {
+      public boolean done() {
+        return !msys.isConnected();
+      }
+      public String description() {
+        return "waiting for distributed system to finish disconnecting: " + msys;
+      }
+    };
+//    try {
+      waitForCriterion(wc, 10000, 1000, true);
+//    } finally {
+//      dumpMyThreads(getLogWriter());
+//    }
+  }
+
+  /** get the host name to use for a server cache in client/server dunit
+   * testing
+   * @param host
+   * @return the host name
+   */
+  public static String getServerHostName(Host host) {
+    return System.getProperty("gemfire.server-bind-address") != null?
+        System.getProperty("gemfire.server-bind-address")
+        : host.getHostName();
+  }
+
+  /** 
+   * Delete locator state files.  Use this after getting a random port
+   * to ensure that an old locator state file isn't picked up by the
+   * new locator you're starting.
+   * 
+   * @param ports
+   */
+  public static void deleteLocatorStateFile(final int... ports) {
+    for (int i=0; i<ports.length; i++) {
+      final File stateFile = new File("locator"+ports[i]+"state.dat");
+      if (stateFile.exists()) {
+        stateFile.delete();
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/NetworkSupport.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/NetworkSupport.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/NetworkSupport.java
new file mode 100755
index 0000000..f702b4e
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/NetworkSupport.java
@@ -0,0 +1,23 @@
+package com.gemstone.gemfire.test.dunit;
+
+import java.net.UnknownHostException;
+
+import com.gemstone.gemfire.internal.SocketCreator;
+
+public class NetworkSupport {
+  
+  protected NetworkSupport() {
+  }
+
+  /** get the IP literal name for the current host, use this instead of  
+   * "localhost" to avoid IPv6 name resolution bugs in the JDK/machine config.
+   * @return an ip literal, this method honors java.net.preferIPvAddresses
+   */
+  public static String getIPLiteral() { // TODO: move
+    try {
+      return SocketCreator.getLocalHost().getHostAddress();
+    } catch (UnknownHostException e) {
+      throw new Error("problem determining host IP address", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitTestSuite.java
new file mode 100755
index 0000000..3c9fe83
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitTestSuite.java
@@ -0,0 +1,16 @@
+package com.gemstone.gemfire.test.dunit.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  BasicDUnitTest.class,
+  DistributedTestNameDUnitTest.class,
+  VMDUnitTest.class,
+})
+/**
+ * Suite of tests for the test.dunit DUnit Test framework.
+ */
+public class DUnitTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DistributedTestNameDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DistributedTestNameDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DistributedTestNameDUnitTest.java
new file mode 100755
index 0000000..d6afc02
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DistributedTestNameDUnitTest.java
@@ -0,0 +1,75 @@
+package com.gemstone.gemfire.test.dunit.tests;
+
+import static com.gemstone.gemfire.test.dunit.Invoke.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestWatcher;
+import org.junit.runner.Description;
+
+import com.gemstone.gemfire.internal.lang.reflect.ReflectionUtils;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.SerializableRunnable;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
+
+/**
+ * Verifies that test name is available and consistent in the controller JVM 
+ * and all 4 dunit JVMs.
+ * 
+ * @author Kirk Lund
+ */
+@Category(DistributedTest.class)
+public class DistributedTestNameDUnitTest extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+
+  // TODO: remove transient and fix bug so test FAILs fast
+  
+  @Rule
+  public transient TestWatcher watchman = new TestWatcher() {
+    protected void starting(final Description description) {
+      testClassName = description.getClassName();
+      testMethodName = description.getMethodName();
+    }
+  };
+  
+  private String testClassName;
+  private String testMethodName;
+  
+  @Test
+  public void testNameShouldBeConsistentInAllJVMs() throws Exception {
+    final String methodName = this.testMethodName;
+    
+    // JUnit Rule provides getMethodName in Controller JVM
+    assertThat(getMethodName(), is(methodName));
+    
+    // Controller JVM sets testName = getMethodName in itself and all 4 other JVMs
+    assertThat(getTestName(), is(methodName));
+    
+    invokeInEveryVM(new SerializableRunnable(getMethodName()) {
+      private static final long serialVersionUID = 1L;
+      @Override
+      public void run() {
+        assertThat(getTestName(), is(methodName));
+      }
+    });
+  }
+
+  @Test
+  public void uniqueNameShouldBeConsistentInAllJVMs() throws Exception {
+    //final String uniqueName = testClassName + "_" + testMethodName;
+    final String uniqueName = getClass().getSimpleName() + "_" + testMethodName;
+    
+    assertThat(getUniqueName(), is(uniqueName));
+    
+    invokeInEveryVM(new SerializableRunnable(getMethodName()) {
+      private static final long serialVersionUID = 1L;
+      @Override
+      public void run() {
+        assertThat(getUniqueName(), is(uniqueName));
+      }
+    });
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/MyTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/MyTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/MyTestSuite.java
new file mode 100755
index 0000000..ec90a36
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/MyTestSuite.java
@@ -0,0 +1,23 @@
+package com.gemstone.gemfire.test.dunit.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+import com.gemstone.gemfire.distributed.DistributedMemberDUnitTest;
+import com.gemstone.gemfire.distributed.HostedLocatorsDUnitTest;
+import com.gemstone.gemfire.internal.offheap.OutOfOffHeapMemoryDUnitTest;
+import com.gemstone.gemfire.test.catchexception.CatchExceptionExampleDUnitTest;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  BasicDUnitTest.class,
+  DistributedTestNameDUnitTest.class,
+  VMDUnitTest.class,
+  
+  CatchExceptionExampleDUnitTest.class,
+  DistributedMemberDUnitTest.class,
+  HostedLocatorsDUnitTest.class,
+  OutOfOffHeapMemoryDUnitTest.class,
+})
+public class MyTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestSuite.java
new file mode 100755
index 0000000..ef2686e
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestSuite.java
@@ -0,0 +1,27 @@
+package com.gemstone.gemfire.test.golden;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  FailWithErrorInOutputJUnitTest.class,
+  FailWithExtraLineInOutputJUnitTest.class,
+  FailWithLineMissingFromEndOfOutputJUnitTest.class,
+  FailWithLineMissingFromMiddleOfOutputJUnitTest.class,
+  FailWithLoggerErrorInOutputJUnitTest.class,
+  FailWithLoggerFatalInOutputJUnitTest.class,
+  FailWithLoggerWarnInOutputJUnitTest.class,
+  FailWithSevereInOutputJUnitTest.class,
+  FailWithTimeoutOfWaitForOutputToMatchJUnitTest.class,
+  FailWithWarningInOutputJUnitTest.class,
+  PassJUnitTest.class,
+  PassWithExpectedErrorJUnitTest.class,
+  PassWithExpectedSevereJUnitTest.class,
+  PassWithExpectedWarningJUnitTest.class,
+})
+/**
+ * Suite of tests for the test.golden Golden Test framework classes.
+ */
+public class GoldenTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
new file mode 100755
index 0000000..af1dc2f
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
@@ -0,0 +1,17 @@
+package com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Java Annotation used to annotate a test suite class test case method in order to
+ * retry it in case of failure up to the specified maximum attempts.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Retry {
+  
+  public static int DEFAULT = 1;
+  
+  int value() default DEFAULT;
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/33d2c1c8/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
new file mode 100755
index 0000000..0de55ac
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
@@ -0,0 +1,161 @@
+package com.gemstone.gemfire.test.junit.rules;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import com.gemstone.gemfire.test.junit.Retry;
+
+/**
+ * JUnit Rule that enables retrying a failed test up to a maximum number of retries.
+ * </p> 
+ * RetryRule can be used globally for all tests in a test case by specifying a 
+ * retryCount when instantiating it:
+ * <pre>
+ * @Rule
+ * public final RetryRule retryRule = new RetryRule(3);
+ * 
+ * @Test
+ * public void shouldBeRetriedUntilPasses() {
+ *   ...
+ * }
+ * </pre>
+ * </p> 
+ * The above will result in 3 retries for every test in the test case.
+ * </p> 
+ * RetryRule can be used locally for specific tests by annotating the test 
+ * method with @Rule and specifying a retryCount for that test:
+ * <pre>
+ * @Rule
+ * public final RetryRule retryRule = new RetryRule();
+ * 
+ * @Test
+ * @Retry(3)
+ * public void shouldBeRetriedUntilPasses() {
+ *   ...
+ * }
+ * </pre>
+ * </p>
+ * This version of RetryRule will retry a test that fails because of any kind 
+ * of Throwable.
+ */
+public class RetryRule implements TestRule {
+  /**
+   * Enables printing of failures to System.err even if test passes on a retry
+   */
+  private static final boolean LOG = false;
+  
+  private final AbstractRetryRule implementation;
+
+  public RetryRule() {
+    this.implementation = new LocalRetryRule();
+  }
+
+  public RetryRule(final int retryCount) {
+    this.implementation = new GlobalRetryRule(retryCount);
+  }
+
+  @Override
+  public Statement apply(final Statement base, final Description description) {
+    return this.implementation.apply(base, description);
+  }
+
+  protected abstract class AbstractRetryRule implements TestRule {
+    protected AbstractRetryRule() {
+    }
+    protected void evaluate(final Statement base, final Description description, final int retryCount) throws Throwable {
+      if (retryCount == 0) {
+        
+      }
+      Throwable caughtThrowable = null;
+      
+      for (int count = 0; count < retryCount; count++) {
+        try {
+          base.evaluate();
+          return;
+        } catch (Throwable t) {
+          caughtThrowable = t;
+          debug(description.getDisplayName() + ": run " + (count + 1) + " failed");
+        }
+      }
+      
+      debug(description.getDisplayName() + ": giving up after " + retryCount + " failures");
+      throw caughtThrowable;
+    }
+    private void debug(final String message) {
+      if (LOG) {
+        System.err.println(message);
+      }
+    }
+  }
+  
+  /**
+   * Implementation of RetryRule for all test methods in a test case
+   */
+  protected class GlobalRetryRule extends AbstractRetryRule {
+    
+    private final int retryCount;
+
+    protected GlobalRetryRule(final int retryCount) {
+      if (retryCount < 1) {
+        throw new IllegalArgumentException("Retry count must be greater than zero");
+      }
+      this.retryCount = retryCount;
+    }
+    
+    @Override
+    public Statement apply(final Statement base, final Description description) {
+      return new Statement() {
+        @Override
+        public void evaluate() throws Throwable {
+          GlobalRetryRule.this.evaluatePerCase(base, description);
+        }
+      };
+    }
+
+    protected void evaluatePerCase(final Statement base, final Description description) throws Throwable {
+      evaluate(base, description, this.retryCount);
+    }
+  }
+
+  /**
+   * Implementation of RetryRule for test methods annotated with Retry
+   */
+  protected class LocalRetryRule extends AbstractRetryRule {
+    
+    protected LocalRetryRule() {
+    }
+    
+    @Override
+    public Statement apply(final Statement base, final Description description) {
+      return new Statement() {
+        @Override 
+        public void evaluate() throws Throwable {
+          LocalRetryRule.this.evaluatePerTest(base, description);
+        }
+      };
+    }
+
+    protected void evaluatePerTest(final Statement base, final Description description) throws Throwable {
+      if (isTest(description)) {
+        Retry retry = description.getAnnotation(Retry.class);
+        int retryCount = getRetryCount(retry);
+        evaluate(base, description, retryCount);
+      }
+    }
+
+    private int getRetryCount(final Retry retry) {
+      int retryCount = Retry.DEFAULT;
+
+      if (retry != null) {
+        retryCount = retry.value();
+      }
+
+      return retryCount;
+    }
+
+    private boolean isTest(final Description description) {
+      return (description.isSuite() || description.isTest());
+    }
+  }
+}


[3/9] incubator-geode git commit: Dunit changes for JUnit 4 syntax. Refactoring to modernize API.

Posted by kl...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
new file mode 100755
index 0000000..8535d85
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
@@ -0,0 +1,696 @@
+package com.gemstone.gemfire.test.dunit.cache;
+
+import static com.gemstone.gemfire.test.dunit.Assert.*;
+import static com.gemstone.gemfire.test.dunit.ExpectedExceptionString.*;
+import static com.gemstone.gemfire.test.dunit.Invoke.*;
+import static com.gemstone.gemfire.test.dunit.Wait.*;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import com.gemstone.gemfire.SystemFailure;
+import com.gemstone.gemfire.cache.AttributesFactory;
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.CacheException;
+import com.gemstone.gemfire.cache.CacheExistsException;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.CacheTransactionManager;
+import com.gemstone.gemfire.cache.ExpirationAttributes;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionAttributes;
+import com.gemstone.gemfire.cache.RegionExistsException;
+import com.gemstone.gemfire.cache.TimeoutException;
+import com.gemstone.gemfire.cache.client.ClientCache;
+import com.gemstone.gemfire.cache.client.ClientCacheFactory;
+import com.gemstone.gemfire.cache.client.PoolManager;
+import com.gemstone.gemfire.cache30.CacheSerializableRunnable;
+import com.gemstone.gemfire.distributed.internal.DistributionMessageObserver;
+import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
+import com.gemstone.gemfire.internal.FileUtil;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.internal.cache.HARegion;
+import com.gemstone.gemfire.internal.cache.InternalRegionArguments;
+import com.gemstone.gemfire.internal.cache.LocalRegion;
+import com.gemstone.gemfire.internal.cache.PartitionedRegion;
+import com.gemstone.gemfire.internal.cache.xmlcache.CacheCreation;
+import com.gemstone.gemfire.internal.cache.xmlcache.CacheXmlGenerator;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.VM;
+import com.gemstone.gemfire.test.dunit.WaitCriterion;
+
+/**
+ * The abstract superclass of tests that require the creation of a
+ * {@link Cache}.
+ *
+ * @author David Whitlock
+ * @since 3.0
+ */
+@SuppressWarnings({ "deprecation", "serial", "rawtypes", "unchecked" })
+public abstract class CacheTestCase extends DistributedTestCase {
+
+  /** The Cache from which regions are obtained 
+   * 
+   * All references synchronized via <code>CacheTestCase.class</code>
+   * */
+  // static so it doesn't get serialized with SerializableRunnable inner classes
+  protected static Cache cache;
+  
+  ////////  Helper methods
+  /**
+   * Creates the <code>Cache</code> for this test
+   */
+  private void createCache() {
+    createCache(false);
+  }
+  
+  private void createCache(boolean client) {
+    createCache(client, null);
+  }
+  
+  private void createCache(boolean client, CacheFactory cf) {
+    synchronized(CacheTestCase.class) {
+      try {
+        System.setProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE", "true");
+        Cache c;
+        if (client) {
+          c = (Cache)new ClientCacheFactory(getSystem().getProperties()).create();
+        } else {
+          if(cf == null) {
+            c = CacheFactory.create(getSystem());
+          } else {
+            Properties props = getSystem().getProperties();
+            for(Map.Entry entry : props.entrySet()) {
+              cf.set((String) entry.getKey(), (String)entry.getValue());
+            }
+            c = cf.create();
+          }
+        }
+        cache = c;
+      } catch (CacheExistsException e) {
+        fail("the cache already exists", e);
+
+      } catch (RuntimeException ex) {
+        throw ex;
+
+      } catch (Exception ex) {
+        fail("Checked exception while initializing cache??", ex);
+      } finally {
+        System.clearProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");
+      }
+    }
+  }
+
+  /**
+   * Creates the <code>Cache</code> for this test that is not connected
+   * to other members
+   */
+  public Cache createLonerCache() {
+    synchronized(CacheTestCase.class) {
+      try {
+        System.setProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE", "true");
+        Cache c = CacheFactory.create(getLonerSystem()); 
+        cache = c;
+      } catch (CacheExistsException e) {
+        fail("the cache already exists", e);
+
+      } catch (RuntimeException ex) {
+        throw ex;
+
+      } catch (Exception ex) {
+        fail("Checked exception while initializing cache??", ex);
+      } finally {
+        System.clearProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");
+      }
+      return cache;
+    }
+  }
+  
+  /**
+   * Creates the <code>Cache</code> for this test that is not connected
+   * to other members.
+   * Added specifically to test scenario of defect #47181.
+   */
+  public Cache createLonerCacheWithEnforceUniqueHost() {
+    synchronized(CacheTestCase.class) {
+      try {
+        System.setProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE", "true");
+        Cache c = CacheFactory.create(getLonerSystemWithEnforceUniqueHost()); 
+        cache = c;
+      } catch (CacheExistsException e) {
+        fail("the cache already exists", e);
+
+      } catch (RuntimeException ex) {
+        throw ex;
+
+      } catch (Exception ex) {
+        fail("Checked exception while initializing cache??", ex);
+      } finally {
+        System.clearProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");
+      }
+      return cache;
+    }
+  }
+
+  /**
+   * Creates the <code>Cache</code> for this test that has its own mcast group
+   */
+  public Cache createMcastCache() {
+    synchronized(CacheTestCase.class) {
+      try {
+        System.setProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE", "true");
+        Cache c = CacheFactory.create(getMcastSystem()); 
+        cache = c;
+      } catch (CacheExistsException e) {
+        fail("the cache already exists", e);
+
+      } catch (RuntimeException ex) {
+        throw ex;
+
+      } catch (Exception ex) {
+        fail("Checked exception while initializing cache??", ex);
+      } finally {
+        System.clearProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");
+      }
+      return cache;
+    }
+  }
+
+  /**
+   * Creates the <code>Cache</code> for this test that has its own mcast group
+   */
+  public Cache createMcastCache(int jgroupsPort) {
+    synchronized(CacheTestCase.class) {
+      try {
+        System.setProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE", "true");
+        Cache c = CacheFactory.create(getMcastSystem(jgroupsPort)); 
+        cache = c;
+      } catch (CacheExistsException e) {
+        fail("the cache already exists", e);
+
+      } catch (RuntimeException ex) {
+        throw ex;
+
+      } catch (Exception ex) {
+        fail("Checked exception while initializing cache??", ex);
+      } finally {
+        System.clearProperty("gemfire.DISABLE_DISCONNECT_DS_ON_CACHE_CLOSE");
+      }
+      return cache;
+    }
+  }
+  /**
+   * Sets this test up with a CacheCreation as its cache.
+   * Any existing cache is closed. Whoever calls this must also call finishCacheXml
+   */
+  public static synchronized void beginCacheXml() {
+//    getLogWriter().info("before closeCache");
+    closeCache();
+//    getLogWriter().info("before TestCacheCreation");
+    cache = new TestCacheCreation();
+//    getLogWriter().info("after TestCacheCreation");
+  }
+  /**
+   * Finish what beginCacheXml started. It does this be generating a cache.xml
+   * file and then creating a real cache using that cache.xml.
+   */
+  public void finishCacheXml(String name) {
+    synchronized(CacheTestCase.class) {
+      File file = new File(name + "-cache.xml");
+      try {
+        PrintWriter pw = new PrintWriter(new FileWriter(file), true);
+        CacheXmlGenerator.generate(cache, pw);
+        pw.close();
+      } catch (IOException ex) {
+        fail("IOException during cache.xml generation to " + file, ex);
+      }
+      cache = null;
+      GemFireCacheImpl.testCacheXml = file;
+      try {
+        createCache();
+      } finally {
+        GemFireCacheImpl.testCacheXml = null;
+      }
+    }
+  }
+  
+  /**
+   * Finish what beginCacheXml started. It does this be generating a cache.xml
+   * file and then creating a real cache using that cache.xml.
+   */
+  public void finishCacheXml(String name, boolean useSchema, String xmlVersion) {
+    synchronized(CacheTestCase.class) {
+      File dir = new File("XML_" + xmlVersion);
+      dir.mkdirs();
+      File file = new File(dir, name + ".xml");
+      try {
+        PrintWriter pw = new PrintWriter(new FileWriter(file), true);
+        CacheXmlGenerator.generate(cache, pw, useSchema, xmlVersion);
+        pw.close();
+      } catch (IOException ex) {
+        fail("IOException during cache.xml generation to " + file, ex);
+      }
+      cache = null;
+      GemFireCacheImpl.testCacheXml = file;
+      try {
+        createCache();
+      } finally {
+        GemFireCacheImpl.testCacheXml = null;
+      }
+    }
+  }
+
+  /**
+   * Return a cache for obtaining regions, created lazily.
+   */
+  public final Cache getCache() {
+    return getCache(false);
+  }
+  
+  public final Cache getCache(CacheFactory cf) {
+    return getCache(false, cf);
+  }
+  
+  public final Cache getCache(boolean client) {
+    return getCache(client, null);
+  }
+
+  public final Cache getCache(boolean client, CacheFactory cf) {
+    synchronized (CacheTestCase.class) {
+      final GemFireCacheImpl gfCache = GemFireCacheImpl.getInstance();
+      if (gfCache != null && !gfCache.isClosed()
+          && gfCache.getCancelCriterion().cancelInProgress() != null) {
+        waitForCriterion(new WaitCriterion() {
+
+          public boolean done() {
+            return gfCache.isClosed();
+          }
+
+          public String description() {
+            return "waiting for cache to close";
+          }
+        }, 30 * 1000, 300, true);
+      }
+      if (cache == null || cache.isClosed()) {
+        cache = null;
+        createCache(client, cf);
+      }
+      if (client && cache != null) {
+        addExpectedExceptionString("java.net.ConnectException");
+      }
+      return cache;
+    }
+  }
+
+  /**
+   * creates a client cache from the factory if one does not already exist
+   * @since 6.5
+   * @param factory
+   * @return the client cache
+   */
+  public final ClientCache getClientCache(ClientCacheFactory factory) {
+    synchronized (CacheTestCase.class) {
+      final GemFireCacheImpl gfCache = GemFireCacheImpl.getInstance();
+      if (gfCache != null && !gfCache.isClosed()
+          && gfCache.getCancelCriterion().cancelInProgress() != null) {
+        waitForCriterion(new WaitCriterion() {
+
+          public boolean done() {
+            return gfCache.isClosed();
+          }
+
+          public String description() {
+            return "waiting for cache to close";
+          }
+        }, 30 * 1000, 300, true);
+      }
+      if (cache == null || cache.isClosed()) {
+        cache = null;
+        disconnectFromDS();
+        cache = (Cache)factory.create();
+      }
+      if (cache != null) {
+        addExpectedExceptionString("java.net.ConnectException");
+      }
+      return (ClientCache)cache;
+    }
+  }
+
+  /**
+   * same as {@link #getCache()} but with casting
+   */
+  public final GemFireCacheImpl getGemfireCache() {
+    return (GemFireCacheImpl)getCache();
+  }
+  public static synchronized final boolean hasCache() {
+      return cache != null;
+  }
+
+  /**
+   * Return current cache without creating one.
+   */
+  public static synchronized final Cache basicGetCache() {
+      return cache;
+  }
+
+  public static synchronized void disconnectFromDS() {
+    closeCache();
+    DistributedTestCase.disconnectFromDS();
+  }
+  
+  /** Close the cache */
+  public static synchronized void closeCache() {
+    //Workaround for that fact that some classes are now extending
+    //CacheTestCase but not using it properly.
+    if(cache == null) {
+      cache = GemFireCacheImpl.getInstance();
+    }
+    try {
+    if (cache != null) {
+      try {
+        if (!cache.isClosed()) {
+          if (cache instanceof GemFireCacheImpl) {
+            CacheTransactionManager txMgr = ((GemFireCacheImpl)cache).getTxManager();
+            if (txMgr != null) {
+              if (txMgr.exists()) {
+                try {
+                  // make sure we cleanup this threads txid stored in a thread local
+                  txMgr.rollback();
+                }catch(Exception ignore) {
+                  
+                }
+              }
+            }
+          }
+          try {
+            cache.close();
+          }
+          catch (VirtualMachineError e) {
+            SystemFailure.initiateFailure(e);
+            throw e;
+          }
+          catch (Throwable t) {
+          }
+          finally {
+          }
+        }
+        // @todo darrel: destroy DiskStore files
+      }
+      finally {
+        cache = null;
+      }
+    } // cache != null
+    } finally {
+      //Make sure all pools are closed, even if we never
+      //created a cache
+      PoolManager.close(false);
+    }
+  }
+
+  /** Closed the cache in all VMs. */
+  protected void closeAllCache() {
+    closeCache();
+    invokeInEveryVM(CacheTestCase.class, "closeCache");
+  }
+
+  @Override
+  public void tearDown2() throws Exception {
+    // locally destroy all root regions and close the cache
+    remoteTearDown();
+    // Now invoke it in every VM
+    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);
+        vm.invoke(CacheTestCase.class, "remoteTearDown");
+      }
+    }
+    super.tearDown2(); 
+  }
+
+  /**
+   * Local destroy all root regions and close the cache.  
+   */
+  protected synchronized static void remoteTearDown() {
+    try {
+      DistributionMessageObserver.setInstance(null);
+      if (cache != null && !cache.isClosed()) {
+        //try to destroy the root regions first so that
+        //we clean up any persistent files.
+        for (Iterator itr = cache.rootRegions().iterator(); itr.hasNext();) {
+          Region root = (Region)itr.next();
+//          String name = root.getName();
+          //for colocated regions you can't locally destroy a partitioned
+          //region.
+    if(root.isDestroyed() || root instanceof HARegion || root instanceof PartitionedRegion) {
+            continue;
+          }
+          try {
+            root.localDestroyRegion("teardown");
+          }
+          catch (VirtualMachineError e) {
+            SystemFailure.initiateFailure(e);
+            throw e;
+          }
+          catch (Throwable t) {
+            getLogWriter().error(t);
+          }
+        }
+      }
+    }
+    finally {
+      try {
+        closeCache();
+      }
+      catch (VirtualMachineError e) {
+        SystemFailure.initiateFailure(e);
+        throw e;
+      }
+      catch (Throwable t) {
+        getLogWriter().error("Error in closing the cache ", t);
+        
+      }
+    }
+
+    try {
+      cleanDiskDirs();
+    } catch(IOException e) {
+      getLogWriter().error("Error cleaning disk dirs", e);
+    }
+  }
+  
+  /**
+   * Returns a region with the given name and attributes
+   */
+  public final Region createRegion(String name,
+                                      RegionAttributes attrs)
+    throws CacheException {
+    return createRegion(name, "root", attrs);
+  }
+  
+  /**
+   * Provide any internal region arguments, typically required when 
+   * internal use (aka meta-data) regions are needed.
+   * @return internal arguements, which may be null.  If null, then default 
+   * InternalRegionArguments are used to construct the Region
+   */
+  public InternalRegionArguments getInternalRegionArguments()
+  {
+    return null;
+  }
+
+  final public Region createRegion(String name, String rootName,
+                                      RegionAttributes attrs)
+    throws CacheException {
+    Region root = getRootRegion(rootName);
+    if (root == null) {
+      // don't put listeners on root region
+      RegionAttributes rootAttrs = attrs;
+      AttributesFactory fac = new AttributesFactory(attrs);
+      ExpirationAttributes expiration = ExpirationAttributes.DEFAULT;
+
+      // fac.setCacheListener(null);
+      fac.setCacheLoader(null);
+      fac.setCacheWriter(null);
+      fac.setPoolName(null);
+      fac.setPartitionAttributes(null);
+      fac.setRegionTimeToLive(expiration);
+      fac.setEntryTimeToLive(expiration);
+      fac.setRegionIdleTimeout(expiration);
+      fac.setEntryIdleTimeout(expiration);
+      rootAttrs = fac.create();
+      root = createRootRegion(rootName, rootAttrs);
+    }
+
+    InternalRegionArguments internalArgs = getInternalRegionArguments();
+    if (internalArgs == null) {
+      return root.createSubregion(name, attrs);
+    } else {
+      try {
+        LocalRegion lr = (LocalRegion) root;
+        return lr.createSubregion(name, attrs, internalArgs);
+      } catch (IOException ioe) {
+        AssertionError assErr = new AssertionError("unexpected exception");
+        assErr.initCause(ioe);
+        throw assErr;
+      } catch (ClassNotFoundException cnfe) {
+        AssertionError assErr = new AssertionError("unexpected exception");
+        assErr.initCause(cnfe);
+        throw assErr;
+      } 
+    }
+  }
+  
+  public final Region getRootRegion() {
+    return getRootRegion("root");
+  }
+  
+  public final Region getRootRegion(String rootName) {
+    return getCache().getRegion(rootName);
+  }
+
+  protected final Region createRootRegion(RegionAttributes attrs)
+  throws RegionExistsException, TimeoutException {
+    return createRootRegion("root", attrs);
+  }
+
+  public final Region createRootRegion(String rootName, RegionAttributes attrs)
+  throws RegionExistsException, TimeoutException {
+    return getCache().createRegion(rootName, attrs);
+  }
+
+  /**
+   * send an unordered message requiring an ack to all connected members 
+   * in order to flush the unordered communication channel
+   */
+  public void sendUnorderedMessageToAll() {
+    //if (getCache() instanceof distcache.gemfire.GemFireCacheImpl) {
+      try {
+        com.gemstone.gemfire.distributed.internal.HighPriorityAckedMessage msg = new com.gemstone.gemfire.distributed.internal.HighPriorityAckedMessage();
+        msg.send(InternalDistributedSystem.getConnectedInstance().getDM().getNormalDistributionManagerIds(), false);
+      }
+      catch (Exception e) {
+        throw new RuntimeException("Unable to send unordered message due to exception", e);
+      }
+    //}
+  }
+
+  /**
+   * send an unordered message requiring an ack to all connected admin members 
+   * in order to flush the unordered communication channel
+   */
+//  public void sendUnorderedMessageToAdminMembers() {
+//    //if (getCache() instanceof distcache.gemfire.GemFireCacheImpl) {
+//      try {
+//        com.gemstone.gemfire.distributed.internal.HighPriorityAckedMessage msg = new com.gemstone.gemfire.distributed.internal.HighPriorityAckedMessage();
+//        msg.send(DistributedSystemHelper.getAdminMembers(), false);
+//      }
+//      catch (Exception e) {
+//        throw new RuntimeException("Unable to send unordered message due to exception", e);
+//      }
+//    //}
+//  }
+
+  /**
+   * send an ordered message requiring an ack to all connected members 
+   * in order to flush the ordered communication channel
+   */
+  public void sendSerialMessageToAll() {
+    if (getCache() instanceof GemFireCacheImpl) {
+      try {
+        com.gemstone.gemfire.distributed.internal.SerialAckedMessage msg = new com.gemstone.gemfire.distributed.internal.SerialAckedMessage();
+        msg.send(InternalDistributedSystem.getConnectedInstance().getDM().getNormalDistributionManagerIds(), false);
+      }
+      catch (Exception e) {
+        throw new RuntimeException("Unable to send serial message due to exception", e);
+      }
+    }
+  }
+
+  /**
+   * @deprecated Use DistributedTestCase.addExpectedException
+   */
+  @Deprecated
+  protected CacheSerializableRunnable addExceptionTag1(final String expectedException) {
+    CacheSerializableRunnable addExceptionTag = new CacheSerializableRunnable(
+    "addExceptionTag") {
+      public void run2()
+      {
+        getCache().getLogger().info(
+            "<ExpectedException action=add>" + expectedException
+            + "</ExpectedException>");
+      }
+    };
+    
+    return addExceptionTag;
+  }
+
+  /**
+   * @deprecated Use DistributedTestCase.addExpectedException
+   */
+  @Deprecated
+  protected CacheSerializableRunnable removeExceptionTag1(final String expectedException) {
+    CacheSerializableRunnable removeExceptionTag = new CacheSerializableRunnable(
+    "removeExceptionTag") {
+      public void run2() throws CacheException {
+        getCache().getLogger().info(
+            "<ExpectedException action=remove>" + expectedException
+            + "</ExpectedException>");
+      }
+    };
+    return removeExceptionTag;
+  }
+
+  /**
+   * Used to generate a cache.xml. Basically just a CacheCreation
+   * with a few more methods implemented.
+   */
+  static class TestCacheCreation extends CacheCreation {
+    private boolean closed = false;
+    @Override
+    public void close() {
+      this.closed = true;
+    }
+    @Override
+    public boolean isClosed() {
+      return this.closed;
+    }
+  }
+  
+  public static File getDiskDir() {
+    int vmNum = VM.getCurrentVMNum();
+    File dir = new File("diskDir", "disk" + String.valueOf(vmNum)).getAbsoluteFile();
+    dir.mkdirs();
+    return dir;
+  }
+  
+  /**
+   * Return a set of disk directories
+   * for persistence tests. These directories
+   * will be automatically cleaned up 
+   * on test case closure.
+   */
+  public static File[] getDiskDirs() {
+    return new File[] {getDiskDir()};
+  }
+  
+  public static void cleanDiskDirs() throws IOException {
+    FileUtil.delete(getDiskDir());
+    File[] defaultStoreFiles = new File(".").listFiles(new FilenameFilter() {
+      
+      public boolean accept(File dir, String name) {
+        return name.startsWith("BACKUPDiskStore-" + System.getProperty("vmid"));
+      }
+    });
+    
+    for(File file: defaultStoreFiles) {
+      FileUtil.delete(file);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ChildVM.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ChildVM.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ChildVM.java
new file mode 100644
index 0000000..bbd540d
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ChildVM.java
@@ -0,0 +1,62 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.standalone;
+
+import hydra.HydraRuntimeException;
+import hydra.Log;
+
+import java.rmi.Naming;
+
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.internal.OSProcess;
+import com.gemstone.gemfire.internal.logging.LogService;
+
+import com.gemstone.gemfire.test.dunit.standalone.DUnitLauncher.MasterRemote;
+
+/**
+ * @author dsmith
+ *
+ */
+public class ChildVM {
+  
+  static {
+    createHydraLogWriter();
+  }
+  
+  private final static Logger logger = LogService.getLogger();
+  
+  public static void main(String[] args) throws Throwable {
+    try {
+      int namingPort = Integer.getInteger(DUnitLauncher.RMI_PORT_PARAM).intValue();
+      int vmNum = Integer.getInteger(DUnitLauncher.VM_NUM_PARAM).intValue();
+      int pid = OSProcess.getId();
+      logger.info("VM" + vmNum + " is launching" + (pid > 0? " with PID " + pid : ""));
+      MasterRemote holder = (MasterRemote) Naming.lookup("//localhost:" + namingPort + "/" + DUnitLauncher.MASTER_PARAM);
+      DUnitLauncher.init(holder);
+      DUnitLauncher.locatorPort = holder.getLocatorPort();
+      Naming.rebind("//localhost:" + namingPort + "/vm" + vmNum, new RemoteDUnitVM());
+      holder.signalVMReady();
+      //This loop is here so this VM will die even if the master is mean killed.
+      while(true) {
+        holder.ping();
+        Thread.sleep(1000);
+      }
+    } catch (Throwable t) {
+      t.printStackTrace();
+      System.exit(1);
+    }
+  }
+
+  private static void createHydraLogWriter() {
+    try {
+      Log.createLogWriter("dunit-childvm", "fine");
+    } catch (HydraRuntimeException ignore) {
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/DUnitLauncher.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/DUnitLauncher.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/DUnitLauncher.java
new file mode 100644
index 0000000..5d27004
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/DUnitLauncher.java
@@ -0,0 +1,416 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.standalone;
+
+import hydra.Log;
+import hydra.MethExecutorResult;
+
+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.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 org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.junit.Assert;
+
+import batterytest.greplogs.ExpectedStrings;
+import batterytest.greplogs.LogConsumer;
+
+import com.gemstone.gemfire.distributed.Locator;
+import com.gemstone.gemfire.internal.AvailablePortHelper;
+import com.gemstone.gemfire.internal.logging.LogService;
+
+import com.gemstone.gemfire.test.dunit.BounceResult;
+import com.gemstone.gemfire.test.dunit.DUnitEnv;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RemoteDUnitVMIF;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * 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.
+ * 
+ * @author dsmith
+ *
+ */
+public class DUnitLauncher {
+
+  static int locatorPort;
+
+  private static final int NUM_VMS = 4;
+  private static final int DEBUGGING_VM_NUM = -1;
+  private static final int LOCATOR_VM_NUM = -2;
+
+  static final long STARTUP_TIMEOUT = 30 * 1000;
+  private static final String SUSPECT_FILENAME = "dunit_suspect.log";
+  private static File DUNIT_SUSPECT_FILE;
+
+  public static final String DUNIT_DIR = "dunit";
+  public static final String LOG_LEVEL = System.getProperty("logLevel", "config");
+  public static final String WORKSPACE_DIR_PARAM = "WORKSPACE_DIR";
+  public static final boolean LOCATOR_LOG_TO_DISK = Boolean.getBoolean("locatorLogToDisk");
+
+  static final String MASTER_PARAM = "DUNIT_MASTER";
+  static final String RMI_PORT_PARAM = "gemfire.DUnitLauncher.RMI_PORT";
+  static final String VM_NUM_PARAM = "gemfire.DUnitLauncher.VM_NUM";
+
+  private static final String LAUNCHED_PROPERTY = "gemfire.DUnitLauncher.LAUNCHED";
+
+  private DUnitLauncher() {
+  }
+  
+  private static boolean isHydra() {
+    try {
+      //TODO - this is hacky way to test for a hydra environment - see
+      //if there is registered test configuration object.
+      Class<?> clazz = Class.forName("hydra.TestConfig");
+      Method getInstance = clazz.getMethod("getInstance", new Class[0]);
+      getInstance.invoke(null, null);
+      return true;
+    } catch (Exception e) {
+      return false;
+    }
+  }
+  /**
+   * Launch DUnit. If the unit test was launched through
+   * the hydra framework, leave the test alone.
+   */
+  public static void launchIfNeeded() {
+    if(System.getProperties().contains(VM_NUM_PARAM)) {
+      //we're a dunit child vm, do nothing.
+      return;
+    }
+
+    if(!isHydra() &&!isLaunched()) {
+      try {
+        launch();
+      } catch (Exception e) {
+        throw new RuntimeException("Unable to launch dunit VMS", e);
+      }
+    }
+  }
+  
+  /**
+   * Test it see if the eclise dunit environment is launched.
+   */
+  public static boolean isLaunched() {
+    return Boolean.getBoolean(LAUNCHED_PROPERTY);
+  }
+  
+  public static String getLocatorString() {
+    return "localhost[" + locatorPort + "]";
+  }
+
+  
+  private static void launch() throws URISyntaxException, AlreadyBoundException, IOException, InterruptedException, NotBoundException  {
+//  initialize the log writer that hydra uses
+    Log.createLogWriter( "dunit-master", LOG_LEVEL );
+
+    DUNIT_SUSPECT_FILE = new File(SUSPECT_FILENAME);
+    DUNIT_SUSPECT_FILE.delete();
+    DUNIT_SUSPECT_FILE.deleteOnExit();
+    
+    locatorPort = AvailablePortHelper.getRandomAvailableTCPPort();
+     
+    //create an RMI registry and add an object to share our tests config
+    int namingPort = AvailablePortHelper.getRandomAvailableTCPPort();
+    Registry registry = LocateRegistry.createRegistry(namingPort);
+
+    final ProcessManager processManager = new ProcessManager(namingPort, registry);
+    Master master = new Master(registry, processManager);
+    registry.bind(MASTER_PARAM, master);
+
+    Runtime.getRuntime().addShutdownHook(new Thread() {
+      public void run() {
+        processManager.killVMs();
+      }
+    });
+    
+    //Create a VM for the locator
+    processManager.launchVM(LOCATOR_VM_NUM);
+    
+    //Launch an initial set of VMs
+    for(int i=0; i < NUM_VMS; i++) {
+      processManager.launchVM(i);
+    }
+    
+    //wait for the VMS to start up
+    if(!processManager.waitForVMs(STARTUP_TIMEOUT)) {
+      throw new RuntimeException("VMs did not start up with 30 seconds");
+    }
+    
+    //populate the Host class with our stubs. The tests use this host class
+    DUnitHost host = new DUnitHost(InetAddress.getLocalHost().getCanonicalHostName(), processManager);
+    host.init(registry, NUM_VMS);
+
+    init(master);
+    
+    startLocator(registry);
+  }
+  
+  public static Properties getDistributedSystemProperties() {
+    Properties p = new Properties();
+    p.setProperty("locators", getLocatorString());
+    p.setProperty("mcast-port", "0");
+    p.setProperty("enable-cluster-configuration", "false");
+    p.setProperty("use-cluster-configuration", "false");
+    p.setProperty("log-level", LOG_LEVEL);
+    return p;
+  }
+
+  /**
+   * Add an appender to Log4j which sends all INFO+ messages to a separate file
+   * which will be used later to scan for suspect strings.  The pattern of the
+   * messages conforms to the original log format so that hydra will be able
+   * to parse them.
+   */
+  private static void addSuspectFileAppender(final String workspaceDir) {
+    final String suspectFilename = new File(workspaceDir, SUSPECT_FILENAME).getAbsolutePath();
+
+    final LoggerContext appenderContext = ((org.apache.logging.log4j.core.Logger)
+        LogManager.getLogger(LogService.BASE_LOGGER_NAME)).getContext();
+
+    final PatternLayout layout = PatternLayout.createLayout(
+        "[%level{lowerCase=true} %date{yyyy/MM/dd HH:mm:ss.SSS z} <%thread> tid=%tid] %message%n%throwable%n", null, null,
+        Charset.defaultCharset(), true, false, "", "");
+    
+    final FileAppender fileAppender = FileAppender.createAppender(suspectFilename, "true", "false",
+        DUnitLauncher.class.getName(), "true", "false", "false", "0", layout, null, null, null, appenderContext.getConfiguration());
+    fileAppender.start();
+
+    LoggerConfig loggerConfig = appenderContext.getConfiguration().getLoggerConfig(LogService.BASE_LOGGER_NAME);
+    loggerConfig.addAppender(fileAppender, Level.INFO, null);
+  }
+  
+  private static void startLocator(Registry registry) throws IOException, NotBoundException {
+    RemoteDUnitVMIF remote = (RemoteDUnitVMIF) registry.lookup("vm" + LOCATOR_VM_NUM);
+    final File locatorLogFile =
+        LOCATOR_LOG_TO_DISK ? new File("locator-" + locatorPort + ".log") : new File(""); 
+    MethExecutorResult result = remote.executeMethodOnObject(new SerializableCallable() {
+      public Object call() throws IOException {
+        Properties p = getDistributedSystemProperties();
+        // I never want this locator to end up starting a jmx manager
+        // since it is part of the unit test framework
+        p.setProperty("jmx-manager", "false");
+        //Disable the shared configuration on this locator.
+        //Shared configuration tests create their own locator
+        p.setProperty("enable-cluster-configuration", "false");
+        Locator.startLocatorAndDS(locatorPort, locatorLogFile, p);
+        return null;
+      }
+    }, "call");
+    if(result.getException() != null) {
+      RuntimeException ex = new RuntimeException("Failed to start locator", result.getException());
+      ex.printStackTrace();
+      throw ex;
+    }
+  }
+
+  public static void init(MasterRemote master) {
+    DUnitEnv.set(new StandAloneDUnitEnv(master));
+    //fake out tests that are using a bunch of hydra stuff
+    String workspaceDir = System.getProperty(DUnitLauncher.WORKSPACE_DIR_PARAM) ;
+    workspaceDir = workspaceDir == null ? new File(".").getAbsolutePath() : workspaceDir;
+    
+    addSuspectFileAppender(workspaceDir);
+    
+    //Free off heap memory when disconnecting from the distributed system
+    System.setProperty("gemfire.free-off-heap-memory", "true");
+    
+    //indicate that this CM is controlled by the eclipse dunit.
+    System.setProperty(LAUNCHED_PROPERTY, "true");
+  }
+  
+  public static void closeAndCheckForSuspects() {
+    if (isLaunched()) {
+      final boolean skipLogMsgs = ExpectedStrings.skipLogMsgs("dunit");
+      final List<?> expectedStrings = ExpectedStrings.create("dunit");
+      final LogConsumer logConsumer = new LogConsumer(skipLogMsgs, expectedStrings, "log4j", 5);
+
+      final StringBuilder suspectStringBuilder = new StringBuilder();
+
+      BufferedReader buffReader = null;
+      FileChannel fileChannel = null;
+      try {
+        fileChannel = new FileOutputStream(DUNIT_SUSPECT_FILE, true).getChannel();
+        buffReader = new BufferedReader(new FileReader(DUNIT_SUSPECT_FILE));
+      } catch (FileNotFoundException e) {
+        System.err.println("Could not find the suspect string output file: " + e);
+        return;
+      }
+      try {
+        String line;
+        try {
+          while ((line = buffReader.readLine()) != null) {
+            final StringBuilder builder = logConsumer.consume(line);
+            if (builder != null) {
+              suspectStringBuilder.append(builder);
+            }
+          }
+        } catch (IOException e) {
+          System.err.println("Could not read the suspect string output file: " + e);
+        }
+        
+        try {
+          fileChannel.truncate(0);
+        } catch (IOException e) {
+          System.err.println("Could not truncate the suspect string output file: " + e);
+        }
+        
+      } finally {
+        try {
+          buffReader.close();
+          fileChannel.close();
+        } catch (IOException e) {
+          System.err.println("Could not close the suspect string output file: " + e);
+        }
+      }
+
+      if (suspectStringBuilder.length() != 0) {
+        System.err.println("Suspicious strings were written to the log during this run.\n"
+            + "Fix the strings or use DistributedTestCase.addExpectedException to ignore.\n"
+            + suspectStringBuilder);
+        
+        Assert.fail("Suspicious strings were written to the log during this run.\n"
+            + "Fix the strings or use DistributedTestCase.addExpectedException to ignore.\n"
+            + suspectStringBuilder);
+      }
+    }
+  }
+
+  public interface MasterRemote extends Remote {
+    public int getLocatorPort() throws RemoteException;
+    public void signalVMReady() throws RemoteException;
+    public void ping() throws RemoteException;
+    public BounceResult bounce(int pid) throws RemoteException;
+  }
+  
+  public static class Master extends UnicastRemoteObject implements MasterRemote {
+    private static final long serialVersionUID = 1178600200232603119L;
+    
+    private final Registry registry;
+    private final ProcessManager processManager;
+
+
+    public Master(Registry registry, ProcessManager processManager) throws RemoteException {
+      this.processManager = processManager;
+      this.registry = registry;
+    }
+
+    public int getLocatorPort()  throws RemoteException{
+      return locatorPort;
+    }
+
+    public synchronized void signalVMReady() {
+      processManager.signalVMReady();
+    }
+    
+    public void ping() {
+      //do nothing
+    }
+
+    @Override
+    public BounceResult bounce(int pid) {
+      processManager.bounce(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);
+        return new BounceResult(pid, remote);
+      } catch (RemoteException | NotBoundException e) {
+        throw new RuntimeException("could not lookup name", e);
+      } catch (InterruptedException e) {
+        throw new RuntimeException("Failed waiting for VM", e);
+      }
+    }
+  }
+  
+  private static class DUnitHost extends Host {
+    private static final long serialVersionUID = -8034165624503666383L;
+    
+    private transient final 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.processManager = processManager;
+    }
+    
+    public void init(Registry registry, int numVMs) throws AccessException, RemoteException, NotBoundException, InterruptedException {
+      for(int i = 0; i < numVMs; i++) {
+        RemoteDUnitVMIF remote = processManager.getStub(i);
+        addVM(i, remote);
+      }
+      
+      addLocator(LOCATOR_VM_NUM, processManager.getStub(LOCATOR_VM_NUM));
+      
+      addHost(this);
+    }
+
+    @Override
+    public VM getVM(int n) {
+      
+      if(n == DEBUGGING_VM_NUM) {
+        //for ease of debugging, pass -1 to get the local VM
+        return debuggingVM;
+      }
+
+      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++) {
+            processManager.launchVM(i);
+          }
+          processManager.waitForVMs(STARTUP_TIMEOUT);
+
+          for(int i = oldVMCount; i <= n; i++) {
+            addVM(i, processManager.getStub(i));
+          }
+
+        } catch (IOException | InterruptedException | NotBoundException e) {
+          throw new RuntimeException("Could not dynamically launch vm + " + n, e);
+        }
+      }
+      
+      return super.getVM(n);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ProcessManager.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ProcessManager.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ProcessManager.java
new file mode 100644
index 0000000..d625892
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/ProcessManager.java
@@ -0,0 +1,228 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.standalone;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+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;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+
+import com.gemstone.gemfire.internal.FileUtil;
+import com.gemstone.gemfire.internal.logging.LogService;
+
+import com.gemstone.gemfire.test.dunit.RemoteDUnitVMIF;
+
+/**
+ * @author dsmith
+ *
+ */
+public class ProcessManager {
+  
+  private int namingPort;
+  private Map<Integer, ProcessHolder> processes = new HashMap<Integer, ProcessHolder>();
+  private File log4jConfig;
+  private int pendingVMs;
+  private Registry registry;
+
+  public ProcessManager(int namingPort, Registry registry) {
+    this.namingPort = namingPort;
+    this.registry = registry;
+  }
+  
+  public void launchVMs() throws IOException, NotBoundException {
+    log4jConfig = LogService.findLog4jConfigInCurrentDir();
+  }
+
+  public synchronized void launchVM(int vmNum) throws IOException {
+    if(processes.containsKey(vmNum)) {
+      throw new IllegalStateException("VM " + vmNum + " is already running.");
+    }
+    
+    String[] cmd = buildJavaCommand(vmNum, namingPort);
+    System.out.println("Executing " + Arrays.asList(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()));
+    }
+    workingDir.mkdirs();
+    if (log4jConfig != null) {
+      FileUtils.copyFileToDirectory(log4jConfig, workingDir);
+    }
+    
+    //TODO - delete directory contents, preferably with commons io FileUtils
+    Process process = Runtime.getRuntime().exec(cmd, null, workingDir);
+    pendingVMs++;
+    ProcessHolder holder = new ProcessHolder(process);
+    processes.put(vmNum, holder);
+    linkStreams(vmNum, holder, process.getErrorStream(), System.err);
+    linkStreams(vmNum, holder, process.getInputStream(), System.out);
+  }
+
+  public static File getVMDir(int vmNum) {
+    return new File(DUnitLauncher.DUNIT_DIR, "vm" + vmNum);
+  }
+  
+  public synchronized void killVMs() {
+    for(ProcessHolder process : processes.values()) {
+      if(process != null) {
+        //TODO - stop it gracefully? Why bother
+        process.kill();
+      }
+    }
+  }
+  
+  public synchronized void bounce(int vmNum) {
+    if(!processes.containsKey(vmNum)) {
+      throw new IllegalStateException("No such process " + vmNum);
+    }
+    try {
+      ProcessHolder holder = processes.remove(vmNum);
+      holder.kill();
+      holder.getProcess().waitFor();
+      launchVM(vmNum);
+    } 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) {
+    Thread ioTransport = new Thread() {
+      public void run() {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+        String vmName = (vmNum==-2)? "[locator]" : "[vm_"+vmNum+"]";
+        try {
+          String line = reader.readLine();
+          while(line != null) {
+            out.print(vmName);
+            out.println(line);
+            line = reader.readLine();
+          }
+        } catch(Exception e) {
+          if(!holder.isKilled()) {
+            out.println("Error transporting IO from child process");
+            e.printStackTrace(out);
+          }
+        }
+      }
+    };
+
+    ioTransport.setDaemon(true);
+    ioTransport.start();
+  }
+
+  private String[] buildJavaCommand(int vmNum, int namingPort) {
+    String cmd = System.getProperty( "java.home" ) + File.separator + "bin" + File.separator + "java";
+    String classPath = System.getProperty("java.class.path");
+    //String tmpDir = System.getProperty("java.io.tmpdir");
+    String agent = getAgentString();
+    return new String[] {
+      cmd, "-classpath", classPath,
+      "-D" + DUnitLauncher.RMI_PORT_PARAM + "=" + namingPort,
+      "-D" + DUnitLauncher.VM_NUM_PARAM + "=" + vmNum,
+      "-D" + DUnitLauncher.WORKSPACE_DIR_PARAM + "=" + new File(".").getAbsolutePath(),
+      "-DlogLevel=" + DUnitLauncher.LOG_LEVEL,
+      "-Djava.library.path=" + System.getProperty("java.library.path"),
+      "-Xrunjdwp:transport=dt_socket,server=y,suspend=n",
+      "-XX:+HeapDumpOnOutOfMemoryError",
+      "-Xmx512m",
+      "-XX:MaxPermSize=256M",
+      "-Dgemfire.DEFAULT_MAX_OPLOG_SIZE=10",
+      "-Dgemfire.disallowMcastDefaults=true",
+      "-XX:MaxPermSize=256M",
+      "-ea",
+      agent,
+      ChildVM.class.getName()
+    };
+  }
+  
+  /**
+   * Get the java agent passed to this process and pass it to the child VMs.
+   * This was added to support jacoco code coverage reports
+   */
+  private String getAgentString() {
+    RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
+    if (runtimeBean != null) {
+      for(String arg: runtimeBean.getInputArguments()) {
+        if(arg.contains("-javaagent:")) {
+          //HACK for gradle bug  GRADLE-2859. Jacoco is passing a relative path
+          //That won't work when we pass this to dunit VMs in a different 
+          //directory
+          arg = arg.replace("-javaagent:..", "-javaagent:" + System.getProperty("user.dir") + File.separator + "..");
+          arg = arg.replace("destfile=..", "destfile=" + System.getProperty("user.dir") + File.separator + "..");
+          return arg;
+        }
+      }
+    }
+    
+    return "-DdummyArg=true";
+  }
+
+  synchronized void signalVMReady() {
+    pendingVMs--;
+    this.notifyAll();
+  }
+  
+  public synchronized boolean waitForVMs(long timeout) throws InterruptedException {
+    long end = System.currentTimeMillis() + timeout;
+    while(pendingVMs > 0) {
+      long remaining = end - System.currentTimeMillis();
+      if(remaining <= 0) {
+        return false;
+      }
+      this.wait(remaining);
+    }
+    
+    return true;
+  }
+  
+  private static class ProcessHolder {
+    private final Process process;
+    private volatile boolean killed = false;
+    
+    public ProcessHolder(Process process) {
+      this.process = process;
+    }
+
+    public void kill() {
+      this.killed = true;
+      process.destroy();
+      
+    }
+
+    public Process getProcess() {
+      return process;
+    }
+
+    public boolean isKilled() {
+      return killed;
+    }
+  }
+
+  public RemoteDUnitVMIF getStub(int i) throws AccessException, RemoteException, NotBoundException, InterruptedException {
+    waitForVMs(DUnitLauncher.STARTUP_TIMEOUT);
+    return (RemoteDUnitVMIF) registry.lookup("vm" + i);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/RemoteDUnitVM.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/RemoteDUnitVM.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/RemoteDUnitVM.java
new file mode 100644
index 0000000..031b706
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/RemoteDUnitVM.java
@@ -0,0 +1,136 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.standalone;
+
+import hydra.MethExecutor;
+import hydra.MethExecutorResult;
+
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.internal.logging.LogService;
+
+import com.gemstone.gemfire.test.dunit.RemoteDUnitVMIF;
+
+/**
+ * @author dsmith
+ *
+ */
+public class RemoteDUnitVM extends UnicastRemoteObject implements RemoteDUnitVMIF {
+  
+  private static final Logger logger = LogService.getLogger();
+  
+  public RemoteDUnitVM() throws RemoteException {
+    super();
+  }
+
+  /** 
+   * Called remotely by the master controller to cause the client to execute 
+   * the instance method on the object.  Does this synchronously (does not spawn
+   * a thread).  This method is used by the unit test framework, dunit.
+   *
+   * @param obj the object to execute the method on
+   * @param methodName the name of the method to execute
+   * @return the result of method execution
+   */ 
+   public MethExecutorResult executeMethodOnObject( Object obj, String methodName ) {
+     String name = obj.getClass().getName() + "." + methodName + 
+       " on object: " + obj;
+     logger.info("Received method: " + name);
+     long start = System.currentTimeMillis();
+     MethExecutorResult result = MethExecutor.executeObject( obj, methodName );
+     long delta = System.currentTimeMillis() - start;
+     logger.info( "Got result: " + result.toString().trim()  + " from " +
+               name + " (took " + delta + " ms)");
+     return result;
+   }
+
+   /**
+    * Executes a given instance method on a given object with the given
+    * arguments. 
+    */
+   public MethExecutorResult executeMethodOnObject(Object obj,
+                                                   String methodName,
+                                                   Object[] args) {
+     String name = obj.getClass().getName() + "." + methodName + 
+              (args != null ? " with " + args.length + " args": "") +
+       " on object: " + obj;
+     logger.info("Received method: " + name);
+     long start = System.currentTimeMillis();
+     MethExecutorResult result = 
+       MethExecutor.executeObject(obj, methodName, args);
+     long delta = System.currentTimeMillis() - start;
+     logger.info( "Got result: " + result.toString() + " from " + name + 
+               " (took " + delta + " ms)");
+     return result;
+   }
+
+  /** 
+   * Called remotely by the master controller to cause the client to execute 
+   * the method on the class.  Does this synchronously (does not spawn a thread).
+   * This method is used by the unit test framework, dunit.
+   *
+   * @param className the name of the class execute
+   * @param methodName the name of the method to execute
+   * @return the result of method execution
+   */ 
+   public MethExecutorResult executeMethodOnClass( String className, String methodName ) {
+     String name = className + "." + methodName;
+     logger.info("Received method: " +  name);
+     long start = System.currentTimeMillis();
+     MethExecutorResult result = MethExecutor.execute( className, methodName );
+     long delta = System.currentTimeMillis() - start;
+     logger.info( "Got result: " + result.toString() + " from " + name + 
+               " (took " + delta + " ms)");
+     
+     return result;
+   }
+
+   /**
+    * Executes a given static method in a given class with the given
+    * arguments. 
+    */
+   public MethExecutorResult executeMethodOnClass(String className,
+                                                  String methodName,
+                                                  Object[] args) {
+     String name = className + "." + methodName + 
+       (args != null ? " with " + args.length + " args": "");
+     logger.info("Received method: " + name);
+     long start = System.currentTimeMillis();
+     MethExecutorResult result = 
+       MethExecutor.execute(className, methodName, args);
+     long delta = System.currentTimeMillis() - start;
+     logger.info( "Got result: " + result.toString() + " from " + name +
+               " (took " + delta + " ms)");
+     return result;
+   }
+
+  public void executeTask(int tsid, int type, int index) throws RemoteException {
+    throw new UnsupportedOperationException();
+    
+  }
+  
+  public void runShutdownHook() throws RemoteException {
+    
+  }
+
+  public void notifyDynamicActionComplete(int actionId) throws RemoteException {
+    throw new UnsupportedOperationException();
+    
+  }
+
+  public void shutDownVM(boolean disconnect, boolean runShutdownHook)
+      throws RemoteException {
+  }
+
+  public void disconnectVM()
+  throws RemoteException {
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/StandAloneDUnitEnv.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/StandAloneDUnitEnv.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/StandAloneDUnitEnv.java
new file mode 100644
index 0000000..8746a70
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/standalone/StandAloneDUnitEnv.java
@@ -0,0 +1,66 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.standalone;
+
+import java.io.File;
+import java.rmi.RemoteException;
+import java.util.Properties;
+
+import com.gemstone.gemfire.test.dunit.BounceResult;
+import com.gemstone.gemfire.test.dunit.DUnitEnv;
+import com.gemstone.gemfire.test.dunit.standalone.DUnitLauncher.MasterRemote;
+
+public class StandAloneDUnitEnv extends DUnitEnv {
+
+  private MasterRemote master;
+
+  public StandAloneDUnitEnv(MasterRemote master) {
+    this.master = master;
+  }
+
+  @Override
+  public String getLocatorString() {
+    return DUnitLauncher.getLocatorString();
+  }
+
+  @Override
+  public String getLocatorAddress() {
+    return "localhost";
+  }
+  
+  @Override
+  public int getLocatorPort() {
+    return DUnitLauncher.locatorPort;
+  }
+
+  @Override
+  public Properties getDistributedSystemProperties() {
+    return DUnitLauncher.getDistributedSystemProperties();
+  }
+
+  @Override
+  public int getPid() {
+    return Integer.getInteger(DUnitLauncher.VM_NUM_PARAM, -1).intValue();
+  }
+
+  @Override
+  public int getVMID() {
+    return getPid();
+  }
+
+  @Override
+  public BounceResult bounce(int pid) throws RemoteException {
+    return master.bounce(pid);
+  }
+
+  @Override
+  public File getWorkingDirectory(int pid) {
+    return ProcessManager.getVMDir(pid);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
new file mode 100644
index 0000000..d0b1710
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
@@ -0,0 +1,124 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.tests;
+
+import static com.gemstone.gemfire.test.dunit.Assert.*;
+import static org.hamcrest.Matchers.*;
+
+import java.util.Properties;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.gemstone.gemfire.test.dunit.AsyncInvocation;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RMIException;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * This class tests the basic functionality of the distributed unit
+ * test framework.
+ */
+public class BasicDUnitTest extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+
+  private static final String REMOTE_THROW_EXCEPTION_MESSAGE = "Throwing remoteThrowException";
+  
+  private static Properties bindings = new Properties();
+
+  /**
+   * Tests how the DUnit framework handles an error
+   */
+  @Test(expected = RMIException.class)
+  public void testDontCatchRemoteException() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    vm.invoke(getClass(), "remoteThrowException");
+  }
+
+  @Test
+  public void testRemoteInvocationWithException() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invoke(getClass(), "remoteThrowException");
+      fail("Should have thrown a BasicTestException");
+
+    } catch (RMIException expected) {
+      Throwable cause = expected.getCause();
+      assertThat(cause, is(instanceOf(BasicTestException.class)));
+      assertThat(cause.getMessage(), is("Throwing remoteThrowException"));
+    }
+  }
+  
+  @Test
+  public void testRemoteInvokeAsync() throws InterruptedException {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    String name = this.getUniqueName();
+    String value = "Hello";
+
+    AsyncInvocation ai = vm.invokeAsync(this.getClass(), "remoteBind", new Object[] { name, value });
+    ai.join();
+    if (ai.exceptionOccurred()) {
+      fail("remoteBind failed", ai.getException());
+    }
+
+    ai = vm.invokeAsync(this.getClass(), "remoteValidateBind", new Object[] {name, value });
+    ai.join();
+    if (ai.exceptionOccurred()) {
+      fail("remoteValidateBind failed", ai.getException());
+    }
+  }
+
+  @Test
+  public void testRemoteInvokeAsyncWithException() throws InterruptedException {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+
+    AsyncInvocation ai = vm.invokeAsync(this.getClass(), "remoteThrowException");
+    ai.join();
+    assertTrue(ai.exceptionOccurred());
+    Throwable ex = ai.getException();
+    assertTrue(ex instanceof BasicTestException);
+  }
+
+  @Test
+  @Ignore("not implemented")
+  public void testRemoteInvocationBoolean() {
+  }
+
+  /**
+   * Accessed via reflection.  DO NOT REMOVE
+   */
+  protected static void remoteThrowException() {
+    throw new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE);
+  }
+  
+  protected static void remoteBind(String name, String s) {
+    new BasicDUnitTest().getSystem(); // forces connection
+    bindings.setProperty(name, s);
+  }
+
+  protected static void remoteValidateBind(String name, String expected) {
+    assertEquals(expected, bindings.getProperty(name));
+  }
+
+  protected static class BasicTestException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public BasicTestException() {
+      super();
+    }
+    
+    public BasicTestException(String message) {
+      super(message);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
new file mode 100755
index 0000000..82664b2
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
@@ -0,0 +1,16 @@
+package com.gemstone.gemfire.test.dunit.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  BasicDUnitTest.class,
+  VMDUnitTest.class,
+})
+/**
+ * Suite of tests for the test.dunit DUnit Test framework.
+ */
+public class DUnitFrameworkTestSuite {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/TestFailure.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/TestFailure.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/TestFailure.java
new file mode 100644
index 0000000..d6d89e3
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/TestFailure.java
@@ -0,0 +1,37 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.tests;
+
+import static org.junit.Assert.*;
+
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+
+/**
+ * The tests in this class always fail.  It is used when developing
+ * DUnit to give us an idea of how test failure are logged, etc.
+ *
+ * @author David Whitlock
+ *
+ * @since 3.0
+ */
+public class TestFailure extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+
+  public void testFailure() {
+    assertTrue("Test Failure", false);
+  }
+
+  public void testError() {
+    String s = "Test Error";
+    throw new Error(s);
+  }
+
+  public void testHang() throws InterruptedException {
+    Thread.sleep(100000 * 1000);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
new file mode 100644
index 0000000..12faffe
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
@@ -0,0 +1,245 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit.tests;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.io.Serializable;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+import com.gemstone.gemfire.test.dunit.AsyncInvocation;
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RMIException;
+import com.gemstone.gemfire.test.dunit.VM;
+
+/**
+ * This class tests the functionality of the {@link VM} class.
+ */
+public class VMDUnitTest extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+  
+  private static final boolean BOOLEAN_VALUE = true;
+  private static final byte BYTE_VALUE = (byte) 40;
+  private static final long LONG_VALUE = 42L;
+  private static final String STRING_VALUE = "BLAH BLAH BLAH";
+
+  private static final AtomicInteger COUNTER = new AtomicInteger();
+  
+  @Test
+  public void testInvokeNonExistentMethod() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invoke(VMDUnitTest.class, "nonExistentMethod");
+      fail("Should have thrown an RMIException");
+
+    } catch (RMIException ex) {
+      String s = "Excepted a NoSuchMethodException, got a " + ex.getCause();;
+      assertTrue(s, ex.getCause() instanceof NoSuchMethodException);
+    }
+  }
+
+  @Test
+  public void testInvokeStaticBoolean() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    assertEquals(BOOLEAN_VALUE, vm.invokeBoolean(VMDUnitTest.class, "remoteBooleanMethod")); 
+  }
+
+  @Test
+  public void testInvokeStaticBooleanNotBoolean() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invokeBoolean(VMDUnitTest.class, "remoteByteMethod");
+      fail("Should have thrown an IllegalArgumentException");
+
+    } catch (IllegalArgumentException ex) {
+      String s = "Method \"remoteByteMethod\" in class \"" + getClass().getName() + "\" returned a \"" + Byte.class.getName() + "\" expected a boolean";
+      assertThat(ex.getMessage(), equalTo(s));
+    }
+  }
+
+  @Test
+  public void testInvokeStaticLong() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    assertEquals(LONG_VALUE, vm.invokeLong(VMDUnitTest.class, "remoteLongMethod")); 
+  }
+
+  @Test
+  public void testInvokeStaticLongNotLong() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invokeLong(VMDUnitTest.class, "remoteByteMethod");
+      fail("Should have thrown an IllegalArgumentException");
+
+    } catch (IllegalArgumentException ex) {
+      String s = "Method \"remoteByteMethod\" in class \"" + getClass().getName() + "\" returned a \"" + Byte.class.getName() + "\" expected a long";
+      assertThat(ex.getMessage(), equalTo(s));
+    }
+  }
+
+  @Test
+  public void testInvokeInstanceLong() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    assertEquals(LONG_VALUE, vm.invokeLong(new ClassWithLong(), "getLong"));
+  }
+
+  @Test
+  public void testInvokeInstanceLongNotLong() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invokeLong(new ClassWithByte(), "getByte");
+      fail("Should have thrown an IllegalArgumentException");
+
+    } catch (IllegalArgumentException ex) {
+      String s = "Method \"getByte\" in class \"" + ClassWithByte.class.getName() + "\" returned a \"" + Byte.class.getName() + "\" expected a long";
+      assertThat(ex.getMessage(), equalTo(s));
+    }
+  }
+
+  @Test
+  public void testInvokeInstance() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    assertEquals(STRING_VALUE, vm.invoke(new ClassWithString(), "getString"));
+  }
+
+  @Test
+  public void testInvokeRunnable() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+    try {
+      vm.invoke(new InvokeRunnable());
+      fail("Should have thrown a BasicTestException");
+
+    } catch (RMIException ex) {
+      assertTrue(ex.getCause() instanceof BasicDUnitTest.BasicTestException);
+    }
+  }
+  
+  @Test
+  public void testReturnValue() throws Exception {
+    final Host host = Host.getHost(0);
+    final VM vm = host.getVM(0);
+    // Assert class static invocation works
+    AsyncInvocation a1 = vm.invokeAsync(getClass(), "getAndIncStaticCount");
+    a1.join();
+    assertEquals(new Integer(0), a1.getReturnValue());
+    // Assert class static invocation with args works
+    a1 = vm.invokeAsync(getClass(), "incrementStaticCount", new Object[] {new Integer(2)});
+    a1.join();
+    assertEquals(new Integer(3), a1.getReturnValue());
+    // Assert that previous values are not returned when invoking method w/ no return val
+    a1 = vm.invokeAsync(getClass(), "incStaticCount");
+    a1.join();
+    assertNull(a1.getReturnValue());
+    // Assert that previous null returns are over-written 
+    a1 = vm.invokeAsync(getClass(), "getAndIncStaticCount");
+    a1.join();
+    assertEquals(new Integer(4), a1.getReturnValue());
+
+    // Assert object method invocation works with zero arg method
+    final VMTestObject o = new VMTestObject(0);
+    a1 = vm.invokeAsync(o, "incrementAndGet", new Object[] {});
+    a1.join();
+    assertEquals(new Integer(1), a1.getReturnValue());
+    // Assert object method invocation works with no return
+    a1 = vm.invokeAsync(o, "set", new Object[] {new Integer(3)});
+    a1.join();
+    assertNull(a1.getReturnValue());
+  }
+
+  protected static Integer getAndIncStaticCount() {
+    return new Integer(COUNTER.getAndIncrement());
+  }
+  
+  protected static Integer incrementStaticCount(Integer inc) {
+    return new Integer(COUNTER.addAndGet(inc.intValue()));
+  }
+  
+  protected static void incStaticCount() {
+    COUNTER.incrementAndGet();
+  }
+  
+  /**
+   * Accessed via reflection.  DO NOT REMOVE
+   */
+  protected static byte remoteByteMethod() {
+    return BYTE_VALUE;
+  }
+
+  /**
+   * Accessed via reflection.  DO NOT REMOVE
+   */
+  protected static boolean remoteBooleanMethod() {
+    return BOOLEAN_VALUE;
+  }
+
+  /**
+   * Accessed via reflection.  DO NOT REMOVE
+   */
+  protected static long remoteLongMethod() {
+    return LONG_VALUE;
+  }
+
+  protected static class InvokeRunnable implements Serializable, Runnable {
+    private static final long serialVersionUID = 1L;
+    @Override
+    public void run() {
+      throw new BasicDUnitTest.BasicTestException();
+    }
+  }
+
+  protected static class ClassWithString implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public String getString() {
+      return STRING_VALUE;
+    }
+  }
+
+  protected static class VMTestObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private final AtomicInteger val;
+    public VMTestObject(int init) {
+      this.val = new AtomicInteger(init);
+    }
+    public Integer get() {
+      return new Integer(this.val.get());
+    }
+    public Integer incrementAndGet() {
+      return new Integer(this.val.incrementAndGet());
+    }
+    public void set(Integer newVal) {
+      this.val.set(newVal.intValue());
+    }
+  }
+  
+  protected static class ClassWithLong implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public long getLong() {
+      return LONG_VALUE;
+    }
+  }
+
+  protected static class ClassWithByte implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public byte getByte() {
+      return BYTE_VALUE;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/dunit/DistributedTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/dunit/DistributedTestCase.java b/gemfire-core/src/test/java/dunit/DistributedTestCase.java
index 8aa8b6d..d26d3e1 100755
--- a/gemfire-core/src/test/java/dunit/DistributedTestCase.java
+++ b/gemfire-core/src/test/java/dunit/DistributedTestCase.java
@@ -144,7 +144,7 @@ public abstract class DistributedTestCase extends TestCase implements java.io.Se
     vm.invoke(new SerializableRunnable("Attach Debugger") {
       public void run() {
         com.gemstone.gemfire.internal.util.DebuggerSupport.
-        waitForJavaDebugger(getSystem().getLogWriter().convertToLogWriterI18n(), msg);
+        waitForJavaDebugger(msg);
       } 
     });
   }
@@ -526,7 +526,7 @@ public abstract class DistributedTestCase extends TestCase implements java.io.Se
    * NOTE: if you use this method be sure that you clean up the VM before the end of your
    * test with disconnectFromDS() or disconnectAllFromDS().
    */
-  public boolean crashDistributedSystem(VM vm) {
+  public static boolean crashDistributedSystem(VM vm) {
     return (Boolean)vm.invoke(new SerializableCallable("crash distributed system") {
       public Object call() throws Exception {
         DistributedSystem msys = InternalDistributedSystem.getAnyInstance();
@@ -544,7 +544,7 @@ public abstract class DistributedTestCase extends TestCase implements java.io.Se
    * NOTE: if you use this method be sure that you clean up the VM before the end of your
    * test with disconnectFromDS() or disconnectAllFromDS().
    */
-  public void crashDistributedSystem(final DistributedSystem msys) {
+  public static void crashDistributedSystem(final DistributedSystem msys) {
     MembershipManagerHelper.inhibitForcedDisconnectLogging(true);
     MembershipManagerHelper.playDead(msys);
     JChannel c = MembershipManagerHelper.getJChannel(msys);

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/dunit/VM.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/dunit/VM.java b/gemfire-core/src/test/java/dunit/VM.java
index 323dbfb..537c53b 100644
--- a/gemfire-core/src/test/java/dunit/VM.java
+++ b/gemfire-core/src/test/java/dunit/VM.java
@@ -14,8 +14,6 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.rmi.RemoteException;
 import java.util.concurrent.Callable;
-//import java.util.Iterator;
-//import java.util.Vector;
 
 /**
  * This class represents a Java Virtual Machine that runs on a host.

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java b/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java
index 5b38816..965b1ab 100644
--- a/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java
+++ b/gemfire-core/src/test/java/dunit/standalone/ProcessManager.java
@@ -157,7 +157,7 @@ public class ProcessManager {
       "-XX:MaxPermSize=256M",
       "-ea",
       agent,
-      "dunit.standalone.ChildVM"
+      ChildVM.class.getName()
     };
   }
   

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/categories/MembershipTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/categories/MembershipTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/categories/MembershipTest.java
new file mode 100755
index 0000000..458eaad
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/categories/MembershipTest.java
@@ -0,0 +1,9 @@
+package com.gemstone.gemfire.test.junit.categories;
+
+/**
+ * JUnit Test Category that specifies a test involving membership in a distributed system.
+ * 
+ * @author Kirk Lund
+ */
+public class MembershipTest {
+}


[8/9] incubator-geode git commit: More examples and rules

Posted by kl...@apache.org.
More examples and rules


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/d0c03307
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/d0c03307
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/d0c03307

Branch: refs/heads/feature/GEODE-217
Commit: d0c033074b239162ea6d2f5fde7ac8e329402a24
Parents: 33d2c1c
Author: Kirk Lund <kl...@pivotal.io>
Authored: Fri Aug 21 13:27:27 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Fri Aug 21 13:27:27 2015 -0700

----------------------------------------------------------------------
 .../test/assertj/AssertJExampleJUnitTest.java   | 119 ++++++++
 .../CatchExceptionExampleDUnitTest.java         |  59 ++++
 .../CatchExceptionExampleJUnitTest.java         |  99 +++++++
 .../JUnitParamsExampleJUnitTest.java            |  36 +++
 .../com/gemstone/gemfire/test/junit/Repeat.java |  26 ++
 .../test/junit/rules/ExpectedTimeoutRule.java   | 164 +++++++++++
 .../gemfire/test/junit/rules/RepeatRule.java    |  57 ++++
 .../tests/ExpectedTimeoutRuleJUnitTest.java     | 206 ++++++++++++++
 .../junit/rules/tests/JUnitRuleTestSuite.java   |  16 ++
 .../junit/rules/tests/RepeatRuleJUnitTest.java  | 278 +++++++++++++++++++
 .../RetryRuleGlobalWithErrorJUnitTest.java      | 247 ++++++++++++++++
 .../RetryRuleGlobalWithExceptionJUnitTest.java  | 253 +++++++++++++++++
 .../tests/RetryRuleLocalWithErrorJUnitTest.java | 206 ++++++++++++++
 .../RetryRuleLocalWithExceptionJUnitTest.java   | 221 +++++++++++++++
 14 files changed, 1987 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-core/src/test/java/com/gemstone/gemfire/test/assertj/AssertJExampleJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/assertj/AssertJExampleJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/assertj/AssertJExampleJUnitTest.java
new file mode 100755
index 0000000..aaa6a84
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/assertj/AssertJExampleJUnitTest.java
@@ -0,0 +1,119 @@
+package com.gemstone.gemfire.test.assertj;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class AssertJExampleJUnitTest {
+
+  private Character aragorn;
+  private Character boromir;
+  private Character elrond;
+  private Character frodo;
+  private Character galadriel;
+  private Character gandalf;
+  private Character gimli;
+  private Character legolas;
+  private Character merry;
+  private Character pippin;
+  private Character sauron;
+  private Character sam;
+  
+  private Ring narya;
+  private Ring nenya;
+  private Ring oneRing;
+  private Ring vilya;
+  
+  private Set<Character> fellowshipOfTheRing;
+  private Map<Ring, Character> ringBearers;
+  
+  @Before
+  public void setUp() {
+    this.aragorn = new Character("Aragorn");
+    this.boromir = new Character("Boromir");
+    this.elrond = new Character("Elrond");
+    this.frodo = new Character("Frodo");
+    this.galadriel = new Character("Galadriel");
+    this.gandalf = new Character("Gandalf");
+    this.gimli = new Character("Gimli");
+    this.legolas = new Character("Legolas");
+    this.merry = new Character("Merry");
+    this.pippin = new Character("Pippin");
+    this.sauron = new Character("Sauron");
+    this.sam = new Character("Sam");
+    
+    this.narya = new Ring();
+    this.nenya = new Ring();
+    this.oneRing = new Ring();
+    this.vilya = new Ring();
+    
+    this.fellowshipOfTheRing = new HashSet<Character>();
+    this.fellowshipOfTheRing.add(this.aragorn);
+    this.fellowshipOfTheRing.add(this.boromir);
+    this.fellowshipOfTheRing.add(this.frodo);
+    this.fellowshipOfTheRing.add(this.gandalf);
+    this.fellowshipOfTheRing.add(this.gimli);
+    this.fellowshipOfTheRing.add(this.legolas);
+    this.fellowshipOfTheRing.add(this.merry);
+    this.fellowshipOfTheRing.add(this.pippin);
+    this.fellowshipOfTheRing.add(this.sam);
+
+    this.ringBearers = new HashMap<Ring, Character>();
+    this.ringBearers.put(this.oneRing, this.frodo);
+    this.ringBearers.put(this.nenya, this.galadriel);
+    this.ringBearers.put(this.narya, this.gandalf);
+    this.ringBearers.put(this.vilya, this.elrond);
+  }
+  
+  @Test
+  public void exampleShouldPass() {
+    // common assertions
+    assertThat(frodo.getName()).isEqualTo("Frodo");
+    assertThat(frodo).isNotEqualTo(sauron)
+                     .isIn(fellowshipOfTheRing);
+
+    // String specific assertions
+    assertThat(frodo.getName()).startsWith("Fro")
+                               .endsWith("do")
+                               .isEqualToIgnoringCase("frodo");
+
+    // collection specific assertions
+    assertThat(fellowshipOfTheRing).hasSize(9)
+                                   .contains(frodo, sam)
+                                   .doesNotContain(sauron);
+
+    // using extracting magical feature to check fellowshipOfTheRing characters name :)
+    assertThat(fellowshipOfTheRing).extracting("name").contains("Boromir", "Gandalf", "Frodo", "Legolas")
+                                                      .doesNotContain("Sauron", "Elrond");
+
+    // map specific assertions, ringBearers initialized with the elves rings and the one ring bearers.
+    assertThat(ringBearers).hasSize(4)
+                           .contains(entry(oneRing, frodo), entry(nenya, galadriel))
+                           .doesNotContainEntry(oneRing, aragorn);  
+  }
+  
+  protected static class Character {
+    private final String name;
+    public Character(final String name) {
+      this.name = name;
+    }
+    public String getName() {
+      return this.name;
+    }
+  }
+  
+  protected static class Ring {
+    public Ring() {
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleDUnitTest.java
new file mode 100755
index 0000000..845c46d
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleDUnitTest.java
@@ -0,0 +1,59 @@
+package com.gemstone.gemfire.test.catchexception;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static com.googlecode.catchexception.apis.BDDCatchException.when;
+import static org.assertj.core.api.BDDAssertions.*;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.dunit.DistributedTestCase;
+import com.gemstone.gemfire.test.dunit.Host;
+import com.gemstone.gemfire.test.dunit.RMIException;
+import com.gemstone.gemfire.test.dunit.SerializableCallable;
+import com.gemstone.gemfire.test.dunit.VM;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
+
+/**
+ * Using Catch-Exception works well for remote exceptions and asserting details
+ * about root cause of RMIExceptions in DUnit tests.
+ */
+@Category(DistributedTest.class)
+public class CatchExceptionExampleDUnitTest extends DistributedTestCase {
+  private static final long serialVersionUID = 1L;
+
+  private static final String REMOTE_THROW_EXCEPTION_MESSAGE = "Throwing remoteThrowException";
+
+  @Test
+  public void testRemoteInvocationWithException() {
+    Host host = Host.getHost(0);
+    VM vm = host.getVM(0);
+
+    when(vm).invoke(new ThrowBasicTestException());
+
+    then(caughtException())
+        .isInstanceOf(RMIException.class)
+        .hasCause(new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE));
+  }
+  
+  protected static class ThrowBasicTestException extends SerializableCallable<Object> {
+    private static final long serialVersionUID = 1L;
+    
+    @Override
+    public Object call() throws Exception {
+      throw new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE);
+    }
+  }
+  
+  protected static class BasicTestException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public BasicTestException() {
+      super();
+    }
+    
+    public BasicTestException(String message) {
+      super(message);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleJUnitTest.java
new file mode 100755
index 0000000..73dc361
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionExampleJUnitTest.java
@@ -0,0 +1,99 @@
+package com.gemstone.gemfire.test.catchexception;
+
+import static com.googlecode.catchexception.CatchException.*;
+import static com.googlecode.catchexception.apis.BDDCatchException.when;
+import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
+import static org.assertj.core.api.BDDAssertions.*;
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Simple unit tests exercising Catch-Exception with AssertJ, Hamcrest and JUnit.
+ */
+@Category(UnitTest.class)
+public class CatchExceptionExampleJUnitTest {
+
+  @Test
+  public void catchExceptionShouldCatchException() {
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    // then: catch the exception if any is thrown
+    catchException(myList).get(1);
+    
+    // then: we expect an IndexOutOfBoundsException
+    assertThat(caughtException(), is(instanceOf(IndexOutOfBoundsException.class)));
+  }
+  
+  @Test
+  public void verifyExceptionShouldCatchException() {
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    // then: catch the exception if any is thrown
+    // then: we expect an IndexOutOfBoundsException
+    verifyException(myList, IndexOutOfBoundsException.class).get(1);
+  }
+  
+  @Test
+  public void whenShouldCatchExceptionAndUseAssertJAssertion() {
+    // given: an empty list
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    when(myList).get(1);
+
+    // then: we expect an IndexOutOfBoundsException
+    then(caughtException())
+            .isInstanceOf(IndexOutOfBoundsException.class)
+            .hasMessage("Index: 1, Size: 0")
+            .hasNoCause();
+  }
+  
+  @Test
+  public void catchExceptionShouldCatchExceptionAndUseHamcrestAssertion() {
+    // given: an empty list
+    List<?> myList = new ArrayList<Object>();
+
+    // when: we try to get the first element of the list
+    catchException(myList).get(1);
+
+    // then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
+    assertThat(caughtException(),
+      allOf(
+        instanceOf(IndexOutOfBoundsException.class),
+        hasMessage("Index: 1, Size: 0"),
+        hasNoCause()
+      )
+    );
+  }
+  
+  @Test
+  public void shouldCatchFromThrowException() throws Exception {
+    String message = "error message";
+    
+    catchException(this).throwException(message);
+    
+    assertThat(caughtException(), is(instanceOf(Exception.class)));
+  }
+  
+  @Test
+  public void shouldVerifyFromThrowException() throws Exception {
+    String message = "error message";
+
+    verifyException(this).throwException(message);
+  }
+  
+  // fails if private
+  protected void throwException(final String message) throws Exception {
+    throw new Exception(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-core/src/test/java/com/gemstone/gemfire/test/junitparams/JUnitParamsExampleJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/junitparams/JUnitParamsExampleJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/junitparams/JUnitParamsExampleJUnitTest.java
new file mode 100755
index 0000000..4e14fa7
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/junitparams/JUnitParamsExampleJUnitTest.java
@@ -0,0 +1,36 @@
+package com.gemstone.gemfire.test.junitparams;
+
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@Category(UnitTest.class)
+@RunWith(JUnitParamsRunner.class)
+public class JUnitParamsExampleJUnitTest {
+  @Test
+  @Parameters({"17, false", 
+               "22, true" })
+  public void personIsAdult(int age, boolean valid) throws Exception {
+    assertThat(true, is(true));
+    assertThat(new Person(age).isAdult(), is(valid));
+  }
+  
+  protected static class Person {
+    private static final int MIN_AGE_OF_ADULT = 18;
+    private final int age;
+    public Person(final int age) {
+      this.age = age;
+    }
+    public Boolean isAdult() {
+      return this.age >= MIN_AGE_OF_ADULT;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
new file mode 100755
index 0000000..b76d160
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
@@ -0,0 +1,26 @@
+package com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The Repeat class is a Java Annotation enabling an annotated test suite class test case method to be repeated
+ * a specified number of iterations.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface Repeat {
+
+  public static int DEFAULT = 1;
+  
+  int value() default DEFAULT;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
new file mode 100755
index 0000000..bf6456f
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
@@ -0,0 +1,164 @@
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.junit.Assert.assertThat;
+
+import java.util.concurrent.TimeUnit;
+
+import org.hamcrest.Matcher;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Expect an Exception within a specified timeout.
+ * 
+ * @author Kirk Lund
+ * @since 8.2
+ */
+public class ExpectedTimeoutRule implements TestRule {
+
+  /**
+   * @return a Rule that expects no timeout (identical to behavior without this Rule)
+   */
+  public static ExpectedTimeoutRule none() {
+    return new ExpectedTimeoutRule();
+  }
+  
+  private ExpectedException delegate;
+  private boolean expectsThrowable;
+  private long minDuration;
+  private long maxDuration;
+  private TimeUnit timeUnit;
+  
+  private ExpectedTimeoutRule() {
+    this.delegate = ExpectedException.none();
+  }
+
+  public ExpectedTimeoutRule expectMinimumDuration(final long minDuration) {
+    this.minDuration = minDuration;
+    return this;
+  }
+  public ExpectedTimeoutRule expectMaximumDuration(final long maxDuration) {
+    this.maxDuration = maxDuration;
+    return this;
+  }
+  public ExpectedTimeoutRule expectTimeUnit(final TimeUnit timeUnit) {
+    this.timeUnit = timeUnit;
+    return this;
+  }
+
+  public ExpectedTimeoutRule handleAssertionErrors() {
+    this.delegate.handleAssertionErrors();
+    return this;
+  }
+  
+  public ExpectedTimeoutRule handleAssumptionViolatedExceptions() {
+    this.delegate.handleAssumptionViolatedExceptions();
+    return this;
+  }
+  
+  /**
+   * Adds {@code matcher} to the list of requirements for any thrown
+   * exception.
+   */
+  public void expect(final Matcher<?> matcher) {
+    this.delegate.expect(matcher);
+  }
+
+  /**
+   * Adds to the list of requirements for any thrown exception that it should
+   * be an instance of {@code type}
+   */
+  public void expect(final Class<? extends Throwable> type) {
+    this.delegate.expect(type);
+    this.expectsThrowable = true;
+  }
+
+  /**
+   * Adds to the list of requirements for any thrown exception that it should
+   * <em>contain</em> string {@code substring}
+   */
+  public void expectMessage(final String substring) {
+    this.delegate.expectMessage(substring);
+  }
+
+  /**
+   * Adds {@code matcher} to the list of requirements for the message returned
+   * from any thrown exception.
+   */
+  public void expectMessage(final Matcher<String> matcher) {
+    this.delegate.expectMessage(matcher);
+  }
+
+  /**
+   * Adds {@code matcher} to the list of requirements for the cause of
+   * any thrown exception.
+   */
+  public void expectCause(final Matcher<? extends Throwable> expectedCause) {
+    this.delegate.expectCause(expectedCause);
+  }
+
+  public boolean expectsTimeout() {
+    return minDuration > 0 || maxDuration > 0;
+  }
+  
+  public boolean expectsThrowable() {
+    return expectsThrowable = true;
+  }
+  
+  @Override
+  public Statement apply(final Statement base, final Description description) {
+    Statement next = delegate.apply(base, description);
+    return new ExpectedTimeoutStatement(next);
+  }
+  
+  private void handleTime(final Long duration) {
+    if (expectsTimeout()) {
+      assertThat(timeUnit.convert(duration, TimeUnit.NANOSECONDS), new TimeMatcher(timeUnit, minDuration, maxDuration));
+    }
+  }
+  
+  private static class TimeMatcher extends org.hamcrest.TypeSafeMatcher<Long> {
+    
+    private final TimeUnit timeUnit;
+    private final long minDuration;
+    private final long maxDuration;
+ 
+    public TimeMatcher(final TimeUnit timeUnit, final long minDuration, final long maxDuration) {
+      this.timeUnit = timeUnit;
+      this.minDuration = minDuration;
+      this.maxDuration = maxDuration;
+    }
+ 
+    @Override
+    public boolean matchesSafely(final Long duration) {
+      return duration >= this.minDuration && duration <= this.maxDuration;
+    }
+
+    @Override
+    public void describeTo(final org.hamcrest.Description description) {
+      description.appendText("expects duration to be greater than or equal to ")
+          .appendValue(this.minDuration)
+          .appendText(" and less than or equal to ")
+          .appendValue(this.maxDuration)
+          .appendText(" ")
+          .appendValue(this.timeUnit);
+    }
+  }
+  
+  private class ExpectedTimeoutStatement extends Statement {
+    private final Statement next;
+
+    public ExpectedTimeoutStatement(final Statement base) {
+      next = base;
+    }
+
+    @Override
+    public void evaluate() throws Throwable {
+      long start = System.nanoTime();
+      next.evaluate();
+      handleTime(System.nanoTime() - start);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
new file mode 100755
index 0000000..ef66d48
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
@@ -0,0 +1,57 @@
+package com.gemstone.gemfire.test.junit.rules;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.Repeat;
+
+/**
+ * The RepeatRule class is a JUnit TestRule that enables an appropriately @Repeat annotated test case method
+ * to be repeated a specified number of times.
+ * 
+ * TODO: disallow 0 because @Retry(0) is equivalent to @Ignore apparently
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ */
+@SuppressWarnings("unused")
+public class RepeatRule implements TestRule {
+
+  protected static final int DEFAULT_REPETITIONS = 1;
+
+  @Override
+  public Statement apply(final Statement statement, final Description description) {
+    return new Statement() {
+      @Override public void evaluate() throws Throwable {
+        RepeatRule.this.evaluate(statement, description);
+      }
+    };
+  }
+
+  protected void evaluate(final Statement statement, final Description description) throws Throwable {
+    if (isTest(description)) {
+      Repeat repeat = description.getAnnotation(Repeat.class);
+
+      for (int count = 0, repetitions = getRepetitions(repeat); count < repetitions; count++) {
+        statement.evaluate();
+      }
+    }
+  }
+
+  private int getRepetitions(final Repeat repeat) {
+    int repetitions = DEFAULT_REPETITIONS;
+
+    if (repeat != null) {
+      repetitions = repeat.value();
+    }
+
+    return repetitions;
+  }
+
+  private boolean isTest(final Description description) {
+    return (description.isSuite() || description.isTest());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleJUnitTest.java
new file mode 100755
index 0000000..8a14f67
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleJUnitTest.java
@@ -0,0 +1,206 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.core.StringContains.*;
+import static org.hamcrest.core.Is.*;
+import static org.hamcrest.core.IsInstanceOf.*;
+import static org.junit.Assert.*;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.ExpectedTimeoutRule;
+
+/**
+ * Unit tests for ExpectedTimeout JUnit Rule.
+ * 
+ * @author Kirk Lund
+ * @since 8.2
+ */
+@Category(UnitTest.class)
+public class ExpectedTimeoutRuleJUnitTest {
+
+  @Test
+  public void passesUnused() {
+    Result result = runTest(PassingTestShouldPassWhenUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void failsWithoutExpectedException() {
+    Result result = runTest(FailsWithoutExpectedException.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString("Expected test to throw an instance of " + TimeoutException.class.getName()));
+  }
+  
+  @Test
+  public void failsWithoutExpectedTimeoutException() {
+    Result result = runTest(FailsWithoutExpectedTimeoutException.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWithoutExpectedTimeoutException.message + "\")"));
+  }
+  
+  @Test
+  public void failsWithExpectedTimeoutButWrongError() {
+    Result result = runTest(FailsWithExpectedTimeoutButWrongError.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(NullPointerException.class.getName()));
+  }
+  
+  @Test
+  public void passesWithExpectedTimeoutAndTimeoutException() {
+    Result result = runTest(PassesWithExpectedTimeoutAndTimeoutException.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void failsWhenTimeoutIsEarly() {
+    Result result = runTest(FailsWhenTimeoutIsEarly.class);
+   
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsEarly.message + "\")"));
+  }
+  
+  @Test
+  public void failsWhenTimeoutIsLate() {
+    Result result = runTest(FailsWhenTimeoutIsLate.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsLate.message + "\")"));
+  }
+  
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class AbstractExpectedTimeoutRuleTest {
+    @Rule
+    public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none();
+  }
+  
+  public static class PassingTestShouldPassWhenUnused extends AbstractExpectedTimeoutRuleTest {
+    @Test
+    public void passesUnused() throws Exception {
+    }
+  }
+  
+  public static class FailsWithoutExpectedException extends AbstractExpectedTimeoutRuleTest {
+    @Test
+    public void failsWithoutExpectedException() throws Exception {
+      timeout.expect(TimeoutException.class);
+    }
+  }
+  
+  public static class FailsWithoutExpectedTimeoutException extends AbstractExpectedTimeoutRuleTest {
+    public static final String message = "this is a message for FailsWithoutExpectedTimeoutException";
+    @Test
+    public void failsWithoutExpectedTimeoutAndTimeoutException() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(10);
+      timeout.expectMaximumDuration(1000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(100);
+    }
+  }
+  
+  public static class FailsWithExpectedTimeoutButWrongError extends AbstractExpectedTimeoutRuleTest {
+    public static final String message = "this is a message for FailsWithExpectedTimeoutButWrongError";
+    @Test
+    public void failsWithExpectedTimeoutButWrongError() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(10);
+      timeout.expectMaximumDuration(1000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(100);
+      throw new NullPointerException();
+    }
+  }
+
+  public static class PassesWithExpectedTimeoutAndTimeoutException extends AbstractExpectedTimeoutRuleTest {
+    public static final String message = "this is a message for PassesWithExpectedTimeoutAndTimeoutException";
+    public static final Class<TimeoutException> exceptionClass = TimeoutException.class;
+    @Test
+    public void passesWithExpectedTimeoutAndTimeoutException() throws Exception {
+      timeout.expect(exceptionClass);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(10);
+      timeout.expectMaximumDuration(1000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(100);
+      throw new TimeoutException(message);
+    }
+  }
+
+  public static class FailsWhenTimeoutIsEarly extends AbstractExpectedTimeoutRuleTest {
+    public static final String message = "this is a message for FailsWhenTimeoutIsEarly";
+    @Test
+    public void failsWhenTimeoutIsEarly() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(1000);
+      timeout.expectMaximumDuration(2000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(10);
+    }
+  }
+
+  public static class FailsWhenTimeoutIsLate extends AbstractExpectedTimeoutRuleTest {
+    public static final String message = "this is a message for FailsWhenTimeoutIsLate";
+    @Test
+    public void failsWhenTimeoutIsLate() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(10);
+      timeout.expectMaximumDuration(20);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(100);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
new file mode 100755
index 0000000..ff102f7
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
@@ -0,0 +1,16 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+  ExpectedTimeoutRuleJUnitTest.class,
+  RepeatRuleJUnitTest.class,
+  RetryRuleGlobalWithErrorJUnitTest.class,
+  RetryRuleGlobalWithExceptionJUnitTest.class,
+  RetryRuleLocalWithErrorJUnitTest.class,
+  RetryRuleLocalWithExceptionJUnitTest.class,
+})
+public class JUnitRuleTestSuite {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RepeatRuleJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RepeatRuleJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RepeatRuleJUnitTest.java
new file mode 100755
index 0000000..5e69f03
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RepeatRuleJUnitTest.java
@@ -0,0 +1,278 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.Matchers.*;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.Repeat;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RepeatRule;
+
+/**
+ * Unit tests for Repeat JUnit Rule.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class RepeatRuleJUnitTest {
+
+  private static final String ASSERTION_ERROR_MESSAGE = "failing test";
+  
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsUnused() {
+    Result result = runTest(FailingTestShouldFailOneTimeWhenRepeatIsUnused.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(ASSERTION_ERROR_MESSAGE));
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsUnused.count, is(1));
+  }
+
+  @Test
+  public void passingTestShouldPassOneTimeWhenRepeatIsUnused() {
+    Result result = runTest(PassingTestShouldPassOneTimeWhenRepeatIsUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassingTestShouldPassOneTimeWhenRepeatIsUnused.count, is(1));
+  }
+
+  @Test
+  public void failingTestShouldBeSkippedWhenRepeatIsZero() {
+    Result result = runTest(FailingTestShouldBeSkippedWhenRepeatIsZero.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(FailingTestShouldBeSkippedWhenRepeatIsZero.count, is(0));
+  }
+
+  @Test
+  public void passingTestShouldBeSkippedWhenRepeatIsZero() {
+    Result result = runTest(PassingTestShouldBeSkippedWhenRepeatIsZero.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassingTestShouldBeSkippedWhenRepeatIsZero.count, is(0));
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsOne() {
+    Result result = runTest(FailingTestShouldFailOneTimeWhenRepeatIsOne.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(ASSERTION_ERROR_MESSAGE));
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsOne.count, is(1));
+  }
+
+  @Test
+  public void passingTestShouldPassOneTimeWhenRepeatIsOne() {
+    Result result = runTest(PassingTestShouldPassOneTimeWhenRepeatIsOne.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassingTestShouldPassOneTimeWhenRepeatIsOne.count, is(1));
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsTwo() {
+    Result result = runTest(FailingTestShouldFailOneTimeWhenRepeatIsTwo.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(ASSERTION_ERROR_MESSAGE));
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsTwo.count, is(1));
+  }
+
+  @Test
+  public void passingTestShouldPassTwoTimesWhenRepeatIsTwo() {
+    Result result = runTest(PassingTestShouldPassTwoTimesWhenRepeatIsTwo.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassingTestShouldPassTwoTimesWhenRepeatIsTwo.count, is(2));
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsThree() {
+    Result result = runTest(FailingTestShouldFailOneTimeWhenRepeatIsThree.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(ASSERTION_ERROR_MESSAGE));
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsThree.count, is(1));
+  }
+
+  @Test
+  public void passingTestShouldPassThreeTimesWhenRepeatIsThree() {
+    Result result = runTest(PassingTestShouldPassThreeTimesWhenRepeatIsThree.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassingTestShouldPassThreeTimesWhenRepeatIsThree.count, is(3));
+  }
+
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsUnused {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  public static class PassingTestShouldPassOneTimeWhenRepeatIsUnused {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  public static class FailingTestShouldBeSkippedWhenRepeatIsZero {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(0)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  public static class PassingTestShouldBeSkippedWhenRepeatIsZero {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(0)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsOne {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(1)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  public static class PassingTestShouldPassOneTimeWhenRepeatIsOne {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(1)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsTwo {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(2)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  public static class PassingTestShouldPassTwoTimesWhenRepeatIsTwo {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(2)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsThree {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(3)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  public static class PassingTestShouldPassThreeTimesWhenRepeatIsThree {
+    protected static int count = 0;
+    
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(3)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithErrorJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithErrorJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithErrorJUnitTest.java
new file mode 100755
index 0000000..ce473e8
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithErrorJUnitTest.java
@@ -0,0 +1,247 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.Retry;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
+
+/**
+ * Unit tests for Retry JUnit Rule involving global scope (ie Rule affects all 
+ * tests in the test case) with failures due to an Exception.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class RetryRuleGlobalWithErrorJUnitTest {
+  
+  @Test
+  public void zeroIsIllegal() {
+    Result result = runTest(ZeroIsIllegal.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(IllegalArgumentException.class)));
+    assertThat(failure.getException().getMessage(), containsString("Retry count must be greater than zero"));
+    assertThat(ZeroIsIllegal.count, is(0));
+  }
+  
+  @Test
+  public void failsWithOne() {
+    Result result = runTest(FailsWithOne.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsWithOne.message));
+    assertThat(FailsWithOne.count, is(1));
+  }
+  
+  @Test
+  public void passesWithOne() {
+    Result result = runTest(PassesWithOne.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void passesWithUnused() {
+    Result result = runTest(PassesWhenUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = runTest(FailsOnSecondAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnSecondAttempt.message));
+    assertThat(FailsOnSecondAttempt.count, is(2));
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = runTest(PassesOnSecondAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnSecondAttempt.count, is(2));
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = runTest(FailsOnThirdAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnThirdAttempt.message));
+    assertThat(FailsOnThirdAttempt.count, is(3));
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = runTest(PassesOnThirdAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnThirdAttempt.count, is(3));
+  }
+  
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class ZeroIsIllegal {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(0);
+
+    @Test
+    public void zeroIsIllegal() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsWithOne {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void failsWithOne() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+  
+  public static class PassesWithOne {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void passesWithOne() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class PassesWhenUnused {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    public void passesWithUnused() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+  
+  public static class PassesOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+  
+  public static class FailsOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  public static class PassesOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    public void failsOnThirdAttempt() {
+      count++;
+      if (count < 3) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithExceptionJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithExceptionJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithExceptionJUnitTest.java
new file mode 100755
index 0000000..b67880c
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleGlobalWithExceptionJUnitTest.java
@@ -0,0 +1,253 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.Retry;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
+
+/**
+ * Unit tests for Retry JUnit Rule involving global scope (ie Rule affects all 
+ * tests in the test case) with failures due to an Exception.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class RetryRuleGlobalWithExceptionJUnitTest {
+  
+  @Test
+  public void zeroIsIllegal() {
+    Result result = runTest(ZeroIsIllegal.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(IllegalArgumentException.class)));
+    assertThat(failure.getException().getMessage(), containsString("Retry count must be greater than zero"));
+    assertThat(ZeroIsIllegal.count, is(0));
+  }
+  
+  @Test
+  public void failsWithOne() {
+    Result result = runTest(FailsWithOne.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsWithOne.message));
+    assertThat(FailsWithOne.count, is(1));
+  }
+  
+  @Test
+  public void passesWithOne() {
+    Result result = runTest(PassesWithOne.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void passesWithUnused() {
+    Result result = runTest(PassesWhenUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = runTest(FailsOnSecondAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnSecondAttempt.message));
+    assertThat(FailsOnSecondAttempt.count, is(2));
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = runTest(PassesOnSecondAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnSecondAttempt.count, is(2));
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = runTest(FailsOnThirdAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnThirdAttempt.message));
+    assertThat(FailsOnThirdAttempt.count, is(3));
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = runTest(PassesOnThirdAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnThirdAttempt.count, is(3));
+  }
+  
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class CustomException extends Exception {
+    private static final long serialVersionUID = 1L;
+    public CustomException(final String message) {
+      super(message);
+    }
+  }
+  
+  public static class ZeroIsIllegal {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(0);
+
+    @Test
+    public void zeroIsIllegal() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsWithOne {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void failsWithOne() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+  
+  public static class PassesWithOne {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void passesWithOne() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class PassesWhenUnused {
+    protected static int count;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    public void passesWithUnused() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+  
+  public static class PassesOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+  
+  public static class FailsOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  public static class PassesOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    public void failsOnThirdAttempt() throws Exception {
+      count++;
+      if (count < 3) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithErrorJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithErrorJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithErrorJUnitTest.java
new file mode 100755
index 0000000..b06575c
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithErrorJUnitTest.java
@@ -0,0 +1,206 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.Retry;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
+
+/**
+ * Unit tests for Retry JUnit Rule involving local scope (ie Rule affects 
+ * test methods annotated with @Retry) with failures due to an Error.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class RetryRuleLocalWithErrorJUnitTest {
+
+  @Test
+  public void failsUnused() {
+    Result result = runTest(FailsUnused.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsUnused.message));
+    assertThat(FailsUnused.count, is(1));
+  }
+  
+  @Test
+  public void passesUnused() {
+    Result result = runTest(PassesUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesUnused.count, is(1));
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = runTest(FailsOnSecondAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnSecondAttempt.message));
+    assertThat(FailsOnSecondAttempt.count, is(2));
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = runTest(PassesOnSecondAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnSecondAttempt.count, is(2));
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = runTest(FailsOnThirdAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnThirdAttempt.message));
+    assertThat(FailsOnThirdAttempt.count, is(3));
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = runTest(PassesOnThirdAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnThirdAttempt.count, is(3));
+  }
+  
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class FailsUnused {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void failsUnused() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+  
+  public static class PassesUnused {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void passesUnused() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+  
+  public static class PassesOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+  
+  public static class FailsOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() {
+      count++;
+
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  public static class PassesOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() {
+      count++;
+
+      if (count < 3) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/d0c03307/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithExceptionJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithExceptionJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithExceptionJUnitTest.java
new file mode 100755
index 0000000..4cff4bb
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/RetryRuleLocalWithExceptionJUnitTest.java
@@ -0,0 +1,221 @@
+package com.gemstone.gemfire.test.junit.rules.tests;
+
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.Retry;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.FailsOnSecondAttempt;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.FailsOnThirdAttempt;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.FailsUnused;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.PassesOnSecondAttempt;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.PassesOnThirdAttempt;
+import com.gemstone.gemfire.test.junit.rules.tests.RetryRuleLocalWithErrorJUnitTest.PassesUnused;
+
+/**
+ * Unit tests for Retry JUnit Rule involving local scope (ie Rule affects 
+ * test methods annotated with @Retry) with failures due to an Exception.
+ * 
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class RetryRuleLocalWithExceptionJUnitTest {
+
+  @Test
+  public void failsUnused() {
+    Result result = runTest(FailsUnused.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals("Failures: " + failures, 1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsUnused.message));
+    assertThat(FailsUnused.count, is(1));
+  }
+  
+  @Test
+  public void passesUnused() {
+    Result result = runTest(PassesUnused.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesUnused.count, is(1));
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = runTest(FailsOnSecondAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnSecondAttempt.message));
+    assertThat(FailsOnSecondAttempt.count, is(2));
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = runTest(PassesOnSecondAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnSecondAttempt.count, is(2));
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = runTest(FailsOnThirdAttempt.class);
+    
+    assertFalse(result.wasSuccessful());
+    
+    List<Failure> failures = result.getFailures();
+    assertEquals(1, failures.size());
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException(), is(instanceOf(CustomException.class)));
+    assertThat(failure.getException().getMessage(), containsString(FailsOnThirdAttempt.message));
+    assertThat(FailsOnThirdAttempt.count, is(3));
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = runTest(PassesOnThirdAttempt.class);
+    
+    assertTrue(result.wasSuccessful());
+    assertThat(PassesOnThirdAttempt.count, is(3));
+  }
+  
+  private static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+  
+  public static class CustomException extends Exception {
+    private static final long serialVersionUID = 1L;
+    public CustomException(final String message) {
+      super(message);
+    }
+  }
+  
+  public static class FailsUnused {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void failsUnused() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+  
+  public static class PassesUnused {
+    protected static int count;
+    protected static String message;
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void passesUnused() throws Exception {
+      count++;
+    }
+  }
+  
+  public static class FailsOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+  
+  public static class PassesOnSecondAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void failsOnSecondAttempt() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+  
+  public static class FailsOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() throws Exception {
+      count++;
+
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  public static class PassesOnThirdAttempt {
+    protected static int count;
+    protected static String message;
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void failsOnThirdAttempt() throws Exception {
+      count++;
+
+      if (count < 3) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+}


[9/9] incubator-geode git commit: Conditional ignore rule

Posted by kl...@apache.org.
Conditional ignore rule


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/c396e94a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/c396e94a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/c396e94a

Branch: refs/heads/feature/GEODE-217
Commit: c396e94a1a12e27ffc49941c87560779235bf86e
Parents: d0c0330
Author: Kirk Lund <kl...@pivotal.io>
Authored: Fri Aug 21 13:28:39 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Fri Aug 21 13:28:39 2015 -0700

----------------------------------------------------------------------
 .../gemfire/test/junit/ConditionalIgnore.java   |  33 ++++++
 .../gemfire/test/junit/IgnoreCondition.java     |  16 +++
 .../gemfire/test/junit/IgnoreUntil.java         |  33 ++++++
 .../test/junit/rules/ConditionalIgnoreRule.java | 106 +++++++++++++++++++
 .../test/junit/rules/IgnoreUntilRule.java       | 106 +++++++++++++++++++
 .../junit/support/DefaultIgnoreCondition.java   |  41 +++++++
 .../IgnoreConditionEvaluationException.java     |  27 +++++
 7 files changed, 362 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
new file mode 100755
index 0000000..0a3f63d
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
@@ -0,0 +1,33 @@
+package com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition;
+
+/**
+ * The ConditionalIgnore class is a Java Annotation used to annotated a test suite class test case method in order to
+ * conditionally ignore the test case for a fixed amount of time, or based on a predetermined condition provided by
+ * the IgnoreCondition interface.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ * @see com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface ConditionalIgnore {
+
+  Class<? extends IgnoreCondition> condition() default DefaultIgnoreCondition.class;
+
+  String until() default "1970-01-01";
+
+  String value() default "";
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
new file mode 100755
index 0000000..689d0b7
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
@@ -0,0 +1,16 @@
+package com.gemstone.gemfire.test.junit;
+
+import org.junit.runner.Description;
+
+/**
+ * The IgnoreCondition class...
+ *
+ * @author John Blum
+ * @see org.junit.runner.Description
+ */
+@SuppressWarnings("unused")
+public interface IgnoreCondition {
+
+  boolean evaluate(Description testCaseDescription);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
new file mode 100755
index 0000000..66ab929
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
@@ -0,0 +1,33 @@
+package com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition;
+
+/**
+ * The IgnoreUntil class is a Java Annotation used to annotated a test suite class test case method in order to
+ * conditionally ignore the test case for a fixed amount of time, or based on a predetermined condition provided by
+ * the IgnoreCondition interface.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ * @see com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface IgnoreUntil {
+
+  Class<? extends IgnoreCondition> condition() default DefaultIgnoreCondition.class;
+
+  String deadline() default "1970-01-01";
+
+  String value() default "";
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
new file mode 100755
index 0000000..9d73e32
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
@@ -0,0 +1,106 @@
+package com.gemstone.gemfire.test.junit.rules;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.ConditionalIgnore;
+import com.gemstone.gemfire.test.junit.IgnoreCondition;
+import com.gemstone.gemfire.test.junit.support.IgnoreConditionEvaluationException;
+
+/**
+ * The ConditionalIgnoreRule class...
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ * @see com.gemstone.gemfire.test.junit.ConditionalIgnore
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ */
+@SuppressWarnings("unused")
+public class ConditionalIgnoreRule implements TestRule {
+
+  protected static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
+  protected static final String DEFAULT_MESSAGE = "Ignoring test case (%1$s) of test class (%2$s)!";
+
+  protected static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN);
+
+  @Override
+  public Statement apply(final Statement base, final Description description) {
+    return new Statement() {
+      @Override public void evaluate() throws Throwable {
+        ConditionalIgnoreRule.this.evaluate(base, description);
+      }
+    };
+  }
+
+  public final void evaluate(Statement statement, Description description) throws Throwable {
+    throwOnIgnoreTest(statement, description).evaluate();
+  }
+
+  protected Statement throwOnIgnoreTest(Statement statement, Description description) {
+    if (isTest(description)) {
+      boolean ignoreTest = false;
+      String message = "";
+
+      ConditionalIgnore testCaseAnnotation = description.getAnnotation(ConditionalIgnore.class);
+
+      if (testCaseAnnotation != null) {
+        ignoreTest = evaluate(testCaseAnnotation, description);
+        message = testCaseAnnotation.value();
+      }
+      else if (description.getTestClass().isAnnotationPresent(ConditionalIgnore.class)) {
+        ConditionalIgnore testClassAnnotation = description.getTestClass().getAnnotation(ConditionalIgnore.class);
+
+        ignoreTest = evaluate(testClassAnnotation, description);
+        message = testClassAnnotation.value();
+      }
+
+      if (ignoreTest) {
+        throw new AssumptionViolatedException(format(message, description));
+      }
+    }
+
+    return statement;
+  }
+
+  protected boolean isTest(final Description description) {
+    return (description.isSuite() || description.isTest());
+  }
+
+  protected String format(String message, Description description) {
+    message = (!message.isEmpty() ? message : DEFAULT_MESSAGE);
+    return String.format(message, description.getMethodName(), description.getClassName());
+  }
+
+  protected boolean evaluate(ConditionalIgnore conditionalIgnoreAnnotation, Description description) {
+    return (evaluateCondition(conditionalIgnoreAnnotation.condition(), description)
+      || evaluateUntil(conditionalIgnoreAnnotation.until()));
+  }
+
+  protected boolean evaluateCondition(Class<? extends IgnoreCondition> ignoreConditionType, Description description) {
+    try {
+      return ignoreConditionType.newInstance().evaluate(description);
+    }
+    catch (Exception e) {
+      throw new IgnoreConditionEvaluationException(String.format("failed to evaluate IgnoreCondition: %1$s",
+        ignoreConditionType.getName()), e);
+    }
+  }
+
+  protected boolean evaluateUntil(String timestamp) {
+    try {
+      return DATE_FORMAT.parse(timestamp).after(Calendar.getInstance().getTime());
+    }
+    catch (ParseException e) {
+      return false;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
new file mode 100755
index 0000000..fd35ad7
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
@@ -0,0 +1,106 @@
+package com.gemstone.gemfire.test.junit.rules;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.IgnoreUntil;
+import com.gemstone.gemfire.test.junit.IgnoreCondition;
+import com.gemstone.gemfire.test.junit.support.IgnoreConditionEvaluationException;
+
+/**
+ * The IgnoreUntilRule class...
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ * @see com.gemstone.gemfire.test.junit.IgnoreUntil
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ */
+@SuppressWarnings("unused")
+public class IgnoreUntilRule implements TestRule {
+
+  protected static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
+  protected static final String DEFAULT_MESSAGE = "Ignoring test case (%1$s) of test class (%2$s)!";
+
+  protected static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN);
+
+  @Override
+  public Statement apply(final Statement base, final Description description) {
+    return new Statement() {
+      @Override public void evaluate() throws Throwable {
+        IgnoreUntilRule.this.evaluate(base, description);
+      }
+    };
+  }
+
+  public final void evaluate(Statement statement, Description description) throws Throwable {
+    throwOnIgnoreTest(statement, description).evaluate();
+  }
+
+  protected Statement throwOnIgnoreTest(Statement statement, Description description) {
+    if (isTest(description)) {
+      boolean ignoreTest = false;
+      String message = "";
+
+      IgnoreUntil testCaseAnnotation = description.getAnnotation(IgnoreUntil.class);
+
+      if (testCaseAnnotation != null) {
+        ignoreTest = evaluate(testCaseAnnotation, description);
+        message = testCaseAnnotation.value();
+      }
+      else if (description.getTestClass().isAnnotationPresent(IgnoreUntil.class)) {
+        IgnoreUntil testClassAnnotation = description.getTestClass().getAnnotation(IgnoreUntil.class);
+
+        ignoreTest = evaluate(testClassAnnotation, description);
+        message = testClassAnnotation.value();
+      }
+
+      if (ignoreTest) {
+        throw new AssumptionViolatedException(format(message, description));
+      }
+    }
+
+    return statement;
+  }
+
+  protected boolean isTest(final Description description) {
+    return (description.isSuite() || description.isTest());
+  }
+
+  protected String format(String message, Description description) {
+    message = (!message.isEmpty() ? message : DEFAULT_MESSAGE);
+    return String.format(message, description.getMethodName(), description.getClassName());
+  }
+
+  protected boolean evaluate(IgnoreUntil conditionalIgnoreAnnotation, Description description) {
+    return (evaluateCondition(conditionalIgnoreAnnotation.condition(), description)
+      || evaluateUntil(conditionalIgnoreAnnotation.deadline()));
+  }
+
+  protected boolean evaluateCondition(Class<? extends IgnoreCondition> ignoreConditionType, Description description) {
+    try {
+      return ignoreConditionType.newInstance().evaluate(description);
+    }
+    catch (Exception e) {
+      throw new IgnoreConditionEvaluationException(String.format("failed to evaluate IgnoreCondition: %1$s",
+        ignoreConditionType.getName()), e);
+    }
+  }
+
+  protected boolean evaluateUntil(String timestamp) {
+    try {
+      return DATE_FORMAT.parse(timestamp).after(Calendar.getInstance().getTime());
+    }
+    catch (ParseException e) {
+      return false;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
new file mode 100755
index 0000000..24cd98a
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
@@ -0,0 +1,41 @@
+package com.gemstone.gemfire.test.junit.support;
+
+import org.junit.runner.Description;
+import com.gemstone.gemfire.test.junit.IgnoreCondition;
+
+/**
+ * The DefaultIgnoreCondition class...
+ *
+ * @author John Blum
+ * @see org.junit.runner.Description
+ * @see com.gemstone.gemfire.test.junit.ConditionalIgnore
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ */
+@SuppressWarnings("unused")
+public class DefaultIgnoreCondition implements IgnoreCondition {
+
+  public static final boolean DEFAULT_IGNORE = false;
+
+  public static final DefaultIgnoreCondition DO_NOT_IGNORE = new DefaultIgnoreCondition(false);
+  public static final DefaultIgnoreCondition IGNORE = new DefaultIgnoreCondition(true);
+
+  private final boolean ignore;
+
+  public DefaultIgnoreCondition() {
+    this(DEFAULT_IGNORE);
+  }
+
+  public DefaultIgnoreCondition(final boolean ignore) {
+    this.ignore = ignore;
+  }
+
+  public boolean isIgnore() {
+    return ignore;
+  }
+
+  @Override
+  public boolean evaluate(final Description testCaseDescription) {
+    return isIgnore();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/c396e94a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
new file mode 100755
index 0000000..50e1bc7
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
@@ -0,0 +1,27 @@
+package com.gemstone.gemfire.test.junit.support;
+
+/**
+ * The IgnoreConditionEvaluationException class...
+ *
+ * @author John Blum
+ * @see java.lang.RuntimeException
+ */
+@SuppressWarnings("unused")
+public class IgnoreConditionEvaluationException extends RuntimeException {
+
+  public IgnoreConditionEvaluationException() {
+  }
+
+  public IgnoreConditionEvaluationException(final String message) {
+    super(message);
+  }
+
+  public IgnoreConditionEvaluationException(final Throwable cause) {
+    super(cause);
+  }
+
+  public IgnoreConditionEvaluationException(final String message, final Throwable cause) {
+    super(message, cause);
+  }
+
+}


[4/9] incubator-geode git commit: Dunit changes for JUnit 4 syntax. Refactoring to modernize API.

Posted by kl...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
new file mode 100755
index 0000000..a1ef782
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ExpectedExceptionString.java
@@ -0,0 +1,142 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Invoke.invokeInEveryVM;
+
+import java.io.Serializable;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.logging.log4j.Logger;
+
+import com.gemstone.gemfire.internal.logging.LogService;
+
+/**
+ * An expected exception string which is added or removed in the log to 
+ * suppress it during greplogs (grep for error strings).
+ * 
+ * Extracted from DistributedTestCase. Renamed from ExpectedException to 
+ * prevent conflict with the JUnit rule. Note that the implementation
+ * is still writing <code><ExpectedException ...></code> statements to the 
+ * log for the <code>batterytest.greplogs.LogConsumer</code>.
+ * 
+ * @author Mitch Thomas
+ * @since 5.7bugfix
+ * @see batterytest.greplogs.LogConsumer
+ */
+public class ExpectedExceptionString implements Serializable {
+  private static final long serialVersionUID = 1L;
+  private static final Logger logger = LogService.getLogger();
+  
+  // Note: if you change these prefixes and suffix then you must also change batterytest.greplogs.LogConsumer to match
+  private static final String LOG_MESSAGE_PREFIX_ADD = "<ExpectedException action=add>";
+  private static final String LOG_MESSAGE_PREFIX_REMOVE = "<ExpectedException action=remove>";
+  private static final String LOG_MESSAGE_SUFFIX = "</ExpectedException>";
+
+  private final String exceptionString;
+
+  private final transient VM vm;
+
+  // TODO: prevent memory leak here
+  private static final Queue<ExpectedExceptionString> expectedExceptionStrings = new ConcurrentLinkedQueue<ExpectedExceptionString>();
+
+  public ExpectedExceptionString(final String exceptionString) {
+    this(exceptionString, null);
+  }
+  
+  public ExpectedExceptionString(final String exceptionString, final VM vm) {
+    this.exceptionString = exceptionString;
+    this.vm = vm;
+  }
+
+  public String getAddMessage() {
+    return LOG_MESSAGE_PREFIX_ADD + this.exceptionString + LOG_MESSAGE_SUFFIX;
+  }
+
+  public String getRemoveMessage() {
+    return LOG_MESSAGE_PREFIX_REMOVE + this.exceptionString + LOG_MESSAGE_SUFFIX;
+  }
+
+  public void remove() {
+    final SerializableRunnable removeRunnable = newRemoveSerializableRunnable(getRemoveMessage());
+    
+    if (this.vm != null) {
+      this.vm.invoke(removeRunnable);
+    } else {
+      invokeInEveryVM(removeRunnable);
+    }
+    
+    logger.info(getRemoveMessage());
+  }
+
+  /**
+   * Log in all VMs the expected exception string to prevent grep logs from
+   * complaining. The expected string is used by the GrepLogs utility and so 
+   * can contain regular expression characters.
+   * 
+   * If you do not remove the expected exception, it will be removed at the
+   * end of your test case automatically.
+   * 
+   * @since 5.7bugfix
+   * @param exception the exception string to expect
+   * @return an instance that a test can use for removal
+   */
+  public static ExpectedExceptionString addExpectedExceptionString(final String exception) {
+    return addExpectedExceptionString(exception, null);
+  }
+
+  /**
+   * Log in all VMs, the
+   * expected exception string to prevent grep logs from complaining. The
+   * expected string is used by the GrepLogs utility and so can contain
+   * regular expression characters.
+   * 
+   * @since 5.7bugfix
+   * @param exceptionString the exception string to expect
+   * @param vm the VM on which to log the expected exception or null for all VMs
+   * @return an instance that a test can use for removal
+   */
+  public static ExpectedExceptionString addExpectedExceptionString(final String exceptionString, final VM vm) {
+    final ExpectedExceptionString expectedOutput;
+    if (vm != null) {
+      expectedOutput = new ExpectedExceptionString(exceptionString, vm);
+    } else {
+      expectedOutput = new ExpectedExceptionString(exceptionString);
+    }
+    
+    final String addMessage = expectedOutput.getAddMessage();
+    
+    final SerializableRunnable addRunnable = newAddSerializableRunnable(addMessage);
+    
+    if (vm != null) {
+      vm.invoke(addRunnable);
+    } else {
+      invokeInEveryVM(addRunnable);
+    }
+    
+    logger.info(addMessage);
+    expectedExceptionStrings.add(expectedOutput);
+    return expectedOutput;
+  }
+  
+  static ExpectedExceptionString poll() {
+    return expectedExceptionStrings.poll();
+  }
+  
+  @SuppressWarnings("serial")
+  private static SerializableRunnable newAddSerializableRunnable(final String addMessage) {
+    return new SerializableRunnable("addExpectedExceptionString") {
+      public void run() {
+        logger.info(addMessage);
+      }
+    };
+  }
+  
+  @SuppressWarnings("serial")
+  private static SerializableRunnable newRemoveSerializableRunnable(final String removeMessage) {
+    return new SerializableRunnable("removeExpectedExceptionString") {
+      public void run() {
+        logger.info(removeMessage);
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
new file mode 100644
index 0000000..6d69436
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Host.java
@@ -0,0 +1,201 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * <P>This class represents a host on which a remote method may be
+ * invoked.  It provides access to the VMs and GemFire systems that
+ * run on that host.</P>
+ *
+ * <P>Additionally, it provides access to the Java RMI registry that
+ * runs on the host.  By default, an RMI registry is only started on
+ * the host on which Hydra's Master VM runs.  RMI registries may be
+ * started on other hosts via additional Hydra configuration.</P>
+ *
+ * @author David Whitlock
+ *
+ */
+public abstract class Host implements java.io.Serializable {
+
+  /** The available hosts */
+  protected static List hosts = new ArrayList();
+
+  private static VM locator;
+
+  /** Indicates an unstarted RMI registry */
+  protected static int NO_REGISTRY = -1;
+
+  ////////////////////  Instance Fields  ////////////////////
+
+  /** The name of this host machine */
+  private String hostName;
+
+  /** The VMs that run on this host */
+  private List vms;
+
+  /** The GemFire systems that are available on this host */
+  private List systems;
+  
+  /** Key is system name, value is GemFireSystem instance */
+  private HashMap systemNames;
+  
+  ////////////////////  Static Methods  /////////////////////
+
+  /**
+   * Returns the number of known hosts
+   */
+  public static int getHostCount() {
+    return hosts.size();
+  }
+
+  /**
+   * Makes note of a new <code>Host</code>
+   */
+  protected static void addHost(Host host) {
+    hosts.add(host);
+  }
+
+  /**
+   * Returns a given host
+   *
+   * @param n
+   *        A zero-based identifier of the host
+   *
+   * @throws IllegalArgumentException
+   *         <code>n</code> is more than the number of hosts
+   */
+  public static Host getHost(int n) {
+    int size = hosts.size();
+    if (n >= size) {
+      String s = "Cannot request host " + n + ".  There are only " +
+        size + " hosts.";
+      throw new IllegalArgumentException(s);
+
+    } else {
+      return (Host) hosts.get(n);
+    }
+  }
+
+  /////////////////////  Constructors  //////////////////////
+
+  /**
+   * Creates a new <code>Host</code> with the given name
+   */
+  protected Host(String hostName) {
+    if (hostName == null) {
+      String s = "Cannot create a Host with a null name";
+      throw new NullPointerException(s);
+    }
+
+    this.hostName = hostName;
+    this.vms = new ArrayList();
+    this.systems = new ArrayList();
+    this.systemNames = new HashMap();
+  }
+
+  ////////////////////  Instance Methods  ////////////////////
+
+  /**
+   * Returns the machine name of this host
+   */
+  public String getHostName() {
+    return this.hostName;
+  }
+
+  /**
+   * Returns the number of VMs that run on this host
+   */
+  public int getVMCount() {
+    return this.vms.size();
+  }
+
+  /**
+   * Returns a VM that runs on this host
+   *
+   * @param n
+   *        A zero-based identifier of the VM
+   *
+   * @throws IllegalArgumentException
+   *         <code>n</code> is more than the number of VMs
+   */
+  public VM getVM(int n) {
+    int size = vms.size();
+    if (n >= size) {
+      String s = "Cannot request VM " + n + ".  There are only " +
+        size + " VMs on " + this;
+      throw new IllegalArgumentException(s);
+
+    } else {
+      return (VM) vms.get(n);
+    }
+  }
+
+  /**
+   * Adds a VM to this <code>Host</code> with the given process id and client record.
+   */
+  protected void addVM(int pid, RemoteDUnitVMIF client) {
+    VM vm = new VM(this, pid, client);
+    this.vms.add(vm);
+  }
+
+  public static VM getLocator() {
+    return locator;
+  }
+  
+  private static void setLocator(VM l) {
+    locator = l;
+  }
+  
+  protected void addLocator(int pid, RemoteDUnitVMIF client) {
+    setLocator(new VM(this, pid, client));
+  }
+
+  /**
+   * Returns the number of GemFire systems that run on this host
+   */
+  public int getSystemCount() {
+    return this.systems.size();
+  }
+
+  ////////////////////  Utility Methods  ////////////////////
+
+  public String toString() {
+    StringBuffer sb = new StringBuffer("Host ");
+    sb.append(this.getHostName());
+    sb.append(" with ");
+    sb.append(getVMCount());
+    sb.append(" VMs");
+    return sb.toString();
+  }
+
+  /**
+   * Two <code>Host</code>s are considered equal if they have the same
+   * name.
+   */
+  public boolean equals(Object o) {
+    if (o instanceof Host) {
+      return ((Host) o).getHostName().equals(this.getHostName());
+
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * A <code>Host</code>'s hash code is based on the hash code of its
+   * name. 
+   */
+  public int hashCode() {
+    return this.getHostName().hashCode();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
new file mode 100755
index 0000000..bd9eaf6
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
@@ -0,0 +1,146 @@
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A set of remote invocation methods useful for writing tests. 
+ * <pr/>
+ * These methods can be used directly:
+ * <code>Invoke.invokeInEveryVM(...)</code>, however, they read better if they
+ * are referenced through static import:
+ * 
+ * <pre>
+ * import static com.gemstone.gemfire.test.dunit.Invoke.*;
+ *    ...
+ *    invokeInEveryVM(...);
+ * </pre>
+ * <pr/>
+ * Extracted from DistributedTestCase
+ * 
+ * @see VM
+ * @see SerializableCallable
+ * @see SerializableRunnable
+ * @see RepeatableRunnable
+ */
+public class Invoke {
+
+  protected Invoke() {
+  }
+  
+  /**
+   * Invokes a <code>SerializableRunnable</code> in every VM that DUnit knows about.
+   *
+   * @see VM#invoke(Runnable)
+   */
+  public static void invokeInEveryVM(final SerializableRunnable work) {
+    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);
+        vm.invoke(work);
+      }
+    }
+  }
+
+  public static void invokeInLocator(final SerializableRunnable work) {
+    Host.getLocator().invoke(work);
+  }
+  
+  /**
+   * Invokes a <code>SerializableCallable</code> in every VM that DUnit knows about.
+   *
+   * @return a Map of results, where the key is the VM and the value is the result for that VM
+   * @see VM#invoke(java.util.concurrent.Callable)
+   */
+  public static Map<VM, Object> invokeInEveryVM(final SerializableCallable<?> work) {
+    final Map<VM, Object> results = new HashMap<VM, Object>();
+    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);
+        results.put(vm, vm.invoke(work));
+      }
+    }
+    return results;
+  }
+
+  /**
+   * Invokes a method in every remote VM that DUnit knows about.
+   *
+   * @see VM#invoke(Class, String)
+   */
+  public static void invokeInEveryVM(final Class<?> theClass, final String methodName) {
+    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);
+        vm.invoke(theClass, methodName);
+      }
+    }
+  }
+
+  /**
+   * Invokes a method in every remote VM that DUnit knows about.
+   *
+   * @see VM#invoke(Class, String)
+   */
+  public static void invokeInEveryVM(final Class<?> theClass, final String methodName, final Object[] methodArgs) {
+    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);
+        vm.invoke(theClass, methodName, methodArgs);
+      }
+    }
+  }
+  
+  public static void invokeRepeatingIfNecessary(final VM vm, final RepeatableRunnable task) {
+    vm.invokeRepeatingIfNecessary(task, 0);
+  }
+  
+  /**
+   * For ACK scopes, no repeat should be necessary.
+   * 
+   * @param vm
+   * @param task
+   * @param repeatTimeoutMs the number of milliseconds to try repeating validation code in the
+   * event that AssertionFailedError is thrown.  
+   */
+  public static void invokeRepeatingIfNecessary(final VM vm, final RepeatableRunnable task, final long repeatTimeoutMs) {
+    vm.invokeRepeatingIfNecessary(task, repeatTimeoutMs);
+  }
+  
+  /**
+   * Invokes a <code>SerializableRunnable</code> in every VM that
+   * DUnit knows about.  If work.run() throws an assertion failure, 
+   * its execution is repeated, until no assertion failure occurs or
+   * repeatTimeout milliseconds have passed.
+   *
+   * @see VM#invoke(Runnable)
+   */
+  public static void invokeInEveryVMRepeatingIfNecessary(final RepeatableRunnable work) {
+    invokeInEveryVMRepeatingIfNecessary(work, 0);
+  }
+
+  public static void invokeInEveryVMRepeatingIfNecessary(final RepeatableRunnable work, final long repeatTimeoutMs) {
+    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);
+        vm.invokeRepeatingIfNecessary(work, repeatTimeoutMs);
+      }
+    }
+  }
+  
+  /** Return the total number of VMs on all hosts */
+  public static int getVMCount() {
+    int count = 0;
+    for (int h = 0; h < Host.getHostCount(); h++) {
+      Host host = Host.getHost(h);
+      count += host.getVMCount();
+    }
+    return count;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
new file mode 100755
index 0000000..446b4bf
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
@@ -0,0 +1,70 @@
+package com.gemstone.gemfire.test.dunit;
+
+import java.util.Random;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public class Jitter {
+
+  /**
+   * If true, we randomize the amount of time we wait
+   */
+  private static final boolean USE_JITTER = true;
+  
+  private static final Random jitter = new Random();
+  
+  protected Jitter() {
+  }
+  
+  /**
+   * Returns an adjusted interval from <code>minimum()</code to 
+   * <code>intervalMillis</code> milliseconds. If jittering is disabled then 
+   * the value returned will be equal to intervalMillis.
+   * 
+   * @param intervalMillis
+   * @return adjust milliseconds to use as interval for WaitCriteria polling
+   */
+  static long jitterInterval(final long intervalMillis) {
+    if (USE_JITTER) {
+      return adjustIntervalIfJitterIsEnabled(intervalMillis);
+    } else {
+      return intervalMillis;
+    }
+  }
+  
+  static int minimum() {
+    return 10;
+  }
+  
+  static int maximum() {
+    return 5000;
+  }
+  
+  /**
+   * If jittering is enabled then returns a jittered interval up to a maximum
+   * of <code>intervalMillis</code> milliseconds, inclusive.
+   * 
+   * If jittering is disabled then returns <code>intervalMillis</code>.
+   * 
+   * The result is bounded by 50 ms as a minimum and 5000 ms as a maximum.
+   * 
+   * @param ms total amount of time to wait
+   * @return randomized interval we should wait
+   */
+  private static int adjustIntervalIfJitterIsEnabled(final long intervalMillis) {
+    final int minLegal = minimum();
+    final int maxLegal = maximum();
+    
+    if (intervalMillis <= minLegal) {
+      return (int)intervalMillis; // Don't ever jitter anything below this.
+    }
+
+    int maxValue = maxLegal;
+    if (intervalMillis < maxLegal) {
+      maxValue = (int)intervalMillis;
+    }
+
+    return minLegal + jitter.nextInt(maxValue - minLegal + 1);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
new file mode 100644
index 0000000..d08ac25
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RMIException.java
@@ -0,0 +1,161 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import com.gemstone.gemfire.GemFireException;
+
+/**
+ * This exception is thrown when an exception occurs during a remote
+ * method invocation.  This {@link RuntimeException} wraps the actual
+ * exception.  It allows distributed unit tests to verify that an
+ * exception was thrown in a different VM.
+ *
+ * <PRE>
+ *     VM vm0 = host0.getVM(0);
+ *     try {
+ *       vm.invoke(this.getClass(), "getUnknownObject");
+ *
+ *     } catch (RMIException ex) {
+ *       assertEquals(ex.getCause() instanceof ObjectException);
+ *     }
+ * </PRE>
+ *
+ * Note that special steps are taken so that the stack trace of the
+ * cause exception reflects the call stack on the remote machine.
+ * The stack trace of the exception returned by {@link #getCause()}
+ * may not be available.
+ *
+ * @see hydra.RemoteTestModuleIF
+ *
+ * @author David Whitlock
+ *
+ */
+public class RMIException extends GemFireException {
+
+  /** SHADOWED FIELD that holds the cause exception (as opposed to the
+   * HokeyException */
+  private Throwable cause;
+
+  /** The name of the method being invoked */
+  private String methodName;
+
+  /** The name of the class (or class of the object type) whose method
+   * was being invoked */
+  private String className;
+
+  /** The type of exception that was thrown in the remote VM */
+  private String exceptionClassName;
+
+  /** Stack trace for the exception that was thrown in the remote VM */
+  private String stackTrace;
+
+  /** The VM in which the method was executing */
+  private VM vm;
+
+  ////////////////////////  Constructors  ////////////////////////
+
+  /**
+   * Creates a new <code>RMIException</code> that was caused by a
+   * given <code>Throwable</code> while invoking a given method.
+   */
+  public RMIException(VM vm, String className, String methodName,
+                      Throwable cause) {
+    super("While invoking " + className + "." + methodName + " in " +
+          vm, cause);
+    this.cause = cause;
+    this.className = className;
+    this.methodName = methodName;
+    this.vm = vm;
+  }
+
+  /**
+   * Creates a new <code>RMIException</code> to indicate that an
+   * exception of a given type was thrown while invoking a given
+   * method. 
+   *
+   * @param vm
+   *        The VM in which the method was executing
+   * @param className
+   *        The name of the class whose method was being invoked
+   *        remotely 
+   * @param methodName
+   *        The name of the method that was being invoked remotely
+   * @param cause
+   *        The type of exception that was thrown in the remote VM
+   * @param stackTrace
+   *        The stack trace of the exception from the remote VM
+   */
+  public RMIException(VM vm, String className, String methodName, 
+                      Throwable cause, String stackTrace) {
+    super("While invoking " + className + "." + methodName + " in " +
+          vm, new HokeyException(cause, stackTrace));
+    this.vm = vm;
+    this.cause = cause;
+    this.className = className;
+    this.methodName = methodName;
+//    this.exceptionClassName = exceptionClassName; assignment has no effect
+    this.stackTrace = stackTrace;
+  }
+
+  /**
+   * Returns the class name of the exception that was thrown in a
+   * remote method invocation.
+   */
+  public String getExceptionClassName() {
+    return this.exceptionClassName;
+  }
+
+//   /**
+//    * Returns the stack trace for the exception that was thrown in a
+//    * remote method invocation.
+//    */
+//   public String getStackTrace() {
+//     return this.stackTrace;
+//   }
+
+  /**
+   * Returns the cause of this exception.  Note that this is not
+   * necessarily the exception that gets printed out with the stack
+   * trace.
+   */
+  public Throwable getCause() {
+    return this.cause;
+  }
+
+  /**
+   * Returns the VM in which the remote method was invoked
+   */
+  public VM getVM() {
+    return this.vm;
+  }
+
+  //////////////////////  Inner Classes  //////////////////////
+
+  /**
+   * A hokey exception class that makes it looks like we have a real
+   * cause exception.
+   */
+  private static class HokeyException extends Throwable {
+    private String stackTrace;
+    private String toString;
+
+    HokeyException(Throwable cause, String stackTrace) {
+      this.toString = cause.toString();
+      this.stackTrace = stackTrace;
+    }
+
+    public void printStackTrace(java.io.PrintWriter pw) {
+      pw.print(this.stackTrace);
+      pw.flush();
+    }
+
+    public String toString() {
+      return this.toString;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
new file mode 100644
index 0000000..412aeac
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RemoteDUnitVMIF.java
@@ -0,0 +1,18 @@
+package com.gemstone.gemfire.test.dunit;
+
+import hydra.MethExecutorResult;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+public interface RemoteDUnitVMIF extends Remote {
+
+  MethExecutorResult executeMethodOnObject(Object o, String methodName) throws RemoteException;
+
+  MethExecutorResult executeMethodOnObject(Object o, String methodName,
+      Object[] args) throws RemoteException;
+
+  MethExecutorResult executeMethodOnClass(String name, String methodName,
+      Object[] args) throws RemoteException;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
new file mode 100644
index 0000000..c8952bb
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/RepeatableRunnable.java
@@ -0,0 +1,13 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * A RepeatableRunnable is an object that implements a method that
+ * can be invoked repeatably without causing any side affects.
+ *
+ * @author  dmonnie
+ */
+public interface RepeatableRunnable {
+  
+  public void runRepeatingIfNecessary(long repeatTimeoutMs);
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
new file mode 100644
index 0000000..2c21284
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableCallable.java
@@ -0,0 +1,61 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.io.Serializable;
+import java.util.concurrent.Callable;
+
+/**
+ * This interface provides both {@link Serializable} and {@link
+ * Callable}.  It is often used in conjunction with {@link
+ * VM#invoke(Callable)}.
+ *
+ * <PRE>
+ * public void testRepilcatedRegionPut() {
+ *   final Host host = Host.getHost(0);
+ *   VM vm0 = host.getVM(0);
+ *   VM vm1 = host.getVM(1);
+ *   final String name = this.getUniqueName();
+ *   final Object value = new Integer(42);
+ *
+ *   SerializableCallable putMethod = new SerializableCallable("Replicated put") {
+ *       public Object call() throws Exception {
+ *         ...// get replicated test region //...
+ *         return region.put(name, value);
+ *       }
+ *      });
+ *   assertNull(vm0.invoke(putMethod));
+ *   assertEquals(value, vm1.invoke(putMethod));
+ *  }
+ * </PRE>
+ * 
+ * @author Mitch Thomas
+ */
+public abstract class SerializableCallable<T> implements Callable<T>, Serializable {
+  
+  private static final long serialVersionUID = -5914706166172952484L;
+  
+  private String name;
+
+  public SerializableCallable() {
+    this.name = null;
+  }
+
+  public SerializableCallable(String name) {
+    this.name = name;
+  }
+
+  public String toString() {
+    if (this.name != null) {
+      return "\"" + this.name + "\"";
+
+    } else {
+      return super.toString();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
new file mode 100644
index 0000000..28eabc3
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
@@ -0,0 +1,83 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import java.io.Serializable;
+
+/**
+ * This interface provides both {@link Serializable} and {@link
+ * Runnable}.  It is often used in conjunction with {@link
+ * VM#invoke(Runnable)}.
+ *
+ * <PRE>
+ * public void testRegionPutGet() {
+ *   final Host host = Host.getHost(0);
+ *   VM vm0 = host.getVM(0);
+ *   VM vm1 = host.getVM(1);
+ *   final String name = this.getUniqueName();
+ *   final Object value = new Integer(42);
+ *
+ *   vm0.invoke(new SerializableRunnable("Put value") {
+ *       public void run() {
+ *         ...// get the region //...
+ *         region.put(name, value);
+ *       }
+ *      });
+ *   vm1.invoke(new SerializableRunnable("Get value") {
+ *       public void run() {
+ *         ...// get the region //...
+ *         assertEquals(value, region.get(name));
+ *       }
+ *     });
+ *  }
+ * </PRE>
+ */
+public abstract class SerializableRunnable
+  implements Serializable, Runnable {
+
+  private static final long serialVersionUID = 7584289978241650456L;
+  
+  private String name;
+
+  public SerializableRunnable() {
+    this.name = null;
+  }
+
+  /**
+   * This constructor lets you do the following:
+   *
+   * <PRE>
+   * vm.invoke(new SerializableRunnable("Do some work") {
+   *     public void run() {
+   *       // ...
+   *     }
+   *   });
+   * </PRE>
+   */
+  public SerializableRunnable(String name) {
+    this.name = name;
+  }
+  
+  public void setName(String newName) {
+    this.name = newName;
+  }
+  
+  public String getName() {
+    return this.name;
+  }
+
+  public String toString() {
+    if (this.name != null) {
+      return "\"" + this.name + "\"";
+
+    } else {
+      return super.toString();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
new file mode 100755
index 0000000..b1e0d88
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/StoppableWaitCriterion.java
@@ -0,0 +1,12 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public interface StoppableWaitCriterion extends WaitCriterion {
+  /**
+   * If this method returns true then quit waiting even if we are not done.
+   * This allows a wait to fail early.
+   */
+  public boolean stopWaiting();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
new file mode 100755
index 0000000..acf43b9
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/ThreadDump.java
@@ -0,0 +1,157 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Jitter.*;
+import static org.junit.Assert.fail;
+
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.internal.OSProcess;
+import com.gemstone.gemfire.internal.logging.LocalLogWriter;
+import com.gemstone.gemfire.internal.logging.LogWriterImpl;
+
+/**
+ * A set of thread dump methods useful for writing tests. 
+ * <pr/>
+ * These methods can be used directly:
+ * <code>ThreadDump.dumpStack(...)</code>, however, they read better if they
+ * are referenced through static import:
+ * 
+ * <pre>
+ * import static com.gemstone.gemfire.test.dunit.ThreadDump.*;
+ *    ...
+ *    dumpStack(...);
+ * </pre>
+ * <pr/>
+ * Extracted from DistributedTestCase
+ * 
+ * @see VM
+ * @see Host
+ */
+@SuppressWarnings("serial")
+public class ThreadDump {
+
+  protected ThreadDump() {
+  }
+  
+  /** 
+   * Print a stack dump for this vm
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack() {
+    com.gemstone.gemfire.internal.OSProcess.printStacks(0, false);
+  }
+  
+  /** 
+   * Print a stack dump for the given vm
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack(final VM vm) {
+    vm.invoke(dumpStackSerializableRunnable());
+  }
+  
+  /** 
+   * Print stack dumps for all vms on the given host
+   * 
+   * @author bruce
+   * @since 5.0
+   */
+  public static void dumpStack(final Host host) {
+    for (int v=0; v < host.getVMCount(); v++) {
+      host.getVM(v).invoke(dumpStackSerializableRunnable());
+    }
+  }
+  
+  /** 
+   * Print stack dumps for all vms on all hosts
+   * 
+   * @author bruce
+   * @since 5.0
+  */
+  public static void dumpAllStacks() {
+    for (int h=0; h < Host.getHostCount(); h++) {
+      dumpStack(Host.getHost(h));
+    }
+  }
+  
+  public static void dumpStackTrace(final Thread thread, final StackTraceElement[] stack, final LogWriter logWriter) { // TODO: remove LogWriter
+    StringBuilder msg = new StringBuilder();
+    msg.append("Thread=<")
+      .append(thread)
+      .append("> stackDump:\n");
+    for (int i=0; i < stack.length; i++) {
+      msg.append("\t")
+        .append(stack[i])
+        .append("\n");
+    }
+    logWriter.info(msg.toString());
+  }
+
+  /**
+   * Dump all thread stacks
+   */
+  public static void dumpMyThreads(final LogWriter logWriter) { // TODO: remove LogWriter
+    OSProcess.printStacks(0, false);
+  }
+  
+  /**
+   * Wait for a thread to join
+   * @param t thread to wait on
+   * @param ms maximum time to wait
+   * @throws AssertionFailure if the thread does not terminate
+   */
+  static public void join(Thread t, long ms, LogWriter logger) {
+    final long tilt = System.currentTimeMillis() + ms;
+    final long incrementalWait = jitterInterval(ms);
+    final long start = System.currentTimeMillis();
+    for (;;) {
+      // I really do *not* understand why this check is necessary
+      // but it is, at least with JDK 1.6.  According to the source code
+      // and the javadocs, one would think that join() would exit immediately
+      // if the thread is dead.  However, I can tell you from experimentation
+      // that this is not the case. :-(  djp 2008-12-08
+      if (!t.isAlive()) {
+        break;
+      }
+      try {
+        t.join(incrementalWait);
+      } catch (InterruptedException e) {
+        fail("interrupted");
+      }
+      if (System.currentTimeMillis() >= tilt) {
+        break;
+      }
+    } // for
+    if (logger == null) {
+      logger = new LocalLogWriter(LogWriterImpl.INFO_LEVEL, System.out);
+    }
+    if (t.isAlive()) {
+      logger.info("HUNG THREAD");
+      dumpStackTrace(t, t.getStackTrace(), logger);
+      dumpMyThreads(logger);
+      t.interrupt(); // We're in trouble!
+      fail("Thread did not terminate after " + ms + " ms: " + t);
+//      getLogWriter().warning("Thread did not terminate" 
+//          /* , new Exception()*/
+//          );
+    }
+    long elapsedMs = (System.currentTimeMillis() - start);
+    if (elapsedMs > 0) {
+      String msg = "Thread " + t + " took " 
+        + elapsedMs
+        + " ms to exit.";
+      logger.info(msg);
+    }
+  }
+
+  private static SerializableRunnable dumpStackSerializableRunnable() {
+    return new SerializableRunnable() {
+      @Override
+      public void run() {
+        dumpStack();
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
new file mode 100644
index 0000000..f850184
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/VM.java
@@ -0,0 +1,1333 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.test.dunit;
+
+import hydra.MethExecutorResult;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.rmi.RemoteException;
+import java.util.concurrent.Callable;
+
+/**
+ * This class represents a Java Virtual Machine that runs on a host.
+ *
+ * @author David Whitlock
+ *
+ */
+public class VM implements java.io.Serializable {
+
+  /** The host on which this VM runs */
+  private Host host;
+
+  /** The process id of this VM */
+  private int pid;
+
+  /** The hydra client for this VM */
+  private RemoteDUnitVMIF client;
+
+  /** The state of this VM */
+  private volatile boolean available;
+
+  ////////////////////  Constructors  ////////////////////
+
+  /**
+   * Creates a new <code>VM</code> that runs on a given host with a
+   * given process id.
+   */
+  public VM(Host host, int pid, RemoteDUnitVMIF client) {
+    this.host = host;
+    this.pid = pid;
+    this.client = client;
+    this.available = true;
+  }
+
+  //////////////////////  Accessors  //////////////////////
+
+  /**
+   * Returns the host on which this <code>VM</code> runs
+   */
+  public Host getHost() {
+    return this.host;
+  }
+
+  /**
+   * Returns the process id of this <code>VM</code>
+   */
+  public int getPid() {
+    return this.pid;
+  }
+
+  /////////////////  Remote Method Invocation  ///////////////
+
+  /**
+   * Invokes a static zero-arg method  with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Class c, String methodName) {
+    return invoke(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Asynchronously invokes a static zero-arg method with an {@link
+   * Object} or <code>void</code> return type in this VM.  If the
+   * return type of the method is <code>void</code>, <code>null</code>
+   * is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   */
+  public AsyncInvocation invokeAsync(Class c, String methodName) {
+    return invokeAsync(c, methodName, null);
+  }
+
+  /**
+   * Invokes a static method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Class c, String methodName, Object[] args) {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, c.getName(), methodName,
+            new IllegalStateException(s));
+    }
+    MethExecutorResult result = null;
+    int retryCount = 120;
+    do {
+    try {
+      result = this.client.executeMethodOnClass(c.getName(), methodName, args);
+      break; // out of while loop
+    } catch( RemoteException e ) {
+      boolean isWindows = false;
+      String os = System.getProperty("os.name");
+      if (os != null) {
+        if (os.indexOf("Windows") != -1) {
+          isWindows = true;
+        }
+      }
+      if (isWindows && retryCount-- > 0) {
+        boolean interrupted = Thread.interrupted();
+        try { Thread.sleep(1000); } catch (InterruptedException ignore) {interrupted = true;}
+        finally {
+          if (interrupted) {
+            Thread.currentThread().interrupt();
+          }
+        }
+      } else {
+        throw new RMIException(this, c.getName(), methodName, e );
+      }
+    }
+    } while (true);
+
+    if (!result.exceptionOccurred()) {
+      return result.getResult();
+
+    } else {
+      Throwable thr = result.getException();
+      throw new RMIException(this, c.getName(), methodName, thr,
+                             result.getStackTrace()); 
+    }
+  }
+
+  /**
+   * Asynchronously invokes a static method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   */
+  public AsyncInvocation invokeAsync(final Class c, 
+                                     final String methodName,
+                                     final Object[] args) {
+    AsyncInvocation ai =
+      new AsyncInvocation(c, methodName, new Runnable() {
+        public void run() {
+          final Object o = invoke(c, methodName, args);
+          AsyncInvocation.setReturnValue(o);
+        }
+      });
+    ai.start();
+    return ai;
+  }
+
+  /**
+   * Asynchronously invokes an instance method with an {@link Object} or
+   * <code>void</code> return type in this VM.  If the return type of
+   * the method is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param o
+   *        The object on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   */
+  public AsyncInvocation invokeAsync(final Object o, 
+                                     final String methodName,
+                                     final Object[] args) {
+    AsyncInvocation ai =
+      new AsyncInvocation(o, methodName, new Runnable() {
+        public void run() {
+          final Object ret = invoke(o, methodName, args);
+          AsyncInvocation.setReturnValue(ret);
+        }
+      });
+    ai.start();
+    return ai;
+  }
+
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param r
+   *        The <code>Runnable</code> to be run
+   *
+   * @see SerializableRunnable
+   */
+  public AsyncInvocation invokeAsync(Runnable r) {
+    return invokeAsync(r, "run", new Object[0]);
+  }
+  
+  /**
+   * Invokes the <code>call</code> method of a {@link Runnable} in this
+   * VM.  
+   *
+   * @param c
+   *        The <code>Callable</code> to be run
+   *
+   * @see SerializableCallable
+   */
+  public AsyncInvocation invokeAsync(Callable c) {
+    return invokeAsync(c, "call", new Object[0]);
+  }
+
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param r
+   *        The <code>Runnable</code> to be run
+   *
+   * @see SerializableRunnable
+   */
+  public void invoke(Runnable r) {
+    invoke(r, "run");
+  }
+  
+  /**
+   * Invokes the <code>run</code> method of a {@link Runnable} in this
+   * VM.  Recall that <code>run</code> takes no arguments and has no
+   * return value.
+   *
+   * @param c
+   *        The <code>Callable</code> to be run
+   *
+   * @see SerializableCallable
+   */
+  public Object invoke(Callable c) {
+    return invoke(c, "call");
+  }
+  
+  /**
+   * Invokes the <code>run</code method of a {@link Runnable} in this
+   * VM.  If the invocation throws AssertionFailedError, and repeatTimeoutMs
+   * is >0, the <code>run</code> method is invoked repeatedly until it
+   * either succeeds, or repeatTimeoutMs has passed.  The AssertionFailedError
+   * is thrown back to the sender of this method if <code>run</code> has not
+   * completed successfully before repeatTimeoutMs has passed.
+   */
+  public void invokeRepeatingIfNecessary(RepeatableRunnable o, long repeatTimeoutMs) {
+    invoke(o, "runRepeatingIfNecessary", new Object[] {new Long(repeatTimeoutMs)});
+  }
+
+  /**
+   * Invokes an instance method with no arguments on an object that is
+   * serialized into this VM.  The return type of the method can be
+   * either {@link Object} or <code>void</code>.  If the return type
+   * of the method is <code>void</code>, <code>null</code> is
+   * returned.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Object o, String methodName) {
+    return invoke(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method can be either {@link
+   * Object} or <code>void</code>.  If the return type of the method
+   * is <code>void</code>, <code>null</code> is returned.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public Object invoke(Object o, String methodName, Object[] args) {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, o.getClass().getName(), methodName,
+            new IllegalStateException(s));
+    }
+    MethExecutorResult result = null;
+    int retryCount = 120;
+    do {
+    try {
+      if ( args == null )
+        result = this.client.executeMethodOnObject(o, methodName);
+      else
+        result = this.client.executeMethodOnObject(o, methodName, args);
+      break; // out of while loop
+    } catch( RemoteException e ) {
+      if (retryCount-- > 0) {
+        boolean interrupted = Thread.interrupted();
+        try { Thread.sleep(1000); } catch (InterruptedException ignore) {interrupted = true;}
+        finally {
+          if (interrupted) {
+            Thread.currentThread().interrupt();
+          }
+        }
+      } else {
+        throw new RMIException(this, o.getClass().getName(), methodName, e );
+      }
+    }
+    } while (true);
+
+    if (!result.exceptionOccurred()) {
+      return result.getResult();
+
+    } else {
+      Throwable thr = result.getException();
+      throw new RMIException(this, o.getClass().getName(), methodName, thr,
+                             result.getStackTrace()); 
+    }
+  }
+
+  /**
+   * Invokes the <code>main</code> method of a given class
+   *
+   * @param c
+   *        The class on which to invoke the <code>main</code> method
+   * @param args
+   *        The "command line" arguments to pass to the
+   *        <code>main</code> method
+   */
+  public void invokeMain(Class c, String[] args) {
+    Object[] stupid = new Object[] { args };
+    invoke(c, "main", stupid);
+  }
+
+  /**
+   * Asynchronously invokes the <code>main</code> method of a given
+   * class
+   *
+   * @param c
+   *        The class on which to invoke the <code>main</code> method
+   * @param args
+   *        The "command line" arguments to pass to the
+   *        <code>main</code> method
+   */
+  public AsyncInvocation invokeMainAsync(Class c, String[] args) {
+    Object[] stupid = new Object[] { args };
+    return invokeAsync(c, "main", stupid);
+  }
+
+  /**
+   * Invokes a static method with a <code>boolean</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Class c, String methodName) {
+    return invokeBoolean(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>boolean</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a boolean";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Boolean) {
+      return ((Boolean) result).booleanValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a boolean";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>boolean</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Object o, String methodName) {
+    return invokeBoolean(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>boolean</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>boolean</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public boolean invokeBoolean(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a boolean";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Boolean) {
+      return ((Boolean) result).booleanValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a boolean";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>char</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Class c, String methodName) {
+    return invokeChar(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>char</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a char";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Character) {
+      return ((Character) result).charValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a char";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>char</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Object o, String methodName) {
+    return invokeChar(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>char</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>char</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public char invokeChar(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a char";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Character) {
+      return ((Character) result).charValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a char";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>byte</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Class c, String methodName) {
+    return invokeByte(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>byte</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a byte";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Byte) {
+      return ((Byte) result).byteValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a byte";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>byte</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Object o, String methodName) {
+    return invokeByte(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>byte</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>byte</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public byte invokeByte(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a byte";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Byte) {
+      return ((Byte) result).byteValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a byte";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>short</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Class c, String methodName) {
+    return invokeShort(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>short</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a short";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Short) {
+      return ((Short) result).shortValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a short";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>short</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Object o, String methodName) {
+    return invokeShort(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>short</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>short</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public short invokeShort(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a short";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Short) {
+      return ((Short) result).shortValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a short";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>int</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Class c, String methodName) {
+    return invokeInt(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>int</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a int";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Integer) {
+      return ((Integer) result).intValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a int";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>int</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Object o, String methodName) {
+    return invokeInt(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>int</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>int</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public int invokeInt(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a int";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Integer) {
+      return ((Integer) result).intValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a int";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>long</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Class c, String methodName) {
+    return invokeLong(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>long</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a long";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Long) {
+      return ((Long) result).longValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a long";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>long</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Object o, String methodName) {
+    return invokeLong(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>long</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>long</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public long invokeLong(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a long";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Long) {
+      return ((Long) result).longValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a long";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>float</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Class c, String methodName) {
+    return invokeFloat(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>float</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a float";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Float) {
+      return ((Float) result).floatValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a float";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>float</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Object o, String methodName) {
+    return invokeFloat(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>float</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>float</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public float invokeFloat(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a float";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Float) {
+      return ((Float) result).floatValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a float";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes a static method with a <code>double</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Class c, String methodName) {
+    return invokeDouble(c, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes a static method with a <code>double</code> return type
+   * in this VM.
+   *
+   * @param c
+   *        The class on which to invoke the method
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Class c, String methodName, Object[] args) {
+    Object result = invoke(c, methodName, args);
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a double";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Double) {
+      return ((Double) result).doubleValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a double";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>double</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Object o, String methodName) {
+    return invokeDouble(o, methodName, new Object[0]);
+  }
+
+  /**
+   * Invokes an instance method on an object that is serialized into
+   * this VM.  The return type of the method is <code>double</code>.
+   *
+   * @param o
+   *        The receiver of the method invocation
+   * @param methodName
+   *        The name of the method to invoke
+   * @param args
+   *        Arguments passed to the method call (must be {@link
+   *        java.io.Serializable}). 
+   *
+   * @throws IllegalArgumentException
+   *         The method does not return a <code>double</code>
+   * @throws RMIException
+   *         An exception occurred on while invoking the method in
+   *         this VM
+   */
+  public double invokeDouble(Object o, String methodName, Object[] args) {
+    Object result = invoke(o, methodName, args);
+    Class c = o.getClass();
+    if (result == null) {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned null, expected a double";
+      throw new IllegalArgumentException(s);
+
+    } else if (result instanceof Double) {
+      return ((Double) result).doubleValue();
+
+    } else {
+      String s = "Method \"" + methodName + "\" in class \"" +
+        c.getName() + "\" returned a \"" + result.getClass().getName()
+        + "\" expected a double";
+      throw new IllegalArgumentException(s);
+    }
+  }
+
+  /**
+   * Synchronously bounces (mean kills and restarts) this <code>VM</code>.
+   * Concurrent bounce attempts are synchronized but attempts to invoke
+   * methods on a bouncing VM will cause test failure.  Tests using bounce
+   * should be placed at the end of the dunit test suite, since an exception
+   * here will cause all tests using the unsuccessfully bounced VM to fail.
+   * 
+   * This method is currently not supported by the standalone dunit
+   * runner.
+   *
+   * @throws RMIException if an exception occurs while bouncing this VM, for
+   *  example a HydraTimeoutException if the VM fails to stop within {@link
+   *  hydra.Prms#maxClientShutdownWaitSec} or restart within {@link
+   *  hydra.Prms#maxClientStartupWaitSec}.
+   */
+  public synchronized void bounce() {
+    if (!this.available) {
+      String s = "VM not available: " + this;
+      throw new RMIException(this, this.getClass().getName(), "bounceVM",
+            new IllegalStateException(s));
+    }
+    this.available = false;
+    try {
+      BounceResult result = DUnitEnv.get().bounce(this.pid);
+      
+      this.pid = result.getNewPid();
+      this.client = result.getNewClient();
+      this.available = true;
+    } catch (UnsupportedOperationException e) {
+      this.available = true;
+      throw e;
+    } catch (RemoteException e) {
+      StringWriter sw = new StringWriter();
+      e.printStackTrace(new PrintWriter(sw, true));
+      RMIException rmie = new RMIException(this, this.getClass().getName(),
+        "bounceVM", e, sw.toString());
+      throw rmie;
+    }
+  }
+
+  /////////////////////  Utility Methods  ////////////////////
+
+  public String toString() {
+    return "VM " + this.getPid() + " running on " + this.getHost();
+  }
+
+  public static int getCurrentVMNum() {
+    return DUnitEnv.get().getVMID();
+  }
+  
+  public File getWorkingDirectory() {
+    return DUnitEnv.get().getWorkingDirectory(this.getPid());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
new file mode 100755
index 0000000..9653a76
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
@@ -0,0 +1,167 @@
+package com.gemstone.gemfire.test.dunit;
+
+import static com.gemstone.gemfire.test.dunit.Jitter.jitterInterval;
+import static org.junit.Assert.fail;
+
+import com.gemstone.gemfire.internal.cache.LocalRegion;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public class Wait {
+
+  /**
+   * Wait until given criterion is met
+   * 
+   * @param ev criterion to wait on
+   * @param ms total time to wait, in milliseconds
+   * @param interval pause interval between waits
+   * @param throwOnTimeout if false, don't generate an error
+   */
+  public static void waitForCriterion(final WaitCriterion ev, final long ms, final long interval, final boolean throwOnTimeout) {
+    long waitThisTime = jitterInterval(interval);
+    final long tilt = System.currentTimeMillis() + ms;
+    for (;;) {
+      if (ev.done()) {
+        return; // success
+      }
+      
+      if (ev instanceof StoppableWaitCriterion) {
+        StoppableWaitCriterion ev2 = (StoppableWaitCriterion)ev;
+        if (ev2.stopWaiting()) {
+          if (throwOnTimeout) {
+            fail("stopWaiting returned true: " + ev.description());
+          }
+          return;
+        }
+      }
+
+      // Calculate time left
+      long timeLeft = tilt - System.currentTimeMillis();
+      if (timeLeft <= 0) {
+        if (!throwOnTimeout) {
+          return; // not an error, but we're done
+        }
+        fail("Event never occurred after " + ms + " ms: " + ev.description());
+      }
+      
+      if (waitThisTime > timeLeft) {
+        waitThisTime = timeLeft;
+      }
+      
+      // Wait a little bit
+      Thread.yield();
+      try {
+        Thread.sleep(waitThisTime);
+      } catch (InterruptedException e) {
+        fail("interrupted");
+      }
+    }
+  }
+
+  /**
+   * Wait on a mutex.  This is done in a loop in order to address the
+   * "spurious wakeup" "feature" in Java.
+   * 
+   * @param ev condition to test
+   * @param mutex object to lock and wait on
+   * @param ms total amount of time to wait
+   * @param interval interval to pause for the wait
+   * @param throwOnTimeout if false, no error is thrown.
+   */
+  public static void waitOnMutex(final WaitCriterion ev, final Object mutex, final long ms, final long interval, final boolean throwOnTimeout) {
+    final long tilt = System.currentTimeMillis() + ms;
+    long waitThisTime = jitterInterval(interval);
+    synchronized (mutex) {
+      for (;;) {
+        if (ev.done()) {
+          break;
+        }
+        
+        long timeLeft = tilt - System.currentTimeMillis();
+        if (timeLeft <= 0) {
+          if (!throwOnTimeout) {
+            return; // not an error, but we're done
+          }
+          fail("Event never occurred after " + ms + " ms: " + ev.description());
+        }
+        
+        if (waitThisTime > timeLeft) {
+          waitThisTime = timeLeft;
+        }
+        
+        try {
+          mutex.wait(waitThisTime);
+        } catch (InterruptedException e) {
+          fail("interrupted");
+        }
+      } // for
+    } // synchronized
+  }
+
+  /** pause for a default interval */
+  public static void pause() {
+    pause(250);
+  }
+
+  /**
+   * Use of this function indicates a place in the tests tree where t
+   * he use of Thread.sleep() is
+   * highly questionable.
+   * <p>
+   * Some places in the system, especially those that test expirations and other
+   * timeouts, have a very good reason to call {@link Thread#sleep(long)}.  The
+   * <em>other</em> places are marked by the use of this method.
+   * 
+   * @param ms
+   */
+  public static final void staticPause(int ms) {
+    final long target = System.currentTimeMillis() + ms;
+    try {
+      for (;;) {
+        long msLeft = target - System.currentTimeMillis();
+        if (msLeft <= 0) {
+          break;
+        }
+        Thread.sleep(msLeft);
+      }
+    }
+    catch (InterruptedException e) {
+      throw new AssertionError("interrupted", e);
+    }
+    
+  }
+  
+  /**
+   * Blocks until the clock used for expiration on the given region changes.
+   */
+  public static final void waitForExpiryClockToChange(LocalRegion lr) {
+    long startTime = lr.cacheTimeMillis();
+    do {
+      Thread.yield();
+    } while (startTime == lr.cacheTimeMillis());
+  }
+  
+  /** pause for specified ms interval
+   * Make sure system clock has advanced by the specified number of millis before
+   * returning.
+   */
+  public static final void pause(int ms) {
+    if (ms > 50) {
+      //getLogWriter().info("Pausing for " + ms + " ms..."/*, new Exception()*/);
+    }
+    final long target = System.currentTimeMillis() + ms;
+    try {
+      for (;;) {
+        long msLeft = target - System.currentTimeMillis();
+        if (msLeft <= 0) {
+          break;
+        }
+        Thread.sleep(msLeft);
+      }
+    }
+    catch (InterruptedException e) {
+      throw new AssertionError("interrupted", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/49b2913a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
new file mode 100755
index 0000000..493038e
--- /dev/null
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/WaitCriterion.java
@@ -0,0 +1,11 @@
+package com.gemstone.gemfire.test.dunit;
+
+/**
+ * Extracted from DistributedTestCase
+ */
+public interface WaitCriterion {
+
+  public boolean done();
+  
+  public String description();
+}



[6/9] incubator-geode git commit: Reorganization of dunit

Posted by kl...@apache.org.
Reorganization of dunit


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/fcd21422
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/fcd21422
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/fcd21422

Branch: refs/heads/feature/GEODE-217
Commit: fcd214227656a79edc08fecbf655c9ae98114523
Parents: 49b2913
Author: Kirk Lund <kl...@pivotal.io>
Authored: Fri Aug 21 13:14:16 2015 -0700
Committer: Kirk Lund <kl...@pivotal.io>
Committed: Fri Aug 21 13:14:16 2015 -0700

----------------------------------------------------------------------
 build.gradle                                    |   5 +-
 .../distributed/DistributedMemberDUnitTest.java |   2 +-
 .../distributed/HostedLocatorsDUnitTest.java    |   4 +-
 .../gemfire/internal/cache/BackupDUnitTest.java |  15 +-
 .../offheap/OutOfOffHeapMemoryDUnitTest.java    |   4 +-
 .../internal/process/PidFileJUnitTest.java      |   4 +-
 .../catchexception/CatchExceptionDUnitTest.java |  63 --
 .../catchexception/CatchExceptionJUnitTest.java |  95 ---
 .../gemstone/gemfire/test/dunit/DUnitEnv.java   | 100 +++
 .../gemfire/test/dunit/DistributedTestCase.java | 687 +++++++++----------
 .../com/gemstone/gemfire/test/dunit/Invoke.java |   1 -
 .../com/gemstone/gemfire/test/dunit/Jitter.java |   2 +-
 .../test/dunit/SerializableRunnable.java        |   4 +-
 .../com/gemstone/gemfire/test/dunit/Wait.java   |   3 +
 .../gemfire/test/dunit/cache/CacheTestCase.java |   4 +-
 .../test/dunit/tests/BasicDUnitTest.java        |   9 +-
 .../dunit/tests/DUnitFrameworkTestSuite.java    |  16 -
 .../gemfire/test/dunit/tests/VMDUnitTest.java   |   3 +
 .../golden/GoldenTestFrameworkTestSuite.java    |  27 -
 .../test/junit/rules/ExpectedTimeout.java       | 164 -----
 .../junit/rules/ExpectedTimeoutJUnitTest.java   | 188 -----
 21 files changed, 462 insertions(+), 938 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 0311206..b98cdf0 100755
--- a/build.gradle
+++ b/build.gradle
@@ -282,13 +282,12 @@ subprojects {
     testCompile 'eu.codearte.catch-exception:catch-throwable:1.4.4'
     testCompile 'junit:junit:4.12'
     testCompile 'org.assertj:assertj-core:2.1.0'
-    testCompile 'org.easytesting:fest-test:2.1.0'
-    testCompile 'org.mockito:mockito-core:1.10.19'
+    testCompile 'org.easetech:easytest-core:1.3.2'
     testCompile 'org.hamcrest:hamcrest-all:1.3'
     testCompile 'org.jmock:jmock:2.8.1'
     testCompile 'org.jmock:jmock-junit4:2.8.1'
     testCompile 'org.jmock:jmock-legacy:2.8.1'
-    testCompile 'org.unitils:unitils:3.4.2'
+    testCompile 'org.mockito:mockito-core:1.10.19'
     testCompile 'pl.pragmatists:JUnitParams:1.0.4'
 
     testRuntime 'cglib:cglib:3.1'

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
index e45b02d..1f6edab 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/DistributedMemberDUnitTest.java
@@ -281,7 +281,7 @@ public class DistributedMemberDUnitTest extends DistributedTestCase {
         public void run() {
           InternalDistributedSystem sys = getSystem();
           final String expectedMyGroup = makeGroupsString(vm);
-          assertEquals(expectedMyGroup, sys.getConfig().getGroups());
+          assertEquals("vm-"+vm, expectedMyGroup, sys.getConfig().getGroups());
           
           DM dm = sys.getDistributionManager();
           DistributedMember self = sys.getDistributedMember();

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
index e74e12f..f77f50d 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/distributed/HostedLocatorsDUnitTest.java
@@ -37,7 +37,7 @@ import com.gemstone.gemfire.test.dunit.SerializableCallable;
 import com.gemstone.gemfire.test.dunit.SerializableRunnable;
 import com.gemstone.gemfire.test.junit.categories.DistributedTest;
 import com.gemstone.gemfire.test.junit.categories.MembershipTest;
-import com.gemstone.gemfire.test.junit.rules.Retry;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
 
 /**
  * Extracted from LocatorLauncherLocalJUnitTest.
@@ -61,7 +61,7 @@ public class HostedLocatorsDUnitTest extends DistributedTestCase {
   public final transient Timeout globalTimeout = Timeout.seconds(2 * 60 * 1000);
   
   @Rule
-  public final transient Retry retry = new Retry(2);
+  public final transient RetryRule retry = new RetryRule(2);
   
   @Before
   public void setUp() throws Exception {

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/BackupDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/BackupDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/BackupDUnitTest.java
index 5829451..e7b9261 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/BackupDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/cache/BackupDUnitTest.java
@@ -41,9 +41,10 @@ import com.gemstone.gemfire.distributed.internal.DistributionMessageObserver;
 import com.gemstone.gemfire.distributed.internal.ReplyMessage;
 import com.gemstone.gemfire.internal.FileUtil;
 import com.gemstone.gemfire.internal.cache.partitioned.PersistentPartitionedRegionTestBase;
+import com.gemstone.gemfire.internal.process.PidUnavailableException;
+import com.gemstone.gemfire.internal.process.ProcessUtils;
 
 import dunit.AsyncInvocation;
-import dunit.DUnitEnv;
 import dunit.Host;
 import dunit.SerializableCallable;
 import dunit.SerializableRunnable;
@@ -533,10 +534,18 @@ public class BackupDUnitTest extends PersistentPartitionedRegionTestBase {
     vm.invoke(validateUserFileBackup);
   }
 
+  private int identifyPid() {
+    try {
+      return ProcessUtils.identifyPid();
+    } catch (PidUnavailableException e) {
+      throw new AssertionError(e.getMessage(), e);
+    }
+  }
+  
   protected long setBackupFiles(final VM vm) {
     SerializableCallable setUserBackups = new SerializableCallable("set user backups") {
       public Object call() {
-        final int pid = DUnitEnv.get().getPid();
+        final int pid = identifyPid();
         File vmdir = new File("userbackup_"+pid);
         File test1 = new File(vmdir, "test1");
         File test2 = new File(test1, "test2");
@@ -568,7 +577,7 @@ public class BackupDUnitTest extends PersistentPartitionedRegionTestBase {
   protected void verifyUserFileRestored(VM vm, final long lm) {
     vm.invoke(new SerializableRunnable() {
       public void run() {
-        final int pid = DUnitEnv.get().getPid();
+        final int pid = identifyPid();
         File vmdir = new File("userbackup_"+pid);
         File mytext = new File(vmdir, "test1/test2/my.txt");
         assertTrue(mytext.exists());

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
index 644d82c..72b64e6 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/offheap/OutOfOffHeapMemoryDUnitTest.java
@@ -56,7 +56,7 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
   }
   
   @Override
-  public void tearDown2() throws Exception {
+  public void tearDownBefore() throws Exception {
     final SerializableRunnable checkOrphans = new SerializableRunnable() {
       @Override
       public void run() {
@@ -70,7 +70,7 @@ public class OutOfOffHeapMemoryDUnitTest extends CacheTestCase {
       checkOrphans.run();
     } finally {
       invokeInEveryVM(getClass(), "cleanup");
-      super.tearDown2();
+      super.tearDownBefore();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/PidFileJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/PidFileJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/PidFileJUnitTest.java
index e1ad29b..836712b 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/PidFileJUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/internal/process/PidFileJUnitTest.java
@@ -26,7 +26,7 @@ import org.junit.rules.TemporaryFolder;
 
 import com.gemstone.gemfire.internal.util.StopWatch;
 import com.gemstone.gemfire.test.junit.categories.UnitTest;
-import com.gemstone.gemfire.test.junit.rules.ExpectedTimeout;
+import com.gemstone.gemfire.test.junit.rules.ExpectedTimeoutRule;
 
 /**
  * Unit tests the PidFile class.
@@ -44,7 +44,7 @@ public class PidFileJUnitTest {
   public ExpectedException thrown = ExpectedException.none();
   
   @Rule
-  public ExpectedTimeout timeout = ExpectedTimeout.none();
+  public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none();
   
   protected Mockery mockContext;
   private ExecutorService futures;

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
deleted file mode 100755
index a3fc1f1..0000000
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionDUnitTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.gemstone.gemfire.test.catchexception;
-
-import static com.googlecode.catchexception.CatchException.*;
-import static com.googlecode.catchexception.apis.BDDCatchException.when;
-import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
-import static org.assertj.core.api.BDDAssertions.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.fail;
-
-import org.junit.Test;
-
-import com.gemstone.gemfire.test.dunit.DistributedTestCase;
-import com.gemstone.gemfire.test.dunit.Host;
-import com.gemstone.gemfire.test.dunit.RMIException;
-import com.gemstone.gemfire.test.dunit.SerializableCallable;
-import com.gemstone.gemfire.test.dunit.VM;
-
-/**
- * Using Catch-Exception works well for remote exceptions and asserting details
- * about root cause of RMIExceptions in DUnit tests.
- */
-public class CatchExceptionDUnitTest extends DistributedTestCase {
-  private static final long serialVersionUID = 1L;
-
-  private static final String REMOTE_THROW_EXCEPTION_MESSAGE = "Throwing remoteThrowException";
-
-  @Test
-  public void testRemoteInvocationWithException() {
-    Host host = Host.getHost(0);
-    VM vm = host.getVM(0);
-
-    when(vm).invoke(new ThrowBasicTestException());
-
-    then(caughtException())
-        .isInstanceOf(RMIException.class)
-        .hasCause(new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE));
-  }
-  
-  protected static class ThrowBasicTestException extends SerializableCallable<Object> {
-    private static final long serialVersionUID = 1L;
-    
-    @Override
-    public Object call() throws Exception {
-      throw new BasicTestException(REMOTE_THROW_EXCEPTION_MESSAGE);
-    }
-  }
-  
-  protected static class BasicTestException extends RuntimeException {
-    private static final long serialVersionUID = 1L;
-
-    public BasicTestException() {
-      super();
-    }
-    
-    public BasicTestException(String message) {
-      super(message);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
deleted file mode 100755
index d197745..0000000
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/catchexception/CatchExceptionJUnitTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.gemstone.gemfire.test.catchexception;
-
-import static com.googlecode.catchexception.CatchException.*;
-import static com.googlecode.catchexception.apis.BDDCatchException.when;
-import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;
-import static org.assertj.core.api.BDDAssertions.*;
-import static org.hamcrest.Matchers.*;
-import static org.junit.Assert.*;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.Test;
-
-/**
- * Simple unit tests exercising Catch-Exception with AssertJ, Hamcrest and JUnit.
- */
-public class CatchExceptionJUnitTest {
-
-  @Test
-  public void catchExceptionShouldCatchException() {
-    List<?> myList = new ArrayList<Object>();
-
-    // when: we try to get the first element of the list
-    // then: catch the exception if any is thrown
-    catchException(myList).get(1);
-    
-    // then: we expect an IndexOutOfBoundsException
-    assertThat(caughtException(), is(instanceOf(IndexOutOfBoundsException.class)));
-  }
-  
-  @Test
-  public void verifyExceptionShouldCatchException() {
-    List<?> myList = new ArrayList<Object>();
-
-    // when: we try to get the first element of the list
-    // then: catch the exception if any is thrown
-    // then: we expect an IndexOutOfBoundsException
-    verifyException(myList, IndexOutOfBoundsException.class).get(1);
-  }
-  
-  @Test
-  public void whenShouldCatchExceptionAndUseAssertJAssertion() {
-    // given: an empty list
-    List<?> myList = new ArrayList<Object>();
-
-    // when: we try to get the first element of the list
-    when(myList).get(1);
-
-    // then: we expect an IndexOutOfBoundsException
-    then(caughtException())
-            .isInstanceOf(IndexOutOfBoundsException.class)
-            .hasMessage("Index: 1, Size: 0")
-            .hasNoCause();
-  }
-  
-  @Test
-  public void catchExceptionShouldCatchExceptionAndUseHamcrestAssertion() {
-    // given: an empty list
-    List<?> myList = new ArrayList<Object>();
-
-    // when: we try to get the first element of the list
-    catchException(myList).get(1);
-
-    // then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
-    assertThat(caughtException(),
-      allOf(
-        instanceOf(IndexOutOfBoundsException.class),
-        hasMessage("Index: 1, Size: 0"),
-        hasNoCause()
-      )
-    );
-  }
-  
-  @Test
-  public void shouldCatchFromThrowException() throws Exception {
-    String message = "error message";
-    
-    catchException(this).throwException(message);
-    
-    assertThat(caughtException(), is(instanceOf(Exception.class)));
-  }
-  
-  @Test
-  public void shouldVerifyFromThrowException() throws Exception {
-    String message = "error message";
-
-    verifyException(this).throwException(message);
-  }
-  
-  // fails if private
-  protected void throwException(final String message) throws Exception {
-    throw new Exception(message);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
index 96ebd7d..944ad2e 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DUnitEnv.java
@@ -12,8 +12,16 @@ package com.gemstone.gemfire.test.dunit;
 
 import java.io.File;
 import java.rmi.RemoteException;
+import java.util.Iterator;
+import java.util.Map;
 import java.util.Properties;
 
+import com.gemstone.gemfire.LogWriter;
+import com.gemstone.gemfire.distributed.internal.DistributionConfig;
+import com.gemstone.gemfire.distributed.internal.DistributionConfigImpl;
+import com.gemstone.gemfire.internal.logging.LogWriterFactory;
+import com.gemstone.gemfire.internal.logging.ManagerLogWriter;
+
 /**
  * This class provides an abstraction over the environment
  * that is used to run dunit. This will delegate to the hydra
@@ -64,5 +72,97 @@ public abstract class DUnitEnv {
   public abstract BounceResult bounce(int pid) throws RemoteException;
 
   public abstract File getWorkingDirectory(int pid);
+
+  //---------------------------------------------------------------------------
+  // static methods
+  //---------------------------------------------------------------------------
   
+  public static final Properties getAllDistributedSystemProperties(Properties props) { // TODO: delete
+    Properties p = DUnitEnv.get().getDistributedSystemProperties();
+    
+    // our tests do not expect auto-reconnect to be on by default
+    if (!p.contains(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME)) {
+      p.put(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME, "true");
+    }
+        
+    for (Iterator iter = props.entrySet().iterator();
+    iter.hasNext(); ) {
+      Map.Entry entry = (Map.Entry) iter.next();
+      String key = (String) entry.getKey();
+      Object value = entry.getValue();
+      p.put(key, value);
+    }
+    return p;
+  }
+
+  /**
+   * This finds the log level configured for the test run.  It should be used
+   * when creating a new distributed system if you want to specify a log level.
+   * 
+   * @return the dunit log-level setting
+   */
+  public static String getDUnitLogLevel() { // TODO: delete
+    Properties p = DUnitEnv.get().getDistributedSystemProperties();
+    String result = p.getProperty(DistributionConfig.LOG_LEVEL_NAME);
+    if (result == null) {
+      result = ManagerLogWriter.levelToString(DistributionConfig.DEFAULT_LOG_LEVEL);
+    }
+    return result;
+  }
+
+  /**
+   * Get the port that the standard dunit locator is listening on.
+   * @return
+   */
+  public static int getDUnitLocatorPort() {
+    return DUnitEnv.get().getLocatorPort();
+  }
+    
+  /**
+   * Creates a new LogWriter and adds it to the config properties. The config
+   * can then be used to connect to DistributedSystem, thus providing early
+   * access to the LogWriter before connecting. This call does not connect
+   * to the DistributedSystem. It simply creates and returns the LogWriter
+   * that will eventually be used by the DistributedSystem that connects using
+   * config.
+   * 
+   * @param config the DistributedSystem config properties to add LogWriter to
+   * @return early access to the DistributedSystem LogWriter
+   */
+  protected static LogWriter createLogWriter(Properties config) {
+    Properties nonDefault = config;
+    if (nonDefault == null) {
+      nonDefault = new Properties();
+    }
+    addHydraProperties(nonDefault);
+    
+    DistributionConfig dc = new DistributionConfigImpl(nonDefault);
+    LogWriter logger = LogWriterFactory.createLogWriterLogger(
+        false/*isLoner*/, false/*isSecurityLog*/, dc, 
+        false);        
+    
+    // if config was non-null, then these will be added to it...
+    nonDefault.put(DistributionConfig.LOG_WRITER_NAME, logger);
+    
+    return logger;
+  }
+
+  /**
+   * Fetches the GemFireDescription for this test and adds its 
+   * DistributedSystem properties to the provided props parameter.
+   * 
+   * @param config the properties to add hydra's test properties to
+   */
+  private static void addHydraProperties(Properties config) {
+    Properties p = DUnitEnv.get().getDistributedSystemProperties();
+    for (Iterator iter = p.entrySet().iterator();
+        iter.hasNext(); ) {
+      Map.Entry entry = (Map.Entry) iter.next();
+      String key = (String) entry.getKey();
+      String value = (String) entry.getValue();
+      if (config.getProperty(key) == null) {
+        config.setProperty(key, value);
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
index 5eb3b0b..abb0a95 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/DistributedTestCase.java
@@ -1,11 +1,9 @@
 package com.gemstone.gemfire.test.dunit;
 
+import static com.gemstone.gemfire.test.dunit.DUnitEnv.*;
 import static com.gemstone.gemfire.test.dunit.Invoke.*;
-import static com.gemstone.gemfire.test.dunit.Wait.*;
 import static org.junit.Assert.*;
 
-import java.io.File;
-import java.net.UnknownHostException;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Properties;
@@ -28,7 +26,6 @@ import com.gemstone.gemfire.distributed.internal.DistributionConfig;
 import com.gemstone.gemfire.distributed.internal.DistributionMessageObserver;
 import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
 import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.CreationStackGenerator;
-import com.gemstone.gemfire.distributed.internal.membership.jgroup.MembershipManagerHelper;
 import com.gemstone.gemfire.internal.AvailablePort;
 import com.gemstone.gemfire.internal.InternalDataSerializer;
 import com.gemstone.gemfire.internal.InternalInstantiator;
@@ -42,11 +39,8 @@ import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
 import com.gemstone.gemfire.internal.cache.tier.sockets.DataSerializerPropogationDUnitTest;
 import com.gemstone.gemfire.internal.logging.InternalLogWriter;
 import com.gemstone.gemfire.internal.logging.LogService;
-import com.gemstone.gemfire.internal.logging.ManagerLogWriter;
 import com.gemstone.gemfire.internal.logging.log4j.LogWriterLogger;
 import com.gemstone.gemfire.management.internal.cli.LogWrapper;
-import com.gemstone.org.jgroups.Event;
-import com.gemstone.org.jgroups.JChannel;
 import com.gemstone.org.jgroups.stack.IpAddress;
 import com.gemstone.org.jgroups.stack.Protocol;
 import com.gemstone.org.jgroups.util.GemFireTracer;
@@ -58,20 +52,22 @@ import com.gemstone.gemfire.test.dunit.standalone.DUnitLauncher;
  *
  * @author David Whitlock
  */
-@SuppressWarnings({ "deprecation", "serial", "rawtypes" })
+@SuppressWarnings({ "deprecation", "rawtypes" })
 public abstract class DistributedTestCase implements java.io.Serializable {
+  private static final long serialVersionUID = 1L;
   private static final Logger logger = LogService.getLogger();
   private static final LogWriterLogger oldLogger = LogWriterLogger.create(logger);
 
   @Rule
   public transient TestName testNameRule = new TestName();
+  private static volatile String previousTestName;
+  private static volatile String testName;
   
-  public static InternalDistributedSystem system;
-  private static Class lastSystemCreatedInTest;
-  private static Properties lastSystemProperties;
-  public static volatile String testName;
+  private static InternalDistributedSystem system;
+  private static Class previousSystemCreatedInTestClass;
+  private static Properties previousProperties;
   
-  public static final boolean logPerTest = Boolean.getBoolean("dunitLogPerTest");
+  private final boolean logPerTest = Boolean.getBoolean("dunitLogPerTest");
 
   /**
    * Creates a new <code>DistributedTestCase</code> test.
@@ -80,85 +76,137 @@ public abstract class DistributedTestCase implements java.io.Serializable {
     DUnitLauncher.launchIfNeeded();
   }
 
-  private static void setUpCreationStackGenerator() {
-    // the following is moved from InternalDistributedSystem to fix #51058
-    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(
-    new CreationStackGenerator() {
+  //---------------------------------------------------------------------------
+  // setUp methods
+  //---------------------------------------------------------------------------
+  
+  @Before
+  public final void setUpDistributedTestCase() throws Exception {
+    setUpCreationStackGenerator();
+    testName = getMethodName();
+    
+    System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");
+    GemFireCacheImpl.setDefaultDiskStoreName(getDefaultDiskStoreName()); // TODO: not thread safe
+    
+    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);
+        final String vmDefaultDiskStoreName = "DiskStore-" + h + "-" + v + "-" + getClass().getSimpleName() + "." + testName;
+        setUpInVM(vm, testName, vmDefaultDiskStoreName);
+      }
+    }
+    //System.out.println("\n\n[setup] START TEST " + getClass().getSimpleName()+"."+testName+"\n\n");
+  }
+
+  private void setUpInVM(final VM vm, final String testNameToUse, final String diskStoreNameToUse) {
+    vm.invoke(new SerializableRunnable() {
+      private static final long serialVersionUID = 1L;
+
       @Override
-      public Throwable generateCreationStack(final DistributionConfig config) {
-        final StringBuilder sb = new StringBuilder();
-        final String[] validAttributeNames = config.getAttributeNames();
-        for (int i = 0; i < validAttributeNames.length; i++) {
-          final String attName = validAttributeNames[i];
-          final Object actualAtt = config.getAttributeObject(attName);
-          String actualAttStr = actualAtt.toString();
-          sb.append("  ");
-          sb.append(attName);
-          sb.append("=\"");
-          if (actualAtt.getClass().isArray()) {
-            actualAttStr = InternalDistributedSystem.arrayToString(actualAtt);
-          }
-          sb.append(actualAttStr);
-          sb.append("\"");
-          sb.append("\n");
-        }
-        return new Throwable("Creating distributed system with the following configuration:\n" + sb.toString());
+      public void run() {
+        setUpCreationStackGenerator();
+        testName = testNameToUse;
+        System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");    
+        GemFireCacheImpl.setDefaultDiskStoreName(diskStoreNameToUse); // TODO: not thread safe
       }
     });
   }
   
-  private static void tearDownCreationStackGenerator() {
-    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(InternalDistributedSystem.DEFAULT_CREATION_STACK_GENERATOR);
+  //---------------------------------------------------------------------------
+  // tearDown methods
+  //---------------------------------------------------------------------------
+  
+  /**
+   * For logPerTest to work, we have to disconnect from the DS, but all
+   * subclasses do not call super.tearDown(). To prevent this scenario
+   * this method has been declared final. Subclasses must now override
+   * {@link #tearDownBefore()} instead.
+   * @throws Exception
+   */
+  @After
+  public final void tearDownDistributedTestCase() throws Exception {
+    tearDownBefore();
+    realTearDown();
+    tearDownAfter();
+    
+    tearDownCreationStackGenerator();
+    previousTestName = testName;
+    testName = null;
+
+    tearDownInEveryVM();
+  }
+
+  private void tearDownInEveryVM() {
+    invokeInEveryVM(new SerializableRunnable() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
+      public void run() {    
+        tearDownCreationStackGenerator();
+        previousTestName = testName;
+        testName = null;
+      }
+    });
   }
   
-  private Class getTestClass() {
-    Class clazz = getClass();
-    while (clazz.getDeclaringClass() != null) {
-      clazz = clazz.getDeclaringClass();
+  protected void realTearDown() throws Exception {
+    if (logPerTest) {
+      disconnectFromDS();
+      invokeInEveryVM(DistributedTestCase.class, "disconnectFromDS");
     }
-    return clazz;
+    cleanupAllVms();
   }
   
   /**
-   * This finds the log level configured for the test run.  It should be used
-   * when creating a new distributed system if you want to specify a log level.
-   * 
-   * @return the dunit log-level setting
+   * Tears down the test. This method is called by the final {@link #tearDown()} method and should be overridden to
+   * perform actual test cleanup and release resources used by the test.  The tasks executed by this method are
+   * performed before the DUnit test framework using Hydra cleans up the client VMs.
+   * <p/>
+   * @throws Exception if the tear down process and test cleanup fails.
+   * @see #tearDown
+   * @see #tearDownAfter()
    */
-  public static String getDUnitLogLevel() { // TODO: delete
-    Properties p = DUnitEnv.get().getDistributedSystemProperties();
-    String result = p.getProperty(DistributionConfig.LOG_LEVEL_NAME);
-    if (result == null) {
-      result = ManagerLogWriter.levelToString(DistributionConfig.DEFAULT_LOG_LEVEL);
-    }
-    return result;
+  protected void tearDownBefore() throws Exception {
   }
 
-  public final static Properties getAllDistributedSystemProperties(Properties props) { // TODO: delete
-    Properties p = DUnitEnv.get().getDistributedSystemProperties();
-    
-    // our tests do not expect auto-reconnect to be on by default
-    if (!p.contains(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME)) {
-      p.put(DistributionConfig.DISABLE_AUTO_RECONNECT_NAME, "true");
-    }
-        
-    for (Iterator iter = props.entrySet().iterator();
-    iter.hasNext(); ) {
-      Map.Entry entry = (Map.Entry) iter.next();
-      String key = (String) entry.getKey();
-      Object value = entry.getValue();
-      p.put(key, value);
-    }
-    return p;
+  /**
+   * Tears down the test.  Performs additional tear down tasks after the DUnit tests framework using Hydra cleans up
+   * the client VMs.  This method is called by the final {@link #tearDown()} method and should be overridden to perform
+   * post tear down activities.
+   * <p/>
+   * @throws Exception if the test tear down process fails.
+   * @see #tearDown()
+   * @see #tearDownBefore()
+   */
+  protected void tearDownAfter() throws Exception {
   }
 
-  public void setSystem(Properties props, DistributedSystem ds) { // TODO: delete
-    system = (InternalDistributedSystem)ds;
-    lastSystemProperties = props;
-    lastSystemCreatedInTest = getTestClass();
+  //---------------------------------------------------------------------------
+  // test name methods
+  //---------------------------------------------------------------------------
+  
+  public final String getMethodName() {
+    return this.testNameRule.getMethodName();
   }
   
   /**
+   * Returns a unique name for this test method.  It is based on the
+   * name of the class as well as the name of the method.
+   */
+  public final String getUniqueName() { // TODO: consider using FQCN
+    return getClass().getSimpleName() + "_" + getTestName();
+  }
+
+  protected static String getTestName() {
+    return testName;
+  }
+
+  //---------------------------------------------------------------------------
+  // public final methods
+  //---------------------------------------------------------------------------
+  
+  /**
    * Returns this VM's connection to the distributed system.  If
    * necessary, the connection will be lazily created using the given
    * <code>Properties</code>.  Note that this method uses hydra's
@@ -169,125 +217,127 @@ public abstract class DistributedTestCase implements java.io.Serializable {
    * @see hydra.DistributedConnectionMgr#connect
    * @since 3.0
    */
-  public final InternalDistributedSystem getSystem(Properties props) {
-    // Setting the default disk store name is now done in setUp
+  public final InternalDistributedSystem getSystem(Properties properties) {
     if (system == null) {
       system = InternalDistributedSystem.getAnyInstance();
     }
+    
     if (system == null || !system.isConnected()) {
-      // Figure out our distributed system properties
-      Properties p = getAllDistributedSystemProperties(props);
-      lastSystemCreatedInTest = getTestClass();
+      // there is no previous system yet
+      final Properties newProperties = getAllDistributedSystemProperties(properties);
+      previousSystemCreatedInTestClass = getTestClass();
       if (logPerTest) {
-        String testMethod = getTestName();
-        String testName = lastSystemCreatedInTest.getName() + '-' + testMethod;
-        String oldLogFile = p.getProperty(DistributionConfig.LOG_FILE_NAME);
-        p.put(DistributionConfig.LOG_FILE_NAME, 
-            oldLogFile.replace("system.log", testName+".log"));
-        String oldStatFile = p.getProperty(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME);
-        p.put(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, 
-            oldStatFile.replace("statArchive.gfs", testName+".gfs"));
+        newProperties.put(DistributionConfig.LOG_FILE_NAME, getUniqueName() + ".log");
+        newProperties.put(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, getUniqueName() + ".gfs");
       }
-      system = (InternalDistributedSystem)DistributedSystem.connect(p);
-      lastSystemProperties = p;
+      system = (InternalDistributedSystem)DistributedSystem.connect(newProperties);
+      previousProperties = newProperties;
+      
     } else {
+      // there is a previous system
       boolean needNewSystem = false;
-      if(!getTestClass().equals(lastSystemCreatedInTest)) {
-        Properties newProps = getAllDistributedSystemProperties(props);
-        needNewSystem = !newProps.equals(lastSystemProperties);
-        if(needNewSystem) {
-          getLogWriter().info(
+      //if (!getUniqueName().equals(previousTestName)) {
+      if (!getTestClass().equals(previousSystemCreatedInTestClass)) {
+        // previous system was created in a previous test class
+        final Properties newProperties = getAllDistributedSystemProperties(properties);
+        if (logPerTest) {
+          newProperties.put(DistributionConfig.LOG_FILE_NAME, getUniqueName() + ".log");
+          newProperties.put(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, getUniqueName() + ".gfs");
+        }
+        needNewSystem = !newProperties.equals(previousProperties);
+        if (needNewSystem) {
+          logger.info(
               "Test class has changed and the new DS properties are not an exact match. "
                   + "Forcing DS disconnect. Old props = "
-                  + lastSystemProperties + "new props=" + newProps);
+                  + previousProperties + "new props=" + newProperties);
         }
+        
       } else {
-        Properties activeProps = system.getProperties();
-        for (Iterator iter = props.entrySet().iterator();
-        iter.hasNext(); ) {
-          Map.Entry entry = (Map.Entry) iter.next();
-          String key = (String) entry.getKey();
-          String value = (String) entry.getValue();
-          if (!value.equals(activeProps.getProperty(key))) {
+        // previous system was created in this test class
+        final Properties currentProperties = system.getProperties();
+        for (Iterator iter = properties.entrySet().iterator(); iter.hasNext(); ) {
+          final Map.Entry entry = (Map.Entry) iter.next();
+          final String key = (String) entry.getKey();
+          final String value = (String) entry.getValue();
+          if (!value.equals(currentProperties.getProperty(key))) {
             needNewSystem = true;
-            getLogWriter().info("Forcing DS disconnect. For property " + key
-                                + " old value = " + activeProps.getProperty(key)
+            logger.info("Forcing DS disconnect. For property " + key
+                                + " old value = " + currentProperties.getProperty(key)
                                 + " new value = " + value);
             break;
           }
         }
       }
-      if(needNewSystem) {
+      
+      if (needNewSystem) {
         // the current system does not meet our needs to disconnect and
         // call recursively to get a new system.
-        getLogWriter().info("Disconnecting from current DS in order to make a new one");
+        logger.info("Disconnecting from current DS in order to make a new one");
         disconnectFromDS();
-        getSystem(props);
+        getSystem(properties);
       }
     }
     return system;
   }
-
-  /**
-   * Crash the cache in the given VM in such a way that it immediately stops communicating with
-   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
-   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
-   * 
-   * NOTE: if you use this method be sure that you clean up the VM before the end of your
-   * test with disconnectFromDS() or disconnectAllFromDS().
-   */
-  public static boolean crashDistributedSystem(VM vm) { // TODO: move
-    return (Boolean)vm.invoke(new SerializableCallable("crash distributed system") {
-      public Object call() throws Exception {
-        DistributedSystem msys = InternalDistributedSystem.getAnyInstance();
-        crashDistributedSystem(msys);
-        return true;
-      }
-    });
-  }
   
-  /**
-   * Crash the cache in the given VM in such a way that it immediately stops communicating with
-   * peers.  This forces the VM's membership manager to throw a ForcedDisconnectException by
-   * forcibly terminating the JGroups protocol stack with a fake EXIT event.<p>
-   * 
-   * NOTE: if you use this method be sure that you clean up the VM before the end of your
-   * test with disconnectFromDS() or disconnectAllFromDS().
-   */
-  public static void crashDistributedSystem(final DistributedSystem msys) { // TODO: move
-    MembershipManagerHelper.inhibitForcedDisconnectLogging(true);
-    MembershipManagerHelper.playDead(msys);
-    JChannel c = MembershipManagerHelper.getJChannel(msys);
-    Protocol udp = c.getProtocolStack().findProtocol("UDP");
-    udp.stop();
-    udp.passUp(new Event(Event.EXIT, new RuntimeException("killing member's ds")));
-    try {
-      MembershipManagerHelper.getJChannel(msys).waitForClose();
-    }
-    catch (InterruptedException ie) {
-      Thread.currentThread().interrupt();
-      // attempt rest of work with interrupt bit set
-    }
-    MembershipManagerHelper.inhibitForcedDisconnectLogging(false);
-    WaitCriterion wc = new WaitCriterion() {
-      public boolean done() {
-        return !msys.isConnected();
-      }
-      public String description() {
-        return "waiting for distributed system to finish disconnecting: " + msys;
-      }
-    };
-//    try {
-      waitForCriterion(wc, 10000, 1000, true);
-//    } finally {
-//      dumpMyThreads(getLogWriter());
+//  public /*final*/ InternalDistributedSystem getSystem(Properties props) {
+//    // Setting the default disk store name is now done in setUp
+//    if (system == null) {
+//      system = InternalDistributedSystem.getAnyInstance();
 //    }
-  }
-
-  private String getDefaultDiskStoreName() { // TODO: move
-    String vmid = System.getProperty("vmid");
-    return "DiskStore-"  + vmid + "-"+ getTestClass().getCanonicalName() + "." + getTestName();
-  }
+//    if (system == null || !system.isConnected()) {
+//      // Figure out our distributed system properties
+//      Properties p = getAllDistributedSystemProperties(props);
+//      lastSystemCreatedInTest = getTestClass();
+//      if (logPerTest) {
+//        String testMethod = getTestName();
+//        String testName = lastSystemCreatedInTest.getName() + '-' + testMethod;
+//        String oldLogFile = p.getProperty(DistributionConfig.LOG_FILE_NAME);
+//        p.put(DistributionConfig.LOG_FILE_NAME, 
+//            oldLogFile.replace("system.log", testName+".log"));
+//        String oldStatFile = p.getProperty(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME);
+//        p.put(DistributionConfig.STATISTIC_ARCHIVE_FILE_NAME, 
+//            oldStatFile.replace("statArchive.gfs", testName+".gfs"));
+//      }
+//      system = (InternalDistributedSystem)DistributedSystem.connect(p);
+//      previousProperties = p;
+//    } else {
+//      boolean needNewSystem = false;
+//      if(!getTestClass().equals(lastSystemCreatedInTest)) {
+//        Properties newProps = getAllDistributedSystemProperties(props);
+//        needNewSystem = !newProps.equals(previousProperties);
+//        if(needNewSystem) {
+//          getLogWriter().info(
+//              "Test class has changed and the new DS properties are not an exact match. "
+//                  + "Forcing DS disconnect. Old props = "
+//                  + previousProperties + "new props=" + newProps);
+//        }
+//      } else {
+//        Properties activeProps = system.getProperties();
+//        for (Iterator iter = props.entrySet().iterator();
+//        iter.hasNext(); ) {
+//          Map.Entry entry = (Map.Entry) iter.next();
+//          String key = (String) entry.getKey();
+//          String value = (String) entry.getValue();
+//          if (!value.equals(activeProps.getProperty(key))) {
+//            needNewSystem = true;
+//            getLogWriter().info("Forcing DS disconnect. For property " + key
+//                                + " old value = " + activeProps.getProperty(key)
+//                                + " new value = " + value);
+//            break;
+//          }
+//        }
+//      }
+//      if(needNewSystem) {
+//        // the current system does not meet our needs to disconnect and
+//        // call recursively to get a new system.
+//        getLogWriter().info("Disconnecting from current DS in order to make a new one");
+//        disconnectFromDS();
+//        getSystem(props);
+//      }
+//    }
+//    return system;
+//  }
 
   /**
    * Returns this VM's connection to the distributed system.  If
@@ -363,6 +413,10 @@ public abstract class DistributedTestCase implements java.io.Serializable {
     return system != null && system.isConnected();
   }
 
+  //---------------------------------------------------------------------------
+  // public methods
+  //---------------------------------------------------------------------------
+  
   /**
    * Returns a <code>Properties</code> object used to configure a
    * connection to a {@link
@@ -376,97 +430,92 @@ public abstract class DistributedTestCase implements java.io.Serializable {
     return new Properties();
   }
 
-  /**
-   * Sets up the test (noop).
-   */
-  @Before
-  public final void setUpDistributedTestCase() throws Exception {
-    setUpCreationStackGenerator();
-    testName = getName();
-    System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");
-    
-    if (testName != null) {
-      GemFireCacheImpl.setDefaultDiskStoreName(getDefaultDiskStoreName());
-      String baseDefaultDiskStoreName = getTestClass().getCanonicalName() + "." + getTestName();
-      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);
-          String vmDefaultDiskStoreName = "DiskStore-" + h + "-" + v + "-" + baseDefaultDiskStoreName;
-          vm.invoke(DistributedTestCase.class, "perVMSetUp", new Object[] {testName, vmDefaultDiskStoreName});
-        }
-      }
-    }
-    System.out.println("\n\n[setup] START TEST " + getClass().getSimpleName()+"."+testName+"\n\n");
-  }
+  //---------------------------------------------------------------------------
+  // delete
+  //---------------------------------------------------------------------------
 
-  public static void perVMSetUp(String name, String defaultDiskStoreName) { // TODO: move
-    setTestName(name);
-    GemFireCacheImpl.setDefaultDiskStoreName(defaultDiskStoreName);
-    System.setProperty(HoplogConfig.ALLOW_LOCAL_HDFS_PROP, "true");    
+  public void setSystem(Properties props, DistributedSystem ds) { // TODO: delete
+    system = (InternalDistributedSystem)ds;
+    previousProperties = props;
+    previousSystemCreatedInTestClass = getTestClass();
   }
   
-  public static void setTestName(String name) {
-    testName = name;
+  //---------------------------------------------------------------------------
+  // private
+  //---------------------------------------------------------------------------
+
+  private Class getTestClass() {
+    Class clazz = getClass();
+    while (clazz.getDeclaringClass() != null) {
+      clazz = clazz.getDeclaringClass();
+    }
+    return clazz;
   }
   
-  public static String getTestName() {
-    return testName;
-  }
-
-  /**
-   * For logPerTest to work, we have to disconnect from the DS, but all
-   * subclasses do not call super.tearDown(). To prevent this scenario
-   * this method has been declared final. Subclasses must now override
-   * {@link #tearDown2()} instead.
-   * @throws Exception
-   */
-  @After
-  public final void tearDownDistributedTestCase() throws Exception {
-    tearDownCreationStackGenerator();
-    tearDown2();
-    realTearDown();
-    tearDownAfter();
+  private String getDefaultDiskStoreName() { // TODO: move
+    String vmid = System.getProperty("vmid");
+    return "DiskStore-"  + vmid + "-"+ getTestClass().getCanonicalName() + "." + getTestName();
   }
 
+  //---------------------------------------------------------------------------
+  // deprecated static methods
+  //---------------------------------------------------------------------------
+  
   /**
-   * Tears down the test. This method is called by the final {@link #tearDown()} method and should be overridden to
-   * perform actual test cleanup and release resources used by the test.  The tasks executed by this method are
-   * performed before the DUnit test framework using Hydra cleans up the client VMs.
-   * <p/>
-   * @throws Exception if the tear down process and test cleanup fails.
-   * @see #tearDown
-   * @see #tearDownAfter()
+   * Returns a <code>LogWriter</code> for logging information
+   * @deprecated Use a static logger from the log4j2 LogService.getLogger instead.
    */
-  // TODO rename this method to tearDownBefore and change the access modifier to protected!
-  public void tearDown2() throws Exception { // TODO: rename
+  @Deprecated
+  public static InternalLogWriter getLogWriter() { // TODO: delete
+    return oldLogger;
   }
 
-  protected void realTearDown() throws Exception {
-    if (logPerTest) {
-      disconnectFromDS();
-      invokeInEveryVM(DistributedTestCase.class, "disconnectFromDS");
-    }
-    cleanupAllVms();
+  //---------------------------------------------------------------------------
+  // private static methods
+  //---------------------------------------------------------------------------
+  
+  private static void setUpCreationStackGenerator() {
+    // the following is moved from InternalDistributedSystem to fix #51058
+    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(
+    new CreationStackGenerator() {
+      @Override
+      public Throwable generateCreationStack(final DistributionConfig config) {
+        final StringBuilder sb = new StringBuilder();
+        final String[] validAttributeNames = config.getAttributeNames();
+        for (int i = 0; i < validAttributeNames.length; i++) {
+          final String attName = validAttributeNames[i];
+          final Object actualAtt = config.getAttributeObject(attName);
+          String actualAttStr = actualAtt.toString();
+          sb.append("  ");
+          sb.append(attName);
+          sb.append("=\"");
+          if (actualAtt.getClass().isArray()) {
+            actualAttStr = InternalDistributedSystem.arrayToString(actualAtt);
+          }
+          sb.append(actualAttStr);
+          sb.append("\"");
+          sb.append("\n");
+        }
+        return new Throwable("Creating distributed system with the following configuration:\n" + sb.toString());
+      }
+    });
   }
   
-  /**
-   * Tears down the test.  Performs additional tear down tasks after the DUnit tests framework using Hydra cleans up
-   * the client VMs.  This method is called by the final {@link #tearDown()} method and should be overridden to perform
-   * post tear down activities.
-   * <p/>
-   * @throws Exception if the test tear down process fails.
-   * @see #tearDown()
-   * @see #tearDown2()
-   */
-  protected void tearDownAfter() throws Exception {
+  private static void tearDownCreationStackGenerator() {
+    InternalDistributedSystem.TEST_CREATION_STACK_GENERATOR.set(InternalDistributedSystem.DEFAULT_CREATION_STACK_GENERATOR);
   }
-
-  public static void cleanupAllVms()
-  {
+  
+  //---------------------------------------------------------------------------
+  // tearDown methods
+  //---------------------------------------------------------------------------
+  
+  public static void cleanupAllVms() {
     cleanupThisVM();
     invokeInEveryVM(DistributedTestCase.class, "cleanupThisVM");
     invokeInLocator(new SerializableRunnable() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
       public void run() {
         DistributionMessageObserver.setInstance(null);
         unregisterInstantiatorsInThisVM();
@@ -475,58 +524,33 @@ public abstract class DistributedTestCase implements java.io.Serializable {
     DUnitLauncher.closeAndCheckForSuspects();
   }
 
-
-  private static void cleanupThisVM() {
-    IpAddress.resolve_dns = true;
-    SocketCreator.resolve_dns = true;
-    InitialImageOperation.slowImageProcessing = 0;
-    DistributionMessageObserver.setInstance(null);
-    QueryTestUtils.setCache(null);
-    CacheServerTestUtil.clearCacheReference();
-    RegionTestCase.preSnapshotRegion = null;
-    GlobalLockingDUnitTest.region_testBug32356 = null;
-    LogWrapper.close();
-    ClientProxyMembershipID.system = null;
-    MultiVMRegionTestCase.CCRegion = null;
-    InternalBridgeMembership.unregisterAllListeners();
-    ClientStatsManager.cleanupForTests();
-    unregisterInstantiatorsInThisVM();
-    GemFireTracer.DEBUG = Boolean.getBoolean("DistributionManager.DEBUG_JAVAGROUPS");
-    Protocol.trace = GemFireTracer.DEBUG;
-    DistributionMessageObserver.setInstance(null);
-    QueryObserverHolder.reset();
-    if (InternalDistributedSystem.systemAttemptingReconnect != null) {
-      InternalDistributedSystem.systemAttemptingReconnect.stopReconnecting();
-    }
-    ExpectedExceptionString ex;
-    while((ex = ExpectedExceptionString.poll()) != null) {
-      ex.remove();
-    }
-  }
-  
-  public static void unregisterAllDataSerializersFromAllVms() // TODO: move
-  {
+  public static void unregisterAllDataSerializersFromAllVms() {
     unregisterDataSerializerInThisVM();
     invokeInEveryVM(new SerializableRunnable() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
       public void run() {
         unregisterDataSerializerInThisVM();
       }
     });
     invokeInLocator(new SerializableRunnable() {
+      private static final long serialVersionUID = 1L;
+
+      @Override
       public void run() {
         unregisterDataSerializerInThisVM();
       }
     });
   }
 
-  public static void unregisterInstantiatorsInThisVM() { // TODO: move
+  public static void unregisterInstantiatorsInThisVM() {
     // unregister all the instantiators
     InternalInstantiator.reinitialize();
     assertEquals(0, InternalInstantiator.getInstantiators().length);
   }
   
-  public static void unregisterDataSerializerInThisVM() // TODO: move
-  {
+  public static void unregisterDataSerializerInThisVM() {
     DataSerializerPropogationDUnitTest.successfullyLoadedTestDataSerializer = false;
     // unregister all the Dataserializers
     InternalDataSerializer.reinitialize();
@@ -534,18 +558,15 @@ public abstract class DistributedTestCase implements java.io.Serializable {
     assertEquals(0, InternalDataSerializer.getSerializers().length);
   }
 
-
   protected static void disconnectAllFromDS() {
     disconnectFromDS();
-    invokeInEveryVM(DistributedTestCase.class,
-                    "disconnectFromDS");
+    invokeInEveryVM(DistributedTestCase.class, "disconnectFromDS");
   }
 
   /**
    * Disconnects this VM from the distributed system
    */
   public static void disconnectFromDS() {
-    testName = null;
     GemFireCacheImpl.testCacheXml = null;
     if (system != null) {
       system.disconnect();
@@ -565,95 +586,37 @@ public abstract class DistributedTestCase implements java.io.Serializable {
       }
     }
     
-    {
-      AdminDistributedSystemImpl ads = 
-          AdminDistributedSystemImpl.getConnectedInstance();
-      if (ads != null) {// && ads.isConnected()) {
-        ads.disconnect();
-      }
+    AdminDistributedSystemImpl ads = AdminDistributedSystemImpl.getConnectedInstance();
+    if (ads != null) {// && ads.isConnected()) {
+      ads.disconnect();
     }
   }
 
-  /**
-   * Strip the package off and gives just the class name.
-   * Needed because of Windows file name limits.
-   */
-  private String getShortClassName() {
-    String result = this.getClass().getName();
-    int idx = result.lastIndexOf('.');
-    if (idx != -1) {
-      result = result.substring(idx+1);
-    }
-    return result;
-  }
-  
-  /** get the host name to use for a server cache in client/server dunit
-   * testing
-   * @param host
-   * @return the host name
-   */
-  public static String getServerHostName(Host host) { // TODO: move
-    return System.getProperty("gemfire.server-bind-address") != null?
-        System.getProperty("gemfire.server-bind-address")
-        : host.getHostName();
-  }
-
-  /** get the IP literal name for the current host, use this instead of  
-   * "localhost" to avoid IPv6 name resolution bugs in the JDK/machine config.
-   * @return an ip literal, this method honors java.net.preferIPvAddresses
-   */
-  public static String getIPLiteral() { // TODO: move
-    try {
-      return SocketCreator.getLocalHost().getHostAddress();
-    } catch (UnknownHostException e) {
-      throw new Error("problem determining host IP address", e);
+  private static void cleanupThisVM() {
+    IpAddress.resolve_dns = true;
+    SocketCreator.resolve_dns = true;
+    InitialImageOperation.slowImageProcessing = 0;
+    DistributionMessageObserver.setInstance(null);
+    QueryTestUtils.setCache(null);
+    CacheServerTestUtil.clearCacheReference();
+    RegionTestCase.preSnapshotRegion = null;
+    GlobalLockingDUnitTest.region_testBug32356 = null;
+    LogWrapper.close();
+    ClientProxyMembershipID.system = null;
+    MultiVMRegionTestCase.CCRegion = null;
+    InternalBridgeMembership.unregisterAllListeners();
+    ClientStatsManager.cleanupForTests();
+    unregisterInstantiatorsInThisVM();
+    GemFireTracer.DEBUG = Boolean.getBoolean("DistributionManager.DEBUG_JAVAGROUPS");
+    Protocol.trace = GemFireTracer.DEBUG;
+    DistributionMessageObserver.setInstance(null);
+    QueryObserverHolder.reset();
+    if (InternalDistributedSystem.systemAttemptingReconnect != null) {
+      InternalDistributedSystem.systemAttemptingReconnect.stopReconnecting();
     }
-  }
- 
- 
-  /**
-   * Get the port that the standard dunit locator is listening on.
-   * @return
-   */
-  public static int getDUnitLocatorPort() { // TODO: move
-    return DUnitEnv.get().getLocatorPort();
-  }
-    
-  public String getName() {
-    return this.testNameRule.getMethodName();
-  }
-  
-  /**
-   * Returns a unique name for this test method.  It is based on the
-   * name of the class as well as the name of the method.
-   */
-  public String getUniqueName() {
-    return getClass().getSimpleName() + "_" + getName();
-  }
-
-  /**
-   * Returns a <code>LogWriter</code> for logging information
-   * @deprecated Use a static logger from the log4j2 LogService.getLogger instead.
-   */
-  @Deprecated
-  public static InternalLogWriter getLogWriter() { // TODO: delete
-    return oldLogger;
-  }
-
-  /** 
-   * Delete locator state files.  Use this after getting a random port
-   * to ensure that an old locator state file isn't picked up by the
-   * new locator you're starting.
-   * 
-   * @param ports
-   */
-  public static void deleteLocatorStateFile(final int... ports) { // TODO: move
-    for (int i=0; i<ports.length; i++) {
-      final File stateFile = new File("locator"+ports[i]+"state.dat");
-      if (stateFile.exists()) {
-        stateFile.delete();
-      }
+    ExpectedExceptionString ex;
+    while((ex = ExpectedExceptionString.poll()) != null) {
+      ex.remove();
     }
   }
-  
 }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
index bd9eaf6..4ccf972 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Invoke.java
@@ -36,7 +36,6 @@ public class Invoke {
   public static void invokeInEveryVM(final SerializableRunnable work) {
     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);
         vm.invoke(work);

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
index 446b4bf..698d055 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Jitter.java
@@ -5,7 +5,7 @@ import java.util.Random;
 /**
  * Extracted from DistributedTestCase
  */
-public class Jitter {
+class Jitter {
 
   /**
    * If true, we randomize the amount of time we wait

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
index 28eabc3..df3a429 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/SerializableRunnable.java
@@ -37,9 +37,7 @@ import java.io.Serializable;
  *  }
  * </PRE>
  */
-public abstract class SerializableRunnable
-  implements Serializable, Runnable {
-
+public abstract class SerializableRunnable implements Serializable, Runnable {
   private static final long serialVersionUID = 7584289978241650456L;
   
   private String name;

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
index 9653a76..fa9b591 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/Wait.java
@@ -10,6 +10,9 @@ import com.gemstone.gemfire.internal.cache.LocalRegion;
  */
 public class Wait {
 
+  protected Wait() {
+  }
+  
   /**
    * Wait until given criterion is met
    * 

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
index 8535d85..0dbda35 100755
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/cache/CacheTestCase.java
@@ -420,7 +420,7 @@ public abstract class CacheTestCase extends DistributedTestCase {
   }
 
   @Override
-  public void tearDown2() throws Exception {
+  public void tearDownBefore() throws Exception {
     // locally destroy all root regions and close the cache
     remoteTearDown();
     // Now invoke it in every VM
@@ -431,7 +431,7 @@ public abstract class CacheTestCase extends DistributedTestCase {
         vm.invoke(CacheTestCase.class, "remoteTearDown");
       }
     }
-    super.tearDown2(); 
+    super.tearDownBefore(); 
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
index d0b1710..f15fe23 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/BasicDUnitTest.java
@@ -14,17 +14,20 @@ import java.util.Properties;
 
 import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import com.gemstone.gemfire.test.dunit.AsyncInvocation;
 import com.gemstone.gemfire.test.dunit.DistributedTestCase;
 import com.gemstone.gemfire.test.dunit.Host;
 import com.gemstone.gemfire.test.dunit.RMIException;
 import com.gemstone.gemfire.test.dunit.VM;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
 
 /**
  * This class tests the basic functionality of the distributed unit
  * test framework.
  */
+@Category(DistributedTest.class)
 public class BasicDUnitTest extends DistributedTestCase {
   private static final long serialVersionUID = 1L;
 
@@ -58,7 +61,7 @@ public class BasicDUnitTest extends DistributedTestCase {
   }
   
   @Test
-  public void testRemoteInvokeAsync() throws InterruptedException {
+  public void testRemoteInvokeAsync() throws Exception {
     Host host = Host.getHost(0);
     VM vm = host.getVM(0);
     String name = this.getUniqueName();
@@ -78,7 +81,7 @@ public class BasicDUnitTest extends DistributedTestCase {
   }
 
   @Test
-  public void testRemoteInvokeAsyncWithException() throws InterruptedException {
+  public void testRemoteInvokeAsyncWithException() throws Exception {
     Host host = Host.getHost(0);
     VM vm = host.getVM(0);
 
@@ -93,7 +96,7 @@ public class BasicDUnitTest extends DistributedTestCase {
   @Ignore("not implemented")
   public void testRemoteInvocationBoolean() {
   }
-
+  
   /**
    * Accessed via reflection.  DO NOT REMOVE
    */

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
deleted file mode 100755
index 82664b2..0000000
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/DUnitFrameworkTestSuite.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.gemstone.gemfire.test.dunit.tests;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-  BasicDUnitTest.class,
-  VMDUnitTest.class,
-})
-/**
- * Suite of tests for the test.dunit DUnit Test framework.
- */
-public class DUnitFrameworkTestSuite {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
index 12faffe..904da4f 100644
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
+++ b/gemfire-core/src/test/java/com/gemstone/gemfire/test/dunit/tests/VMDUnitTest.java
@@ -15,16 +15,19 @@ import java.io.Serializable;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import com.gemstone.gemfire.test.dunit.AsyncInvocation;
 import com.gemstone.gemfire.test.dunit.DistributedTestCase;
 import com.gemstone.gemfire.test.dunit.Host;
 import com.gemstone.gemfire.test.dunit.RMIException;
 import com.gemstone.gemfire.test.dunit.VM;
+import com.gemstone.gemfire.test.junit.categories.DistributedTest;
 
 /**
  * This class tests the functionality of the {@link VM} class.
  */
+@Category(DistributedTest.class)
 public class VMDUnitTest extends DistributedTestCase {
   private static final long serialVersionUID = 1L;
   

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestFrameworkTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestFrameworkTestSuite.java b/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestFrameworkTestSuite.java
deleted file mode 100755
index ed540be..0000000
--- a/gemfire-core/src/test/java/com/gemstone/gemfire/test/golden/GoldenTestFrameworkTestSuite.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.gemstone.gemfire.test.golden;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-  FailWithErrorInOutputJUnitTest.class,
-  FailWithExtraLineInOutputJUnitTest.class,
-  FailWithLineMissingFromEndOfOutputJUnitTest.class,
-  FailWithLineMissingFromMiddleOfOutputJUnitTest.class,
-  FailWithLoggerErrorInOutputJUnitTest.class,
-  FailWithLoggerFatalInOutputJUnitTest.class,
-  FailWithLoggerWarnInOutputJUnitTest.class,
-  FailWithSevereInOutputJUnitTest.class,
-  FailWithTimeoutOfWaitForOutputToMatchJUnitTest.class,
-  FailWithWarningInOutputJUnitTest.class,
-  PassJUnitTest.class,
-  PassWithExpectedErrorJUnitTest.class,
-  PassWithExpectedSevereJUnitTest.class,
-  PassWithExpectedWarningJUnitTest.class,
-})
-/**
- * Suite of tests for the test.golden Golden Test framework classes.
- */
-public class GoldenTestFrameworkTestSuite {
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeout.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeout.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeout.java
deleted file mode 100755
index 9d4040a..0000000
--- a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeout.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package com.gemstone.gemfire.test.junit.rules;
-
-import static org.junit.Assert.assertThat;
-
-import java.util.concurrent.TimeUnit;
-
-import org.hamcrest.Matcher;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Expect an Exception within a specified timeout.
- * 
- * @author Kirk Lund
- * @since 8.2
- */
-public class ExpectedTimeout implements TestRule {
-
-  /**
-   * @return a Rule that expects no timeout (identical to behavior without this Rule)
-   */
-  public static ExpectedTimeout none() {
-    return new ExpectedTimeout();
-  }
-  
-  private ExpectedException delegate;
-  private boolean expectsThrowable;
-  private long minDuration;
-  private long maxDuration;
-  private TimeUnit timeUnit;
-  
-  private ExpectedTimeout() {
-    this.delegate = ExpectedException.none();
-  }
-
-  public ExpectedTimeout expectMinimumDuration(final long minDuration) {
-    this.minDuration = minDuration;
-    return this;
-  }
-  public ExpectedTimeout expectMaximumDuration(final long maxDuration) {
-    this.maxDuration = maxDuration;
-    return this;
-  }
-  public ExpectedTimeout expectTimeUnit(final TimeUnit timeUnit) {
-    this.timeUnit = timeUnit;
-    return this;
-  }
-
-  public ExpectedTimeout handleAssertionErrors() {
-    this.delegate.handleAssertionErrors();
-    return this;
-  }
-  
-  public ExpectedTimeout handleAssumptionViolatedExceptions() {
-    this.delegate.handleAssumptionViolatedExceptions();
-    return this;
-  }
-  
-  /**
-   * Adds {@code matcher} to the list of requirements for any thrown
-   * exception.
-   */
-  public void expect(final Matcher<?> matcher) {
-    this.delegate.expect(matcher);
-  }
-
-  /**
-   * Adds to the list of requirements for any thrown exception that it should
-   * be an instance of {@code type}
-   */
-  public void expect(final Class<? extends Throwable> type) {
-    this.delegate.expect(type);
-    this.expectsThrowable = true;
-  }
-
-  /**
-   * Adds to the list of requirements for any thrown exception that it should
-   * <em>contain</em> string {@code substring}
-   */
-  public void expectMessage(final String substring) {
-    this.delegate.expectMessage(substring);
-  }
-
-  /**
-   * Adds {@code matcher} to the list of requirements for the message returned
-   * from any thrown exception.
-   */
-  public void expectMessage(final Matcher<String> matcher) {
-    this.delegate.expectMessage(matcher);
-  }
-
-  /**
-   * Adds {@code matcher} to the list of requirements for the cause of
-   * any thrown exception.
-   */
-  public void expectCause(final Matcher<? extends Throwable> expectedCause) {
-    this.delegate.expectCause(expectedCause);
-  }
-
-  public boolean expectsTimeout() {
-    return minDuration > 0 || maxDuration > 0;
-  }
-  
-  public boolean expectsThrowable() {
-    return expectsThrowable = true;
-  }
-  
-  @Override
-  public Statement apply(final Statement base, final Description description) {
-    Statement next = delegate.apply(base, description);
-    return new ExpectedTimeoutStatement(next);
-  }
-  
-  private void handleTime(final Long duration) {
-    if (expectsTimeout()) {
-      assertThat(timeUnit.convert(duration, TimeUnit.NANOSECONDS), new TimeMatcher(timeUnit, minDuration, maxDuration));
-    }
-  }
-  
-  private static class TimeMatcher extends org.hamcrest.TypeSafeMatcher<Long> {
-    
-    private final TimeUnit timeUnit;
-    private final long minDuration;
-    private final long maxDuration;
- 
-    public TimeMatcher(final TimeUnit timeUnit, final long minDuration, final long maxDuration) {
-      this.timeUnit = timeUnit;
-      this.minDuration = minDuration;
-      this.maxDuration = maxDuration;
-    }
- 
-    @Override
-    public boolean matchesSafely(final Long duration) {
-      return duration >= this.minDuration && duration <= this.maxDuration;
-    }
-
-    @Override
-    public void describeTo(final org.hamcrest.Description description) {
-      description.appendText("expects duration to be greater than or equal to ")
-          .appendValue(this.minDuration)
-          .appendText(" and less than or equal to ")
-          .appendValue(this.maxDuration)
-          .appendText(" ")
-          .appendValue(this.timeUnit);
-    }
-  }
-  
-  private class ExpectedTimeoutStatement extends Statement {
-    private final Statement next;
-
-    public ExpectedTimeoutStatement(final Statement base) {
-      next = base;
-    }
-
-    @Override
-    public void evaluate() throws Throwable {
-      long start = System.nanoTime();
-      next.evaluate();
-      handleTime(System.nanoTime() - start);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/fcd21422/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
deleted file mode 100755
index fe11586..0000000
--- a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package com.gemstone.gemfire.test.junit.rules;
-
-import static org.hamcrest.core.StringContains.*;
-import static org.hamcrest.core.Is.*;
-import static org.hamcrest.core.IsInstanceOf.*;
-import static org.junit.Assert.*;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.JUnitCore;
-import org.junit.runner.Request;
-import org.junit.runner.Result;
-import org.junit.runner.notification.Failure;
-
-import com.gemstone.gemfire.test.junit.categories.UnitTest;
-
-/**
- * Unit tests for ExpectedTimeout JUnit Rule.
- * 
- * @author Kirk Lund
- * @since 8.2
- */
-@Category(UnitTest.class)
-public class ExpectedTimeoutJUnitTest {
-
-  @Test
-  public void passesUnused() {
-    Result result = runTest(PassesUnused.class);
-    assertTrue(result.wasSuccessful());
-  }
-  
-  @Test
-  public void failsWithoutExpectedException() {
-    Result result = runTest(FailsWithoutExpectedException.class);
-    assertFalse(result.wasSuccessful());
-    List<Failure> failures = result.getFailures();
-    assertEquals(1, failures.size());
-    Failure failure = failures.get(0);
-    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
-    assertThat(failure.getException().getMessage(), containsString("Expected test to throw an instance of " + TimeoutException.class.getName()));
-  }
-  
-  @Test
-  public void failsWithoutExpectedTimeoutException() {
-    Result result = runTest(FailsWithoutExpectedTimeoutException.class);
-    assertFalse(result.wasSuccessful());
-    List<Failure> failures = result.getFailures();
-    assertEquals(1, failures.size());
-    Failure failure = failures.get(0);
-    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
-    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWithoutExpectedTimeoutException.message + "\")"));
-  }
-  
-  @Test
-  public void failsWithExpectedTimeoutButWrongError() {
-    Result result = runTest(FailsWithExpectedTimeoutButWrongError.class);
-    assertFalse(result.wasSuccessful());
-    List<Failure> failures = result.getFailures();
-    assertEquals(1, failures.size());
-    Failure failure = failures.get(0);
-    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
-    assertThat(failure.getException().getMessage(), containsString(NullPointerException.class.getName()));
-  }
-  
-  @Test
-  public void passesWithExpectedTimeoutAndTimeoutException() {
-    Result result = runTest(PassesWithExpectedTimeoutAndTimeoutException.class);
-    assertTrue(result.wasSuccessful());
-  }
-  
-  @Test
-  public void failsWhenTimeoutIsEarly() {
-    Result result = runTest(FailsWhenTimeoutIsEarly.class);
-    assertFalse(result.wasSuccessful());
-    List<Failure> failures = result.getFailures();
-    assertEquals(1, failures.size());
-    Failure failure = failures.get(0);
-    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
-    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsEarly.message + "\")"));
-  }
-  
-  @Test
-  public void failsWhenTimeoutIsLate() {
-    Result result = runTest(FailsWhenTimeoutIsLate.class);
-    assertFalse(result.wasSuccessful());
-    List<Failure> failures = result.getFailures();
-    assertEquals(1, failures.size());
-    Failure failure = failures.get(0);
-    assertThat(failure.getException(), is(instanceOf(AssertionError.class)));
-    assertThat(failure.getException().getMessage(), containsString("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsLate.message + "\")"));
-  }
-  
-  private static Result runTest(Class<?> test) {
-    JUnitCore junitCore = new JUnitCore();
-    return junitCore.run(Request.aClass(test).getRunner());
-  }
-  
-  public static class AbstractExpectedTimeoutTest {
-    @Rule
-    public ExpectedTimeout timeout = ExpectedTimeout.none();
-  }
-  
-  public static class PassesUnused extends AbstractExpectedTimeoutTest {
-    @Test
-    public void passesUnused() throws Exception {
-    }
-  }
-  
-  public static class FailsWithoutExpectedException extends AbstractExpectedTimeoutTest {
-    @Test
-    public void failsWithoutExpectedException() throws Exception {
-      timeout.expect(TimeoutException.class);
-    }
-  }
-  
-  public static class FailsWithoutExpectedTimeoutException extends AbstractExpectedTimeoutTest {
-    public static final String message = "this is a message for FailsWithoutExpectedTimeoutException";
-    @Test
-    public void failsWithoutExpectedTimeoutAndTimeoutException() throws Exception {
-      timeout.expect(TimeoutException.class);
-      timeout.expectMessage(message);
-      timeout.expectMinimumDuration(10);
-      timeout.expectMaximumDuration(1000);
-      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-      Thread.sleep(100);
-    }
-  }
-  
-  public static class FailsWithExpectedTimeoutButWrongError extends AbstractExpectedTimeoutTest {
-    public static final String message = "this is a message for FailsWithExpectedTimeoutButWrongError";
-    @Test
-    public void failsWithExpectedTimeoutButWrongError() throws Exception {
-      timeout.expect(TimeoutException.class);
-      timeout.expectMessage(message);
-      timeout.expectMinimumDuration(10);
-      timeout.expectMaximumDuration(1000);
-      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-      Thread.sleep(100);
-      throw new NullPointerException();
-    }
-  }
-
-  public static class PassesWithExpectedTimeoutAndTimeoutException extends AbstractExpectedTimeoutTest {
-    public static final String message = "this is a message for PassesWithExpectedTimeoutAndTimeoutException";
-    public static final Class<TimeoutException> exceptionClass = TimeoutException.class;
-    @Test
-    public void passesWithExpectedTimeoutAndTimeoutException() throws Exception {
-      timeout.expect(exceptionClass);
-      timeout.expectMessage(message);
-      timeout.expectMinimumDuration(10);
-      timeout.expectMaximumDuration(1000);
-      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-      Thread.sleep(100);
-      throw new TimeoutException(message);
-    }
-  }
-
-  public static class FailsWhenTimeoutIsEarly extends AbstractExpectedTimeoutTest {
-    public static final String message = "this is a message for FailsWhenTimeoutIsEarly";
-    @Test
-    public void failsWhenTimeoutIsEarly() throws Exception {
-      timeout.expect(TimeoutException.class);
-      timeout.expectMessage(message);
-      timeout.expectMinimumDuration(1000);
-      timeout.expectMaximumDuration(2000);
-      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-      Thread.sleep(10);
-    }
-  }
-
-  public static class FailsWhenTimeoutIsLate extends AbstractExpectedTimeoutTest {
-    public static final String message = "this is a message for FailsWhenTimeoutIsLate";
-    @Test
-    public void failsWhenTimeoutIsLate() throws Exception {
-      timeout.expect(TimeoutException.class);
-      timeout.expectMessage(message);
-      timeout.expectMinimumDuration(10);
-      timeout.expectMaximumDuration(20);
-      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-      Thread.sleep(100);
-    }
-  }
-}