Merge "Get some basic unit testing in place for the RaftActor class"
authorEd Warnicke <eaw@cisco.com>
Mon, 25 Aug 2014 18:03:51 +0000 (18:03 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 25 Aug 2014 18:03:51 +0000 (18:03 +0000)
opendaylight/md-sal/sal-akka-raft/pom.xml
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/RaftActor.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeader.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/client/messages/FindLeaderReply.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/AbstractActorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/resources/application.conf

index 3dcc546426165ac578486c5dd528b7b8cb4d0766..084ef16f575ce67c8725031e2742a86f1f7105d5 100644 (file)
       <artifactId>scala-library</artifactId>
     </dependency>
 
-    <!-- Test Dependencies -->
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.typesafe.akka</groupId>
+      <artifactId>akka-slf4j_${scala.version}</artifactId>
+    </dependency>
+
+
+      <!-- Test Dependencies -->
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
         <artifactId>jacoco-maven-plugin</artifactId>
         <configuration>
           <includes>
-            <include>org.opendaylight.controller.*</include>
+            <include>org/opendaylight/controller/cluster/**/*</include>
           </includes>
+          <excludes>
+              <exclude>org/opendaylight/controller/cluster/raft/protobuff/**/*</exclude>
+              <exclude>org/opendaylight/controller/cluster/example/**/*</exclude>
+          </excludes>
           <check>false</check>
         </configuration>
         <executions>
index ae8b6fe8e3aadc23a33cf57531a43ff9cefed8d4..988789b4011e4f3ba9e9e9abe6b0c3009704c810 100644 (file)
@@ -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 {
 
index a60aea46e82965d0ded03eb7464941bf1a62f4af..98dd0d46531cadef35f8832a89237a1a95ae44fd 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.cluster.raft.client.messages;
 
-public class FindLeader {
+import java.io.Serializable;
+
+public class FindLeader implements Serializable{
 
 }
index b36ef112b364371d01d9e7f411fdf27761938606..64c73508960144ab3f0095ba3af34c897217c336 100644 (file)
@@ -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) {
index 1971432fb9844f747d39e37c8546c7568632f7c0..ec5381546964d7c8846ed446e4947baebe48380f 100644 (file)
@@ -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 (file)
index 0000000..ff0ffeb
--- /dev/null
@@ -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<String, String> peerAddresses) {
+            super(id, peerAddresses);
+        }
+
+        public static Props props(final String id, final Map<String, String> peerAddresses){
+            return Props.create(new Creator<MockRaftActor>(){
+
+                @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<Boolean>(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<String>(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());
+    }
+
+
+}
index dbe7508cc8c185a33a35fcf072498041b589854c..2b753004c48265620628fdbc58a1e41a96a65c51 100644 (file)
@@ -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