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  }