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;
15 import akka.actor.ActorRef;
16 import akka.actor.Props;
17 import akka.pattern.Patterns;
18 import akka.testkit.TestActorRef;
19 import com.google.common.collect.ImmutableMap;
20 import java.util.concurrent.TimeUnit;
21 import org.junit.Test;
22 import org.opendaylight.controller.cluster.notifications.LeaderStateChanged;
23 import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
24 import org.opendaylight.controller.cluster.raft.client.messages.Shutdown;
25 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
26 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
27 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
28 import scala.concurrent.Await;
29 import scala.concurrent.Future;
30 import scala.concurrent.duration.FiniteDuration;
33 * Tests leadership transfer end-to-end.
35 * @author Thomas Pantelis
37 public class LeadershipTransferIntegrationTest extends AbstractRaftActorIntegrationTest {
39 private final String follower3Id = factory.generateActorId("follower");
40 private TestActorRef<MessageCollectorActor> leaderNotifierActor;
41 private TestActorRef<MessageCollectorActor> follower1NotifierActor;
42 private TestActorRef<MessageCollectorActor> follower2NotifierActor;
43 private TestActorRef<MessageCollectorActor> follower3NotifierActor;
44 private TestActorRef<TestRaftActor> follower3Actor;
45 private ActorRef follower3CollectorActor;
48 public void testLeaderTransferOnShutDown() throws Exception {
49 testLog.info("testLeaderTransferOnShutDown starting");
53 sendPayloadWithFollower2Lagging();
55 sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1();
57 sendShutDown(follower2Actor);
59 testLog.info("testLeaderTransferOnShutDown ending");
62 private void sendShutDown(ActorRef actor) throws Exception {
63 testLog.info("sendShutDown for {} starting", actor.path());
65 FiniteDuration duration = FiniteDuration.create(5, TimeUnit.SECONDS);
66 Future<Boolean> stopFuture = Patterns.gracefulStop(actor, duration, Shutdown.INSTANCE);
68 Boolean stopped = Await.result(stopFuture, duration);
69 assertEquals("Stopped", Boolean.TRUE, stopped);
71 testLog.info("sendShutDown for {} ending", actor.path());
74 private void sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1() throws Exception {
75 testLog.info("sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1 starting");
77 clearMessages(leaderNotifierActor);
78 clearMessages(follower1NotifierActor);
79 clearMessages(follower2NotifierActor);
80 clearMessages(follower3NotifierActor);
82 FiniteDuration duration = FiniteDuration.create(5, TimeUnit.SECONDS);
83 final Future<Boolean> stopFuture = Patterns.gracefulStop(leaderActor, duration, Shutdown.INSTANCE);
85 assertNullLeaderIdChange(leaderNotifierActor);
86 assertNullLeaderIdChange(follower1NotifierActor);
87 assertNullLeaderIdChange(follower2NotifierActor);
88 assertNullLeaderIdChange(follower3NotifierActor);
90 verifyRaftState(follower1Actor, RaftState.Leader);
92 Boolean stopped = Await.result(stopFuture, duration);
93 assertEquals("Stopped", Boolean.TRUE, stopped);
95 follower2Actor.underlyingActor().stopDropMessages(AppendEntries.class);
96 ApplyState applyState = expectFirstMatching(follower2CollectorActor, ApplyState.class);
97 assertEquals("Apply sate index", 0, applyState.getReplicatedLogEntry().getIndex());
99 testLog.info("sendShutDownToLeaderAndVerifyLeadershipTransferToFollower1 ending");
102 private void sendPayloadWithFollower2Lagging() {
103 testLog.info("sendPayloadWithFollower2Lagging starting");
105 follower2Actor.underlyingActor().startDropMessages(AppendEntries.class);
107 sendPayloadData(leaderActor, "zero");
109 expectFirstMatching(leaderCollectorActor, ApplyState.class);
110 expectFirstMatching(follower1CollectorActor, ApplyState.class);
111 expectFirstMatching(follower3CollectorActor, ApplyState.class);
113 testLog.info("sendPayloadWithFollower2Lagging ending");
116 private void createRaftActors() {
117 testLog.info("createRaftActors starting");
119 follower1NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
120 factory.generateActorId(follower1Id + "-notifier"));
121 follower1Actor = newTestRaftActor(follower1Id, TestRaftActor.newBuilder().peerAddresses(
122 ImmutableMap.of(leaderId, testActorPath(leaderId), follower2Id, testActorPath(follower2Id),
123 follower3Id, testActorPath(follower3Id)))
124 .config(newFollowerConfigParams()).roleChangeNotifier(follower1NotifierActor));
126 follower2NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
127 factory.generateActorId(follower2Id + "-notifier"));
128 follower2Actor = newTestRaftActor(follower2Id,TestRaftActor.newBuilder().peerAddresses(
129 ImmutableMap.of(leaderId, testActorPath(leaderId), follower1Id, follower1Actor.path().toString(),
130 follower3Id, testActorPath(follower3Id)))
131 .config(newFollowerConfigParams()).roleChangeNotifier(follower2NotifierActor));
133 follower3NotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
134 factory.generateActorId(follower3Id + "-notifier"));
135 follower3Actor = newTestRaftActor(follower3Id,TestRaftActor.newBuilder().peerAddresses(
136 ImmutableMap.of(leaderId, testActorPath(leaderId), follower1Id, follower1Actor.path().toString(),
137 follower2Id, follower2Actor.path().toString()))
138 .config(newFollowerConfigParams()).roleChangeNotifier(follower3NotifierActor));
140 peerAddresses = ImmutableMap.<String, String>builder()
141 .put(follower1Id, follower1Actor.path().toString())
142 .put(follower2Id, follower2Actor.path().toString())
143 .put(follower3Id, follower3Actor.path().toString()).build();
145 leaderConfigParams = newLeaderConfigParams();
146 leaderConfigParams.setElectionTimeoutFactor(3);
147 leaderNotifierActor = factory.createTestActor(Props.create(MessageCollectorActor.class),
148 factory.generateActorId(leaderId + "-notifier"));
149 leaderActor = newTestRaftActor(leaderId, TestRaftActor.newBuilder().peerAddresses(peerAddresses)
150 .config(leaderConfigParams).roleChangeNotifier(leaderNotifierActor));
152 follower1CollectorActor = follower1Actor.underlyingActor().collectorActor();
153 follower2CollectorActor = follower2Actor.underlyingActor().collectorActor();
154 follower3CollectorActor = follower3Actor.underlyingActor().collectorActor();
155 leaderCollectorActor = leaderActor.underlyingActor().collectorActor();
157 leaderContext = leaderActor.underlyingActor().getRaftActorContext();
158 leaderContext.getPeerInfo(follower3Id).setVotingState(VotingState.NON_VOTING);
160 waitUntilLeader(leaderActor);
162 testLog.info("createRaftActors starting");
165 private static void verifyRaftState(ActorRef raftActor, final RaftState expState) {
166 verifyRaftState(raftActor, rs -> assertEquals("getRaftState", expState.toString(), rs.getRaftState()));
169 private static void assertNullLeaderIdChange(TestActorRef<MessageCollectorActor> notifierActor) {
170 LeaderStateChanged change = expectFirstMatching(notifierActor, LeaderStateChanged.class);
171 assertNull("Expected null leader Id", change.getLeaderId());
175 public void testLeaderTransferAborted() throws Exception {
176 testLog.info("testLeaderTransferAborted starting");
180 leaderActor.underlyingActor().startDropMessages(AppendEntriesReply.class);
182 sendShutDown(leaderActor);
184 verifyRaftState(follower1Actor, RaftState.Follower);
185 verifyRaftState(follower2Actor, RaftState.Follower);
186 verifyRaftState(follower3Actor, RaftState.Follower);
188 testLog.info("testLeaderTransferOnShutDown ending");
192 public void testLeaderTransferSkippedOnShutdownWithNoFollowers() throws Exception {
193 testLog.info("testLeaderTransferSkippedOnShutdownWithNoFollowers starting");
195 leaderActor = newTestRaftActor(leaderId, TestRaftActor.newBuilder().config(newLeaderConfigParams()));
196 waitUntilLeader(leaderActor);
198 sendShutDown(leaderActor);
200 testLog.info("testLeaderTransferSkippedOnShutdownWithNoFollowers ending");