node_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package raft
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. "github.com/coreos/etcd/raft/raftpb"
  7. "github.com/coreos/etcd/third_party/code.google.com/p/go.net/context"
  8. )
  9. // TestNodeStep ensures that node.Step sends msgProp to propc chan
  10. // and other kinds of messages to recvc chan.
  11. func TestNodeStep(t *testing.T) {
  12. for i := range mtmap {
  13. n := &Node{
  14. propc: make(chan raftpb.Message, 1),
  15. recvc: make(chan raftpb.Message, 1),
  16. }
  17. n.Step(context.TODO(), raftpb.Message{Type: int64(i)})
  18. // Proposal goes to proc chan. Others go to recvc chan.
  19. if int64(i) == msgProp {
  20. select {
  21. case <-n.propc:
  22. default:
  23. t.Errorf("%d: cannot receive %s on propc chan", i, mtmap[i])
  24. }
  25. } else {
  26. select {
  27. case <-n.recvc:
  28. default:
  29. t.Errorf("%d: cannot receive %s on recvc chan", i, mtmap[i])
  30. }
  31. }
  32. }
  33. }
  34. // Cancel and Stop should unblock Step()
  35. func TestNodeStepUnblock(t *testing.T) {
  36. // a node without buffer to block step
  37. n := &Node{
  38. propc: make(chan raftpb.Message),
  39. done: make(chan struct{}),
  40. }
  41. ctx, cancel := context.WithCancel(context.Background())
  42. stopFunc := func() { close(n.done) }
  43. tests := []struct {
  44. unblock func()
  45. werr error
  46. }{
  47. {stopFunc, ErrStopped},
  48. {cancel, context.Canceled},
  49. }
  50. for i, tt := range tests {
  51. errc := make(chan error, 1)
  52. go func() {
  53. err := n.Step(ctx, raftpb.Message{Type: msgProp})
  54. errc <- err
  55. }()
  56. tt.unblock()
  57. select {
  58. case err := <-errc:
  59. if err != tt.werr {
  60. t.Errorf("#%d: err = %v, want %v", err, tt.werr)
  61. }
  62. //clean up side-effect
  63. if ctx.Err() != nil {
  64. ctx = context.TODO()
  65. }
  66. select {
  67. case <-n.done:
  68. n.done = make(chan struct{})
  69. default:
  70. }
  71. case <-time.After(time.Millisecond * 100):
  72. t.Errorf("#%d: failed to unblock step", i)
  73. }
  74. }
  75. }
  76. func TestNode(t *testing.T) {
  77. ctx, cancel := context.WithCancel(context.Background())
  78. defer cancel()
  79. wants := []Ready{
  80. {
  81. State: raftpb.State{Term: 1, Vote: -1, Commit: 1, LastIndex: 1},
  82. Entries: []raftpb.Entry{{Term: 1, Index: 1}},
  83. CommittedEntries: []raftpb.Entry{{Term: 1, Index: 1}},
  84. },
  85. {
  86. State: raftpb.State{Term: 1, Vote: -1, Commit: 2, LastIndex: 2},
  87. Entries: []raftpb.Entry{{Term: 1, Index: 2, Data: []byte("foo")}},
  88. CommittedEntries: []raftpb.Entry{{Term: 1, Index: 2, Data: []byte("foo")}},
  89. },
  90. }
  91. n := Start(1, []int64{1}, 0, 0)
  92. n.Campaign(ctx)
  93. if g := <-n.Ready(); !reflect.DeepEqual(g, wants[0]) {
  94. t.Errorf("#%d: g = %+v,\n w %+v", 1, g, wants[0])
  95. }
  96. n.Propose(ctx, []byte("foo"))
  97. if g := <-n.Ready(); !reflect.DeepEqual(g, wants[1]) {
  98. t.Errorf("#%d: g = %+v,\n w %+v", 2, g, wants[1])
  99. }
  100. select {
  101. case rd := <-n.Ready():
  102. t.Errorf("unexpected Ready: %+v", rd)
  103. default:
  104. }
  105. }
  106. func TestNodeRestart(t *testing.T) {
  107. entries := []raftpb.Entry{
  108. {Term: 1, Index: 1},
  109. {Term: 1, Index: 2, Data: []byte("foo")},
  110. }
  111. st := raftpb.State{Term: 1, Vote: -1, Commit: 1, LastIndex: 2}
  112. want := Ready{
  113. State: emptyState,
  114. // commit upto index commit index in st
  115. CommittedEntries: entries[:st.Commit],
  116. }
  117. n := Restart(1, []int64{1}, 0, 0, st, entries)
  118. if g := <-n.Ready(); !reflect.DeepEqual(g, want) {
  119. t.Errorf("g = %+v,\n w %+v", g, want)
  120. }
  121. select {
  122. case rd := <-n.Ready():
  123. t.Errorf("unexpected Ready: %+v", rd)
  124. default:
  125. }
  126. }