github.com/koko1123/flow-go-1@v0.29.6/engine/consensus/matching/engine_test.go (about)

     1  package matching
     2  
     3  import (
     4  	"sync"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/mock"
     9  	"github.com/stretchr/testify/require"
    10  	"github.com/stretchr/testify/suite"
    11  
    12  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
    13  	"github.com/koko1123/flow-go-1/engine"
    14  	mockconsensus "github.com/koko1123/flow-go-1/engine/consensus/mock"
    15  	"github.com/koko1123/flow-go-1/model/flow"
    16  	"github.com/koko1123/flow-go-1/module/metrics"
    17  	mockmodule "github.com/koko1123/flow-go-1/module/mock"
    18  	"github.com/koko1123/flow-go-1/network/channels"
    19  	"github.com/koko1123/flow-go-1/network/mocknetwork"
    20  	mockprotocol "github.com/koko1123/flow-go-1/state/protocol/mock"
    21  	mockstorage "github.com/koko1123/flow-go-1/storage/mock"
    22  	"github.com/koko1123/flow-go-1/utils/unittest"
    23  )
    24  
    25  func TestMatchingEngineContext(t *testing.T) {
    26  	suite.Run(t, new(MatchingEngineSuite))
    27  }
    28  
    29  type MatchingEngineSuite struct {
    30  	suite.Suite
    31  
    32  	index    *mockstorage.Index
    33  	receipts *mockstorage.ExecutionReceipts
    34  	core     *mockconsensus.MatchingCore
    35  	state    *mockprotocol.State
    36  
    37  	// Matching Engine
    38  	engine *Engine
    39  }
    40  
    41  func (s *MatchingEngineSuite) SetupTest() {
    42  	metrics := metrics.NewNoopCollector()
    43  	me := &mockmodule.Local{}
    44  	net := &mocknetwork.Network{}
    45  	s.core = &mockconsensus.MatchingCore{}
    46  	s.index = &mockstorage.Index{}
    47  	s.receipts = &mockstorage.ExecutionReceipts{}
    48  	s.state = &mockprotocol.State{}
    49  
    50  	ourNodeID := unittest.IdentifierFixture()
    51  	me.On("NodeID").Return(ourNodeID)
    52  
    53  	con := &mocknetwork.Conduit{}
    54  	net.On("Register", mock.Anything, mock.Anything).Return(con, nil).Once()
    55  
    56  	var err error
    57  	s.engine, err = NewEngine(unittest.Logger(), net, me, metrics, metrics, s.state, s.receipts, s.index, s.core)
    58  	require.NoError(s.T(), err)
    59  
    60  	<-s.engine.Ready()
    61  }
    62  
    63  // TestOnFinalizedBlock tests if finalized block gets processed when send through `Engine`.
    64  // Tests the whole processing pipeline.
    65  func (s *MatchingEngineSuite) TestOnFinalizedBlock() {
    66  
    67  	finalizedBlock := unittest.BlockHeaderFixture()
    68  	s.state.On("Final").Return(unittest.StateSnapshotForKnownBlock(finalizedBlock, nil))
    69  	s.core.On("OnBlockFinalization").Return(nil).Once()
    70  	s.engine.OnFinalizedBlock(model.BlockFromFlow(finalizedBlock, finalizedBlock.View-1))
    71  
    72  	// matching engine has at least 100ms ticks for processing events
    73  	time.Sleep(1 * time.Second)
    74  
    75  	s.core.AssertExpectations(s.T())
    76  }
    77  
    78  // TestOnBlockIncorporated tests if incorporated block gets processed when send through `Engine`.
    79  // Tests the whole processing pipeline.
    80  func (s *MatchingEngineSuite) TestOnBlockIncorporated() {
    81  
    82  	incorporatedBlock := unittest.BlockHeaderFixture()
    83  	incorporatedBlockID := incorporatedBlock.ID()
    84  
    85  	payload := unittest.PayloadFixture(unittest.WithAllTheFixins)
    86  	index := &flow.Index{}
    87  	resultsByID := payload.Results.Lookup()
    88  	for _, receipt := range payload.Receipts {
    89  		index.ReceiptIDs = append(index.ReceiptIDs, receipt.ID())
    90  		fullReceipt := flow.ExecutionReceiptFromMeta(*receipt, *resultsByID[receipt.ResultID])
    91  		s.receipts.On("ByID", receipt.ID()).Return(fullReceipt, nil).Once()
    92  		s.core.On("ProcessReceipt", fullReceipt).Return(nil).Once()
    93  	}
    94  	s.index.On("ByBlockID", incorporatedBlockID).Return(index, nil)
    95  
    96  	s.engine.OnBlockIncorporated(model.BlockFromFlow(incorporatedBlock, incorporatedBlock.View-1))
    97  
    98  	// matching engine has at least 100ms ticks for processing events
    99  	time.Sleep(1 * time.Second)
   100  
   101  	s.core.AssertExpectations(s.T())
   102  }
   103  
   104  // TestMultipleProcessingItems tests that the engine queues multiple receipts
   105  // and eventually feeds them into matching.Core for processing
   106  func (s *MatchingEngineSuite) TestMultipleProcessingItems() {
   107  	originID := unittest.IdentifierFixture()
   108  	block := unittest.BlockFixture()
   109  
   110  	receipts := make([]*flow.ExecutionReceipt, 20)
   111  	for i := range receipts {
   112  		receipt := unittest.ExecutionReceiptFixture(
   113  			unittest.WithExecutorID(originID),
   114  			unittest.WithResult(unittest.ExecutionResultFixture(unittest.WithBlock(&block))),
   115  		)
   116  		receipts[i] = receipt
   117  		s.core.On("ProcessReceipt", receipt).Return(nil).Once()
   118  	}
   119  
   120  	var wg sync.WaitGroup
   121  	wg.Add(1)
   122  	go func() {
   123  		defer wg.Done()
   124  		for _, receipt := range receipts {
   125  			err := s.engine.Process(channels.ReceiveReceipts, originID, receipt)
   126  			s.Require().NoError(err, "should add receipt and result to mempool if valid")
   127  		}
   128  	}()
   129  
   130  	wg.Wait()
   131  
   132  	// matching engine has at least 100ms ticks for processing events
   133  	time.Sleep(1 * time.Second)
   134  
   135  	s.core.AssertExpectations(s.T())
   136  }
   137  
   138  // TestProcessUnsupportedMessageType tests that Process and ProcessLocal correctly handle a case where invalid message type
   139  // was submitted from network layer.
   140  func (s *MatchingEngineSuite) TestProcessUnsupportedMessageType() {
   141  	invalidEvent := uint64(42)
   142  	err := s.engine.Process("ch", unittest.IdentifierFixture(), invalidEvent)
   143  	// shouldn't result in error since byzantine inputs are expected
   144  	require.NoError(s.T(), err)
   145  	// in case of local processing error cannot be consumed since all inputs are trusted
   146  	err = s.engine.ProcessLocal(invalidEvent)
   147  	require.Error(s.T(), err)
   148  	require.True(s.T(), engine.IsIncompatibleInputTypeError(err))
   149  }