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;
11 import akka.actor.ActorRef;
12 import akka.actor.Props;
13 import akka.testkit.TestActorRef;
14 import java.util.HashMap;
16 import org.junit.After;
17 import org.junit.Test;
18 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
19 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
20 import org.opendaylight.controller.cluster.raft.RaftActorContext;
21 import org.opendaylight.controller.cluster.raft.RaftState;
22 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
23 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
25 public class IsolatedLeaderTest extends AbstractLeaderTest<IsolatedLeader> {
27 private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
28 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
30 private final TestActorRef<MessageCollectorActor> senderActor = actorFactory.createTestActor(
31 Props.create(MessageCollectorActor.class), actorFactory.generateActorId("sender"));
33 private AbstractLeader isolatedLeader;
37 public void tearDown() throws Exception {
38 if(isolatedLeader != null) {
39 isolatedLeader.close();
46 protected IsolatedLeader createBehavior(RaftActorContext actorContext) {
47 return new IsolatedLeader(actorContext);
51 protected MockRaftActorContext createActorContext() {
52 return createActorContext(leaderActor);
56 protected MockRaftActorContext createActorContext(ActorRef actor) {
57 DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
58 configParams.setElectionTimeoutFactor(100000);
59 MockRaftActorContext context = new MockRaftActorContext("isolated-leader", getSystem(), actor);
60 context.setConfigParams(configParams);
65 public void testHandleMessageWithThreeMembers() throws Exception {
66 String followerAddress1 = "akka://test/user/$a";
67 String followerAddress2 = "akka://test/user/$b";
69 MockRaftActorContext leaderActorContext = createActorContext();
70 Map<String, String> peerAddresses = new HashMap<>();
71 peerAddresses.put("follower-1", followerAddress1);
72 peerAddresses.put("follower-2", followerAddress2);
73 leaderActorContext.setPeerAddresses(peerAddresses);
75 isolatedLeader = new IsolatedLeader(leaderActorContext);
76 leaderActorContext.setCurrentBehavior(isolatedLeader);
77 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
79 // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
80 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
81 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
82 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1, (short)0));
84 assertEquals("Raft state", RaftState.Leader, behavior.state());
86 isolatedLeader.close();
87 isolatedLeader = (AbstractLeader) behavior;
89 behavior = isolatedLeader.handleMessage(senderActor,
90 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
91 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
93 assertEquals("Raft state", RaftState.Leader, behavior.state());
97 public void testHandleMessageWithFiveMembers() throws Exception {
98 String followerAddress1 = "akka://test/user/$a";
99 String followerAddress2 = "akka://test/user/$b";
100 String followerAddress3 = "akka://test/user/$c";
101 String followerAddress4 = "akka://test/user/$d";
103 MockRaftActorContext leaderActorContext = createActorContext();
104 Map<String, String> peerAddresses = new HashMap<>();
105 peerAddresses.put("follower-1", followerAddress1);
106 peerAddresses.put("follower-2", followerAddress2);
107 peerAddresses.put("follower-3", followerAddress3);
108 peerAddresses.put("follower-4", followerAddress4);
109 leaderActorContext.setPeerAddresses(peerAddresses);
111 isolatedLeader = new IsolatedLeader(leaderActorContext);
112 leaderActorContext.setCurrentBehavior(isolatedLeader);
113 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
115 // in a 5 member cluster, atleast 2 followers need to be active and return a reply
116 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
117 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
118 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
120 assertEquals("Raft state", RaftState.IsolatedLeader, behavior.state());
122 behavior = isolatedLeader.handleMessage(senderActor,
123 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
124 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
126 assertEquals("Raft state", RaftState.Leader, behavior.state());
128 isolatedLeader.close();
129 isolatedLeader = (AbstractLeader) behavior;
131 behavior = isolatedLeader.handleMessage(senderActor,
132 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
133 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
135 assertEquals("Raft state", RaftState.Leader, behavior.state());
139 public void testHandleMessageFromAnotherLeader() throws Exception {
140 String followerAddress1 = "akka://test/user/$a";
141 String followerAddress2 = "akka://test/user/$b";
143 MockRaftActorContext leaderActorContext = createActorContext();
144 Map<String, String> peerAddresses = new HashMap<>();
145 peerAddresses.put("follower-1", followerAddress1);
146 peerAddresses.put("follower-2", followerAddress2);
147 leaderActorContext.setPeerAddresses(peerAddresses);
149 isolatedLeader = new IsolatedLeader(leaderActorContext);
150 assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
152 // if an append-entries reply is received by the isolated-leader, and that reply
153 // has a term > than its own term, then IsolatedLeader switches to Follower
154 // bowing itself to another leader in the cluster
155 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
156 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() + 1, true,
157 isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1, (short)0));
159 assertEquals("Raft state", RaftState.Follower, behavior.state());