Skip to content

Commit aaa411b

Browse files
authored
Merge pull request #135 from lerna-stack/test-receiving-request-vote-response
Test receiving RequestVoteResponse
2 parents ad18426 + 80ee0ac commit aaa411b

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

src/test/scala/lerna/akka/entityreplication/raft/RaftActorCandidateSpec.scala

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import lerna.akka.entityreplication.raft.RaftProtocol.{ Command, ForwardedComman
88
import lerna.akka.entityreplication.raft.model._
99
import lerna.akka.entityreplication.raft.protocol.RaftCommands._
1010
import lerna.akka.entityreplication.raft.routing.MemberIndex
11+
import org.scalatest.Inside
1112

12-
class RaftActorCandidateSpec extends TestKit(ActorSystem()) with RaftActorSpecBase {
13+
class RaftActorCandidateSpec extends TestKit(ActorSystem()) with RaftActorSpecBase with Inside {
1314

1415
import RaftActor._
1516

@@ -164,17 +165,40 @@ class RaftActorCandidateSpec extends TestKit(ActorSystem()) with RaftActorSpecBa
164165
}
165166

166167
"メンバーの過半数に Accept されると Leader になる" in {
168+
val selfMemberIndex = createUniqueMemberIndex()
167169
val follower1MemberIndex = createUniqueMemberIndex()
168170
val follower2MemberIndex = createUniqueMemberIndex()
169171
val candidate = createRaftActor(
172+
selfMemberIndex = selfMemberIndex,
170173
otherMemberIndexes = Set(follower1MemberIndex, follower2MemberIndex),
171174
)
172-
val term = Term.initial()
173-
setState(candidate, Candidate, createCandidateData(term))
175+
val currentTerm = Term(1)
176+
setState(candidate, Candidate, createCandidateData(currentTerm))
177+
inside(getState(candidate)) { state =>
178+
state.stateData.acceptedMembers should be(Set.empty)
179+
}
174180

175-
candidate ! RequestVoteAccepted(term, follower1MemberIndex)
176-
candidate ! RequestVoteAccepted(term, follower2MemberIndex)
177-
getState(candidate).stateName should be(Leader)
181+
// The candidate will vote for itself.
182+
candidate ! RequestVoteAccepted(currentTerm, selfMemberIndex)
183+
inside(getState(candidate)) { state =>
184+
state.stateName should be(Candidate)
185+
state.stateData.currentTerm should be(currentTerm)
186+
state.stateData.acceptedMembers should be(Set(selfMemberIndex))
187+
}
188+
189+
// Denied from follower1, this situation could happen by a split vote.
190+
candidate ! RequestVoteDenied(currentTerm)
191+
inside(getState(candidate)) { state =>
192+
state.stateName should be(Candidate)
193+
state.stateData.currentTerm should be(currentTerm)
194+
state.stateData.acceptedMembers should be(Set(selfMemberIndex))
195+
}
196+
197+
candidate ! RequestVoteAccepted(currentTerm, follower2MemberIndex)
198+
inside(getState(candidate)) { state =>
199+
state.stateName should be(Leader)
200+
state.stateData.currentTerm should be(currentTerm)
201+
}
178202
}
179203

180204
"become a Follower and agree to a Term if it receives RequestVoteDenied with newer Term" in {
@@ -192,6 +216,42 @@ class RaftActorCandidateSpec extends TestKit(ActorSystem()) with RaftActorSpecBa
192216
val state = getState(candidate)
193217
state.stateName should be(Follower)
194218
state.stateData.currentTerm should be(newerTerm)
219+
state.stateData.leaderMember should be(None)
220+
}
221+
222+
"not become the leader by duplicated votes from the same follower" in {
223+
val selfMemberIndex = createUniqueMemberIndex()
224+
val follower1MemberIndex = createUniqueMemberIndex()
225+
val follower2MemberIndex = createUniqueMemberIndex()
226+
val candidate = createRaftActor(
227+
selfMemberIndex = selfMemberIndex,
228+
otherMemberIndexes = Set(follower1MemberIndex, follower2MemberIndex),
229+
)
230+
val currentTerm = Term(1)
231+
setState(candidate, Candidate, createCandidateData(currentTerm))
232+
inside(getState(candidate)) { state =>
233+
state.stateData.acceptedMembers should be(Set.empty)
234+
}
235+
236+
// For simplicity, this test skips that the candidate votes for itself.
237+
238+
// The first vote from follower1
239+
candidate ! RequestVoteAccepted(currentTerm, follower1MemberIndex)
240+
inside(getState(candidate)) { state =>
241+
state.stateName should be(Candidate)
242+
state.stateData.currentTerm should be(currentTerm)
243+
state.stateData.acceptedMembers should be(Set(follower1MemberIndex))
244+
}
245+
246+
// The second duplicated vote from follower1.
247+
// The candidate shouldn't become the leader
248+
// since it doesn't receive votes from the majority of the members.
249+
candidate ! RequestVoteAccepted(currentTerm, follower1MemberIndex)
250+
inside(getState(candidate)) { state =>
251+
state.stateName should be(Candidate)
252+
state.stateData.currentTerm should be(currentTerm)
253+
state.stateData.acceptedMembers should be(Set(follower1MemberIndex))
254+
}
195255
}
196256

197257
"AppendEntries が古い Term を持っているときは拒否" in {

0 commit comments

Comments
 (0)