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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 5fd16a3  GEODE-6033: Support dynamic VMs in SharedErrorCollector 
(#3168)
5fd16a3 is described below

commit 5fd16a3fc2806c2496ff505b8295d202c7eb8065
Author: Kirk Lund <kl...@apache.org>
AuthorDate: Wed Feb 13 16:13:15 2019 -0800

    GEODE-6033: Support dynamic VMs in SharedErrorCollector (#3168)
    
    Make SharedErrorCollector support create and bounce VM.
---
 .../tests/SharedErrorCollectorDistributedTest.java | 357 ++++++++++++++-------
 .../test/dunit/rules/SharedErrorCollector.java     |  76 +++--
 .../geode/test/junit/runners/TestRunner.java       |  65 +++-
 3 files changed, 351 insertions(+), 147 deletions(-)

diff --git 
a/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/SharedErrorCollectorDistributedTest.java
 
b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/SharedErrorCollectorDistributedTest.java
index 0887355..6e1d1df 100644
--- 
a/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/SharedErrorCollectorDistributedTest.java
+++ 
b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/SharedErrorCollectorDistributedTest.java
@@ -14,186 +14,179 @@
  */
 package org.apache.geode.test.dunit.rules.tests;
 
-import static org.apache.geode.test.dunit.VM.DEFAULT_VM_COUNT;
 import static org.apache.geode.test.dunit.VM.getAllVMs;
 import static org.apache.geode.test.dunit.VM.getVM;
 import static org.apache.geode.test.dunit.VM.getVMCount;
+import static 
org.apache.geode.test.junit.runners.TestRunner.runTestWithExpectedFailures;
+import static 
org.apache.geode.test.junit.runners.TestRunner.runTestWithValidation;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.Matchers.is;
 
 import java.io.Serializable;
 import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.List;
 
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
-import org.junit.runner.Result;
-import org.junit.runner.notification.Failure;
 
 import org.apache.geode.test.dunit.VM;
 import org.apache.geode.test.dunit.rules.DistributedRule;
 import org.apache.geode.test.dunit.rules.SharedErrorCollector;
-import org.apache.geode.test.junit.runners.TestRunner;
 
+/**
+ * Distributed tests for {@link SharedErrorCollector}.
+ */
 @SuppressWarnings("serial")
 public class SharedErrorCollectorDistributedTest {
 
-  static final String MESSAGE = "Failure message";
+  private static final String MESSAGE = "Failure message";
 
   @Rule
   public DistributedRule distributedRule = new DistributedRule();
 
-  @Before
-  public void setUp() {
-    assertThat(getVMCount()).isGreaterThanOrEqualTo(DEFAULT_VM_COUNT);
-  }
-
   @Test
-  public void errorCollectorHasExpectedField() throws Exception {
+  public void errorCollectorHasFieldNamedErrors() throws Exception {
     Field errorsField = ErrorCollector.class.getDeclaredField("errors");
+
     
assertThat(errorsField.getDeclaringClass()).isEqualTo(ErrorCollector.class);
   }
 
   @Test
-  public void checkThatFailureInControllerIsReported() {
-    Result result = TestRunner.runTest(CheckThatFailsInController.class);
+  public void whenCheckThatFailsInController_resultIncludesError() {
+    assertFailsWithCollectedErrors(CheckThatFailsInController.class, new 
AssertionError(MESSAGE));
+  }
+
+  @Test
+  public void whenControllerAddsError_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorInController.class, new 
NullPointerException(MESSAGE));
+  }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(AssertionError.class)
-        .hasMessageContaining(MESSAGE);
+  @Test
+  public void whenCheckThatFailsInDUnitVM_resultIncludesError() {
+    assertFailsWithCollectedErrors(CheckThatFailsInDUnitVM.class, new 
AssertionError(MESSAGE));
   }
 
   @Test
-  public void addErrorInControllerIsReported() {
-    Result result = TestRunner.runTest(AddErrorInController.class);
+  public void whenCheckThatFailsInEveryDUnitVM_resultIncludesAllErrors() {
+    List<Throwable> errors = new ArrayList<>();
+    for (VM vm : getAllVMs()) {
+      errors.add(new AssertionError(MESSAGE + " in VM-" + vm.getId()));
+    }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(NullPointerException.class)
-        .hasMessage(MESSAGE);
+    assertFailsWithCollectedErrors(CheckThatFailsInEveryDUnitVM.class, errors);
   }
 
   @Test
-  public void checkThatFailureInDUnitVMIsReported() {
-    Result result = TestRunner.runTest(CheckThatFailsInDUnitVM.class);
+  public void 
whenCheckThatFailsInEveryDUnitVMAndController_resultIncludesAllErrors() {
+    List<Throwable> errors = new ArrayList<>();
+    errors.add(new AssertionError(MESSAGE + " in VM-CONTROLLER"));
+    for (VM vm : getAllVMs()) {
+      errors.add(new AssertionError(MESSAGE + " in VM-" + vm.getId()));
+    }
+
+    
assertFailsWithCollectedErrors(CheckThatFailsInEveryDUnitVMAndController.class, 
errors);
+  }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(AssertionError.class)
-        .hasMessageContaining(MESSAGE);
+  @Test
+  public void whenCheckThatFailsInMethodInDUnitVM_resultIncludesError() {
+    assertFailsWithCollectedErrors(CheckThatFailsInMethodInDUnitVM.class,
+        new AssertionError(MESSAGE));
   }
 
   @Test
-  public void checkThatFailureInEveryDUnitVMIsReported() {
-    Result result = TestRunner.runTest(CheckThatFailsInEveryDUnitVM.class);
-
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(getVMCount());
-    int i = 0;
-    for (Failure failure : failures) {
-      assertThat(failure.getException()).isInstanceOf(AssertionError.class)
-          .hasMessageContaining(MESSAGE + " in VM-" + i++);
+  public void whenDUnitVMAddsError_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorInDUnitVM.class, new 
NullPointerException(MESSAGE));
+  }
+
+  @Test
+  public void whenEveryDUnitVMAddsError_resultIncludesAllErrors() {
+    List<Throwable> errors = new ArrayList<>();
+    for (VM vm : getAllVMs()) {
+      errors.add(new NullPointerException(MESSAGE + " in VM-" + vm.getId()));
     }
+
+    assertFailsWithCollectedErrors(AddErrorInEveryDUnitVM.class, errors);
   }
 
   @Test
-  public void checkThatFailureInEveryDUnitVMAndControllerIsReported() {
-    Result result = 
TestRunner.runTest(CheckThatFailsInEveryDUnitVMAndController.class);
-
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(getVMCount() + 1);
-    boolean first = true;
-    int i = 0;
-    for (Failure failure : failures) {
-      if (first) {
-        assertThat(failure.getException()).isInstanceOf(AssertionError.class)
-            .hasMessageContaining(MESSAGE + " in VM-CONTROLLER");
-        first = false;
-      } else {
-        assertThat(failure.getException()).isInstanceOf(AssertionError.class)
-            .hasMessageContaining(MESSAGE + " in VM-" + i++);
-      }
+  public void whenEveryDUnitVMAndControllerAddsError_resultIncludesAllErrors() 
{
+    List<Throwable> errors = new ArrayList<>();
+    errors.add(new NullPointerException(MESSAGE + " in VM-CONTROLLER"));
+    for (VM vm : getAllVMs()) {
+      errors.add(new NullPointerException(MESSAGE + " in VM-" + vm.getId()));
     }
+
+    assertFailsWithCollectedErrors(AddErrorInEveryDUnitVMAndController.class, 
errors);
   }
 
   @Test
-  public void checkThatFailureInMethodInDUnitVMIsReported() {
-    Result result = TestRunner.runTest(CheckThatFailsInMethodInDUnitVM.class);
+  public void whenDUnitVMAddsErrorInMethod_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorInMethodInDUnitVM.class,
+        new NullPointerException(MESSAGE));
+  }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(AssertionError.class)
-        .hasMessageContaining(MESSAGE);
+  @Test
+  public void whenNewDUnitVMDoesNotAddError_resultIsSuccessful() {
+    assertPasses(AddDUnitVM.class);
   }
 
   @Test
-  public void addErrorInDUnitVMIsReported() {
-    Result result = TestRunner.runTest(AddErrorInDUnitVM.class);
+  public void whenNewDUnitVMAddsError_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorInNewDUnitVM.class, new 
NullPointerException(MESSAGE));
+  }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(NullPointerException.class)
-        .hasMessage(MESSAGE);
+  @Test
+  public void whenBouncedDUnitVMDoesNotAddError_resultIsSuccessful() {
+    assertPasses(BounceDUnitVM.class);
   }
 
   @Test
-  public void addErrorInEveryDUnitVMIsReported() {
-    Result result = TestRunner.runTest(AddErrorInEveryDUnitVM.class);
-
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(getVMCount());
-    int i = 0;
-    for (Failure failure : failures) {
-      
assertThat(failure.getException()).isInstanceOf(NullPointerException.class)
-          .hasMessageContaining(MESSAGE + " in VM-" + i++);
-    }
+  public void whenBouncedDUnitVMAddsErrorAfterBounce_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorInBouncedDUnitVM.class,
+        new NullPointerException(MESSAGE));
   }
 
   @Test
-  public void addErrorInEveryDUnitVMAndControllerIsReported() {
-    Result result = 
TestRunner.runTest(AddErrorInEveryDUnitVMAndController.class);
-
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(getVMCount() + 1);
-    boolean first = true;
-    int i = 0;
-    for (Failure failure : failures) {
-      if (first) {
-        
assertThat(failure.getException()).isInstanceOf(NullPointerException.class)
-            .hasMessageContaining(MESSAGE + " in VM-CONTROLLER");
-        first = false;
-      } else {
-        
assertThat(failure.getException()).isInstanceOf(NullPointerException.class)
-            .hasMessageContaining(MESSAGE + " in VM-" + i++);
-      }
-    }
+  public void whenBouncedDUnitVMAddsErrorBeforeBounce_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorBeforeBouncingDUnitVM.class,
+        new NullPointerException(MESSAGE));
+  }
+
+  @Test
+  public void 
whenBouncedDUnitVMAddsErrorBeforeAndAfterBounce_resultIncludesError() {
+    assertFailsWithCollectedErrors(AddErrorBeforeAndAfterBouncingDUnitVM.class,
+        new NullPointerException(MESSAGE + "-before"),
+        new NullPointerException(MESSAGE + "-after"));
+  }
+
+  @Test
+  public void whenCheckSucceedsDoesNotThrow_resultIsSuccessful() {
+    assertPasses(CheckSucceedsDoesNotThrow.class);
   }
 
   @Test
-  public void addErrorInMethodInDUnitVMIsReported() {
-    Result result = TestRunner.runTest(AddErrorInMethodInDUnitVM.class);
+  public void whenCheckSucceedsThrows_resultIncludesError() {
+    assertFailsWithCollectedErrors(CheckSucceedsThrows.class, new 
NullPointerException(MESSAGE));
+  }
+
+  private void assertPasses(final Class<?> test) {
+    runTestWithValidation(test);
+  }
+
+  private void assertFailsWithCollectedErrors(final Class<?> test,
+      final Throwable... collectedErrors) {
+    runTestWithExpectedFailures(test, collectedErrors);
+  }
 
-    assertThat(result.wasSuccessful()).isFalse();
-    List<Failure> failures = result.getFailures();
-    assertThat(failures).hasSize(1);
-    
assertThat(failures.get(0).getException()).isInstanceOf(NullPointerException.class)
-        .hasMessage(MESSAGE);
+  private void assertFailsWithCollectedErrors(final Class<?> test,
+      final List<Throwable> collectedErrors) {
+    runTestWithExpectedFailures(test, collectedErrors);
   }
 
   /**
-   * Used by test {@link #checkThatFailureInControllerIsReported()}
+   * Used by test {@link #whenCheckThatFailsInController_resultIncludesError()}
    */
   public static class CheckThatFailsInController {
 
@@ -207,7 +200,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #addErrorInControllerIsReported()}
+   * Used by test {@link #whenControllerAddsError_resultIncludesError()}
    */
   public static class AddErrorInController {
 
@@ -221,7 +214,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #checkThatFailureInDUnitVMIsReported()}
+   * Used by test {@link #whenCheckThatFailsInDUnitVM_resultIncludesError()}
    */
   public static class CheckThatFailsInDUnitVM implements Serializable {
 
@@ -235,7 +228,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #checkThatFailureInEveryDUnitVMIsReported()}
+   * Used by test {@link 
#whenCheckThatFailsInEveryDUnitVM_resultIncludesAllErrors()}
    */
   public static class CheckThatFailsInEveryDUnitVM implements Serializable {
 
@@ -252,7 +245,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link 
#checkThatFailureInEveryDUnitVMAndControllerIsReported()}
+   * Used by test {@link 
#whenCheckThatFailsInEveryDUnitVMAndController_resultIncludesAllErrors()}
    */
   public static class CheckThatFailsInEveryDUnitVMAndController implements 
Serializable {
 
@@ -270,7 +263,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #checkThatFailureInMethodInDUnitVMIsReported()}
+   * Used by test {@link 
#whenCheckThatFailsInMethodInDUnitVM_resultIncludesError()}
    */
   public static class CheckThatFailsInMethodInDUnitVM implements Serializable {
 
@@ -288,7 +281,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #addErrorInDUnitVMIsReported()}
+   * Used by test {@link #whenDUnitVMAddsError_resultIncludesError()}
    */
   public static class AddErrorInDUnitVM implements Serializable {
 
@@ -302,7 +295,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #addErrorInEveryDUnitVMIsReported()}
+   * Used by test {@link #whenEveryDUnitVMAddsError_resultIncludesAllErrors()}
    */
   public static class AddErrorInEveryDUnitVM implements Serializable {
 
@@ -319,7 +312,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #addErrorInEveryDUnitVMAndControllerIsReported()}
+   * Used by test {@link 
#whenEveryDUnitVMAndControllerAddsError_resultIncludesAllErrors()}
    */
   public static class AddErrorInEveryDUnitVMAndController implements 
Serializable {
 
@@ -337,7 +330,7 @@ public class SharedErrorCollectorDistributedTest {
   }
 
   /**
-   * Used by test {@link #addErrorInMethodInDUnitVMIsReported()}
+   * Used by test {@link #whenDUnitVMAddsErrorInMethod_resultIncludesError()}
    */
   public static class AddErrorInMethodInDUnitVM implements Serializable {
 
@@ -353,4 +346,128 @@ public class SharedErrorCollectorDistributedTest {
       errorCollector.addError(new NullPointerException(MESSAGE));
     }
   }
+
+  /**
+   * Used by test {@link #whenNewDUnitVMDoesNotAddError_resultIsSuccessful()}
+   */
+  public static class AddDUnitVM implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void addDUnitVM() {
+      int startingVMCount = getVMCount();
+
+      getVM(getVMCount());
+
+      assertThat(getVMCount()).isGreaterThan(startingVMCount);
+    }
+  }
+
+  /**
+   * Used by test {@link #whenNewDUnitVMAddsError_resultIncludesError()}
+   */
+  public static class AddErrorInNewDUnitVM implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void exceptionInNewDUnitVM() {
+      getVM(getVMCount()).invoke(() -> errorCollector.addError(new 
NullPointerException(MESSAGE)));
+    }
+  }
+
+  /**
+   * Used by test {@link 
#whenBouncedDUnitVMDoesNotAddError_resultIsSuccessful()}
+   */
+  public static class BounceDUnitVM implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void addDUnitVM() {
+      getVM(0).bounce();
+    }
+  }
+
+  /**
+   * Used by test {@link 
#whenBouncedDUnitVMAddsErrorAfterBounce_resultIncludesError()}
+   */
+  public static class AddErrorInBouncedDUnitVM implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void exceptionInBouncedDUnitVM() {
+      getVM(0).bounce();
+      getVM(0).invoke(() -> errorCollector.addError(new 
NullPointerException(MESSAGE)));
+    }
+  }
+
+  /**
+   * Used by test {@link 
#whenBouncedDUnitVMAddsErrorBeforeBounce_resultIncludesError()}
+   */
+  public static class AddErrorBeforeBouncingDUnitVM implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void exceptionInBouncedDUnitVM() {
+      getVM(0).invoke(() -> errorCollector.addError(new 
NullPointerException(MESSAGE)));
+      getVM(0).bounce();
+    }
+  }
+
+  /**
+   * Used by test {@link 
#whenBouncedDUnitVMAddsErrorBeforeAndAfterBounce_resultIncludesError()}
+   */
+  public static class AddErrorBeforeAndAfterBouncingDUnitVM implements 
Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void exceptionInBouncedDUnitVM() {
+      getVM(0).invoke(() -> errorCollector.addError(new 
NullPointerException(MESSAGE + "-before")));
+      getVM(0).bounce();
+      getVM(0).invoke(() -> errorCollector.addError(new 
NullPointerException(MESSAGE + "-after")));
+    }
+  }
+
+  /**
+   * Used by test {@link #whenCheckSucceedsDoesNotThrow_resultIsSuccessful()}
+   */
+  public static class CheckSucceedsDoesNotThrow implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void checkSucceeds() {
+      Object result = errorCollector.checkSucceeds(() -> new Object());
+
+      assertThat(result).isNotNull();
+    }
+  }
+
+  /**
+   * Used by test {@link #whenCheckSucceedsThrows_resultIncludesError()}
+   */
+  public static class CheckSucceedsThrows implements Serializable {
+
+    @Rule
+    public SharedErrorCollector errorCollector = new SharedErrorCollector();
+
+    @Test
+    public void checkSucceeds() {
+      errorCollector.checkSucceeds(() -> {
+        throw new NullPointerException(MESSAGE);
+      });
+    }
+  }
 }
diff --git 
a/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/SharedErrorCollector.java
 
b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/SharedErrorCollector.java
index 9afc08d..464885a 100644
--- 
a/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/SharedErrorCollector.java
+++ 
b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/SharedErrorCollector.java
@@ -18,7 +18,10 @@ import static org.apache.geode.test.dunit.VM.getAllVMs;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Callable;
 
 import org.hamcrest.Matcher;
@@ -53,10 +56,11 @@ import org.apache.geode.test.dunit.VM;
  * For a more thorough example, please see
  * {@code org.apache.geode.cache.ReplicateCacheListenerDistributedTest} in the 
tests of geode-core.
  */
-@SuppressWarnings("serial,unused")
 public class SharedErrorCollector extends AbstractDistributedRule {
 
-  private static volatile ProtectedErrorCollector errorCollector;
+  private static volatile VisibleErrorCollector errorCollector;
+
+  private final Map<Integer, List<Throwable>> beforeBounceErrors = new 
HashMap<>();
 
   public SharedErrorCollector() {
     // nothing
@@ -64,16 +68,15 @@ public class SharedErrorCollector extends 
AbstractDistributedRule {
 
   @Override
   protected void before() {
-    invoker().invokeInEveryVMAndController(() -> errorCollector = new 
ProtectedErrorCollector());
+    invoker().invokeInEveryVMAndController(() -> invokeBefore());
   }
 
   @Override
   protected void after() throws Throwable {
-    ProtectedErrorCollector allErrors = errorCollector;
+    VisibleErrorCollector allErrors = errorCollector;
     try {
       for (VM vm : getAllVMs()) {
-        List<Throwable> remoteFailures = new ArrayList<>();
-        remoteFailures.addAll(vm.invoke(() -> errorCollector.errors()));
+        List<Throwable> remoteFailures = new ArrayList<>(vm.invoke(() -> 
errorCollector.errors()));
         for (Throwable t : remoteFailures) {
           allErrors.addError(t);
         }
@@ -84,6 +87,25 @@ public class SharedErrorCollector extends 
AbstractDistributedRule {
     }
   }
 
+  @Override
+  protected void afterCreateVM(VM vm) {
+    vm.invoke(() -> invokeBefore());
+  }
+
+  @Override
+  protected void beforeBounceVM(VM vm) {
+    beforeBounceErrors.put(vm.getId(), vm.invoke(() -> 
errorCollector.errors()));
+  }
+
+  @Override
+  protected void afterBounceVM(VM vm) {
+    List<Throwable> beforeBounceErrorsForVM = 
beforeBounceErrors.remove(vm.getId());
+    vm.invoke(() -> {
+      invokeBefore();
+      errorCollector.addErrors(beforeBounceErrorsForVM);
+    });
+  }
+
   /**
    * @see ErrorCollector#addError(Throwable)
    */
@@ -112,31 +134,43 @@ public class SharedErrorCollector extends 
AbstractDistributedRule {
     return errorCollector.checkSucceeds(callable);
   }
 
+  private void invokeBefore() {
+    errorCollector = new VisibleErrorCollector();
+  }
+
   /**
-   * Uses reflection to acquire access to the {@code List} of {@code 
Throwable}s in
-   * {@link ErrorCollector}.
+   * Increases visibility of {@link #verify()} to public and uses reflection 
to acquire access to
+   * the {@code List} of {@code Throwable}s in {@link ErrorCollector}.
    */
-  private static class ProtectedErrorCollector extends ErrorCollector {
+  private static class VisibleErrorCollector extends ErrorCollector {
+
+    private final List<Throwable> visibleErrors;
+
+    private VisibleErrorCollector() {
+      visibleErrors = getErrorsReference();
+    }
+
+    @Override
+    public void verify() throws Throwable {
+      super.verify();
+    }
 
-    private final List<Throwable> protectedErrors;
+    List<Throwable> errors() {
+      return visibleErrors;
+    }
+
+    void addErrors(Collection<Throwable> errors) {
+      visibleErrors.addAll(errors);
+    }
 
-    ProtectedErrorCollector() {
+    private List<Throwable> getErrorsReference() {
       try {
         Field superErrors = ErrorCollector.class.getDeclaredField("errors");
         superErrors.setAccessible(true);
-        protectedErrors = (List<Throwable>) superErrors.get(this);
+        return (List<Throwable>) superErrors.get(this);
       } catch (IllegalAccessException | NoSuchFieldException e) {
         throw new RuntimeException(e);
       }
     }
-
-    List<Throwable> errors() {
-      return protectedErrors;
-    }
-
-    @Override
-    public void verify() throws Throwable {
-      super.verify();
-    }
   }
 }
diff --git 
a/geode-junit/src/main/java/org/apache/geode/test/junit/runners/TestRunner.java 
b/geode-junit/src/main/java/org/apache/geode/test/junit/runners/TestRunner.java
index ca8a23f..0f3a875 100755
--- 
a/geode-junit/src/main/java/org/apache/geode/test/junit/runners/TestRunner.java
+++ 
b/geode-junit/src/main/java/org/apache/geode/test/junit/runners/TestRunner.java
@@ -14,10 +14,14 @@
  */
 package org.apache.geode.test.junit.runners;
 
+import static java.util.Arrays.asList;
+import static java.util.Objects.hash;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
+import org.assertj.core.util.Streams;
 import org.junit.runner.JUnitCore;
 import org.junit.runner.Request;
 import org.junit.runner.Result;
@@ -28,14 +32,16 @@ import org.junit.runner.notification.Failure;
  */
 public class TestRunner {
 
-  protected TestRunner() {}
+  private TestRunner() {
+    // do not instantiate
+  }
 
-  public static Result runTest(final Class<?> test) {
+  public static Result runTest(Class<?> test) {
     JUnitCore junitCore = new JUnitCore();
     return junitCore.run(Request.aClass(test).getRunner());
   }
 
-  public static Result runTestWithValidation(final Class<?> test) {
+  public static Result runTestWithValidation(Class<?> test) {
     JUnitCore junitCore = new JUnitCore();
     Result result = junitCore.run(Request.aClass(test).getRunner());
 
@@ -50,7 +56,7 @@ public class TestRunner {
     return result;
   }
 
-  public static Failure runTestWithExpectedFailure(final Class<?> test) {
+  public static Failure runTestWithExpectedFailure(Class<?> test) {
     JUnitCore junitCore = new JUnitCore();
     Result result = junitCore.run(Request.aClass(test).getRunner());
 
@@ -60,13 +66,60 @@ public class TestRunner {
     return failures.get(0);
   }
 
-  public static List<Failure> runTestWithExpectedFailures(final Class<?> test) 
{
+  public static List<Failure> runTestWithExpectedFailures(Class<?> test,
+      Throwable... expectedThrowables) {
+    return runTestWithExpectedFailures(test, asList(expectedThrowables));
+  }
+
+  public static List<Failure> runTestWithExpectedFailures(Class<?> test,
+      List<Throwable> expectedThrowables) {
+    List<FailureInfo> expectedFailures = Streams.stream(expectedThrowables)
+        .map(f -> new FailureInfo(f.getClass(), f.getMessage()))
+        .collect(Collectors.toList());
+
     JUnitCore junitCore = new JUnitCore();
     Result result = junitCore.run(Request.aClass(test).getRunner());
 
     List<Failure> failures = result.getFailures();
-    assertThat(failures).isNotEmpty();
+    assertThat(failures).as("Actual failures").hasSameSizeAs(expectedFailures);
+
+    List<FailureInfo> actualFailures = Streams.stream(failures)
+        .map(f -> new FailureInfo(f.getException().getClass(), f.getMessage()))
+        .collect(Collectors.toList());
+
+    assertThat(actualFailures).as("Actual failures info (Throwable and 
message)").hasSameElementsAs(
+        expectedFailures);
 
     return failures;
   }
+
+  private static class FailureInfo {
+
+    final Class<? extends Throwable> thrownClass;
+    final String expectedMessage;
+
+    FailureInfo(Class<? extends Throwable> thrownClass, String 
expectedMessage) {
+      this.thrownClass = thrownClass;
+      this.expectedMessage = expectedMessage;
+    }
+
+    @Override
+    public int hashCode() {
+      return hash(thrownClass, expectedMessage);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj) {
+        return true;
+      }
+      if (obj == null || getClass() != obj.getClass()) {
+        return false;
+      }
+      FailureInfo that = (FailureInfo) obj;
+      return thrownClass.equals(that.thrownClass) &&
+          (expectedMessage.contains(that.expectedMessage) ||
+              that.expectedMessage.contains(expectedMessage));
+    }
+  }
 }

Reply via email to