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%2FFollowerTest.java;h=1b15ecb135a89f87c212ecf3a080cf8181ba921e;hb=224aa4f574c63576961dc9dc37e075e2e5096a5a;hp=2cb0d7ce6546ad93d6cb71196e0bf020a4450fb3;hpb=e9bf41afa2413cc4574a7ac97a55f2cb6c2de6b2;p=controller.git diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java index 2cb0d7ce65..1b15ecb135 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java @@ -1,3 +1,11 @@ +/* + * 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; @@ -64,7 +72,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) { - return new Follower(actorContext); + return new TestFollower(actorContext); } @Override @@ -79,6 +87,13 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { return context; } + private static int getElectionTimeoutCount(RaftActorBehavior follower){ + if(follower instanceof TestFollower){ + return ((TestFollower) follower).getElectionTimeoutCount(); + } + return -1; + } + @Test public void testThatAnElectionTimeoutIsTriggered(){ MockRaftActorContext actorContext = createActorContext(); @@ -115,6 +130,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { assertEquals("isVoteGranted", true, reply.isVoteGranted()); assertEquals("getTerm", term, reply.getTerm()); + assertEquals("schedule election", 1, getElectionTimeoutCount(follower)); } @Test @@ -132,6 +148,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { RequestVoteReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, RequestVoteReply.class); assertEquals("isVoteGranted", false, reply.isVoteGranted()); + assertEquals("schedule election", 0, getElectionTimeoutCount(follower)); } @@ -190,7 +207,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { MockRaftActorContext context = createActorContext(); context.getReplicatedLog().clear(0,2); - context.getReplicatedLog().append(newReplicatedLogEntry(1,100, "bar")); + context.getReplicatedLog().append(newReplicatedLogEntry(1, 100, "bar")); context.getReplicatedLog().setSnapshotIndex(99); List entries = Arrays.asList( @@ -582,6 +599,44 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { expectAndVerifyAppendEntriesReply(2, true, context.getId(), 2, 3); } + @Test + public void testHandleAppendEntriesWhenOutOfSyncLogDetectedRequestForceInstallSnapshot() { + logStart("testHandleAppendEntriesWhenOutOfSyncLogDetectedRequestForceInstallSnapshot"); + + MockRaftActorContext context = 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(newReplicatedLogEntry(1, 0, "zero")); + log.append(newReplicatedLogEntry(1, 1, "one")); + log.append(newReplicatedLogEntry(1, 2, "two")); + + context.setReplicatedLog(log); + + // Prepare the entries to be sent with AppendEntries + List entries = new ArrayList<>(); + entries.add(newReplicatedLogEntry(2, 2, "two-1")); + entries.add(newReplicatedLogEntry(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, entries, 3, -1, (short)0); + + context.setRaftPolicy(createRaftPolicy(false, true)); + follower = createBehavior(context); + + RaftActorBehavior newBehavior = follower.handleMessage(leaderActor, appendEntries); + + Assert.assertSame(follower, newBehavior); + + expectAndVerifyAppendEntriesReply(2, false, context.getId(), 1, 2, true); + } + @Test public void testHandleAppendEntriesPreviousLogEntryMissing(){ logStart("testHandleAppendEntriesPreviousLogEntryMissing"); @@ -694,6 +749,7 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { logStart("testHandleInstallSnapshot"); MockRaftActorContext context = createActorContext(); + context.getTermInformation().update(1, "leader"); follower = createBehavior(context); @@ -727,6 +783,9 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { snapshot.getLastAppliedIndex()); assertEquals("getLastTerm", lastInstallSnapshot.getLastIncludedTerm(), snapshot.getLastTerm()); Assert.assertArrayEquals("getState", bsSnapshot.toByteArray(), snapshot.getState()); + assertEquals("getElectionTerm", 1, snapshot.getElectionTerm()); + assertEquals("getElectionVotedFor", "leader", snapshot.getElectionVotedFor()); + applySnapshot.getCallback().onSuccess(); List replies = MessageCollectorActor.getAllMatching( leaderActor, InstallSnapshotReply.class); @@ -903,6 +962,26 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { MessageCollectorActor.assertNoneMatching(followerActor, ElectionTimeout.class, 500); } + @Test + public void testElectionScheduledWhenAnyRaftRPCReceived(){ + MockRaftActorContext context = createActorContext(); + follower = createBehavior(context); + follower.handleMessage(leaderActor, new RaftRPC() { + @Override + public long getTerm() { + return 100; + } + }); + assertEquals("schedule election", 1, getElectionTimeoutCount(follower)); + } + + @Test + public void testElectionNotScheduledWhenNonRaftRPCMessageReceived(){ + MockRaftActorContext context = createActorContext(); + follower = createBehavior(context); + follower.handleMessage(leaderActor, "non-raft-rpc"); + assertEquals("schedule election", 0, getElectionTimeoutCount(follower)); + } public ByteString getNextChunk (ByteString bs, int offset, int chunkSize){ int snapshotLength = bs.size(); @@ -920,6 +999,12 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { private void expectAndVerifyAppendEntriesReply(int expTerm, boolean expSuccess, String expFollowerId, long expLogLastTerm, long expLogLastIndex) { + expectAndVerifyAppendEntriesReply(expTerm, expSuccess, expFollowerId, expLogLastTerm, expLogLastIndex, false); + } + + private void expectAndVerifyAppendEntriesReply(int expTerm, boolean expSuccess, + String expFollowerId, long expLogLastTerm, long expLogLastIndex, + boolean expForceInstallSnapshot) { AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(leaderActor, AppendEntriesReply.class); @@ -930,9 +1015,11 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { assertEquals("getLogLastTerm", expLogLastTerm, reply.getLogLastTerm()); assertEquals("getLogLastIndex", expLogLastIndex, reply.getLogLastIndex()); assertEquals("getPayloadVersion", payloadVersion, reply.getPayloadVersion()); + assertEquals("isForceInstallSnapshot", expForceInstallSnapshot, reply.isForceInstallSnapshot()); } - private ReplicatedLogEntry newReplicatedLogEntry(long term, long index, String data) { + + private static ReplicatedLogEntry newReplicatedLogEntry(long term, long index, String data) { return new MockRaftActorContext.MockReplicatedLogEntry(term, index, new MockRaftActorContext.MockPayload(data)); } @@ -961,4 +1048,23 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest { AppendEntriesReply reply = MessageCollectorActor.expectFirstMatching(replyActor, AppendEntriesReply.class); assertEquals("isSuccess", true, reply.isSuccess()); } + + private static class TestFollower extends Follower { + + int electionTimeoutCount = 0; + + public TestFollower(RaftActorContext context) { + super(context); + } + + @Override + protected void scheduleElection(FiniteDuration interval) { + electionTimeoutCount++; + super.scheduleElection(interval); + } + + public int getElectionTimeoutCount() { + return electionTimeoutCount; + } + } }