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 }