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  }