code.vegaprotocol.io/vega@v0.79.0/datanode/broker/fan_out_event_source_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package broker_test 17 18 import ( 19 "context" 20 "fmt" 21 "testing" 22 23 "code.vegaprotocol.io/vega/core/events" 24 "code.vegaprotocol.io/vega/core/types" 25 "code.vegaprotocol.io/vega/datanode/broker" 26 "code.vegaprotocol.io/vega/datanode/service" 27 vgcontext "code.vegaprotocol.io/vega/libs/context" 28 29 "github.com/stretchr/testify/assert" 30 ) 31 32 func TestEventFanOut(t *testing.T) { 33 tes := &testEventSource{ 34 eventsCh: make(chan events.Event), 35 errorsCh: make(chan error), 36 } 37 ctx := vgcontext.WithBlockHeight(context.Background(), 1) 38 fos := broker.NewFanOutEventSource(tes, 20, 2) 39 40 evtCh1, _ := fos.Receive(ctx) 41 evtCh2, _ := fos.Receive(ctx) 42 43 e1 := events.NewAssetEvent(ctx, types.Asset{ID: "a1"}) 44 e2 := events.NewAssetEvent(ctx, types.Asset{ID: "a2"}) 45 e1.SetSequenceID(1) 46 e2.SetSequenceID(2) 47 48 tes.eventsCh <- e1 49 tes.eventsCh <- e2 50 51 assert.Equal(t, e1, <-evtCh1) 52 assert.Equal(t, e1, <-evtCh2) 53 54 assert.Equal(t, e2, <-evtCh1) 55 assert.Equal(t, e2, <-evtCh2) 56 } 57 58 func TestCompositeFanOut(t *testing.T) { 59 tes := &testEventSource{ 60 eventsCh: make(chan events.Event), 61 errorsCh: make(chan error), 62 } 63 c, cfunc := context.WithCancel(context.Background()) 64 defer cfunc() 65 ctx := vgcontext.WithBlockHeight(c, 1) 66 fos := broker.NewFanOutEventSource(tes, 20, 1) 67 68 evtCh1, _ := fos.Receive(ctx) 69 70 e1 := events.NewAssetEvent(ctx, types.Asset{ID: "a1"}) 71 e2 := events.NewExpiredOrdersEvent(ctx, "foo", []string{ 72 "party1", 73 "party2", 74 "party3", 75 "party4", 76 }) 77 e3 := events.NewAssetEvent(ctx, types.Asset{ID: "a2"}) 78 e4 := events.NewAssetEvent(ctx, types.Asset{ID: "a3"}) 79 // set seq ID as expected 80 sID := uint64(1) 81 e1.SetSequenceID(sID) 82 sID += e1.CompositeCount() 83 e2.SetSequenceID(sID) 84 sID += e2.CompositeCount() 85 e3.SetSequenceID(sID) 86 sID += e3.CompositeCount() 87 e4.SetSequenceID(sID) 88 89 tes.eventsCh <- e1 90 tes.eventsCh <- e2 91 tes.eventsCh <- e3 92 tes.eventsCh <- e4 93 94 assert.Equal(t, e1, <-evtCh1) 95 assert.Equal(t, e2, <-evtCh1) 96 assert.Equal(t, e3, <-evtCh1) 97 assert.Equal(t, e4, <-evtCh1) 98 } 99 100 func TestCloseChannelsAndExitWithError(t *testing.T) { 101 tes := &testEventSource{ 102 eventsCh: make(chan events.Event), 103 errorsCh: make(chan error, 1), 104 } 105 106 ctx := vgcontext.WithBlockHeight(context.Background(), 1) 107 fos := broker.NewFanOutEventSource(tes, 20, 2) 108 109 evtCh1, errCh1 := fos.Receive(ctx) 110 evtCh2, errCh2 := fos.Receive(ctx) 111 112 e := events.NewAssetEvent(ctx, types.Asset{ID: "a1"}) 113 e.SetSequenceID(1) 114 tes.eventsCh <- e 115 assert.Equal(t, e, <-evtCh1) 116 assert.Equal(t, e, <-evtCh2) 117 118 tes.errorsCh <- fmt.Errorf("e1") 119 close(tes.eventsCh) 120 121 assert.Equal(t, fmt.Errorf("e1"), <-errCh1) 122 assert.Equal(t, fmt.Errorf("e1"), <-errCh2) 123 124 _, ok := <-evtCh1 125 assert.False(t, ok, "channel should be closed") 126 _, ok = <-evtCh2 127 assert.False(t, ok, "channel should be closed") 128 } 129 130 func TestPanicOnInvalidSubscriberNumber(t *testing.T) { 131 defer func() { 132 if r := recover(); r == nil { 133 t.Fatalf("expected panic") 134 } 135 }() 136 137 tes := &testEventSource{ 138 eventsCh: make(chan events.Event), 139 errorsCh: make(chan error), 140 } 141 142 fos := broker.NewFanOutEventSource(tes, 20, 2) 143 144 fos.Receive(context.Background()) 145 fos.Receive(context.Background()) 146 fos.Receive(context.Background()) 147 } 148 149 func TestListenOnlyCalledOnceOnSource(t *testing.T) { 150 tes := &testEventSource{ 151 eventsCh: make(chan events.Event), 152 errorsCh: make(chan error), 153 } 154 155 fos := broker.NewFanOutEventSource(tes, 20, 2) 156 fos.Listen() 157 fos.Listen() 158 fos.Listen() 159 160 assert.Equal(t, 1, tes.listenCount) 161 } 162 163 type testEventSource struct { 164 eventsCh chan events.Event 165 errorsCh chan error 166 listenCount int 167 protocolUpgradeSvc *service.ProtocolUpgrade 168 } 169 170 func (te *testEventSource) Listen() error { 171 te.listenCount++ 172 return nil 173 } 174 175 func (te *testEventSource) Receive(ctx context.Context) (<-chan events.Event, <-chan error) { 176 return te.eventsCh, te.errorsCh 177 } 178 179 func (te *testEventSource) Send(e events.Event) error { 180 return nil 181 }