func setupConsensusModuleR3_SOLO( t *testing.T, electionTimeoutLow time.Duration, logTerms []TermNo, imrsc *inMemoryRpcServiceConnector, ) (IConsensusModule, *log.InMemoryLog, *testhelpers.DummyStateMachine) { ps := rps.NewIMPSWithCurrentTerm(0) iml := log.TestUtil_NewInMemoryLog_WithTerms(logTerms) dsm := testhelpers.NewDummyStateMachine() ts := config.TimeSettings{testdata.TickerDuration, testdata.ElectionTimeoutLow} ci, err := config.NewClusterInfo([]ServerId{"_SOLO_"}, "_SOLO_") if err != nil { t.Fatal(err) } cm, err := NewConsensusModule(ps, iml, imrsc, ci, testdata.MaxEntriesPerAppendEntry, ts) if err != nil { t.Fatal(err) } if cm == nil { t.Fatal() } err = cm.Start(dsm) if err != nil { t.Fatal(err) } return cm, iml, dsm }
func setupConsensusModuleR2( t *testing.T, logTerms []TermNo, ) (*ConsensusModule, *testhelpers.MockRpcSender) { ps := rps.NewIMPSWithCurrentTerm(testdata.CurrentTerm) iml := log.TestUtil_NewInMemoryLog_WithTerms(logTerms) dsm := testhelpers.NewDummyStateMachine() mrs := testhelpers.NewMockRpcSender() ts := config.TimeSettings{testdata.TickerDuration, testdata.ElectionTimeoutLow} ci, err := config.NewClusterInfo(testdata.AllServerIds, testdata.ThisServerId) if err != nil { t.Fatal(err) } cm, err := NewConsensusModule(ps, iml, mrs, ci, testdata.MaxEntriesPerAppendEntry, ts) if err != nil { t.Fatal(err) } if cm == nil { t.Fatal() } err = cm.Start(dsm) if err != nil { t.Fatal(err) } return cm, mrs }
func TestFindNewerCommitIndex_Figure8_CaseEextended(t *testing.T) { ci, err := config.NewClusterInfo([]ServerId{"s1", "s2", "s3", "s4", "s5"}, "s1") if err != nil { t.Fatal(err) } // Figure 8, case (e) extended with extra term 4 entry at index 4 terms := []TermNo{1, 2, 4, 4} // leader line for the case imle := log.TestUtil_NewInMemoryLog_WithTerms(terms) lvs, err := consensus_state.NewLeaderVolatileState(ci, LogIndex(len(terms))) if err != nil { t.Fatal(err) } _findNewerCommitIndex := func(currentTerm TermNo, commitIndex LogIndex) LogIndex { nci, err := consensus_state.FindNewerCommitIndex(ci, lvs, imle, currentTerm, commitIndex) if err != nil { t.Fatal(err) } return nci } // match peers err = lvs.SetMatchIndexAndNextIndex("s2", 4) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s3", 4) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s4", 1) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s5", 1) if err != nil { t.Fatal(err) } // currentTerm = 4 has a solution // the highest match is returned if _findNewerCommitIndex(4, 0) != 4 { t.Fatal() } if _findNewerCommitIndex(4, 1) != 4 { t.Fatal() } if _findNewerCommitIndex(4, 2) != 4 { t.Fatal() } if _findNewerCommitIndex(4, 3) != 4 { t.Fatal() } // returns 0 if current commitIndex is the highest match if _findNewerCommitIndex(4, 4) != 0 { t.Fatal() } }
func TestFindNewerCommitIndex_SOLO(t *testing.T) { ci, err := config.NewClusterInfo([]ServerId{"s1"}, "s1") if err != nil { t.Fatal(err) } terms := []TermNo{1, 2, 2, 2, 3, 3} imle := log.TestUtil_NewInMemoryLog_WithTerms(terms) lvs, err := consensus_state.NewLeaderVolatileState(ci, LogIndex(len(terms))) if err != nil { t.Fatal(err) } _findNewerCommitIndex := func(currentTerm TermNo, commitIndex LogIndex) LogIndex { nci, err := consensus_state.FindNewerCommitIndex(ci, lvs, imle, currentTerm, commitIndex) if err != nil { t.Fatal(err) } return nci } if nci := _findNewerCommitIndex(1, 0); nci != 1 { t.Fatal(nci) } if nci := _findNewerCommitIndex(1, 1); nci != 0 { t.Fatal(nci) } // the highest match is returned if nci := _findNewerCommitIndex(2, 0); nci != 4 { t.Fatal(nci) } if nci := _findNewerCommitIndex(2, 3); nci != 4 { t.Fatal(nci) } if nci := _findNewerCommitIndex(3, 1); nci != 6 { t.Fatal(nci) } // returns 0 if current commitIndex is the highest match if nci := _findNewerCommitIndex(2, 4); nci != 0 { t.Fatal(nci) } }
func setupManagedConsensusModuleR2( t *testing.T, logTerms []TermNo, solo bool, ) (*managedConsensusModule, *testhelpers.MockRpcSender) { ps := rps.NewIMPSWithCurrentTerm(testdata.CurrentTerm) iml := log.TestUtil_NewInMemoryLog_WithTerms(logTerms) dsm := testhelpers.NewDummyStateMachine() mrs := testhelpers.NewMockRpcSender() var allServerIds []ServerId if solo { allServerIds = []ServerId{testdata.ThisServerId} } else { allServerIds = testdata.AllServerIds } ci, err := config.NewClusterInfo(allServerIds, testdata.ThisServerId) if err != nil { t.Fatal(err) } now := time.Now() cm, err := NewPassiveConsensusModule( ps, iml, dsm, mrs, ci, testdata.MaxEntriesPerAppendEntry, testdata.ElectionTimeoutLow, now, ) if err != nil { t.Fatal(err) } if cm == nil { t.Fatal() } // Bias simulated clock to avoid exact time matches now = now.Add(testdata.SleepToLetGoroutineRun) mcm := &managedConsensusModule{cm, now, iml, dsm} return mcm, mrs }
func TestFindNewerCommitIndex_Figure8_CaseCAndE(t *testing.T) { ci, err := config.NewClusterInfo([]ServerId{"s1", "s2", "s3", "s4", "s5"}, "s1") if err != nil { t.Fatal(err) } // Figure 8, case (c) terms := []TermNo{1, 2, 4} // leader line for the case imle := log.TestUtil_NewInMemoryLog_WithTerms(terms) lvs, err := consensus_state.NewLeaderVolatileState(ci, LogIndex(len(terms))) if err != nil { t.Fatal(err) } _findNewerCommitIndex := func(currentTerm TermNo, commitIndex LogIndex) LogIndex { nci, err := consensus_state.FindNewerCommitIndex(ci, lvs, imle, currentTerm, commitIndex) if err != nil { t.Fatal(err) } return nci } // With matchIndex stuck at 0, there is no solution for any currentTerm if _findNewerCommitIndex(1, 0) != 0 { t.Fatal() } if _findNewerCommitIndex(2, 0) != 0 { t.Fatal() } if _findNewerCommitIndex(3, 0) != 0 { t.Fatal() } // match peers for Figure 8, case (c) err = lvs.SetMatchIndexAndNextIndex("s2", 2) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s3", 2) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s4", 1) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s5", 1) if err != nil { t.Fatal(err) } // While we cannot be at currentTerm=1, it has solutions if _findNewerCommitIndex(1, 0) != 1 { t.Fatal() } if _findNewerCommitIndex(1, 1) != 0 { t.Fatal() } // While we cannot be at currentTerm=2, it has solutions if _findNewerCommitIndex(2, 0) != 2 { t.Fatal() } if _findNewerCommitIndex(2, 1) != 2 { t.Fatal() } // While we cannot be at currentTerm=3, it has no solution if _findNewerCommitIndex(3, 0) != 0 { t.Fatal() } if _findNewerCommitIndex(3, 1) != 0 { t.Fatal() } if _findNewerCommitIndex(3, 2) != 0 { t.Fatal() } // No solution for currentTerm >= 4 if _findNewerCommitIndex(4, 0) != 0 { t.Fatal() } if _findNewerCommitIndex(4, 1) != 0 { t.Fatal() } if _findNewerCommitIndex(4, 2) != 0 { t.Fatal() } // match peers for Figure 8, case (e) err = lvs.SetMatchIndexAndNextIndex("s2", 3) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s3", 3) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s4", 1) if err != nil { t.Fatal(err) } err = lvs.SetMatchIndexAndNextIndex("s5", 1) if err != nil { t.Fatal(err) } // Now currentTerm = 4 has a solution if _findNewerCommitIndex(4, 0) != 3 { t.Fatal() } if _findNewerCommitIndex(4, 1) != 3 { t.Fatal() } if _findNewerCommitIndex(4, 2) != 3 { t.Fatal() } if _findNewerCommitIndex(4, 3) != 0 { t.Fatal() } }