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