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