You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
5.2 KiB

  1. package behavior_test
  2. import (
  3. "sync"
  4. "testing"
  5. bh "github.com/tendermint/tendermint/blockchain/v2/internal/behavior"
  6. "github.com/tendermint/tendermint/p2p"
  7. )
  8. // TestMockReporter tests the MockReporter's ability to store reported
  9. // peer behavior in memory indexed by the peerID.
  10. func TestMockReporter(t *testing.T) {
  11. var peerID p2p.NodeID = "MockPeer"
  12. pr := bh.NewMockReporter()
  13. behaviors := pr.GetBehaviors(peerID)
  14. if len(behaviors) != 0 {
  15. t.Error("Expected to have no behaviors reported")
  16. }
  17. badMessage := bh.BadMessage(peerID, "bad message")
  18. if err := pr.Report(badMessage); err != nil {
  19. t.Error(err)
  20. }
  21. behaviors = pr.GetBehaviors(peerID)
  22. if len(behaviors) != 1 {
  23. t.Error("Expected the peer have one reported behavior")
  24. }
  25. if behaviors[0] != badMessage {
  26. t.Error("Expected Bad Message to have been reported")
  27. }
  28. }
  29. type scriptItem struct {
  30. peerID p2p.NodeID
  31. behavior bh.PeerBehavior
  32. }
  33. // equalBehaviors returns true if a and b contain the same PeerBehaviors with
  34. // the same freequencies and otherwise false.
  35. func equalBehaviors(a []bh.PeerBehavior, b []bh.PeerBehavior) bool {
  36. aHistogram := map[bh.PeerBehavior]int{}
  37. bHistogram := map[bh.PeerBehavior]int{}
  38. for _, behavior := range a {
  39. aHistogram[behavior]++
  40. }
  41. for _, behavior := range b {
  42. bHistogram[behavior]++
  43. }
  44. if len(aHistogram) != len(bHistogram) {
  45. return false
  46. }
  47. for _, behavior := range a {
  48. if aHistogram[behavior] != bHistogram[behavior] {
  49. return false
  50. }
  51. }
  52. for _, behavior := range b {
  53. if bHistogram[behavior] != aHistogram[behavior] {
  54. return false
  55. }
  56. }
  57. return true
  58. }
  59. // TestEqualPeerBehaviors tests that equalBehaviors can tell that two slices
  60. // of peer behaviors can be compared for the behaviors they contain and the
  61. // freequencies that those behaviors occur.
  62. func TestEqualPeerBehaviors(t *testing.T) {
  63. var (
  64. peerID p2p.NodeID = "MockPeer"
  65. consensusVote = bh.ConsensusVote(peerID, "voted")
  66. blockPart = bh.BlockPart(peerID, "blocked")
  67. equals = []struct {
  68. left []bh.PeerBehavior
  69. right []bh.PeerBehavior
  70. }{
  71. // Empty sets
  72. {[]bh.PeerBehavior{}, []bh.PeerBehavior{}},
  73. // Single behaviors
  74. {[]bh.PeerBehavior{consensusVote}, []bh.PeerBehavior{consensusVote}},
  75. // Equal Frequencies
  76. {[]bh.PeerBehavior{consensusVote, consensusVote},
  77. []bh.PeerBehavior{consensusVote, consensusVote}},
  78. // Equal frequencies different orders
  79. {[]bh.PeerBehavior{consensusVote, blockPart},
  80. []bh.PeerBehavior{blockPart, consensusVote}},
  81. }
  82. unequals = []struct {
  83. left []bh.PeerBehavior
  84. right []bh.PeerBehavior
  85. }{
  86. // Comparing empty sets to non empty sets
  87. {[]bh.PeerBehavior{}, []bh.PeerBehavior{consensusVote}},
  88. // Different behaviors
  89. {[]bh.PeerBehavior{consensusVote}, []bh.PeerBehavior{blockPart}},
  90. // Same behavior with different frequencies
  91. {[]bh.PeerBehavior{consensusVote},
  92. []bh.PeerBehavior{consensusVote, consensusVote}},
  93. }
  94. )
  95. for _, test := range equals {
  96. if !equalBehaviors(test.left, test.right) {
  97. t.Errorf("expected %#v and %#v to be equal", test.left, test.right)
  98. }
  99. }
  100. for _, test := range unequals {
  101. if equalBehaviors(test.left, test.right) {
  102. t.Errorf("expected %#v and %#v to be unequal", test.left, test.right)
  103. }
  104. }
  105. }
  106. // TestPeerBehaviorConcurrency constructs a scenario in which
  107. // multiple goroutines are using the same MockReporter instance.
  108. // This test reproduces the conditions in which MockReporter will
  109. // be used within a Reactor `Receive` method tests to ensure thread safety.
  110. func TestMockPeerBehaviorReporterConcurrency(t *testing.T) {
  111. var (
  112. behaviorScript = []struct {
  113. peerID p2p.NodeID
  114. behaviors []bh.PeerBehavior
  115. }{
  116. {"1", []bh.PeerBehavior{bh.ConsensusVote("1", "")}},
  117. {"2", []bh.PeerBehavior{bh.ConsensusVote("2", ""), bh.ConsensusVote("2", ""), bh.ConsensusVote("2", "")}},
  118. {
  119. "3",
  120. []bh.PeerBehavior{bh.BlockPart("3", ""),
  121. bh.ConsensusVote("3", ""),
  122. bh.BlockPart("3", ""),
  123. bh.ConsensusVote("3", "")}},
  124. {
  125. "4",
  126. []bh.PeerBehavior{bh.ConsensusVote("4", ""),
  127. bh.ConsensusVote("4", ""),
  128. bh.ConsensusVote("4", ""),
  129. bh.ConsensusVote("4", "")}},
  130. {
  131. "5",
  132. []bh.PeerBehavior{bh.BlockPart("5", ""),
  133. bh.ConsensusVote("5", ""),
  134. bh.BlockPart("5", ""),
  135. bh.ConsensusVote("5", "")}},
  136. }
  137. )
  138. var receiveWg sync.WaitGroup
  139. pr := bh.NewMockReporter()
  140. scriptItems := make(chan scriptItem)
  141. done := make(chan int)
  142. numConsumers := 3
  143. for i := 0; i < numConsumers; i++ {
  144. receiveWg.Add(1)
  145. go func() {
  146. defer receiveWg.Done()
  147. for {
  148. select {
  149. case pb := <-scriptItems:
  150. if err := pr.Report(pb.behavior); err != nil {
  151. t.Error(err)
  152. }
  153. case <-done:
  154. return
  155. }
  156. }
  157. }()
  158. }
  159. var sendingWg sync.WaitGroup
  160. sendingWg.Add(1)
  161. go func() {
  162. defer sendingWg.Done()
  163. for _, item := range behaviorScript {
  164. for _, reason := range item.behaviors {
  165. scriptItems <- scriptItem{item.peerID, reason}
  166. }
  167. }
  168. }()
  169. sendingWg.Wait()
  170. for i := 0; i < numConsumers; i++ {
  171. done <- 1
  172. }
  173. receiveWg.Wait()
  174. for _, items := range behaviorScript {
  175. reported := pr.GetBehaviors(items.peerID)
  176. if !equalBehaviors(reported, items.behaviors) {
  177. t.Errorf("expected peer %s to have behaved \nExpected: %#v \nGot %#v \n",
  178. items.peerID, items.behaviors, reported)
  179. }
  180. }
  181. }