X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2FTestActorFactory.java;h=ea38c16acc95fc5110165feba04d504f5434fbb0;hb=e9fc7e7ed2b13d274518d6a872ab67749ef4507a;hp=4ca018c5e2a29634f37a716fe889367a3b0f789d;hpb=250f3f77c80284536cc32e96739f713d21844103;p=controller.git diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java index 4ca018c5e2..ea38c16acc 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java @@ -8,25 +8,25 @@ package org.opendaylight.controller.cluster.raft; -/* - * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ - import akka.actor.Actor; +import akka.actor.ActorIdentity; import akka.actor.ActorRef; +import akka.actor.ActorSelection; import akka.actor.ActorSystem; +import akka.actor.Identify; +import akka.actor.InvalidActorNameException; import akka.actor.PoisonPill; import akka.actor.Props; -import akka.testkit.JavaTestKit; +import akka.pattern.Patterns; import akka.testkit.TestActorRef; +import akka.testkit.javadsl.TestKit; import akka.util.Timeout; +import com.google.common.base.Stopwatch; +import com.google.common.util.concurrent.Uninterruptibles; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; +import org.junit.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import scala.concurrent.Await; @@ -34,7 +34,8 @@ import scala.concurrent.Future; /** * TestActorFactory provides methods to create both normal and test actors and to kill them when the factory is closed - * The ideal usage for TestActorFactory is with try with resources,
+ * The ideal usage for TestActorFactory is with try with resources. + *

* For example
*

  *     try (TestActorFactory factory = new TestActorFactory(getSystem())){
@@ -45,122 +46,157 @@ import scala.concurrent.Future;
  * 
*/ public class TestActorFactory implements AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(TestActorFactory.class); + private final ActorSystem system; List createdActors = new LinkedList<>(); - Logger LOG = LoggerFactory.getLogger(getClass()); private static int actorCount = 1; - public TestActorFactory(ActorSystem system){ + public TestActorFactory(ActorSystem system) { this.system = system; } /** - * Create a normal actor with an auto-generated name + * Create a normal actor with an auto-generated name. * - * @param props - * @return + * @param props the actor Props + * @return the ActorRef */ - public ActorRef createActor(Props props){ + public ActorRef createActor(Props props) { ActorRef actorRef = system.actorOf(props); - return addActor(actorRef); + return addActor(actorRef, true); + } + + /** + * Create a normal actor with the passed in name. + * + * @param props the actor Props + * @param actorId name of actor + * @return the ActorRef + */ + public ActorRef createActor(Props props, String actorId) { + ActorRef actorRef = system.actorOf(props, actorId); + return addActor(actorRef, true); } /** - * Create a normal actor with the passed in name - * @param props + * Create a normal actor with the passed in name w/o verifying that the actor is ready. + * + * @param props the actor Props * @param actorId name of actor - * @return + * @return the ActorRef */ - public ActorRef createActor(Props props, String actorId){ + public ActorRef createActorNoVerify(Props props, String actorId) { ActorRef actorRef = system.actorOf(props, actorId); - return addActor(actorRef); + return addActor(actorRef, false); + } + + /** + * Create a test actor with the passed in name. + * + * @param props the actor Props + * @param actorId name of actor + * @param the actor type + * @return the ActorRef + */ + @SuppressWarnings("unchecked") + public TestActorRef createTestActor(Props props, String actorId) { + InvalidActorNameException lastError = null; + for (int i = 0; i < 10; i++) { + try { + TestActorRef actorRef = TestActorRef.create(system, props, actorId); + return (TestActorRef) addActor(actorRef, true); + } catch (InvalidActorNameException e) { + lastError = e; + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + } + } + + throw lastError; } /** - * Create a test actor with the passed in name - * @param props - * @param actorId - * @param - * @return + * Create a test actor with an auto-generated name. + * + * @param props the actor Props + * @param the actor type + * @return the TestActorRef */ @SuppressWarnings("unchecked") - public TestActorRef createTestActor(Props props, String actorId){ - TestActorRef actorRef = TestActorRef.create(system, props, actorId); - return (TestActorRef) addActor(actorRef); + public TestActorRef createTestActor(Props props) { + TestActorRef actorRef = TestActorRef.create(system, props); + return (TestActorRef) addActor(actorRef, true); } - private ActorRef addActor(T actorRef) { + private ActorRef addActor(T actorRef, boolean verify) { createdActors.add(actorRef); - verifyActorReady(actorRef); + if (verify) { + verifyActorReady(actorRef); + } + return actorRef; } + @SuppressWarnings("checkstyle:IllegalCatch") private void verifyActorReady(ActorRef actorRef) { // Sometimes we see messages go to dead letters soon after creation - it seems the actor isn't quite // in a state yet to receive messages or isn't actually created yet. This seems to happen with - // actorSelection so, to alleviate it, we use an actorSelection and call resolveOne with retries to - // ensure it's ready. + // actorSelection so, to alleviate it, we use an actorSelection and send an Identify message with + // retries to ensure it's ready. - int tries = 1; - while(true) { + Timeout timeout = new Timeout(100, TimeUnit.MILLISECONDS); + Throwable lastError = null; + Stopwatch sw = Stopwatch.createStarted(); + while (sw.elapsed(TimeUnit.SECONDS) <= 10) { try { - Timeout timeout = new Timeout(100, TimeUnit.MILLISECONDS); - Future future = system.actorSelection(actorRef.path()).resolveOne(timeout); - Await.ready(future, timeout.duration()); - break; - } catch (Exception e) { - if(tries++ > 20) { - throw new RuntimeException(e); - } + ActorSelection actorSelection = system.actorSelection(actorRef.path().toString()); + Future future = Patterns.ask(actorSelection, new Identify(""), timeout); + ActorIdentity reply = (ActorIdentity)Await.result(future, timeout.duration()); + Assert.assertNotNull("Identify returned null", reply.getRef()); + return; + } catch (Exception | AssertionError e) { + Uninterruptibles.sleepUninterruptibly(100, TimeUnit.MILLISECONDS); + lastError = e; } } - } - /** - * Create a test actor with an auto-generated name - * @param props - * @param - * @return - */ - @SuppressWarnings("unchecked") - public TestActorRef createTestActor(Props props){ - TestActorRef actorRef = TestActorRef.create(system, props); - return (TestActorRef) addActor(actorRef); + throw new RuntimeException(lastError); } /** - * Generate a friendly but unique actor id/name - * @param prefix - * @return + * Generate a friendly but unique actor id/name. + * + * @param prefix the name prefix + * @return the actor name */ - public String generateActorId(String prefix){ + public String generateActorId(String prefix) { return prefix + actorCount++; } - public void killActor(ActorRef actor, JavaTestKit kit) { + public void killActor(ActorRef actor, TestKit kit) { killActor(actor, kit, true); } - public String createTestActorPath(String actorId){ - return "akka://test/user/" + actorId; - } - - private void killActor(ActorRef actor, JavaTestKit kit, boolean remove) { + private void killActor(ActorRef actor, TestKit kit, boolean remove) { LOG.info("Killing actor {}", actor); kit.watch(actor); actor.tell(PoisonPill.getInstance(), ActorRef.noSender()); - kit.expectTerminated(JavaTestKit.duration("5 seconds"), actor); + kit.expectTerminated(kit.duration("5 seconds"), actor); - if(remove) { + if (remove) { createdActors.remove(actor); } } + public String createTestActorPath(String actorId) { + return "akka://test/user/" + actorId; + } + @Override public void close() { - JavaTestKit kit = new JavaTestKit(system); - for(ActorRef actor : createdActors) { + TestKit kit = new TestKit(system); + for (ActorRef actor : createdActors) { killActor(actor, kit, false); } } -} \ No newline at end of file +}