github.com/kiali/kiali@v1.84.0/business/checkers/virtualservices/single_host_checker_test.go (about) 1 package virtualservices 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/models" 10 "github.com/kiali/kiali/tests/data" 11 "github.com/kiali/kiali/tests/testutils/validations" 12 ) 13 14 func TestOneVirtualServicePerHost(t *testing.T) { 15 vss := []*networking_v1beta1.VirtualService{ 16 buildVirtualService("virtual-1", "reviews"), 17 buildVirtualService("virtual-2", "ratings"), 18 } 19 vals := SingleHostChecker{ 20 VirtualServices: vss, 21 }.Check() 22 23 emptyValidationTest(t, vals) 24 25 // First virtual service has a gateway 26 vss = []*networking_v1beta1.VirtualService{ 27 buildVirtualServiceWithGateway("virtual-1", "reviews", "bookinfo-gateway"), 28 buildVirtualService("virtual-2", "ratings"), 29 } 30 vals = SingleHostChecker{ 31 VirtualServices: vss, 32 }.Check() 33 34 emptyValidationTest(t, vals) 35 emptyValidationTest(t, vals) 36 37 // Second virtual service has a gateway 38 vss = []*networking_v1beta1.VirtualService{ 39 buildVirtualService("virtual-1", "reviews"), 40 buildVirtualServiceWithGateway("virtual-2", "ratings", "bookinfo-gateway"), 41 } 42 vals = SingleHostChecker{ 43 VirtualServices: vss, 44 }.Check() 45 46 emptyValidationTest(t, vals) 47 emptyValidationTest(t, vals) 48 49 // Both virtual services have a gateway 50 vss = []*networking_v1beta1.VirtualService{ 51 buildVirtualServiceWithGateway("virtual-1", "reviews", "bookinfo-gateway"), 52 buildVirtualServiceWithGateway("virtual-2", "ratings", "bookinfo-gateway"), 53 } 54 55 vals = SingleHostChecker{ 56 VirtualServices: vss, 57 }.Check() 58 59 emptyValidationTest(t, vals) 60 emptyValidationTest(t, vals) 61 } 62 63 func TestOneVirtualServicePerFQDNHost(t *testing.T) { 64 vss := []*networking_v1beta1.VirtualService{ 65 buildVirtualService("virtual-1", "reviews.bookinfo.svc.cluster.local"), 66 buildVirtualService("virtual-2", "ratings.bookinfo.svc.cluster.local"), 67 } 68 vals := SingleHostChecker{ 69 VirtualServices: vss, 70 }.Check() 71 72 emptyValidationTest(t, vals) 73 } 74 75 func TestOneVirtualServicePerFQDNWildcardHost(t *testing.T) { 76 vss := []*networking_v1beta1.VirtualService{ 77 buildVirtualService("virtual-1", "*.bookinfo.svc.cluster.local"), 78 buildVirtualService("virtual-2", "*.eshop.svc.cluster.local"), 79 } 80 vals := SingleHostChecker{ 81 VirtualServices: vss, 82 }.Check() 83 84 emptyValidationTest(t, vals) 85 } 86 87 func TestRepeatingSimpleHost(t *testing.T) { 88 vss := []*networking_v1beta1.VirtualService{ 89 buildVirtualService("virtual-1", "reviews"), 90 buildVirtualService("virtual-2", "reviews"), 91 buildVirtualService("virtual-3", "reviews"), 92 } 93 94 vals := SingleHostChecker{ 95 VirtualServices: vss, 96 }.Check() 97 98 presentValidationTest(t, vals, "virtual-1") 99 presentValidationTest(t, vals, "virtual-2") 100 presentValidationTest(t, vals, "virtual-3") 101 102 for _, validation := range vals { 103 switch validation.Name { 104 case "virtual-1": 105 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 106 case "virtual-2": 107 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 108 case "virtual-3": 109 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 110 } 111 } 112 } 113 114 func TestRepeatingSimpleHostWithGateway(t *testing.T) { 115 vss := []*networking_v1beta1.VirtualService{ 116 buildVirtualServiceWithGateway("virtual-1", "reviews", "bookinfo"), 117 buildVirtualService("virtual-2", "reviews"), 118 } 119 120 vals := SingleHostChecker{ 121 VirtualServices: vss, 122 }.Check() 123 124 noObjectValidationTest(t, vals, "virtual-1") 125 noObjectValidationTest(t, vals, "virtual-2") 126 127 vss = []*networking_v1beta1.VirtualService{ 128 buildVirtualService("virtual-1", "reviews"), 129 buildVirtualServiceWithGateway("virtual-2", "reviews", "bookinfo"), 130 } 131 132 vals = SingleHostChecker{ 133 VirtualServices: vss, 134 }.Check() 135 136 noObjectValidationTest(t, vals, "virtual-1") 137 noObjectValidationTest(t, vals, "virtual-2") 138 139 vss = []*networking_v1beta1.VirtualService{ 140 buildVirtualServiceWithGateway("virtual-1", "reviews", "bookinfo"), 141 buildVirtualServiceWithGateway("virtual-2", "reviews", "bookinfo"), 142 } 143 144 vals = SingleHostChecker{ 145 VirtualServices: vss, 146 }.Check() 147 148 refKey := models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: "virtual-2"} 149 presentValidationTest(t, vals, "virtual-1") 150 presentReference(t, *(vals[refKey]), "virtual-1") 151 152 refKey.Name = "virtual-2" 153 presentValidationTest(t, vals, "virtual-2") 154 presentReference(t, *(vals[refKey]), "virtual-1") 155 } 156 157 func TestRepeatingSVCNSHost(t *testing.T) { 158 vss := []*networking_v1beta1.VirtualService{ 159 buildVirtualService("virtual-1", "reviews.bookinfo"), 160 buildVirtualService("virtual-2", "reviews.bookinfo"), 161 } 162 vals := SingleHostChecker{ 163 Namespaces: models.Namespaces{ 164 {Name: "bookinfo"}, 165 }, 166 VirtualServices: vss, 167 }.Check() 168 169 presentValidationTest(t, vals, "virtual-1") 170 presentValidationTest(t, vals, "virtual-2") 171 172 vss = []*networking_v1beta1.VirtualService{ 173 buildVirtualService("virtual-1", "reviews"), 174 buildVirtualService("virtual-2", "reviews.bookinfo"), 175 } 176 vals = SingleHostChecker{ 177 Namespaces: models.Namespaces{ 178 {Name: "bookinfo"}, 179 }, 180 VirtualServices: vss, 181 }.Check() 182 183 presentValidationTest(t, vals, "virtual-1") 184 presentValidationTest(t, vals, "virtual-2") 185 186 vss = []*networking_v1beta1.VirtualService{ 187 buildVirtualService("virtual-1", "reviews.bookinfo.svc.cluster.local"), 188 buildVirtualService("virtual-2", "reviews.bookinfo"), 189 buildVirtualServiceWithGateway("virtual-3", "reviews", "bookinfo-gateway-auto"), 190 } 191 vals = SingleHostChecker{ 192 Namespaces: models.Namespaces{ 193 {Name: "bookinfo"}, 194 }, 195 VirtualServices: vss, 196 }.Check() 197 198 presentValidationTest(t, vals, "virtual-1") 199 presentValidationTest(t, vals, "virtual-2") 200 201 vss = []*networking_v1beta1.VirtualService{ 202 buildVirtualService("virtual-1", "*.bookinfo.svc.cluster.local"), 203 buildVirtualService("virtual-2", "reviews.bookinfo"), 204 } 205 vals = SingleHostChecker{ 206 Namespaces: models.Namespaces{ 207 {Name: "bookinfo"}, 208 }, 209 VirtualServices: vss, 210 }.Check() 211 212 presentValidationTest(t, vals, "virtual-1") 213 presentValidationTest(t, vals, "virtual-2") 214 215 vss = []*networking_v1beta1.VirtualService{ 216 buildVirtualService("virtual-1", "reviews"), 217 buildVirtualService("virtual-2", "details.bookinfo"), 218 } 219 vals = SingleHostChecker{ 220 Namespaces: models.Namespaces{ 221 {Name: "bookinfo"}, 222 }, 223 VirtualServices: vss, 224 }.Check() 225 226 noObjectValidationTest(t, vals, "virtual-1") 227 noObjectValidationTest(t, vals, "virtual-2") 228 emptyValidationTest(t, vals) 229 230 vss = []*networking_v1beta1.VirtualService{ 231 buildVirtualService("virtual-1", "reviews.bookinfo.svc.cluster.local"), 232 buildVirtualService("virtual-2", "details.bookinfo"), 233 } 234 vals = SingleHostChecker{ 235 Namespaces: models.Namespaces{ 236 {Name: "bookinfo"}, 237 }, 238 VirtualServices: vss, 239 }.Check() 240 241 noObjectValidationTest(t, vals, "virtual-1") 242 noObjectValidationTest(t, vals, "virtual-2") 243 emptyValidationTest(t, vals) 244 } 245 246 func TestRepeatingFQDNHost(t *testing.T) { 247 vss := []*networking_v1beta1.VirtualService{ 248 buildVirtualService("virtual-1", "reviews.bookinfo.svc.cluster.local"), 249 buildVirtualService("virtual-2", "reviews.bookinfo.svc.cluster.local"), 250 buildVirtualService("virtual-3", "reviews.bookinfo.svc.cluster.local"), 251 } 252 vals := SingleHostChecker{ 253 VirtualServices: vss, 254 }.Check() 255 256 presentValidationTest(t, vals, "virtual-1") 257 presentValidationTest(t, vals, "virtual-2") 258 presentValidationTest(t, vals, "virtual-3") 259 260 for _, validation := range vals { 261 switch validation.Name { 262 case "virtual-1": 263 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 264 case "virtual-2": 265 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 266 case "virtual-3": 267 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 268 } 269 } 270 } 271 272 func TestRepeatingFQDNWildcardHost(t *testing.T) { 273 vss := []*networking_v1beta1.VirtualService{ 274 buildVirtualService("virtual-1", "*.bookinfo.svc.cluster.local"), 275 buildVirtualService("virtual-2", "*.bookinfo.svc.cluster.local"), 276 buildVirtualService("virtual-3", "*.bookinfo.svc.cluster.local"), 277 } 278 vals := SingleHostChecker{ 279 VirtualServices: vss, 280 }.Check() 281 282 presentValidationTest(t, vals, "virtual-1") 283 presentValidationTest(t, vals, "virtual-2") 284 presentValidationTest(t, vals, "virtual-3") 285 286 for _, validation := range vals { 287 switch validation.Name { 288 case "virtual-1": 289 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 290 case "virtual-2": 291 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 292 case "virtual-3": 293 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 294 } 295 } 296 } 297 298 func TestIncludedIntoWildCard(t *testing.T) { 299 vss := []*networking_v1beta1.VirtualService{ 300 buildVirtualService("virtual-1", "*.bookinfo.svc.cluster.local"), 301 buildVirtualService("virtual-2", "reviews.bookinfo.svc.cluster.local"), 302 buildVirtualService("virtual-3", "reviews.bookinfo.svc.cluster.local"), 303 } 304 vals := SingleHostChecker{ 305 VirtualServices: vss, 306 }.Check() 307 308 presentValidationTest(t, vals, "virtual-1") 309 presentValidationTest(t, vals, "virtual-2") 310 presentValidationTest(t, vals, "virtual-3") 311 312 for _, validation := range vals { 313 switch validation.Name { 314 case "virtual-1": 315 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 316 case "virtual-2": 317 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 318 case "virtual-3": 319 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 320 } 321 } 322 323 // Same test, with different order of appearance 324 vss = []*networking_v1beta1.VirtualService{ 325 buildVirtualService("virtual-1", "reviews.bookinfo.svc.cluster.local"), 326 buildVirtualService("virtual-2", "*.bookinfo.svc.cluster.local"), 327 buildVirtualService("virtual-3", "reviews.bookinfo.svc.cluster.local"), 328 } 329 vals = SingleHostChecker{ 330 VirtualServices: vss, 331 }.Check() 332 333 presentValidationTest(t, vals, "virtual-1") 334 presentValidationTest(t, vals, "virtual-2") 335 presentValidationTest(t, vals, "virtual-3") 336 337 for _, validation := range vals { 338 switch validation.Name { 339 case "virtual-1": 340 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 341 case "virtual-2": 342 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 343 case "virtual-3": 344 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 345 } 346 } 347 } 348 349 func TestShortHostNameIncludedIntoWildCard(t *testing.T) { 350 vss := []*networking_v1beta1.VirtualService{ 351 buildVirtualService("virtual-1", "*.bookinfo.svc.cluster.local"), 352 buildVirtualService("virtual-2", "reviews"), 353 buildVirtualService("virtual-3", "reviews"), 354 } 355 vals := SingleHostChecker{ 356 VirtualServices: vss, 357 }.Check() 358 359 presentValidationTest(t, vals, "virtual-1") 360 presentValidationTest(t, vals, "virtual-2") 361 presentValidationTest(t, vals, "virtual-3") 362 363 for _, validation := range vals { 364 switch validation.Name { 365 case "virtual-1": 366 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 367 case "virtual-2": 368 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 369 case "virtual-3": 370 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 371 } 372 } 373 } 374 375 func TestWildcardisMarkedInvalid(t *testing.T) { 376 vss := []*networking_v1beta1.VirtualService{ 377 buildVirtualService("virtual-1", "*"), 378 buildVirtualService("virtual-2", "reviews"), 379 buildVirtualService("virtual-3", "reviews"), 380 } 381 vals := SingleHostChecker{ 382 VirtualServices: vss, 383 }.Check() 384 385 presentValidationTest(t, vals, "virtual-1") 386 presentValidationTest(t, vals, "virtual-2") 387 presentValidationTest(t, vals, "virtual-3") 388 389 for _, validation := range vals { 390 switch validation.Name { 391 case "virtual-1": 392 presentReferences(t, *validation, []string{"virtual-2", "virtual-3"}) 393 case "virtual-2": 394 presentReferences(t, *validation, []string{"virtual-1", "virtual-3"}) 395 case "virtual-3": 396 presentReferences(t, *validation, []string{"virtual-1", "virtual-2"}) 397 } 398 } 399 } 400 401 func TestMultipleHostsFailing(t *testing.T) { 402 vss := []*networking_v1beta1.VirtualService{ 403 buildVirtualService("virtual-1", "reviews"), 404 buildVirtualServiceMultipleHosts("virtual-2", []string{"reviews", 405 "mongo.backup.svc.cluster.local", "mongo.staging.svc.cluster.local"}), 406 } 407 vals := SingleHostChecker{ 408 VirtualServices: vss, 409 }.Check() 410 411 presentValidationTest(t, vals, "virtual-1") 412 presentValidationTest(t, vals, "virtual-2") 413 414 for _, validation := range vals { 415 switch validation.Name { 416 case "virtual-1": 417 presentReference(t, *validation, "virtual-2") 418 case "virtual-2": 419 presentReference(t, *validation, "virtual-1") 420 } 421 } 422 } 423 424 func TestMultipleHostsPassing(t *testing.T) { 425 vss := []*networking_v1beta1.VirtualService{ 426 buildVirtualService("virtual-1", "reviews"), 427 buildVirtualServiceMultipleHosts("virtual-2", []string{"ratings", 428 "mongo.backup.svc.cluster.local", "mongo.staging.svc.cluster.local"}), 429 } 430 vals := SingleHostChecker{ 431 VirtualServices: vss, 432 }.Check() 433 434 emptyValidationTest(t, vals) 435 } 436 437 func buildVirtualService(name, host string) *networking_v1beta1.VirtualService { 438 return buildVirtualServiceMultipleHosts(name, []string{host}) 439 } 440 441 func buildVirtualServiceWithGateway(name, host, gateway string) *networking_v1beta1.VirtualService { 442 return data.AddGatewaysToVirtualService([]string{gateway}, data.CreateEmptyVirtualService(name, 443 "bookinfo", []string{host})) 444 } 445 446 func buildVirtualServiceMultipleHosts(name string, hosts []string) *networking_v1beta1.VirtualService { 447 return data.CreateEmptyVirtualService(name, "bookinfo", hosts) 448 } 449 450 func emptyValidationTest(t *testing.T, vals models.IstioValidations) { 451 assert := assert.New(t) 452 assert.Empty(vals) 453 454 validation, ok := vals[models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: "virtual-1"}] 455 assert.False(ok) 456 assert.Nil(validation) 457 458 validation, ok = vals[models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: "virtual-2"}] 459 assert.False(ok) 460 assert.Nil(validation) 461 } 462 463 func noObjectValidationTest(t *testing.T, vals models.IstioValidations, name string) { 464 assert := assert.New(t) 465 466 validation, ok := vals[models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: name}] 467 assert.False(ok) 468 assert.Nil(validation) 469 } 470 471 func presentValidationTest(t *testing.T, vals models.IstioValidations, serviceName string) { 472 assert := assert.New(t) 473 assert.NotEmpty(vals) 474 475 validation, ok := vals[models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: serviceName}] 476 assert.True(ok) 477 478 assert.True(validation.Valid) 479 assert.NotEmpty(validation.Checks) 480 assert.Equal(models.WarningSeverity, validation.Checks[0].Severity) 481 assert.NoError(validations.ConfirmIstioCheckMessage("virtualservices.singlehost", validation.Checks[0])) 482 assert.Equal("spec/hosts", validation.Checks[0].Path) 483 } 484 485 func presentReference(t *testing.T, validation models.IstioValidation, serviceName string) { 486 assert := assert.New(t) 487 refKey := models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: serviceName} 488 489 assert.True(len(validation.References) > 0) 490 assert.Contains(validation.References, refKey) 491 } 492 493 func presentReferences(t *testing.T, validation models.IstioValidation, serviceNames []string) { 494 assert := assert.New(t) 495 assert.True(len(validation.References) > 0) 496 497 for _, sn := range serviceNames { 498 refKey := models.IstioValidationKey{ObjectType: "virtualservice", Namespace: "bookinfo", Name: sn} 499 assert.Contains(validation.References, refKey) 500 } 501 }