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%2Fbehaviors%2FCandidateTest.java;h=b04c9e39715acbb3566e2c5f11e77a0f132cbcf4;hb=HEAD;hp=c25127955d5b00c651c91257b5771938596daa00;hpb=dcc92fc8fdf056d5ada94931f2d24523070fd9a7;p=controller.git 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 c25127955d..b04c9e3971 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 @@ -10,10 +10,12 @@ package org.opendaylight.controller.cluster.raft.behaviors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; + import akka.actor.ActorRef; -import akka.actor.Props; +import akka.dispatch.Dispatchers; import akka.testkit.TestActorRef; import com.google.common.base.Stopwatch; +import com.google.common.util.concurrent.MoreExecutors; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -39,17 +41,19 @@ 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.persisted.SimpleReplicatedLogEntry; import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CandidateTest extends AbstractRaftActorBehaviorTest { +public class CandidateTest extends AbstractRaftActorBehaviorTest { static final Logger LOG = LoggerFactory.getLogger(CandidateTest.class); private final TestActorRef candidateActor = actorFactory.createTestActor( - Props.create(MessageCollectorActor.class), actorFactory.generateActorId("candidate")); + MessageCollectorActor.props().withDispatcher(Dispatchers.DefaultDispatcherId()), + actorFactory.generateActorId("candidate")); - private TestActorRef[] peerActors; + private ActorRef[] peerActors; private RaftActorBehavior candidate; @@ -59,8 +63,8 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { @Override @After - public void tearDown() throws Exception { - if(candidate != null) { + public void tearDown() { + if (candidate != null) { candidate.close(); } @@ -68,50 +72,51 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { } @Test - public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself(){ + public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself() { RaftActorContext raftActorContext = createActorContext(); long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm(); candidate = new Candidate(raftActorContext); - assertEquals("getCurrentTerm", expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm()); + assertEquals("getCurrentTerm", expectedTerm + 1, raftActorContext.getTermInformation().getCurrentTerm()); assertEquals("getVotedFor", raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor()); } @Test - public void testThatAnElectionTimeoutIsTriggered(){ - MockRaftActorContext actorContext = createActorContext(); - candidate = new Candidate(actorContext); + public void testThatAnElectionTimeoutIsTriggered() { + MockRaftActorContext actorContext = createActorContext(); + candidate = new Candidate(actorContext); - MessageCollectorActor.expectFirstMatching(candidateActor, ElectionTimeout.class, - actorContext.getConfigParams().getElectionTimeOutInterval().$times(6).toMillis()); + MessageCollectorActor.expectFirstMatching(candidateActor, ElectionTimeout.class, + actorContext.getConfigParams().getElectionTimeOutInterval().$times(6).toMillis()); } @Test - public void testHandleElectionTimeoutWhenThereAreZeroPeers(){ + public void testHandleElectionTimeoutWhenThereAreZeroPeers() { RaftActorContext raftActorContext = createActorContext(); candidate = new Candidate(raftActorContext); RaftActorBehavior newBehavior = - candidate.handleMessage(candidateActor, new ElectionTimeout()); + candidate.handleMessage(candidateActor, ElectionTimeout.INSTANCE); assertEquals("Behavior", RaftState.Leader, newBehavior.state()); } @Test - public void testHandleElectionTimeoutWhenThereAreTwoNodeCluster(){ + public void testHandleElectionTimeoutWhenThereAreTwoNodeCluster() { MockRaftActorContext raftActorContext = createActorContext(); raftActorContext.setPeerAddresses(setupPeers(1)); candidate = new Candidate(raftActorContext); - candidate = candidate.handleMessage(candidateActor, new ElectionTimeout()); + candidate = candidate.handleMessage(candidateActor, ElectionTimeout.INSTANCE); assertEquals("Behavior", RaftState.Candidate, candidate.state()); } @Test - public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodeCluster(){ + public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodeCluster() { MockRaftActorContext raftActorContext = createActorContext(); + raftActorContext.setLastApplied(raftActorContext.getReplicatedLog().lastIndex()); raftActorContext.setPeerAddresses(setupPeers(2)); candidate = new Candidate(raftActorContext); @@ -121,11 +126,26 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { } @Test - public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodeCluster(){ + public void testBecomePreLeaderOnReceivingMajorityVotesInThreeNodeCluster() { + MockRaftActorContext raftActorContext = createActorContext(); + raftActorContext.setLastApplied(-1); + raftActorContext.setPeerAddresses(setupPeers(2)); + candidate = new Candidate(raftActorContext); + + candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, true)); + + // LastApplied is -1 and behind the last index. + assertEquals("Behavior", RaftState.PreLeader, candidate.state()); + } + + @Test + public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodeCluster() { MockRaftActorContext raftActorContext = createActorContext(); raftActorContext.getTermInformation().update(2L, "other"); - raftActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder(). - createEntries(0, 5, 1).build()); + raftActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder() + .createEntries(0, 5, 1).build()); + raftActorContext.setCommitIndex(raftActorContext.getReplicatedLog().lastIndex()); + raftActorContext.setLastApplied(raftActorContext.getReplicatedLog().lastIndex()); raftActorContext.setPeerAddresses(setupPeers(4)); candidate = new Candidate(raftActorContext); @@ -154,14 +174,12 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { } @Test - public void testBecomeLeaderOnReceivingMajorityVotesWithNonVotingPeers(){ + public void testBecomeLeaderOnReceivingMajorityVotesWithNonVotingPeers() { ElectionTerm mockElectionTerm = Mockito.mock(ElectionTerm.class); Mockito.doReturn(1L).when(mockElectionTerm).getCurrentTerm(); - Mockito.doNothing().when(mockElectionTerm).updateAndPersist(Mockito.any(long.class), Mockito.any(String.class)); - RaftActorContext raftActorContext = new RaftActorContextImpl(candidateActor, candidateActor.actorContext(), "candidate", mockElectionTerm, -1, -1, setupPeers(4), new DefaultConfigParamsImpl(), - new NonPersistentDataProvider(), LOG); + new NonPersistentDataProvider(Runnable::run), applyState -> { }, LOG, MoreExecutors.directExecutor()); raftActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().build()); raftActorContext.getPeerInfo("peer1").setVotingState(VotingState.NON_VOTING); raftActorContext.getPeerInfo("peer4").setVotingState(VotingState.NON_VOTING); @@ -275,7 +293,7 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { } @Test - public void testCandidateSchedulesElectionTimeoutImmediatelyWhenItHasNoPeers(){ + public void testCandidateSchedulesElectionTimeoutImmediatelyWhenItHasNoPeers() { MockRaftActorContext context = createActorContext(); Stopwatch stopwatch = Stopwatch.createStarted(); @@ -291,7 +309,7 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { @Test @Override - public void testHandleAppendEntriesAddSameEntryToLog() throws Exception { + public void testHandleAppendEntriesAddSameEntryToLog() { MockRaftActorContext context = createActorContext(); context.getTermInformation().update(2, "test"); @@ -301,9 +319,9 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { setLastLogEntry(context, 2, 0, payload); List entries = new ArrayList<>(); - entries.add(new MockRaftActorContext.MockReplicatedLogEntry(2, 0, payload)); + entries.add(new SimpleReplicatedLogEntry(0, 2, payload)); - AppendEntries appendEntries = new AppendEntries(2, "leader-1", -1, -1, entries, 2, -1, (short)0); + final AppendEntries appendEntries = new AppendEntries(2, "leader-1", -1, -1, entries, 2, -1, (short)0); behavior = createBehavior(context); @@ -315,8 +333,7 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { context.getTermInformation().update(2, "test"); // Send an unknown message so that the state of the RaftActor remains unchanged - RaftActorBehavior expected = behavior.handleMessage(candidateActor, "unknown"); - assertTrue(expected instanceof Candidate); + behavior.handleMessage(candidateActor, "unknown"); RaftActorBehavior raftBehavior = behavior.handleMessage(candidateActor, appendEntries); @@ -328,31 +345,36 @@ public class CandidateTest extends AbstractRaftActorBehaviorTest { } @Override - protected RaftActorBehavior createBehavior(RaftActorContext actorContext) { + protected Candidate createBehavior(final RaftActorContext actorContext) { return new Candidate(actorContext); } - @Override protected MockRaftActorContext createActorContext() { + @Override + protected MockRaftActorContext createActorContext() { return new MockRaftActorContext("candidate", getSystem(), candidateActor); } - @SuppressWarnings("unchecked") - private Map setupPeers(int count) { + private Map setupPeers(final int count) { Map peerMap = new HashMap<>(); - peerActors = new TestActorRef[count]; - for(int i = 0; i < count; i++) { - peerActors[i] = actorFactory.createTestActor(Props.create(MessageCollectorActor.class), + peerActors = new ActorRef[count]; + for (int i = 0; i < count; i++) { + peerActors[i] = actorFactory.createActor(MessageCollectorActor.props(), actorFactory.generateActorId("peer")); - peerMap.put("peer" + (i+1), peerActors[i].path().toString()); + peerMap.put("peer" + (i + 1), peerActors[i].path().toString()); } return peerMap; } @Override - protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(RaftActorContext actorContext, - ActorRef actorRef, RaftRPC rpc) throws Exception { + protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(final MockRaftActorContext actorContext, + final ActorRef actorRef, final RaftRPC rpc) { super.assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, actorRef, rpc); - assertEquals("New votedFor", null, actorContext.getTermInformation().getVotedFor()); + if (rpc instanceof RequestVote) { + assertEquals("New votedFor", ((RequestVote)rpc).getCandidateId(), + actorContext.getTermInformation().getVotedFor()); + } else { + assertEquals("New votedFor", null, actorContext.getTermInformation().getVotedFor()); + } } }