github.com/kiali/kiali@v1.84.0/business/checkers/gateways/multi_match_checker_test.go (about) 1 package gateways 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 networking_v1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" 8 9 "github.com/kiali/kiali/config" 10 "github.com/kiali/kiali/models" 11 "github.com/kiali/kiali/tests/data" 12 ) 13 14 func TestCorrectGateways(t *testing.T) { 15 conf := config.NewConfig() 16 config.Set(conf) 17 18 assert := assert.New(t) 19 20 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 21 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 22 "app": "real", 23 })) 24 25 gws := []*networking_v1beta1.Gateway{gwObject} 26 27 vals := MultiMatchChecker{ 28 Gateways: gws, 29 }.Check() 30 31 assert.Empty(vals) 32 _, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}] 33 assert.False(ok) 34 } 35 36 func TestCaseMatching(t *testing.T) { 37 conf := config.NewConfig() 38 config.Set(conf) 39 40 assert := assert.New(t) 41 42 gwObject := data.AddServerToGateway(data.CreateServer( 43 []string{ 44 "NOTFINE.example.com", 45 "notfine.example.com", 46 }, 80, "http", "http"), 47 48 data.CreateEmptyGateway("foxxed", "test", map[string]string{ 49 "app": "canidae", 50 })) 51 52 gws := []*networking_v1beta1.Gateway{gwObject} 53 54 vals := MultiMatchChecker{ 55 Gateways: gws, 56 }.Check() 57 58 assert.NotEmpty(vals) 59 assert.Equal(1, len(vals)) 60 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "foxxed"}] 61 assert.True(ok) 62 assert.True(validation.Valid) 63 } 64 65 func TestDashSubdomainMatching(t *testing.T) { 66 conf := config.NewConfig() 67 config.Set(conf) 68 69 assert := assert.New(t) 70 71 gwObject := data.AddServerToGateway(data.CreateServer( 72 []string{ 73 "api.dev.example.com", 74 "api-dev.example.com", 75 }, 80, "http", "http"), 76 77 data.CreateEmptyGateway("foxxed", "test", map[string]string{ 78 "app": "canidae", 79 })) 80 81 gws := []*networking_v1beta1.Gateway{gwObject} 82 83 vals := MultiMatchChecker{ 84 Gateways: gws, 85 }.Check() 86 87 assert.Empty(vals) 88 } 89 90 // Two gateways can share port+host unless they use different ingress 91 func TestSameHostPortConfigInDifferentIngress(t *testing.T) { 92 conf := config.NewConfig() 93 config.Set(conf) 94 95 assert := assert.New(t) 96 97 gwObject := data.AddServerToGateway(data.CreateServer([]string{"reviews"}, 80, "http", "http"), 98 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 99 "app": "istio-ingress-pub", 100 })) 101 102 // Another namespace 103 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"reviews"}, 80, "http", "http"), 104 data.CreateEmptyGateway("stillvalid", "test", map[string]string{ 105 "app": "istio-ingress-prv", 106 })) 107 108 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2} 109 110 vals := MultiMatchChecker{ 111 Gateways: gws, 112 }.Check() 113 114 assert.Equal(0, len(vals)) 115 } 116 117 func TestSameHostPortConfigInDifferentNamespace(t *testing.T) { 118 conf := config.NewConfig() 119 config.Set(conf) 120 121 assert := assert.New(t) 122 123 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 124 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 125 "app": "real", 126 })) 127 128 // Another namespace 129 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 130 data.CreateEmptyGateway("stillvalid", "bookinfo", map[string]string{ 131 "app": "real", 132 })) 133 134 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2} 135 136 vals := MultiMatchChecker{ 137 Gateways: gws, 138 }.Check() 139 140 assert.NotEmpty(vals) 141 assert.Equal(2, len(vals)) 142 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo", Name: "stillvalid"}] 143 assert.True(ok) 144 assert.True(validation.Valid) 145 146 secValidation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}] 147 assert.True(ok) 148 assert.True(secValidation.Valid) 149 150 // Check references 151 assert.Equal(1, len(validation.References)) 152 assert.Equal(1, len(secValidation.References)) 153 } 154 155 func TestSameHostDifferentPortConfig(t *testing.T) { 156 conf := config.NewConfig() 157 config.Set(conf) 158 159 assert := assert.New(t) 160 161 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 162 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 163 "istio": "istio-ingress", 164 })) 165 166 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 443, "https", "https"), 167 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 168 "istio": "istio-ingress", 169 })) 170 171 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2} 172 173 vals := MultiMatchChecker{ 174 Gateways: gws, 175 }.Check() 176 177 assert.Equal(0, len(vals)) 178 } 179 180 func TestWildCardMatchingHost(t *testing.T) { 181 conf := config.NewConfig() 182 config.Set(conf) 183 184 assert := assert.New(t) 185 186 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 187 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 188 "istio": "istio-ingress", 189 })) 190 191 // Another namespace 192 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 193 data.CreateEmptyGateway("stillvalid", "test", map[string]string{ 194 "istio": "istio-ingress", 195 })) 196 197 // Another namespace 198 gwObject3 := data.AddServerToGateway(data.CreateServer([]string{"*.justhost.com"}, 80, "http", "http"), 199 data.CreateEmptyGateway("keepsvalid", "test", map[string]string{ 200 "istio": "istio-ingress", 201 })) 202 203 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2, gwObject3} 204 205 vals := MultiMatchChecker{ 206 Gateways: gws, 207 }.Check() 208 209 assert.NotEmpty(vals) 210 assert.Equal(3, len(vals)) 211 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "stillvalid"}] 212 assert.True(ok) 213 assert.True(validation.Valid) 214 215 // valid should have "*" as ref 216 // "*" should have valid and *.just as ref 217 // *.just should have "*" as ref 218 for _, v := range vals { 219 if v.Name == "stillvalid" { 220 assert.Equal(2, len(v.References)) 221 } else { 222 assert.Equal(1, len(v.References)) 223 } 224 } 225 } 226 227 func TestSkipWildCardMatchingHost(t *testing.T) { 228 conf := config.NewConfig() 229 conf.KialiFeatureFlags.Validations.SkipWildcardGatewayHosts = true 230 config.Set(conf) 231 232 assert := assert.New(t) 233 234 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid"}, 80, "http", "http"), 235 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 236 "istio": "istio-ingress", 237 })) 238 239 // Another namespace 240 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 241 data.CreateEmptyGateway("stillvalid", "test", map[string]string{ 242 "istio": "istio-ingress", 243 })) 244 245 // Another namespace 246 gwObject3 := data.AddServerToGateway(data.CreateServer([]string{"*.justhost.com"}, 80, "http", "http"), 247 data.CreateEmptyGateway("keepsvalid", "test", map[string]string{ 248 "istio": "istio-ingress", 249 })) 250 251 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2, gwObject3} 252 253 vals := MultiMatchChecker{ 254 Gateways: gws, 255 }.Check() 256 257 assert.Equal(0, len(vals)) 258 } 259 260 func TestSameWildcardHostPortConfigInDifferentNamespace(t *testing.T) { 261 conf := config.NewConfig() 262 config.Set(conf) 263 264 assert := assert.New(t) 265 266 gwObject := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 267 data.CreateEmptyGateway("bookinfo-gateway-auto-host", "bookinfo", map[string]string{})) 268 269 // Another namespace 270 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 271 data.CreateEmptyGateway("bookinfo-gateway-auto-host-copy", "bookinfo2", map[string]string{})) 272 273 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2} 274 275 vals := MultiMatchChecker{ 276 Gateways: gws, 277 }.Check() 278 279 assert.NotEmpty(vals) 280 assert.Equal(2, len(vals)) 281 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo2", Name: "bookinfo-gateway-auto-host-copy"}] 282 assert.True(ok) 283 assert.True(validation.Valid) 284 285 secValidation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "bookinfo", Name: "bookinfo-gateway-auto-host"}] 286 assert.True(ok) 287 assert.True(secValidation.Valid) 288 289 // Check references 290 assert.Equal(1, len(validation.References)) 291 assert.Equal(1, len(secValidation.References)) 292 } 293 294 func TestAnotherSubdomainWildcardCombination(t *testing.T) { 295 conf := config.NewConfig() 296 config.Set(conf) 297 298 assert := assert.New(t) 299 300 gwObject := data.AddServerToGateway(data.CreateServer( 301 []string{ 302 "*.echidna.com", 303 "tachyglossa.echidna.com", 304 }, 80, "http", "http"), 305 306 data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{ 307 "app": "monotreme", 308 })) 309 310 gws := []*networking_v1beta1.Gateway{gwObject} 311 312 vals := MultiMatchChecker{ 313 Gateways: gws, 314 }.Check() 315 316 assert.NotEmpty(vals) 317 assert.Equal(1, len(vals)) 318 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}] 319 assert.True(ok) 320 assert.True(validation.Valid) 321 } 322 323 func TestNoMatchOnSubdomainHost(t *testing.T) { 324 conf := config.NewConfig() 325 config.Set(conf) 326 327 assert := assert.New(t) 328 329 gwObject := data.AddServerToGateway(data.CreateServer( 330 []string{ 331 "example.com", 332 "thisisfine.example.com", 333 }, 80, "http", "http"), 334 335 data.CreateEmptyGateway("shouldbevalid", "test", map[string]string{ 336 "app": "someother", 337 })) 338 339 gws := []*networking_v1beta1.Gateway{gwObject} 340 341 vals := MultiMatchChecker{ 342 Gateways: gws, 343 }.Check() 344 345 assert.Empty(vals) 346 } 347 348 func TestTwoWildCardsMatching(t *testing.T) { 349 conf := config.NewConfig() 350 config.Set(conf) 351 352 assert := assert.New(t) 353 354 gwObject := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 355 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 356 "istio": "istio-ingress", 357 })) 358 359 // Another namespace 360 gwObject2 := data.AddServerToGateway(data.CreateServer([]string{"*"}, 80, "http", "http"), 361 data.CreateEmptyGateway("stillvalid", "test", map[string]string{ 362 "istio": "istio-ingress", 363 })) 364 365 gws := []*networking_v1beta1.Gateway{gwObject, gwObject2} 366 367 vals := MultiMatchChecker{ 368 Gateways: gws, 369 }.Check() 370 371 assert.NotEmpty(vals) 372 assert.Equal(2, len(vals)) 373 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "stillvalid"}] 374 assert.True(ok) 375 assert.True(validation.Valid) 376 assert.Equal("spec/servers[0]/hosts[0]", validation.Checks[0].Path) 377 } 378 379 func TestDuplicateGatewaysErrorCount(t *testing.T) { 380 conf := config.NewConfig() 381 config.Set(conf) 382 383 assert := assert.New(t) 384 385 gwObject := data.AddServerToGateway(data.CreateServer([]string{"valid", "second.valid"}, 80, "http", "http"), 386 data.CreateEmptyGateway("validgateway", "test", map[string]string{ 387 "app": "real", 388 })) 389 390 gwObjectIdentical := data.AddServerToGateway(data.CreateServer([]string{"valid", "second.valid"}, 80, "http", "http"), 391 data.CreateEmptyGateway("duplicatevalidgateway", "test", map[string]string{ 392 "app": "real", 393 })) 394 395 gws := []*networking_v1beta1.Gateway{gwObject, gwObjectIdentical} 396 397 vals := MultiMatchChecker{ 398 Gateways: gws, 399 }.Check() 400 401 assert.NotEmpty(vals) 402 validgateway, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "validgateway"}] 403 assert.True(ok) 404 405 duplicatevalidgateway, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "duplicatevalidgateway"}] 406 assert.True(ok) 407 408 assert.Equal(2, len(validgateway.Checks)) 409 assert.Equal("spec/servers[0]/hosts[0]", validgateway.Checks[0].Path) 410 assert.Equal("spec/servers[0]/hosts[1]", validgateway.Checks[1].Path) 411 412 assert.Equal(2, len(duplicatevalidgateway.Checks)) 413 assert.Equal("spec/servers[0]/hosts[0]", duplicatevalidgateway.Checks[0].Path) 414 assert.Equal("spec/servers[0]/hosts[1]", duplicatevalidgateway.Checks[1].Path) 415 } 416 417 // One Host can be defined for multiple target namespaces without conflict 418 func TestNoMatchOnDifferentTargetNamespaces(t *testing.T) { 419 conf := config.NewConfig() 420 config.Set(conf) 421 422 assert := assert.New(t) 423 424 gwObject := data.AddServerToGateway(data.CreateServer( 425 []string{ 426 "test1/example.com", 427 "test2/example.com", 428 }, 80, "http", "http"), 429 430 data.CreateEmptyGateway("shouldbevalid", "test", map[string]string{ 431 "app": "ingressgateway", 432 })) 433 434 gws := []*networking_v1beta1.Gateway{gwObject} 435 436 vals := MultiMatchChecker{ 437 Gateways: gws, 438 }.Check() 439 440 assert.Empty(vals) 441 } 442 443 // target Namespace '.' means that the Host is available in the Namespace of the Gateway resource 444 func TestMatchOnSameTargetNamespace(t *testing.T) { 445 conf := config.NewConfig() 446 config.Set(conf) 447 448 assert := assert.New(t) 449 450 gwObject := data.AddServerToGateway(data.CreateServer( 451 []string{ 452 "test/example.com", 453 "./example.com", 454 }, 80, "http", "http"), 455 456 data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{ 457 "app": "ingressgateway", 458 })) 459 460 gws := []*networking_v1beta1.Gateway{gwObject} 461 462 vals := MultiMatchChecker{ 463 Gateways: gws, 464 }.Check() 465 466 assert.NotEmpty(vals) 467 assert.Equal(1, len(vals)) 468 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}] 469 assert.True(ok) 470 assert.True(validation.Valid) 471 } 472 473 // target Namespace * means that the Host is available in all namespaces 474 func TestMatchOnWildcardTargetNamespace(t *testing.T) { 475 conf := config.NewConfig() 476 config.Set(conf) 477 478 assert := assert.New(t) 479 480 gwObject := data.AddServerToGateway(data.CreateServer( 481 []string{ 482 "test/example.com", 483 "*/example.com", 484 }, 80, "http", "http"), 485 486 data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{ 487 "app": "ingressgateway", 488 })) 489 490 gws := []*networking_v1beta1.Gateway{gwObject} 491 492 vals := MultiMatchChecker{ 493 Gateways: gws, 494 }.Check() 495 496 assert.NotEmpty(vals) 497 assert.Equal(1, len(vals)) 498 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}] 499 assert.True(ok) 500 assert.True(validation.Valid) 501 } 502 503 // having no target namespace set is the same as having * as target Namespace 504 func TestMatchOnImplicitWildcardTargetNamespace(t *testing.T) { 505 conf := config.NewConfig() 506 config.Set(conf) 507 508 assert := assert.New(t) 509 510 gwObject := data.AddServerToGateway(data.CreateServer( 511 []string{ 512 "test/example.com", 513 "example.com", 514 }, 80, "http", "http"), 515 516 data.CreateEmptyGateway("shouldnotbevalid", "test", map[string]string{ 517 "app": "ingressgateway", 518 })) 519 520 gws := []*networking_v1beta1.Gateway{gwObject} 521 522 vals := MultiMatchChecker{ 523 Gateways: gws, 524 }.Check() 525 526 assert.NotEmpty(vals) 527 assert.Equal(1, len(vals)) 528 validation, ok := vals[models.IstioValidationKey{ObjectType: "gateway", Namespace: "test", Name: "shouldnotbevalid"}] 529 assert.True(ok) 530 assert.True(validation.Valid) 531 }