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 2016/02/23 21:24:27 UTC

[91/94] [abbrv] incubator-geode git commit: Merge remote-tracking branch 'origin/develop' into feature/GEODE-953

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/504a222f/geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
----------------------------------------------------------------------
diff --cc geode-junit/src/main/java/com/gemstone/gemfire/test/junit/support/DefaultIgnoreCondition.java
index 0000000,b721c41..67177d2
mode 000000,100755..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
@@@ -1,0 -1,57 +1,57 @@@
+ /*
+  * 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.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;
++    return this.ignore;
+   }
+ 
+   @Override
+   public boolean evaluate(final Description testCaseDescription) {
+     return isIgnore();
+   }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
index 0000000,0000000..5a0d45c
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRuleTest.java
@@@ -1,0 -1,0 +1,249 @@@
++/*
++ * 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}.
++ * 
++ * @author Kirk Lund
++ * @since 8.2
++ */
++@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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
index 0000000,0000000..9d99971
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRuleTest.java
@@@ -1,0 -1,0 +1,147 @@@
++/*
++ * 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}.
++ * 
++ * @author Kirk Lund
++ */
++@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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
index 0000000,0000000..e22a87a
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRuleTest.java
@@@ -1,0 -1,0 +1,413 @@@
++/*
++ * 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}.
++ * 
++ * @author Kirk Lund
++ */
++@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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
index 0000000,0000000..75d5a60
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithErrorTest.java
@@@ -1,0 -1,0 +1,327 @@@
++/*
++ * 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}.
++ * 
++ * @author Kirk Lund
++ * @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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
index 0000000,0000000..b060820
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleGlobalWithExceptionTest.java
@@@ -1,0 -1,0 +1,333 @@@
++/*
++ * 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}.
++ * 
++ * @author Kirk Lund
++ * @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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
index 0000000,0000000..a57462e
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithErrorTest.java
@@@ -1,0 -1,0 +1,267 @@@
++/*
++ * 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}.
++ *
++ * @author Kirk Lund
++ */
++@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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
index 0000000,0000000..48e34d2
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRuleLocalWithExceptionTest.java
@@@ -1,0 -1,0 +1,277 @@@
++/*
++ * 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}.
++ *
++ * @author Kirk Lund
++ * @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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
index 0000000,0000000..0ae23f1
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RuleListTest.java
@@@ -1,0 -1,0 +1,215 @@@
++/*
++ * 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 beforeClassThrowable;
++    private final Throwable beforeThrowable;
++
++    SpyRule(String name, Invocations invocations) {
++      this.name = name;
++      this.invocations = invocations;
++      this.beforeClassThrowable = null;
++      this.beforeThrowable = null;
++    }
++
++    SpyRule(SpyRuleBuilder builder) {
++      this.name = builder.name;
++      this.invocations = builder.invocations;
++      this.beforeClassThrowable = builder.beforeClassThrowable;
++      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 beforeClassThrowable;
++    Throwable beforeThrowable;
++
++    SpyRuleBuilder withName(String name) {
++      this.name = name;
++      return this;
++    }
++
++    SpyRuleBuilder withInvocations(Invocations invocations) {
++      this.invocations = invocations;
++      return this;
++    }
++
++    SpyRuleBuilder beforeClassThrows(Throwable throwable) {
++      this.beforeClassThrowable = throwable;
++      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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestFixtureRuleTest.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestFixtureRuleTest.java
index 0000000,0000000..a3ab5ed
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestFixtureRuleTest.java
@@@ -1,0 -1,0 +1,384 @@@
++/*
++ * 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.ClassRule;
++import org.junit.Rule;
++import org.junit.Test;
++import org.junit.runner.Result;
++
++/**
++ * Unit tests for {@link TestFixtureRule}.
++ */
++public class TestFixtureRuleTest {
++
++  @Test
++  public void methodRuleAndClassRuleShouldInvokeCallbacksInOrder() {
++    Result result = TestRunner.runTest(MethodRuleAndClassRuleInvocations.class);
++
++    assertThat(result.wasSuccessful()).isTrue();
++    assertThat(MethodRuleAndClassRuleInvocations.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(MethodRuleAndClassRuleInvocations.invocations().beforeInvocation).isEqualTo(2);
++    assertThat(MethodRuleAndClassRuleInvocations.invocations().testInvocation).isEqualTo(3);
++    assertThat(MethodRuleAndClassRuleInvocations.invocations().afterInvocation).isEqualTo(4);
++    assertThat(MethodRuleAndClassRuleInvocations.invocations().afterClassInvocation).isEqualTo(5);
++  }
++
++  @Test
++  public void methodRuleShouldInvokeCallbacksInOrder() {
++    Result result = TestRunner.runTest(MethodRuleInvocations.class);
++
++    assertThat(result.wasSuccessful()).isTrue();
++    assertThat(MethodRuleInvocations.invocations().beforeClassInvocation).isEqualTo(0);
++    assertThat(MethodRuleInvocations.invocations().beforeInvocation).isEqualTo(1);
++    assertThat(MethodRuleInvocations.invocations().testInvocation).isEqualTo(2);
++    assertThat(MethodRuleInvocations.invocations().afterInvocation).isEqualTo(3);
++    assertThat(MethodRuleInvocations.invocations().afterClassInvocation).isEqualTo(0);
++  }
++
++  @Test
++  public void classRuleShouldInvokeCallbacksInOrder() {
++    Result result = TestRunner.runTest(ClassRuleInvocations.class);
++
++    assertThat(result.wasSuccessful()).isTrue();
++    assertThat(ClassRuleInvocations.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(ClassRuleInvocations.invocations().beforeInvocation).isEqualTo(0);
++    assertThat(ClassRuleInvocations.invocations().testInvocation).isEqualTo(2);
++    assertThat(ClassRuleInvocations.invocations().afterInvocation).isEqualTo(0);
++    assertThat(ClassRuleInvocations.invocations().afterClassInvocation).isEqualTo(3);
++  }
++
++  @Test
++  public void beforeClassThrowsExceptionShouldSkipBeforeTestAndAfterClass() {
++    Result result = TestRunner.runTest(BeforeClassThrowsException.class);
++
++    assertThat(result.wasSuccessful()).isFalse();
++    assertThat(BeforeClassThrowsException.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(BeforeClassThrowsException.invocations().beforeInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsException.invocations().testInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsException.invocations().afterInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsException.invocations().afterClassInvocation).isEqualTo(0);
++  }
++
++  @Test
++  public void beforeClassThrowsErrorShouldSkipBeforeTestAndAfterClass() {
++    Result result = TestRunner.runTest(BeforeClassThrowsError.class);
++
++    assertThat(result.wasSuccessful()).isFalse();
++    assertThat(BeforeClassThrowsError.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(BeforeClassThrowsError.invocations().beforeInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsError.invocations().testInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsError.invocations().afterInvocation).isEqualTo(0);
++    assertThat(BeforeClassThrowsError.invocations().afterClassInvocation).isEqualTo(0);
++  }
++
++  @Test
++  public void beforeThrowsExceptionShouldSkipTestAndAfter() {
++    Result result = TestRunner.runTest(BeforeThrowsException.class);
++
++    assertThat(result.wasSuccessful()).isFalse();
++    assertThat(BeforeThrowsException.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(BeforeThrowsException.invocations().beforeInvocation).isEqualTo(2);
++    assertThat(BeforeThrowsException.invocations().testInvocation).isEqualTo(0);
++    assertThat(BeforeThrowsException.invocations().afterInvocation).isEqualTo(0);
++    assertThat(BeforeThrowsException.invocations().afterClassInvocation).isEqualTo(3);
++  }
++
++  @Test
++  public void beforeThrowsErrorShouldSkipTestAndAfter() {
++    Result result = TestRunner.runTest(BeforeThrowsError.class);
++
++    assertThat(result.wasSuccessful()).isFalse();
++    assertThat(BeforeThrowsError.invocations().beforeClassInvocation).isEqualTo(1);
++    assertThat(BeforeThrowsError.invocations().beforeInvocation).isEqualTo(2);
++    assertThat(BeforeThrowsError.invocations().testInvocation).isEqualTo(0);
++    assertThat(BeforeThrowsError.invocations().afterInvocation).isEqualTo(0);
++    assertThat(BeforeThrowsError.invocations().afterClassInvocation).isEqualTo(3);
++  }
++
++  /**
++   * Used by test {@link #methodRuleAndClassRuleShouldInvokeCallbacksInOrder()}
++   */
++  public static class MethodRuleAndClassRuleInvocations {
++
++    @ClassRule
++    public static SpyRule staticRule = new SpyRule(new Invocations());
++
++    @Rule
++    public SpyRule rule = staticRule;
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  /**
++   * Used by test {@link #classRuleShouldInvokeCallbacksInOrder()}
++   */
++  public static class ClassRuleInvocations {
++
++    @ClassRule
++    public static SpyRule staticRule = new SpyRule(new Invocations());
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      staticRule.test();
++    }
++  }
++
++  /**
++   * Used by test {@link #methodRuleShouldInvokeCallbacksInOrder()}
++   */
++  public static class MethodRuleInvocations {
++
++    // do NOT use @ClassRule
++    static SpyRule staticSpy = new SpyRule(new Invocations());
++
++    @Rule
++    public SpyRule rule = staticSpy;
++
++    static Invocations invocations() {
++      return staticSpy.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  public static class BeforeClassThrowsException {
++
++    static final Throwable throwable = new Exception("Thrown by BeforeClassThrowsException");
++
++    @ClassRule
++    public static SpyRule staticRule = SpyRule.builder()
++        .withInvocations(new Invocations())
++        .beforeClassThrows(throwable)
++        .build();
++
++    @Rule
++    public SpyRule rule = staticRule;
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  public static class BeforeClassThrowsError {
++
++    static final Throwable throwable = new Error("Thrown by BeforeClassThrowsError");
++
++    @ClassRule
++    public static SpyRule staticRule = SpyRule.builder()
++        .withInvocations(new Invocations())
++        .beforeClassThrows(throwable)
++        .build();
++
++    @Rule
++    public SpyRule rule = staticRule;
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  public static class BeforeThrowsException {
++
++    static final Throwable throwable = new Exception("Thrown by BeforeThrowsException");
++
++    @ClassRule
++    public static SpyRule staticRule = SpyRule.builder()
++      .withInvocations(new Invocations())
++      .beforeThrows(throwable)
++      .build();
++
++    @Rule
++    public SpyRule rule = staticRule;
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  public static class BeforeThrowsError {
++
++    static final Throwable throwable = new Error("Thrown by BeforeThrowsError");
++
++    @ClassRule
++    public static SpyRule staticRule = SpyRule.builder()
++        .withInvocations(new Invocations())
++        .beforeThrows(throwable)
++        .build();
++
++    @Rule
++    public SpyRule rule = staticRule;
++
++    static Invocations invocations() {
++      return staticRule.invocations;
++    }
++
++    @Test
++    public void doTest() throws Exception {
++      rule.test();
++    }
++  }
++
++  /**
++   * Structure of rule callback and test invocations
++   */
++  public static class Invocations {
++    int invocation = 0;
++    int beforeClassInvocation = 0;
++    int afterClassInvocation = 0;
++    int beforeInvocation = 0;
++    int afterInvocation = 0;
++    int testInvocation = 0;
++
++    void invokedTest() {
++      testInvocation = ++invocation;
++    }
++    void invokedBeforeClass() {
++      beforeClassInvocation = ++invocation;
++    }
++    void invokedAfterClass() {
++      afterClassInvocation = ++invocation;
++    }
++    void invokedBefore() {
++      beforeInvocation = ++invocation;
++    }
++    void invokedAfter() {
++      afterInvocation = ++invocation;
++    }
++  }
++
++  /**
++   * Implementation of TestRule that records the order of callbacks invoked on
++   * it. Used by {@link TestFixtureRuleTest}.
++   */
++  public static class SpyRule extends TestFixtureRule {
++
++    static SpyRuleBuilder builder() {
++      return new SpyRuleBuilder();
++    }
++
++    private final Invocations invocations;
++    private final Throwable beforeClassThrowable;
++    private final Throwable beforeThrowable;
++
++    SpyRule(Invocations invocations) {
++      this.invocations = invocations;
++      this.beforeClassThrowable = null;
++      this.beforeThrowable = null;
++    }
++
++    SpyRule(SpyRuleBuilder builder) {
++      this.invocations = builder.invocations;
++      this.beforeClassThrowable = builder.beforeClassThrowable;
++      this.beforeThrowable = builder.beforeThrowable;
++    }
++
++    Invocations invocations() {
++      return this.invocations;
++    }
++
++    void test() {
++      this.invocations.invokedTest();
++    }
++
++    @Override
++    protected void beforeClass() throws Throwable {
++      this.invocations.invokedBeforeClass();
++      if (this.beforeClassThrowable != null) {
++        throw this.beforeClassThrowable;
++      }
++    }
++
++    @Override
++    protected void afterClass() {
++      this.invocations.invokedAfterClass();
++    }
++
++    @Override
++    protected void before() throws Throwable {
++      this.invocations.invokedBefore();
++      if (this.beforeThrowable != null) {
++        throw this.beforeThrowable;
++      }
++    }
++
++    @Override
++    protected void after() {
++      this.invocations.invokedAfter();
++    }
++  }
++
++  /**
++   * Builder for more control of constructing an instance of {@link SpyRule}
++   */
++  public static class SpyRuleBuilder {
++
++    Invocations invocations;
++    Throwable beforeClassThrowable;
++    Throwable beforeThrowable;
++
++    SpyRuleBuilder withInvocations(Invocations invocations) {
++      this.invocations = invocations;
++      return this;
++    }
++
++    SpyRuleBuilder beforeClassThrows(Throwable throwable) {
++      this.beforeClassThrowable = throwable;
++      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/504a222f/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
----------------------------------------------------------------------
diff --cc geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
index 0000000,0000000..86addb5
new file mode 100755
--- /dev/null
+++ b/geode-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/TestRunner.java
@@@ -1,0 -1,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());
++  }
++}