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.

115 lines
2.9 KiB

p2p: PeerBehaviour implementation (#3539) (#3552) * p2p: initial implementation of peer behaviour * [p2p] re-use newMockPeer * p2p: add inline docs for peer_behaviour interface * [p2p] Align PeerBehaviour interface (#3558) * [p2p] make switchedPeerHebaviour private * [p2p] make storePeerHebaviour private * [p2p] Add CHANGELOG_PENDING entry for PeerBehaviour * [p2p] Adjustment naming for PeerBehaviour * [p2p] Add coarse lock around storedPeerBehaviour * [p2p]: Fix non-pointer methods in storedPeerBehaviour + Structs with embeded locks must specify all methods with pointer receivers to avoid creating a copy of the embeded lock. * [p2p] Thorough refactoring based on comments in #3552 + Decouple PeerBehaviour interface from Peer by parametrizing methods with `p2p.ID` instead of `p2p.Peer` + Setter methods wrapped in a write lock + Getter methods wrapped in a read lock + Getter methods on storedPeerBehaviour now take a `p2p.ID` + Getter methods return a copy of underlying stored behaviours + Add doc strings to public types and methods * [p2p] make structs public * [p2p] Test empty StoredPeerBehaviour * [p2p] typo fix * [p2p] add TestStoredPeerBehaviourConcurrency + Add a test which uses StoredPeerBehaviour in multiple goroutines to ensure thread-safety. * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour_test.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * Update p2p/peer_behaviour.go Co-Authored-By: brapse <brapse@gmail.com> * [p2p] field ordering convention * p2p: peer behaviour refactor + Change naming of reporting behaviour to `Report` + Remove the responsibility of distinguishing between the categories of good and bad behaviour and instead focus on reporting behaviour. * p2p: rename PeerReporter -> PeerBehaviourReporter
6 years ago
  1. package p2p
  2. import (
  3. "net"
  4. "sync"
  5. "testing"
  6. )
  7. // TestMockPeerBehaviour tests the MockPeerBehaviour' ability to store reported
  8. // peer behaviour in memory indexed by the peerID
  9. func TestMockPeerBehaviourReporter(t *testing.T) {
  10. peer := newMockPeer(net.IP{127, 0, 0, 1})
  11. pr := NewMockPeerBehaviourReporter()
  12. behaviours := pr.GetBehaviours(peer.ID())
  13. if len(behaviours) != 0 {
  14. t.Errorf("Expected to have no behaviours reported")
  15. }
  16. pr.Report(peer.ID(), PeerBehaviourBadMessage)
  17. behaviours = pr.GetBehaviours(peer.ID())
  18. if len(behaviours) != 1 {
  19. t.Errorf("Expected the peer have one reported behaviour")
  20. }
  21. if behaviours[0] != PeerBehaviourBadMessage {
  22. t.Errorf("Expected PeerBehaviourBadMessage to have been reported")
  23. }
  24. }
  25. type scriptedBehaviours struct {
  26. PeerID ID
  27. Behaviours []PeerBehaviour
  28. }
  29. type scriptItem struct {
  30. PeerID ID
  31. Behaviour PeerBehaviour
  32. }
  33. func equalBehaviours(a []PeerBehaviour, b []PeerBehaviour) bool {
  34. if len(a) != len(b) {
  35. return false
  36. }
  37. same := make([]PeerBehaviour, len(a))
  38. for i, aBehaviour := range a {
  39. for _, bBehaviour := range b {
  40. if aBehaviour == bBehaviour {
  41. same[i] = aBehaviour
  42. }
  43. }
  44. }
  45. return len(same) == len(a)
  46. }
  47. // TestPeerBehaviourConcurrency constructs a scenario in which
  48. // multiple goroutines are using the same MockPeerBehaviourReporter instance.
  49. // This test reproduces the conditions in which MockPeerBehaviourReporter will
  50. // be used within a Reactor Receive method tests to ensure thread safety.
  51. func TestMockPeerBehaviourReporterConcurrency(t *testing.T) {
  52. behaviourScript := []scriptedBehaviours{
  53. {"1", []PeerBehaviour{PeerBehaviourVote}},
  54. {"2", []PeerBehaviour{PeerBehaviourVote, PeerBehaviourVote, PeerBehaviourVote, PeerBehaviourVote}},
  55. {"3", []PeerBehaviour{PeerBehaviourBlockPart, PeerBehaviourVote, PeerBehaviourBlockPart, PeerBehaviourVote}},
  56. {"4", []PeerBehaviour{PeerBehaviourVote, PeerBehaviourVote, PeerBehaviourVote, PeerBehaviourVote}},
  57. {"5", []PeerBehaviour{PeerBehaviourBlockPart, PeerBehaviourVote, PeerBehaviourBlockPart, PeerBehaviourVote}},
  58. }
  59. var receiveWg sync.WaitGroup
  60. pr := NewMockPeerBehaviourReporter()
  61. scriptItems := make(chan scriptItem)
  62. done := make(chan int)
  63. numConsumers := 3
  64. for i := 0; i < numConsumers; i++ {
  65. receiveWg.Add(1)
  66. go func() {
  67. defer receiveWg.Done()
  68. for {
  69. select {
  70. case pb := <-scriptItems:
  71. pr.Report(pb.PeerID, pb.Behaviour)
  72. case <-done:
  73. return
  74. }
  75. }
  76. }()
  77. }
  78. var sendingWg sync.WaitGroup
  79. sendingWg.Add(1)
  80. go func() {
  81. defer sendingWg.Done()
  82. for _, item := range behaviourScript {
  83. for _, reason := range item.Behaviours {
  84. scriptItems <- scriptItem{item.PeerID, reason}
  85. }
  86. }
  87. }()
  88. sendingWg.Wait()
  89. for i := 0; i < numConsumers; i++ {
  90. done <- 1
  91. }
  92. receiveWg.Wait()
  93. for _, items := range behaviourScript {
  94. if !equalBehaviours(pr.GetBehaviours(items.PeerID), items.Behaviours) {
  95. t.Errorf("Expected peer %s to have behaved \n", items.PeerID)
  96. }
  97. }
  98. }