geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [3/4] incubator-geode git commit: GEODE-953: Cleanup geode-junit
Date Mon, 29 Feb 2016 21:45:50 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestRule.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestRule.java b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestRule.java
new file mode 100755
index 0000000..9d06bc6
--- /dev/null
+++ b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestRule.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules.serializable;
+
+import java.io.Serializable;
+
+import org.junit.rules.TestRule;
+
+/**
+ * Specifies that a {@link org.junit.rules.TestRule TestRule} is
+ * {@code Serializable}.
+ */
+public interface SerializableTestRule extends Serializable, TestRule {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestWatcher.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestWatcher.java b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestWatcher.java
new file mode 100755
index 0000000..d325b09
--- /dev/null
+++ b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTestWatcher.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules.serializable;
+
+import org.junit.rules.TestWatcher;
+
+/**
+ * Serializable subclass of {@link org.junit.rules.TestWatcher TestWatcher}.
+ * There are no instance variables to be serialized.
+ */
+public abstract class SerializableTestWatcher extends TestWatcher implements SerializableTestRule {
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTimeout.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTimeout.java b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTimeout.java
new file mode 100755
index 0000000..f3a4ba7
--- /dev/null
+++ b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/rules/serializable/SerializableTimeout.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules.serializable;
+
+import static com.gemstone.gemfire.test.junit.rules.serializable.FieldSerializationUtils.*;
+import static com.gemstone.gemfire.test.junit.rules.serializable.FieldsOfTimeout.*;
+
+import org.junit.rules.Timeout;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Serializable subclass of {@link org.junit.rules.Timeout Timeout}. All
+ * instance variables of {@code Timeout} are serialized by reflection.
+ */
+public class SerializableTimeout extends Timeout implements SerializableTestRule {
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public SerializableTimeout(final long timeout, final TimeUnit timeUnit) {
+    super(timeout, timeUnit);
+  }
+
+  protected SerializableTimeout(final Builder builder) {
+    super(builder);
+  }
+
+  private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
+    throw new InvalidObjectException("SerializationProxy required");
+  }
+
+  private Object writeReplace() {
+    return new SerializationProxy(this);
+  }
+
+  /**
+   * Builder for {@code SerializableTimeout}.
+   */
+  public static class Builder extends Timeout.Builder {
+    
+    protected Builder() {
+      super();
+    }
+
+    @Override
+    public Builder withTimeout(final long timeout, final TimeUnit unit) {
+      super.withTimeout(timeout, unit);
+      return this;
+    }
+
+    @Override
+    public Builder withLookingForStuckThread(final boolean enable) {
+      super.withLookingForStuckThread(enable);
+      return this;
+    }
+
+    @Override
+    public SerializableTimeout build() {
+      return new SerializableTimeout(this);
+    }
+  }
+
+  /**
+   * Serialization proxy for {@code SerializableTimeout}.
+   */
+  private static class SerializationProxy implements Serializable {
+
+    private final long timeout;
+    private final TimeUnit timeUnit;
+    private final boolean lookForStuckThread;
+
+    SerializationProxy(final SerializableTimeout instance) {
+      this.timeout = (long) readField(Timeout.class, instance, FIELD_TIMEOUT);
+      this.timeUnit =(TimeUnit) readField(Timeout.class, instance, FIELD_TIME_UNIT);
+      this.lookForStuckThread =(boolean) readField(Timeout.class, instance, FIELD_LOOK_FOR_STUCK_THREAD);
+    }
+
+    private Object readResolve() {
+      return new SerializableTimeout.Builder()
+          .withTimeout(this.timeout, this.timeUnit)
+          .withLookingForStuckThread(this.lookForStuckThread)
+          .build();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
index b721c41..0f30c80 100755
--- a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
+++ b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
@@ -22,7 +22,6 @@ 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
@@ -46,7 +45,7 @@ public class DefaultIgnoreCondition implements IgnoreCondition {
   }
 
   public boolean isIgnore() {
-    return ignore;
+    return this.ignore;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
index 0d8a321..958e371 100755
--- a/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
+++ b/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/IgnoreConditionEvaluationException.java
@@ -19,7 +19,6 @@ package com.gemstone.gemfire.test.junit.support;
 /**
  * The IgnoreConditionEvaluationException class...
  *
- * @author John Blum
  * @see java.lang.RuntimeException
  */
 @SuppressWarnings({ "serial", "unused" })

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
deleted file mode 100755
index 24ebdde..0000000
--- a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutJUnitTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package 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);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
new file mode 100755
index 0000000..c1ad074
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+
+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.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link ExpectedTimeoutRule}.
+ */
+@Category(UnitTest.class)
+public class ExpectedTimeoutRuleTest {
+
+  @Test
+  public void passesUnused() {
+    Result result = TestRunner.runTest(PassingTestShouldPassWhenUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+  }
+  
+  @Test
+  public void failsWithoutExpectedException() {
+    Result result = TestRunner.runTest(FailsWithoutExpectedException.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw an instance of " + TimeoutException.class.getName());
+  }
+  
+  @Test
+  public void failsWithoutExpectedTimeoutException() {
+    Result result = TestRunner.runTest(FailsWithoutExpectedTimeoutException.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("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 = TestRunner.runTest(FailsWithExpectedTimeoutButWrongError.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+    
+    Failure failure = failures.get(0);
+    String expectedMessage = 
+        "\n" + 
+        "Expected: (an instance of java.util.concurrent.TimeoutException and exception with message a string containing \"this is a message for FailsWithExpectedTimeoutButWrongError\")" +
+        "\n" + 
+        "     " +
+        "but: an instance of java.util.concurrent.TimeoutException <java.lang.NullPointerException> is a java.lang.NullPointerException";
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessageContaining(expectedMessage);
+  }
+  
+  @Test
+  public void passesWithExpectedTimeoutAndTimeoutException() {
+    Result result = TestRunner.runTest(PassesWithExpectedTimeoutAndTimeoutException.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+  }
+  
+  @Test
+  public void failsWhenTimeoutIsEarly() {
+    Result result = TestRunner.runTest(FailsWhenTimeoutIsEarly.class);
+   
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("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 = TestRunner.runTest(FailsWhenTimeoutIsLate.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+    
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsLate.message + "\")");
+  }
+
+  /**
+   * Base class for all inner class test cases
+   */
+  public static class AbstractExpectedTimeoutRuleTest {
+
+    @Rule
+    public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none();
+  }
+
+  /**
+   * Used by test {@link #passesUnused()}
+   */
+  public static class PassingTestShouldPassWhenUnused extends AbstractExpectedTimeoutRuleTest {
+
+    @Test
+    public void doTest() {
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWithoutExpectedException()}
+   */
+  public static class FailsWithoutExpectedException extends AbstractExpectedTimeoutRuleTest {
+
+    @Test
+    public void doTest() {
+      timeout.expect(TimeoutException.class);
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWithoutExpectedTimeoutException()}
+   */
+  public static class FailsWithoutExpectedTimeoutException extends AbstractExpectedTimeoutRuleTest {
+
+    static final String message = "this is a message for FailsWithoutExpectedTimeoutException";
+
+    @Test
+    public void doTest() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(10);
+      timeout.expectMaximumDuration(1000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(100);
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWithExpectedTimeoutButWrongError()}
+   */
+  public static class FailsWithExpectedTimeoutButWrongError extends AbstractExpectedTimeoutRuleTest {
+
+    static final String message = "this is a message for FailsWithExpectedTimeoutButWrongError";
+
+    @Test
+    public void doTest() 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();
+    }
+  }
+
+  /**
+   * Used by test {@link #passesWithExpectedTimeoutAndTimeoutException()}
+   */
+  public static class PassesWithExpectedTimeoutAndTimeoutException extends AbstractExpectedTimeoutRuleTest {
+
+    static final String message = "this is a message for PassesWithExpectedTimeoutAndTimeoutException";
+    static final Class<TimeoutException> exceptionClass = TimeoutException.class;
+
+    @Test
+    public void doTest() 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);
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWhenTimeoutIsEarly()}
+   */
+  public static class FailsWhenTimeoutIsEarly extends AbstractExpectedTimeoutRuleTest {
+
+    static final String message = "this is a message for FailsWhenTimeoutIsEarly";
+
+    @Test
+    public void doTest() throws Exception {
+      timeout.expect(TimeoutException.class);
+      timeout.expectMessage(message);
+      timeout.expectMinimumDuration(1000);
+      timeout.expectMaximumDuration(2000);
+      timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+      Thread.sleep(10);
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWhenTimeoutIsLate()}
+   */
+  public static class FailsWhenTimeoutIsLate extends AbstractExpectedTimeoutRuleTest {
+
+    static final String message = "this is a message for FailsWhenTimeoutIsLate";
+
+    @Test
+    public void doTest() 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/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
new file mode 100755
index 0000000..d080f7c
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.IgnoreUntil;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link IgnoreUntilRule}.
+ */
+@Category(UnitTest.class)
+public class IgnoreUntilRuleTest {
+
+  private static final String ASSERTION_ERROR_MESSAGE = "failing test";
+  
+  @Test
+  public void shouldIgnoreWhenUntilIsInFuture() {
+    Result result = TestRunner.runTest(ShouldIgnoreWhenUntilIsInFuture.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(ShouldIgnoreWhenUntilIsInFuture.count).isEqualTo(0);
+  }
+  
+  @Test
+  public void shouldExecuteWhenUntilIsInPast() {
+    Result result = TestRunner.runTest(ShouldExecuteWhenUntilIsInPast.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(ShouldExecuteWhenUntilIsInPast.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void shouldExecuteWhenUntilIsDefault() {
+    Result result = TestRunner.runTest(ShouldExecuteWhenUntilIsDefault.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(ShouldExecuteWhenUntilIsDefault.count).isEqualTo(1);
+  }
+
+  /**
+   * Used by test {@link #shouldIgnoreWhenUntilIsInFuture()}
+   */
+  public static class ShouldIgnoreWhenUntilIsInFuture {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+    @Test
+    @IgnoreUntil(value = "description", until = "3000-01-01")
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #shouldExecuteWhenUntilIsInPast()}
+   */
+  public static class ShouldExecuteWhenUntilIsInPast {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+    @Test
+    @IgnoreUntil(value = "description", until = "1980-01-01")
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #shouldExecuteWhenUntilIsDefault()}
+   */
+  public static class ShouldExecuteWhenUntilIsDefault {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+    @Test
+    @IgnoreUntil("description")
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
new file mode 100755
index 0000000..235b16f
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
@@ -0,0 +1,411 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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;
+
+/**
+ * Unit tests for {@link RepeatRule}.
+ */
+@Category(UnitTest.class)
+public class RepeatRuleTest {
+
+  private static final String ASSERTION_ERROR_MESSAGE = "failing test";
+  
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsUnused() {
+    Result result = TestRunner.runTest(FailingTestShouldFailOneTimeWhenRepeatIsUnused.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsUnused.count).isEqualTo(1);
+  }
+
+  @Test
+  public void passingTestShouldPassOneTimeWhenRepeatIsUnused() {
+    Result result = TestRunner.runTest(PassingTestShouldPassOneTimeWhenRepeatIsUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassingTestShouldPassOneTimeWhenRepeatIsUnused.count).isEqualTo(1);
+  }
+
+  @Test
+  public void zeroValueShouldThrowIllegalArgumentException() {
+    Result result = TestRunner.runTest(ZeroValueShouldThrowIllegalArgumentException.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(IllegalArgumentException.class).hasMessage("Repeat value must be a positive integer");
+    assertThat(ZeroValueShouldThrowIllegalArgumentException.count).isEqualTo(0);
+  }
+  
+  @Test
+  public void negativeValueShouldThrowIllegalArgumentException() {
+    Result result = TestRunner.runTest(NegativeValueShouldThrowIllegalArgumentException.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(IllegalArgumentException.class).hasMessage("Repeat value must be a positive integer");
+    assertThat(NegativeValueShouldThrowIllegalArgumentException.count).isEqualTo(0);
+  }
+
+  /**
+   * Characterizes the behavior but is not a requirement for {@code RepeatRule}.
+   */
+  @Test
+  public void passingTestShouldBeSkippedWhenRepeatIsZero() {
+    Result result = TestRunner.runTest(PassingTestShouldBeSkippedWhenRepeatIsZero.class);
+
+    assertThat(result.wasSuccessful()).isFalse();
+    assertThat(PassingTestShouldBeSkippedWhenRepeatIsZero.count).isEqualTo(0);
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsOne() {
+    Result result = TestRunner.runTest(FailingTestShouldFailOneTimeWhenRepeatIsOne.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsOne.count).isEqualTo(1);
+  }
+
+  @Test
+  public void passingTestShouldPassOneTimeWhenRepeatIsOne() {
+    Result result = TestRunner.runTest(PassingTestShouldPassOneTimeWhenRepeatIsOne.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassingTestShouldPassOneTimeWhenRepeatIsOne.count).isEqualTo(1);
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsTwo() {
+    Result result = TestRunner.runTest(FailingTestShouldFailOneTimeWhenRepeatIsTwo.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsTwo.count).isEqualTo(1);
+  }
+
+  @Test
+  public void passingTestShouldPassTwoTimesWhenRepeatIsTwo() {
+    Result result = TestRunner.runTest(PassingTestShouldPassTwoTimesWhenRepeatIsTwo.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassingTestShouldPassTwoTimesWhenRepeatIsTwo.count).isEqualTo(2);
+  }
+
+  @Test
+  public void failingTestShouldFailOneTimeWhenRepeatIsThree() {
+    Result result = TestRunner.runTest(FailingTestShouldFailOneTimeWhenRepeatIsThree.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+    assertThat(FailingTestShouldFailOneTimeWhenRepeatIsThree.count).isEqualTo(1);
+  }
+
+  @Test
+  public void passingTestShouldPassThreeTimesWhenRepeatIsThree() {
+    Result result = TestRunner.runTest(PassingTestShouldPassThreeTimesWhenRepeatIsThree.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassingTestShouldPassThreeTimesWhenRepeatIsThree.count).isEqualTo(3);
+  }
+
+  /**
+   * Used by test {@link #failingTestShouldFailOneTimeWhenRepeatIsUnused()}
+   */
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsUnused {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #passingTestShouldPassOneTimeWhenRepeatIsUnused()}
+   */
+  public static class PassingTestShouldPassOneTimeWhenRepeatIsUnused {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #zeroValueShouldThrowIllegalArgumentException()}
+   */
+  public static class ZeroValueShouldThrowIllegalArgumentException {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(0)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #negativeValueShouldThrowIllegalArgumentException()}
+   */
+  public static class NegativeValueShouldThrowIllegalArgumentException {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(-1)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #passingTestShouldBeSkippedWhenRepeatIsZero()}
+   */
+  public static class PassingTestShouldBeSkippedWhenRepeatIsZero {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(0)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failingTestShouldFailOneTimeWhenRepeatIsOne()}
+   */
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsOne {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(1)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #passingTestShouldPassOneTimeWhenRepeatIsOne()}
+   */
+  public static class PassingTestShouldPassOneTimeWhenRepeatIsOne {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(1)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failingTestShouldFailOneTimeWhenRepeatIsTwo()}
+   */
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsTwo {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(2)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #passingTestShouldPassTwoTimesWhenRepeatIsTwo()}
+   */
+  public static class PassingTestShouldPassTwoTimesWhenRepeatIsTwo {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(2)
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failingTestShouldFailOneTimeWhenRepeatIsThree()}
+   */
+  public static class FailingTestShouldFailOneTimeWhenRepeatIsThree {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RepeatRule repeat = new RepeatRule();
+
+    @Test
+    @Repeat(3)
+    public void doTest() throws Exception {
+      count++;
+      fail(ASSERTION_ERROR_MESSAGE);
+    }
+  }
+
+  /**
+   * Used by test {@link #passingTestShouldPassThreeTimesWhenRepeatIsThree()}
+   */
+  public static class PassingTestShouldPassThreeTimesWhenRepeatIsThree {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      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/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
new file mode 100755
index 0000000..0e54298
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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;
+
+/**
+ * Unit tests for {@link RetryRule} involving global scope (ie rule affects all
+ * tests in the test class) with failures due to an {@code Error}.
+ * 
+ * @see com.gemstone.gemfire.test.junit.rules.RetryRule
+ */
+@Category(UnitTest.class)
+public class RetryRuleGlobalWithErrorTest {
+  
+  @Test
+  public void zeroIsIllegal() {
+    Result result = TestRunner.runTest(ZeroIsIllegal.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(IllegalArgumentException.class).hasMessage(ZeroIsIllegal.message);
+    assertThat(ZeroIsIllegal.count).isEqualTo(0);
+  }
+  
+  @Test
+  public void failsWithOne() {
+    Result result = TestRunner.runTest(FailsWithOne.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsWithOne.message);
+    assertThat(FailsWithOne.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void passesWithOne() {
+    Result result = TestRunner.runTest(PassesWithOne.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesWithOne.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void passesWithUnused() {
+    Result result = TestRunner.runTest(PassesWhenUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesWhenUnused.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = TestRunner.runTest(FailsOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsOnSecondAttempt.message);
+    assertThat(FailsOnSecondAttempt.count).isEqualTo(2);
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = TestRunner.runTest(PassesOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnSecondAttempt.count).isEqualTo(2);
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = TestRunner.runTest(FailsOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsOnThirdAttempt.message);
+    assertThat(FailsOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = TestRunner.runTest(PassesOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  /**
+   * Used by test {@link #zeroIsIllegal()}
+   */
+  public static class ZeroIsIllegal {
+
+    static final String message = "Retry count must be greater than zero";
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(0);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWithOne()}
+   */
+  public static class FailsWithOne {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesWithOne()}
+   */
+  public static class PassesWithOne {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #passesWithUnused()}
+   */
+  public static class PassesWhenUnused {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnSecondAttempt()}
+   */
+  public static class FailsOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnSecondAttempt()}
+   */
+  public static class PassesOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnThirdAttempt()}
+   */
+  public static class FailsOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnThirdAttempt()}
+   */
+  public static class PassesOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      if (count < 3) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
new file mode 100755
index 0000000..8ece92b
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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;
+
+/**
+ * Unit tests for {@link RetryRule} involving global scope (ie rule affects all
+ * tests in the test class) with failures due to an {@code Exception}.
+ * 
+ * @see com.gemstone.gemfire.test.junit.rules.RetryRule
+ */
+@Category(UnitTest.class)
+public class RetryRuleGlobalWithExceptionTest {
+  
+  @Test
+  public void zeroIsIllegal() {
+    Result result = TestRunner.runTest(ZeroIsIllegal.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(IllegalArgumentException.class).hasMessage(ZeroIsIllegal.message);
+    assertThat(ZeroIsIllegal.count).isEqualTo(0);
+  }
+  
+  @Test
+  public void failsWithOne() {
+    Result result = TestRunner.runTest(FailsWithOne.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsWithOne.message);
+    assertThat(FailsWithOne.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void passesWithOne() {
+    Result result = TestRunner.runTest(PassesWithOne.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+  }
+  
+  @Test
+  public void passesWithUnused() {
+    Result result = TestRunner.runTest(PassesWhenUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = TestRunner.runTest(FailsOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsOnSecondAttempt.message);
+    assertThat(FailsOnSecondAttempt.count).isEqualTo(2);
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = TestRunner.runTest(PassesOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnSecondAttempt.count).isEqualTo(2);
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = TestRunner.runTest(FailsOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsOnThirdAttempt.message);
+    assertThat(FailsOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = TestRunner.runTest(PassesOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  /**
+   * Custom exception used by several tests
+   */
+  public static class CustomException extends Exception {
+    public CustomException(final String message) {
+      super(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #zeroIsIllegal()}
+   */
+  public static class ZeroIsIllegal {
+
+    static int count = 0;
+    static final String message = "Retry count must be greater than zero";
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(0);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsWithOne()}
+   */
+  public static class FailsWithOne {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesWithOne()}
+   */
+  public static class PassesWithOne {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(1);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #passesWithUnused()}
+   */
+  public static class PassesWhenUnused {
+
+    static int count = 0;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnSecondAttempt()}
+   */
+  public static class FailsOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnSecondAttempt()}
+   */
+  public static class PassesOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule(2);
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnThirdAttempt()}
+   */
+  public static class FailsOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnThirdAttempt()}
+   */
+  public static class PassesOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule(3);
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      if (count < 3) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
new file mode 100755
index 0000000..3f0642c
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.junit.Assert.fail;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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;
+
+/**
+ * Unit tests for {@link RetryRule} involving local scope (ie rule affects
+ * only the test methods annotated with {@code @Retry}) with failures due to
+ * an {@code Error}.
+ */
+@Category(UnitTest.class)
+public class RetryRuleLocalWithErrorTest {
+
+  @Test
+  public void failsUnused() {
+    Result result = TestRunner.runTest(FailsUnused.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsUnused.message);
+    assertThat(FailsUnused.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void passesUnused() {
+    Result result = TestRunner.runTest(PassesUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesUnused.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = TestRunner.runTest(FailsOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsOnSecondAttempt.message);
+    assertThat(FailsOnSecondAttempt.count).isEqualTo(2);
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = TestRunner.runTest(PassesOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnSecondAttempt.count).isEqualTo(2);
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = TestRunner.runTest(FailsOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(FailsOnThirdAttempt.message);
+    assertThat(FailsOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = TestRunner.runTest(PassesOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  /**
+   * Used by test {@link #failsUnused()}
+   */
+  public static class FailsUnused {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesUnused()}
+   */
+  public static class PassesUnused {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnSecondAttempt()}
+   */
+  public static class FailsOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnSecondAttempt()}
+   */
+  public static class PassesOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnThirdAttempt()}
+   */
+  public static class FailsOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+
+      message = "Failing " + count;
+      fail(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnThirdAttempt()}
+   */
+  public static class PassesOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+
+      if (count < 3) {
+        message = "Failing " + count;
+        fail(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
new file mode 100755
index 0000000..6322e88
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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;
+
+/**
+ * Unit tests for {@link RetryRule} involving local scope (ie rule affects
+ * only the test methods annotated with {@code @Retry}) with failures due to
+ * an {@code Exception}.
+ *
+ * @see com.gemstone.gemfire.test.junit.Retry
+ * @see com.gemstone.gemfire.test.junit.rules.RetryRule
+ */
+@Category(UnitTest.class)
+public class RetryRuleLocalWithExceptionTest {
+
+  @Test
+  public void failsUnused() {
+    Result result = TestRunner.runTest(FailsUnused.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsUnused.message);
+    assertThat(FailsUnused.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void passesUnused() {
+    Result result = TestRunner.runTest(PassesUnused.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesUnused.count).isEqualTo(1);
+  }
+  
+  @Test
+  public void failsOnSecondAttempt() {
+    Result result = TestRunner.runTest(FailsOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsOnSecondAttempt.message);
+    assertThat(FailsOnSecondAttempt.count).isEqualTo(2);
+  }
+
+  @Test
+  public void passesOnSecondAttempt() {
+    Result result = TestRunner.runTest(PassesOnSecondAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnSecondAttempt.count).isEqualTo(2);
+  }
+  
+  @Test
+  public void failsOnThirdAttempt() {
+    Result result = TestRunner.runTest(FailsOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isFalse();
+    
+    List<Failure> failures = result.getFailures();
+    assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+    Failure failure = failures.get(0);
+    assertThat(failure.getException()).isExactlyInstanceOf(CustomException.class).hasMessage(FailsOnThirdAttempt.message);
+    assertThat(FailsOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  @Test
+  public void passesOnThirdAttempt() {
+    Result result = TestRunner.runTest(PassesOnThirdAttempt.class);
+    
+    assertThat(result.wasSuccessful()).isTrue();
+    assertThat(PassesOnThirdAttempt.count).isEqualTo(3);
+  }
+
+  /**
+   * Custom exception used by several tests
+   */
+  public static class CustomException extends Exception {
+    public CustomException(final String message) {
+      super(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #failsUnused()}
+   */
+  public static class FailsUnused {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesUnused()}
+   */
+  public static class PassesUnused {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    public void doTest() throws Exception {
+      count++;
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnSecondAttempt()}
+   */
+  public static class FailsOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnSecondAttempt()}
+   */
+  public static class PassesOnSecondAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(2)
+    public void doTest() throws Exception {
+      count++;
+      if (count < 2) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+
+  /**
+   * Used by test {@link #failsOnThirdAttempt()}
+   */
+  public static class FailsOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+
+      message = "Failing " + count;
+      throw new CustomException(message);
+    }
+  }
+
+  /**
+   * Used by test {@link #passesOnThirdAttempt()}
+   */
+  public static class PassesOnThirdAttempt {
+
+    static int count = 0;
+    static String message = null;
+
+    @BeforeClass
+    public static void beforeClass() {
+      count = 0;
+      message = null;
+    }
+    
+    @Rule
+    public RetryRule retryRule = new RetryRule();
+
+    @Test
+    @Retry(3)
+    public void doTest() throws Exception {
+      count++;
+
+      if (count < 3) {
+        message = "Failing " + count;
+        throw new CustomException(message);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
new file mode 100755
index 0000000..ce98dfe
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExternalResource;
+import org.junit.runner.Result;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Unit tests for {@link RuleList}.
+ */
+public class RuleListTest {
+
+  private static AtomicInteger counter;
+  private static Invocations[] invocations;
+
+  @BeforeClass
+  public static void setUpClass() {
+    counter = new AtomicInteger();
+    invocations = new Invocations[] { new Invocations(counter), new Invocations(counter), new Invocations(counter) };
+  }
+
+  @AfterClass
+  public static void tearDownClass() {
+    counter = null;
+    invocations = null;
+    ThreeRules.ruleListStatic = null;
+  }
+
+  @Test
+  public void firstShouldBeFirstBeforeLastAfter() {
+    Result result = TestRunner.runTest(ThreeRules.class);
+
+    assertThat(result.wasSuccessful()).isTrue();
+
+    assertThat(counter.get()).isEqualTo(9);
+
+    assertThat(invocations[0].beforeInvocation).isEqualTo(1);
+    assertThat(invocations[1].beforeInvocation).isEqualTo(2);
+    assertThat(invocations[2].beforeInvocation).isEqualTo(3);
+
+    assertThat(invocations[0].testInvocation).isEqualTo(4);
+    assertThat(invocations[1].testInvocation).isEqualTo(5);
+    assertThat(invocations[2].testInvocation).isEqualTo(6);
+
+    assertThat(invocations[2].afterInvocation).isEqualTo(7);
+    assertThat(invocations[1].afterInvocation).isEqualTo(8);
+    assertThat(invocations[0].afterInvocation).isEqualTo(9);
+  }
+
+  /**
+   * Used by test {@link #firstShouldBeFirstBeforeLastAfter()}
+   */
+  public static class ThreeRules {
+
+    static RuleList ruleListStatic;
+
+    public SpyRule ruleOne = new SpyRule("ruleOne", invocations[0]);
+    public SpyRule ruleTwo = new SpyRule("ruleTwo", invocations[1]);
+    public SpyRule ruleThree = new SpyRule("ruleThree", invocations[2]);
+
+    @Rule
+    public RuleList ruleList = new RuleList().add(ruleThree).add(ruleTwo).add(ruleOne);
+
+    @Test
+    public void doTest() throws Exception {
+      ruleListStatic = ruleList;
+      invocations[0].invokedTest();
+      invocations[1].invokedTest();
+      invocations[2].invokedTest();
+    }
+  }
+
+  /**
+   * Structure of rule callback and test invocations
+   */
+  public static class Invocations {
+
+    private final AtomicInteger counter;
+    int beforeInvocation = 0;
+    int testInvocation = 0;
+    int afterInvocation = 0;
+
+    Invocations(AtomicInteger counter) {
+      this.counter = counter;
+    }
+
+    void invokedTest() {
+      testInvocation = counter.incrementAndGet();
+    }
+    void invokedBefore() {
+      beforeInvocation = counter.incrementAndGet();
+    }
+    void invokedAfter() {
+      afterInvocation = counter.incrementAndGet();
+    }
+
+    @Override
+    public String toString() {
+      return "Invocations{" + "counter=" + counter + ", beforeInvocation=" + beforeInvocation + ", testInvocation=" + testInvocation + ", afterInvocation=" + afterInvocation + '}';
+    }
+  }
+
+  /**
+   * Implementation of TestRule that records the order of callbacks invoked on
+   * it. Used by {@link RuleListTest}.
+   */
+  public static class SpyRule extends ExternalResource {
+
+    static SpyRuleBuilder builder() {
+      return new SpyRuleBuilder();
+    }
+
+    private final String name;
+    private final Invocations invocations;
+    private final Throwable beforeThrowable;
+
+    SpyRule(String name, Invocations invocations) {
+      this.name = name;
+      this.invocations = invocations;
+      this.beforeThrowable = null;
+    }
+
+    SpyRule(SpyRuleBuilder builder) {
+      this.name = builder.name;
+      this.invocations = builder.invocations;
+      this.beforeThrowable = builder.beforeThrowable;
+    }
+
+    Invocations invocations() {
+      return this.invocations;
+    }
+
+    void test() {
+      this.invocations.invokedTest();
+    }
+
+    @Override
+    protected void before() throws Throwable {
+      this.invocations.invokedBefore();
+      if (this.beforeThrowable != null) {
+        throw this.beforeThrowable;
+      }
+    }
+
+    @Override
+    protected void after() {
+      this.invocations.invokedAfter();
+    }
+
+    @Override
+    public String toString() {
+      return "SpyRule{" + "name='" + name + '\'' + '}';
+    }
+  }
+
+  /**
+   * Builder for more control of constructing an instance of {@link SpyRule}
+   */
+  public static class SpyRuleBuilder {
+
+    String name;
+    Invocations invocations;
+    Throwable beforeThrowable;
+
+    SpyRuleBuilder withName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    SpyRuleBuilder withInvocations(Invocations invocations) {
+      this.invocations = invocations;
+      return this;
+    }
+
+    SpyRuleBuilder beforeThrows(Throwable throwable) {
+      this.beforeThrowable = throwable;
+      return this;
+    }
+
+    SpyRule build() {
+      return new SpyRule(this);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/5342935d/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
new file mode 100755
index 0000000..86addb5
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gemstone.gemfire.test.junit.rules;
+
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Request;
+import org.junit.runner.Result;
+
+/**
+ * Used by JUnit rule unit tests to execute inner test cases.
+ */
+public class TestRunner {
+
+  protected TestRunner() {
+  }
+
+  public static Result runTest(Class<?> test) {
+    JUnitCore junitCore = new JUnitCore();
+    return junitCore.run(Request.aClass(test).getRunner());
+  }
+}



Mime
View raw message