Merge "Fix raw references to SimpleNode"
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / behaviors / CandidateTest.java
1 package org.opendaylight.controller.cluster.raft.behaviors;
2
3 import akka.actor.ActorRef;
4 import akka.actor.Props;
5 import akka.testkit.JavaTestKit;
6 import org.junit.Assert;
7 import org.junit.Before;
8 import org.junit.Test;
9 import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
10 import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
11 import org.opendaylight.controller.cluster.raft.RaftActorContext;
12 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
13 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
14 import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
15 import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
16 import org.opendaylight.controller.cluster.raft.messages.RequestVote;
17 import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
18 import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22 import static org.junit.Assert.assertEquals;
23
24 public class CandidateTest extends AbstractRaftActorBehaviorTest {
25
26     private final ActorRef candidateActor = getSystem().actorOf(Props.create(
27         DoNothingActor.class));
28
29     private final ActorRef peerActor1 = getSystem().actorOf(Props.create(
30         DoNothingActor.class));
31
32     private final ActorRef peerActor2 = getSystem().actorOf(Props.create(
33         DoNothingActor.class));
34
35     private final ActorRef peerActor3 = getSystem().actorOf(Props.create(
36         DoNothingActor.class));
37
38     private final ActorRef peerActor4 = getSystem().actorOf(Props.create(
39         DoNothingActor.class));
40
41     private final Map<String, String> onePeer = new HashMap<>();
42     private final Map<String, String> twoPeers = new HashMap<>();
43     private final Map<String, String> fourPeers = new HashMap<>();
44
45     @Before
46     public void setUp(){
47         onePeer.put(peerActor1.path().toString(),
48             peerActor1.path().toString());
49
50         twoPeers.put(peerActor1.path().toString(),
51             peerActor1.path().toString());
52         twoPeers.put(peerActor2.path().toString(),
53             peerActor2.path().toString());
54
55         fourPeers.put(peerActor1.path().toString(),
56             peerActor1.path().toString());
57         fourPeers.put(peerActor2.path().toString(),
58             peerActor2.path().toString());
59         fourPeers.put(peerActor3.path().toString(),
60             peerActor3.path().toString());
61         fourPeers.put(peerActor4.path().toString(),
62             peerActor3.path().toString());
63
64
65     }
66
67     @Test
68     public void testWhenACandidateIsCreatedItIncrementsTheCurrentTermAndVotesForItself(){
69         RaftActorContext raftActorContext = createActorContext();
70         long expectedTerm = raftActorContext.getTermInformation().getCurrentTerm();
71
72         new Candidate(raftActorContext);
73
74         assertEquals(expectedTerm+1, raftActorContext.getTermInformation().getCurrentTerm());
75         assertEquals(raftActorContext.getId(), raftActorContext.getTermInformation().getVotedFor());
76     }
77
78     @Test
79     public void testThatAnElectionTimeoutIsTriggered(){
80         new JavaTestKit(getSystem()) {{
81
82             new Within(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6)) {
83                 protected void run() {
84
85                     Candidate candidate = new Candidate(createActorContext(getTestActor()));
86
87                     final Boolean out = new ExpectMsg<Boolean>(DefaultConfigParamsImpl.HEART_BEAT_INTERVAL.$times(6), "ElectionTimeout") {
88                         // do not put code outside this method, will run afterwards
89                         protected Boolean match(Object in) {
90                             if (in instanceof ElectionTimeout) {
91                                  return true;
92                             } else {
93                                 throw noMatch();
94                             }
95                         }
96                     }.get();
97
98                     assertEquals(true, out);
99                 }
100             };
101         }};
102     }
103
104     @Test
105     public void testHandleElectionTimeoutWhenThereAreZeroPeers(){
106         RaftActorContext raftActorContext = createActorContext();
107         Candidate candidate =
108             new Candidate(raftActorContext);
109
110         RaftActorBehavior raftBehavior =
111             candidate.handleMessage(candidateActor, new ElectionTimeout());
112
113         Assert.assertTrue(raftBehavior instanceof Leader);
114     }
115
116     @Test
117     public void testHandleElectionTimeoutWhenThereAreTwoNodesInCluster(){
118         MockRaftActorContext raftActorContext =
119             (MockRaftActorContext) createActorContext();
120         raftActorContext.setPeerAddresses(onePeer);
121         Candidate candidate =
122             new Candidate(raftActorContext);
123
124         RaftActorBehavior raftBehavior =
125             candidate.handleMessage(candidateActor, new ElectionTimeout());
126
127         Assert.assertTrue(raftBehavior instanceof Candidate);
128     }
129
130     @Test
131     public void testBecomeLeaderOnReceivingMajorityVotesInThreeNodesInCluster(){
132         MockRaftActorContext raftActorContext =
133             (MockRaftActorContext) createActorContext();
134         raftActorContext.setPeerAddresses(twoPeers);
135         Candidate candidate =
136             new Candidate(raftActorContext);
137
138         RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
139
140         Assert.assertTrue(behaviorOnFirstVote instanceof Leader);
141
142     }
143
144     @Test
145     public void testBecomeLeaderOnReceivingMajorityVotesInFiveNodesInCluster(){
146         MockRaftActorContext raftActorContext =
147             (MockRaftActorContext) createActorContext();
148         raftActorContext.setPeerAddresses(fourPeers);
149         Candidate candidate =
150             new Candidate(raftActorContext);
151
152         RaftActorBehavior behaviorOnFirstVote = candidate.handleMessage(peerActor1, new RequestVoteReply(0, true));
153
154         RaftActorBehavior behaviorOnSecondVote = candidate.handleMessage(peerActor2, new RequestVoteReply(0, true));
155
156         Assert.assertTrue(behaviorOnFirstVote instanceof Candidate);
157         Assert.assertTrue(behaviorOnSecondVote instanceof Leader);
158
159     }
160
161     @Test
162     public void testResponseToAppendEntriesWithLowerTerm(){
163         new JavaTestKit(getSystem()) {{
164
165             new Within(duration("1 seconds")) {
166                 protected void run() {
167
168                     Candidate candidate = new Candidate(createActorContext(getTestActor()));
169
170                     candidate.handleMessage(getTestActor(), new AppendEntries(0, "test", 0,0,Collections.<ReplicatedLogEntry>emptyList(), 0));
171
172                     final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
173                         // do not put code outside this method, will run afterwards
174                         protected Boolean match(Object in) {
175                             if (in instanceof AppendEntriesReply) {
176                                 AppendEntriesReply reply = (AppendEntriesReply) in;
177                                 return reply.isSuccess();
178                             } else {
179                                 throw noMatch();
180                             }
181                         }
182                     }.get();
183
184                     assertEquals(false, out);
185                 }
186             };
187         }};
188     }
189
190     @Test
191     public void testResponseToRequestVoteWithLowerTerm(){
192         new JavaTestKit(getSystem()) {{
193
194             new Within(duration("1 seconds")) {
195                 protected void run() {
196
197                     Candidate candidate = new Candidate(createActorContext(getTestActor()));
198
199                     candidate.handleMessage(getTestActor(), new RequestVote(0, "test", 0, 0));
200
201                     final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "AppendEntriesResponse") {
202                         // do not put code outside this method, will run afterwards
203                         protected Boolean match(Object in) {
204                             if (in instanceof RequestVoteReply) {
205                                 RequestVoteReply reply = (RequestVoteReply) in;
206                                 return reply.isVoteGranted();
207                             } else {
208                                 throw noMatch();
209                             }
210                         }
211                     }.get();
212
213                     assertEquals(false, out);
214                 }
215             };
216         }};
217     }
218
219     @Test
220     public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNull(){
221         new JavaTestKit(getSystem()) {{
222
223             new Within(duration("1 seconds")) {
224                 protected void run() {
225
226                     RaftActorContext context = createActorContext(getTestActor());
227
228                     context.getTermInformation().update(1000, null);
229
230                     // Once a candidate is created it will immediately increment the current term so after
231                     // construction the currentTerm should be 1001
232                     RaftActorBehavior follower = createBehavior(context);
233
234                     follower.handleMessage(getTestActor(), new RequestVote(1001, "test", 10000, 999));
235
236                     final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
237                         // do not put code outside this method, will run afterwards
238                         protected Boolean match(Object in) {
239                             if (in instanceof RequestVoteReply) {
240                                 RequestVoteReply reply = (RequestVoteReply) in;
241                                 return reply.isVoteGranted();
242                             } else {
243                                 throw noMatch();
244                             }
245                         }
246                     }.get();
247
248                     assertEquals(true, out);
249                 }
250             };
251         }};
252     }
253
254     @Test
255     public void testHandleRequestVoteWhenSenderTermEqualToCurrentTermAndVotedForIsNotTheSameAsCandidateId(){
256         new JavaTestKit(getSystem()) {{
257
258             new Within(duration("1 seconds")) {
259                 protected void run() {
260
261                     RaftActorContext context = createActorContext(getTestActor());
262
263                     context.getTermInformation().update(1000, "test");
264
265                     RaftActorBehavior follower = createBehavior(context);
266
267                     follower.handleMessage(getTestActor(), new RequestVote(1001, "candidate", 10000, 999));
268
269                     final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"), "RequestVoteReply") {
270                         // do not put code outside this method, will run afterwards
271                         protected Boolean match(Object in) {
272                             if (in instanceof RequestVoteReply) {
273                                 RequestVoteReply reply = (RequestVoteReply) in;
274                                 return reply.isVoteGranted();
275                             } else {
276                                 throw noMatch();
277                             }
278                         }
279                     }.get();
280
281                     assertEquals(false, out);
282                 }
283             };
284         }};
285     }
286
287
288
289     @Override protected RaftActorBehavior createBehavior(RaftActorContext actorContext) {
290         return new Candidate(actorContext);
291     }
292
293     @Override protected RaftActorContext createActorContext() {
294         return new MockRaftActorContext("test", getSystem(), candidateActor);
295     }
296
297
298 }