go.temporal.io/server@v1.23.0/common/archiver/s3store/query_parser_test.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package s3store
    26  
    27  import (
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/stretchr/testify/require"
    32  	"github.com/stretchr/testify/suite"
    33  
    34  	"go.temporal.io/server/common/convert"
    35  )
    36  
    37  type queryParserSuite struct {
    38  	*require.Assertions
    39  	suite.Suite
    40  
    41  	parser QueryParser
    42  }
    43  
    44  func TestQueryParserSuite(t *testing.T) {
    45  	suite.Run(t, new(queryParserSuite))
    46  }
    47  
    48  func (s *queryParserSuite) SetupTest() {
    49  	s.Assertions = require.New(s.T())
    50  	s.parser = NewQueryParser()
    51  }
    52  
    53  func (s *queryParserSuite) TestParseWorkflowIDAndWorkflowTypeName() {
    54  	testCases := []struct {
    55  		query       string
    56  		expectErr   bool
    57  		parsedQuery *parsedQuery
    58  	}{
    59  		{
    60  			query:     "WorkflowId = \"random workflowID\"",
    61  			expectErr: false,
    62  			parsedQuery: &parsedQuery{
    63  				workflowID: convert.StringPtr("random workflowID"),
    64  			},
    65  		},
    66  		{
    67  			query:     "WorkflowTypeName = \"random workflowTypeName\"",
    68  			expectErr: false,
    69  			parsedQuery: &parsedQuery{
    70  				workflowTypeName: convert.StringPtr("random workflowTypeName"),
    71  			},
    72  		},
    73  		{
    74  			query:     "WorkflowId = \"random workflowID\" and WorkflowTypeName = \"random workflowTypeName\"",
    75  			expectErr: true,
    76  		},
    77  		{
    78  			query:     "WorkflowId = \"random workflowID\" and WorkflowId = \"random workflowID\"",
    79  			expectErr: true,
    80  		},
    81  		{
    82  			query:     "RunId = \"random runID\"",
    83  			expectErr: true,
    84  		},
    85  		{
    86  			query:     "WorkflowId = 'random workflowID'",
    87  			expectErr: false,
    88  			parsedQuery: &parsedQuery{
    89  				workflowID: convert.StringPtr("random workflowID"),
    90  			},
    91  		},
    92  		{
    93  			query:     "(WorkflowId = \"random workflowID\")",
    94  			expectErr: false,
    95  			parsedQuery: &parsedQuery{
    96  				workflowID: convert.StringPtr("random workflowID"),
    97  			},
    98  		},
    99  		{
   100  			query:     "runId = random workflowID",
   101  			expectErr: true,
   102  		},
   103  		{
   104  			query:     "WorkflowId = \"random workflowID\" or WorkflowId = \"another workflowID\"",
   105  			expectErr: true,
   106  		},
   107  		{
   108  			query:     "WorkflowId = \"random workflowID\" or runId = \"random runID\"",
   109  			expectErr: true,
   110  		},
   111  		{
   112  			query:     "workflowid = \"random workflowID\"",
   113  			expectErr: true,
   114  		},
   115  		{
   116  			query:     "runId > \"random workflowID\"",
   117  			expectErr: true,
   118  		},
   119  	}
   120  
   121  	for _, tc := range testCases {
   122  		parsedQuery, err := s.parser.Parse(tc.query)
   123  		if tc.expectErr {
   124  			s.Error(err)
   125  			continue
   126  		}
   127  		s.NoError(err)
   128  		s.Equal(tc.parsedQuery.workflowID, parsedQuery.workflowID)
   129  		s.Equal(tc.parsedQuery.workflowTypeName, parsedQuery.workflowTypeName)
   130  
   131  	}
   132  }
   133  
   134  func (s *queryParserSuite) TestParsePrecision() {
   135  	commonQueryPart := "WorkflowId = \"random workflowID\" AND "
   136  	testCases := []struct {
   137  		query       string
   138  		expectErr   bool
   139  		parsedQuery *parsedQuery
   140  	}{
   141  		{
   142  			query:     commonQueryPart + "CloseTime = 1000 and SearchPrecision = 'Day'",
   143  			expectErr: false,
   144  			parsedQuery: &parsedQuery{
   145  				searchPrecision: convert.StringPtr(PrecisionDay),
   146  			},
   147  		},
   148  		{
   149  			query:     commonQueryPart + "CloseTime = 1000 and SearchPrecision = 'Hour'",
   150  			expectErr: false,
   151  			parsedQuery: &parsedQuery{
   152  				searchPrecision: convert.StringPtr(PrecisionHour),
   153  			},
   154  		},
   155  		{
   156  			query:     commonQueryPart + "CloseTime = 1000 and SearchPrecision = 'Minute'",
   157  			expectErr: false,
   158  			parsedQuery: &parsedQuery{
   159  				searchPrecision: convert.StringPtr(PrecisionMinute),
   160  			},
   161  		},
   162  		{
   163  			query:     commonQueryPart + "StartTime = 1000 and SearchPrecision = 'Second'",
   164  			expectErr: false,
   165  			parsedQuery: &parsedQuery{
   166  				searchPrecision: convert.StringPtr(PrecisionSecond),
   167  			},
   168  		},
   169  		{
   170  			query:     commonQueryPart + "SearchPrecision = 'Second'",
   171  			expectErr: true,
   172  		},
   173  		{
   174  			query:     commonQueryPart + "SearchPrecision = 'Invalid string'",
   175  			expectErr: true,
   176  		},
   177  	}
   178  
   179  	for _, tc := range testCases {
   180  		parsedQuery, err := s.parser.Parse(tc.query)
   181  		if tc.expectErr {
   182  			s.Error(err)
   183  			continue
   184  		}
   185  		s.NoError(err)
   186  		s.Equal(tc.parsedQuery.searchPrecision, parsedQuery.searchPrecision)
   187  	}
   188  }
   189  
   190  func ptr[T any](v T) *T {
   191  	return &v
   192  }
   193  
   194  func (s *queryParserSuite) TestParseCloseTime() {
   195  	commonQueryPart := "WorkflowId = \"random workflowID\" AND SearchPrecision = 'Day' AND "
   196  
   197  	testCases := []struct {
   198  		query       string
   199  		expectErr   bool
   200  		parsedQuery *parsedQuery
   201  	}{
   202  		{
   203  			query:     commonQueryPart + "CloseTime = 1000",
   204  			expectErr: false,
   205  			parsedQuery: &parsedQuery{
   206  				closeTime: ptr(time.Unix(0, 1000).UTC()),
   207  			},
   208  		},
   209  		{
   210  			query:     commonQueryPart + "CloseTime = \"2019-01-01T11:11:11Z\"",
   211  			expectErr: false,
   212  			parsedQuery: &parsedQuery{
   213  				closeTime: ptr(time.Date(2019, 1, 1, 11, 11, 11, 0, time.UTC)),
   214  			},
   215  		},
   216  		{
   217  			query:     commonQueryPart + "closeTime = 2000",
   218  			expectErr: true,
   219  		},
   220  		{
   221  			query:     commonQueryPart + "CloseTime > \"2019-01-01 00:00:00\"",
   222  			expectErr: true,
   223  		},
   224  	}
   225  
   226  	for _, tc := range testCases {
   227  		parsedQuery, err := s.parser.Parse(tc.query)
   228  		if tc.expectErr {
   229  			s.Error(err)
   230  			continue
   231  		}
   232  		s.NoError(err)
   233  		s.Equal(tc.parsedQuery.closeTime, parsedQuery.closeTime)
   234  
   235  	}
   236  }
   237  
   238  func (s *queryParserSuite) TestParseStartTime() {
   239  	commonQueryPart := "WorkflowId = \"random workflowID\" AND SearchPrecision = 'Day' AND "
   240  
   241  	testCases := []struct {
   242  		query       string
   243  		expectErr   bool
   244  		parsedQuery *parsedQuery
   245  	}{
   246  		{
   247  			query:     commonQueryPart + "StartTime = 1000",
   248  			expectErr: false,
   249  			parsedQuery: &parsedQuery{
   250  				startTime: ptr(time.Unix(0, 1000)),
   251  			},
   252  		},
   253  		{
   254  			query:     commonQueryPart + "StartTime = \"2019-01-01T11:11:11Z\"",
   255  			expectErr: false,
   256  			parsedQuery: &parsedQuery{
   257  				startTime: ptr(time.Date(2019, 1, 1, 11, 11, 11, 0, time.UTC)),
   258  			},
   259  		},
   260  		{
   261  			query:     commonQueryPart + "startTime = 2000",
   262  			expectErr: true,
   263  		},
   264  		{
   265  			query:     commonQueryPart + "StartTime > \"2019-01-01 00:00:00\"",
   266  			expectErr: true,
   267  		},
   268  	}
   269  
   270  	for _, tc := range testCases {
   271  		parsedQuery, err := s.parser.Parse(tc.query)
   272  		if tc.expectErr {
   273  			s.Error(err)
   274  			continue
   275  		}
   276  		s.NoError(err)
   277  		s.Equal(tc.parsedQuery.closeTime, parsedQuery.closeTime)
   278  	}
   279  }