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  }