You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by bu...@apache.org on 2020/10/30 16:32:11 UTC
[geode] 02/03: GEODE-8540: Create new DistributedBlackboard Rule
(#5557)
This is an automated email from the ASF dual-hosted git repository.
burcham pushed a commit to branch backport-1-13-GEODE-8652-and-friends
in repository https://gitbox.apache.org/repos/asf/geode.git
commit 9a066e64b1722f914994fecb454a2f67f2a46148
Author: Kirk Lund <kl...@apache.org>
AuthorDate: Wed Sep 30 09:39:30 2020 -0700
GEODE-8540: Create new DistributedBlackboard Rule (#5557)
Package up DUnitBlackboard as a JUnit Rule named DistributedBlackboard.
(cherry picked from commit 26cb822f2ee467545dd708ecc867cebbd2473c70)
---
.../dunit/internal/DUnitBlackboardDUnitTest.java | 75 +++---
.../DistributedBlackboardDistributedTest.java | 297 +++++++++++++++++++++
.../InternalBlackboard.java => Blackboard.java} | 54 ++--
.../apache/geode/test/dunit/DUnitBlackboard.java | 55 ++--
.../test/dunit/internal/InternalBlackboard.java | 33 ++-
.../dunit/internal/InternalBlackboardImpl.java | 59 ++--
.../test/dunit/rules/DistributedBlackboard.java | 138 ++++++++++
7 files changed, 584 insertions(+), 127 deletions(-)
diff --git a/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/internal/DUnitBlackboardDUnitTest.java b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/internal/DUnitBlackboardDUnitTest.java
index ae78247..5e151d7 100755
--- a/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/internal/DUnitBlackboardDUnitTest.java
+++ b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/internal/DUnitBlackboardDUnitTest.java
@@ -14,83 +14,70 @@
*/
package org.apache.geode.test.dunit.internal;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.test.dunit.VM.getVM;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
-import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.VM;
-
+@SuppressWarnings("serial")
public class DUnitBlackboardDUnitTest extends JUnit4DistributedTestCase {
+
@Test
- public void canPassDataBetweenVMs() throws Exception {
+ public void canPassDataBetweenVMs() {
final String MBOX = "myMailbox";
- VM vm0 = Host.getHost(0).getVM(0);
- VM vm1 = Host.getHost(0).getVM(1);
+ VM vm0 = getVM(0);
+ VM vm1 = getVM(1);
vm0.invoke("put data in mailbox", () -> getBlackboard().setMailbox(MBOX, "testing"));
- String result = (String) vm1.invoke("get data from mailbox", () -> {
- return getBlackboard().getMailbox(MBOX);
- });
+ String result = vm1.invoke("get data from mailbox", () -> getBlackboard().getMailbox(MBOX));
- assertEquals("testing", result);
+ assertThat(result).isEqualTo("testing");
}
@Test
- public void canSignalAnotherVM() throws Exception {
+ public void canSignalAnotherVM() {
final String GATE = "myGate";
- VM vm0 = Host.getHost(0).getVM(0);
- VM vm1 = Host.getHost(0).getVM(1);
+ VM vm0 = getVM(0);
+ VM vm1 = getVM(1);
vm1.invoke("wait on gate not yet signalled", () -> {
- assertFalse(getBlackboard().isGateSignaled(GATE));
- try {
- getBlackboard().waitForGate(GATE, 1, TimeUnit.SECONDS);
- } catch (TimeoutException e) {
- // expected
- return;
- } catch (InterruptedException e) {
- fail("unexpected interrupt");
- }
- fail("unexpected success");
+ assertThat(getBlackboard().isGateSignaled(GATE)).isFalse();
+
+ Throwable thrown = catchThrowable(() -> {
+ getBlackboard().waitForGate(GATE, 1, SECONDS);
+ });
+
+ assertThat(thrown).isInstanceOf(TimeoutException.class);
});
vm0.invoke("signal gate", () -> getBlackboard().signalGate(GATE));
- vm1.invoke("wait on gate not yet signalled", () -> {
- try {
- getBlackboard().waitForGate(GATE, 1, TimeUnit.SECONDS);
- } catch (TimeoutException e) {
- fail("unexpected timeout");
- } catch (InterruptedException e) {
- fail("unexpected interrupt");
- }
- // success expected
- });
+ vm1.invoke("wait on gate not yet signalled",
+ () -> getBlackboard().waitForGate(GATE, 1, SECONDS));
}
@Test
- public void initBlackboardClearsEverything() throws Exception {
+ public void initBlackboardClearsEverything() {
for (int i = 0; i < 100; i++) {
getBlackboard().setMailbox("MBOX" + i, "value" + i);
- assertEquals("value" + i, getBlackboard().getMailbox("MBOX" + i));
+ assertThat((Object) getBlackboard().getMailbox("MBOX" + i)).isEqualTo("value" + i);
+
getBlackboard().signalGate("GATE" + i);
- assertTrue(getBlackboard().isGateSignaled("GATE" + i));
+ assertThat(getBlackboard().isGateSignaled("GATE" + i)).isTrue();
}
- Host.getHost(0).getVM(1).invoke("clear blackboard", () -> getBlackboard().initBlackboard());
+
+ getVM(1).invoke("clear blackboard", () -> getBlackboard().initBlackboard());
for (int i = 0; i < 100; i++) {
- assertNull(getBlackboard().getMailbox("MBOX" + i));
- assertFalse(getBlackboard().isGateSignaled("GATE" + i));
+ assertThat((Object) getBlackboard().getMailbox("MBOX" + i)).isNull();
+ assertThat(getBlackboard().isGateSignaled("GATE" + i)).isFalse();
}
}
}
diff --git a/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/DistributedBlackboardDistributedTest.java b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/DistributedBlackboardDistributedTest.java
new file mode 100644
index 0000000..ea3ed2e
--- /dev/null
+++ b/geode-dunit/src/distributedTest/java/org/apache/geode/test/dunit/rules/tests/DistributedBlackboardDistributedTest.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.dunit.rules.tests;
+
+import static java.util.Arrays.asList;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.test.dunit.VM.getController;
+import static org.apache.geode.test.dunit.VM.getVM;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import java.io.Serializable;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.rules.DistributedBlackboard;
+import org.apache.geode.test.dunit.rules.DistributedRule;
+import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+
+@SuppressWarnings({"serial", "CodeBlock2Expr"})
+public class DistributedBlackboardDistributedTest implements Serializable {
+
+ @Rule
+ public DistributedRule distributedRule = new DistributedRule();
+ @Rule
+ public DistributedBlackboard blackboard = new DistributedBlackboard();
+ @Rule
+ public SerializableTestName testName = new SerializableTestName();
+
+ @Test
+ public void canPassDataBetweenVMs() {
+ VM vm0 = getVM(0);
+ VM vm1 = getVM(1);
+
+ vm0.invoke("put data in mailbox", () -> blackboard.setMailbox(mailbox(), value()));
+
+ String result = vm1.invoke("get data from mailbox", () -> blackboard.getMailbox(mailbox()));
+
+ assertThat(result).isEqualTo(value());
+ }
+
+ @Test
+ public void canSignalAnotherVM() {
+ VM vm0 = getVM(0);
+ VM vm1 = getVM(1);
+
+ vm1.invoke("wait on gate not yet signalled", () -> {
+ assertThat(blackboard.isGateSignaled(gate())).isFalse();
+
+ Throwable thrown = catchThrowable(() -> {
+ blackboard.waitForGate(gate(), 1, SECONDS);
+ });
+
+ assertThat(thrown).isInstanceOf(TimeoutException.class);
+ });
+
+ vm0.invoke("signal gate", () -> blackboard.signalGate(gate()));
+
+ vm1.invoke("wait on gate not yet signalled", () -> blackboard.waitForGate(gate(), 1, SECONDS));
+ }
+
+ @Test
+ public void initBlackboardClearsEverything() {
+ for (int i = 0; i < 100; i++) {
+ blackboard.setMailbox(mailbox(i), value(i));
+ assertThat((Object) blackboard.getMailbox(mailbox(i))).isEqualTo(value(i));
+
+ blackboard.signalGate(gate(i));
+ assertThat(blackboard.isGateSignaled(gate(i))).isTrue();
+ }
+
+ getVM(1).invoke("clear blackboard", () -> blackboard.initBlackboard());
+
+ for (int i = 0; i < 100; i++) {
+ assertThat((Object) blackboard.getMailbox(mailbox(i))).isNull();
+ assertThat(blackboard.isGateSignaled(gate(i))).isFalse();
+ }
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromSameVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(0).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromOtherVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(1).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromSameVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(0).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromOtherVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(1).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(2).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromSameVM_afterBouncingVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(0).bounceForcibly();
+
+ getVM(0).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromOtherVM_afterBouncingVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(0).bounceForcibly();
+
+ getVM(1).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromSameVM_afterBouncingVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(0).bounceForcibly();
+
+ getVM(0).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox(1))).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromOtherVM_afterBouncingFirstVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(1).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(0).bounceForcibly();
+
+ getVM(2).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromOtherVM_afterBouncingSecondVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(1).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(1).bounceForcibly();
+
+ getVM(2).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void setMailbox_overwrites_valueFromOtherVM_afterBouncingBothVMs() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value(1)));
+ getVM(1).invoke(() -> blackboard.setMailbox(mailbox(), value(2)));
+
+ getVM(0).bounceForcibly();
+ getVM(1).bounceForcibly();
+
+ getVM(2).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value(2));
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromSameVM_afterBouncingEveryVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(0).bounceForcibly();
+ getVM(1).bounceForcibly();
+ getVM(2).bounceForcibly();
+ getVM(3).bounceForcibly();
+
+ getVM(0).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromOtherVM_afterBouncingEveryVM() {
+ getVM(0).invoke(() -> blackboard.setMailbox(mailbox(), value()));
+
+ getVM(0).bounceForcibly();
+ getVM(1).bounceForcibly();
+ getVM(2).bounceForcibly();
+ getVM(3).bounceForcibly();
+
+ getVM(1).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueFromControllerVM_afterBouncingEveryVM() {
+ blackboard.setMailbox(mailbox(), value());
+
+ getVM(0).bounceForcibly();
+ getVM(1).bounceForcibly();
+ getVM(2).bounceForcibly();
+ getVM(3).bounceForcibly();
+
+ getVM(3).invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+
+ @Test
+ public void getMailbox_returnsValueInControllerVM_afterBouncingEveryVM() {
+ blackboard.setMailbox(mailbox(), value());
+
+ getVM(0).bounceForcibly();
+ getVM(1).bounceForcibly();
+ getVM(2).bounceForcibly();
+ getVM(3).bounceForcibly();
+
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ }
+
+ @Test
+ public void getMailbox_returnsValueInEveryVM() {
+ blackboard.setMailbox(mailbox(), value());
+
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ for (VM vm : asList(getController(), getVM(0), getVM(1), getVM(2), getVM(3))) {
+ vm.invoke(() -> {
+ assertThat((Object) blackboard.getMailbox(mailbox())).isEqualTo(value());
+ });
+ }
+ }
+
+ private String mailbox() {
+ return value("mailbox", 1);
+ }
+
+ private String value() {
+ return value("value", 1);
+ }
+
+ private String gate() {
+ return value("gate", 1);
+ }
+
+ private String mailbox(int count) {
+ return value("mailbox", count);
+ }
+
+ private String value(int count) {
+ return value("value", count);
+ }
+
+ private String gate(int count) {
+ return value("gate", count);
+ }
+
+ private String value(String prefix, int count) {
+ return prefix + "-" + testName.getMethodName() + "-" + count;
+ }
+}
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/Blackboard.java
old mode 100755
new mode 100644
similarity index 51%
copy from geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java
copy to geode-dunit/src/main/java/org/apache/geode/test/dunit/Blackboard.java
index 24abf4f..2b15ebd
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/Blackboard.java
@@ -12,66 +12,68 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.test.dunit.internal;
+package org.apache.geode.test.dunit;
-import java.io.Serializable;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import org.apache.geode.test.awaitility.GeodeAwaitility;
+
/**
- * DUnitBlackboard provides mailboxes and synchronization gateways for distributed unit tests.
+ * Blackboard provides mailboxes and synchronization gateways for distributed tests.
+ *
* <p>
* Tests may use the blackboard to pass objects and status between JVMs with mailboxes instead of
* using static variables in classes. The caveat being that the objects will be serialized using
* Java serialization.
+ *
* <p>
- * Gates may be used to synchronize operations between unit test JVMs. Combined with Awaitility
- * these can be used to test for conditions being met, actions having happened, etc.
+ * Gates may be used to synchronize operations between distributed test JVMs. Combined with
+ * Awaitility these can be used to test for conditions being met, actions having happened, etc.
+ *
* <p>
* Look for references to the given methods in your IDE for examples.
*/
-public interface InternalBlackboard extends Remote, Serializable {
+public interface Blackboard {
+
/**
- * resets the blackboard
+ * Resets the blackboard.
*/
- void initBlackboard() throws RemoteException;
+ void initBlackboard();
/**
- * signals a boolean gate
+ * Signals a boolean gate.
*/
- void signalGate(String gateName) throws RemoteException;
+ void signalGate(String gateName);
/**
- * wait for a gate to be signaled
+ * Waits at most {@link GeodeAwaitility#getTimeout()} for a gate to be signaled.
*/
- void waitForGate(String gateName, long timeout, TimeUnit units)
- throws RemoteException, TimeoutException, InterruptedException;
+ void waitForGate(String gateName) throws TimeoutException, InterruptedException;
/**
- * clears a gate
+ * Waits at most the specified timeout for a gate to be signaled.
*/
- void clearGate(String gateName) throws RemoteException;
+ void waitForGate(String gateName, long timeout, TimeUnit units)
+ throws TimeoutException, InterruptedException;
/**
- * test to see if a gate has been signeled
+ * Clears a gate.
*/
- boolean isGateSignaled(String gateName) throws RemoteException;
+ void clearGate(String gateName);
/**
- * put an object into a mailbox slot. The object must be java-serializable
+ * Checks to see if a gate has been signaled.
*/
- void setMailbox(String boxName, Object value) throws RemoteException;
+ boolean isGateSignaled(String gateName);
/**
- * retrieve an object from a mailbox slot
+ * Puts an object into a mailbox slot. The object must be java-serializable.
*/
- <T> T getMailbox(String boxName) throws RemoteException;
+ <T> void setMailbox(String boxName, T value);
/**
- * ping the blackboard to make sure it's there
+ * Retrieves an object from a mailbox slot.
*/
- void ping() throws RemoteException;
-
+ <T> T getMailbox(String boxName);
}
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/DUnitBlackboard.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/DUnitBlackboard.java
index d87b99d..1ff5a0a 100755
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/DUnitBlackboard.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/DUnitBlackboard.java
@@ -14,6 +14,9 @@
*/
package org.apache.geode.test.dunit;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.getTimeout;
+
import java.rmi.RemoteException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -22,7 +25,7 @@ import org.apache.geode.test.dunit.internal.InternalBlackboard;
import org.apache.geode.test.dunit.internal.InternalBlackboardImpl;
/**
- * DUnitBlackboard provides mailboxes and synchronization gateways for distributed unit tests.
+ * DUnitBlackboard provides mailboxes and synchronization gateways for distributed tests.
*
* <p>
* Tests may use the blackboard to pass objects and status between JVMs with mailboxes instead of
@@ -36,17 +39,19 @@ import org.apache.geode.test.dunit.internal.InternalBlackboardImpl;
* <p>
* Look for references to the given methods in your IDE for examples.
*/
-public class DUnitBlackboard {
+public class DUnitBlackboard implements Blackboard {
- private InternalBlackboard blackboard;
+ private final InternalBlackboard blackboard;
public DUnitBlackboard() {
- blackboard = InternalBlackboardImpl.getInstance();
+ this(InternalBlackboardImpl.getInstance());
+ }
+
+ public DUnitBlackboard(InternalBlackboard blackboard) {
+ this.blackboard = blackboard;
}
- /**
- * resets the blackboard
- */
+ @Override
public void initBlackboard() {
try {
blackboard.initBlackboard();
@@ -55,11 +60,8 @@ public class DUnitBlackboard {
}
}
- /**
- * signals a boolean gate
- */
+ @Override
public void signalGate(String gateName) {
- // System.out.println(Thread.currentThread().getName()+": signaling gate " + gateName);
try {
blackboard.signalGate(gateName);
} catch (RemoteException e) {
@@ -67,12 +69,15 @@ public class DUnitBlackboard {
}
}
- /**
- * wait for a gate to be signaled
- */
+ @Override
+ public void waitForGate(String gateName)
+ throws TimeoutException, InterruptedException {
+ waitForGate(gateName, getTimeout().toMinutes(), MINUTES);
+ }
+
+ @Override
public void waitForGate(String gateName, long timeout, TimeUnit units)
throws TimeoutException, InterruptedException {
- // System.out.println(Thread.currentThread().getName()+": waiting for gate " + gateName);
try {
blackboard.waitForGate(gateName, timeout, units);
} catch (RemoteException e) {
@@ -80,9 +85,7 @@ public class DUnitBlackboard {
}
}
- /**
- * clear a gate
- */
+ @Override
public void clearGate(String gateName) {
try {
blackboard.clearGate(gateName);
@@ -91,9 +94,7 @@ public class DUnitBlackboard {
}
}
- /**
- * test to see if a gate has been signeled
- */
+ @Override
public boolean isGateSignaled(String gateName) {
try {
return blackboard.isGateSignaled(gateName);
@@ -102,9 +103,7 @@ public class DUnitBlackboard {
}
}
- /**
- * put an object into a mailbox slot. The object must be java-serializable
- */
+ @Override
public void setMailbox(String boxName, Object value) {
try {
blackboard.setMailbox(boxName, value);
@@ -113,9 +112,7 @@ public class DUnitBlackboard {
}
}
- /**
- * retrieve an object from a mailbox slot
- */
+ @Override
public <T> T getMailbox(String boxName) {
try {
return blackboard.getMailbox(boxName);
@@ -123,4 +120,8 @@ public class DUnitBlackboard {
throw new RuntimeException("remote call failed", e);
}
}
+
+ public InternalBlackboard internal() {
+ return blackboard;
+ }
}
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java
index 24abf4f..222a301 100755
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboard.java
@@ -17,61 +17,70 @@ package org.apache.geode.test.dunit.internal;
import java.io.Serializable;
import java.rmi.Remote;
import java.rmi.RemoteException;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
- * DUnitBlackboard provides mailboxes and synchronization gateways for distributed unit tests.
+ * InternalBlackboard provides mailboxes and synchronization gateways for distributed tests.
+ *
* <p>
* Tests may use the blackboard to pass objects and status between JVMs with mailboxes instead of
* using static variables in classes. The caveat being that the objects will be serialized using
* Java serialization.
+ *
* <p>
* Gates may be used to synchronize operations between unit test JVMs. Combined with Awaitility
* these can be used to test for conditions being met, actions having happened, etc.
- * <p>
- * Look for references to the given methods in your IDE for examples.
*/
public interface InternalBlackboard extends Remote, Serializable {
+
/**
- * resets the blackboard
+ * Resets the blackboard.
*/
void initBlackboard() throws RemoteException;
/**
- * signals a boolean gate
+ * Signals a boolean gate.
*/
void signalGate(String gateName) throws RemoteException;
/**
- * wait for a gate to be signaled
+ * Waits for a gate to be signaled.
*/
void waitForGate(String gateName, long timeout, TimeUnit units)
throws RemoteException, TimeoutException, InterruptedException;
/**
- * clears a gate
+ * Clears a gate.
*/
void clearGate(String gateName) throws RemoteException;
/**
- * test to see if a gate has been signeled
+ * Checks to see if a gate has been signaled.
*/
boolean isGateSignaled(String gateName) throws RemoteException;
/**
- * put an object into a mailbox slot. The object must be java-serializable
+ * Puts an object into a mailbox slot. The object must be java-serializable.
*/
- void setMailbox(String boxName, Object value) throws RemoteException;
+ <T> void setMailbox(String boxName, T value) throws RemoteException;
/**
- * retrieve an object from a mailbox slot
+ * Retrieves an object from a mailbox slot.
*/
<T> T getMailbox(String boxName) throws RemoteException;
/**
- * ping the blackboard to make sure it's there
+ * Pings the blackboard to make sure it's there.
*/
void ping() throws RemoteException;
+ Map<String, Boolean> gates() throws RemoteException;
+
+ Map<String, Serializable> mailboxes() throws RemoteException;
+
+ void putGates(Map<String, Boolean> gates) throws RemoteException;
+
+ void putMailboxes(Map<String, Serializable> mailboxes) throws RemoteException;
}
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboardImpl.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboardImpl.java
index bbed22e..e24a5a0 100755
--- a/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboardImpl.java
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/internal/InternalBlackboardImpl.java
@@ -14,6 +14,12 @@
*/
package org.apache.geode.test.dunit.internal;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.apache.geode.util.internal.UncheckedUtils.uncheckedCast;
+
+import java.io.Serializable;
+import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
@@ -24,26 +30,24 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-
public class InternalBlackboardImpl extends UnicastRemoteObject implements InternalBlackboard {
- public static InternalBlackboard blackboard;
- private Map<String, Boolean> gates = new ConcurrentHashMap<>();
-
- private Map<String, Object> mailboxes = new ConcurrentHashMap();
+ private static InternalBlackboard blackboard;
+ private final Map<String, Boolean> gates = new ConcurrentHashMap<>();
+ private final Map<String, Serializable> mailboxes = new ConcurrentHashMap<>();
/**
* Zero-arg constructor for remote method invocations.
*/
public InternalBlackboardImpl() throws RemoteException {
- super();
+ // nothing
}
/**
* Creates a singleton event listeners blackboard.
*/
- public static InternalBlackboard getInstance() {
+ public static synchronized InternalBlackboard getInstance() {
if (blackboard == null) {
try {
initialize();
@@ -56,11 +60,12 @@ public class InternalBlackboardImpl extends UnicastRemoteObject implements Inter
return blackboard;
}
- private static synchronized void initialize() throws Exception {
+ private static synchronized void initialize()
+ throws AlreadyBoundException, MalformedURLException, RemoteException {
if (blackboard == null) {
System.out.println(
DUnitLauncher.RMI_PORT_PARAM + "=" + System.getProperty(DUnitLauncher.RMI_PORT_PARAM));
- int namingPort = Integer.getInteger(DUnitLauncher.RMI_PORT_PARAM).intValue();
+ int namingPort = Integer.getInteger(DUnitLauncher.RMI_PORT_PARAM);
String name = "//localhost:" + namingPort + "/" + "InternalBlackboard";
try {
blackboard = (InternalBlackboard) Naming.lookup(name);
@@ -74,8 +79,8 @@ public class InternalBlackboardImpl extends UnicastRemoteObject implements Inter
@Override
public void initBlackboard() throws RemoteException {
- this.gates.clear();
- this.mailboxes.clear();
+ gates.clear();
+ mailboxes.clear();
}
@Override
@@ -90,8 +95,8 @@ public class InternalBlackboardImpl extends UnicastRemoteObject implements Inter
@Override
public void waitForGate(final String gateName, final long timeout, final TimeUnit units)
- throws RemoteException, TimeoutException, InterruptedException {
- long giveupTime = System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(timeout, units);
+ throws InterruptedException, RemoteException, TimeoutException {
+ long giveupTime = System.currentTimeMillis() + MILLISECONDS.convert(timeout, units);
while (System.currentTimeMillis() < giveupTime) {
Boolean gate = gates.get(gateName);
if (gate != null && gate) {
@@ -105,17 +110,17 @@ public class InternalBlackboardImpl extends UnicastRemoteObject implements Inter
@Override
public boolean isGateSignaled(final String gateName) {
Boolean gate = gates.get(gateName);
- return (gate != null && gate);
+ return gate != null && gate;
}
@Override
- public void setMailbox(String boxName, Object value) {
- mailboxes.put(boxName, value);
+ public <T> void setMailbox(String boxName, T value) {
+ mailboxes.put(boxName, (Serializable) value);
}
@Override
- public Object getMailbox(String boxName) {
- return mailboxes.get(boxName);
+ public <T> T getMailbox(String boxName) {
+ return uncheckedCast(mailboxes.get(boxName));
}
@Override
@@ -123,5 +128,23 @@ public class InternalBlackboardImpl extends UnicastRemoteObject implements Inter
// no-op
}
+ @Override
+ public Map<String, Boolean> gates() {
+ return unmodifiableMap(gates);
+ }
+ @Override
+ public Map<String, Serializable> mailboxes() {
+ return unmodifiableMap(mailboxes);
+ }
+
+ @Override
+ public void putGates(Map<String, Boolean> gates) {
+ this.gates.putAll(gates);
+ }
+
+ @Override
+ public void putMailboxes(Map<String, Serializable> mailboxes) {
+ this.mailboxes.putAll(mailboxes);
+ }
}
diff --git a/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/DistributedBlackboard.java b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/DistributedBlackboard.java
new file mode 100644
index 0000000..8161b6d
--- /dev/null
+++ b/geode-dunit/src/main/java/org/apache/geode/test/dunit/rules/DistributedBlackboard.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.dunit.rules;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.geode.test.dunit.Blackboard;
+import org.apache.geode.test.dunit.DUnitBlackboard;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.internal.InternalBlackboard;
+import org.apache.geode.test.dunit.internal.InternalBlackboardImpl;
+
+/**
+ * DistributedBlackboard provides mailboxes and synchronization gateways for distributed tests.
+ *
+ * <p>
+ * Tests may use the blackboard to pass objects and status between JVMs with mailboxes instead of
+ * using static variables in classes. The caveat being that the objects will be serialized using
+ * Java serialization.
+ *
+ * <p>
+ * Gates may be used to synchronize operations between distributed test JVMs. Combined with
+ * Awaitility these can be used to test for conditions being met, actions having happened, etc.
+ *
+ * <p>
+ * Look for references to the given methods in your IDE for examples.
+ */
+@SuppressWarnings({"serial", "unused"})
+public class DistributedBlackboard extends AbstractDistributedRule implements Blackboard {
+
+ private static final AtomicReference<DUnitBlackboard> BLACKBOARD = new AtomicReference<>();
+ private static final AtomicReference<InternalBlackboard> INTERNAL = new AtomicReference<>();
+
+ private final Map<Integer, Map<String, Boolean>> keepGates = new ConcurrentHashMap<>();
+ private final Map<Integer, Map<String, Serializable>> keepMailboxes = new ConcurrentHashMap<>();
+
+ @Override
+ protected void before() {
+ invoker().invokeInEveryVMAndController(() -> invokeBefore());
+ }
+
+ @Override
+ protected void after() throws Throwable {
+ invoker().invokeInEveryVMAndController(() -> invokeAfter());
+ }
+
+ @Override
+ protected void afterCreateVM(VM vm) {
+ vm.invoke(() -> invokeBefore());
+ }
+
+ @Override
+ protected void beforeBounceVM(VM vm) {
+ keepGates.put(vm.getId(), vm.invoke(() -> INTERNAL.get().gates()));
+ keepMailboxes.put(vm.getId(), vm.invoke(() -> INTERNAL.get().mailboxes()));
+ }
+
+ @Override
+ protected void afterBounceVM(VM vm) {
+ Map<String, Boolean> keepGatesForVM = keepGates.remove(vm.getId());
+ Map<String, Serializable> keepMailboxesForVM = keepMailboxes.remove(vm.getId());
+
+ vm.invoke(() -> {
+ invokeBefore();
+ INTERNAL.get().putGates(keepGatesForVM);
+ INTERNAL.get().putMailboxes(keepMailboxesForVM);
+ });
+ }
+
+ private void invokeBefore() {
+ InternalBlackboard internalBlackboard = InternalBlackboardImpl.getInstance();
+ INTERNAL.set(internalBlackboard);
+ BLACKBOARD.set(new DUnitBlackboard(internalBlackboard));
+ }
+
+ private void invokeAfter() {
+ BLACKBOARD.set(null);
+ INTERNAL.set(null);
+ }
+
+ @Override
+ public void initBlackboard() {
+ BLACKBOARD.get().initBlackboard();
+ }
+
+ @Override
+ public void signalGate(String gateName) {
+ BLACKBOARD.get().signalGate(gateName);
+ }
+
+ @Override
+ public void waitForGate(String gateName) throws TimeoutException, InterruptedException {
+ BLACKBOARD.get().waitForGate(gateName);
+ }
+
+ @Override
+ public void waitForGate(String gateName, long timeout, TimeUnit units)
+ throws TimeoutException, InterruptedException {
+ BLACKBOARD.get().waitForGate(gateName, timeout, units);
+ }
+
+ @Override
+ public void clearGate(String gateName) {
+ BLACKBOARD.get().clearGate(gateName);
+ }
+
+ @Override
+ public boolean isGateSignaled(String gateName) {
+ return BLACKBOARD.get().isGateSignaled(gateName);
+ }
+
+ @Override
+ public <T> void setMailbox(String boxName, T value) {
+ BLACKBOARD.get().setMailbox(boxName, value);
+ }
+
+ @Override
+ public <T> T getMailbox(String boxName) {
+ return BLACKBOARD.get().getMailbox(boxName);
+ }
+}