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 }