Example #1
0
func testCM_SOLO_Follower_ElectsSelfOnElectionTimeout(
	t *testing.T,
	mcm *managedConsensusModule,
	mrs *testhelpers.MockRpcSender,
) {
	if mcm.pcm.GetServerState() != FOLLOWER {
		t.Fatal()
	}
	if mcm.pcm.RaftPersistentState.GetVotedFor() != "" {
		t.Fatal()
	}

	// Test that a tick before election timeout causes no state change.
	err := mcm.Tick()
	if err != nil {
		t.Fatal(err)
	}
	if mcm.pcm.RaftPersistentState.GetCurrentTerm() != testdata.CurrentTerm {
		t.Fatal()
	}
	if mcm.pcm.GetServerState() != FOLLOWER {
		t.Fatal()
	}

	var expectedNewTerm TermNo = testdata.CurrentTerm + 1

	timeout1 := mcm.pcm.ElectionTimeoutTracker.GetCurrentElectionTimeout()
	// Test that election timeout causes a new election
	mcm.tickTilElectionTimeout(t)
	if mcm.pcm.RaftPersistentState.GetCurrentTerm() != expectedNewTerm {
		t.Fatal(expectedNewTerm, mcm.pcm.RaftPersistentState.GetCurrentTerm())
	}
	// Single node should immediately elect itself as leader
	if mcm.pcm.GetServerState() != LEADER {
		t.Fatal()
	}
	// candidate has voted for itself
	if mcm.pcm.RaftPersistentState.GetVotedFor() != testdata.ThisServerId {
		t.Fatal()
	}
	// a new election timeout was chosen
	if mcm.pcm.ElectionTimeoutTracker.GetCurrentElectionTimeout() == timeout1 {
		t.Fatal()
	}
	// candidate state is fresh
	expectedCvs, err := consensus_state.NewCandidateVolatileState(mcm.pcm.ClusterInfo)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(mcm.pcm.CandidateVolatileState, expectedCvs) {
		t.Fatal()
	}

	// no RPCs issued
	mrs.CheckSentRpcs(t, make(map[ServerId]interface{}))
	mrs.ClearSentRpcs()
}
Example #2
0
func testCM_FollowerOrCandidate_StartsElectionOnElectionTimeout_Part2(
	t *testing.T,
	mcm *managedConsensusModule,
	mrs *testhelpers.MockRpcSender,
	expectedNewTerm TermNo,
) {
	timeout1 := mcm.pcm.ElectionTimeoutTracker.GetCurrentElectionTimeout()
	// Test that election timeout causes a new election
	mcm.tickTilElectionTimeout(t)
	if mcm.pcm.RaftPersistentState.GetCurrentTerm() != expectedNewTerm {
		t.Fatal(expectedNewTerm, mcm.pcm.RaftPersistentState.GetCurrentTerm())
	}
	if mcm.pcm.GetServerState() != CANDIDATE {
		t.Fatal()
	}
	// candidate has voted for itself
	if mcm.pcm.RaftPersistentState.GetVotedFor() != testdata.ThisServerId {
		t.Fatal()
	}
	// a new election timeout was chosen
	// Playing the odds here :P
	if mcm.pcm.ElectionTimeoutTracker.GetCurrentElectionTimeout() == timeout1 {
		t.Fatal()
	}
	// candidate state is fresh
	expectedCvs, err := consensus_state.NewCandidateVolatileState(mcm.pcm.ClusterInfo)
	if err != nil {
		t.Fatal(err)
	}
	if !reflect.DeepEqual(mcm.pcm.CandidateVolatileState, expectedCvs) {
		t.Fatal()
	}

	// candidate has issued RequestVote RPCs to all other servers.
	lastLogIndex, lastLogTerm, err := GetIndexAndTermOfLastEntry(mcm.pcm.LogRO)
	if err != nil {
		t.Fatal(err)
	}
	expectedRpc := &RpcRequestVote{expectedNewTerm, lastLogIndex, lastLogTerm}
	expectedRpcs := map[ServerId]interface{}{}
	err = mcm.pcm.ClusterInfo.ForEachPeer(func(serverId ServerId) error {
		expectedRpcs[serverId] = expectedRpc
		return nil
	})
	if err != nil {
		t.Fatal(err)
	}
	mrs.CheckSentRpcs(t, expectedRpcs)
	mrs.ClearSentRpcs()
}
Example #3
0
func testIsLeaderWithTermAndSentEmptyAppendEntries(
	t *testing.T,
	mcm *managedConsensusModule,
	mrs *testhelpers.MockRpcSender,
	serverTerm TermNo,
) {
	if mcm.pcm.GetServerState() != LEADER {
		t.Fatal()
	}
	if mcm.pcm.RaftPersistentState.GetCurrentTerm() != serverTerm {
		t.Fatal()
	}

	// leader state is fresh
	expectedNextIndex := map[ServerId]LogIndex{"s2": 11, "s3": 11, "s4": 11, "s5": 11}
	if !reflect.DeepEqual(mcm.pcm.LeaderVolatileState.NextIndex, expectedNextIndex) {
		t.Fatal()
	}
	expectedMatchIndex := map[ServerId]LogIndex{"s2": 0, "s3": 0, "s4": 0, "s5": 0}
	if !reflect.DeepEqual(mcm.pcm.LeaderVolatileState.MatchIndex, expectedMatchIndex) {
		t.Fatal()
	}

	// leader setup
	lastLogIndex, lastLogTerm, err := GetIndexAndTermOfLastEntry(mcm.pcm.LogRO)
	if err != nil {
		t.Fatal(err)
	}
	expectedRpc := &RpcAppendEntries{
		serverTerm,
		lastLogIndex,
		lastLogTerm,
		[]LogEntry{},
		mcm.pcm.GetCommitIndex(),
	}
	expectedRpcs := map[ServerId]interface{}{
		"s2": expectedRpc,
		"s3": expectedRpc,
		"s4": expectedRpc,
		"s5": expectedRpc,
	}
	mrs.CheckSentRpcs(t, expectedRpcs)
}
Example #4
0
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)
	}
}