github.com/verrazzano/verrazzano@v1.7.0/platform-operator/internal/vzconfig/ingress_test.go (about)

     1  // Copyright (c) 2020, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  package vzconfig
     4  
     5  import (
     6  	"github.com/verrazzano/verrazzano/pkg/nginxutil"
     7  	"testing"
     8  
     9  	"github.com/verrazzano/verrazzano/pkg/test/ip"
    10  
    11  	vzapi "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    12  	vpoconst "github.com/verrazzano/verrazzano/platform-operator/constants"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  	k8scheme "k8s.io/client-go/kubernetes/scheme"
    18  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    19  )
    20  
    21  const testDomain = "mydomain.com"
    22  
    23  // Test_getServiceTypeLoadBalancer tests the GetServiceType function
    24  // GIVEN a call to GetServiceType
    25  //
    26  //	WHEN the Ingress specifies a LoadBalancer type
    27  //	THEN the LoadBalancer type is returned with no error
    28  func Test_getServiceTypeLoadBalancer(t *testing.T) {
    29  	vz := &vzapi.Verrazzano{
    30  		Spec: vzapi.VerrazzanoSpec{
    31  			EnvironmentName: "myenv",
    32  			Components: vzapi.ComponentSpec{
    33  				Ingress: &vzapi.IngressNginxComponent{
    34  					Type: vzapi.LoadBalancer,
    35  				},
    36  			},
    37  		},
    38  	}
    39  
    40  	svcType, err := GetIngressServiceType(vz)
    41  	assert.NoError(t, err)
    42  	assert.Equal(t, vzapi.LoadBalancer, svcType)
    43  }
    44  
    45  // Test_getServiceTypeNodePort tests the GetServiceType function
    46  // GIVEN a call to GetServiceType
    47  //
    48  //	WHEN the Ingress specifies a NodePort type
    49  //	THEN the NodePort type is returned with no error
    50  func Test_getServiceTypeNodePort(t *testing.T) {
    51  	vz := &vzapi.Verrazzano{
    52  		Spec: vzapi.VerrazzanoSpec{
    53  			EnvironmentName: "myenv",
    54  			Components: vzapi.ComponentSpec{
    55  				Ingress: &vzapi.IngressNginxComponent{
    56  					Type: vzapi.NodePort,
    57  				},
    58  			},
    59  		},
    60  	}
    61  
    62  	svcType, err := GetIngressServiceType(vz)
    63  	assert.NoError(t, err)
    64  	assert.Equal(t, vzapi.NodePort, svcType)
    65  }
    66  
    67  // Test_getServiceTypeInvalidType tests the GetServiceType function
    68  // GIVEN a call to GetServiceType
    69  //
    70  //	WHEN the Ingress specifies invalid service type
    71  //	THEN an empty string and an error are returned
    72  func Test_getServiceTypeInvalidType(t *testing.T) {
    73  	vz := &vzapi.Verrazzano{
    74  		Spec: vzapi.VerrazzanoSpec{
    75  			EnvironmentName: "myenv",
    76  			Components: vzapi.ComponentSpec{
    77  				Ingress: &vzapi.IngressNginxComponent{
    78  					Type: "somethingbad",
    79  				},
    80  			},
    81  		},
    82  	}
    83  
    84  	svcType, err := GetIngressServiceType(vz)
    85  	assert.Error(t, err)
    86  	assert.Equal(t, vzapi.IngressType(""), svcType)
    87  }
    88  
    89  // TestGetIngressServiceNotFound tests the GetIngressIP function
    90  // GIVEN a call to GetIngressIP
    91  //
    92  //	WHEN the VZ config Ingress is a LB type and no service is found
    93  //	THEN an error is returned
    94  func TestGetIngressServiceNotFound(t *testing.T) {
    95  	vz := &vzapi.Verrazzano{
    96  		Spec: vzapi.VerrazzanoSpec{
    97  			Components: vzapi.ComponentSpec{
    98  				Ingress: &vzapi.IngressNginxComponent{
    99  					Type: vzapi.LoadBalancer,
   100  				},
   101  			},
   102  		},
   103  	}
   104  	fakeClient := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build()
   105  	_, err := GetIngressIP(fakeClient, vz)
   106  	assert.Error(t, err)
   107  }
   108  
   109  func TestGetIngressIP(t *testing.T) {
   110  	testExternalIP := ip.RandomIP()
   111  	testLoadBalancerIP := ip.RandomIP()
   112  	tests := []struct {
   113  		name        string
   114  		serviceType vzapi.IngressType
   115  		lbIP        string
   116  		externalIP  string
   117  		want        string
   118  		wantErr     bool
   119  	}{
   120  		{
   121  			name:        "lb no address found",
   122  			serviceType: vzapi.LoadBalancer,
   123  			wantErr:     true,
   124  		},
   125  		{
   126  			name:        "lb with both lb and external ip",
   127  			serviceType: vzapi.LoadBalancer,
   128  			lbIP:        testLoadBalancerIP,
   129  			externalIP:  testExternalIP,
   130  			want:        testExternalIP,
   131  		},
   132  		{
   133  			name:        "lb with lb ip",
   134  			serviceType: vzapi.LoadBalancer,
   135  			lbIP:        testLoadBalancerIP,
   136  			want:        testLoadBalancerIP,
   137  		},
   138  		{
   139  			name:        "lb with external ip",
   140  			serviceType: vzapi.LoadBalancer,
   141  			externalIP:  testExternalIP,
   142  			want:        testExternalIP,
   143  		},
   144  		{
   145  			name:        "nodeport without external ip",
   146  			serviceType: vzapi.NodePort,
   147  			wantErr:     true,
   148  		},
   149  		{
   150  			name:        "nodeport with external ip",
   151  			serviceType: vzapi.NodePort,
   152  			externalIP:  testExternalIP,
   153  			want:        testExternalIP,
   154  		},
   155  	}
   156  	for _, tt := range tests {
   157  		t.Run(tt.name, func(t *testing.T) {
   158  			vz := &vzapi.Verrazzano{
   159  				Spec: vzapi.VerrazzanoSpec{
   160  					Components: vzapi.ComponentSpec{
   161  						Ingress: &vzapi.IngressNginxComponent{
   162  							Type: tt.serviceType,
   163  						},
   164  					},
   165  				},
   166  			}
   167  			svc := &corev1.Service{
   168  				ObjectMeta: metav1.ObjectMeta{
   169  					Namespace: nginxutil.IngressNGINXNamespace(),
   170  					Name:      vpoconst.NGINXControllerServiceName,
   171  				},
   172  			}
   173  			if len(tt.externalIP) > 0 {
   174  				svc.Spec = corev1.ServiceSpec{
   175  					ExternalIPs: []string{tt.externalIP},
   176  				}
   177  			}
   178  			if len(tt.lbIP) > 0 {
   179  				svc.Status = corev1.ServiceStatus{
   180  					LoadBalancer: corev1.LoadBalancerStatus{
   181  						Ingress: []corev1.LoadBalancerIngress{
   182  							{IP: tt.lbIP},
   183  						},
   184  					},
   185  				}
   186  			}
   187  			fakeClient := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(svc).Build()
   188  			got, err := GetIngressIP(fakeClient, vz)
   189  			if (err != nil) != tt.wantErr {
   190  				t.Errorf("GetIngressIP() error = %v, wantErr %v", err, tt.wantErr)
   191  				return
   192  			}
   193  			if got != tt.want {
   194  				t.Errorf("GetIngressIP() got = %v, want %v", got, tt.want)
   195  			}
   196  		})
   197  	}
   198  }
   199  
   200  func TestGetDNSSuffix(t *testing.T) {
   201  	const testWildCardSuffix = "xip.io"
   202  	testExternalIP := ip.RandomIP()
   203  	testLoadBalancerIP := ip.RandomIP()
   204  	tests := []struct {
   205  		name              string
   206  		serviceType       vzapi.IngressType
   207  		dnsOCIZone        string
   208  		dnsExternalSuffix string
   209  		dnsWildCardSuffix string
   210  		lbIP              string
   211  		externalIP        string
   212  		want              string
   213  		wantErr           bool
   214  	}{
   215  		{
   216  			name:        "lb with oci dns",
   217  			serviceType: vzapi.LoadBalancer,
   218  			dnsOCIZone:  testDomain,
   219  			want:        testDomain,
   220  		},
   221  		{
   222  			name:              "lb with external dns",
   223  			serviceType:       vzapi.LoadBalancer,
   224  			dnsExternalSuffix: testDomain,
   225  			want:              testDomain,
   226  		},
   227  		{
   228  			name:              "lb with external dns and external ip",
   229  			serviceType:       vzapi.LoadBalancer,
   230  			dnsExternalSuffix: testDomain,
   231  			externalIP:        testExternalIP,
   232  			want:              testDomain,
   233  		},
   234  		{
   235  			name:              "lb with wildcard dns and lb ip",
   236  			serviceType:       vzapi.LoadBalancer,
   237  			dnsWildCardSuffix: testWildCardSuffix,
   238  			lbIP:              testLoadBalancerIP,
   239  			want:              testLoadBalancerIP + "." + testWildCardSuffix,
   240  		},
   241  		{
   242  			name:              "lb with wildcard dns and external ip",
   243  			serviceType:       vzapi.LoadBalancer,
   244  			dnsWildCardSuffix: testWildCardSuffix,
   245  			externalIP:        testExternalIP,
   246  			want:              testExternalIP + "." + testWildCardSuffix,
   247  		},
   248  		{
   249  			name:              "lb with wildcard dns and both external and lb ip",
   250  			serviceType:       vzapi.LoadBalancer,
   251  			dnsWildCardSuffix: testWildCardSuffix,
   252  			lbIP:              testLoadBalancerIP,
   253  			externalIP:        testExternalIP,
   254  			want:              testExternalIP + "." + testWildCardSuffix,
   255  		},
   256  		{
   257  			name:        "lb with external ip",
   258  			serviceType: vzapi.LoadBalancer,
   259  			externalIP:  testExternalIP,
   260  			want:        testExternalIP + "." + defaultWildcardDomain,
   261  		},
   262  		{
   263  			name:        "lb with lb ip",
   264  			serviceType: vzapi.LoadBalancer,
   265  			lbIP:        testLoadBalancerIP,
   266  			want:        testLoadBalancerIP + "." + defaultWildcardDomain,
   267  		},
   268  		{
   269  			name:        "lb with both external and lb ip",
   270  			serviceType: vzapi.LoadBalancer,
   271  			lbIP:        testLoadBalancerIP,
   272  			externalIP:  testExternalIP,
   273  			want:        testExternalIP + "." + defaultWildcardDomain,
   274  		},
   275  		{
   276  			name:        "lb no address found",
   277  			serviceType: vzapi.LoadBalancer,
   278  			wantErr:     true,
   279  		},
   280  		{
   281  			name:        "nodeport without external ip",
   282  			serviceType: vzapi.NodePort,
   283  			wantErr:     true,
   284  		},
   285  		{
   286  			name:        "nodeport with external ip",
   287  			serviceType: vzapi.NodePort,
   288  			externalIP:  testExternalIP,
   289  			want:        testExternalIP + "." + defaultWildcardDomain,
   290  		},
   291  		{
   292  			name:              "nodeport with external dns and external ip",
   293  			serviceType:       vzapi.NodePort,
   294  			dnsExternalSuffix: testDomain,
   295  			externalIP:        testExternalIP,
   296  			want:              testDomain,
   297  		},
   298  	}
   299  	for _, tt := range tests {
   300  		t.Run(tt.name, func(t *testing.T) {
   301  			vz := &vzapi.Verrazzano{
   302  				Spec: vzapi.VerrazzanoSpec{
   303  					Components: vzapi.ComponentSpec{
   304  						Ingress: &vzapi.IngressNginxComponent{
   305  							Type: tt.serviceType,
   306  						},
   307  					},
   308  				},
   309  			}
   310  			if len(tt.dnsOCIZone) > 0 {
   311  				vz.Spec.Components.DNS = &vzapi.DNSComponent{
   312  					OCI: &vzapi.OCI{
   313  						DNSZoneName: testDomain,
   314  					},
   315  				}
   316  			} else if len(tt.dnsExternalSuffix) > 0 {
   317  				vz.Spec.Components.DNS = &vzapi.DNSComponent{
   318  					External: &vzapi.External{
   319  						Suffix: tt.dnsExternalSuffix,
   320  					},
   321  				}
   322  			} else if len(tt.dnsWildCardSuffix) > 0 {
   323  				vz.Spec.Components.DNS = &vzapi.DNSComponent{
   324  					Wildcard: &vzapi.Wildcard{
   325  						Domain: tt.dnsWildCardSuffix,
   326  					},
   327  				}
   328  			}
   329  			svc := &corev1.Service{
   330  				ObjectMeta: metav1.ObjectMeta{
   331  					Namespace: nginxutil.IngressNGINXNamespace(),
   332  					Name:      vpoconst.NGINXControllerServiceName,
   333  				},
   334  			}
   335  			if len(tt.externalIP) > 0 {
   336  				svc.Spec = corev1.ServiceSpec{
   337  					ExternalIPs: []string{tt.externalIP},
   338  				}
   339  			}
   340  			if len(tt.lbIP) > 0 {
   341  				svc.Status = corev1.ServiceStatus{
   342  					LoadBalancer: corev1.LoadBalancerStatus{
   343  						Ingress: []corev1.LoadBalancerIngress{
   344  							{IP: tt.lbIP},
   345  						},
   346  					},
   347  				}
   348  			}
   349  			fakeClient := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(svc).Build()
   350  			got, err := GetDNSSuffix(fakeClient, vz)
   351  			if (err != nil) != tt.wantErr {
   352  				t.Errorf("GetDNSSuffix() error = %v, wantErr %v", err, tt.wantErr)
   353  				return
   354  			}
   355  			if got != tt.want {
   356  				t.Errorf("GetDNSSuffix() got = %v, want %v", got, tt.want)
   357  			}
   358  		})
   359  	}
   360  }
   361  
   362  // TestGetEnvName tests the GetEnvName function
   363  // GIVEN a call to GetEnvName
   364  //
   365  //	WHEN the VZ config specifies an env name
   366  //	THEN the configured env name is returned
   367  func TestGetEnvName(t *testing.T) {
   368  	vz := &vzapi.Verrazzano{
   369  		Spec: vzapi.VerrazzanoSpec{
   370  			EnvironmentName: "myenv",
   371  		},
   372  	}
   373  	assert.Equal(t, "myenv", GetEnvName(vz))
   374  }
   375  
   376  // TestGetEnvNameDefault tests the GetEnvName function
   377  // GIVEN a call to GetEnvName
   378  //
   379  //	WHEN the VZ config does not explicitly configure an EnvironmentName
   380  //	THEN then "default" is returned
   381  func TestGetEnvNameDefault(t *testing.T) {
   382  	vz := &vzapi.Verrazzano{}
   383  	assert.Equal(t, "default", GetEnvName(vz))
   384  }
   385  
   386  // TestBuildDNSDomainDefaultEnv tests the BuildDNSDomain function
   387  // GIVEN a call to BuildDNSDomain
   388  //
   389  //	WHEN the VZ config specifies no env name
   390  //	THEN the domain name is correctly returned
   391  func TestBuildDNSDomainDefaultEnv(t *testing.T) {
   392  	vz := &vzapi.Verrazzano{
   393  		Spec: vzapi.VerrazzanoSpec{
   394  			Components: vzapi.ComponentSpec{
   395  				DNS: &vzapi.DNSComponent{
   396  					OCI: &vzapi.OCI{
   397  						DNSZoneName: testDomain,
   398  					},
   399  				},
   400  			},
   401  		},
   402  	}
   403  	domain, err := BuildDNSDomain(fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build(), vz)
   404  	assert.NoError(t, err)
   405  	assert.Equal(t, "default."+testDomain, domain)
   406  }
   407  
   408  // TestBuildDNSDomainCustomEnv tests the BuildDNSDomain function
   409  // GIVEN a call to BuildDNSDomain
   410  //
   411  //	WHEN the VZ config specifies a custom env name
   412  //	THEN the domain name is correctly returned
   413  func TestBuildDNSDomainCustomEnv(t *testing.T) {
   414  	vz := &vzapi.Verrazzano{
   415  		Spec: vzapi.VerrazzanoSpec{
   416  			EnvironmentName: "myenv",
   417  			Components: vzapi.ComponentSpec{
   418  				DNS: &vzapi.DNSComponent{
   419  					OCI: &vzapi.OCI{
   420  						DNSZoneName: testDomain,
   421  					},
   422  				},
   423  			},
   424  		},
   425  	}
   426  	domain, err := BuildDNSDomain(fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build(), vz)
   427  	assert.NoError(t, err)
   428  	assert.Equal(t, "myenv."+testDomain, domain)
   429  }
   430  
   431  // TestFindVolumeTemplate Test the FindVolumeTemplate utility function
   432  // GIVEN a call to FindVolumeTemplate
   433  // WHEN valid or invalid arguments are given
   434  // THEN true and the found template are is returned if found, nil/false otherwise
   435  func TestFindVolumeTemplate(t *testing.T) {
   436  
   437  	specTemplateList := []vzapi.VolumeClaimSpecTemplate{
   438  		{
   439  			ObjectMeta: metav1.ObjectMeta{Name: "default"},
   440  			Spec: corev1.PersistentVolumeClaimSpec{
   441  				VolumeName: "defVolume",
   442  			},
   443  		},
   444  		{
   445  			ObjectMeta: metav1.ObjectMeta{Name: "template1"},
   446  			Spec: corev1.PersistentVolumeClaimSpec{
   447  				VolumeName: "temp1Volume",
   448  			},
   449  		},
   450  		{
   451  			ObjectMeta: metav1.ObjectMeta{Name: "template2"},
   452  			Spec: corev1.PersistentVolumeClaimSpec{
   453  				VolumeName: "temp2Volume",
   454  			},
   455  		},
   456  	}
   457  
   458  	vz := vzapi.Verrazzano{
   459  		Spec: vzapi.VerrazzanoSpec{
   460  			VolumeClaimSpecTemplates: specTemplateList,
   461  		},
   462  	}
   463  	// Test boundary conditions
   464  	invalidName, found := FindVolumeTemplate("blah", &vz)
   465  	assert.Nil(t, invalidName)
   466  	assert.False(t, found)
   467  	emptyName, found2 := FindVolumeTemplate("", &vz)
   468  	assert.Nil(t, emptyName)
   469  	assert.False(t, found2)
   470  	nilList, found3 := FindVolumeTemplate("default", nil)
   471  	assert.Nil(t, nilList)
   472  	assert.False(t, found3)
   473  	emptyList, found4 := FindVolumeTemplate("default", &vzapi.Verrazzano{
   474  		Spec: vzapi.VerrazzanoSpec{
   475  			VolumeClaimSpecTemplates: []vzapi.VolumeClaimSpecTemplate{},
   476  		},
   477  	})
   478  	assert.Nil(t, emptyList)
   479  	assert.False(t, found4)
   480  
   481  	// Test normal behavior
   482  	defTemplate, found := FindVolumeTemplate("default", &vz)
   483  	assert.True(t, found)
   484  	assert.Equal(t, "defVolume", defTemplate.VolumeName)
   485  	temp1, found := FindVolumeTemplate("template1", &vz)
   486  	assert.True(t, found)
   487  	assert.Equal(t, "temp1Volume", temp1.VolumeName)
   488  	temp2, found := FindVolumeTemplate("template2", &vz)
   489  	assert.True(t, found)
   490  	assert.Equal(t, "temp2Volume", temp2.VolumeName)
   491  }
   492  
   493  // TestGetIngressClassName Tests the GetIngressClassName utility function
   494  // GIVEN a call to GetIngressClassName
   495  // WHEN a Verrazzano resource with an ingress class name specified is given
   496  // THEN the ingress class name specified in the Verrazzano resource is returned
   497  func TestGetIngressClassName(t *testing.T) {
   498  	assert.Equal(t, defaultIngressClassName, GetIngressClassName(&vzapi.Verrazzano{}))
   499  	ingressClassName := "foobar"
   500  	assert.Equal(t, ingressClassName, GetIngressClassName(&vzapi.Verrazzano{
   501  		Spec: vzapi.VerrazzanoSpec{
   502  			Components: vzapi.ComponentSpec{
   503  				Ingress: &vzapi.IngressNginxComponent{
   504  					IngressClassName: &ingressClassName,
   505  				},
   506  			},
   507  		},
   508  	}))
   509  }