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 akka.actor.ActorRef;
11 import akka.actor.Props;
12 import akka.testkit.JavaTestKit;
13 import java.util.HashMap;
15 import org.junit.Test;
16 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
17 import org.opendaylight.controller.cluster.raft.RaftActorContext;
18 import org.opendaylight.controller.cluster.raft.RaftState;
19 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
20 import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
24 public class IsolatedLeaderTest extends AbstractRaftActorBehaviorTest {
26 private ActorRef leaderActor =
27 getSystem().actorOf(Props.create(DoNothingActor.class));
29 private ActorRef senderActor =
30 getSystem().actorOf(Props.create(DoNothingActor.class));
33 protected RaftActorBehavior createBehavior(
34 RaftActorContext actorContext) {
35 return new Leader(actorContext);
39 protected RaftActorContext createActorContext() {
40 return createActorContext(leaderActor);
45 public void testHandleMessageWithThreeMembers() {
46 new JavaTestKit(getSystem()) {{
47 String followerAddress1 = "akka://test/user/$a";
48 String followerAddress2 = "akka://test/user/$b";
50 MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
51 Map<String, String> peerAddresses = new HashMap<>();
52 peerAddresses.put("follower-1", followerAddress1);
53 peerAddresses.put("follower-2", followerAddress2);
54 leaderActorContext.setPeerAddresses(peerAddresses);
56 IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
57 assertTrue(isolatedLeader.state() == RaftState.IsolatedLeader);
59 // in a 3 node cluster, even if 1 follower is returns a reply, the isolatedLeader is not isolated
60 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
61 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
62 isolatedLeader.lastIndex() - 1, isolatedLeader.lastTerm() - 1));
64 assertEquals(RaftState.Leader, behavior.state());
66 behavior = isolatedLeader.handleMessage(senderActor,
67 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
68 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
70 assertEquals(RaftState.Leader, behavior.state());
75 public void testHandleMessageWithFiveMembers() {
76 new JavaTestKit(getSystem()) {{
78 String followerAddress1 = "akka://test/user/$a";
79 String followerAddress2 = "akka://test/user/$b";
80 String followerAddress3 = "akka://test/user/$c";
81 String followerAddress4 = "akka://test/user/$d";
83 MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
84 Map<String, String> peerAddresses = new HashMap<>();
85 peerAddresses.put("follower-1", followerAddress1);
86 peerAddresses.put("follower-2", followerAddress2);
87 peerAddresses.put("follower-3", followerAddress3);
88 peerAddresses.put("follower-4", followerAddress4);
89 leaderActorContext.setPeerAddresses(peerAddresses);
91 IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
92 assertEquals(RaftState.IsolatedLeader, isolatedLeader.state());
94 // in a 5 member cluster, atleast 2 followers need to be active and return a reply
95 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
96 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() - 1, true,
97 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
99 assertEquals(RaftState.IsolatedLeader, behavior.state());
101 behavior = isolatedLeader.handleMessage(senderActor,
102 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
103 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
105 assertEquals(RaftState.Leader, behavior.state());
107 behavior = isolatedLeader.handleMessage(senderActor,
108 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
109 isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1 ));
111 assertEquals(RaftState.Leader, behavior.state());
116 public void testHandleMessageFromAnotherLeader() {
117 new JavaTestKit(getSystem()) {{
118 String followerAddress1 = "akka://test/user/$a";
119 String followerAddress2 = "akka://test/user/$b";
121 MockRaftActorContext leaderActorContext = (MockRaftActorContext) createActorContext();
122 Map<String, String> peerAddresses = new HashMap<>();
123 peerAddresses.put("follower-1", followerAddress1);
124 peerAddresses.put("follower-2", followerAddress2);
125 leaderActorContext.setPeerAddresses(peerAddresses);
127 IsolatedLeader isolatedLeader = new IsolatedLeader(leaderActorContext);
128 assertTrue(isolatedLeader.state() == RaftState.IsolatedLeader);
130 // if an append-entries reply is received by the isolated-leader, and that reply
131 // has a term > than its own term, then IsolatedLeader switches to Follower
132 // bowing itself to another leader in the cluster
133 RaftActorBehavior behavior = isolatedLeader.handleMessage(senderActor,
134 new AppendEntriesReply("follower-1", isolatedLeader.lastTerm() + 1, true,
135 isolatedLeader.lastIndex() + 1, isolatedLeader.lastTerm() + 1));
137 assertEquals(RaftState.Follower, behavior.state());