+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
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.testkit.JavaTestKit;
-import org.junit.Assert;
+import akka.testkit.TestActorRef;
+import com.google.common.base.Stopwatch;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.cluster.NonPersistentDataProvider;
import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
+import org.opendaylight.controller.cluster.raft.ElectionTerm;
import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
import org.opendaylight.controller.cluster.raft.RaftActorContext;
+import org.opendaylight.controller.cluster.raft.RaftActorContextImpl;
+import org.opendaylight.controller.cluster.raft.RaftState;
import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.VotingState;
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.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.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import static org.junit.Assert.assertEquals;
+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<Candidate> {
+ static final Logger LOG = LoggerFactory.getLogger(CandidateTest.class);
- private final ActorRef candidateActor = getSystem().actorOf(Props.create(
- DoNothingActor.class));
+ private final TestActorRef<MessageCollectorActor> candidateActor = actorFactory.createTestActor(
+ Props.create(MessageCollectorActor.class), actorFactory.generateActorId("candidate"));
- private final ActorRef peerActor1 = getSystem().actorOf(Props.create(
- DoNothingActor.class));
+ private TestActorRef<MessageCollectorActor>[] peerActors;
- private final ActorRef peerActor2 = getSystem().actorOf(Props.create(
- DoNothingActor.class));
+ private RaftActorBehavior candidate;
- private final ActorRef peerActor3 = getSystem().actorOf(Props.create(
- DoNothingActor.class));
+ @Before
+ public void setUp(){
+ }
- private final ActorRef peerActor4 = getSystem().actorOf(Props.create(
- DoNothingActor.class));
+ @Override
+ @After
+ public void tearDown() {
+ if (candidate != null) {
+ candidate.close();
+ }
- private final Map<String, String> onePeer = new HashMap<>();
- private final Map<String, String> twoPeers = new HashMap<>();
- private final Map<String, String> fourPeers = new HashMap<>();
+ super.tearDown();
+ }
- @Before
- public void setUp(){
- onePeer.put(peerActor1.path().toString(),
- peerActor1.path().toString());
+ @Test
+ public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself() {
+ RaftActorContext raftActorContext = createActorContext();
+ long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm();
- twoPeers.put(peerActor1.path().toString(),
- peerActor1.path().toString());
- twoPeers.put(peerActor2.path().toString(),
- peerActor2.path().toString());
+ candidate = new Candidate(raftActorContext);
- 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());
+ 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);
+ MessageCollectorActor.expectFirstMatching(candidateActor, ElectionTimeout.class,
+ actorContext.getConfigParams().getElectionTimeOutInterval().$times(6).toMillis());
}
@Test
- public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself(){
+ public void testHandleElectionTimeoutWhenThereAreZeroPeers() {
RaftActorContext raftActorContext = createActorContext();
- long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm();
+ candidate = new Candidate(raftActorContext);
- new Candidate(raftActorContext);
+ RaftActorBehavior newBehavior =
+ candidate.handleMessage(candidateActor, ElectionTimeout.INSTANCE);
- assertEquals(expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm());
- assertEquals(raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor());
+ assertEquals("Behavior", RaftState.Leader, newBehavior.state());
}
@Test
- public void testThatAnElectionTimeoutIsTriggered(){
- new JavaTestKit(getSystem()) {{
-
- new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) {
- protected void run() {
-
- Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
- final Boolean out = new ExpectMsg<Boolean>(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) {
- return true;
- } else {
- throw noMatch();
- }
- }
- }.get();
-
- assertEquals(true, out);
- }
- };
- }};
+ public void testHandleElectionTimeoutWhenThereAreTwoNodeCluster() {
+ MockRaftActorContext raftActorContext = createActorContext();
+ raftActorContext.setPeerAddresses(setupPeers(1));
+ candidate = new Candidate(raftActorContext);
+
+ candidate = candidate.handleMessage(candidateActor, ElectionTimeout.INSTANCE);
+
+ assertEquals("Behavior", RaftState.Candidate, candidate.state());
}
@Test
- public void testHandleElectionTimeoutWhenThereAreZeroPeers(){
- RaftActorContext raftActorContext = createActorContext();
- Candidate candidate =
- new Candidate(raftActorContext);
+ public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodeCluster() {
+ MockRaftActorContext raftActorContext = createActorContext();
+ raftActorContext.setLastApplied(raftActorContext.getReplicatedLog().lastIndex());
+ raftActorContext.setPeerAddresses(setupPeers(2));
+ candidate = new Candidate(raftActorContext);
- RaftActorBehavior raftBehavior =
- candidate.handleMessage(candidateActor, new ElectionTimeout());
+ candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, true));
- Assert.assertTrue(raftBehavior instanceof Leader);
+ assertEquals("Behavior", RaftState.Leader, candidate.state());
}
@Test
- public void testHandleElectionTimeoutWhenThereAreTwoNodesInCluster(){
- MockRaftActorContext raftActorContext =
- (MockRaftActorContext) createActorContext();
- raftActorContext.setPeerAddresses(onePeer);
- Candidate candidate =
- new Candidate(raftActorContext);
+ public void testBecomePreLeaderOnReceivingMajorityVotesInThreeNodeCluster() {
+ MockRaftActorContext raftActorContext = createActorContext();
+ raftActorContext.setLastApplied(-1);
+ raftActorContext.setPeerAddresses(setupPeers(2));
+ candidate = new Candidate(raftActorContext);
- RaftActorBehavior raftBehavior =
- candidate.handleMessage(candidateActor, new ElectionTimeout());
+ candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, true));
- Assert.assertTrue(raftBehavior instanceof Candidate);
+ // LastApplied is -1 and behind the last index.
+ assertEquals("Behavior", RaftState.PreLeader, candidate.state());
}
@Test
- public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodesInCluster(){
- MockRaftActorContext raftActorContext =
- (MockRaftActorContext) createActorContext();
- raftActorContext.setPeerAddresses(twoPeers);
- Candidate candidate =
- new Candidate(raftActorContext);
+ public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodeCluster() {
+ MockRaftActorContext raftActorContext = createActorContext();
+ raftActorContext.getTermInformation().update(2L, "other");
+ 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);
+
+ RequestVote requestVote = MessageCollectorActor.expectFirstMatching(peerActors[0], RequestVote.class);
+ assertEquals("getTerm", 3L, requestVote.getTerm());
+ assertEquals("getCandidateId", raftActorContext.getId(), requestVote.getCandidateId());
+ assertEquals("getLastLogTerm", 1L, requestVote.getLastLogTerm());
+ assertEquals("getLastLogIndex", 4L, requestVote.getLastLogIndex());
- RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+ MessageCollectorActor.expectFirstMatching(peerActors[1], RequestVote.class);
+ MessageCollectorActor.expectFirstMatching(peerActors[2], RequestVote.class);
+ MessageCollectorActor.expectFirstMatching(peerActors[3], RequestVote.class);
- Assert.assertTrue(behaviorOnFirstVote instanceof Leader);
+ // First peers denies the vote.
+ candidate = candidate.handleMessage(peerActors[0], new RequestVoteReply(1, false));
+ assertEquals("Behavior", RaftState.Candidate, candidate.state());
+
+ candidate = candidate.handleMessage(peerActors[1], new RequestVoteReply(1, true));
+
+ assertEquals("Behavior", RaftState.Candidate, candidate.state());
+
+ candidate = candidate.handleMessage(peerActors[2], new RequestVoteReply(1, true));
+
+ assertEquals("Behavior", RaftState.Leader, candidate.state());
}
@Test
- public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodesInCluster(){
- MockRaftActorContext raftActorContext =
- (MockRaftActorContext) createActorContext();
- raftActorContext.setPeerAddresses(fourPeers);
- Candidate candidate =
- new Candidate(raftActorContext);
+ public void testBecomeLeaderOnReceivingMajorityVotesWithNonVotingPeers() {
+ ElectionTerm mockElectionTerm = Mockito.mock(ElectionTerm.class);
+ Mockito.doReturn(1L).when(mockElectionTerm).getCurrentTerm();
+ RaftActorContext raftActorContext = new RaftActorContextImpl(candidateActor, candidateActor.actorContext(),
+ "candidate", mockElectionTerm, -1, -1, setupPeers(4), new DefaultConfigParamsImpl(),
+ new NonPersistentDataProvider(Runnable::run), applyState -> { }, LOG);
+ raftActorContext.setReplicatedLog(new MockRaftActorContext.MockReplicatedLogBuilder().build());
+ raftActorContext.getPeerInfo("peer1").setVotingState(VotingState.NON_VOTING);
+ raftActorContext.getPeerInfo("peer4").setVotingState(VotingState.NON_VOTING);
+ candidate = new Candidate(raftActorContext);
- RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
+ MessageCollectorActor.expectFirstMatching(peerActors[1], RequestVote.class);
+ MessageCollectorActor.expectFirstMatching(peerActors[2], RequestVote.class);
+ MessageCollectorActor.assertNoneMatching(peerActors[0], RequestVote.class, 300);
+ MessageCollectorActor.assertNoneMatching(peerActors[3], RequestVote.class, 100);
- RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true));
+ candidate = candidate.handleMessage(peerActors[1], new RequestVoteReply(1, false));
- Assert.assertTrue(behaviorOnFirstVote instanceof Candidate);
- Assert.assertTrue(behaviorOnSecondVote instanceof Leader);
+ assertEquals("Behavior", RaftState.Candidate, candidate.state());
+ candidate = candidate.handleMessage(peerActors[2], new RequestVoteReply(1, true));
+
+ assertEquals("Behavior", RaftState.Leader, candidate.state());
}
@Test
- public void testResponseToAppendEntriesWithLowerTerm(){
- new JavaTestKit(getSystem()) {{
-
- new Within(duration("1 seconds")) {
- protected void run() {
-
- Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
- candidate.handleMessage(getTestActor(), new AppendEntries(0, "test", 0,0,Collections.<ReplicatedLogEntry>emptyList(), 0));
-
- final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
- // do not put code outside this method, will run afterwards
- protected Boolean match(Object in) {
- if (in instanceof AppendEntriesReply) {
- AppendEntriesReply reply = (AppendEntriesReply) in;
- return reply.isSuccess();
- } else {
- throw noMatch();
- }
- }
- }.get();
-
- assertEquals(false, out);
- }
- };
- }};
+ public void testResponseToHandleAppendEntriesWithLowerTerm() {
+ candidate = new Candidate(createActorContext());
+
+ setupPeers(1);
+ RaftActorBehavior newBehavior = candidate.handleMessage(peerActors[0], new AppendEntries(1, "test", 0, 0,
+ Collections.<ReplicatedLogEntry>emptyList(), 0, -1, (short) 0));
+
+ AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(
+ peerActors[0], AppendEntriesReply.class);
+ assertEquals("isSuccess", false, reply.isSuccess());
+ assertEquals("getTerm", 2, reply.getTerm());
+ assertTrue("New Behavior : " + newBehavior, newBehavior instanceof Candidate);
}
@Test
- public void testResponseToRequestVoteWithLowerTerm(){
- new JavaTestKit(getSystem()) {{
-
- new Within(duration("1 seconds")) {
- protected void run() {
-
- Candidate candidate = new Candidate(createActorContext(getTestActor()));
-
- candidate.handleMessage(getTestActor(), new RequestVote(0, "test", 0, 0));
-
- final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
- // 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);
- }
- };
- }};
+ public void testResponseToHandleAppendEntriesWithHigherTerm() {
+ candidate = new Candidate(createActorContext());
+
+ setupPeers(1);
+ RaftActorBehavior newBehavior = candidate.handleMessage(peerActors[0], new AppendEntries(5, "test", 0, 0,
+ Collections.<ReplicatedLogEntry>emptyList(), 0, -1, (short) 0));
+
+ assertTrue("New Behavior : " + newBehavior, newBehavior instanceof Follower);
}
@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<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);
- }
- };
- }};
+ public void testResponseToHandleAppendEntriesWithEqualTerm() {
+ MockRaftActorContext actorContext = createActorContext();
+
+ candidate = new Candidate(actorContext);
+
+ setupPeers(1);
+ RaftActorBehavior newBehavior = candidate.handleMessage(peerActors[0], new AppendEntries(2, "test", 0, 0,
+ Collections.<ReplicatedLogEntry>emptyList(), 0, -1, (short) 0));
+
+ assertTrue("New Behavior : " + newBehavior + " term = " + actorContext.getTermInformation().getCurrentTerm(),
+ newBehavior instanceof Follower);
}
+
@Test
- public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId(){
- new JavaTestKit(getSystem()) {{
+ public void testResponseToRequestVoteWithLowerTerm() {
+ candidate = new Candidate(createActorContext());
- new Within(duration("1 seconds")) {
- protected void run() {
+ setupPeers(1);
+ candidate.handleMessage(peerActors[0], new RequestVote(1, "test", 0, 0));
- RaftActorContext context = createActorContext(getTestActor());
+ RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+ peerActors[0], RequestVoteReply.class);
+ assertEquals("isVoteGranted", false, reply.isVoteGranted());
+ assertEquals("getTerm", 2, reply.getTerm());
+ }
- context.getTermInformation().update(1000, "test");
+ @Test
+ public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForMatches() {
+ MockRaftActorContext context = createActorContext();
+ context.getTermInformation().update(1000, null);
- RaftActorBehavior follower = createBehavior(context);
+ // Once a candidate is created it will immediately increment the current term so after
+ // construction the currentTerm should be 1001
+ candidate = new Candidate(context);
- follower.handleMessage(getTestActor(), new RequestVote(1001, "candidate", 10000, 999));
+ setupPeers(1);
+ candidate.handleMessage(peerActors[0], new RequestVote(1001, context.getId(), 10000, 999));
+
+ RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+ peerActors[0], RequestVoteReply.class);
+ assertEquals("isVoteGranted", true, reply.isVoteGranted());
+ assertEquals("getTerm", 1001, reply.getTerm());
+ }
+
+ @Test
+ public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForDoesNotMatch() {
+ MockRaftActorContext context = createActorContext();
+ context.getTermInformation().update(1000, null);
- 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();
+ // Once a candidate is created it will immediately increment the current term so after
+ // construction the currentTerm should be 1001
+ candidate = new Candidate(context);
- assertEquals(false, out);
- }
- };
- }};
+ setupPeers(1);
+
+ // RequestVote candidate ID ("candidate2") does not match this candidate's votedFor
+ // (it votes for itself)
+ candidate.handleMessage(peerActors[0], new RequestVote(1001, "candidate2", 10000, 999));
+
+ RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(
+ peerActors[0], RequestVoteReply.class);
+ assertEquals("isVoteGranted", false, reply.isVoteGranted());
+ assertEquals("getTerm", 1001, reply.getTerm());
}
+ @Test
+ public void testCandidateSchedulesElectionTimeoutImmediatelyWhenItHasNoPeers() {
+ MockRaftActorContext context = createActorContext();
+
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ candidate = createBehavior(context);
+
+ MessageCollectorActor.expectFirstMatching(candidateActor, ElectionTimeout.class);
+
+ long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+
+ assertTrue(elapsed < context.getConfigParams().getElectionTimeOutInterval().toMillis());
+ }
- @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
+ @Test
+ @Override
+ public void testHandleAppendEntriesAddSameEntryToLog() {
+ MockRaftActorContext context = createActorContext();
+
+ context.getTermInformation().update(2, "test");
+
+ // Prepare the receivers log
+ MockRaftActorContext.MockPayload payload = new MockRaftActorContext.MockPayload("zero");
+ setLastLogEntry(context, 2, 0, payload);
+
+ List<ReplicatedLogEntry> entries = new ArrayList<>();
+ entries.add(new SimpleReplicatedLogEntry(0, 2, payload));
+
+ final AppendEntries appendEntries = new AppendEntries(2, "leader-1", -1, -1, entries, 2, -1, (short)0);
+
+ behavior = createBehavior(context);
+
+ // Resetting the Candidates term to make sure it will match
+ // the term sent by AppendEntries. If this was not done then
+ // the test will fail because the Candidate will assume that
+ // the message was sent to it from a lower term peer and will
+ // thus respond with a failure
+ context.getTermInformation().update(2, "test");
+
+ // Send an unknown message so that the state of the RaftActor remains unchanged
+ behavior.handleMessage(candidateActor, "unknown");
+
+ RaftActorBehavior raftBehavior = behavior.handleMessage(candidateActor, appendEntries);
+
+ assertEquals("Raft state", RaftState.Follower, raftBehavior.state());
+
+ assertEquals("ReplicatedLog size", 1, context.getReplicatedLog().size());
+
+ handleAppendEntriesAddSameEntryToLogReply(candidateActor);
+ }
+
+ @Override
+ protected Candidate createBehavior(final RaftActorContext actorContext) {
return new Candidate(actorContext);
}
- @Override protected RaftActorContext createActorContext() {
- return new MockRaftActorContext("test", getSystem(), candidateActor);
+ @Override
+ protected MockRaftActorContext createActorContext() {
+ return new MockRaftActorContext("candidate", getSystem(), candidateActor);
}
+ @SuppressWarnings("unchecked")
+ private Map<String, String> setupPeers(final int count) {
+ Map<String, String> peerMap = new HashMap<>();
+ peerActors = new TestActorRef[count];
+ for (int i = 0; i < count; i++) {
+ peerActors[i] = actorFactory.createTestActor(Props.create(MessageCollectorActor.class),
+ actorFactory.generateActorId("peer"));
+ peerMap.put("peer" + (i + 1), peerActors[i].path().toString());
+ }
+
+ return peerMap;
+ }
+ @Override
+ protected void assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(final MockRaftActorContext actorContext,
+ final ActorRef actorRef, final RaftRPC rpc) {
+ super.assertStateChangesToFollowerWhenRaftRPCHasNewerTerm(actorContext, actorRef, rpc);
+ if (rpc instanceof RequestVote) {
+ assertEquals("New votedFor", ((RequestVote)rpc).getCandidateId(),
+ actorContext.getTermInformation().getVotedFor());
+ } else {
+ assertEquals("New votedFor", null, actorContext.getTermInformation().getVotedFor());
+ }
+ }
}