pubsub: Refactor Event Subscription (#6634)

This commit is contained in:
Aleksandr Bezobchuk
2021-07-01 11:17:48 -04:00
committed by GitHub
parent b0a413eb17
commit 414130aee1
19 changed files with 428 additions and 226 deletions
+5 -1
View File
@@ -1,11 +1,15 @@
package query
import (
"github.com/tendermint/tendermint/abci/types"
)
// Empty query matches any set of events.
type Empty struct {
}
// Matches always returns true.
func (Empty) Matches(tags map[string][]string) (bool, error) {
func (Empty) Matches(events []types.Event) (bool, error) {
return true, nil
}
+37 -10
View File
@@ -3,8 +3,8 @@ package query_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/pubsub/query"
)
@@ -12,17 +12,44 @@ func TestEmptyQueryMatchesAnything(t *testing.T) {
q := query.Empty{}
testCases := []struct {
query map[string][]string
events []abci.Event
}{
{map[string][]string{}},
{map[string][]string{"Asher": {"Roth"}}},
{map[string][]string{"Route": {"66"}}},
{map[string][]string{"Route": {"66"}, "Billy": {"Blue"}}},
{
[]abci.Event{},
},
{
[]abci.Event{
{
Type: "Asher",
Attributes: []abci.EventAttribute{{Key: "Roth"}},
},
},
},
{
[]abci.Event{
{
Type: "Route",
Attributes: []abci.EventAttribute{{Key: "66"}},
},
},
},
{
[]abci.Event{
{
Type: "Route",
Attributes: []abci.EventAttribute{{Key: "66"}},
},
{
Type: "Billy",
Attributes: []abci.EventAttribute{{Key: "Blue"}},
},
},
},
}
for _, tc := range testCases {
match, err := q.Matches(tc.query)
assert.Nil(t, err)
assert.True(t, match)
match, err := q.Matches(tc.events)
require.Nil(t, err)
require.True(t, match)
}
}
+27 -2
View File
@@ -15,6 +15,8 @@ import (
"strconv"
"strings"
"time"
"github.com/tendermint/tendermint/abci/types"
)
var (
@@ -198,11 +200,13 @@ func (q *Query) Conditions() ([]Condition, error) {
//
// For example, query "name=John" matches events = {"name": ["John", "Eric"]}.
// More examples could be found in parser_test.go and query_test.go.
func (q *Query) Matches(events map[string][]string) (bool, error) {
if len(events) == 0 {
func (q *Query) Matches(rawEvents []types.Event) (bool, error) {
if len(rawEvents) == 0 {
return false, nil
}
events := flattenEvents(rawEvents)
var (
eventAttr string
op Operator
@@ -500,3 +504,24 @@ func matchValue(value string, op Operator, operand reflect.Value) (bool, error)
return false, nil
}
func flattenEvents(events []types.Event) map[string][]string {
flattened := make(map[string][]string)
for _, event := range events {
if len(event.Type) == 0 {
continue
}
for _, attr := range event.Attributes {
if len(attr.Key) == 0 {
continue
}
compositeEvent := fmt.Sprintf("%s.%s", event.Type, attr.Key)
flattened[compositeEvent] = append(flattened[compositeEvent], attr.Value)
}
}
return flattened
}
+36 -11
View File
@@ -2,15 +2,38 @@ package query_test
import (
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/pubsub/query"
)
func expandEvents(flattenedEvents map[string][]string) []abci.Event {
events := make([]abci.Event, len(flattenedEvents))
for composite, values := range flattenedEvents {
tokens := strings.Split(composite, ".")
attrs := make([]abci.EventAttribute, len(values))
for i, v := range values {
attrs[i] = abci.EventAttribute{
Key: tokens[len(tokens)-1],
Value: v,
}
}
events = append(events, abci.Event{
Type: strings.Join(tokens[:len(tokens)-1], "."),
Attributes: attrs,
})
}
return events
}
func TestMatches(t *testing.T) {
var (
txDate = "2017-01-01"
@@ -159,21 +182,23 @@ func TestMatches(t *testing.T) {
}
require.NotNil(t, q, "Query '%s' should not be nil", tc.s)
rawEvents := expandEvents(tc.events)
if tc.matches {
match, err := q.Matches(tc.events)
assert.Nil(t, err, "Query '%s' should not error on match %v", tc.s, tc.events)
assert.True(t, match, "Query '%s' should match %v", tc.s, tc.events)
match, err := q.Matches(rawEvents)
require.Nil(t, err, "Query '%s' should not error on match %v", tc.s, tc.events)
require.True(t, match, "Query '%s' should match %v", tc.s, tc.events)
} else {
match, err := q.Matches(tc.events)
assert.Equal(t, tc.matchErr, err != nil, "Unexpected error for query '%s' match %v", tc.s, tc.events)
assert.False(t, match, "Query '%s' should not match %v", tc.s, tc.events)
match, err := q.Matches(rawEvents)
require.Equal(t, tc.matchErr, err != nil, "Unexpected error for query '%s' match %v", tc.s, tc.events)
require.False(t, match, "Query '%s' should not match %v", tc.s, tc.events)
}
}
}
func TestMustParse(t *testing.T) {
assert.Panics(t, func() { query.MustParse("=") })
assert.NotPanics(t, func() { query.MustParse("tm.events.type='NewBlock'") })
require.Panics(t, func() { query.MustParse("=") })
require.NotPanics(t, func() { query.MustParse("tm.events.type='NewBlock'") })
}
func TestConditions(t *testing.T) {
@@ -217,6 +242,6 @@ func TestConditions(t *testing.T) {
c, err := q.Conditions()
require.NoError(t, err)
assert.Equal(t, tc.conditions, c)
require.Equal(t, tc.conditions, c)
}
}