2 * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.raft;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNull;
12 import static org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor.clearMessages;
13 import static org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor.expectFirstMatching;
14 import akka.actor.ActorRef;
15 import akka.actor.Props;
16 import akka.pattern.Patterns;
17 import akka.testkit.TestActorRef;
18 import com.google.common.collect.ImmutableMap;
19 import java.util.concurrent.TimeUnit;
20 import org.junit.Test;
21 import org.opendaylight.controller.cluster.notifications.LeaderStateChanged;
22 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
23 import org.opendaylight.controller.cluster.raft.client.messages.Shutdown;
24 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
25 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
26 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
27 import scala.concurrent.Await;
28 import scala.concurrent.Future;
29 import scala.concurrent.duration.FiniteDuration;
32 * Tests leadership transfer end-to-end.
34 * @author Thomas Pantelis
36 public class LeadershipTransferIntegrationTest extends AbstractRaftActorIntegrationTest {
38 private final String follower3Id = factory.generateActorId("follower");
39 private TestActorRef<MessageCollectorActor> leaderNotifierActor;
40 private TestActorRef<MessageCollectorActor> follower1NotifierActor;
41 private TestActorRef<MessageCollectorActor> follower2NotifierActor;
42 private TestActorRef<MessageCollectorActor> follower3NotifierActor;
43 private TestActorRef<TestRaftActor> follower3Actor;
44 private ActorRef follower3CollectorActor;
47 public void testLeaderTransferOnShutDown() throws Throwable {
48 testLog.info("testLeaderTransferOnShutDown starting");
52 sendPayloadWithFollower2Lagging();
54 sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1();
56 sendShutDown(follower2Actor);
58 testLog.info("testLeaderTransferOnShutDown ending");
61 private void sendShutDown(ActorRef actor) throws Exception {
62 testLog.info("sendShutDown for {} starting", actor.path());
64 FiniteDuration duration = FiniteDuration.create(5, TimeUnit.SECONDS);
65 Future<Boolean> stopFuture = Patterns.gracefulStop(actor, duration, Shutdown.INSTANCE);
67 Boolean stopped = Await.result(stopFuture, duration);
68 assertEquals("Stopped", Boolean.TRUE, stopped);
70 testLog.info("sendShutDown for {} ending", actor.path());
73 private void sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1() throws Throwable {
74 testLog.info("sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1 starting");
76 clearMessages(leaderNotifierActor);
77 clearMessages(follower1NotifierActor);
78 clearMessages(follower2NotifierActor);
79 clearMessages(follower3NotifierActor);
81 FiniteDuration duration = FiniteDuration.create(5, TimeUnit.SECONDS);
82 Future<Boolean> stopFuture = Patterns.gracefulStop(leaderActor, duration, Shutdown.INSTANCE);
84 assertNullLeaderIdChange(leaderNotifierActor);
85 assertNullLeaderIdChange(follower1NotifierActor);
86 assertNullLeaderIdChange(follower2NotifierActor);
87 assertNullLeaderIdChange(follower3NotifierActor);
89 verifyRaftState(follower1Actor, RaftState.Leader);
91 Boolean stopped = Await.result(stopFuture, duration);
92 assertEquals("Stopped", Boolean.TRUE, stopped);
94 follower2Actor.underlyingActor().stopDropMessages(AppendEntries.class);
95 ApplyState applyState = expectFirstMatching(follower2CollectorActor, ApplyState.class);
96 assertEquals("Apply sate index", 0, applyState.getReplicatedLogEntry().getIndex());
98 testLog.info("sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1 ending");
101 private void sendPayloadWithFollower2Lagging() {
102 testLog.info("sendPayloadWithFollower2Lagging starting");
104 follower2Actor.underlyingActor().startDropMessages(AppendEntries.class);
106 sendPayloadData(leaderActor, "zero");
108 expectFirstMatching(leaderCollectorActor, ApplyState.class);
109 expectFirstMatching(follower1CollectorActor, ApplyState.class);
110 expectFirstMatching(follower3CollectorActor, ApplyState.class);
112 testLog.info("sendPayloadWithFollower2Lagging ending");
115 private void createRaftActors() {
116 testLog.info("createRaftActors starting");
118 follower1NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
119 factory.generateActorId(follower1Id + "-notifier"));
120 follower1Actor = newTestRaftActor(follower1Id, TestRaftActor.newBuilder().peerAddresses(
121 ImmutableMap.of(leaderId, testActorPath(leaderId), follower2Id, testActorPath(follower2Id),
122 follower3Id, testActorPath(follower3Id))).
123 config(newFollowerConfigParams()).roleChangeNotifier(follower1NotifierActor));
125 follower2NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
126 factory.generateActorId(follower2Id + "-notifier"));
127 follower2Actor = newTestRaftActor(follower2Id,TestRaftActor.newBuilder().peerAddresses(
128 ImmutableMap.of(leaderId, testActorPath(leaderId), follower1Id, follower1Actor.path().toString(),
129 follower3Id, testActorPath(follower3Id))).
130 config(newFollowerConfigParams()).roleChangeNotifier(follower2NotifierActor));
132 follower3NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
133 factory.generateActorId(follower3Id + "-notifier"));
134 follower3Actor = newTestRaftActor(follower3Id,TestRaftActor.newBuilder().peerAddresses(
135 ImmutableMap.of(leaderId, testActorPath(leaderId), follower1Id, follower1Actor.path().toString(),
136 follower2Id, follower2Actor.path().toString())).
137 config(newFollowerConfigParams()).roleChangeNotifier(follower3NotifierActor));
139 peerAddresses = ImmutableMap.<String, String>builder().
140 put(follower1Id, follower1Actor.path().toString()).
141 put(follower2Id, follower2Actor.path().toString()).
142 put(follower3Id, follower3Actor.path().toString()).build();
144 leaderConfigParams = newLeaderConfigParams();
145 leaderConfigParams.setElectionTimeoutFactor(3);
146 leaderNotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
147 factory.generateActorId(leaderId + "-notifier"));
148 leaderActor = newTestRaftActor(leaderId, TestRaftActor.newBuilder().peerAddresses(peerAddresses).
149 config(leaderConfigParams).roleChangeNotifier(leaderNotifierActor));
151 follower1CollectorActor = follower1Actor.underlyingActor().collectorActor();
152 follower2CollectorActor = follower2Actor.underlyingActor().collectorActor();
153 follower3CollectorActor = follower3Actor.underlyingActor().collectorActor();
154 leaderCollectorActor = leaderActor.underlyingActor().collectorActor();
156 leaderContext = leaderActor.underlyingActor().getRaftActorContext();
157 leaderContext.getPeerInfo(follower3Id).setVotingState(VotingState.NON_VOTING);
159 waitUntilLeader(leaderActor);
161 testLog.info("createRaftActors starting");
164 private static void verifyRaftState(ActorRef raftActor, final RaftState expState) {
165 verifyRaftState(raftActor, rs -> assertEquals("getRaftState", expState.toString(), rs.getRaftState()));
168 private static void assertNullLeaderIdChange(TestActorRef<MessageCollectorActor> notifierActor) {
169 LeaderStateChanged change = expectFirstMatching(notifierActor, LeaderStateChanged.class);
170 assertNull("Expected null leader Id", change.getLeaderId());
174 public void testLeaderTransferAborted() throws Throwable {
175 testLog.info("testLeaderTransferAborted starting");
179 leaderActor.underlyingActor().startDropMessages(AppendEntriesReply.class);
181 sendShutDown(leaderActor);
183 verifyRaftState(follower1Actor, RaftState.Follower);
184 verifyRaftState(follower2Actor, RaftState.Follower);
185 verifyRaftState(follower3Actor, RaftState.Follower);
187 testLog.info("testLeaderTransferOnShutDown ending");
191 public void testLeaderTransferSkippedOnShutdownWithNoFollowers() throws Throwable {
192 testLog.info("testLeaderTransferSkippedOnShutdownWithNoFollowers starting");
194 leaderActor = newTestRaftActor(leaderId, TestRaftActor.newBuilder().config(newLeaderConfigParams()));
195 waitUntilLeader(leaderActor);
197 sendShutDown(leaderActor);
199 testLog.info("testLeaderTransferSkippedOnShutdownWithNoFollowers ending");