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 }