func TestCandidateToLeader(t *testing.T) { log.SetOutput(&bytes.Buffer{}) defer log.SetOutput(os.Stdout) oldMin, oldMax := raft.ResetElectionTimeoutMs(25, 50) defer raft.ResetElectionTimeoutMs(oldMin, oldMax) noop := func([]byte) ([]byte, error) { return []byte{}, nil } server := raft.NewServer(1, &bytes.Buffer{}, noop) server.SetPeers(raft.MakePeers(nonresponsivePeer(1), approvingPeer(2), nonresponsivePeer(3))) server.Start() defer func() { server.Stop(); t.Logf("server stopped") }() time.Sleep(raft.MaximumElectionTimeout()) cutoff := time.Now().Add(2 * raft.MaximumElectionTimeout()) backoff := raft.BroadcastInterval() for { if time.Now().After(cutoff) { t.Fatal("failed to become Leader") } if state := server.State(); state != raft.Leader { time.Sleep(backoff) backoff *= 2 continue } t.Logf("became Leader") break } }
func TestFailedElection(t *testing.T) { log.SetOutput(&bytes.Buffer{}) defer log.SetOutput(os.Stdout) oldMin, oldMax := raft.ResetElectionTimeoutMs(25, 50) defer raft.ResetElectionTimeoutMs(oldMin, oldMax) noop := func([]byte) ([]byte, error) { return []byte{}, nil } server := raft.NewServer(1, &bytes.Buffer{}, noop) server.SetPeers(raft.MakePeers(disapprovingPeer(2), nonresponsivePeer(3))) server.Start() defer func() { server.Stop(); t.Logf("server stopped") }() time.Sleep(2 * raft.ElectionTimeout()) if server.State() == raft.Leader { t.Fatalf("erroneously became Leader") } t.Logf("remained %s", server.State()) }
func TestSimpleConsensus(t *testing.T) { logBuffer := &bytes.Buffer{} log.SetOutput(logBuffer) defer log.SetOutput(os.Stdout) defer printOnFailure(t, logBuffer) oldMin, oldMax := raft.ResetElectionTimeoutMs(25, 50) defer raft.ResetElectionTimeoutMs(oldMin, oldMax) type SetValue struct { Value int32 `json:"value"` } var i1, i2, i3 int32 applyValue := func(id uint64, i *int32) func([]byte) ([]byte, error) { return func(cmd []byte) ([]byte, error) { var sv SetValue if err := json.Unmarshal(cmd, &sv); err != nil { return []byte{}, err } atomic.StoreInt32(i, sv.Value) return json.Marshal(map[string]interface{}{"applied_to_server": id, "applied_value": sv.Value}) } } s1 := raft.NewServer(1, &bytes.Buffer{}, applyValue(1, &i1)) s2 := raft.NewServer(2, &bytes.Buffer{}, applyValue(2, &i2)) s3 := raft.NewServer(3, &bytes.Buffer{}, applyValue(3, &i3)) s1Responses := &synchronizedBuffer{} s2Responses := &synchronizedBuffer{} s3Responses := &synchronizedBuffer{} defer func(sb *synchronizedBuffer) { t.Logf("s1 responses: %s", sb.String()) }(s1Responses) defer func(sb *synchronizedBuffer) { t.Logf("s2 responses: %s", sb.String()) }(s2Responses) defer func(sb *synchronizedBuffer) { t.Logf("s3 responses: %s", sb.String()) }(s3Responses) peers := raft.MakePeers( raft.NewLocalPeer(s1), raft.NewLocalPeer(s2), raft.NewLocalPeer(s3), ) s1.SetPeers(peers) s2.SetPeers(peers) s3.SetPeers(peers) s1.Start() s2.Start() s3.Start() defer s1.Stop() defer s2.Stop() defer s3.Stop() var v int32 = 42 cmd, _ := json.Marshal(SetValue{v}) response := make(chan []byte, 1) func() { for { switch err := s1.Command(cmd, response); err { case nil: return case raft.ErrUnknownLeader: time.Sleep(raft.MinimumElectionTimeout()) default: t.Fatal(err) } } }() r, ok := <-response if ok { s1Responses.Write(r) } else { t.Logf("didn't receive command response") } ticker := time.Tick(raft.BroadcastInterval()) timeout := time.After(1 * time.Second) for { select { case <-ticker: i1l := atomic.LoadInt32(&i1) i2l := atomic.LoadInt32(&i2) i3l := atomic.LoadInt32(&i3) t.Logf("i1=%02d i2=%02d i3=%02d", i1l, i2l, i3l) if i1l == v && i2l == v && i3l == v { t.Logf("success!") return } case <-timeout: t.Fatal("timeout") } } }