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