github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/params/params_test.go (about)

     1  // Copyright 2022-2023 The Inspektor Gadget authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package params
    16  
    17  import (
    18  	"errors"
    19  	"net"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestParamAs(t *testing.T) {
    27  	type test struct {
    28  		name     string
    29  		value    string
    30  		typeHint TypeHint
    31  		expected any
    32  		getter   func(*Param) any
    33  	}
    34  
    35  	tests := []test{
    36  		{
    37  			name:     "Float32()",
    38  			value:    "-20.123",
    39  			typeHint: TypeFloat32,
    40  			expected: float32(-20.123),
    41  			getter:   func(p *Param) any { return p.AsFloat32() },
    42  		},
    43  		{
    44  			name:     "Floa64()",
    45  			value:    "-20.123456",
    46  			typeHint: TypeFloat64,
    47  			expected: float64(-20.123456),
    48  			getter:   func(p *Param) any { return p.AsFloat64() },
    49  		},
    50  		{
    51  			name:     "Int()",
    52  			value:    "-20",
    53  			typeHint: TypeInt,
    54  			expected: int(-20),
    55  			getter:   func(p *Param) any { return p.AsInt() },
    56  		},
    57  		{
    58  			name:     "Int8()",
    59  			value:    "-111",
    60  			typeHint: TypeInt8,
    61  			expected: int8(-111),
    62  			getter:   func(p *Param) any { return p.AsInt8() },
    63  		},
    64  		{
    65  			name:     "Int16()",
    66  			value:    "-5555",
    67  			typeHint: TypeInt16,
    68  			expected: int16(-5555),
    69  			getter:   func(p *Param) any { return p.AsInt16() },
    70  		},
    71  		{
    72  			name:     "Int32()",
    73  			value:    "-33333",
    74  			typeHint: TypeInt32,
    75  			expected: int32(-33333),
    76  			getter:   func(p *Param) any { return p.AsInt32() },
    77  		},
    78  		{
    79  			name:     "Int64()",
    80  			value:    "-2222222222",
    81  			typeHint: TypeInt64,
    82  			expected: int64(-2222222222),
    83  			getter:   func(p *Param) any { return p.AsInt64() },
    84  		},
    85  		{
    86  			name:     "Uint()",
    87  			value:    "20",
    88  			typeHint: TypeUint,
    89  			expected: uint(20),
    90  			getter:   func(p *Param) any { return p.AsUint() },
    91  		},
    92  		{
    93  			name:     "Uint8()",
    94  			value:    "111",
    95  			typeHint: TypeUint8,
    96  			expected: uint8(111),
    97  			getter:   func(p *Param) any { return p.AsUint8() },
    98  		},
    99  		{
   100  			name:     "Uint16()",
   101  			value:    "5555",
   102  			typeHint: TypeUint16,
   103  			expected: uint16(5555),
   104  			getter:   func(p *Param) any { return p.AsUint16() },
   105  		},
   106  		{
   107  			name:     "Uint32()",
   108  			value:    "33333",
   109  			typeHint: TypeUint32,
   110  			expected: uint32(33333),
   111  			getter:   func(p *Param) any { return p.AsUint32() },
   112  		},
   113  		{
   114  			name:     "Uint64()",
   115  			value:    "2222222222",
   116  			typeHint: TypeUint64,
   117  			expected: uint64(2222222222),
   118  			getter:   func(p *Param) any { return p.AsUint64() },
   119  		},
   120  		{
   121  			name:     "String()",
   122  			value:    "eW91J3JlIGN1cmlvdXM=",
   123  			typeHint: TypeString,
   124  			expected: string("eW91J3JlIGN1cmlvdXM="),
   125  			getter:   func(p *Param) any { return p.AsString() },
   126  		},
   127  		{
   128  			name:     "StringSlice()",
   129  			value:    "foo,bar,zas",
   130  			expected: []string{"foo", "bar", "zas"},
   131  			getter:   func(p *Param) any { return p.AsStringSlice() },
   132  		},
   133  		{
   134  			name:     "StringSlice()_Empty",
   135  			value:    "",
   136  			expected: []string{},
   137  			getter:   func(p *Param) any { return p.AsStringSlice() },
   138  		},
   139  		{
   140  			name:     "Bool()_true",
   141  			value:    "true",
   142  			typeHint: TypeBool,
   143  			expected: bool(true),
   144  			getter:   func(p *Param) any { return p.AsBool() },
   145  		},
   146  		{
   147  			name:     "Bool()_false",
   148  			value:    "false",
   149  			typeHint: TypeBool,
   150  			expected: bool(false),
   151  			getter:   func(p *Param) any { return p.AsBool() },
   152  		},
   153  		{
   154  			name:     "Uint16Slice()",
   155  			value:    "7777,8888,9999",
   156  			expected: []uint16{7777, 8888, 9999},
   157  			getter:   func(p *Param) any { return p.AsUint16Slice() },
   158  		},
   159  		{
   160  			name:     "Uint16Slice()_empty",
   161  			value:    "",
   162  			expected: []uint16{},
   163  			getter:   func(p *Param) any { return p.AsUint16Slice() },
   164  		},
   165  		{
   166  			name:     "Uint64Slice()",
   167  			value:    "7777,8888,9999",
   168  			expected: []uint64{7777, 8888, 9999},
   169  			getter:   func(p *Param) any { return p.AsUint64Slice() },
   170  		},
   171  		{
   172  			name:     "Uint64Slice()_empty",
   173  			value:    "",
   174  			expected: []uint64{},
   175  			getter:   func(p *Param) any { return p.AsUint64Slice() },
   176  		},
   177  		{
   178  			name:     "Int64Slice()",
   179  			value:    "-7777,-8888,9999",
   180  			expected: []int64{-7777, -8888, 9999},
   181  			getter:   func(p *Param) any { return p.AsInt64Slice() },
   182  		},
   183  		{
   184  			name:     "Uint64Slice()_empty",
   185  			value:    "",
   186  			expected: []int64{},
   187  			getter:   func(p *Param) any { return p.AsInt64Slice() },
   188  		},
   189  		{
   190  			name:     "Duration()_1s",
   191  			value:    "1s",
   192  			typeHint: TypeDuration,
   193  			expected: time.Duration(time.Second),
   194  			getter:   func(p *Param) any { return p.AsDuration() },
   195  		},
   196  		{
   197  			name:     "Duration()_5m",
   198  			value:    "5m",
   199  			typeHint: TypeDuration,
   200  			expected: time.Duration(5 * time.Minute),
   201  			getter:   func(p *Param) any { return p.AsDuration() },
   202  		},
   203  		{
   204  			name:     "Duration()_half_hour",
   205  			value:    "0.5h",
   206  			typeHint: TypeDuration,
   207  			expected: time.Duration(30 * time.Minute),
   208  			getter:   func(p *Param) any { return p.AsDuration() },
   209  		},
   210  		{
   211  			name:     "IPv4",
   212  			value:    "127.0.0.1",
   213  			typeHint: TypeIP,
   214  			expected: net.IPv4(127, 0, 0, 1),
   215  			getter:   func(p *Param) any { return p.AsIP() },
   216  		},
   217  		{
   218  			name:     "IPv6",
   219  			value:    "::1",
   220  			typeHint: TypeIP,
   221  			expected: net.IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
   222  			getter:   func(p *Param) any { return p.AsIP() },
   223  		},
   224  	}
   225  
   226  	for _, test := range tests {
   227  		test := test
   228  		t.Run(test.name, func(t *testing.T) {
   229  			p := &Param{
   230  				ParamDesc: &ParamDesc{
   231  					TypeHint: test.typeHint,
   232  				},
   233  				value: test.value,
   234  			}
   235  
   236  			require.Equal(t, test.expected, test.getter(p))
   237  
   238  			if test.typeHint != TypeUnknown {
   239  				require.Equal(t, test.expected, p.AsAny())
   240  			}
   241  		})
   242  	}
   243  }
   244  
   245  func TestParamsValidators(t *testing.T) {
   246  	type test struct {
   247  		name          string
   248  		desc          *ParamDesc
   249  		value         string
   250  		expectedError bool
   251  	}
   252  
   253  	tests := []test{
   254  		{
   255  			name:          "novalidation",
   256  			desc:          &ParamDesc{},
   257  			value:         "for,bar,yes,20.33",
   258  			expectedError: false,
   259  		},
   260  		{
   261  			name:          "novalidation_empty_str",
   262  			desc:          &ParamDesc{},
   263  			value:         "",
   264  			expectedError: false,
   265  		},
   266  		{
   267  			name: "IsMandatory_true_error",
   268  			desc: &ParamDesc{
   269  				IsMandatory: true,
   270  			},
   271  			value:         "",
   272  			expectedError: true,
   273  		},
   274  		{
   275  			name: "IsMandatory_true_no_error",
   276  			desc: &ParamDesc{
   277  				IsMandatory: true,
   278  			},
   279  			value:         "foo",
   280  			expectedError: false,
   281  		},
   282  		{
   283  			name: "PossibleValues_2_no_error",
   284  			desc: &ParamDesc{
   285  				PossibleValues: []string{"foo", "bar"},
   286  			},
   287  			value:         "foo",
   288  			expectedError: false,
   289  		},
   290  		{
   291  			name: "PossibleValues_2_error",
   292  			desc: &ParamDesc{
   293  				PossibleValues: []string{"foo", "bar"},
   294  			},
   295  			value:         "zas",
   296  			expectedError: true,
   297  		},
   298  		{
   299  			name: "TypeHint_int_no_error",
   300  			desc: &ParamDesc{
   301  				TypeHint: TypeInt,
   302  			},
   303  			value:         "-256",
   304  			expectedError: false,
   305  		},
   306  		{
   307  			name: "TypeHint_int_error",
   308  			desc: &ParamDesc{
   309  				TypeHint: TypeInt,
   310  			},
   311  			value:         "zas",
   312  			expectedError: true,
   313  		},
   314  		{
   315  			name: "TypeHint_uint_no_error",
   316  			desc: &ParamDesc{
   317  				TypeHint: TypeUint,
   318  			},
   319  			value:         "256",
   320  			expectedError: false,
   321  		},
   322  		{
   323  			name: "TypeHint_uint_error_string",
   324  			desc: &ParamDesc{
   325  				TypeHint: TypeUint,
   326  			},
   327  			value:         "zas",
   328  			expectedError: true,
   329  		},
   330  		{
   331  			name: "TypeHint_uint_error_negative",
   332  			desc: &ParamDesc{
   333  				TypeHint: TypeUint,
   334  			},
   335  			value:         "-256",
   336  			expectedError: true,
   337  		},
   338  		{
   339  			name: "TypeHint_float_no_error",
   340  			desc: &ParamDesc{
   341  				TypeHint: TypeFloat32,
   342  			},
   343  			value:         "-256.55",
   344  			expectedError: false,
   345  		},
   346  		{
   347  			name: "TypeHint_float_error",
   348  			desc: &ParamDesc{
   349  				TypeHint: TypeFloat32,
   350  			},
   351  			value:         "zas",
   352  			expectedError: true,
   353  		},
   354  		{
   355  			name: "TypeHint_bool_no_error_false",
   356  			desc: &ParamDesc{
   357  				TypeHint: TypeBool,
   358  			},
   359  			value:         "false",
   360  			expectedError: false,
   361  		},
   362  		{
   363  			name: "TypeHint_bool_no_error_true",
   364  			desc: &ParamDesc{
   365  				TypeHint: TypeBool,
   366  			},
   367  			value:         "true",
   368  			expectedError: false,
   369  		},
   370  		{
   371  			name: "TypeHint_bool_error",
   372  			desc: &ParamDesc{
   373  				TypeHint: TypeBool,
   374  			},
   375  			value:         "zas",
   376  			expectedError: true,
   377  		},
   378  		{
   379  			name: "Validator_error",
   380  			desc: &ParamDesc{
   381  				Validator: func(string) error { return errors.New("error") },
   382  			},
   383  			value:         "zas",
   384  			expectedError: true,
   385  		},
   386  		{
   387  			name: "Validator_no_error",
   388  			desc: &ParamDesc{
   389  				Validator: func(string) error { return nil },
   390  			},
   391  			value:         "zas",
   392  			expectedError: false,
   393  		},
   394  		{
   395  			name: "IsMandatory_and_Validator",
   396  			desc: &ParamDesc{
   397  				IsMandatory: true,
   398  				Validator:   func(string) error { return nil },
   399  			},
   400  			value:         "",
   401  			expectedError: true,
   402  		},
   403  		{
   404  			name: "IsMandatory_and_PossibleValues",
   405  			desc: &ParamDesc{
   406  				IsMandatory:    true,
   407  				PossibleValues: []string{"", "foo", "bar"},
   408  			},
   409  			value:         "",
   410  			expectedError: true,
   411  		},
   412  	}
   413  
   414  	for _, test := range tests {
   415  		test := test
   416  		t.Run(test.name, func(t *testing.T) {
   417  			p := test.desc.ToParam()
   418  
   419  			err := p.Set(test.value)
   420  			if test.expectedError {
   421  				require.Error(t, err)
   422  			} else {
   423  				require.Nil(t, err)
   424  			}
   425  		})
   426  	}
   427  }
   428  
   429  func TestParamDefaultValue(t *testing.T) {
   430  	pd := ParamDesc{
   431  		DefaultValue: "foo",
   432  	}
   433  
   434  	param := pd.ToParam()
   435  	require.Equal(t, "foo", param.String())
   436  	param.Set("bar")
   437  	require.Equal(t, "bar", param.String())
   438  }
   439  
   440  func TestBytesHandling(t *testing.T) {
   441  	// Test if a param of type Bytes gets compressed and decompressed correctly
   442  	const testString = "test123"
   443  	const testStringCompressed = "eJwqSS0uMTQyBgQAAP//CsoCVw=="
   444  	params := Params{
   445  		&Param{
   446  			ParamDesc: &ParamDesc{
   447  				Key:      "bytes",
   448  				TypeHint: TypeBytes,
   449  			},
   450  		},
   451  	}
   452  
   453  	// Compress
   454  	params[0].Set(testString)
   455  	testMap := map[string]string{}
   456  	params.CopyToMap(testMap, "")
   457  	require.Equal(t, testStringCompressed, testMap["bytes"], "compression + B64 encoding failed")
   458  
   459  	// Decompress
   460  	params[0].Set("")
   461  	params.CopyFromMap(testMap, "")
   462  	require.Equal(t, testString, string(params[0].AsBytes()), "decompression + B64 decoding failed")
   463  }
   464  
   465  func TestIsSet(t *testing.T) {
   466  	pd := ParamDesc{
   467  		DefaultValue: "foo",
   468  	}
   469  	p := pd.ToParam()
   470  	require.False(t, p.IsSet())
   471  	p.Set("foo")
   472  	require.True(t, p.IsSet())
   473  }
   474  
   475  func TestIsDefault(t *testing.T) {
   476  	pd := ParamDesc{
   477  		DefaultValue: "foo",
   478  	}
   479  	p := pd.ToParam()
   480  	require.True(t, p.IsDefault())
   481  	p.Set("foo")
   482  	require.True(t, p.IsDefault())
   483  	p.Set("bar")
   484  	require.False(t, p.IsDefault())
   485  }