go.temporal.io/server@v1.23.0/common/searchattribute/validator_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 searchattribute 26 27 import ( 28 "testing" 29 30 "github.com/golang/mock/gomock" 31 "github.com/stretchr/testify/suite" 32 commonpb "go.temporal.io/api/common/v1" 33 34 "go.temporal.io/server/common/dynamicconfig" 35 "go.temporal.io/server/common/payload" 36 "go.temporal.io/server/common/persistence/visibility/manager" 37 ) 38 39 type searchAttributesValidatorSuite struct { 40 suite.Suite 41 42 mockVisibilityManager *manager.MockVisibilityManager 43 } 44 45 func TestSearchAttributesValidatorSuite(t *testing.T) { 46 ctrl := gomock.NewController(t) 47 s := &searchAttributesValidatorSuite{ 48 mockVisibilityManager: manager.NewMockVisibilityManager(ctrl), 49 } 50 s.mockVisibilityManager.EXPECT().GetIndexName().Return("").AnyTimes() 51 s.mockVisibilityManager.EXPECT(). 52 ValidateCustomSearchAttributes(gomock.Any()). 53 DoAndReturn( 54 func(searchAttributes map[string]any) (map[string]any, error) { 55 return searchAttributes, nil 56 }, 57 ). 58 AnyTimes() 59 suite.Run(t, s) 60 } 61 62 func (s *searchAttributesValidatorSuite) TestSearchAttributesValidate() { 63 numOfKeysLimit := 2 64 sizeOfValueLimit := 5 65 sizeOfTotalLimit := 20 66 67 saValidator := NewValidator( 68 NewTestProvider(), 69 NewTestMapperProvider(nil), 70 dynamicconfig.GetIntPropertyFilteredByNamespace(numOfKeysLimit), 71 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfValueLimit), 72 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfTotalLimit), 73 s.mockVisibilityManager, 74 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(true), 75 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 76 ) 77 78 namespace := "namespace" 79 var attr *commonpb.SearchAttributes 80 81 err := saValidator.Validate(attr, namespace) 82 s.NoError(err) 83 84 intPayload, err := payload.Encode(1) 85 s.NoError(err) 86 fields := map[string]*commonpb.Payload{ 87 "CustomIntField": intPayload, 88 } 89 attr = &commonpb.SearchAttributes{ 90 IndexedFields: fields, 91 } 92 err = saValidator.Validate(attr, namespace) 93 s.NoError(err) 94 95 fields = map[string]*commonpb.Payload{ 96 "CustomIntField": intPayload, 97 "CustomKeywordField": payload.EncodeString("keyword"), 98 "CustomBoolField": payload.EncodeString("true"), 99 } 100 attr.IndexedFields = fields 101 err = saValidator.Validate(attr, namespace) 102 s.Error(err) 103 s.Equal("number of search attributes 3 exceeds limit 2", err.Error()) 104 105 fields = map[string]*commonpb.Payload{ 106 "InvalidKey": payload.EncodeString("1"), 107 } 108 attr.IndexedFields = fields 109 err = saValidator.Validate(attr, namespace) 110 s.Error(err) 111 s.Equal("search attribute InvalidKey is not defined", err.Error()) 112 113 fields = map[string]*commonpb.Payload{ 114 "CustomTextField": payload.EncodeString("1"), 115 "CustomBoolField": payload.EncodeString("123"), 116 } 117 attr.IndexedFields = fields 118 err = saValidator.Validate(attr, namespace) 119 s.Error(err) 120 s.Equal("invalid value for search attribute CustomBoolField of type Bool: 123", err.Error()) 121 122 intArrayPayload, err := payload.Encode([]int{1, 2}) 123 s.NoError(err) 124 fields = map[string]*commonpb.Payload{ 125 "CustomIntField": intArrayPayload, 126 } 127 attr.IndexedFields = fields 128 err = saValidator.Validate(attr, namespace) 129 s.NoError(err) 130 131 fields = map[string]*commonpb.Payload{ 132 "StartTime": intPayload, 133 } 134 attr.IndexedFields = fields 135 err = saValidator.Validate(attr, namespace) 136 s.Error(err) 137 s.Equal("StartTime attribute can't be set in SearchAttributes", err.Error()) 138 } 139 140 func (s *searchAttributesValidatorSuite) TestSearchAttributesValidate_SuppressError() { 141 numOfKeysLimit := 2 142 sizeOfValueLimit := 5 143 sizeOfTotalLimit := 20 144 145 saValidator := NewValidator( 146 NewTestProvider(), 147 NewTestMapperProvider(nil), 148 dynamicconfig.GetIntPropertyFilteredByNamespace(numOfKeysLimit), 149 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfValueLimit), 150 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfTotalLimit), 151 s.mockVisibilityManager, 152 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 153 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(true), 154 ) 155 156 namespace := "namespace" 157 attr := &commonpb.SearchAttributes{ 158 IndexedFields: map[string]*commonpb.Payload{ 159 "ParentWorkflowId": payload.EncodeString("foo"), 160 }, 161 } 162 163 err := saValidator.Validate(attr, namespace) 164 s.NoError(err) 165 } 166 167 func (s *searchAttributesValidatorSuite) TestSearchAttributesValidate_Mapper() { 168 numOfKeysLimit := 2 169 sizeOfValueLimit := 5 170 sizeOfTotalLimit := 20 171 172 saValidator := NewValidator( 173 NewTestProvider(), 174 NewTestMapperProvider(&TestMapper{}), 175 dynamicconfig.GetIntPropertyFilteredByNamespace(numOfKeysLimit), 176 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfValueLimit), 177 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfTotalLimit), 178 s.mockVisibilityManager, 179 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 180 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 181 ) 182 183 namespace := "test-namespace" 184 var attr *commonpb.SearchAttributes 185 186 err := saValidator.Validate(attr, namespace) 187 s.Nil(err) 188 189 intPayload, err := payload.Encode(1) 190 s.NoError(err) 191 fields := map[string]*commonpb.Payload{ 192 "CustomIntField": intPayload, 193 } 194 attr = &commonpb.SearchAttributes{ 195 IndexedFields: fields, 196 } 197 err = saValidator.Validate(attr, namespace) 198 s.NoError(err) 199 200 fields = map[string]*commonpb.Payload{ 201 "CustomIntField": intPayload, 202 } 203 attr = &commonpb.SearchAttributes{ 204 IndexedFields: fields, 205 } 206 err = saValidator.Validate(attr, "test-namespace") 207 s.NoError(err) 208 209 fields = map[string]*commonpb.Payload{ 210 "InvalidKey": payload.EncodeString("1"), 211 } 212 attr.IndexedFields = fields 213 err = saValidator.Validate(attr, namespace) 214 s.Error(err) 215 s.Equal("search attribute AliasForInvalidKey is not defined", err.Error()) 216 217 err = saValidator.Validate(attr, "error-namespace") 218 s.Error(err) 219 s.EqualError(err, "mapper error") 220 221 fields = map[string]*commonpb.Payload{ 222 "CustomTextField": payload.EncodeString("1"), 223 "CustomBoolField": payload.EncodeString("123"), 224 } 225 attr.IndexedFields = fields 226 err = saValidator.Validate(attr, namespace) 227 s.Error(err) 228 s.Equal("invalid value for search attribute AliasForCustomBoolField of type Bool: 123", err.Error()) 229 } 230 231 func (s *searchAttributesValidatorSuite) TestSearchAttributesValidateSize() { 232 numOfKeysLimit := 2 233 sizeOfValueLimit := 5 234 sizeOfTotalLimit := 20 235 236 saValidator := NewValidator( 237 NewTestProvider(), 238 NewTestMapperProvider(nil), 239 dynamicconfig.GetIntPropertyFilteredByNamespace(numOfKeysLimit), 240 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfValueLimit), 241 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfTotalLimit), 242 s.mockVisibilityManager, 243 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 244 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 245 ) 246 247 namespace := "namespace" 248 249 fields := map[string]*commonpb.Payload{ 250 "CustomKeywordField": payload.EncodeString("123456"), 251 } 252 attr := &commonpb.SearchAttributes{ 253 IndexedFields: fields, 254 } 255 256 attr.IndexedFields = fields 257 err := saValidator.ValidateSize(attr, namespace) 258 s.Error(err) 259 s.Equal("search attribute CustomKeywordField value size 8 exceeds size limit 5", err.Error()) 260 261 fields = map[string]*commonpb.Payload{ 262 "CustomKeywordField": payload.EncodeString("123"), 263 "CustomTextField": payload.EncodeString("12"), 264 } 265 attr.IndexedFields = fields 266 err = saValidator.ValidateSize(attr, namespace) 267 s.Error(err) 268 s.Equal("total size of search attributes 106 exceeds size limit 20", err.Error()) 269 } 270 271 func (s *searchAttributesValidatorSuite) TestSearchAttributesValidateSize_Mapper() { 272 numOfKeysLimit := 2 273 sizeOfValueLimit := 5 274 sizeOfTotalLimit := 20 275 276 saValidator := NewValidator( 277 NewTestProvider(), 278 NewTestMapperProvider(&TestMapper{}), 279 dynamicconfig.GetIntPropertyFilteredByNamespace(numOfKeysLimit), 280 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfValueLimit), 281 dynamicconfig.GetIntPropertyFilteredByNamespace(sizeOfTotalLimit), 282 s.mockVisibilityManager, 283 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 284 dynamicconfig.GetBoolPropertyFnFilteredByNamespace(false), 285 ) 286 287 namespace := "test-namespace" 288 289 fields := map[string]*commonpb.Payload{ 290 "CustomKeywordField": payload.EncodeString("123456"), 291 } 292 attr := &commonpb.SearchAttributes{ 293 IndexedFields: fields, 294 } 295 296 attr.IndexedFields = fields 297 err := saValidator.ValidateSize(attr, namespace) 298 s.Error(err) 299 s.Equal("search attribute AliasForCustomKeywordField value size 8 exceeds size limit 5", err.Error()) 300 301 fields = map[string]*commonpb.Payload{ 302 "CustomKeywordField": payload.EncodeString("123"), 303 "CustomTextField": payload.EncodeString("12"), 304 } 305 attr.IndexedFields = fields 306 err = saValidator.ValidateSize(attr, namespace) 307 s.Error(err) 308 s.Equal("total size of search attributes 106 exceeds size limit 20", err.Error()) 309 }