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  }