github.com/openfga/openfga@v1.5.4-rc1/internal/condition/condition_test.go (about)

     1  package condition_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	openfgav1 "github.com/openfga/api/proto/openfga/v1"
    11  	"github.com/stretchr/testify/require"
    12  	"google.golang.org/protobuf/types/known/structpb"
    13  
    14  	"github.com/openfga/openfga/internal/condition"
    15  	"github.com/openfga/openfga/internal/condition/types"
    16  )
    17  
    18  func TestNewCompiled(t *testing.T) {
    19  	var tests = []struct {
    20  		name      string
    21  		condition *openfgav1.Condition
    22  		err       *condition.CompilationError
    23  	}{
    24  		{
    25  			name: "valid",
    26  			condition: &openfgav1.Condition{
    27  				Name:       "condition1",
    28  				Expression: "param1 == 'ok'",
    29  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
    30  					"param1": {
    31  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
    32  					},
    33  				},
    34  			},
    35  			err: nil,
    36  		},
    37  		{
    38  			name: "invalid_parameter_type",
    39  			condition: &openfgav1.Condition{
    40  				Name:       "condition1",
    41  				Expression: "param1 == 'ok'",
    42  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
    43  					"param1": {
    44  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_UNSPECIFIED,
    45  					},
    46  				},
    47  			},
    48  			err: &condition.CompilationError{
    49  				Condition: "condition1",
    50  				Cause:     fmt.Errorf("failed to decode parameter type for parameter 'param1': unknown condition parameter type `TYPE_NAME_UNSPECIFIED`"),
    51  			},
    52  		},
    53  		{
    54  			name: "invalid_expression",
    55  			condition: &openfgav1.Condition{
    56  				Name:       "condition1",
    57  				Expression: "invalid",
    58  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
    59  					"param1": {
    60  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
    61  					},
    62  				},
    63  			},
    64  			err: &condition.CompilationError{
    65  				Condition: "condition1",
    66  				Cause:     fmt.Errorf("ERROR: condition1:1:1: undeclared reference to 'invalid' (in container '')\n | invalid\n | ^"),
    67  			},
    68  		},
    69  		{
    70  			name: "invalid_output_type",
    71  			condition: &openfgav1.Condition{
    72  				Name:       "condition1",
    73  				Expression: "param1",
    74  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
    75  					"param1": {
    76  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
    77  					},
    78  				},
    79  			},
    80  			err: &condition.CompilationError{
    81  				Condition: "condition1",
    82  				Cause:     fmt.Errorf("expected a bool condition expression output, but got 'string'"),
    83  			},
    84  		},
    85  		{
    86  			name: "ipaddress_literal_malformed_bool",
    87  			condition: &openfgav1.Condition{
    88  				Name:       "condition1",
    89  				Expression: `ipaddress(true).in_cidr("192.168.0.0/24")`,
    90  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{},
    91  			},
    92  			err: &condition.CompilationError{
    93  				Condition: "condition1",
    94  				Cause:     fmt.Errorf("ERROR: condition1:1:10: found no matching overload for 'ipaddress' applied to '(bool)'\n | ipaddress(true).in_cidr(\"192.168.0.0/24\")\n | .........^"),
    95  			},
    96  		},
    97  	}
    98  
    99  	for _, test := range tests {
   100  		t.Run(test.name, func(t *testing.T) {
   101  			_, err := condition.NewCompiled(test.condition)
   102  
   103  			if test.err != nil {
   104  				require.EqualError(t, err, test.err.Error())
   105  			} else {
   106  				require.NoError(t, err)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  func TestEvaluate(t *testing.T) {
   113  	var tests = []struct {
   114  		name      string
   115  		condition *openfgav1.Condition
   116  		context   map[string]interface{}
   117  		result    condition.EvaluationResult
   118  		err       *condition.EvaluationError
   119  	}{
   120  		{
   121  			name: "success_condition_met",
   122  			condition: &openfgav1.Condition{
   123  				Name:       "condition1",
   124  				Expression: "param1 == 'ok'",
   125  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   126  					"param1": {
   127  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   128  					},
   129  				},
   130  			},
   131  			context: map[string]interface{}{
   132  				"param1": "ok",
   133  			},
   134  			result: condition.EvaluationResult{ConditionMet: true},
   135  		},
   136  		{
   137  			name: "success_condition_unmet",
   138  			condition: &openfgav1.Condition{
   139  				Name:       "condition1",
   140  				Expression: "param1 == 'ok'",
   141  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   142  					"param1": {
   143  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   144  					},
   145  				},
   146  			},
   147  			context: map[string]interface{}{"param1": "notok"},
   148  			result:  condition.EvaluationResult{ConditionMet: false},
   149  		},
   150  		{
   151  			name: "fail_no_such_attribute_nil_context",
   152  			condition: &openfgav1.Condition{
   153  				Name:       "condition1",
   154  				Expression: "param1 == 'ok'",
   155  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   156  					"param1": {
   157  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   158  					},
   159  				},
   160  			},
   161  			context: nil,
   162  			result: condition.EvaluationResult{
   163  				ConditionMet:      false,
   164  				MissingParameters: []string{"param1"},
   165  			},
   166  		},
   167  		{
   168  			name: "fail_no_such_attribute_empty_context",
   169  			condition: &openfgav1.Condition{
   170  				Name:       "condition1",
   171  				Expression: "param1 == 'ok'",
   172  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   173  					"param1": {
   174  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   175  					},
   176  				},
   177  			},
   178  			context: map[string]interface{}{},
   179  			result: condition.EvaluationResult{
   180  				ConditionMet:      false,
   181  				MissingParameters: []string{"param1"},
   182  			},
   183  		},
   184  		{
   185  			name: "fail_found_invalid_context_parameter",
   186  			condition: &openfgav1.Condition{
   187  				Name:       "condition1",
   188  				Expression: "param1 == 'ok'",
   189  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   190  					"param1": {
   191  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   192  					},
   193  				},
   194  			},
   195  			context: map[string]interface{}{
   196  				"param2": "ok",
   197  			},
   198  			result: condition.EvaluationResult{
   199  				ConditionMet:      false,
   200  				MissingParameters: []string{"param1"},
   201  			},
   202  		},
   203  		{
   204  			name: "fail_unexpected_type",
   205  			condition: &openfgav1.Condition{
   206  				Name:       "condition1",
   207  				Expression: "param1 == 'ok'",
   208  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   209  					"param1": {
   210  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   211  					},
   212  				},
   213  			},
   214  			context: map[string]interface{}{
   215  				"param1": true,
   216  			},
   217  			result: condition.EvaluationResult{ConditionMet: false},
   218  			err: &condition.EvaluationError{
   219  				Condition: "condition1",
   220  				Cause: &condition.ParameterTypeError{
   221  					Condition: "condition1",
   222  					Cause:     fmt.Errorf("failed to convert context parameter 'param1': expected type value 'string', but found 'bool'"),
   223  				},
   224  			},
   225  		},
   226  		{
   227  			name: "ipaddress_literal",
   228  			condition: &openfgav1.Condition{
   229  				Name:       "condition1",
   230  				Expression: `ipaddress("192.168.0.1").in_cidr("192.168.0.0/24")`,
   231  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{},
   232  			},
   233  			context: map[string]interface{}{},
   234  			result:  condition.EvaluationResult{ConditionMet: true},
   235  		},
   236  		{
   237  			name: "ipaddress_literal_malformed_addr",
   238  			condition: &openfgav1.Condition{
   239  				Name:       "condition1",
   240  				Expression: `ipaddress("192.168.0").in_cidr("192.168.0.0/24")`,
   241  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{},
   242  			},
   243  			context: map[string]interface{}{},
   244  			result:  condition.EvaluationResult{ConditionMet: false},
   245  			err: &condition.EvaluationError{
   246  				Condition: "condition1",
   247  				Cause:     fmt.Errorf("failed to evaluate condition expression: ParseAddr(\"192.168.0\"): IPv4 address too short"),
   248  			},
   249  		},
   250  	}
   251  
   252  	for _, test := range tests {
   253  		t.Run(test.name, func(t *testing.T) {
   254  			ctx := context.Background()
   255  			compiledCondition, err := condition.NewCompiled(test.condition)
   256  			require.NoError(t, err)
   257  
   258  			contextStruct, err := structpb.NewStruct(test.context)
   259  			require.NoError(t, err)
   260  
   261  			result, err := compiledCondition.Evaluate(ctx, contextStruct.GetFields())
   262  
   263  			require.Equal(t, test.result, result)
   264  			if test.err != nil {
   265  				var evalError *condition.EvaluationError
   266  				require.ErrorAs(t, err, &evalError)
   267  				require.EqualError(t, evalError, test.err.Error())
   268  			} else {
   269  				require.NoError(t, err)
   270  			}
   271  		})
   272  	}
   273  }
   274  
   275  func TestEvaluateWithMaxCost(t *testing.T) {
   276  	var tests = []struct {
   277  		name      string
   278  		condition *openfgav1.Condition
   279  		context   map[string]any
   280  		maxCost   uint64
   281  		result    condition.EvaluationResult
   282  		err       error
   283  	}{
   284  		{
   285  			name: "cost_exceeded_int",
   286  			condition: &openfgav1.Condition{
   287  				Name:       "condition1",
   288  				Expression: "x < y",
   289  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   290  					"x": {
   291  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   292  					},
   293  					"y": {
   294  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   295  					},
   296  				},
   297  			},
   298  			context: map[string]interface{}{
   299  				"x": int64(1),
   300  				"y": int64(2),
   301  			},
   302  			maxCost: 2,
   303  			err:     fmt.Errorf("operation cancelled: actual cost limit exceeded"),
   304  		},
   305  		{
   306  			name: "cost_not_exceeded_int",
   307  			condition: &openfgav1.Condition{
   308  				Name:       "condition1",
   309  				Expression: "x < y",
   310  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   311  					"x": {
   312  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   313  					},
   314  					"y": {
   315  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   316  					},
   317  				},
   318  			},
   319  			context: map[string]interface{}{
   320  				"x": int64(1),
   321  				"y": int64(2),
   322  			},
   323  			maxCost: 3,
   324  			result: condition.EvaluationResult{
   325  				Cost:         3,
   326  				ConditionMet: true,
   327  			},
   328  		},
   329  		{
   330  			name: "cost_exceeded_str",
   331  			condition: &openfgav1.Condition{
   332  				Name:       "condition1",
   333  				Expression: "x == y",
   334  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   335  					"x": {
   336  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   337  					},
   338  					"y": {
   339  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   340  					},
   341  				},
   342  			},
   343  			context: map[string]interface{}{
   344  				"x": "ab",
   345  				"y": "ab",
   346  			},
   347  			maxCost: 2,
   348  			err:     fmt.Errorf("operation cancelled: actual cost limit exceeded"),
   349  		},
   350  		{
   351  			name: "cost_exceeded_list",
   352  			condition: &openfgav1.Condition{
   353  				Name:       "condition1",
   354  				Expression: "'a' in strlist",
   355  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   356  					"strlist": {
   357  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   358  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   359  							{
   360  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   361  							},
   362  						},
   363  					},
   364  				},
   365  			},
   366  			context: map[string]interface{}{
   367  				"strlist": []interface{}{"c", "b", "a"},
   368  			},
   369  			maxCost: 3,
   370  			err:     fmt.Errorf("operation cancelled: actual cost limit exceeded"),
   371  		},
   372  		{
   373  			name: "cost_not_exceeded_list",
   374  			condition: &openfgav1.Condition{
   375  				Name:       "condition1",
   376  				Expression: "'d' in strlist",
   377  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   378  					"strlist": {
   379  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   380  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   381  							{
   382  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   383  							},
   384  						},
   385  					},
   386  				},
   387  			},
   388  			context: map[string]interface{}{
   389  				"strlist": []interface{}{"a", "b", "c"},
   390  			},
   391  			maxCost: 4,
   392  			result: condition.EvaluationResult{
   393  				Cost:         4,
   394  				ConditionMet: false,
   395  			},
   396  		},
   397  	}
   398  
   399  	for _, test := range tests {
   400  		t.Run(test.name, func(t *testing.T) {
   401  			ctx := context.Background()
   402  			condition := condition.NewUncompiled(test.condition).WithMaxEvaluationCost(test.maxCost)
   403  
   404  			err := condition.Compile()
   405  			require.NoError(t, err)
   406  
   407  			contextStruct, err := structpb.NewStruct(test.context)
   408  			require.NoError(t, err)
   409  
   410  			result, err := condition.Evaluate(ctx, contextStruct.GetFields())
   411  
   412  			require.Equal(t, test.result, result)
   413  			if test.err != nil {
   414  				require.ErrorContains(t, err, test.err.Error())
   415  			} else {
   416  				require.NoError(t, err)
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func TestCastContextToTypedParameters(t *testing.T) {
   423  	tests := []struct {
   424  		name                    string
   425  		contextMap              map[string]any
   426  		conditionParameterTypes map[string]*openfgav1.ConditionParamTypeRef
   427  		expectedParams          map[string]any
   428  		expectedError           *condition.ParameterTypeError
   429  	}{
   430  		{
   431  			name: "valid",
   432  			contextMap: map[string]any{
   433  				"param1": "ok",
   434  			},
   435  			conditionParameterTypes: map[string]*openfgav1.ConditionParamTypeRef{
   436  				"param1": {
   437  					TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_STRING,
   438  				},
   439  			},
   440  			expectedParams: map[string]any{
   441  				"param1": mustConvertValue(types.StringParamType, "ok"),
   442  			},
   443  		},
   444  		{
   445  			name:                    "empty_context_map",
   446  			contextMap:              map[string]any{},
   447  			conditionParameterTypes: map[string]*openfgav1.ConditionParamTypeRef{},
   448  			expectedParams:          nil,
   449  		},
   450  		{
   451  			name: "empty_parameter_types",
   452  			contextMap: map[string]any{
   453  				"param1": "ok",
   454  			},
   455  			conditionParameterTypes: map[string]*openfgav1.ConditionParamTypeRef{},
   456  			expectedParams:          nil,
   457  			expectedError: &condition.ParameterTypeError{
   458  				Condition: "condition1",
   459  				Cause:     fmt.Errorf("no parameters defined for the condition"),
   460  			},
   461  		},
   462  		{
   463  			name: "failed_to_decode_condition_parameter_type",
   464  			contextMap: map[string]any{
   465  				"param1": "ok",
   466  			},
   467  			conditionParameterTypes: map[string]*openfgav1.ConditionParamTypeRef{
   468  				"param1": {
   469  					TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_UNSPECIFIED,
   470  				},
   471  			},
   472  			expectedParams: nil,
   473  			expectedError: &condition.ParameterTypeError{
   474  				Condition: "condition1",
   475  				Cause:     fmt.Errorf("failed to decode condition parameter type 'TYPE_NAME_UNSPECIFIED': unknown condition parameter type `TYPE_NAME_UNSPECIFIED`"),
   476  			},
   477  		},
   478  	}
   479  
   480  	for _, test := range tests {
   481  		t.Run(test.name, func(t *testing.T) {
   482  			c := condition.NewUncompiled(&openfgav1.Condition{
   483  				Name:       "condition1",
   484  				Expression: "param1 == 'ok'",
   485  				Parameters: test.conditionParameterTypes,
   486  			})
   487  
   488  			contextStruct, err := structpb.NewStruct(test.contextMap)
   489  			require.NoError(t, err)
   490  
   491  			typedParams, err := c.CastContextToTypedParameters(contextStruct.GetFields())
   492  
   493  			if test.expectedError != nil {
   494  				require.Error(t, err)
   495  				require.EqualError(t, err, test.expectedError.Error())
   496  			} else {
   497  				require.NoError(t, err)
   498  			}
   499  
   500  			if !reflect.DeepEqual(typedParams, test.expectedParams) {
   501  				t.Errorf("expected %v, got %v", test.expectedParams, typedParams)
   502  			}
   503  		})
   504  	}
   505  }
   506  
   507  func TestEvaluateWithInterruptCheckFrequency(t *testing.T) {
   508  	makeItems := func(size int) []interface{} {
   509  		items := make([]interface{}, size)
   510  		for i := int(0); i < size; i++ {
   511  			items[i] = i
   512  		}
   513  		return items
   514  	}
   515  
   516  	// numLoops is the number of loops being evaluated by a CEL
   517  	// expression. This number needs to be large enough to not
   518  	// be resolved before the 1 microsecond context timeout.
   519  	numLoops := 500
   520  
   521  	var tests = []struct {
   522  		name           string
   523  		condition      *openfgav1.Condition
   524  		context        map[string]any
   525  		checkFrequency uint
   526  		result         condition.EvaluationResult
   527  		err            error
   528  	}{
   529  		{
   530  			name: "operation_interrupted_one_comprehension",
   531  			condition: &openfgav1.Condition{
   532  				Name:       "condition1",
   533  				Expression: "items.map(i, i * 2).size() > 0",
   534  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   535  					"items": {
   536  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   537  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   538  							{
   539  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   540  							},
   541  						},
   542  					},
   543  				},
   544  			},
   545  			checkFrequency: uint(numLoops),
   546  			context: map[string]interface{}{
   547  				"items": makeItems(numLoops),
   548  			},
   549  			result: condition.EvaluationResult{
   550  				ConditionMet: false,
   551  			},
   552  			err: fmt.Errorf("failed to evaluate relationship condition: 'condition1' - failed to evaluate condition expression: operation interrupted"),
   553  		},
   554  		{
   555  			name: "operation_not_interrupted_one_comprehension",
   556  			condition: &openfgav1.Condition{
   557  				Name:       "condition1",
   558  				Expression: "items.map(i, i * 2).size() > 0",
   559  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   560  					"items": {
   561  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   562  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   563  							{
   564  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   565  							},
   566  						},
   567  					},
   568  				},
   569  			},
   570  			checkFrequency: uint(numLoops),
   571  			context: map[string]interface{}{
   572  				"items": makeItems(numLoops - 1),
   573  			},
   574  			result: condition.EvaluationResult{
   575  				ConditionMet: true,
   576  			},
   577  			err: nil,
   578  		},
   579  		{
   580  			name: "operation_interrupted_two_comprehensions",
   581  			condition: &openfgav1.Condition{
   582  				Name:       "condition1",
   583  				Expression: "items.map(i, i * 2).map(i, i * i).size() > 0",
   584  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   585  					"items": {
   586  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   587  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   588  							{
   589  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   590  							},
   591  						},
   592  					},
   593  				},
   594  			},
   595  			checkFrequency: uint(numLoops),
   596  			context: map[string]interface{}{
   597  				"items": makeItems(numLoops),
   598  			},
   599  			result: condition.EvaluationResult{
   600  				ConditionMet: false,
   601  			},
   602  			err: fmt.Errorf("failed to evaluate relationship condition: 'condition1' - failed to evaluate condition expression: operation interrupted"),
   603  		},
   604  		{
   605  			name: "operation_not_interrupted_two_comprehensions",
   606  			condition: &openfgav1.Condition{
   607  				Name:       "condition1",
   608  				Expression: "items.map(i, i * 2).map(i, i * i).size() > 0",
   609  				Parameters: map[string]*openfgav1.ConditionParamTypeRef{
   610  					"items": {
   611  						TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_LIST,
   612  						GenericTypes: []*openfgav1.ConditionParamTypeRef{
   613  							{
   614  								TypeName: openfgav1.ConditionParamTypeRef_TYPE_NAME_INT,
   615  							},
   616  						},
   617  					},
   618  				},
   619  			},
   620  			checkFrequency: uint(numLoops),
   621  			context: map[string]interface{}{
   622  				"items": makeItems(numLoops - 1),
   623  			},
   624  			result: condition.EvaluationResult{
   625  				ConditionMet: false,
   626  			},
   627  			err: fmt.Errorf("failed to evaluate relationship condition: 'condition1' - failed to evaluate condition expression: operation interrupted"),
   628  		},
   629  	}
   630  
   631  	for _, test := range tests {
   632  		t.Run(test.name, func(t *testing.T) {
   633  			ctx := context.Background()
   634  			condition := condition.NewUncompiled(test.condition).
   635  				WithInterruptCheckFrequency(test.checkFrequency)
   636  
   637  			err := condition.Compile()
   638  			require.NoError(t, err)
   639  
   640  			contextStruct, err := structpb.NewStruct(test.context)
   641  			require.NoError(t, err)
   642  
   643  			evalCtx, cancel := context.WithTimeout(ctx, time.Microsecond)
   644  			defer cancel()
   645  
   646  			result, err := condition.Evaluate(evalCtx, contextStruct.GetFields())
   647  
   648  			require.Equal(t, test.result, result)
   649  			if test.err != nil {
   650  				require.ErrorContains(t, err, test.err.Error())
   651  			} else {
   652  				require.NoError(t, err)
   653  			}
   654  		})
   655  	}
   656  }
   657  
   658  func mustConvertValue(varType types.ParameterType, value any) any {
   659  	convertedParam, err := varType.ConvertValue(value)
   660  	if err != nil {
   661  		panic(err)
   662  	}
   663  
   664  	return convertedParam
   665  }