- package p2p_test
-
- import (
- "sync"
- "testing"
-
- "github.com/tendermint/tendermint/p2p"
- )
-
- // TestMockPeerBehaviour tests the MockPeerBehaviour' ability to store reported
- // peer behaviour in memory indexed by the peerID
- func TestMockPeerBehaviourReporter(t *testing.T) {
- var peerID p2p.ID = "MockPeer"
- pr := p2p.NewMockPeerBehaviourReporter()
-
- behaviours := pr.GetBehaviours(peerID)
- if len(behaviours) != 0 {
- t.Error("Expected to have no behaviours reported")
- }
-
- pr.Report(peerID, p2p.PeerBehaviourBadMessage)
- behaviours = pr.GetBehaviours(peerID)
- if len(behaviours) != 1 {
- t.Error("Expected the peer have one reported behaviour")
- }
-
- if behaviours[0] != p2p.PeerBehaviourBadMessage {
- t.Error("Expected PeerBehaviourBadMessage to have been reported")
- }
- }
-
- type scriptedBehaviours struct {
- PeerID p2p.ID
- Behaviours []p2p.PeerBehaviour
- }
-
- type scriptItem struct {
- PeerID p2p.ID
- Behaviour p2p.PeerBehaviour
- }
-
- // equalBehaviours returns true if a and b contain the same PeerBehaviours with
- // the same freequency and otherwise false.
- func equalBehaviours(a []p2p.PeerBehaviour, b []p2p.PeerBehaviour) bool {
- aHistogram := map[p2p.PeerBehaviour]int{}
- bHistogram := map[p2p.PeerBehaviour]int{}
-
- for _, behaviour := range a {
- aHistogram[behaviour] += 1
- }
-
- for _, behaviour := range b {
- bHistogram[behaviour] += 1
- }
-
- if len(aHistogram) != len(bHistogram) {
- return false
- }
-
- for _, behaviour := range a {
- if aHistogram[behaviour] != bHistogram[behaviour] {
- return false
- }
- }
-
- for _, behaviour := range b {
- if bHistogram[behaviour] != aHistogram[behaviour] {
- return false
- }
- }
-
- return true
- }
-
- // TestEqualPeerBehaviours tests that equalBehaviours can tell that two slices
- // of peer behaviours can be compared for the behaviours they contain and the
- // freequencies that those behaviours occur.
- func TestEqualPeerBehaviours(t *testing.T) {
- equals := []struct {
- left []p2p.PeerBehaviour
- right []p2p.PeerBehaviour
- }{
- // Empty sets
- {[]p2p.PeerBehaviour{}, []p2p.PeerBehaviour{}},
- // Single behaviours
- {[]p2p.PeerBehaviour{p2p.PeerBehaviourVote}, []p2p.PeerBehaviour{p2p.PeerBehaviourVote}},
- // Equal Frequencies
- {[]p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourVote},
- []p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourVote}},
- // Equal frequencies different orders
- {[]p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourBlockPart},
- []p2p.PeerBehaviour{p2p.PeerBehaviourBlockPart, p2p.PeerBehaviourVote}},
- }
-
- for _, test := range equals {
- if !equalBehaviours(test.left, test.right) {
- t.Errorf("Expected %#v and %#v to be equal", test.left, test.right)
- }
- }
-
- unequals := []struct {
- left []p2p.PeerBehaviour
- right []p2p.PeerBehaviour
- }{
- // Comparing empty sets to non empty sets
- {[]p2p.PeerBehaviour{}, []p2p.PeerBehaviour{p2p.PeerBehaviourVote}},
- // Different behaviours
- {[]p2p.PeerBehaviour{p2p.PeerBehaviourVote}, []p2p.PeerBehaviour{p2p.PeerBehaviourBlockPart}},
- // Same behaviour with different frequencies
- {[]p2p.PeerBehaviour{p2p.PeerBehaviourVote},
- []p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourVote}},
- }
-
- for _, test := range unequals {
- if equalBehaviours(test.left, test.right) {
- t.Errorf("Expected %#v and %#v to be unequal", test.left, test.right)
- }
- }
- }
-
- // TestPeerBehaviourConcurrency constructs a scenario in which
- // multiple goroutines are using the same MockPeerBehaviourReporter instance.
- // This test reproduces the conditions in which MockPeerBehaviourReporter will
- // be used within a Reactor Receive method tests to ensure thread safety.
- func TestMockPeerBehaviourReporterConcurrency(t *testing.T) {
- behaviourScript := []scriptedBehaviours{
- {"1", []p2p.PeerBehaviour{p2p.PeerBehaviourVote}},
- {"2", []p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourVote, p2p.PeerBehaviourVote, p2p.PeerBehaviourVote}},
- {"3", []p2p.PeerBehaviour{p2p.PeerBehaviourBlockPart, p2p.PeerBehaviourVote, p2p.PeerBehaviourBlockPart, p2p.PeerBehaviourVote}},
- {"4", []p2p.PeerBehaviour{p2p.PeerBehaviourVote, p2p.PeerBehaviourVote, p2p.PeerBehaviourVote, p2p.PeerBehaviourVote}},
- {"5", []p2p.PeerBehaviour{p2p.PeerBehaviourBlockPart, p2p.PeerBehaviourVote, p2p.PeerBehaviourBlockPart, p2p.PeerBehaviourVote}},
- }
-
- var receiveWg sync.WaitGroup
- pr := p2p.NewMockPeerBehaviourReporter()
- scriptItems := make(chan scriptItem)
- done := make(chan int)
- numConsumers := 3
- for i := 0; i < numConsumers; i++ {
- receiveWg.Add(1)
- go func() {
- defer receiveWg.Done()
- for {
- select {
- case pb := <-scriptItems:
- pr.Report(pb.PeerID, pb.Behaviour)
- case <-done:
- return
- }
- }
- }()
- }
-
- var sendingWg sync.WaitGroup
- sendingWg.Add(1)
- go func() {
- defer sendingWg.Done()
- for _, item := range behaviourScript {
- for _, reason := range item.Behaviours {
- scriptItems <- scriptItem{item.PeerID, reason}
- }
- }
- }()
-
- sendingWg.Wait()
-
- for i := 0; i < numConsumers; i++ {
- done <- 1
- }
-
- receiveWg.Wait()
-
- for _, items := range behaviourScript {
- reported := pr.GetBehaviours(items.PeerID)
- if !equalBehaviours(reported, items.Behaviours) {
- t.Errorf("Expected peer %s to have behaved \nExpected: %#v \nGot %#v \n",
- items.PeerID, items.Behaviours, reported)
- }
- }
- }
|