X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2Fbehaviors%2FCandidateTest.java;h=485ee4b316d2506b35d31cfed5f6aa252f16bff3;hp=9efdbd7c54a497d6b07ce11977f35b7814a58e99;hb=1b69a9ae877e79ba6addb1b0e343692b2acff1ec;hpb=97222f19035815199200e727f43960513073eb9e diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java index 9efdbd7c54..485ee4b316 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/CandidateTest.java @@ -3,21 +3,22 @@ package org.opendaylight.controller.cluster.raft.behaviors; import akka.actor.ActorRef; import akka.actor.Props; import akka.testkit.JavaTestKit; -import junit.framework.Assert; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl; import org.opendaylight.controller.cluster.raft.MockRaftActorContext; import org.opendaylight.controller.cluster.raft.RaftActorContext; -import org.opendaylight.controller.cluster.raft.RaftState; -import org.opendaylight.controller.cluster.raft.internal.messages.ElectionTimeout; +import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.messages.AppendEntries; import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply; 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.Arrays; import java.util.Collections; - +import java.util.HashMap; +import java.util.Map; import static org.junit.Assert.assertEquals; public class CandidateTest extends AbstractRaftActorBehaviorTest { @@ -37,14 +38,40 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { private final ActorRef peerActor4 = getSystem().actorOf(Props.create( DoNothingActor.class)); + private final Map onePeer = new HashMap<>(); + private final Map twoPeers = new HashMap<>(); + private final Map fourPeers = new HashMap<>(); + + @Before + public void setUp(){ + onePeer.put(peerActor1.path().toString(), + peerActor1.path().toString()); + + twoPeers.put(peerActor1.path().toString(), + peerActor1.path().toString()); + twoPeers.put(peerActor2.path().toString(), + peerActor2.path().toString()); + + fourPeers.put(peerActor1.path().toString(), + peerActor1.path().toString()); + fourPeers.put(peerActor2.path().toString(), + peerActor2.path().toString()); + fourPeers.put(peerActor3.path().toString(), + peerActor3.path().toString()); + fourPeers.put(peerActor4.path().toString(), + peerActor3.path().toString()); + + + } + @Test public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself(){ RaftActorContext raftActorContext = createActorContext(); - long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm().get(); + long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm(); - new Candidate(raftActorContext, Collections.EMPTY_LIST); + new Candidate(raftActorContext); - assertEquals(expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm().get()); + assertEquals(expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm()); assertEquals(raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor()); } @@ -52,12 +79,12 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { public void testThatAnElectionTimeoutIsTriggered(){ new JavaTestKit(getSystem()) {{ - new Within(duration("1 seconds")) { + new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) { protected void run() { - Candidate candidate = new Candidate(createActorContext(getTestActor()), Collections.EMPTY_LIST); + Candidate candidate = new Candidate(createActorContext(getTestActor())); - final Boolean out = new ExpectMsg(duration("1 seconds"), "ElectionTimeout") { + final Boolean out = new ExpectMsg(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") { // do not put code outside this method, will run afterwards protected Boolean match(Object in) { if (in instanceof ElectionTimeout) { @@ -78,57 +105,56 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { public void testHandleElectionTimeoutWhenThereAreZeroPeers(){ RaftActorContext raftActorContext = createActorContext(); Candidate candidate = - new Candidate(raftActorContext, Collections.EMPTY_LIST); + new Candidate(raftActorContext); - RaftState raftState = + RaftActorBehavior raftBehavior = candidate.handleMessage(candidateActor, new ElectionTimeout()); - Assert.assertEquals(RaftState.Leader, raftState); + Assert.assertTrue(raftBehavior instanceof Leader); } @Test - public void testHandleElectionTimeoutWhenThereAreTwoPeers(){ - RaftActorContext raftActorContext = createActorContext(); + public void testHandleElectionTimeoutWhenThereAreTwoNodesInCluster(){ + MockRaftActorContext raftActorContext = + (MockRaftActorContext) createActorContext(); + raftActorContext.setPeerAddresses(onePeer); Candidate candidate = - new Candidate(raftActorContext, Arrays - .asList(peerActor1.path().toString(), - peerActor2.path().toString())); + new Candidate(raftActorContext); - RaftState raftState = + RaftActorBehavior raftBehavior = candidate.handleMessage(candidateActor, new ElectionTimeout()); - Assert.assertEquals(RaftState.Candidate, raftState); + Assert.assertTrue(raftBehavior instanceof Candidate); } @Test - public void testBecomeLeaderOnReceivingMajorityVotesInThreePeerCluster(){ - RaftActorContext raftActorContext = createActorContext(); + public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodesInCluster(){ + MockRaftActorContext raftActorContext = + (MockRaftActorContext) createActorContext(); + raftActorContext.setPeerAddresses(twoPeers); Candidate candidate = - new Candidate(raftActorContext, Arrays - .asList(peerActor1.path().toString(), - peerActor2.path().toString())); + new Candidate(raftActorContext); - RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); - Assert.assertEquals(RaftState.Leader, stateOnFirstVote); + Assert.assertTrue(behaviorOnFirstVote instanceof Leader); } @Test - public void testBecomeLeaderOnReceivingMajorityVotesInFivePeerCluster(){ - RaftActorContext raftActorContext = createActorContext(); + public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodesInCluster(){ + MockRaftActorContext raftActorContext = + (MockRaftActorContext) createActorContext(); + raftActorContext.setPeerAddresses(fourPeers); Candidate candidate = - new Candidate(raftActorContext, Arrays - .asList(peerActor1.path().toString(), - peerActor2.path().toString(), - peerActor3.path().toString())); + new Candidate(raftActorContext); - RaftState stateOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); - RaftState stateOnSecondVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true)); + RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true)); - Assert.assertEquals(RaftState.Candidate, stateOnFirstVote); - Assert.assertEquals(RaftState.Leader, stateOnSecondVote); + Assert.assertTrue(behaviorOnFirstVote instanceof Candidate); + Assert.assertTrue(behaviorOnSecondVote instanceof Leader); } @@ -139,9 +165,9 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { new Within(duration("1 seconds")) { protected void run() { - Candidate candidate = new Candidate(createActorContext(getTestActor()), Collections.EMPTY_LIST); + Candidate candidate = new Candidate(createActorContext(getTestActor())); - candidate.handleMessage(getTestActor(), new AppendEntries(0, "test", 0,0,Collections.EMPTY_LIST, 0)); + candidate.handleMessage(getTestActor(), new AppendEntries(0, "test", 0,0,Collections.emptyList(), 0)); final Boolean out = new ExpectMsg(duration("1 seconds"), "AppendEntriesResponse") { // do not put code outside this method, will run afterwards @@ -168,7 +194,7 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { new Within(duration("1 seconds")) { protected void run() { - Candidate candidate = new Candidate(createActorContext(getTestActor()), Collections.EMPTY_LIST); + Candidate candidate = new Candidate(createActorContext(getTestActor())); candidate.handleMessage(getTestActor(), new RequestVote(0, "test", 0, 0)); @@ -190,18 +216,83 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { }}; } + @Test + public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNull(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + RaftActorContext context = createActorContext(getTestActor()); + + context.getTermInformation().update(1000, null); + + // Once a candidate is created it will immediately increment the current term so after + // construction the currentTerm should be 1001 + RaftActorBehavior follower = createBehavior(context); + + follower.handleMessage(getTestActor(), new RequestVote(1001, "test", 10000, 999)); + + final Boolean out = new ExpectMsg(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 testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId(){ + new JavaTestKit(getSystem()) {{ + + new Within(duration("1 seconds")) { + protected void run() { + + RaftActorContext context = createActorContext(getTestActor()); + + context.getTermInformation().update(1000, "test"); + + RaftActorBehavior follower = createBehavior(context); + + follower.handleMessage(getTestActor(), new RequestVote(1001, "candidate", 10000, 999)); + + final Boolean out = new ExpectMsg(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); + } + }; + }}; + } + @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) { - return new Candidate(actorContext, Collections.EMPTY_LIST); + return new Candidate(actorContext); } @Override protected RaftActorContext createActorContext() { return new MockRaftActorContext("test", getSystem(), candidateActor); } - protected RaftActorContext createActorContext(ActorRef candidateActor) { - return new MockRaftActorContext("test", getSystem(), candidateActor); - } }