| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- package raft
- import (
- "reflect"
- "testing"
- )
- // TestBuildCluster ensures cluster with various size could be built.
- func TestBuildCluster(t *testing.T) {
- tests := []struct {
- size int
- ids []int64
- }{
- {1, nil},
- {3, nil},
- {5, nil},
- {7, nil},
- {9, nil},
- {13, nil},
- {51, nil},
- {1, []int64{1}},
- {3, []int64{1, 3, 5}},
- {5, []int64{1, 4, 7, 10, 13}},
- }
- for i, tt := range tests {
- _, nodes := buildCluster(tt.size, tt.ids)
- base := ltoa(nodes[0].sm.raftLog)
- for j, n := range nodes {
- // ensure same log
- l := ltoa(n.sm.raftLog)
- if g := diffu(base, l); g != "" {
- t.Errorf("#%d.%d: log diff:\n%s", i, j, g)
- }
- // ensure same leader
- var w int64
- if tt.ids != nil {
- w = tt.ids[0]
- }
- if g := n.sm.lead.Get(); g != w {
- t.Errorf("#%d.%d: lead = %d, want %d", i, j, g, w)
- }
- // ensure same peer map
- p := map[int64]struct{}{}
- for k := range n.sm.ins {
- p[k] = struct{}{}
- }
- wp := map[int64]struct{}{}
- for k := 0; k < tt.size; k++ {
- if tt.ids != nil {
- wp[tt.ids[k]] = struct{}{}
- } else {
- wp[int64(k)] = struct{}{}
- }
- }
- if !reflect.DeepEqual(p, wp) {
- t.Errorf("#%d.%d: peers = %+v, want %+v", i, j, p, wp)
- }
- }
- }
- }
- func TestInitCluster(t *testing.T) {
- node := New(1, defaultHeartbeat, defaultElection)
- dictate(node)
- node.Next()
- if node.ClusterId() != 0xBEEF {
- t.Errorf("clusterId = %x, want %x", node.ClusterId(), 0xBEEF)
- }
- func() {
- defer func() {
- e := recover()
- if e != "cannot init a started cluster" {
- t.Errorf("err = %v, want cannot init a started cluster", e)
- }
- }()
- node.InitCluster(0xFBEE)
- node.Next()
- }()
- }
- func TestMessageFromDifferentCluster(t *testing.T) {
- tests := []struct {
- clusterId int64
- wType messageType
- }{
- {0xBEEF, msgVoteResp},
- {0xFBEE, msgDenied},
- }
- for i, tt := range tests {
- node := New(1, defaultHeartbeat, defaultElection)
- dictate(node)
- node.Next()
- node.Step(Message{From: 1, ClusterId: tt.clusterId, Type: msgVote, Term: 2, LogTerm: 2, Index: 2})
- msgs := node.Msgs()
- if len(msgs) != 1 {
- t.Errorf("#%d: len(msgs) = %d, want 1", i, len(msgs))
- }
- if msgs[0].Type != tt.wType {
- t.Errorf("#%d: msg.Type = %v, want %d", i, msgs[0].Type, tt.wType)
- }
- }
- }
- // TestBasicCluster ensures all nodes can send proposal to the cluster.
- // And all the proposals will get committed.
- func TestBasicCluster(t *testing.T) {
- tests := []struct {
- size int
- round int
- }{
- {1, 3},
- {3, 3},
- {5, 3},
- {7, 3},
- {13, 1},
- }
- for i, tt := range tests {
- nt, nodes := buildCluster(tt.size, nil)
- for j := 0; j < tt.round; j++ {
- for _, n := range nodes {
- data := []byte{byte(n.Id())}
- nt.send(Message{From: n.Id(), To: n.Id(), ClusterId: n.ClusterId(), Type: msgProp, Entries: []Entry{{Data: data}}})
- base := nodes[0].Next()
- if len(base) != 1 {
- t.Fatalf("#%d: len(ents) = %d, want 1", i, len(base))
- }
- if !reflect.DeepEqual(base[0].Data, data) {
- t.Errorf("#%d: data = %s, want %s", i, base[0].Data, data)
- }
- for k := 1; k < tt.size; k++ {
- g := nodes[k].Next()
- if !reflect.DeepEqual(g, base) {
- t.Errorf("#%d.%d: ent = %v, want %v", i, k, g, base)
- }
- }
- }
- }
- }
- }
- // This function is full of heck now. It will go away when we finish our
- // network Interface, and ticker infrastructure.
- func buildCluster(size int, ids []int64) (nt *network, nodes []*Node) {
- if ids == nil {
- ids = make([]int64, size)
- for i := 0; i < size; i++ {
- ids[i] = int64(i)
- }
- }
- nodes = make([]*Node, size)
- nis := make([]Interface, size)
- for i := range nodes {
- nodes[i] = New(ids[i], defaultHeartbeat, defaultElection)
- nis[i] = nodes[i]
- }
- nt = newNetwork(nis...)
- lead := dictate(nodes[0])
- lead.Next()
- for i := 1; i < size; i++ {
- lead.Add(ids[i], "", nil)
- nt.send(lead.Msgs()...)
- for j := 0; j < i; j++ {
- nodes[j].Next()
- }
- }
- for i := 0; i < 10*defaultHeartbeat; i++ {
- nodes[0].Tick()
- }
- msgs := nodes[0].Msgs()
- nt.send(msgs...)
- for _, n := range nodes {
- n.Next()
- }
- return
- }
|