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 }