Remove DelegatingRaftActorBehavior
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / IsolatedLeaderTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.raft.behaviors;
9
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;
15 import java.util.Map;
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;
24
25 public class IsolatedLeaderTest extends AbstractLeaderTest<IsolatedLeader> {
26
27     private final TestActorRef<MessageCollectorActor> leaderActor = actorFactory.createTestActor(
28             Props.create(MessageCollectorActor.class), actorFactory.generateActorId("leader"));
29
30     private final TestActorRef<MessageCollectorActor> senderActor = actorFactory.createTestActor(
31             Props.create(MessageCollectorActor.class), actorFactory.generateActorId("sender"));
32
33     private AbstractLeader isolatedLeader;
34
35     @Override
36     @After
37     public void tearDown() throws Exception {
38         if(isolatedLeader != null) {
39             isolatedLeader.close();
40         }
41
42         super.tearDown();
43     }
44
45     @Override
46     protected IsolatedLeader createBehavior(RaftActorContext actorContext) {
47         return new IsolatedLeader(actorContext);
48     }
49
50     @Override
51     protected MockRaftActorContext createActorContext() {
52         return createActorContext(leaderActor);
53     }
54
55     @Override
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);
61         return context;
62     }
63
64     @Test
65     public void testHandleMessageWithThreeMembers() throws Exception {
66         String followerAddress1 = "akka://test/user/$a";
67         String followerAddress2 = "akka://test/user/$b";
68
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);
74
75         isolatedLeader = new IsolatedLeader(leaderActorContext);
76         leaderActorContext.setCurrentBehavior(isolatedLeader);
77         assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
78
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));
83
84         assertEquals("Raft state", RaftState.Leader, behavior.state());
85
86         isolatedLeader.close();
87         isolatedLeader = (AbstractLeader) behavior;
88
89         behavior = isolatedLeader.handleMessage(senderActor,
90                 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
91                         isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
92
93         assertEquals("Raft state", RaftState.Leader, behavior.state());
94     }
95
96     @Test
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";
102
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);
110
111         isolatedLeader = new IsolatedLeader(leaderActorContext);
112         leaderActorContext.setCurrentBehavior(isolatedLeader);
113         assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
114
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 ));
119
120         assertEquals("Raft state", RaftState.IsolatedLeader, behavior.state());
121
122         behavior = isolatedLeader.handleMessage(senderActor,
123                 new AppendEntriesReply("follower-2", isolatedLeader.lastTerm() - 1, true,
124                         isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
125
126         assertEquals("Raft state", RaftState.Leader, behavior.state());
127
128         isolatedLeader.close();
129         isolatedLeader = (AbstractLeader) behavior;
130
131         behavior = isolatedLeader.handleMessage(senderActor,
132                 new AppendEntriesReply("follower-3", isolatedLeader.lastTerm() - 1, true,
133                         isolatedLeader.lastIndex() -1, isolatedLeader.lastTerm() -1, (short)0 ));
134
135         assertEquals("Raft state", RaftState.Leader, behavior.state());
136     }
137
138     @Test
139     public void testHandleMessageFromAnotherLeader() throws Exception {
140         String followerAddress1 = "akka://test/user/$a";
141         String followerAddress2 = "akka://test/user/$b";
142
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);
148
149         isolatedLeader = new IsolatedLeader(leaderActorContext);
150         assertEquals("Raft state", RaftState.IsolatedLeader, isolatedLeader.state());
151
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));
158
159         assertEquals("Raft state", RaftState.Follower, behavior.state());
160
161         behavior.close();
162     }
163 }