Properly handle RequestVote in all states
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / AbstractRaftActorBehaviorTest.java
index e6bf26cdcdd9d8beefbcd1557c096ec24f312736..1e7aa6a1d5fe40e2fd57e3088e80dc0dcbe1d653 100644 (file)
@@ -1,6 +1,7 @@
 package org.opendaylight.controller.cluster.raft.behaviors;
 
 import akka.actor.ActorRef;
+import akka.actor.Props;
 import akka.testkit.JavaTestKit;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.raft.AbstractActorTest;
@@ -12,12 +13,17 @@ import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
 import org.opendaylight.controller.cluster.raft.messages.RaftRPC;
 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
+import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
 
 import java.util.concurrent.atomic.AtomicLong;
 
 import static org.junit.Assert.assertEquals;
 
 public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest{
+
+    private final ActorRef behaviorActor = getSystem().actorOf(Props.create(
+        DoNothingActor.class));
+
    @Test
     public void testHandlingOfRaftRPCWithNewerTerm() throws Exception {
         new JavaTestKit(getSystem()) {{
@@ -45,7 +51,7 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest{
             RaftActorContext context =
                 createActorContext();
 
-            ((MockRaftActorContext) context).setLastApplied(new AtomicLong(100));
+            ((MockRaftActorContext) context).setLastApplied(100);
 
             AppendEntries appendEntries =
                 new AppendEntries(100, "leader-1", 0, 0, null, 101);
@@ -53,8 +59,114 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest{
             RaftState raftState =
                 createBehavior(context).handleMessage(getRef(), appendEntries);
 
-            assertEquals(new AtomicLong(101).get(), context.getLastApplied().get());
+            assertEquals(new AtomicLong(101).get(), context.getLastApplied());
+
+        }};
+    }
+
+    @Test
+    public void testHandleRequestVoteWhenSenderTermGreaterThanCurrentTermAndSenderLogMoreUpToDate(){
+        new JavaTestKit(getSystem()) {{
+
+            new Within(duration("1 seconds")) {
+                protected void run() {
+
+                    RaftActorBehavior follower = createBehavior(
+                        createActorContext(behaviorActor));
+
+                    follower.handleMessage(getTestActor(), new RequestVote(1000, "test", 10000, 999));
+
+                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
+                        // do not put code outside this method, will run afterwards
+                        protected Boolean match(Object in) {
+                            if (in instanceof RequestVoteReply) {
+                                RequestVoteReply reply = (RequestVoteReply) in;
+                                return reply.isVoteGranted();
+                            } else {
+                                throw noMatch();
+                            }
+                        }
+                    }.get();
+
+                    assertEquals(true, out);
+                }
+            };
+        }};
+    }
+
+    @Test
+    public void testHandleRequestVoteWhenSenderTermGreaterThanCurrentTermButSenderLogLessUptoDate(){
+        new JavaTestKit(getSystem()) {{
+
+            new Within(duration("1 seconds")) {
+                protected void run() {
+
+                    RaftActorContext actorContext =
+                        createActorContext(behaviorActor);
+
+                    MockRaftActorContext.MockReplicatedLog log = new MockRaftActorContext.MockReplicatedLog();
+                    log.setReplicatedLogEntry(new MockRaftActorContext.MockReplicatedLogEntry(20000, 1000000, ""));
+                    log.setLast(
+                        new MockRaftActorContext.MockReplicatedLogEntry(20000,
+                            1000000, ""));
+
+                    ((MockRaftActorContext) actorContext).setReplicatedLog(log);
+
+                    RaftActorBehavior follower = createBehavior(actorContext);
+
+                    follower.handleMessage(getTestActor(), new RequestVote(1000, "test", 10000, 999));
 
+                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
+                        // do not put code outside this method, will run afterwards
+                        protected Boolean match(Object in) {
+                            if (in instanceof RequestVoteReply) {
+                                RequestVoteReply reply = (RequestVoteReply) in;
+                                return reply.isVoteGranted();
+                            } else {
+                                throw noMatch();
+                            }
+                        }
+                    }.get();
+
+                    assertEquals(false, out);
+                }
+            };
+        }};
+    }
+
+
+
+
+    @Test
+    public void testHandleRequestVoteWhenSenderTermLessThanCurrentTerm(){
+        new JavaTestKit(getSystem()) {{
+
+            new Within(duration("1 seconds")) {
+                protected void run() {
+
+                    RaftActorContext context = createActorContext(behaviorActor);
+
+                    context.getTermInformation().update(1000, null);
+
+                    RaftActorBehavior follower = createBehavior(context);
+
+                    follower.handleMessage(getTestActor(), new RequestVote(999, "test", 10000, 999));
+
+                    final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
+                        // do not put code outside this method, will run afterwards
+                        protected Boolean match(Object in) {
+                            if (in instanceof RequestVoteReply) {
+                                RequestVoteReply reply = (RequestVoteReply) in;
+                                return reply.isVoteGranted();
+                            } else {
+                                throw noMatch();
+                            }
+                        }
+                    }.get();
+
+                    assertEquals(false, out);
+                }
+            };
         }};
     }
 
@@ -76,6 +188,10 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest{
         return new MockRaftActorContext();
     }
 
+    protected RaftActorContext createActorContext(ActorRef actor) {
+        return new MockRaftActorContext("test", getSystem(), actor);
+    }
+
     protected AppendEntries createAppendEntriesWithNewerTerm(){
         return new AppendEntries(100, "leader-1", 0, 0, null, 1);
     }
@@ -92,4 +208,6 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest{
         return new RequestVoteReply(100, false);
     }
 
+
+
 }