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

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.