2017-06-20 17:25:42 +04:00
|
|
|
package pubsub_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"runtime/debug"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/tendermint/tmlibs/log"
|
|
|
|
"github.com/tendermint/tmlibs/pubsub"
|
|
|
|
"github.com/tendermint/tmlibs/pubsub/query"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
clientID = "test-client"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSubscribe(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
ch := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err := s.Subscribe(clientID, query.Empty{}, ch)
|
2017-06-20 17:25:42 +04:00
|
|
|
require.NoError(t, err)
|
2017-07-14 13:02:32 +03:00
|
|
|
s.Publish("Ka-Zar")
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Ka-Zar", ch)
|
|
|
|
|
2017-07-14 13:02:32 +03:00
|
|
|
s.Publish("Quicksilver")
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Quicksilver", ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDifferentClients(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
ch1 := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err := s.Subscribe("client-1", query.MustParse("tm.events.type=NewBlock"), ch1)
|
2017-06-20 17:25:42 +04:00
|
|
|
require.NoError(t, err)
|
2017-07-14 13:02:32 +03:00
|
|
|
s.PublishWithTags("Iceman", map[string]interface{}{"tm.events.type": "NewBlock"})
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Iceman", ch1)
|
|
|
|
|
|
|
|
ch2 := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err = s.Subscribe("client-2", query.MustParse("tm.events.type=NewBlock AND abci.account.name=Igor"), ch2)
|
2017-06-20 17:25:42 +04:00
|
|
|
require.NoError(t, err)
|
2017-07-14 13:02:32 +03:00
|
|
|
s.PublishWithTags("Ultimo", map[string]interface{}{"tm.events.type": "NewBlock", "abci.account.name": "Igor"})
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Ultimo", ch1)
|
|
|
|
assertReceive(t, "Ultimo", ch2)
|
|
|
|
|
|
|
|
ch3 := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err = s.Subscribe("client-3", query.MustParse("tm.events.type=NewRoundStep AND abci.account.name=Igor AND abci.invoice.number = 10"), ch3)
|
2017-06-20 17:25:42 +04:00
|
|
|
require.NoError(t, err)
|
2017-07-14 13:02:32 +03:00
|
|
|
s.PublishWithTags("Valeria Richards", map[string]interface{}{"tm.events.type": "NewRoundStep"})
|
2017-06-20 17:25:42 +04:00
|
|
|
assert.Zero(t, len(ch3))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestClientResubscribes(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
q := query.MustParse("tm.events.type=NewBlock")
|
|
|
|
|
|
|
|
ch1 := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err := s.Subscribe(clientID, q, ch1)
|
2017-06-20 17:25:42 +04:00
|
|
|
require.NoError(t, err)
|
2017-07-14 13:02:32 +03:00
|
|
|
s.PublishWithTags("Goblin Queen", map[string]interface{}{"tm.events.type": "NewBlock"})
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Goblin Queen", ch1)
|
|
|
|
|
|
|
|
ch2 := make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err = s.Subscribe(clientID, q, ch2)
|
|
|
|
require.NoError(t, err)
|
2017-06-20 17:25:42 +04:00
|
|
|
|
|
|
|
_, ok := <-ch1
|
|
|
|
assert.False(t, ok)
|
|
|
|
|
2017-07-14 13:02:32 +03:00
|
|
|
s.PublishWithTags("Spider-Man", map[string]interface{}{"tm.events.type": "NewBlock"})
|
2017-06-20 17:25:42 +04:00
|
|
|
assertReceive(t, "Spider-Man", ch2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnsubscribe(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
ch := make(chan interface{})
|
2017-07-14 13:02:32 +03:00
|
|
|
err := s.Subscribe(clientID, query.Empty{}, ch)
|
|
|
|
require.NoError(t, err)
|
2017-06-20 17:25:42 +04:00
|
|
|
s.Unsubscribe(clientID, query.Empty{})
|
|
|
|
|
2017-07-14 13:02:32 +03:00
|
|
|
s.Publish("Nick Fury")
|
2017-06-20 17:25:42 +04:00
|
|
|
assert.Zero(t, len(ch), "Should not receive anything after Unsubscribe")
|
|
|
|
|
|
|
|
_, ok := <-ch
|
|
|
|
assert.False(t, ok)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnsubscribeAll(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
ch1, ch2 := make(chan interface{}, 1), make(chan interface{}, 1)
|
2017-07-14 13:02:32 +03:00
|
|
|
err := s.Subscribe(clientID, query.MustParse("tm.events.type=NewBlock"), ch1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = s.Subscribe(clientID, query.MustParse("tm.events.type=NewBlockHeader"), ch2)
|
|
|
|
require.NoError(t, err)
|
2017-06-20 17:25:42 +04:00
|
|
|
|
|
|
|
s.UnsubscribeAll(clientID)
|
|
|
|
|
2017-07-14 13:02:32 +03:00
|
|
|
s.Publish("Nick Fury")
|
2017-06-20 17:25:42 +04:00
|
|
|
assert.Zero(t, len(ch1), "Should not receive anything after UnsubscribeAll")
|
|
|
|
assert.Zero(t, len(ch2), "Should not receive anything after UnsubscribeAll")
|
|
|
|
|
|
|
|
_, ok := <-ch1
|
|
|
|
assert.False(t, ok)
|
|
|
|
_, ok = <-ch2
|
|
|
|
assert.False(t, ok)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBufferCapacity(t *testing.T) {
|
|
|
|
s := pubsub.NewServer(pubsub.BufferCapacity(2))
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
|
2017-07-14 13:02:32 +03:00
|
|
|
s.Publish("Nighthawk")
|
|
|
|
s.Publish("Sage")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSubscribeReturnsErrorIfServerOverflowed(t *testing.T) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.SetLogger(log.TestingLogger())
|
|
|
|
|
|
|
|
ch := make(chan interface{}, 1)
|
|
|
|
err := s.Subscribe(clientID, query.MustParse("tm.events.type=NewBlock"), ch)
|
|
|
|
if assert.Error(t, err) {
|
|
|
|
assert.Equal(t, pubsub.ErrorOverflow, err)
|
|
|
|
}
|
2017-06-20 17:25:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func Benchmark10Clients(b *testing.B) { benchmarkNClients(10, b) }
|
|
|
|
func Benchmark100Clients(b *testing.B) { benchmarkNClients(100, b) }
|
|
|
|
func Benchmark1000Clients(b *testing.B) { benchmarkNClients(1000, b) }
|
|
|
|
|
2017-07-12 22:52:13 +03:00
|
|
|
func Benchmark10ClientsOneQuery(b *testing.B) { benchmarkNClientsOneQuery(10, b) }
|
|
|
|
func Benchmark100ClientsOneQuery(b *testing.B) { benchmarkNClientsOneQuery(100, b) }
|
|
|
|
func Benchmark1000ClientsOneQuery(b *testing.B) { benchmarkNClientsOneQuery(1000, b) }
|
|
|
|
|
2017-06-20 17:25:42 +04:00
|
|
|
func benchmarkNClients(n int, b *testing.B) {
|
2017-07-12 22:52:13 +03:00
|
|
|
s := pubsub.NewServer()
|
2017-06-20 17:25:42 +04:00
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
ch := make(chan interface{})
|
2017-07-12 22:52:13 +03:00
|
|
|
go func() {
|
|
|
|
for range ch {
|
|
|
|
}
|
|
|
|
}()
|
2017-06-20 17:25:42 +04:00
|
|
|
s.Subscribe(clientID, query.MustParse(fmt.Sprintf("abci.Account.Owner = Ivan AND abci.Invoices.Number = %d", i)), ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
s.PublishWithTags("Gamora", map[string]interface{}{"abci.Account.Owner": "Ivan", "abci.Invoices.Number": i})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-12 22:52:13 +03:00
|
|
|
func benchmarkNClientsOneQuery(n int, b *testing.B) {
|
|
|
|
s := pubsub.NewServer()
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
|
|
|
|
q := query.MustParse("abci.Account.Owner = Ivan AND abci.Invoices.Number = 1")
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
ch := make(chan interface{})
|
|
|
|
go func() {
|
|
|
|
for range ch {
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
s.Subscribe(clientID, q, ch)
|
|
|
|
}
|
|
|
|
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
s.PublishWithTags("Gamora", map[string]interface{}{"abci.Account.Owner": "Ivan", "abci.Invoices.Number": 1})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-20 17:25:42 +04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/// HELPERS
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
func assertReceive(t *testing.T, expected interface{}, ch <-chan interface{}, msgAndArgs ...interface{}) {
|
|
|
|
select {
|
|
|
|
case actual := <-ch:
|
|
|
|
if actual != nil {
|
|
|
|
assert.Equal(t, expected, actual, msgAndArgs...)
|
|
|
|
}
|
|
|
|
case <-time.After(1 * time.Second):
|
|
|
|
t.Errorf("Expected to receive %v from the channel, got nothing after 1s", expected)
|
|
|
|
debug.PrintStack()
|
|
|
|
}
|
|
|
|
}
|