github.com/vipernet-xyz/tm@v0.34.24/libs/pubsub/query/query_test.go (about)

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