X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-distributed-datastore%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fdatastore%2Futils%2FActorContextTest.java;h=2746bcf982906af7046c8c8e3cb930711929df43;hp=5d8fb8393d6c4fd773a0a94b6fd156ac02fe1c14;hb=3104f91c7d1b3ee5914d8778f87315f4ac64036d;hpb=15fa131be8b16703089a6d8508546120cf15d45d diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java index 5d8fb8393d..2746bcf982 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/ActorContextTest.java @@ -1,69 +1,68 @@ package org.opendaylight.controller.cluster.datastore.utils; -import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import akka.actor.ActorRef; import akka.actor.ActorSelection; import akka.actor.ActorSystem; +import akka.actor.Address; import akka.actor.Props; import akka.actor.UntypedActor; +import akka.dispatch.Futures; import akka.japi.Creator; import akka.testkit.JavaTestKit; - +import akka.testkit.TestActorRef; +import akka.util.Timeout; +import com.google.common.base.Optional; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.Uninterruptibles; +import com.typesafe.config.ConfigFactory; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.apache.commons.lang.time.StopWatch; +import org.junit.Assert; import org.junit.Test; import org.opendaylight.controller.cluster.datastore.AbstractActorTest; import org.opendaylight.controller.cluster.datastore.ClusterWrapper; import org.opendaylight.controller.cluster.datastore.Configuration; +import org.opendaylight.controller.cluster.datastore.DatastoreContext; +import org.opendaylight.controller.cluster.datastore.exceptions.NoShardLeaderException; +import org.opendaylight.controller.cluster.datastore.exceptions.NotInitializedException; +import org.opendaylight.controller.cluster.datastore.exceptions.PrimaryNotFoundException; +import org.opendaylight.controller.cluster.datastore.messages.ActorNotInitialized; import org.opendaylight.controller.cluster.datastore.messages.FindLocalShard; +import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; import org.opendaylight.controller.cluster.datastore.messages.LocalShardFound; import org.opendaylight.controller.cluster.datastore.messages.LocalShardNotFound; - +import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; +import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; +import scala.concurrent.duration.FiniteDuration; public class ActorContextTest extends AbstractActorTest{ - @Test - public void testResolvePathForRemoteActor(){ - ActorContext actorContext = - new ActorContext(mock(ActorSystem.class), mock(ActorRef.class),mock( - ClusterWrapper.class), - mock(Configuration.class)); - - String actual = actorContext.resolvePath( - "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard", - "akka://system/user/shardmanager/shard/transaction"); - - String expected = "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard/transaction"; - - assertEquals(expected, actual); - } - - @Test - public void testResolvePathForLocalActor(){ - ActorContext actorContext = - new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), - mock(Configuration.class)); - - String actual = actorContext.resolvePath( - "akka://system/user/shardmanager/shard", - "akka://system/user/shardmanager/shard/transaction"); - - String expected = "akka://system/user/shardmanager/shard/transaction"; - assertEquals(expected, actual); + static final Logger log = LoggerFactory.getLogger(ActorContextTest.class); - System.out.println(actorContext - .actorFor("akka://system/user/shardmanager/shard/transaction")); + private static class TestMessage { } - private static class MockShardManager extends UntypedActor { private final boolean found; private final ActorRef actorRef; + private final Map findPrimaryResponses = Maps.newHashMap(); private MockShardManager(boolean found, ActorRef actorRef){ @@ -72,6 +71,18 @@ public class ActorContextTest extends AbstractActorTest{ } @Override public void onReceive(Object message) throws Exception { + if(message instanceof FindPrimary) { + FindPrimary fp = (FindPrimary)message; + Object resp = findPrimaryResponses.get(fp.getShardName()); + if(resp == null) { + log.error("No expected FindPrimary response found for shard name {}", fp.getShardName()); + } else { + getSender().tell(resp, getSelf()); + } + + return; + } + if(found){ getSender().tell(new LocalShardFound(actorRef), getSelf()); } else { @@ -79,15 +90,28 @@ public class ActorContextTest extends AbstractActorTest{ } } + void addFindPrimaryResp(String shardName, Object resp) { + findPrimaryResponses.put(shardName, resp); + } + private static Props props(final boolean found, final ActorRef actorRef){ return Props.create(new MockShardManagerCreator(found, actorRef) ); } + private static Props props(){ + return Props.create(new MockShardManagerCreator() ); + } + @SuppressWarnings("serial") private static class MockShardManagerCreator implements Creator { final boolean found; final ActorRef actorRef; + MockShardManagerCreator() { + this.found = false; + this.actorRef = null; + } + MockShardManagerCreator(boolean found, ActorRef actorRef) { this.found = found; this.actorRef = actorRef; @@ -101,7 +125,7 @@ public class ActorContextTest extends AbstractActorTest{ } @Test - public void testExecuteLocalShardOperationWithShardFound(){ + public void testFindLocalShardWithShardFound(){ new JavaTestKit(getSystem()) {{ new Within(duration("1 seconds")) { @@ -117,9 +141,9 @@ public class ActorContextTest extends AbstractActorTest{ new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - Object out = actorContext.executeLocalShardOperation("default", "hello"); + Optional out = actorContext.findLocalShard("default"); - assertEquals("hello", out); + assertEquals(shardActorRef, out.get()); expectNoMsg(); @@ -130,149 +154,403 @@ public class ActorContextTest extends AbstractActorTest{ } @Test - public void testExecuteLocalShardOperationWithShardNotFound(){ + public void testFindLocalShardWithShardNotFound(){ new JavaTestKit(getSystem()) {{ + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(false, null)); - new Within(duration("1 seconds")) { - @Override - protected void run() { + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(false, null)); + Optional out = actorContext.findLocalShard("default"); + assertTrue(!out.isPresent()); + }}; - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + } + + @Test + public void testExecuteRemoteOperation() { + new JavaTestKit(getSystem()) {{ + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), mock(Configuration.class)); - Object out = actorContext.executeLocalShardOperation("default", "hello"); + ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); - assertNull(out); + Object out = actorContext.executeOperation(actor, "hello"); + assertEquals("hello", out); + }}; + } - expectNoMsg(); - } - }; + @Test + public void testExecuteRemoteOperationAsync() { + new JavaTestKit(getSystem()) {{ + ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + + ActorRef shardManagerActorRef = getSystem() + .actorOf(MockShardManager.props(true, shardActorRef)); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), + mock(Configuration.class)); + + ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); + + Future future = actorContext.executeOperationAsync(actor, "hello"); + + try { + Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS)); + assertEquals("Result", "hello", result); + } catch(Exception e) { + throw new AssertionError(e); + } }}; + } + @Test + public void testIsPathLocal() { + MockClusterWrapper clusterWrapper = new MockClusterWrapper(); + ActorContext actorContext = null; + + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal(null)); + assertEquals(false, actorContext.isPathLocal("")); + + clusterWrapper.setSelfAddress(null); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal("")); + + // even if the path is in local format, match the primary path (first 3 elements) and return true + clusterWrapper.setSelfAddress(new Address("akka", "test")); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal("akka://test/user/$a")); + + clusterWrapper.setSelfAddress(new Address("akka", "test")); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal("akka://test/user/$a")); + + clusterWrapper.setSelfAddress(new Address("akka", "test")); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal("akka://test/user/token2/token3/$a")); + + // self address of remote format,but Tx path local format. + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system", "127.0.0.1", 2550)); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal( + "akka://system/user/shardmanager/shard/transaction")); + + // self address of local format,but Tx path remote format. + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system")); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal( + "akka://system@127.0.0.1:2550/user/shardmanager/shard/transaction")); + + //local path but not same + clusterWrapper.setSelfAddress(new Address("akka", "test")); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal("akka://test1/user/$a")); + + //ip and port same + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system", "127.0.0.1", 2550)); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(true, actorContext.isPathLocal("akka.tcp://system@127.0.0.1:2550/")); + + // forward-slash missing in address + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system", "127.0.0.1", 2550)); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal("akka.tcp://system@127.0.0.1:2550")); + + //ips differ + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system", "127.0.0.1", 2550)); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal("akka.tcp://system@127.1.0.1:2550/")); + + //ports differ + clusterWrapper.setSelfAddress(new Address("akka.tcp", "system", "127.0.0.1", 2550)); + actorContext = new ActorContext(getSystem(), null, clusterWrapper, mock(Configuration.class)); + assertEquals(false, actorContext.isPathLocal("akka.tcp://system@127.0.0.1:2551/")); } + @Test + public void testResolvePathForRemoteActor() { + ActorContext actorContext = + new ActorContext(getSystem(), mock(ActorRef.class), mock( + ClusterWrapper.class), + mock(Configuration.class)); + + String actual = actorContext.resolvePath( + "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard", + "akka://system/user/shardmanager/shard/transaction"); + + String expected = "akka.tcp://system@127.0.0.1:2550/user/shardmanager/shard/transaction"; + + assertEquals(expected, actual); + } @Test - public void testFindLocalShardWithShardFound(){ - new JavaTestKit(getSystem()) {{ + public void testResolvePathForLocalActor() { + ActorContext actorContext = + new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), + mock(Configuration.class)); - new Within(duration("1 seconds")) { - @Override - protected void run() { + String actual = actorContext.resolvePath( + "akka://system/user/shardmanager/shard", + "akka://system/user/shardmanager/shard/transaction"); - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + String expected = "akka://system/user/shardmanager/shard/transaction"; - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); + assertEquals(expected, actual); + } - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); + @Test + public void testResolvePathForRemoteActorWithProperRemoteAddress() { + ActorContext actorContext = + new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), + mock(Configuration.class)); - Object out = actorContext.findLocalShard("default"); + String actual = actorContext.resolvePath( + "akka.tcp://system@7.0.0.1:2550/user/shardmanager/shard", + "akka.tcp://system@7.0.0.1:2550/user/shardmanager/shard/transaction"); - assertEquals(shardActorRef, out); + String expected = "akka.tcp://system@7.0.0.1:2550/user/shardmanager/shard/transaction"; + assertEquals(expected, actual); + } - expectNoMsg(); - } - }; - }}; + @Test + public void testRateLimiting(){ + DatastoreContext dataStoreContext = DatastoreContext.newBuilder().dataStoreType("config"). + transactionCreationInitialRateLimit(155L).build(); + + ActorContext actorContext = + new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), + mock(Configuration.class), dataStoreContext); + + // Check that the initial value is being picked up from DataStoreContext + assertEquals(dataStoreContext.getTransactionCreationInitialRateLimit(), actorContext.getTxCreationLimit(), 1e-15); + + actorContext.setTxCreationLimit(1.0); + + assertEquals(1.0, actorContext.getTxCreationLimit(), 1e-15); + + + StopWatch watch = new StopWatch(); + + watch.start(); + + actorContext.acquireTxCreationPermit(); + actorContext.acquireTxCreationPermit(); + actorContext.acquireTxCreationPermit(); + watch.stop(); + + assertTrue("did not take as much time as expected", watch.getTime() > 1000); } @Test - public void testFindLocalShardWithShardNotFound(){ - new JavaTestKit(getSystem()) {{ + public void testClientDispatcherIsGlobalDispatcher(){ + ActorContext actorContext = + new ActorContext(getSystem(), mock(ActorRef.class), mock(ClusterWrapper.class), + mock(Configuration.class), DatastoreContext.newBuilder().build()); - new Within(duration("1 seconds")) { - @Override - protected void run() { + assertEquals(getSystem().dispatchers().defaultGlobalDispatcher(), actorContext.getClientDispatcher()); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(false, null)); + } - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); + @Test + public void testClientDispatcherIsNotGlobalDispatcher(){ + ActorSystem actorSystem = ActorSystem.create("with-custom-dispatchers", ConfigFactory.load("application-with-custom-dispatchers.conf")); - Object out = actorContext.findLocalShard("default"); + ActorContext actorContext = + new ActorContext(actorSystem, mock(ActorRef.class), mock(ClusterWrapper.class), + mock(Configuration.class), DatastoreContext.newBuilder().build()); - assertNull(out); + assertNotEquals(actorSystem.dispatchers().defaultGlobalDispatcher(), actorContext.getClientDispatcher()); + actorSystem.shutdown(); - expectNoMsg(); - } - }; + } + + @Test + public void testSetDatastoreContext() { + new JavaTestKit(getSystem()) {{ + ActorContext actorContext = new ActorContext(getSystem(), getRef(), mock(ClusterWrapper.class), + mock(Configuration.class), DatastoreContext.newBuilder(). + operationTimeoutInSeconds(5).shardTransactionCommitTimeoutInSeconds(7).build()); + + assertEquals("getOperationDuration", 5, actorContext.getOperationDuration().toSeconds()); + assertEquals("getTransactionCommitOperationTimeout", 7, + actorContext.getTransactionCommitOperationTimeout().duration().toSeconds()); + + DatastoreContext newContext = DatastoreContext.newBuilder().operationTimeoutInSeconds(6). + shardTransactionCommitTimeoutInSeconds(8).build(); + + actorContext.setDatastoreContext(newContext); + + expectMsgClass(duration("5 seconds"), DatastoreContext.class); + + Assert.assertSame("getDatastoreContext", newContext, actorContext.getDatastoreContext()); + + assertEquals("getOperationDuration", 6, actorContext.getOperationDuration().toSeconds()); + assertEquals("getTransactionCommitOperationTimeout", 8, + actorContext.getTransactionCommitOperationTimeout().duration().toSeconds()); }}; + } + + @Test + public void testFindPrimaryShardAsyncPrimaryFound() throws Exception { + + TestActorRef shardManager = + TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class)); + + DatastoreContext dataStoreContext = DatastoreContext.newBuilder().dataStoreType("config"). + shardLeaderElectionTimeout(100, TimeUnit.MILLISECONDS).build(); + + ActorContext actorContext = + new ActorContext(getSystem(), shardManager, mock(ClusterWrapper.class), + mock(Configuration.class), dataStoreContext) { + @Override + protected Future doAsk(ActorRef actorRef, Object message, Timeout timeout) { + return Futures.successful((Object) new PrimaryFound("akka://test-system/test")); + } + }; + + + Future foobar = actorContext.findPrimaryShardAsync("foobar"); + ActorSelection actual = Await.result(foobar, Duration.apply(5000, TimeUnit.MILLISECONDS)); + + assertNotNull(actual); + + Future cached = actorContext.getPrimaryShardActorSelectionCache().getIfPresent("foobar"); + + ActorSelection cachedSelection = Await.result(cached, FiniteDuration.apply(1, TimeUnit.MILLISECONDS)); + + assertEquals(cachedSelection, actual); + + // Wait for 200 Milliseconds. The cached entry should have been removed. + + Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS); + + cached = actorContext.getPrimaryShardActorSelectionCache().getIfPresent("foobar"); + + assertNull(cached); } @Test - public void testExecuteRemoteOperation() { - new JavaTestKit(getSystem()) {{ + public void testFindPrimaryShardAsyncPrimaryNotFound() throws Exception { - new Within(duration("3 seconds")) { - @Override - protected void run() { + TestActorRef shardManager = + TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class)); - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + DatastoreContext dataStoreContext = DatastoreContext.newBuilder().dataStoreType("config"). + shardLeaderElectionTimeout(100, TimeUnit.MILLISECONDS).build(); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); + ActorContext actorContext = + new ActorContext(getSystem(), shardManager, mock(ClusterWrapper.class), + mock(Configuration.class), dataStoreContext) { + @Override + protected Future doAsk(ActorRef actorRef, Object message, Timeout timeout) { + return Futures.successful((Object) new PrimaryNotFound("foobar")); + } + }; - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); - ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); + Future foobar = actorContext.findPrimaryShardAsync("foobar"); - Object out = actorContext.executeRemoteOperation(actor, "hello"); + try { + Await.result(foobar, Duration.apply(100, TimeUnit.MILLISECONDS)); + fail("Expected PrimaryNotFoundException"); + } catch(PrimaryNotFoundException e){ - assertEquals("hello", out); + } - expectNoMsg(); - } - }; - }}; + Future cached = actorContext.getPrimaryShardActorSelectionCache().getIfPresent("foobar"); + + assertNull(cached); } @Test - public void testExecuteRemoteOperationAsync() { - new JavaTestKit(getSystem()) {{ + public void testFindPrimaryShardAsyncActorNotInitialized() throws Exception { - new Within(duration("3 seconds")) { - @Override - protected void run() { + TestActorRef shardManager = + TestActorRef.create(getSystem(), Props.create(MessageCollectorActor.class)); - ActorRef shardActorRef = getSystem().actorOf(Props.create(EchoActor.class)); + DatastoreContext dataStoreContext = DatastoreContext.newBuilder().dataStoreType("config"). + shardLeaderElectionTimeout(100, TimeUnit.MILLISECONDS).build(); - ActorRef shardManagerActorRef = getSystem() - .actorOf(MockShardManager.props(true, shardActorRef)); + ActorContext actorContext = + new ActorContext(getSystem(), shardManager, mock(ClusterWrapper.class), + mock(Configuration.class), dataStoreContext) { + @Override + protected Future doAsk(ActorRef actorRef, Object message, Timeout timeout) { + return Futures.successful((Object) new ActorNotInitialized()); + } + }; - ActorContext actorContext = - new ActorContext(getSystem(), shardManagerActorRef , mock(ClusterWrapper.class), - mock(Configuration.class)); - ActorSelection actor = actorContext.actorSelection(shardActorRef.path()); + Future foobar = actorContext.findPrimaryShardAsync("foobar"); - Future future = actorContext.executeRemoteOperationAsync(actor, "hello"); + try { + Await.result(foobar, Duration.apply(100, TimeUnit.MILLISECONDS)); + fail("Expected NotInitializedException"); + } catch(NotInitializedException e){ - try { - Object result = Await.result(future, Duration.create(3, TimeUnit.SECONDS)); - assertEquals("Result", "hello", result); - } catch(Exception e) { - throw new AssertionError(e); - } + } - expectNoMsg(); - } - }; + Future cached = actorContext.getPrimaryShardActorSelectionCache().getIfPresent("foobar"); + + assertNull(cached); + } + + @Test + public void testBroadcast() { + new JavaTestKit(getSystem()) {{ + ActorRef shardActorRef1 = getSystem().actorOf(Props.create(MessageCollectorActor.class)); + ActorRef shardActorRef2 = getSystem().actorOf(Props.create(MessageCollectorActor.class)); + + TestActorRef shardManagerActorRef = TestActorRef.create(getSystem(), MockShardManager.props()); + MockShardManager shardManagerActor = shardManagerActorRef.underlyingActor(); + shardManagerActor.addFindPrimaryResp("shard1", new PrimaryFound(shardActorRef1.path().toString()).toSerializable()); + shardManagerActor.addFindPrimaryResp("shard2", new PrimaryFound(shardActorRef2.path().toString()).toSerializable()); + shardManagerActor.addFindPrimaryResp("shard3", new NoShardLeaderException("not found")); + + Configuration mockConfig = mock(Configuration.class); + doReturn(Sets.newLinkedHashSet(Arrays.asList("shard1", "shard2", "shard3"))). + when(mockConfig).getAllShardNames(); + + ActorContext actorContext = new ActorContext(getSystem(), shardManagerActorRef, + mock(ClusterWrapper.class), mockConfig, + DatastoreContext.newBuilder().shardInitializationTimeout(200, TimeUnit.MILLISECONDS).build()); + + actorContext.broadcast(new TestMessage()); + + expectFirstMatching(shardActorRef1, TestMessage.class); + expectFirstMatching(shardActorRef2, TestMessage.class); }}; } + + private T expectFirstMatching(ActorRef actor, Class clazz) { + int count = 5000 / 50; + for(int i = 0; i < count; i++) { + try { + T message = (T) MessageCollectorActor.getFirstMatching(actor, clazz); + if(message != null) { + return message; + } + } catch (Exception e) {} + + Uninterruptibles.sleepUninterruptibly(50, TimeUnit.MILLISECONDS); + } + + Assert.fail("Did not receive message of type " + clazz); + return null; + } }