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.

186 lines
5.1 KiB

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