cluster_test.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package raft
  2. import (
  3. "reflect"
  4. "testing"
  5. )
  6. // TestBuildCluster ensures cluster with various size could be built.
  7. func TestBuildCluster(t *testing.T) {
  8. tests := []struct {
  9. size int
  10. ids []int64
  11. }{
  12. {1, nil},
  13. {3, nil},
  14. {5, nil},
  15. {7, nil},
  16. {9, nil},
  17. {13, nil},
  18. {51, nil},
  19. {1, []int64{1}},
  20. {3, []int64{1, 3, 5}},
  21. {5, []int64{1, 4, 7, 10, 13}},
  22. }
  23. for i, tt := range tests {
  24. _, nodes := buildCluster(tt.size, tt.ids)
  25. base := ltoa(nodes[0].sm.raftLog)
  26. for j, n := range nodes {
  27. // ensure same log
  28. l := ltoa(n.sm.raftLog)
  29. if g := diffu(base, l); g != "" {
  30. t.Errorf("#%d.%d: log diff:\n%s", i, j, g)
  31. }
  32. // ensure same leader
  33. var w int64
  34. if tt.ids != nil {
  35. w = tt.ids[0]
  36. }
  37. if g := n.sm.lead.Get(); g != w {
  38. t.Errorf("#%d.%d: lead = %d, want %d", i, j, g, w)
  39. }
  40. // ensure same peer map
  41. p := map[int64]struct{}{}
  42. for k := range n.sm.ins {
  43. p[k] = struct{}{}
  44. }
  45. wp := map[int64]struct{}{}
  46. for k := 0; k < tt.size; k++ {
  47. if tt.ids != nil {
  48. wp[tt.ids[k]] = struct{}{}
  49. } else {
  50. wp[int64(k)] = struct{}{}
  51. }
  52. }
  53. if !reflect.DeepEqual(p, wp) {
  54. t.Errorf("#%d.%d: peers = %+v, want %+v", i, j, p, wp)
  55. }
  56. }
  57. }
  58. }
  59. func TestInitCluster(t *testing.T) {
  60. node := New(1, defaultHeartbeat, defaultElection)
  61. dictate(node)
  62. node.Next()
  63. if node.ClusterId() != 0xBEEF {
  64. t.Errorf("clusterId = %x, want %x", node.ClusterId(), 0xBEEF)
  65. }
  66. func() {
  67. defer func() {
  68. e := recover()
  69. if e != "cannot init a started cluster" {
  70. t.Errorf("err = %v, want cannot init a started cluster", e)
  71. }
  72. }()
  73. node.InitCluster(0xFBEE)
  74. node.Next()
  75. }()
  76. }
  77. func TestMessageFromDifferentCluster(t *testing.T) {
  78. tests := []struct {
  79. clusterId int64
  80. wType messageType
  81. }{
  82. {0xBEEF, msgVoteResp},
  83. {0xFBEE, msgDenied},
  84. }
  85. for i, tt := range tests {
  86. node := New(1, defaultHeartbeat, defaultElection)
  87. dictate(node)
  88. node.Next()
  89. node.Step(Message{From: 1, ClusterId: tt.clusterId, Type: msgVote, Term: 2, LogTerm: 2, Index: 2})
  90. msgs := node.Msgs()
  91. if len(msgs) != 1 {
  92. t.Errorf("#%d: len(msgs) = %d, want 1", i, len(msgs))
  93. }
  94. if msgs[0].Type != tt.wType {
  95. t.Errorf("#%d: msg.Type = %v, want %d", i, msgs[0].Type, tt.wType)
  96. }
  97. }
  98. }
  99. // TestBasicCluster ensures all nodes can send proposal to the cluster.
  100. // And all the proposals will get committed.
  101. func TestBasicCluster(t *testing.T) {
  102. tests := []struct {
  103. size int
  104. round int
  105. }{
  106. {1, 3},
  107. {3, 3},
  108. {5, 3},
  109. {7, 3},
  110. {13, 1},
  111. }
  112. for i, tt := range tests {
  113. nt, nodes := buildCluster(tt.size, nil)
  114. for j := 0; j < tt.round; j++ {
  115. for _, n := range nodes {
  116. data := []byte{byte(n.Id())}
  117. nt.send(Message{From: n.Id(), To: n.Id(), ClusterId: n.ClusterId(), Type: msgProp, Entries: []Entry{{Data: data}}})
  118. base := nodes[0].Next()
  119. if len(base) != 1 {
  120. t.Fatalf("#%d: len(ents) = %d, want 1", i, len(base))
  121. }
  122. if !reflect.DeepEqual(base[0].Data, data) {
  123. t.Errorf("#%d: data = %s, want %s", i, base[0].Data, data)
  124. }
  125. for k := 1; k < tt.size; k++ {
  126. g := nodes[k].Next()
  127. if !reflect.DeepEqual(g, base) {
  128. t.Errorf("#%d.%d: ent = %v, want %v", i, k, g, base)
  129. }
  130. }
  131. }
  132. }
  133. }
  134. }
  135. // This function is full of heck now. It will go away when we finish our
  136. // network Interface, and ticker infrastructure.
  137. func buildCluster(size int, ids []int64) (nt *network, nodes []*Node) {
  138. if ids == nil {
  139. ids = make([]int64, size)
  140. for i := 0; i < size; i++ {
  141. ids[i] = int64(i)
  142. }
  143. }
  144. nodes = make([]*Node, size)
  145. nis := make([]Interface, size)
  146. for i := range nodes {
  147. nodes[i] = New(ids[i], defaultHeartbeat, defaultElection)
  148. nis[i] = nodes[i]
  149. }
  150. nt = newNetwork(nis...)
  151. lead := dictate(nodes[0])
  152. lead.Next()
  153. for i := 1; i < size; i++ {
  154. lead.Add(ids[i], "", nil)
  155. nt.send(lead.Msgs()...)
  156. for j := 0; j < i; j++ {
  157. nodes[j].Next()
  158. }
  159. }
  160. for i := 0; i < 10*defaultHeartbeat; i++ {
  161. nodes[0].Tick()
  162. }
  163. msgs := nodes[0].Msgs()
  164. nt.send(msgs...)
  165. for _, n := range nodes {
  166. n.Next()
  167. }
  168. return
  169. }