func testConsensusModule_RpcReplyCallback_AndBecomeLeader( t *testing.T, cm *ConsensusModule, mrs *testhelpers.MockRpcSender, ) { // FIXME: multiple unsafe concurrent accesses // Sleep till election starts ett := cm.passiveConsensusModule.ElectionTimeoutTracker max_ticks := (ett.GetCurrentElectionTimeout().Nanoseconds() / testdata.TickerDuration.Nanoseconds()) + 2 for i := int64(0); i < max_ticks; i++ { time.Sleep(testdata.TickerDuration) if cm.GetServerState() != FOLLOWER { break } } if cm.GetServerState() != CANDIDATE { t.Fatal() } // candidate has issued RequestVote RPCs to all other servers. lastLogIndex, lastLogTerm, err := consensus.GetIndexAndTermOfLastEntry(cm.passiveConsensusModule.LogRO) if err != nil { t.Fatal(err) } expectedRpc := &RpcRequestVote{testdata.CurrentTerm + 1, lastLogIndex, lastLogTerm} expectedRpcs := map[ServerId]interface{}{ "s2": expectedRpc, "s3": expectedRpc, "s4": expectedRpc, "s5": expectedRpc, } mrs.CheckSentRpcs(t, expectedRpcs) // reply true for all votes serverTerm := cm.passiveConsensusModule.RaftPersistentState.GetCurrentTerm() if n := mrs.SendRVRepliesAndClearRpcs(&RpcRequestVoteReply{serverTerm, true}); n != 4 { t.Fatal(n) } time.Sleep(testdata.SleepToLetGoroutineRun) // server should now be a leader if cm.IsStopped() { t.Fatal() } if cm.GetServerState() != LEADER { t.Fatal() } // leader setup expectedRpc2 := &RpcAppendEntries{ serverTerm, lastLogIndex, lastLogTerm, []LogEntry{}, cm.passiveConsensusModule.GetCommitIndex(), } expectedRpcs2 := map[ServerId]interface{}{ "s2": expectedRpc2, "s3": expectedRpc2, "s4": expectedRpc2, "s5": expectedRpc2, } mrs.CheckSentRpcs(t, expectedRpcs2) // reply handling expectedMatchIndex := map[ServerId]LogIndex{"s2": 0, "s3": 0, "s4": 0, "s5": 0} if !reflect.DeepEqual(cm.passiveConsensusModule.LeaderVolatileState.MatchIndex, expectedMatchIndex) { t.Fatal() } if n := mrs.SendAERepliesAndClearRpcs(&RpcAppendEntriesReply{serverTerm, true}); n != 4 { t.Fatal(n) } time.Sleep(testdata.SleepToLetGoroutineRun) expectedMatchIndex = map[ServerId]LogIndex{ "s2": lastLogIndex, "s3": lastLogIndex, "s4": lastLogIndex, "s5": lastLogIndex, } if !reflect.DeepEqual(cm.passiveConsensusModule.LeaderVolatileState.MatchIndex, expectedMatchIndex) { t.Fatal(cm.passiveConsensusModule.LeaderVolatileState.MatchIndex) } }