github.com/DFWallet/tendermint-cosmos@v0.0.2/behaviour/reporter_test.go (about)

     1  package behaviour_test
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  
     7  	bh "github.com/DFWallet/tendermint-cosmos/behaviour"
     8  	"github.com/DFWallet/tendermint-cosmos/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  }