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%2FAbstractRaftActorBehaviorTest.java;h=8068dfbcff48970ad7203c43aae378eac4803851;hp=3cd373adf4319e36f5101c418e330adc90c7931d;hb=0eb621d29daaf08979c356e2148e99c48458e169;hpb=a0c5aba42aa36337ff1c6760175918b786897c9e diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java index 3cd373adf4..8068dfbcff 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/AbstractRaftActorBehaviorTest.java @@ -9,18 +9,19 @@ 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.ReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.SerializationUtils; 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.protobuff.client.messages.Payload; import org.opendaylight.controller.cluster.raft.utils.DoNothingActor; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { @@ -53,35 +54,6 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { }}; } - /** - * This test verifies that when an AppendEntries RPC is received by a RaftActor - * with a commitIndex that is greater than what has been applied to the - * state machine of the RaftActor, the RaftActor applies the state and - * sets it current applied state to the commitIndex of the sender. - * - * @throws Exception - */ - @Test - public void testHandleAppendEntriesWithNewerCommitIndex() throws Exception { - new JavaTestKit(getSystem()) {{ - - RaftActorContext context = - createActorContext(); - - context.setLastApplied(100); - setLastLogEntry((MockRaftActorContext) context, 0, 0, ""); - - // The new commitIndex is 101 - AppendEntries appendEntries = - new AppendEntries(100, "leader-1", 0, 0, null, 101); - - RaftState raftState = - createBehavior(context).handleMessage(getRef(), appendEntries); - - assertEquals(101L, context.getLastApplied()); - - }}; - } /** * This test verifies that when an AppendEntries is received with a term that @@ -134,248 +106,56 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { }}; } - /** - * This test verifies that when an AppendEntries is received a specific prevLogTerm - * which does not match the term that is in RaftActors log entry at prevLogIndex - * then the RaftActor does not change it's state and it returns a failure. - * - * @throws Exception - */ - @Test - public void testHandleAppendEntriesSenderPrevLogTermNotSameAsReceiverPrevLogTerm() - throws Exception { - new JavaTestKit(getSystem()) {{ - - MockRaftActorContext context = (MockRaftActorContext) - createActorContext(); - - // First set the receivers term to lower number - context.getTermInformation().update(95, "test"); - - // Set the last log entry term for the receiver to be greater than - // what we will be sending as the prevLogTerm in AppendEntries - MockRaftActorContext.MockReplicatedLog mockReplicatedLog = - setLastLogEntry(context, 20, 0, ""); - - // Also set the entry at index 0 with term 20 which will be greater - // than the prevLogTerm sent by the sender - mockReplicatedLog.setReplicatedLogEntry( - new MockRaftActorContext.MockReplicatedLogEntry(20, 0, "")); - - // AppendEntries is now sent with a bigger term - // this will set the receivers term to be the same as the sender's term - AppendEntries appendEntries = - new AppendEntries(100, "leader-1", 0, 0, null, 101); - - RaftActorBehavior behavior = createBehavior(context); - - // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); - - RaftState raftState = - behavior.handleMessage(getRef(), appendEntries); - - assertEquals(expected, raftState); - // Also expect an AppendEntriesReply to be sent where success is false - final Boolean out = new ExpectMsg(duration("1 seconds"), - "AppendEntriesReply") { - // 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); - - - }}; - } - - /** - * This test verifies that when a new AppendEntries message is received with - * new entries and the logs of the sender and receiver match that the new - * entries get added to the log and the log is incremented by the number of - * entries received in appendEntries - * - * @throws Exception - */ @Test - public void testHandleAppendEntriesAddNewEntries() throws Exception { - new JavaTestKit(getSystem()) {{ + public void testHandleAppendEntriesAddSameEntryToLog(){ + new JavaTestKit(getSystem()) { + { - MockRaftActorContext context = (MockRaftActorContext) - createActorContext(); + MockRaftActorContext context = (MockRaftActorContext) + createActorContext(); - // First set the receivers term to lower number - context.getTermInformation().update(1, "test"); - - // Prepare the receivers log - MockRaftActorContext.SimpleReplicatedLog log = - new MockRaftActorContext.SimpleReplicatedLog(); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 0, "zero")); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 1, "one")); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 2, "two")); - - context.setReplicatedLog(log); - - // Prepare the entries to be sent with AppendEntries - List entries = new ArrayList<>(); - entries.add( - new MockRaftActorContext.MockReplicatedLogEntry(1, 3, "three")); - entries.add( - new MockRaftActorContext.MockReplicatedLogEntry(1, 4, "four")); - - // Send appendEntries with the same term as was set on the receiver - // before the new behavior was created (1 in this case) - // This will not work for a Candidate because as soon as a Candidate - // is created it increments the term - AppendEntries appendEntries = - new AppendEntries(1, "leader-1", 2, 1, entries, 101); + // First set the receivers term to lower number + context.getTermInformation().update(2, "test"); - RaftActorBehavior behavior = createBehavior(context); + // Prepare the receivers log + MockRaftActorContext.SimpleReplicatedLog log = + new MockRaftActorContext.SimpleReplicatedLog(); + log.append( + new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero"))); - if (AbstractRaftActorBehaviorTest.this instanceof CandidateTest) { - // 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(1, "test"); - } + context.setReplicatedLog(log); - // Send an unknown message so that the state of the RaftActor remains unchanged - RaftState expected = behavior.handleMessage(getRef(), "unknown"); + List entries = new ArrayList<>(); + entries.add( + new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero"))); - RaftState raftState = - behavior.handleMessage(getRef(), appendEntries); + AppendEntries appendEntries = + new AppendEntries(2, "leader-1", -1, 1, entries, 0); - assertEquals(expected, raftState); - assertEquals(5, log.last().getIndex() + 1); - assertNotNull(log.get(3)); - assertNotNull(log.get(4)); + RaftActorBehavior behavior = createBehavior(context); - // Also expect an AppendEntriesReply to be sent where success is false - final Boolean out = new ExpectMsg(duration("1 seconds"), - "AppendEntriesReply") { - // 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(); - } + if (AbstractRaftActorBehaviorTest.this instanceof CandidateTest) { + // 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"); } - }.get(); - - assertEquals(true, out); - - - }}; - } - - /** - * This test verifies that when a new AppendEntries message is received with - * new entries and the logs of the sender and receiver are out-of-sync that - * the log is first corrected by removing the out of sync entries from the - * log and then adding in the new entries sent with the AppendEntries message - * - * @throws Exception - */ - @Test - public void testHandleAppendEntriesCorrectReceiverLogEntries() - throws Exception { - new JavaTestKit(getSystem()) {{ - MockRaftActorContext context = (MockRaftActorContext) - createActorContext(); + // Send an unknown message so that the state of the RaftActor remains unchanged + RaftState expected = behavior.handleMessage(getRef(), "unknown"); - // First set the receivers term to lower number - context.getTermInformation().update(2, "test"); - - // Prepare the receivers log - MockRaftActorContext.SimpleReplicatedLog log = - new MockRaftActorContext.SimpleReplicatedLog(); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 0, "zero")); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 1, "one")); - log.append( - new MockRaftActorContext.MockReplicatedLogEntry(1, 2, "two")); - - context.setReplicatedLog(log); - - // Prepare the entries to be sent with AppendEntries - List entries = new ArrayList<>(); - entries.add( - new MockRaftActorContext.MockReplicatedLogEntry(2, 2, "two-1")); - entries.add( - new MockRaftActorContext.MockReplicatedLogEntry(2, 3, "three")); - - // Send appendEntries with the same term as was set on the receiver - // before the new behavior was created (1 in this case) - // This will not work for a Candidate because as soon as a Candidate - // is created it increments the term - AppendEntries appendEntries = - new AppendEntries(2, "leader-1", 1, 1, entries, 101); - - RaftActorBehavior behavior = createBehavior(context); + RaftState raftState = + behavior.handleMessage(getRef(), appendEntries); - if (AbstractRaftActorBehaviorTest.this instanceof CandidateTest) { - // 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 - RaftState expected = behavior.handleMessage(getRef(), "unknown"); - - RaftState raftState = - behavior.handleMessage(getRef(), appendEntries); - - assertEquals(expected, raftState); - - // The entry at index 2 will be found out-of-sync with the leader - // and will be removed - // Then the two new entries will be added to the log - // Thus making the log to have 4 entries - assertEquals(4, log.last().getIndex() + 1); - assertNotNull(log.get(2)); - - // Check that the entry at index 2 has the new data - assertEquals("two-1", log.get(2).getData()); - assertNotNull(log.get(3)); - - // Also expect an AppendEntriesReply to be sent where success is false - final Boolean out = new ExpectMsg(duration("1 seconds"), - "AppendEntriesReply") { - // 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(expected, raftState); - assertEquals(true, out); + assertEquals(1, log.size()); - }}; + }}; } /** @@ -391,28 +171,33 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { new Within(duration("1 seconds")) { protected void run() { - RaftActorBehavior follower = createBehavior( + RaftActorBehavior behavior = createBehavior( createActorContext(behaviorActor)); - follower.handleMessage(getTestActor(), + RaftState raftState = behavior.handleMessage(getTestActor(), new RequestVote(1000, "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(); + if(behavior.state() != RaftState.Follower){ + assertEquals(RaftState.Follower, raftState); + } else { + + 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(); + }.get(); - assertEquals(true, out); + assertEquals(true, out); + } } }; }}; @@ -433,39 +218,39 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { RaftActorContext actorContext = createActorContext(behaviorActor); - MockRaftActorContext.MockReplicatedLog - log = new MockRaftActorContext.MockReplicatedLog(); - log.setReplicatedLogEntry( + MockRaftActorContext.SimpleReplicatedLog + log = new MockRaftActorContext.SimpleReplicatedLog(); + log.append( new MockRaftActorContext.MockReplicatedLogEntry(20000, - 1000000, "")); - log.setLast( - new MockRaftActorContext.MockReplicatedLogEntry(20000, - 1000000, "") - ); + 1000000, new MockRaftActorContext.MockPayload(""))); ((MockRaftActorContext) actorContext).setReplicatedLog(log); - RaftActorBehavior follower = createBehavior(actorContext); + RaftActorBehavior behavior = createBehavior(actorContext); - follower.handleMessage(getTestActor(), + RaftState raftState = behavior.handleMessage(getTestActor(), new RequestVote(1000, "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(); + if(behavior.state() != RaftState.Follower){ + assertEquals(RaftState.Follower, raftState); + } else { + 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(); + }.get(); - assertEquals(false, out); + assertEquals(false, out); + } } }; }}; @@ -520,8 +305,9 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { ActorRef actorRef, RaftRPC rpc) { RaftActorContext actorContext = createActorContext(); + Payload p = new MockRaftActorContext.MockPayload(""); setLastLogEntry( - (MockRaftActorContext) actorContext, 0, 0, ""); + (MockRaftActorContext) actorContext, 0, 0, p); RaftState raftState = createBehavior(actorContext) .handleMessage(actorRef, rpc); @@ -529,18 +315,17 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { assertEquals(RaftState.Follower, raftState); } - protected MockRaftActorContext.MockReplicatedLog setLastLogEntry( - MockRaftActorContext actorContext, long term, long index, Object data) { + protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry( + MockRaftActorContext actorContext, long term, long index, Payload data) { return setLastLogEntry(actorContext, new MockRaftActorContext.MockReplicatedLogEntry(term, index, data)); } - protected MockRaftActorContext.MockReplicatedLog setLastLogEntry( + protected MockRaftActorContext.SimpleReplicatedLog setLastLogEntry( MockRaftActorContext actorContext, ReplicatedLogEntry logEntry) { - MockRaftActorContext.MockReplicatedLog - log = new MockRaftActorContext.MockReplicatedLog(); - // By default MockReplicateLog has last entry set to (1,1,"") - log.setLast(logEntry); + MockRaftActorContext.SimpleReplicatedLog + log = new MockRaftActorContext.SimpleReplicatedLog(); + log.append(logEntry); actorContext.setReplicatedLog(log); return log; @@ -566,7 +351,7 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { } protected AppendEntriesReply createAppendEntriesReplyWithNewerTerm() { - return new AppendEntriesReply(100, false); + return new AppendEntriesReply("follower-1", 100, false, 100, 100); } protected RequestVote createRequestVoteWithNewerTerm() { @@ -577,6 +362,7 @@ public abstract class AbstractRaftActorBehaviorTest extends AbstractActorTest { return new RequestVoteReply(100, false); } - - + protected Object fromSerializableMessage(Object serializable){ + return SerializationUtils.fromSerializable(serializable); + } }