go.temporal.io/server@v1.23.0/common/searchattribute/encode_value_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 "errors" 29 "testing" 30 "time" 31 32 "github.com/stretchr/testify/assert" 33 enumspb "go.temporal.io/api/enums/v1" 34 "go.temporal.io/sdk/converter" 35 36 "go.temporal.io/server/common/payload" 37 ) 38 39 func Test_DecodeValue_AllowList_FromMetadata_Success(t *testing.T) { 40 s := assert.New(t) 41 allowList := true 42 43 payloadStr := payload.EncodeString("qwe") 44 payloadStr.Metadata["type"] = []byte("Text") 45 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) // MetadataType is used. 46 s.NoError(err) 47 s.Equal("qwe", decodedStr) 48 49 payloadBool, err := payload.Encode(true) 50 s.NoError(err) 51 payloadBool.Metadata["type"] = []byte("Bool") 52 decodedBool, err := DecodeValue(payloadBool, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) // MetadataType is used. 53 s.NoError(err) 54 s.Equal(true, decodedBool) 55 56 payloadNil, err := payload.Encode(nil) 57 s.NoError(err) 58 payloadNil.Metadata["type"] = []byte("Double") 59 decodedNil, err := DecodeValue(payloadNil, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 60 s.NoError(err) 61 s.Nil(decodedNil) 62 63 payloadSlice, err := payload.Encode([]string{"val1", "val2"}) 64 s.NoError(err) 65 payloadSlice.Metadata["type"] = []byte("Keyword") 66 decodedSlice, err := DecodeValue(payloadSlice, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 67 s.NoError(err) 68 s.Equal([]string{"val1", "val2"}, decodedSlice) 69 70 payloadEmptySlice, err := payload.Encode([]string{}) 71 s.NoError(err) 72 payloadEmptySlice.Metadata["type"] = []byte("Keyword") 73 decodedNil, err = DecodeValue(payloadEmptySlice, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 74 s.NoError(err) 75 s.Nil(decodedNil) 76 77 var expectedEncodedRepresentation = "2022-03-07T21:27:35.986848-05:00" 78 timeValue, err := time.Parse(time.RFC3339, expectedEncodedRepresentation) 79 s.NoError(err) 80 payloadDatetime, err := payload.Encode(timeValue) 81 s.NoError(err) 82 payloadDatetime.Metadata["type"] = []byte("Datetime") 83 decodedDatetime, err := DecodeValue(payloadDatetime, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 84 s.NoError(err) 85 s.Equal(timeValue, decodedDatetime) 86 } 87 88 func Test_DecodeValue_AllowList_FromParameter_Success(t *testing.T) { 89 s := assert.New(t) 90 allowList := true 91 92 payloadStr := payload.EncodeString("qwe") 93 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_TEXT, allowList) 94 s.NoError(err) 95 s.Equal("qwe", decodedStr) 96 97 payloadInt, err := payload.Encode(123) 98 s.NoError(err) 99 decodedInt, err := DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 100 s.NoError(err) 101 s.Equal(int64(123), decodedInt) 102 103 payloadNil, err := payload.Encode(nil) 104 s.NoError(err) 105 decodedNil, err := DecodeValue(payloadNil, enumspb.INDEXED_VALUE_TYPE_DOUBLE, allowList) 106 s.NoError(err) 107 s.Nil(decodedNil) 108 109 payloadSlice, err := payload.Encode([]string{"val1", "val2"}) 110 s.NoError(err) 111 decodedSlice, err := DecodeValue(payloadSlice, enumspb.INDEXED_VALUE_TYPE_KEYWORD, allowList) 112 s.NoError(err) 113 s.Equal([]string{"val1", "val2"}, decodedSlice) 114 115 payloadEmptySlice, err := payload.Encode([]string{}) 116 s.NoError(err) 117 decodedNil, err = DecodeValue(payloadEmptySlice, enumspb.INDEXED_VALUE_TYPE_KEYWORD, allowList) 118 s.NoError(err) 119 s.Nil(decodedNil) 120 121 var expectedEncodedRepresentation = "2022-03-07T21:27:35.986848-05:00" 122 timeValue, err := time.Parse(time.RFC3339, expectedEncodedRepresentation) 123 s.NoError(err) 124 payloadDatetime, err := payload.Encode(timeValue) 125 s.NoError(err) 126 decodedDatetime, err := DecodeValue(payloadDatetime, enumspb.INDEXED_VALUE_TYPE_DATETIME, allowList) 127 s.NoError(err) 128 s.Equal(timeValue, decodedDatetime) 129 130 payloadInt, err = payload.Encode(123) 131 s.NoError(err) 132 payloadInt.Metadata["type"] = []byte("String") // MetadataType is not used. 133 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 134 s.NoError(err) 135 s.Equal(int64(123), decodedInt) 136 137 payloadInt, err = payload.Encode(123) 138 s.NoError(err) 139 payloadInt.Metadata["type"] = []byte("UnknownType") // MetadataType is not used. 140 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 141 s.NoError(err) 142 s.Equal(int64(123), decodedInt) 143 144 payloadBool, err := payload.Encode(true) 145 s.NoError(err) 146 decodedBool, err := DecodeValue(payloadBool, enumspb.INDEXED_VALUE_TYPE_BOOL, allowList) 147 s.NoError(err) 148 s.Equal(true, decodedBool) 149 } 150 151 func Test_DecodeValue_AllowList_Error(t *testing.T) { 152 s := assert.New(t) 153 allowList := true 154 155 payloadStr := payload.EncodeString("qwe") 156 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 157 s.Error(err) 158 s.ErrorIs(err, ErrInvalidType) 159 s.Nil(decodedStr) 160 161 payloadInt, err := payload.Encode(123) 162 s.NoError(err) 163 payloadInt.Metadata["type"] = []byte("UnknownType") 164 decodedInt, err := DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 165 s.Error(err) 166 s.ErrorIs(err, ErrInvalidType) 167 s.Nil(decodedInt) 168 169 payloadInt, err = payload.Encode(123) 170 s.NoError(err) 171 payloadInt.Metadata["type"] = []byte("Text") 172 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 173 s.Error(err) 174 s.ErrorIs(err, converter.ErrUnableToDecode, err.Error()) 175 s.Nil(decodedInt) 176 } 177 178 func Test_DecodeValue_NotAllowList_FromMetadata_Success(t *testing.T) { 179 s := assert.New(t) 180 allowList := false 181 182 payloadStr := payload.EncodeString("qwe") 183 payloadStr.Metadata["type"] = []byte("Text") 184 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 185 s.NoError(err) 186 s.Equal("qwe", decodedStr) 187 188 payloadBool, err := payload.Encode(true) 189 s.NoError(err) 190 payloadBool.Metadata["type"] = []byte("Bool") 191 decodedBool, err := DecodeValue(payloadBool, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 192 s.NoError(err) 193 s.Equal(true, decodedBool) 194 195 payloadNil, err := payload.Encode(nil) 196 s.NoError(err) 197 payloadNil.Metadata["type"] = []byte("Double") 198 decodedNil, err := DecodeValue(payloadNil, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 199 s.NoError(err) 200 s.Nil(decodedNil) 201 202 payloadKeyword, err := payload.Encode([]string{"Keyword"}) 203 s.NoError(err) 204 payloadKeyword.Metadata["type"] = []byte("Keyword") 205 decodedKeyword, err := DecodeValue(payloadKeyword, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 206 s.NoError(err) 207 s.Equal("Keyword", decodedKeyword) 208 209 payloadSlice, err := payload.Encode([]string{"val1", "val2"}) 210 s.NoError(err) 211 payloadSlice.Metadata["type"] = []byte("KeywordList") 212 decodedSlice, err := DecodeValue(payloadSlice, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 213 s.NoError(err) 214 s.Equal([]string{"val1", "val2"}, decodedSlice) 215 216 payloadEmptySlice, err := payload.Encode([]string{}) 217 s.NoError(err) 218 payloadEmptySlice.Metadata["type"] = []byte("Keyword") 219 decodedNil, err = DecodeValue(payloadEmptySlice, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 220 s.NoError(err) 221 s.Nil(decodedNil) 222 223 var expectedEncodedRepresentation = "2022-03-07T21:27:35.986848-05:00" 224 timeValue, err := time.Parse(time.RFC3339, expectedEncodedRepresentation) 225 s.NoError(err) 226 payloadDatetime, err := payload.Encode(timeValue) 227 s.NoError(err) 228 payloadDatetime.Metadata["type"] = []byte("Datetime") 229 decodedDatetime, err := DecodeValue(payloadDatetime, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 230 s.NoError(err) 231 s.Equal(timeValue, decodedDatetime) 232 } 233 234 func Test_DecodeValue_NotAllowList_FromParameter_Success(t *testing.T) { 235 s := assert.New(t) 236 allowList := false 237 238 payloadStr := payload.EncodeString("qwe") 239 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_TEXT, allowList) 240 s.NoError(err) 241 s.Equal("qwe", decodedStr) 242 243 payloadInt, err := payload.Encode(123) 244 s.NoError(err) 245 decodedInt, err := DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 246 s.NoError(err) 247 s.Equal(int64(123), decodedInt) 248 249 payloadNil, err := payload.Encode(nil) 250 s.NoError(err) 251 decodedNil, err := DecodeValue(payloadNil, enumspb.INDEXED_VALUE_TYPE_DOUBLE, allowList) 252 s.NoError(err) 253 s.Nil(decodedNil) 254 255 payloadKeyword, err := payload.Encode([]string{"Keyword"}) 256 s.NoError(err) 257 decodedKeyword, err := DecodeValue(payloadKeyword, enumspb.INDEXED_VALUE_TYPE_KEYWORD, allowList) 258 s.NoError(err) 259 s.Equal("Keyword", decodedKeyword) 260 261 payloadSlice, err := payload.Encode([]string{"val1", "val2"}) 262 s.NoError(err) 263 decodedSlice, err := DecodeValue(payloadSlice, enumspb.INDEXED_VALUE_TYPE_KEYWORD_LIST, allowList) 264 s.NoError(err) 265 s.Equal([]string{"val1", "val2"}, decodedSlice) 266 267 payloadEmptySlice, err := payload.Encode([]string{}) 268 s.NoError(err) 269 decodedNil, err = DecodeValue(payloadEmptySlice, enumspb.INDEXED_VALUE_TYPE_KEYWORD, allowList) 270 s.NoError(err) 271 s.Nil(decodedNil) 272 273 var expectedEncodedRepresentation = "2022-03-07T21:27:35.986848-05:00" 274 timeValue, err := time.Parse(time.RFC3339, expectedEncodedRepresentation) 275 s.NoError(err) 276 payloadDatetime, err := payload.Encode(timeValue) 277 s.NoError(err) 278 decodedDatetime, err := DecodeValue(payloadDatetime, enumspb.INDEXED_VALUE_TYPE_DATETIME, allowList) 279 s.NoError(err) 280 s.Equal(timeValue, decodedDatetime) 281 282 payloadInt, err = payload.Encode(123) 283 s.NoError(err) 284 payloadInt.Metadata["type"] = []byte("String") // MetadataType is not used. 285 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 286 s.NoError(err) 287 s.Equal(int64(123), decodedInt) 288 289 payloadInt, err = payload.Encode(123) 290 s.NoError(err) 291 payloadInt.Metadata["type"] = []byte("UnknownType") // MetadataType is not used. 292 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_INT, allowList) 293 s.NoError(err) 294 s.Equal(int64(123), decodedInt) 295 296 payloadBool, err := payload.Encode(true) 297 s.NoError(err) 298 decodedBool, err := DecodeValue(payloadBool, enumspb.INDEXED_VALUE_TYPE_BOOL, allowList) 299 s.NoError(err) 300 s.Equal(true, decodedBool) 301 } 302 303 func Test_DecodeValue_NotAllowList_Error(t *testing.T) { 304 s := assert.New(t) 305 allowList := false 306 307 payloadStr := payload.EncodeString("qwe") 308 decodedStr, err := DecodeValue(payloadStr, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 309 s.Error(err) 310 s.ErrorIs(err, ErrInvalidType) 311 s.Nil(decodedStr) 312 313 payloadInt, err := payload.Encode(123) 314 s.NoError(err) 315 payloadInt.Metadata["type"] = []byte("UnknownType") 316 decodedInt, err := DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 317 s.Error(err) 318 s.ErrorIs(err, ErrInvalidType) 319 s.Nil(decodedInt) 320 321 payloadInt, err = payload.Encode(123) 322 s.NoError(err) 323 payloadInt.Metadata["type"] = []byte("Text") 324 decodedInt, err = DecodeValue(payloadInt, enumspb.INDEXED_VALUE_TYPE_UNSPECIFIED, allowList) 325 s.Error(err) 326 s.ErrorIs(err, converter.ErrUnableToDecode, err.Error()) 327 s.Nil(decodedInt) 328 329 payloadSlice, err := payload.Encode([]string{"val1", "val2"}) 330 s.NoError(err) 331 decodedSlice, err := DecodeValue(payloadSlice, enumspb.INDEXED_VALUE_TYPE_KEYWORD, allowList) 332 s.Error(err) 333 s.Nil(decodedSlice) 334 } 335 336 func Test_EncodeValue(t *testing.T) { 337 s := assert.New(t) 338 339 encodedPayload, err := EncodeValue(123, enumspb.INDEXED_VALUE_TYPE_INT) 340 s.NoError(err) 341 s.Equal("123", string(encodedPayload.GetData())) 342 s.Equal("Int", string(encodedPayload.Metadata["type"])) 343 344 encodedPayload, err = EncodeValue("qwe", enumspb.INDEXED_VALUE_TYPE_TEXT) 345 s.NoError(err) 346 s.Equal(`"qwe"`, string(encodedPayload.GetData())) 347 s.Equal("Text", string(encodedPayload.Metadata["type"])) 348 349 encodedPayload, err = EncodeValue(nil, enumspb.INDEXED_VALUE_TYPE_DOUBLE) 350 s.NoError(err) 351 s.Equal("", string(encodedPayload.GetData())) 352 s.Equal("Double", string(encodedPayload.Metadata["type"])) 353 s.Equal("binary/null", string(encodedPayload.Metadata["encoding"])) 354 355 encodedPayload, err = EncodeValue([]string{"val1", "val2"}, enumspb.INDEXED_VALUE_TYPE_KEYWORD) 356 s.NoError(err) 357 s.Equal(`["val1","val2"]`, string(encodedPayload.GetData())) 358 s.Equal("Keyword", string(encodedPayload.Metadata["type"])) 359 s.Equal("json/plain", string(encodedPayload.Metadata["encoding"])) 360 361 encodedPayload, err = EncodeValue([]string{}, enumspb.INDEXED_VALUE_TYPE_KEYWORD) 362 s.NoError(err) 363 s.Equal("[]", string(encodedPayload.GetData())) 364 s.Equal("Keyword", string(encodedPayload.Metadata["type"])) 365 s.Equal("json/plain", string(encodedPayload.Metadata["encoding"])) 366 367 var expectedEncodedRepresentation = "2022-03-07T21:27:35.986848-05:00" 368 timeValue, err := time.Parse(time.RFC3339, expectedEncodedRepresentation) 369 s.NoError(err) 370 encodedPayload, err = EncodeValue(timeValue, enumspb.INDEXED_VALUE_TYPE_DATETIME) 371 s.NoError(err) 372 s.Equal(`"`+expectedEncodedRepresentation+`"`, string(encodedPayload.GetData()), 373 "Datetime Search Attribute is expected to be encoded in RFC 3339 format") 374 s.Equal("Datetime", string(encodedPayload.Metadata["type"])) 375 } 376 377 func Test_ValidateStrings(t *testing.T) { 378 _, err := validateStrings("anything here", errors.New("test error")) 379 assert.Error(t, err) 380 assert.Contains(t, err.Error(), "test error") 381 382 _, err = validateStrings("\x87\x01", nil) 383 assert.Error(t, err) 384 assert.Contains(t, err.Error(), "is not a valid UTF-8 string") 385 386 value, err := validateStrings("anything here", nil) 387 assert.Nil(t, err) 388 assert.Equal(t, "anything here", value) 389 390 _, err = validateStrings([]string{"abc", "\x87\x01"}, nil) 391 assert.Error(t, err) 392 assert.Contains(t, err.Error(), "is not a valid UTF-8 string") 393 }