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