code.vegaprotocol.io/vega@v0.79.0/datanode/broker/broker_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 "net" 22 "os" 23 "os/exec" 24 "sync" 25 "sync/atomic" 26 "testing" 27 "time" 28 29 "code.vegaprotocol.io/vega/core/broker" 30 "code.vegaprotocol.io/vega/core/broker/mocks" 31 "code.vegaprotocol.io/vega/core/events" 32 "code.vegaprotocol.io/vega/core/stats" 33 "code.vegaprotocol.io/vega/core/types" 34 vgtesting "code.vegaprotocol.io/vega/datanode/libs/testing" 35 vgcontext "code.vegaprotocol.io/vega/libs/context" 36 "code.vegaprotocol.io/vega/logging" 37 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 38 39 "github.com/golang/mock/gomock" 40 "github.com/golang/protobuf/proto" 41 "github.com/stretchr/testify/assert" 42 "go.nanomsg.org/mangos/v3/protocol/pair" 43 ) 44 45 type brokerTst struct { 46 *broker.Broker 47 cfunc context.CancelFunc 48 ctx context.Context 49 ctrl *gomock.Controller 50 } 51 52 type evt struct { 53 t events.Type 54 ctx context.Context 55 sid uint64 56 id string 57 cid string 58 txHash string 59 } 60 61 func getBroker(t *testing.T) *brokerTst { 62 t.Helper() 63 ctx, cfunc := context.WithCancel(context.Background()) 64 ctrl := gomock.NewController(t) 65 logger := logging.NewTestLogger() 66 broker, _ := broker.New(ctx, logger, broker.NewDefaultConfig(), stats.NewBlockchain()) 67 t.Cleanup(cfunc) 68 return &brokerTst{ 69 Broker: broker, 70 cfunc: cfunc, 71 ctx: ctx, 72 ctrl: ctrl, 73 } 74 } 75 76 func (b brokerTst) randomEvt() *evt { 77 idString := "generic-id" 78 if ctxV, ok := b.ctx.Value("traceID").(string); ok { 79 idString = ctxV 80 } 81 return &evt{ 82 t: events.All, 83 ctx: b.ctx, 84 id: idString, 85 cid: "testchain", 86 txHash: "testTxHash", 87 } 88 } 89 90 func TestSequenceIDGen(t *testing.T) { 91 t.Parallel() 92 t.Run("Sequence ID is correctly - events dispatched per block (ordered)", testSequenceIDGenSeveralBlocksOrdered) 93 t.Run("Sequence ID is correctly - events dispatched for several blocks at the same time", testSequenceIDGenSeveralBlocksUnordered) 94 } 95 96 func TestSubscribe(t *testing.T) { 97 t.Parallel() 98 t.Run("Subscribe and unsubscribe required - success", testSubUnsubSuccess) 99 t.Run("Subscribe reuses keys", testSubReuseKey) 100 t.Run("Unsubscribe automatically if subscriber is closed", testAutoUnsubscribe) 101 } 102 103 func TestStream(t *testing.T) { 104 t.Parallel() 105 t.Run("Streams events over socket", testStreamsOverSocket) 106 t.Run("Stops process if can not send to socket", testStopsProcessOnStreamError) 107 } 108 109 func TestSendEvent(t *testing.T) { 110 t.Parallel() 111 t.Run("Skip optional subscribers", testSkipOptional) 112 t.Run("Skip optional subscribers in a batch send", testSendBatchChannel) 113 t.Run("Send batch to ack subscriber", testSendBatch) 114 t.Run("Stop sending if context is cancelled", testStopCtx) 115 t.Run("Stop sending if context is cancelled, even new events", testStopCtxSendAgain) 116 t.Run("Skip subscriber based on channel state", testSubscriberSkip) 117 t.Run("Send only to typed subscriber (also tests TxErrEvents are skipped)", testEventTypeSubscription) 118 } 119 120 func testSequenceIDGenSeveralBlocksOrdered(t *testing.T) { 121 t.Parallel() 122 tstBroker := getBroker(t) 123 124 ctxH1, ctxH2 := vgcontext.WithTraceID(tstBroker.ctx, "hash-1"), vgcontext.WithTraceID(tstBroker.ctx, "hash-2") 125 dataH1 := []events.Event{ 126 events.NewTime(ctxH1, time.Now()), 127 events.NewPartyEvent(ctxH1, types.Party{Id: "test-party-h1"}), 128 } 129 dataH2 := []events.Event{ 130 events.NewTime(ctxH2, time.Now()), 131 events.NewPartyEvent(ctxH2, types.Party{Id: "test-party-h2"}), 132 } 133 allData := make([]events.Event, 0, len(dataH1)+len(dataH2)) 134 done := make(chan struct{}) 135 mu := sync.Mutex{} 136 sub := mocks.NewMockSubscriber(tstBroker.ctrl) 137 sub.EXPECT().Types().Times(2).Return(nil) 138 sub.EXPECT().Ack().Times(1).Return(true) 139 sub.EXPECT().Skip().AnyTimes().Return(tstBroker.ctx.Done()) 140 sub.EXPECT().Closed().AnyTimes().Return(tstBroker.ctx.Done()) 141 sub.EXPECT().Push(gomock.Any()).AnyTimes().Do(func(evts ...events.Event) { 142 // race detector complains about appending here, because data comes from 143 // different go routines, so we'll use a quick & dirty fix: mutex the slice 144 mu.Lock() 145 defer mu.Unlock() 146 allData = append(allData, evts...) 147 if len(allData) >= cap(allData) { 148 close(done) 149 } 150 }) 151 sub.EXPECT().SetID(gomock.Any()).Times(1) 152 k := tstBroker.Subscribe(sub) 153 // send batches for both events - hash 2 after hash 1 154 tstBroker.SendBatch(dataH1) 155 tstBroker.SendBatch(dataH2) 156 seqH1 := []uint64{} 157 seqH2 := []uint64{} 158 for i := range dataH1 { 159 seqH1 = append(seqH1, dataH1[i].Sequence()) 160 seqH2 = append(seqH2, dataH2[i].Sequence()) 161 } 162 assert.Equal(t, seqH1, seqH2) 163 <-done 164 tstBroker.Unsubscribe(k) 165 assert.NotEqual(t, seqH1[0], seqH2[1]) // the two are equal, we can compare X-slice 166 assert.Equal(t, len(allData), len(dataH1)+len(dataH2)) 167 } 168 169 func testSequenceIDGenSeveralBlocksUnordered(t *testing.T) { 170 t.Parallel() 171 tstBroker := getBroker(t) 172 173 ctxH1, ctxH2 := vgcontext.WithTraceID(tstBroker.ctx, "hash-1"), vgcontext.WithTraceID(tstBroker.ctx, "hash-2") 174 dataH1 := []events.Event{ 175 events.NewTime(ctxH1, time.Now()), 176 events.NewPartyEvent(ctxH1, types.Party{Id: "test-party-h1"}), 177 } 178 dataH2 := []events.Event{ 179 events.NewTime(ctxH2, time.Now()), 180 events.NewPartyEvent(ctxH2, types.Party{Id: "test-party-h2"}), 181 } 182 allData := make([]events.Event, 0, len(dataH1)+len(dataH2)) 183 mu := sync.Mutex{} 184 done := make(chan struct{}) 185 sub := mocks.NewMockSubscriber(tstBroker.ctrl) 186 sub.EXPECT().Types().Times(2).Return(nil) 187 sub.EXPECT().Ack().Times(1).Return(true) 188 sub.EXPECT().Skip().AnyTimes().Return(tstBroker.ctx.Done()) 189 sub.EXPECT().Closed().AnyTimes().Return(tstBroker.ctx.Done()) 190 sub.EXPECT().Push(gomock.Any()).AnyTimes().Do(func(evts ...events.Event) { 191 mu.Lock() 192 defer mu.Unlock() 193 allData = append(allData, evts...) 194 if len(allData) >= cap(allData) { 195 close(done) 196 } 197 }) 198 sub.EXPECT().SetID(gomock.Any()).Times(1) 199 k := tstBroker.Subscribe(sub) 200 // We can't use sendBatch here: we use the traceID of the first event in the batch to determine 201 // the hash (batch-sending events can only happen within a single block) 202 for i := range dataH1 { 203 tstBroker.Send(dataH1[i]) 204 tstBroker.Send(dataH2[i]) 205 } 206 seqH1 := []uint64{} 207 seqH2 := []uint64{} 208 for i := range dataH1 { 209 seqH1 = append(seqH1, dataH1[i].Sequence()) 210 seqH2 = append(seqH2, dataH2[i].Sequence()) 211 } 212 assert.Equal(t, seqH1, seqH2) 213 <-done 214 tstBroker.Unsubscribe(k) 215 assert.NotEqual(t, seqH1[0], seqH2[1]) // the two are equal, we can compare X-slice 216 assert.Equal(t, len(allData), len(dataH1)+len(dataH2)) 217 } 218 219 func testSubUnsubSuccess(t *testing.T) { 220 t.Parallel() 221 broker := getBroker(t) 222 223 sub := mocks.NewMockSubscriber(broker.ctrl) 224 reqSub := mocks.NewMockSubscriber(broker.ctrl) 225 // subscribe + unsubscribe -> 2 calls 226 sub.EXPECT().Types().Times(2).Return(nil) 227 sub.EXPECT().Ack().Times(1).Return(false) 228 sub.EXPECT().SetID(gomock.Any()).Times(1) 229 reqSub.EXPECT().Types().Times(2).Return(nil) 230 reqSub.EXPECT().Ack().Times(1).Return(true) 231 reqSub.EXPECT().SetID(gomock.Any()).Times(1) 232 k1 := broker.Subscribe(sub) // not required 233 k2 := broker.Subscribe(reqSub) // required 234 assert.NotZero(t, k1) 235 assert.NotZero(t, k2) 236 assert.NotEqual(t, k1, k2) 237 broker.Unsubscribe(k1) 238 broker.Unsubscribe(k2) 239 // no calls to subs expected once they are unsubscribed 240 broker.Send(broker.randomEvt()) 241 } 242 243 func testSubReuseKey(t *testing.T) { 244 t.Parallel() 245 broker := getBroker(t) 246 247 sub := mocks.NewMockSubscriber(broker.ctrl) 248 sub.EXPECT().Types().Times(4).Return(nil) 249 sub.EXPECT().Ack().Times(1).Return(false) 250 sub.EXPECT().SetID(gomock.Any()).Times(2) 251 k1 := broker.Subscribe(sub) 252 sub.EXPECT().Ack().Times(1).Return(true) 253 assert.NotZero(t, k1) 254 broker.Unsubscribe(k1) 255 k2 := broker.Subscribe(sub) 256 assert.Equal(t, k1, k2) 257 broker.Unsubscribe(k2) 258 // second unsubscribe is a no-op 259 broker.Unsubscribe(k1) 260 } 261 262 func testAutoUnsubscribe(t *testing.T) { 263 t.Parallel() 264 broker := getBroker(t) 265 266 sub := mocks.NewMockSubscriber(broker.ctrl) 267 // sub, auto-unsub, sub again 268 sub.EXPECT().Types().Times(3).Return(nil) 269 sub.EXPECT().Ack().Times(1).Return(true) 270 sub.EXPECT().SetID(gomock.Any()).Times(2) 271 k1 := broker.Subscribe(sub) 272 assert.NotZero(t, k1) 273 // set up sub to be closed 274 skipCh := make(chan struct{}) 275 closedCh := make(chan struct{}) 276 wg := sync.WaitGroup{} 277 wg.Add(1) 278 defer func() { 279 close(skipCh) 280 }() 281 close(closedCh) // close the closed channel, so the subscriber is marked as closed when we try to send an event 282 sub.EXPECT().Skip().AnyTimes().Return(skipCh) 283 sub.EXPECT().Closed().AnyTimes().Return(closedCh).Do(func() { 284 // indicator this function has been called already 285 wg.Done() 286 }) 287 // send an event, the subscriber should be marked as closed, and automatically unsubscribed 288 broker.Send(broker.randomEvt()) 289 // introduce some wait mechanism here, because the unsubscribe call acquires its own lock now 290 // so it's possible we haven't unsubscribed yet... the waitgroup should introduce enough time 291 wg.Wait() 292 // now try and subscribe again, the key should be reused 293 sub.EXPECT().Ack().Times(1).Return(false) 294 k2 := broker.Subscribe(sub) 295 assert.Equal(t, k1, k2) 296 } 297 298 func testSendBatch(t *testing.T) { 299 t.Parallel() 300 tstBroker := getBroker(t) 301 sub := mocks.NewMockSubscriber(tstBroker.ctrl) 302 cancelCh := make(chan struct{}) 303 defer func() { 304 close(cancelCh) 305 }() 306 sub.EXPECT().Types().Times(1).Return(nil) 307 sub.EXPECT().Ack().AnyTimes().Return(true) 308 sub.EXPECT().SetID(gomock.Any()).Times(1) 309 k1 := tstBroker.Subscribe(sub) 310 assert.NotZero(t, k1) 311 data := []events.Event{ 312 tstBroker.randomEvt(), 313 tstBroker.randomEvt(), 314 tstBroker.randomEvt(), 315 } 316 // ensure all 3 events are being sent (wait for routine to spawn) 317 sub.EXPECT().Closed().AnyTimes().Return(cancelCh) 318 sub.EXPECT().Skip().AnyTimes().Return(cancelCh) 319 wg := sync.WaitGroup{} 320 wg.Add(1) 321 sub.EXPECT().Push(gomock.Any()).Times(1).Do(func(evts ...events.Event) { 322 assert.Equal(t, len(data), len(evts)) 323 wg.Done() 324 }) 325 326 // send events 327 tstBroker.SendBatch(data) 328 wg.Wait() 329 } 330 331 func testSendBatchChannel(t *testing.T) { 332 t.Parallel() 333 tstBroker := getBroker(t) 334 sub := mocks.NewMockSubscriber(tstBroker.ctrl) 335 skipCh, closedCh, cCh := make(chan struct{}), make(chan struct{}), make(chan []events.Event, 1) 336 defer func() { 337 close(closedCh) 338 close(skipCh) 339 }() 340 twg := sync.WaitGroup{} 341 twg.Add(2) 342 sub.EXPECT().Types().Times(2).Return(nil).Do(func() { 343 twg.Done() 344 }) 345 sub.EXPECT().Ack().AnyTimes().Return(false) 346 sub.EXPECT().SetID(gomock.Any()).Times(1) 347 k1 := tstBroker.Subscribe(sub) 348 assert.NotZero(t, k1) 349 batch2 := []events.Event{ 350 tstBroker.randomEvt(), 351 tstBroker.randomEvt(), 352 } 353 evts := []events.Event{ 354 tstBroker.randomEvt(), 355 tstBroker.randomEvt(), 356 tstBroker.randomEvt(), 357 } 358 // ensure both batches are sent 359 wg := sync.WaitGroup{} 360 // 3 calls, only the first batch will be sent 361 // third call is routine that tries to send the second batch. This will of course fail 362 wg.Add(3) 363 sub.EXPECT().Closed().AnyTimes().Return(closedCh) 364 sub.EXPECT().Skip().AnyTimes().Return(skipCh) 365 // we try to get the channel 3 times, only 1 of the attempts will actually publish the events 366 sub.EXPECT().C().Times(3).Return(cCh).Do(func() { 367 // Done call each time we tried sending an event 368 wg.Done() 369 }) 370 371 // send events 372 tstBroker.SendBatch(evts) 373 tstBroker.SendBatch(batch2) 374 wg.Wait() 375 // we've tried to send 2 batches of events, subscriber could only accept one. Check state of all the things 376 // we need to unsubscribe the subscriber, because we're closing the channels and race detector complains 377 // because there's a loop calling functions that are returning the channels we're closing here 378 tstBroker.Unsubscribe(k1) 379 // ensure unsubscribe has returned 380 twg.Wait() 381 382 // get our batches 383 batches := [][]events.Event{ 384 <-cCh, <-cCh, 385 } 386 387 // assert we have all events now. 388 batchSizes := map[int]struct{}{} 389 evtSeq := map[uint64]struct{}{} 390 for _, batch := range batches { 391 batchSizes[len(batch)] = struct{}{} 392 for _, v := range batch { 393 evtSeq[v.Sequence()] = struct{}{} 394 } 395 } 396 397 // now ensure we have the batch with right sizes 398 _, ok := batchSizes[len(batch2)] 399 assert.True(t, ok, "missing batch of size ", len(batch2)) 400 _, ok = batchSizes[len(evts)] 401 assert.True(t, ok, "missing batch of size ", len(evts)) 402 403 // now ensure we got all sequence IDs 404 for _, v := range append(evts, batch2...) { 405 _, ok := evtSeq[v.Sequence()] 406 if !ok { 407 t.Fatalf("missing event sequence from batches %v", v.Sequence()) 408 } 409 } 410 } 411 412 func testSkipOptional(t *testing.T) { 413 t.Parallel() 414 tstBroker := getBroker(t) 415 sub := mocks.NewMockSubscriber(tstBroker.ctrl) 416 skipCh, closedCh, cCh := make(chan struct{}), make(chan struct{}), make(chan []events.Event, 1) 417 defer func() { 418 close(closedCh) 419 close(skipCh) 420 }() 421 twg := sync.WaitGroup{} 422 twg.Add(2) 423 sub.EXPECT().Types().Times(2).Return(nil).Do(func() { 424 twg.Done() 425 }) 426 sub.EXPECT().Ack().AnyTimes().Return(false) 427 sub.EXPECT().SetID(gomock.Any()).Times(1) 428 k1 := tstBroker.Subscribe(sub) 429 assert.NotZero(t, k1) 430 431 evts := []*evt{ 432 tstBroker.randomEvt(), 433 tstBroker.randomEvt(), 434 tstBroker.randomEvt(), 435 } 436 // ensure all 3 events are being sent (wait for routine to spawn) 437 wg := sync.WaitGroup{} 438 wg.Add(len(evts)*2 - 1) 439 sub.EXPECT().Closed().AnyTimes().Return(closedCh) 440 sub.EXPECT().Skip().AnyTimes().Return(skipCh) 441 // we try to get the channel 3 times, only 1 of the attempts will actually publish the event 442 // the other 2 attempts will run in a routine 443 sub.EXPECT().C().Times(len(evts)*2 - 1).Return(cCh).Do(func() { 444 // Done call each time we tried sending an event 445 wg.Done() 446 }) 447 448 // send events 449 for _, e := range evts { 450 tstBroker.Send(e) 451 } 452 wg.Wait() 453 // we've tried to send 3 events, subscriber could only accept one. Check state of all the things 454 // we need to unsubscribe the subscriber, because we're closing the channels and race detector complains 455 // because there's a loop calling functions that are returning the channels we're closing here 456 tstBroker.Unsubscribe(k1) 457 // ensure unsubscribe has returned 458 twg.Wait() 459 460 // make a map to check all sequences 461 seq := map[uint64]struct{}{} 462 for i := len(evts); i != 0; i-- { 463 ev := <-cCh 464 assert.NotEmpty(t, ev) 465 for _, e := range ev { 466 seq[e.Sequence()] = struct{}{} 467 } 468 } 469 470 // no verify all ev sequence are received 471 for _, ev := range evts { 472 _, ok := seq[ev.Sequence()] 473 if !ok { 474 t.Fatalf("missing event sequence from received events %v", ev.Sequence()) 475 } 476 } 477 478 // make sure the channel is empty (no writes were pending) 479 assert.Equal(t, 0, len(cCh)) 480 } 481 482 func testStopCtx(t *testing.T) { 483 t.Parallel() 484 broker := getBroker(t) 485 486 sub := mocks.NewMockSubscriber(broker.ctrl) 487 ch := make(chan struct{}) 488 sub.EXPECT().Closed().AnyTimes().Return(ch) 489 sub.EXPECT().Skip().AnyTimes().Return(ch) 490 // no calls sub are expected, we cancelled the context 491 broker.cfunc() 492 sub.EXPECT().Types().Times(2).Return(nil) 493 sub.EXPECT().Ack().AnyTimes().Return(true) 494 sub.EXPECT().SetID(gomock.Any()).Times(1) 495 k1 := broker.Subscribe(sub) // required sub 496 assert.NotZero(t, k1) 497 broker.Send(broker.randomEvt()) 498 // calling unsubscribe acquires lock, so we can ensure the Send call has returned 499 broker.Unsubscribe(k1) 500 close(ch) 501 } 502 503 func testStopCtxSendAgain(t *testing.T) { 504 t.Parallel() 505 broker := getBroker(t) 506 507 sub := mocks.NewMockSubscriber(broker.ctrl) 508 ch := make(chan struct{}) 509 sub.EXPECT().Closed().AnyTimes().Return(ch) 510 sub.EXPECT().Skip().AnyTimes().Return(ch) 511 // no calls sub are expected, we cancelled the context 512 broker.cfunc() 513 sub.EXPECT().Types().Times(2).Return(nil) 514 sub.EXPECT().Ack().AnyTimes().Return(true) 515 sub.EXPECT().SetID(gomock.Any()).Times(1) 516 k1 := broker.Subscribe(sub) // required sub 517 assert.NotZero(t, k1) 518 broker.Send(broker.randomEvt()) 519 broker.cfunc() 520 broker.Send(broker.randomEvt()) 521 // calling unsubscribe acquires lock, so we can ensure the Send call has returned 522 broker.Unsubscribe(k1) 523 close(ch) 524 } 525 526 func testSubscriberSkip(t *testing.T) { 527 t.Parallel() 528 broker := getBroker(t) 529 530 sub := mocks.NewMockSubscriber(broker.ctrl) 531 skipCh, closeCh := make(chan struct{}), make(chan struct{}) 532 skip := int64(0) 533 events := []*evt{ 534 broker.randomEvt(), 535 broker.randomEvt(), 536 } 537 wg := sync.WaitGroup{} 538 wg.Add(len(events)) 539 sub.EXPECT().Closed().AnyTimes().Return(closeCh).Do(func() { 540 wg.Done() 541 }) 542 sub.EXPECT().Skip().AnyTimes().DoAndReturn(func() <-chan struct{} { 543 // ensure at least all events + 1 skip are called 544 if s := atomic.AddInt64(&skip, 1); s == 1 { 545 // skip the first one 546 ch := make(chan struct{}) 547 // return closed channel, so this subscriber is marked to skip events 548 close(ch) 549 return ch 550 } 551 return skipCh 552 }) 553 // we expect this call once, and only for the SECOND call 554 sub.EXPECT().Push(events[1]).Times(1) 555 sub.EXPECT().Types().Times(2).Return(nil) 556 sub.EXPECT().Ack().AnyTimes().Return(true) 557 sub.EXPECT().SetID(gomock.Any()).Times(1) 558 k1 := broker.Subscribe(sub) // required sub 559 assert.NotZero(t, k1) 560 for _, e := range events { 561 broker.Send(e) 562 } 563 wg.Wait() 564 // calling unsubscribe acquires lock, so we can ensure the Send call has returned 565 broker.Unsubscribe(k1) 566 close(skipCh) 567 close(closeCh) 568 } 569 570 // test making sure that events are sent only to subs that are interested in it. 571 func testEventTypeSubscription(t *testing.T) { 572 t.Parallel() 573 broker := getBroker(t) 574 575 sub := mocks.NewMockSubscriber(broker.ctrl) 576 allSub := mocks.NewMockSubscriber(broker.ctrl) 577 diffSub := mocks.NewMockSubscriber(broker.ctrl) 578 skipCh, closeCh := make(chan struct{}), make(chan struct{}) 579 event := broker.randomEvt() 580 event.t = events.TimeUpdate 581 wg := sync.WaitGroup{} 582 wg.Add(2) 583 // Closed check 584 sub.EXPECT().Closed().AnyTimes().Return(closeCh) 585 diffSub.EXPECT().Closed().AnyTimes().Return(closeCh) // can use the same channels, we're not closing them anyway 586 allSub.EXPECT().Closed().AnyTimes().Return(closeCh) 587 // skip check 588 sub.EXPECT().Skip().AnyTimes().Return(skipCh) 589 allSub.EXPECT().Skip().AnyTimes().Return(skipCh) 590 diffSub.EXPECT().Skip().AnyTimes().Return(skipCh) 591 // actually push the event - diffSub expects nothing 592 sub.EXPECT().Push(gomock.Any()).Times(1).Do(func(_ interface{}) { 593 wg.Done() 594 }) 595 allSub.EXPECT().Push(gomock.Any()).Times(1).Do(func(_ interface{}) { 596 wg.Done() 597 }) 598 // the event types this subscriber is interested in 599 sub.EXPECT().Types().Times(2).Return([]events.Type{events.TimeUpdate}) 600 allSub.EXPECT().Types().Times(2).Return(nil) // subscribed to ALL events 601 // fake type: 602 different := events.Type(int(events.All) + int(events.TimeUpdate) + 1 + int(events.TxErrEvent)) // this value cannot exist as an events.Type value 603 diffSub.EXPECT().Types().Times(2).Return([]events.Type{different}) 604 // subscribe the subscriber 605 sub.EXPECT().Ack().AnyTimes().Return(true) 606 diffSub.EXPECT().Ack().AnyTimes().Return(true) 607 allSub.EXPECT().Ack().AnyTimes().Return(true) 608 sub.EXPECT().SetID(gomock.Any()).Times(1) 609 diffSub.EXPECT().SetID(gomock.Any()).Times(1) 610 allSub.EXPECT().SetID(gomock.Any()).Times(1) 611 k1 := broker.Subscribe(sub) // required sub 612 k2 := broker.Subscribe(diffSub) // required sub, but won't be used anyway 613 k3 := broker.Subscribe(allSub) 614 assert.NotZero(t, k1) 615 assert.NotZero(t, k2) 616 assert.NotZero(t, k3) 617 assert.NotEqual(t, k1, k2) 618 // send a time event 619 broker.Send(events.NewTime(context.Background(), time.Now())) 620 // ensure the event was delivered 621 wg.Wait() 622 // unsubscribe the subscriber, now we're done 623 broker.Unsubscribe(k1) 624 broker.Unsubscribe(k2) 625 broker.Unsubscribe(k3) 626 close(skipCh) 627 close(closeCh) 628 } 629 630 func testStreamsOverSocket(t *testing.T) { 631 t.Parallel() 632 ctx, cfunc := context.WithCancel(context.Background()) 633 config := broker.NewDefaultConfig() 634 config.Socket.Enabled = true 635 config.Socket.Transport = "inproc" 636 637 sock, err := pair.NewSocket() 638 assert.NoError(t, err) 639 640 addr := fmt.Sprintf( 641 "inproc://%s", 642 net.JoinHostPort(config.Socket.Address, fmt.Sprintf("%d", config.Socket.Port)), 643 ) 644 err = sock.Listen(addr) 645 assert.NoError(t, err) 646 647 broker, _ := broker.New(ctx, logging.NewTestLogger(), config, stats.NewBlockchain()) 648 649 defer func() { 650 cfunc() 651 652 sock.Close() 653 }() 654 655 sentEvent := events.NewTime(ctx, time.Date(2020, time.December, 25, 0o0, 0o1, 0o1, 0, time.UTC)) 656 657 broker.Send(sentEvent) 658 659 receivedBytes, err := sock.Recv() 660 assert.NoError(t, err) 661 662 var receivedEvent eventspb.BusEvent 663 err = proto.Unmarshal(receivedBytes, &receivedEvent) 664 assert.NoError(t, err) 665 vgtesting.AssertProtoEqual(t, sentEvent.StreamMessage(), &receivedEvent) 666 } 667 668 func testStopsProcessOnStreamError(t *testing.T) { 669 t.Parallel() 670 if os.Getenv("RUN_TEST") == "1" { 671 ctx, cfunc := context.WithCancel(context.Background()) 672 config := broker.NewDefaultConfig() 673 config.Socket.Enabled = true 674 config.Socket.Transport = "inproc" 675 676 // Having such a small buffers will make the process fail 677 config.Socket.SocketChannelBufferSize = 0 678 config.Socket.EventChannelBufferSize = 0 679 680 sock, err := pair.NewSocket() 681 assert.NoError(t, err) 682 683 addr := fmt.Sprintf( 684 "inproc://%s", 685 net.JoinHostPort(config.Socket.Address, fmt.Sprintf("%d", config.Socket.Port)), 686 ) 687 err = sock.Listen(addr) 688 assert.NoError(t, err) 689 690 broker, _ := broker.New(ctx, logging.NewTestLogger(), config, stats.NewBlockchain()) 691 692 defer func() { 693 cfunc() 694 695 sock.Close() 696 }() 697 698 sentEvent := events.NewTime(ctx, time.Date(2020, time.December, 25, 0o0, 0o1, 0o1, 0, time.UTC)) 699 700 broker.Send(sentEvent) 701 // One of the next call should terminate the process 702 broker.Send(sentEvent) 703 broker.Send(sentEvent) 704 broker.Send(sentEvent) 705 return 706 } 707 708 cmd := exec.Command(os.Args[0], "-test.run=TestStream/Stops_process_if_can_not_send_to_socket") 709 cmd.Env = append(os.Environ(), "RUN_TEST=1") 710 err := cmd.Run() 711 if e, ok := err.(*exec.ExitError); ok && !e.Success() { 712 return 713 } 714 t.Fatalf("process ran with err %v, want exit status 1", err) 715 } 716 717 func (e evt) Type() events.Type { 718 return e.t 719 } 720 721 func (e evt) Replace(context.Context) {} 722 723 func (e evt) Context() context.Context { 724 return e.ctx 725 } 726 727 func (e *evt) SetSequenceID(s uint64) { 728 e.sid = s 729 } 730 731 func (e evt) Sequence() uint64 { 732 return e.sid 733 } 734 735 func (e evt) TraceID() string { 736 return e.id 737 } 738 739 func (e evt) BlockNr() int64 { 740 return 0 741 } 742 743 func (e evt) ChainID() string { 744 return e.cid 745 } 746 747 func (e evt) TxHash() string { 748 return e.txHash 749 } 750 751 func (e evt) StreamMessage() *eventspb.BusEvent { 752 return nil 753 } 754 755 func (e evt) CompositeCount() uint64 { 756 return 1 757 }