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

     1  package splitter_test
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  	"testing"
     7  
     8  	"github.com/hashicorp/go-multierror"
     9  	"github.com/rs/zerolog"
    10  	"github.com/stretchr/testify/suite"
    11  
    12  	"github.com/koko1123/flow-go-1/engine/common/splitter"
    13  	"github.com/koko1123/flow-go-1/network/channels"
    14  	"github.com/koko1123/flow-go-1/network/mocknetwork"
    15  	"github.com/koko1123/flow-go-1/utils/unittest"
    16  )
    17  
    18  func getEvent() interface{} {
    19  	return struct {
    20  		foo string
    21  	}{
    22  		foo: "bar",
    23  	}
    24  }
    25  
    26  type Suite struct {
    27  	suite.Suite
    28  
    29  	channel channels.Channel
    30  	engine  *splitter.Engine
    31  }
    32  
    33  func (suite *Suite) SetupTest() {
    34  	suite.channel = channels.TestNetworkChannel
    35  	suite.engine = splitter.New(zerolog.Logger{}, suite.channel)
    36  }
    37  
    38  func TestSplitter(t *testing.T) {
    39  	suite.Run(t, new(Suite))
    40  }
    41  
    42  // TestDownstreamEngineFailure tests the case where one of the engines registered with
    43  // the splitter encounters an error while processing a message.
    44  func (suite *Suite) TestDownstreamEngineFailure() {
    45  	id := unittest.IdentifierFixture()
    46  	event := getEvent()
    47  
    48  	engine1 := new(mocknetwork.Engine)
    49  	engine2 := new(mocknetwork.Engine)
    50  
    51  	suite.engine.RegisterEngine(engine1)
    52  	suite.engine.RegisterEngine(engine2)
    53  
    54  	processError := errors.New("Process Error!")
    55  
    56  	// engine1 processing error should not impact engine2
    57  
    58  	engine1.On("Process", suite.channel, id, event).Return(processError).Once()
    59  	engine2.On("Process", suite.channel, id, event).Return(nil).Once()
    60  
    61  	err := suite.engine.Process(suite.channel, id, event)
    62  	merr, ok := err.(*multierror.Error)
    63  	suite.Assert().True(ok)
    64  	suite.Assert().Len(merr.Errors, 1)
    65  	suite.Assert().ErrorIs(merr.Errors[0], processError)
    66  
    67  	engine1.AssertNumberOfCalls(suite.T(), "Process", 1)
    68  	engine2.AssertNumberOfCalls(suite.T(), "Process", 1)
    69  
    70  	engine1.AssertExpectations(suite.T())
    71  	engine2.AssertExpectations(suite.T())
    72  
    73  	// engine2 processing error should not impact engine1
    74  
    75  	engine1.On("Process", suite.channel, id, event).Return(nil).Once()
    76  	engine2.On("Process", suite.channel, id, event).Return(processError).Once()
    77  
    78  	err = suite.engine.Process(suite.channel, id, event)
    79  	merr, ok = err.(*multierror.Error)
    80  	suite.Assert().True(ok)
    81  	suite.Assert().Len(merr.Errors, 1)
    82  	suite.Assert().ErrorIs(merr.Errors[0], processError)
    83  
    84  	engine1.AssertNumberOfCalls(suite.T(), "Process", 2)
    85  	engine2.AssertNumberOfCalls(suite.T(), "Process", 2)
    86  
    87  	engine1.AssertExpectations(suite.T())
    88  	engine2.AssertExpectations(suite.T())
    89  }
    90  
    91  // TestProcessUnregisteredChannel tests that receiving a message on an unknown channel
    92  // returns an error.
    93  func (suite *Suite) TestProcessUnknownChannel() {
    94  	id := unittest.IdentifierFixture()
    95  	event := getEvent()
    96  
    97  	unknownChannel := channels.Channel("unknown-chan")
    98  
    99  	engine := new(mocknetwork.Engine)
   100  
   101  	suite.engine.RegisterEngine(engine)
   102  
   103  	err := suite.engine.Process(unknownChannel, id, event)
   104  	suite.Assert().Error(err)
   105  
   106  	engine.AssertNumberOfCalls(suite.T(), "Process", 0)
   107  }
   108  
   109  // TestConcurrentEvents tests that sending multiple messages concurrently, results in each engine
   110  // receiving every message.
   111  func (suite *Suite) TestConcurrentEvents() {
   112  	id := unittest.IdentifierFixture()
   113  	const numEvents = 10
   114  	const numEngines = 5
   115  
   116  	var engines [numEngines]*mocknetwork.Engine
   117  
   118  	for i := 0; i < numEngines; i++ {
   119  		engine := new(mocknetwork.Engine)
   120  		suite.engine.RegisterEngine(engine)
   121  		engines[i] = engine
   122  	}
   123  
   124  	for i := 0; i < numEvents; i++ {
   125  		for _, engine := range engines {
   126  			engine.On("Process", suite.channel, id, i).Return(nil).Once()
   127  		}
   128  	}
   129  
   130  	var wg sync.WaitGroup
   131  
   132  	for i := 0; i < numEvents; i++ {
   133  		wg.Add(1)
   134  
   135  		go func(value int) {
   136  			defer wg.Done()
   137  			err := suite.engine.Process(suite.channel, id, value)
   138  			suite.Assert().Nil(err)
   139  		}(i)
   140  	}
   141  
   142  	wg.Wait()
   143  
   144  	for _, engine := range engines {
   145  		engine.AssertNumberOfCalls(suite.T(), "Process", numEvents)
   146  		engine.AssertExpectations(suite.T())
   147  	}
   148  }