github.com/number571/tendermint@v0.34.11-gost/libs/pubsub/query/query_test.go (about)

     1  package query_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	abci "github.com/number571/tendermint/abci/types"
    10  	"github.com/number571/tendermint/libs/pubsub/query"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func expandEvents(flattenedEvents map[string][]string) []abci.Event {
    15  	events := make([]abci.Event, len(flattenedEvents))
    16  
    17  	for composite, values := range flattenedEvents {
    18  		tokens := strings.Split(composite, ".")
    19  
    20  		attrs := make([]abci.EventAttribute, len(values))
    21  		for i, v := range values {
    22  			attrs[i] = abci.EventAttribute{
    23  				Key:   tokens[len(tokens)-1],
    24  				Value: v,
    25  			}
    26  		}
    27  
    28  		events = append(events, abci.Event{
    29  			Type:       strings.Join(tokens[:len(tokens)-1], "."),
    30  			Attributes: attrs,
    31  		})
    32  	}
    33  
    34  	return events
    35  }
    36  
    37  func TestMatches(t *testing.T) {
    38  	var (
    39  		txDate = "2017-01-01"
    40  		txTime = "2018-05-03T14:45:00Z"
    41  	)
    42  
    43  	testCases := []struct {
    44  		s        string
    45  		events   map[string][]string
    46  		err      bool
    47  		matches  bool
    48  		matchErr bool
    49  	}{
    50  		{"tm.events.type='NewBlock'", map[string][]string{"tm.events.type": {"NewBlock"}}, false, true, false},
    51  		{"tx.gas > 7", map[string][]string{"tx.gas": {"8"}}, false, true, false},
    52  		{"transfer.amount > 7", map[string][]string{"transfer.amount": {"8stake"}}, false, true, false},
    53  		{"transfer.amount > 7", map[string][]string{"transfer.amount": {"8.045stake"}}, false, true, false},
    54  		{"transfer.amount > 7.043", map[string][]string{"transfer.amount": {"8.045stake"}}, false, true, false},
    55  		{"transfer.amount > 8.045", map[string][]string{"transfer.amount": {"8.045stake"}}, false, false, false},
    56  		{"tx.gas > 7 AND tx.gas < 9", map[string][]string{"tx.gas": {"8"}}, false, true, false},
    57  		{"body.weight >= 3.5", map[string][]string{"body.weight": {"3.5"}}, false, true, false},
    58  		{"account.balance < 1000.0", map[string][]string{"account.balance": {"900"}}, false, true, false},
    59  		{"apples.kg <= 4", map[string][]string{"apples.kg": {"4.0"}}, false, true, false},
    60  		{"body.weight >= 4.5", map[string][]string{"body.weight": {fmt.Sprintf("%v", float32(4.5))}}, false, true, false},
    61  		{
    62  			"oranges.kg < 4 AND watermellons.kg > 10",
    63  			map[string][]string{"oranges.kg": {"3"}, "watermellons.kg": {"12"}},
    64  			false,
    65  			true,
    66  			false,
    67  		},
    68  		{"peaches.kg < 4", map[string][]string{"peaches.kg": {"5"}}, false, false, false},
    69  		{
    70  			"tx.date > DATE 2017-01-01",
    71  			map[string][]string{"tx.date": {time.Now().Format(query.DateLayout)}},
    72  			false,
    73  			true,
    74  			false,
    75  		},
    76  		{"tx.date = DATE 2017-01-01", map[string][]string{"tx.date": {txDate}}, false, true, false},
    77  		{"tx.date = DATE 2018-01-01", map[string][]string{"tx.date": {txDate}}, false, false, false},
    78  		{
    79  			"tx.time >= TIME 2013-05-03T14:45:00Z",
    80  			map[string][]string{"tx.time": {time.Now().Format(query.TimeLayout)}},
    81  			false,
    82  			true,
    83  			false,
    84  		},
    85  		{"tx.time = TIME 2013-05-03T14:45:00Z", map[string][]string{"tx.time": {txTime}}, false, false, false},
    86  		{"abci.owner.name CONTAINS 'Igor'", map[string][]string{"abci.owner.name": {"Igor,Ivan"}}, false, true, false},
    87  		{"abci.owner.name CONTAINS 'Igor'", map[string][]string{"abci.owner.name": {"Pavel,Ivan"}}, false, false, false},
    88  		{"abci.owner.name = 'Igor'", map[string][]string{"abci.owner.name": {"Igor", "Ivan"}}, false, true, false},
    89  		{
    90  			"abci.owner.name = 'Ivan'",
    91  			map[string][]string{"abci.owner.name": {"Igor", "Ivan"}},
    92  			false,
    93  			true,
    94  			false,
    95  		},
    96  		{
    97  			"abci.owner.name = 'Ivan' AND abci.owner.name = 'Igor'",
    98  			map[string][]string{"abci.owner.name": {"Igor", "Ivan"}},
    99  			false,
   100  			true,
   101  			false,
   102  		},
   103  		{
   104  			"abci.owner.name = 'Ivan' AND abci.owner.name = 'John'",
   105  			map[string][]string{"abci.owner.name": {"Igor", "Ivan"}},
   106  			false,
   107  			false,
   108  			false,
   109  		},
   110  		{
   111  			"tm.events.type='NewBlock'",
   112  			map[string][]string{"tm.events.type": {"NewBlock"}, "app.name": {"fuzzed"}},
   113  			false,
   114  			true,
   115  			false,
   116  		},
   117  		{
   118  			"app.name = 'fuzzed'",
   119  			map[string][]string{"tm.events.type": {"NewBlock"}, "app.name": {"fuzzed"}},
   120  			false,
   121  			true,
   122  			false,
   123  		},
   124  		{
   125  			"tm.events.type='NewBlock' AND app.name = 'fuzzed'",
   126  			map[string][]string{"tm.events.type": {"NewBlock"}, "app.name": {"fuzzed"}},
   127  			false,
   128  			true,
   129  			false,
   130  		},
   131  		{
   132  			"tm.events.type='NewHeader' AND app.name = 'fuzzed'",
   133  			map[string][]string{"tm.events.type": {"NewBlock"}, "app.name": {"fuzzed"}},
   134  			false,
   135  			false,
   136  			false,
   137  		},
   138  		{"slash EXISTS",
   139  			map[string][]string{"slash.reason": {"missing_signature"}, "slash.power": {"6000"}},
   140  			false,
   141  			true,
   142  			false,
   143  		},
   144  		{"sl EXISTS",
   145  			map[string][]string{"slash.reason": {"missing_signature"}, "slash.power": {"6000"}},
   146  			false,
   147  			true,
   148  			false,
   149  		},
   150  		{"slash EXISTS",
   151  			map[string][]string{"transfer.recipient": {"cosmos1gu6y2a0ffteesyeyeesk23082c6998xyzmt9mz"},
   152  				"transfer.sender": {"cosmos1crje20aj4gxdtyct7z3knxqry2jqt2fuaey6u5"}},
   153  			false,
   154  			false,
   155  			false,
   156  		},
   157  		{"slash.reason EXISTS AND slash.power > 1000",
   158  			map[string][]string{"slash.reason": {"missing_signature"}, "slash.power": {"6000"}},
   159  			false,
   160  			true,
   161  			false,
   162  		},
   163  		{"slash.reason EXISTS AND slash.power > 1000",
   164  			map[string][]string{"slash.reason": {"missing_signature"}, "slash.power": {"500"}},
   165  			false,
   166  			false,
   167  			false,
   168  		},
   169  		{"slash.reason EXISTS",
   170  			map[string][]string{"transfer.recipient": {"cosmos1gu6y2a0ffteesyeyeesk23082c6998xyzmt9mz"},
   171  				"transfer.sender": {"cosmos1crje20aj4gxdtyct7z3knxqry2jqt2fuaey6u5"}},
   172  			false,
   173  			false,
   174  			false,
   175  		},
   176  	}
   177  
   178  	for _, tc := range testCases {
   179  		q, err := query.New(tc.s)
   180  		if !tc.err {
   181  			require.Nil(t, err)
   182  		}
   183  		require.NotNil(t, q, "Query '%s' should not be nil", tc.s)
   184  
   185  		rawEvents := expandEvents(tc.events)
   186  
   187  		if tc.matches {
   188  			match, err := q.Matches(rawEvents)
   189  			require.Nil(t, err, "Query '%s' should not error on match %v", tc.s, tc.events)
   190  			require.True(t, match, "Query '%s' should match %v", tc.s, tc.events)
   191  		} else {
   192  			match, err := q.Matches(rawEvents)
   193  			require.Equal(t, tc.matchErr, err != nil, "Unexpected error for query '%s' match %v", tc.s, tc.events)
   194  			require.False(t, match, "Query '%s' should not match %v", tc.s, tc.events)
   195  		}
   196  	}
   197  }
   198  
   199  func TestMustParse(t *testing.T) {
   200  	require.Panics(t, func() { query.MustParse("=") })
   201  	require.NotPanics(t, func() { query.MustParse("tm.events.type='NewBlock'") })
   202  }
   203  
   204  func TestConditions(t *testing.T) {
   205  	txTime, err := time.Parse(time.RFC3339, "2013-05-03T14:45:00Z")
   206  	require.NoError(t, err)
   207  
   208  	testCases := []struct {
   209  		s          string
   210  		conditions []query.Condition
   211  	}{
   212  		{
   213  			s: "tm.events.type='NewBlock'",
   214  			conditions: []query.Condition{
   215  				{CompositeKey: "tm.events.type", Op: query.OpEqual, Operand: "NewBlock"},
   216  			},
   217  		},
   218  		{
   219  			s: "tx.gas > 7 AND tx.gas < 9",
   220  			conditions: []query.Condition{
   221  				{CompositeKey: "tx.gas", Op: query.OpGreater, Operand: int64(7)},
   222  				{CompositeKey: "tx.gas", Op: query.OpLess, Operand: int64(9)},
   223  			},
   224  		},
   225  		{
   226  			s: "tx.time >= TIME 2013-05-03T14:45:00Z",
   227  			conditions: []query.Condition{
   228  				{CompositeKey: "tx.time", Op: query.OpGreaterEqual, Operand: txTime},
   229  			},
   230  		},
   231  		{
   232  			s: "slashing EXISTS",
   233  			conditions: []query.Condition{
   234  				{CompositeKey: "slashing", Op: query.OpExists},
   235  			},
   236  		},
   237  	}
   238  
   239  	for _, tc := range testCases {
   240  		q, err := query.New(tc.s)
   241  		require.Nil(t, err)
   242  
   243  		c, err := q.Conditions()
   244  		require.NoError(t, err)
   245  		require.Equal(t, tc.conditions, c)
   246  	}
   247  }