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  }