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 akka.actor.Props;
14 import akka.testkit.TestActorRef;
15 import java.util.HashMap;
17 import org.junit.After;
18 import org.junit.Test;
19 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
20 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
21 import org.opendaylight.controller.cluster.raft.RaftActorContext;
22 import org.opendaylight.controller.cluster.raft.RaftState;
23 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
24 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
26 public class IsolatedLeaderTest extends AbstractLeaderTest<IsolatedLeader> {
28 private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
29 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
31 private final TestActorRef<MessageCollectorActor> senderActor = actorFactory.createTestActor(
32 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("sender"));
34 private AbstractLeader isolatedLeader;
38 public void tearDown() throws Exception {
39 if (isolatedLeader != null) {
40 isolatedLeader.close();
47 protected IsolatedLeader createBehavior(RaftActorContext actorContext) {
48 return new IsolatedLeader(actorContext);
52 protected MockRaftActorContext createActorContext() {
53 return createActorContext(leaderActor);
57 protected MockRaftActorContext createActorContext(ActorRef actor) {
58 DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
59 configParams.setElectionTimeoutFactor(100000);
60 MockRaftActorContext context = new MockRaftActorContext("isolated-leader", getSystem(), actor);
61 context.setConfigParams(configParams);
66 public void testHandleMessageWithThreeMembers() throws Exception {
67 String followerAddress1 = "akka://test/user/$a";
68 String followerAddress2 = "akka://test/user/$b";
70 MockRaftActorContext leaderActorContext = createActorContext();
71 Map<String, String> peerAddresses = new HashMap<>();
72 peerAddresses.put("follower-1", followerAddress1);
73 peerAddresses.put("follower-2", followerAddress2);
74 leaderActorContext.setPeerAddresses(peerAddresses);
76 isolatedLeader = new IsolatedLeader(leaderActorContext);
77 leaderActorContext.setCurrentBehavior(isolatedLeader);
78 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
80 // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
81 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
82 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
83 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0));
85 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
87 isolatedLeader.close();
88 isolatedLeader = (AbstractLeader) newBehavior;
90 newBehavior = isolatedLeader.handleMessage(senderActor,
91 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
92 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0 ));
94 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
98 public void testHandleMessageWithFiveMembers() throws Exception {
99 String followerAddress1 = "akka://test/user/$a";
100 String followerAddress2 = "akka://test/user/$b";
101 String followerAddress3 = "akka://test/user/$c";
102 String followerAddress4 = "akka://test/user/$d";
104 final MockRaftActorContext leaderActorContext = createActorContext();
105 Map<String, String> peerAddresses = new HashMap<>();
106 peerAddresses.put("follower-1", followerAddress1);
107 peerAddresses.put("follower-2", followerAddress2);
108 peerAddresses.put("follower-3", followerAddress3);
109 peerAddresses.put("follower-4", followerAddress4);
110 leaderActorContext.setPeerAddresses(peerAddresses);
112 isolatedLeader = new IsolatedLeader(leaderActorContext);
113 leaderActorContext.setCurrentBehavior(isolatedLeader);
114 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
116 // in a 5 member cluster, atleast 2 followers need to be active and return a reply
117 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
118 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
119 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0 ));
121 assertEquals("Raft state", RaftState.IsolatedLeader, newBehavior.state());
123 newBehavior = isolatedLeader.handleMessage(senderActor,
124 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
125 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0 ));
127 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
129 isolatedLeader.close();
130 isolatedLeader = (AbstractLeader) newBehavior;
132 newBehavior = isolatedLeader.handleMessage(senderActor,
133 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
134 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0 ));
136 assertEquals("Raft state", RaftState.Leader, newBehavior.state());
140 public void testHandleMessageFromAnotherLeader() throws Exception {
141 String followerAddress1 = "akka://test/user/$a";
142 String followerAddress2 = "akka://test/user/$b";
144 MockRaftActorContext leaderActorContext = createActorContext();
145 Map<String, String> peerAddresses = new HashMap<>();
146 peerAddresses.put("follower-1", followerAddress1);
147 peerAddresses.put("follower-2", followerAddress2);
148 leaderActorContext.setPeerAddresses(peerAddresses);
150 isolatedLeader = new IsolatedLeader(leaderActorContext);
151 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
153 // if an append-entries reply is received by the isolated-leader, and that reply
154 // has a term > than its own term, then IsolatedLeader switches to Follower
155 // bowing itself to another leader in the cluster
156 RaftActorBehavior newBehavior = isolatedLeader.handleMessage(senderActor,
157 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() + 1, true,
158 isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1, (short)0));
160 assertEquals("Raft state", RaftState.Follower, newBehavior.state());