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  }