2 * Copyright (c) 2014 Cisco 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.behaviors;
10 import static org.junit.Assert.assertEquals;
12 import akka.actor.ActorRef;
13 import java.util.HashMap;
15 import org.junit.After;
16 import org.junit.Test;
17 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
18 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
19 import org.opendaylight.controller.cluster.raft.RaftActorContext;
20 import org.opendaylight.controller.cluster.raft.RaftState;
21 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
22 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
24 public class IsolatedLeaderTest extends AbstractLeaderTest<IsolatedLeader> {
26 private final ActorRef leaderActor = actorFactory.createActor(
27 MessageCollectorActor.props(), actorFactory.generateActorId("leader"));
29 private final ActorRef senderActor = actorFactory.createActor(
30 MessageCollectorActor.props(), actorFactory.generateActorId("sender"));
32 private AbstractLeader isolatedLeader;
36 public void tearDown() {
37 if (isolatedLeader != null) {
38 isolatedLeader.close();
45 protected IsolatedLeader createBehavior(final RaftActorContext actorContext) {
46 return new IsolatedLeader(actorContext);
50 protected MockRaftActorContext createActorContext() {
51 return createActorContext(leaderActor);
55 protected MockRaftActorContext createActorContext(final ActorRef actor) {
56 DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
57 configParams.setElectionTimeoutFactor(100000);
58 MockRaftActorContext context = new MockRaftActorContext("isolated-leader", getSystem(), actor);
59 context.setConfigParams(configParams);
64 public void testHandleMessageWithThreeMembers() {
65 String followerAddress1 = "akka://test/user/$a";
66 String followerAddress2 = "akka://test/user/$b";
68 MockRaftActorContext leaderActorContext = createActorContext();
69 Map<String, String> peerAddresses = new HashMap<>();
70 peerAddresses.put("follower-1", followerAddress1);
71 peerAddresses.put("follower-2", followerAddress2);
72 leaderActorContext.setPeerAddresses(peerAddresses);
74 isolatedLeader = new IsolatedLeader(leaderActorContext);
75 leaderActorContext.setCurrentBehavior(isolatedLeader);
76 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
78 // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
79 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
80 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
81 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0));
83 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
85 isolatedLeader.close();
86 isolatedLeader = (AbstractLeader) newBehavior;
88 newBehavior = isolatedLeader.handleMessage(senderActor,
89 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
90 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short) 0));
92 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
96 public void testHandleMessageWithFiveMembers() {
97 String followerAddress1 = "akka://test/user/$a";
98 String followerAddress2 = "akka://test/user/$b";
99 String followerAddress3 = "akka://test/user/$c";
100 String followerAddress4 = "akka://test/user/$d";
102 final MockRaftActorContext leaderActorContext = createActorContext();
103 Map<String, String> peerAddresses = new HashMap<>();
104 peerAddresses.put("follower-1", followerAddress1);
105 peerAddresses.put("follower-2", followerAddress2);
106 peerAddresses.put("follower-3", followerAddress3);
107 peerAddresses.put("follower-4", followerAddress4);
108 leaderActorContext.setPeerAddresses(peerAddresses);
110 isolatedLeader = new IsolatedLeader(leaderActorContext);
111 leaderActorContext.setCurrentBehavior(isolatedLeader);
112 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
114 // in a 5 member cluster, atleast 2 followers need to be active and return a reply
115 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
116 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
117 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short) 0));
119 assertEquals("Raft state", RaftState.IsolatedLeader, newBehavior.state());
121 newBehavior = isolatedLeader.handleMessage(senderActor,
122 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
123 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short) 0));
125 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
127 isolatedLeader.close();
128 isolatedLeader = (AbstractLeader) newBehavior;
130 newBehavior = isolatedLeader.handleMessage(senderActor,
131 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
132 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short) 0));
134 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
138 public void testHandleMessageFromAnotherLeader() {
139 String followerAddress1 = "akka://test/user/$a";
140 String followerAddress2 = "akka://test/user/$b";
142 MockRaftActorContext leaderActorContext = createActorContext();
143 Map<String, String> peerAddresses = new HashMap<>();
144 peerAddresses.put("follower-1", followerAddress1);
145 peerAddresses.put("follower-2", followerAddress2);
146 leaderActorContext.setPeerAddresses(peerAddresses);
148 isolatedLeader = new IsolatedLeader(leaderActorContext);
149 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
151 // if an append-entries reply is received by the isolated-leader, and that reply
152 // has a term > than its own term, then IsolatedLeader switches to Follower
153 // bowing itself to another leader in the cluster
154 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
155 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() + 1, true,
156 isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1, (short)0));
158 assertEquals("Raft state", RaftState.Follower, newBehavior.state());