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%2FRaftActorServerConfigurationSupportTest.java;h=3145950b80ed5ca5af4b4cac2bd110d83d9fa407;hp=02ba0153191c7d8fec0dad94ca02729c4b46f24c;hb=92cbb07ef81943b0740ba7c8915001ac6785f560;hpb=782f06145be869e3f541a199915212f8188488ae diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupportTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupportTest.java index 02ba015319..3145950b80 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupportTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorServerConfigurationSupportTest.java @@ -34,15 +34,12 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.opendaylight.controller.cluster.NonPersistentDataProvider; -import org.opendaylight.controller.cluster.raft.ServerConfigurationPayload.ServerInfo; -import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries; import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot; import org.opendaylight.controller.cluster.raft.base.messages.ApplyState; import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply; import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout; import org.opendaylight.controller.cluster.raft.base.messages.InitiateCaptureSnapshot; -import org.opendaylight.controller.cluster.raft.base.messages.SnapshotComplete; -import org.opendaylight.controller.cluster.raft.base.messages.UpdateElectionTerm; +import org.opendaylight.controller.cluster.raft.base.messages.TimeoutNow; import org.opendaylight.controller.cluster.raft.behaviors.AbstractLeader; import org.opendaylight.controller.cluster.raft.behaviors.Follower; import org.opendaylight.controller.cluster.raft.behaviors.Leader; @@ -59,6 +56,10 @@ import org.opendaylight.controller.cluster.raft.messages.ServerChangeReply; import org.opendaylight.controller.cluster.raft.messages.ServerChangeStatus; import org.opendaylight.controller.cluster.raft.messages.ServerRemoved; import org.opendaylight.controller.cluster.raft.messages.UnInitializedFollowerSnapshotReply; +import org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries; +import org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload; +import org.opendaylight.controller.cluster.raft.persisted.ServerInfo; +import org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm; import org.opendaylight.controller.cluster.raft.policy.DisableElectionsRaftPolicy; import org.opendaylight.controller.cluster.raft.utils.ForwardMessageToBehaviorActor; import org.opendaylight.controller.cluster.raft.utils.InMemoryJournal; @@ -374,7 +375,7 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { followerActor.underlyingActor().setBehavior(newFollower2); MockNewFollowerRaftActor newFollowerRaftActorInstance = newFollowerRaftActor.underlyingActor(); - newFollowerRaftActorInstance.setDropMessageOfType(InstallSnapshot.SERIALIZABLE_CLASS); + newFollowerRaftActorInstance.setDropMessageOfType(InstallSnapshot.class); leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef()); @@ -605,7 +606,7 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { ((DefaultConfigParamsImpl)leaderActorContext.getConfigParams()).setElectionTimeoutFactor(1); // Drop the InstallSnapshot message so it times out - newFollowerRaftActor.underlyingActor().setDropMessageOfType(InstallSnapshot.SERIALIZABLE_CLASS); + newFollowerRaftActor.underlyingActor().setDropMessageOfType(InstallSnapshot.class); leaderActor.tell(new AddServer(NEW_SERVER_ID, newFollowerRaftActor.path().toString(), true), testKit.getRef()); @@ -1085,12 +1086,28 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { LOG.info("testChangeLeaderToNonVoting ending"); } + @Test + public void testChangeLeaderToNonVotingInSingleNode() { + LOG.info("testChangeLeaderToNonVotingInSingleNode starting"); + + TestActorRef leaderActor = actorFactory.createTestActor( + MockLeaderRaftActor.props(ImmutableMap.of(), new MockRaftActorContext()). + withDispatcher(Dispatchers.DefaultDispatcherId()), actorFactory.generateActorId(LEADER_ID)); + + leaderActor.tell(new ChangeServersVotingStatus(ImmutableMap.of(LEADER_ID, false)), testKit.getRef()); + ServerChangeReply reply = testKit.expectMsgClass(JavaTestKit.duration("5 seconds"), ServerChangeReply.class); + assertEquals("getStatus", ServerChangeStatus.INVALID_REQUEST, reply.getStatus()); + + LOG.info("testChangeLeaderToNonVotingInSingleNode ending"); + } + @Test public void testChangeToVotingWithNoLeader() { LOG.info("testChangeToVotingWithNoLeader starting"); DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl(); configParams.setHeartBeatInterval(new FiniteDuration(100, TimeUnit.MILLISECONDS)); + configParams.setElectionTimeoutFactor(5); final String node1ID = "node1"; final String node2ID = "node2"; @@ -1106,8 +1123,10 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { InMemoryJournal.addEntry(node1ID, 1, new UpdateElectionTerm(1, "downNode1")); InMemoryJournal.addEntry(node1ID, 2, persistedServerConfigEntry); + InMemoryJournal.addEntry(node1ID, 3, new ApplyJournalEntries(0)); InMemoryJournal.addEntry(node2ID, 1, new UpdateElectionTerm(1, "downNode2")); InMemoryJournal.addEntry(node2ID, 2, persistedServerConfigEntry); + InMemoryJournal.addEntry(node2ID, 3, new ApplyJournalEntries(0)); TestActorRef node1Collector = actorFactory.createTestActor( MessageCollectorActor.props().withDispatcher(Dispatchers.DefaultDispatcherId()), @@ -1125,8 +1144,8 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { PERSISTENT, node2Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node2ID); CollectingMockRaftActor node2RaftActor = node2RaftActorRef.underlyingActor(); - // Wait for snapshot after recovery - MessageCollectorActor.expectFirstMatching(node1Collector, SnapshotComplete.class); + node1RaftActor.waitForInitializeBehaviorComplete(); + node2RaftActor.waitForInitializeBehaviorComplete(); // Verify the intended server config was loaded and applied. verifyServerConfigurationPayloadEntry(node1RaftActor.getRaftActorContext().getReplicatedLog(), @@ -1136,7 +1155,9 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { assertEquals("getRaftState", RaftState.Follower, node1RaftActor.getRaftState()); assertEquals("getLeaderId", null, node1RaftActor.getLeaderId()); - MessageCollectorActor.expectFirstMatching(node2Collector, SnapshotComplete.class); + verifyServerConfigurationPayloadEntry(node2RaftActor.getRaftActorContext().getReplicatedLog(), + nonVotingServer(node1ID), nonVotingServer(node2ID), votingServer("downNode1"), + votingServer("downNode2")); assertEquals("isVotingMember", false, node2RaftActor.getRaftActorContext().isVotingMember()); // For the test, we send a ChangeServersVotingStatus message to node1 to flip the voting states for @@ -1152,6 +1173,19 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { ServerChangeReply reply = testKit.expectMsgClass(JavaTestKit.duration("5 seconds"), ServerChangeReply.class); assertEquals("getStatus", ServerChangeStatus.NO_LEADER, reply.getStatus()); + // Send an AppendEntries so node1 has a leaderId + + MessageCollectorActor.clearMessages(node1Collector); + + long term = node1RaftActor.getRaftActorContext().getTermInformation().getCurrentTerm(); + node1RaftActorRef.tell(new AppendEntries(term, "downNode1", -1L, -1L, + Collections.emptyList(), 0, -1, (short)1), ActorRef.noSender()); + + // Wait for the ElectionTimeout to clear the leaderId. he leaderId must be null so on the + // ChangeServersVotingStatus message, it will try to elect a leader. + + MessageCollectorActor.expectFirstMatching(node1Collector, ElectionTimeout.class); + // Update node2's peer address and send the message again node1RaftActor.setPeerAddress(node2ID, node2RaftActorRef.path().toString()); @@ -1221,9 +1255,6 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { PERSISTENT, node2Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node2ID); CollectingMockRaftActor node2RaftActor = node2RaftActorRef.underlyingActor(); - // Wait for snapshot after recovery - MessageCollectorActor.expectFirstMatching(node1Collector, SnapshotComplete.class); - // Send a ChangeServersVotingStatus message to node1 to change mode1 to voting. This should cause // node1 to try to elect itself as leader in order to apply the new server config. But we'll drop // RequestVote messages in node2 which should cause node1 to time out and revert back to the previous @@ -1269,6 +1300,7 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { InMemoryJournal.addEntry(node2ID, 2, persistedServerConfigEntry); InMemoryJournal.addEntry(node2ID, 3, new ReplicatedLogImplEntry(1, 1, new MockRaftActorContext.MockPayload("2"))); + InMemoryJournal.addEntry(node2ID, 4, new ApplyJournalEntries(1)); TestActorRef node1Collector = actorFactory.createTestActor( MessageCollectorActor.props().withDispatcher(Dispatchers.DefaultDispatcherId()), @@ -1286,9 +1318,6 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { PERSISTENT, node2Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node2ID); CollectingMockRaftActor node2RaftActor = node2RaftActorRef.underlyingActor(); - // Wait for snapshot after recovery - MessageCollectorActor.expectFirstMatching(node1Collector, SnapshotComplete.class); - // Send a ChangeServersVotingStatus message to node1 to change mode1 to voting. This should cause // node1 to try to elect itself as leader in order to apply the new server config. However node1's log // is behind node2's so node2 should not grant node1's vote. This should cause node1 to time out and @@ -1353,9 +1382,6 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { PERSISTENT, node2Collector).withDispatcher(Dispatchers.DefaultDispatcherId()), node2ID); CollectingMockRaftActor node2RaftActor = node2RaftActorRef.underlyingActor(); - // Wait for snapshot after recovery - MessageCollectorActor.expectFirstMatching(node1Collector, SnapshotComplete.class); - // Send a ChangeServersVotingStatus message to node1 to change node1 to voting. This should cause // node1 to try to elect itself as leader in order to apply the new server config. But we'll drop // RequestVote messages in node2 and make it the leader so node1 should forward the server change @@ -1369,7 +1395,7 @@ public class RaftActorServerConfigurationSupportTest extends AbstractActorTest { MessageCollectorActor.expectFirstMatching(node2Collector, RequestVote.class); - node2RaftActorRef.tell(ElectionTimeout.INSTANCE, ActorRef.noSender()); + node2RaftActorRef.tell(TimeoutNow.INSTANCE, ActorRef.noSender()); ServerChangeReply reply = testKit.expectMsgClass(JavaTestKit.duration("5 seconds"), ServerChangeReply.class); assertEquals("getStatus", ServerChangeStatus.OK, reply.getStatus());