From 83f7f24d355f87d8c1a850098d5b7c82e5d746dd Mon Sep 17 00:00:00 2001 From: Moiz Raja Date: Thu, 14 Aug 2014 15:02:58 -0700 Subject: [PATCH] Get some basic unit testing in place for the RaftActor class The two tests that were added do the following, - test construction - test finding a leader when the current raft actor is the leader This commit also specifies the proper includes and excludes for code coverage Change-Id: I5898c4a7f4044f13587fe5d58878d560f60e65dc Signed-off-by: Moiz Raja --- opendaylight/md-sal/sal-akka-raft/pom.xml | 19 ++- .../controller/cluster/raft/RaftActor.java | 37 +++-- .../raft/client/messages/FindLeader.java | 4 +- .../raft/client/messages/FindLeaderReply.java | 4 +- .../cluster/raft/AbstractActorTest.java | 18 ++- .../cluster/raft/RaftActorTest.java | 137 ++++++++++++++++++ .../src/test/resources/application.conf | 3 +- 7 files changed, 196 insertions(+), 26 deletions(-) create mode 100644 opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java diff --git a/opendaylight/md-sal/sal-akka-raft/pom.xml b/opendaylight/md-sal/sal-akka-raft/pom.xml index 3dcc546426..084ef16f57 100644 --- a/opendaylight/md-sal/sal-akka-raft/pom.xml +++ b/opendaylight/md-sal/sal-akka-raft/pom.xml @@ -55,7 +55,18 @@ scala-library - + + commons-io + commons-io + + + + com.typesafe.akka + akka-slf4j_${scala.version} + + + + junit junit @@ -110,8 +121,12 @@ jacoco-maven-plugin - org.opendaylight.controller.* + org/opendaylight/controller/cluster/**/* + + org/opendaylight/controller/cluster/raft/protobuff/**/* + org/opendaylight/controller/cluster/example/**/* + false diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java index ae8b6fe8e3..988789b401 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java @@ -168,8 +168,7 @@ public abstract class RaftActor extends UntypedPersistentActor { } else if (message instanceof FindLeader) { getSender().tell( - new FindLeaderReply( - context.getPeerAddress(currentBehavior.getLeaderId())), + new FindLeaderReply(getLeaderAddress()), getSelf() ); @@ -183,12 +182,6 @@ public abstract class RaftActor extends UntypedPersistentActor { // TODO: Handle failure in saving the snapshot - } else if (message instanceof FindLeader){ - - getSender().tell(new FindLeaderReply( - context.getPeerAddress(currentBehavior.getLeaderId())), - getSelf()); - } else if (message instanceof AddRaftPeer){ // FIXME : Do not add raft peers like this. @@ -269,18 +262,9 @@ public abstract class RaftActor extends UntypedPersistentActor { * @return A reference to the leader if known, null otherwise */ protected ActorSelection getLeader(){ - String leaderId = currentBehavior.getLeaderId(); - if (leaderId == null) { - return null; - } - String peerAddress = context.getPeerAddress(leaderId); - LOG.debug("getLeader leaderId = " + leaderId + " peerAddress = " - + peerAddress); + String leaderAddress = getLeaderAddress(); - if(peerAddress == null){ - return null; - } - return context.actorSelection(peerAddress); + return context.actorSelection(leaderAddress); } /** @@ -424,6 +408,21 @@ public abstract class RaftActor extends UntypedPersistentActor { deleteMessages(sequenceNumber); } + private String getLeaderAddress(){ + if(isLeader()){ + return getSelf().path().toString(); + } + String leaderId = currentBehavior.getLeaderId(); + if (leaderId == null) { + return null; + } + String peerAddress = context.getPeerAddress(leaderId); + LOG.debug("getLeaderAddress leaderId = " + leaderId + " peerAddress = " + + peerAddress); + + return peerAddress; + } + private class ReplicatedLogImpl extends AbstractReplicatedLogImpl { diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java index a60aea46e8..98dd0d4653 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.cluster.raft.client.messages; -public class FindLeader { +import java.io.Serializable; + +public class FindLeader implements Serializable{ } diff --git a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java index b36ef112b3..64c7350896 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java +++ b/opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java @@ -8,7 +8,9 @@ package org.opendaylight.controller.cluster.raft.client.messages; -public class FindLeaderReply { +import java.io.Serializable; + +public class FindLeaderReply implements Serializable { private final String leaderActor; public FindLeaderReply(String leaderActor) { diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java index 1971432fb9..ec53815469 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java @@ -10,20 +10,26 @@ package org.opendaylight.controller.cluster.raft; import akka.actor.ActorSystem; import akka.testkit.JavaTestKit; +import org.apache.commons.io.FileUtils; import org.junit.AfterClass; import org.junit.BeforeClass; +import java.io.File; +import java.io.IOException; + public abstract class AbstractActorTest { private static ActorSystem system; @BeforeClass - public static void setUpClass() { + public static void setUpClass() throws Exception{ + deleteJournal(); System.setProperty("shard.persistent", "false"); system = ActorSystem.create("test"); } @AfterClass - public static void tearDownClass() { + public static void tearDownClass() throws Exception{ + deleteJournal(); JavaTestKit.shutdownActorSystem(system); system = null; } @@ -32,4 +38,12 @@ public abstract class AbstractActorTest { return system; } + protected static void deleteJournal() throws IOException { + File journal = new File("journal"); + + if(journal.exists()) { + FileUtils.deleteDirectory(journal); + } + } + } diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java new file mode 100644 index 0000000000..ff0ffeb271 --- /dev/null +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java @@ -0,0 +1,137 @@ +package org.opendaylight.controller.cluster.raft; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.event.Logging; +import akka.japi.Creator; +import akka.testkit.JavaTestKit; +import org.junit.Test; +import org.opendaylight.controller.cluster.raft.client.messages.FindLeader; +import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply; + +import java.util.Collections; +import java.util.Map; + +import static junit.framework.TestCase.assertEquals; + +public class RaftActorTest extends AbstractActorTest { + + + public static class MockRaftActor extends RaftActor { + + public MockRaftActor(String id, + Map peerAddresses) { + super(id, peerAddresses); + } + + public static Props props(final String id, final Map peerAddresses){ + return Props.create(new Creator(){ + + @Override public MockRaftActor create() throws Exception { + return new MockRaftActor(id, peerAddresses); + } + }); + } + + @Override protected void applyState(ActorRef clientActor, + String identifier, + Object data) { + } + + @Override protected Object createSnapshot() { + throw new UnsupportedOperationException("createSnapshot"); + } + + @Override protected void applySnapshot(Object snapshot) { + throw new UnsupportedOperationException("applySnapshot"); + } + + @Override protected void onStateChanged() { + } + + @Override public String persistenceId() { + return this.getId(); + } + + } + + + private static class RaftActorTestKit extends JavaTestKit { + private final ActorRef raftActor; + + public RaftActorTestKit(ActorSystem actorSystem, String actorName) { + super(actorSystem); + + raftActor = this.getSystem() + .actorOf(MockRaftActor.props(actorName, + Collections.EMPTY_MAP), actorName); + + } + + + public boolean waitForStartup(){ + // Wait for a specific log message to show up + return + new JavaTestKit.EventFilter(Logging.Info.class + ) { + protected Boolean run() { + return true; + } + }.from(raftActor.path().toString()) + .message("Switching from state Candidate to Leader") + .occurrences(1).exec(); + + + } + + public void findLeader(final String expectedLeader){ + + + new Within(duration("1 seconds")) { + protected void run() { + + raftActor.tell(new FindLeader(), getRef()); + + String s = new ExpectMsg(duration("1 seconds"), + "findLeader") { + // do not put code outside this method, will run afterwards + protected String match(Object in) { + if (in instanceof FindLeaderReply) { + return ((FindLeaderReply) in).getLeaderActor(); + } else { + throw noMatch(); + } + } + }.get();// this extracts the received message + + assertEquals(expectedLeader, s); + + } + + + }; + } + + public ActorRef getRaftActor() { + return raftActor; + } + + } + + + @Test + public void testConstruction() { + boolean started = new RaftActorTestKit(getSystem(), "testConstruction").waitForStartup(); + assertEquals(true, started); + } + + @Test + public void testFindLeaderWhenLeaderIsSelf(){ + RaftActorTestKit kit = new RaftActorTestKit(getSystem(), "testFindLeader"); + kit.waitForStartup(); + kit.findLeader(kit.getRaftActor().path().toString()); + } + + +} diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf b/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf index dbe7508cc8..2b753004c4 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf +++ b/opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf @@ -1,6 +1,6 @@ akka { - loglevel = "DEBUG" + loggers = ["akka.testkit.TestEventListener", "akka.event.slf4j.Slf4jLogger"] actor { # enable to test serialization only. @@ -12,6 +12,7 @@ akka { } serialization-bindings { + "org.opendaylight.controller.cluster.raft.client.messages.FindLeader" = java "org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry" = java "com.google.protobuf.Message" = proto "com.google.protobuf.GeneratedMessage" = proto -- 2.36.6