github.com/Finschia/ostracon@v1.1.5/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/Finschia/ostracon/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  			"root.dummy.v1.EventDummy.seq = '\"1\"'",
   155  			map[string][]string{"root.dummy.v1.EventDummy.seq": {"\"1\""}},
   156  			false,
   157  			true,
   158  			false,
   159  		},
   160  	}
   161  
   162  	for _, tc := range testCases {
   163  		q, err := query.New(tc.s)
   164  		if !tc.err {
   165  			require.Nil(t, err)
   166  		}
   167  		require.NotNil(t, q, "Query '%s' should not be nil", tc.s)
   168  
   169  		if tc.matches {
   170  			match, err := q.Matches(tc.events)
   171  			assert.Nil(t, err, "Query '%s' should not error on match %v", tc.s, tc.events)
   172  			assert.True(t, match, "Query '%s' should match %v", tc.s, tc.events)
   173  		} else {
   174  			match, err := q.Matches(tc.events)
   175  			assert.Equal(t, tc.matchErr, err != nil, "Unexpected error for query '%s' match %v", tc.s, tc.events)
   176  			assert.False(t, match, "Query '%s' should not match %v", tc.s, tc.events)
   177  		}
   178  	}
   179  }
   180  
   181  func TestMustParse(t *testing.T) {
   182  	assert.Panics(t, func() { query.MustParse("=") })
   183  	assert.NotPanics(t, func() { query.MustParse("tm.events.type='NewBlock'") })
   184  }
   185  
   186  func TestConditions(t *testing.T) {
   187  	txTime, err := time.Parse(time.RFC3339, "2013-05-03T14:45:00Z")
   188  	require.NoError(t, err)
   189  
   190  	testCases := []struct {
   191  		s          string
   192  		conditions []query.Condition
   193  	}{
   194  		{
   195  			s: "tm.events.type='NewBlock'",
   196  			conditions: []query.Condition{
   197  				{CompositeKey: "tm.events.type", Op: query.OpEqual, Operand: "NewBlock"},
   198  			},
   199  		},
   200  		{
   201  			s: "tx.gas > 7 AND tx.gas < 9",
   202  			conditions: []query.Condition{
   203  				{CompositeKey: "tx.gas", Op: query.OpGreater, Operand: int64(7)},
   204  				{CompositeKey: "tx.gas", Op: query.OpLess, Operand: int64(9)},
   205  			},
   206  		},
   207  		{
   208  			s: "tx.time >= TIME 2013-05-03T14:45:00Z",
   209  			conditions: []query.Condition{
   210  				{CompositeKey: "tx.time", Op: query.OpGreaterEqual, Operand: txTime},
   211  			},
   212  		},
   213  		{
   214  			s: "slashing EXISTS",
   215  			conditions: []query.Condition{
   216  				{CompositeKey: "slashing", Op: query.OpExists},
   217  			},
   218  		},
   219  	}
   220  
   221  	for _, tc := range testCases {
   222  		q, err := query.New(tc.s)
   223  		require.Nil(t, err)
   224  
   225  		c, err := q.Conditions()
   226  		require.NoError(t, err)
   227  		assert.Equal(t, tc.conditions, c)
   228  	}
   229  }