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