github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/cosmos/libs/pubsub/pubsub_test.go (about)

     1  package pubsub_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"runtime/debug"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/tendermint/tendermint/libs/log"
    14  
    15  	"github.com/tendermint/tendermint/libs/pubsub"
    16  	"github.com/tendermint/tendermint/libs/pubsub/query"
    17  )
    18  
    19  const (
    20  	clientID = "test-client"
    21  )
    22  
    23  func TestSubscribe(t *testing.T) {
    24  	s := pubsub.NewServer()
    25  	s.SetLogger(log.TestingLogger())
    26  	s.Start()
    27  	defer s.Stop()
    28  
    29  	ctx := context.Background()
    30  	ch := make(chan interface{}, 1)
    31  	err := s.Subscribe(ctx, clientID, query.Empty{}, ch)
    32  	require.NoError(t, err)
    33  	err = s.Publish(ctx, "Ka-Zar")
    34  	require.NoError(t, err)
    35  	assertReceive(t, "Ka-Zar", ch)
    36  
    37  	err = s.Publish(ctx, "Quicksilver")
    38  	require.NoError(t, err)
    39  	assertReceive(t, "Quicksilver", ch)
    40  }
    41  
    42  func TestDifferentClients(t *testing.T) {
    43  	s := pubsub.NewServer()
    44  	s.SetLogger(log.TestingLogger())
    45  	s.Start()
    46  	defer s.Stop()
    47  
    48  	ctx := context.Background()
    49  	ch1 := make(chan interface{}, 1)
    50  	err := s.Subscribe(ctx, "client-1", query.MustParse("tm.events.type='NewBlock'"), ch1)
    51  	require.NoError(t, err)
    52  	err = s.PublishWithTags(ctx, "Iceman", pubsub.NewTagMap(map[string]string{"tm.events.type": "NewBlock"}))
    53  	require.NoError(t, err)
    54  	assertReceive(t, "Iceman", ch1)
    55  
    56  	ch2 := make(chan interface{}, 1)
    57  	err = s.Subscribe(ctx, "client-2", query.MustParse("tm.events.type='NewBlock' AND abci.account.name='Igor'"), ch2)
    58  	require.NoError(t, err)
    59  	err = s.PublishWithTags(ctx, "Ultimo", pubsub.NewTagMap(map[string]string{"tm.events.type": "NewBlock", "abci.account.name": "Igor"}))
    60  	require.NoError(t, err)
    61  	assertReceive(t, "Ultimo", ch1)
    62  	assertReceive(t, "Ultimo", ch2)
    63  
    64  	ch3 := make(chan interface{}, 1)
    65  	err = s.Subscribe(ctx, "client-3", query.MustParse("tm.events.type='NewRoundStep' AND abci.account.name='Igor' AND abci.invoice.number = 10"), ch3)
    66  	require.NoError(t, err)
    67  	err = s.PublishWithTags(ctx, "Valeria Richards", pubsub.NewTagMap(map[string]string{"tm.events.type": "NewRoundStep"}))
    68  	require.NoError(t, err)
    69  	assert.Zero(t, len(ch3))
    70  }
    71  
    72  func TestClientSubscribesTwice(t *testing.T) {
    73  	s := pubsub.NewServer()
    74  	s.SetLogger(log.TestingLogger())
    75  	s.Start()
    76  	defer s.Stop()
    77  
    78  	ctx := context.Background()
    79  	q := query.MustParse("tm.events.type='NewBlock'")
    80  
    81  	ch1 := make(chan interface{}, 1)
    82  	err := s.Subscribe(ctx, clientID, q, ch1)
    83  	require.NoError(t, err)
    84  	err = s.PublishWithTags(ctx, "Goblin Queen", pubsub.NewTagMap(map[string]string{"tm.events.type": "NewBlock"}))
    85  	require.NoError(t, err)
    86  	assertReceive(t, "Goblin Queen", ch1)
    87  
    88  	ch2 := make(chan interface{}, 1)
    89  	err = s.Subscribe(ctx, clientID, q, ch2)
    90  	require.Error(t, err)
    91  
    92  	err = s.PublishWithTags(ctx, "Spider-Man", pubsub.NewTagMap(map[string]string{"tm.events.type": "NewBlock"}))
    93  	require.NoError(t, err)
    94  	assertReceive(t, "Spider-Man", ch1)
    95  }
    96  
    97  func TestUnsubscribe(t *testing.T) {
    98  	s := pubsub.NewServer()
    99  	s.SetLogger(log.TestingLogger())
   100  	s.Start()
   101  	defer s.Stop()
   102  
   103  	ctx := context.Background()
   104  	ch := make(chan interface{})
   105  	err := s.Subscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"), ch)
   106  	require.NoError(t, err)
   107  	err = s.Unsubscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"))
   108  	require.NoError(t, err)
   109  
   110  	err = s.Publish(ctx, "Nick Fury")
   111  	require.NoError(t, err)
   112  	assert.Zero(t, len(ch), "Should not receive anything after Unsubscribe")
   113  
   114  	_, ok := <-ch
   115  	assert.False(t, ok)
   116  }
   117  
   118  func TestResubscribe(t *testing.T) {
   119  	s := pubsub.NewServer()
   120  	s.SetLogger(log.TestingLogger())
   121  	s.Start()
   122  	defer s.Stop()
   123  
   124  	ctx := context.Background()
   125  	ch := make(chan interface{})
   126  	err := s.Subscribe(ctx, clientID, query.Empty{}, ch)
   127  	require.NoError(t, err)
   128  	err = s.Unsubscribe(ctx, clientID, query.Empty{})
   129  	require.NoError(t, err)
   130  	ch = make(chan interface{})
   131  	err = s.Subscribe(ctx, clientID, query.Empty{}, ch)
   132  	require.NoError(t, err)
   133  
   134  	err = s.Publish(ctx, "Cable")
   135  	require.NoError(t, err)
   136  	assertReceive(t, "Cable", ch)
   137  }
   138  
   139  func TestUnsubscribeAll(t *testing.T) {
   140  	s := pubsub.NewServer()
   141  	s.SetLogger(log.TestingLogger())
   142  	s.Start()
   143  	defer s.Stop()
   144  
   145  	ctx := context.Background()
   146  	ch1, ch2 := make(chan interface{}, 1), make(chan interface{}, 1)
   147  	err := s.Subscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlock'"), ch1)
   148  	require.NoError(t, err)
   149  	err = s.Subscribe(ctx, clientID, query.MustParse("tm.events.type='NewBlockHeader'"), ch2)
   150  	require.NoError(t, err)
   151  
   152  	err = s.UnsubscribeAll(ctx, clientID)
   153  	require.NoError(t, err)
   154  
   155  	err = s.Publish(ctx, "Nick Fury")
   156  	require.NoError(t, err)
   157  	assert.Zero(t, len(ch1), "Should not receive anything after UnsubscribeAll")
   158  	assert.Zero(t, len(ch2), "Should not receive anything after UnsubscribeAll")
   159  
   160  	_, ok := <-ch1
   161  	assert.False(t, ok)
   162  	_, ok = <-ch2
   163  	assert.False(t, ok)
   164  }
   165  
   166  func TestBufferCapacity(t *testing.T) {
   167  	s := pubsub.NewServer(pubsub.BufferCapacity(2))
   168  	s.SetLogger(log.TestingLogger())
   169  
   170  	assert.Equal(t, 2, s.BufferCapacity())
   171  
   172  	ctx := context.Background()
   173  	err := s.Publish(ctx, "Nighthawk")
   174  	require.NoError(t, err)
   175  	err = s.Publish(ctx, "Sage")
   176  	require.NoError(t, err)
   177  
   178  	ctx, cancel := context.WithTimeout(ctx, 10*time.Millisecond)
   179  	defer cancel()
   180  	err = s.Publish(ctx, "Ironclad")
   181  	if assert.Error(t, err) {
   182  		assert.Equal(t, context.DeadlineExceeded, err)
   183  	}
   184  }
   185  
   186  func Benchmark10Clients(b *testing.B)   { benchmarkNClients(10, b) }
   187  func Benchmark100Clients(b *testing.B)  { benchmarkNClients(100, b) }
   188  func Benchmark1000Clients(b *testing.B) { benchmarkNClients(1000, b) }
   189  
   190  func Benchmark10ClientsOneQuery(b *testing.B)   { benchmarkNClientsOneQuery(10, b) }
   191  func Benchmark100ClientsOneQuery(b *testing.B)  { benchmarkNClientsOneQuery(100, b) }
   192  func Benchmark1000ClientsOneQuery(b *testing.B) { benchmarkNClientsOneQuery(1000, b) }
   193  
   194  func benchmarkNClients(n int, b *testing.B) {
   195  	s := pubsub.NewServer()
   196  	s.Start()
   197  	defer s.Stop()
   198  
   199  	ctx := context.Background()
   200  	for i := 0; i < n; i++ {
   201  		ch := make(chan interface{})
   202  		go func() {
   203  			for range ch {
   204  			}
   205  		}()
   206  		s.Subscribe(ctx, clientID, query.MustParse(fmt.Sprintf("abci.Account.Owner = 'Ivan' AND abci.Invoices.Number = %d", i)), ch)
   207  	}
   208  
   209  	b.ReportAllocs()
   210  	b.ResetTimer()
   211  	for i := 0; i < b.N; i++ {
   212  		s.PublishWithTags(ctx, "Gamora", pubsub.NewTagMap(map[string]string{"abci.Account.Owner": "Ivan", "abci.Invoices.Number": string(i)}))
   213  	}
   214  }
   215  
   216  func benchmarkNClientsOneQuery(n int, b *testing.B) {
   217  	s := pubsub.NewServer()
   218  	s.Start()
   219  	defer s.Stop()
   220  
   221  	ctx := context.Background()
   222  	q := query.MustParse("abci.Account.Owner = 'Ivan' AND abci.Invoices.Number = 1")
   223  	for i := 0; i < n; i++ {
   224  		ch := make(chan interface{})
   225  		go func() {
   226  			for range ch {
   227  			}
   228  		}()
   229  		s.Subscribe(ctx, clientID, q, ch)
   230  	}
   231  
   232  	b.ReportAllocs()
   233  	b.ResetTimer()
   234  	for i := 0; i < b.N; i++ {
   235  		s.PublishWithTags(ctx, "Gamora", pubsub.NewTagMap(map[string]string{"abci.Account.Owner": "Ivan", "abci.Invoices.Number": "1"}))
   236  	}
   237  }
   238  
   239  ///////////////////////////////////////////////////////////////////////////////
   240  /// HELPERS
   241  ///////////////////////////////////////////////////////////////////////////////
   242  
   243  func assertReceive(t *testing.T, expected interface{}, ch <-chan interface{}, msgAndArgs ...interface{}) {
   244  	select {
   245  	case actual := <-ch:
   246  		if actual != nil {
   247  			assert.Equal(t, expected, actual, msgAndArgs...)
   248  		}
   249  	case <-time.After(1 * time.Second):
   250  		t.Errorf("Expected to receive %v from the channel, got nothing after 1s", expected)
   251  		debug.PrintStack()
   252  	}
   253  }