github.com/cilium/cilium@v1.16.2/operator/pkg/ingress/annotations/annotations_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package annotations
     5  
     6  import (
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	networkingv1 "k8s.io/api/networking/v1"
    12  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    13  
    14  	"github.com/cilium/cilium/operator/pkg/model"
    15  )
    16  
    17  func TestGetAnnotationServiceType(t *testing.T) {
    18  	type args struct {
    19  		ingress *networkingv1.Ingress
    20  	}
    21  	tests := []struct {
    22  		name string
    23  		args args
    24  		want string
    25  	}{
    26  		{
    27  			name: "no service type annotation",
    28  			args: args{
    29  				ingress: &networkingv1.Ingress{},
    30  			},
    31  			want: "LoadBalancer",
    32  		},
    33  		{
    34  			name: "service type annotation as LoadBalancer",
    35  			args: args{
    36  				ingress: &networkingv1.Ingress{
    37  					ObjectMeta: metav1.ObjectMeta{
    38  						Annotations: map[string]string{
    39  							"ingress.cilium.io/service-type": "LoadBalancer",
    40  						},
    41  					},
    42  				},
    43  			},
    44  			want: "LoadBalancer",
    45  		},
    46  		{
    47  			name: "service type annotation as NodePort",
    48  			args: args{
    49  				ingress: &networkingv1.Ingress{
    50  					ObjectMeta: metav1.ObjectMeta{
    51  						Annotations: map[string]string{
    52  							"ingress.cilium.io/service-type": "NodePort",
    53  						},
    54  					},
    55  				},
    56  			},
    57  			want: "NodePort",
    58  		},
    59  	}
    60  	for _, tt := range tests {
    61  		t.Run(tt.name, func(t *testing.T) {
    62  			if got := GetAnnotationServiceType(tt.args.ingress); got != tt.want {
    63  				t.Errorf("GetAnnotationServiceType() = %v, want %v", got, tt.want)
    64  			}
    65  		})
    66  	}
    67  }
    68  
    69  func TestGetAnnotationServiceExternalTrafficPolicy(t *testing.T) {
    70  	type args struct {
    71  		ingress *networkingv1.Ingress
    72  	}
    73  	tests := []struct {
    74  		name    string
    75  		args    args
    76  		want    string
    77  		wantErr bool
    78  	}{
    79  		{
    80  			name: "no externalTrafficPolicy annotation",
    81  			args: args{
    82  				ingress: &networkingv1.Ingress{},
    83  			},
    84  			want: "Cluster",
    85  		},
    86  		{
    87  			name: "externalTrafficPolicy as Cluster",
    88  			args: args{
    89  				ingress: &networkingv1.Ingress{
    90  					ObjectMeta: metav1.ObjectMeta{
    91  						Annotations: map[string]string{
    92  							"ingress.cilium.io/service-external-traffic-policy": "Cluster",
    93  						},
    94  					},
    95  				},
    96  			},
    97  			want: "Cluster",
    98  		},
    99  		{
   100  			name: "externalTrafficPolicy as Local",
   101  			args: args{
   102  				ingress: &networkingv1.Ingress{
   103  					ObjectMeta: metav1.ObjectMeta{
   104  						Annotations: map[string]string{
   105  							"ingress.cilium.io/service-external-traffic-policy": "Local",
   106  						},
   107  					},
   108  				},
   109  			},
   110  			want: "Local",
   111  		},
   112  		{
   113  			name: "externalTrafficPolicy set to invalid value",
   114  			args: args{
   115  				ingress: &networkingv1.Ingress{
   116  					ObjectMeta: metav1.ObjectMeta{
   117  						Annotations: map[string]string{
   118  							"ingress.cilium.io/service-external-traffic-policy": "invalid-value",
   119  						},
   120  					},
   121  				},
   122  			},
   123  			want:    "Cluster",
   124  			wantErr: true,
   125  		},
   126  	}
   127  	for _, tt := range tests {
   128  		t.Run(tt.name, func(t *testing.T) {
   129  			got, err := GetAnnotationServiceExternalTrafficPolicy(tt.args.ingress)
   130  			if (err != nil) != tt.wantErr {
   131  				t.Errorf("GetAnnotationServiceExternalTrafficPolicy() error = %v, wantErr %v", err, tt.wantErr)
   132  				return
   133  			}
   134  			if !reflect.DeepEqual(got, tt.want) {
   135  				t.Errorf("GetAnnotationServiceExternalTrafficPolicy() got = %v, want %v", got, tt.want)
   136  			}
   137  		})
   138  	}
   139  }
   140  
   141  func TestGetAnnotationRequestTimeout(t *testing.T) {
   142  	type args struct {
   143  		ingress *networkingv1.Ingress
   144  	}
   145  
   146  	tests := []struct {
   147  		name    string
   148  		args    args
   149  		want    *time.Duration
   150  		wantErr bool
   151  	}{
   152  		{
   153  			name: "no request timeout annotation",
   154  			args: args{
   155  				ingress: &networkingv1.Ingress{},
   156  			},
   157  			want: nil,
   158  		},
   159  		{
   160  			name: "request timeout annotation with valid value",
   161  			args: args{
   162  				ingress: &networkingv1.Ingress{
   163  					ObjectMeta: metav1.ObjectMeta{
   164  						Annotations: map[string]string{
   165  							RequestTimeoutAnnotation: "10s",
   166  						},
   167  					},
   168  				},
   169  			},
   170  			want: model.AddressOf(time.Second * 10),
   171  		},
   172  		{
   173  			name: "request timeout annotation with invalid value",
   174  			args: args{
   175  				ingress: &networkingv1.Ingress{
   176  					ObjectMeta: metav1.ObjectMeta{
   177  						Annotations: map[string]string{
   178  							RequestTimeoutAnnotation: "invalid",
   179  						},
   180  					},
   181  				},
   182  			},
   183  			want:    nil,
   184  			wantErr: true,
   185  		},
   186  	}
   187  
   188  	for _, tt := range tests {
   189  		t.Run(tt.name, func(t *testing.T) {
   190  			got, err := GetAnnotationRequestTimeout(tt.args.ingress)
   191  			if (err != nil) != tt.wantErr {
   192  				t.Errorf("GetAnnotationRequestTimeout() error = %v, wantErr %v", err, tt.wantErr)
   193  				return
   194  			}
   195  
   196  			if !reflect.DeepEqual(got, tt.want) {
   197  				t.Errorf("GetAnnotationRequestTimeout() got = %v, want %v", got, tt.want)
   198  			}
   199  		})
   200  	}
   201  }
   202  
   203  func TestGetAnnotationSecureNodePort(t *testing.T) {
   204  	type args struct {
   205  		ingress *networkingv1.Ingress
   206  	}
   207  	tests := []struct {
   208  		name    string
   209  		args    args
   210  		want    *uint32
   211  		wantErr bool
   212  	}{
   213  		{
   214  			name: "no secure node port annotation",
   215  			args: args{
   216  				ingress: &networkingv1.Ingress{},
   217  			},
   218  			want: nil,
   219  		},
   220  		{
   221  			name: "secure node port annotation with valid value",
   222  			args: args{
   223  				ingress: &networkingv1.Ingress{
   224  					ObjectMeta: metav1.ObjectMeta{
   225  						Annotations: map[string]string{
   226  							"ingress.cilium.io/secure-node-port": "1000",
   227  						},
   228  					},
   229  				},
   230  			},
   231  			want: uint32p(1000),
   232  		},
   233  		{
   234  			name: "secure node port annotation with invalid value",
   235  			args: args{
   236  				ingress: &networkingv1.Ingress{
   237  					ObjectMeta: metav1.ObjectMeta{
   238  						Annotations: map[string]string{
   239  							"ingress.cilium.io/secure-node-port": "invalid-numeric-value",
   240  						},
   241  					},
   242  				},
   243  			},
   244  			want:    nil,
   245  			wantErr: true,
   246  		},
   247  	}
   248  
   249  	for _, tt := range tests {
   250  		t.Run(tt.name, func(t *testing.T) {
   251  			got, err := GetAnnotationSecureNodePort(tt.args.ingress)
   252  			if (err != nil) != tt.wantErr {
   253  				t.Errorf("GetAnnotationSecureNodePort() error = %v, wantErr %v", err, tt.wantErr)
   254  				return
   255  			}
   256  			if !reflect.DeepEqual(got, tt.want) {
   257  				t.Errorf("GetAnnotationSecureNodePort() got = %v, want %v", got, tt.want)
   258  			}
   259  		})
   260  	}
   261  }
   262  
   263  func TestGetAnnotationInsecureNodePort(t *testing.T) {
   264  	type args struct {
   265  		ingress *networkingv1.Ingress
   266  	}
   267  	tests := []struct {
   268  		name    string
   269  		args    args
   270  		want    *uint32
   271  		wantErr bool
   272  	}{
   273  		{
   274  			name: "no insecure node port annotation",
   275  			args: args{
   276  				ingress: &networkingv1.Ingress{},
   277  			},
   278  			want: nil,
   279  		},
   280  		{
   281  			name: "insecure node port annotation with valid value",
   282  			args: args{
   283  				ingress: &networkingv1.Ingress{
   284  					ObjectMeta: metav1.ObjectMeta{
   285  						Annotations: map[string]string{
   286  							"ingress.cilium.io/insecure-node-port": "1000",
   287  						},
   288  					},
   289  				},
   290  			},
   291  			want: uint32p(1000),
   292  		},
   293  		{
   294  			name: "insecure node port annotation with invalid value",
   295  			args: args{
   296  				ingress: &networkingv1.Ingress{
   297  					ObjectMeta: metav1.ObjectMeta{
   298  						Annotations: map[string]string{
   299  							"ingress.cilium.io/insecure-node-port": "invalid-numeric-value",
   300  						},
   301  					},
   302  				},
   303  			},
   304  			want:    nil,
   305  			wantErr: true,
   306  		},
   307  	}
   308  	for _, tt := range tests {
   309  		t.Run(tt.name, func(t *testing.T) {
   310  			got, err := GetAnnotationInsecureNodePort(tt.args.ingress)
   311  			if (err != nil) != tt.wantErr {
   312  				t.Errorf("GetAnnotationSecureNodePort() error = %v, wantErr %v", err, tt.wantErr)
   313  				return
   314  			}
   315  			if !reflect.DeepEqual(got, tt.want) {
   316  				t.Errorf("GetAnnotationSecureNodePort() got = %v, want %v", got, tt.want)
   317  			}
   318  		})
   319  	}
   320  }
   321  
   322  func TestGetAnnotationHostListenerPort(t *testing.T) {
   323  	type args struct {
   324  		ingress *networkingv1.Ingress
   325  	}
   326  	tests := []struct {
   327  		name    string
   328  		args    args
   329  		want    *uint32
   330  		wantErr bool
   331  	}{
   332  		{
   333  			name: "no host listener port annotation",
   334  			args: args{
   335  				ingress: &networkingv1.Ingress{},
   336  			},
   337  			want: nil,
   338  		},
   339  		{
   340  			name: "host listener port annotation with valid value",
   341  			args: args{
   342  				ingress: &networkingv1.Ingress{
   343  					ObjectMeta: metav1.ObjectMeta{
   344  						Annotations: map[string]string{
   345  							"ingress.cilium.io/host-listener-port": "1000",
   346  						},
   347  					},
   348  				},
   349  			},
   350  			want: uint32p(1000),
   351  		},
   352  		{
   353  			name: "host listener port annotation with invalid non-numeric value",
   354  			args: args{
   355  				ingress: &networkingv1.Ingress{
   356  					ObjectMeta: metav1.ObjectMeta{
   357  						Annotations: map[string]string{
   358  							"ingress.cilium.io/host-listener-port": "invalid-numeric-value",
   359  						},
   360  					},
   361  				},
   362  			},
   363  			want:    nil,
   364  			wantErr: true,
   365  		},
   366  	}
   367  
   368  	for _, tt := range tests {
   369  		t.Run(tt.name, func(t *testing.T) {
   370  			got, err := GetAnnotationHostListenerPort(tt.args.ingress)
   371  			if (err != nil) != tt.wantErr {
   372  				t.Errorf("GetAnnotationHostListenerPort() error = %v, wantErr %v", err, tt.wantErr)
   373  				return
   374  			}
   375  			if !reflect.DeepEqual(got, tt.want) {
   376  				t.Errorf("GetAnnotationHostListenerPort() got = %v, want %v", got, tt.want)
   377  			}
   378  		})
   379  	}
   380  }
   381  
   382  func TestGetAnnotationSSLPassthrough(t *testing.T) {
   383  	type args struct {
   384  		ingress *networkingv1.Ingress
   385  	}
   386  	tests := []struct {
   387  		name string
   388  		args args
   389  		want bool
   390  	}{
   391  		{
   392  			name: "no SSL Passthrough port annotation",
   393  			args: args{
   394  				ingress: &networkingv1.Ingress{},
   395  			},
   396  			want: false,
   397  		},
   398  		{
   399  			name: "SSL Passthrough annotation present and enabled",
   400  			args: args{
   401  				ingress: &networkingv1.Ingress{
   402  					ObjectMeta: metav1.ObjectMeta{
   403  						Annotations: map[string]string{
   404  							"ingress.cilium.io/tls-passthrough": "enabled",
   405  						},
   406  					},
   407  				},
   408  			},
   409  			want: true,
   410  		},
   411  		{
   412  			name: "SSL Passthrough annotation present and disabled",
   413  			args: args{
   414  				ingress: &networkingv1.Ingress{
   415  					ObjectMeta: metav1.ObjectMeta{
   416  						Annotations: map[string]string{
   417  							"ingress.cilium.io/tls-passthrough": "disabled",
   418  						},
   419  					},
   420  				},
   421  			},
   422  			want: false,
   423  		},
   424  		{
   425  			name: "SSL Passthrough annotation present and true",
   426  			args: args{
   427  				ingress: &networkingv1.Ingress{
   428  					ObjectMeta: metav1.ObjectMeta{
   429  						Annotations: map[string]string{
   430  							"ingress.cilium.io/tls-passthrough": "true",
   431  						},
   432  					},
   433  				},
   434  			},
   435  			want: true,
   436  		},
   437  		{
   438  			name: "SSL Passthrough annotation present and false",
   439  			args: args{
   440  				ingress: &networkingv1.Ingress{
   441  					ObjectMeta: metav1.ObjectMeta{
   442  						Annotations: map[string]string{
   443  							"ingress.cilium.io/tls-passthrough": "false",
   444  						},
   445  					},
   446  				},
   447  			},
   448  			want: false,
   449  		},
   450  		{
   451  			name: "SSL Passthrough annotation present and invalid",
   452  			args: args{
   453  				ingress: &networkingv1.Ingress{
   454  					ObjectMeta: metav1.ObjectMeta{
   455  						Annotations: map[string]string{
   456  							"ingress.cilium.io/tls-passthrough": "invalid",
   457  						},
   458  					},
   459  				},
   460  			},
   461  			want: false,
   462  		},
   463  	}
   464  	for _, tt := range tests {
   465  		t.Run(tt.name, func(t *testing.T) {
   466  			got := GetAnnotationTLSPassthroughEnabled(tt.args.ingress)
   467  
   468  			if !reflect.DeepEqual(got, tt.want) {
   469  				t.Errorf("GetAnnotationSecureNodePort() got = %v, want %v", got, tt.want)
   470  			}
   471  		})
   472  	}
   473  }
   474  
   475  func TestGetAnnotationEnforceHTTPSEnabled(t *testing.T) {
   476  	type args struct {
   477  		ingress *networkingv1.Ingress
   478  	}
   479  
   480  	tests := []struct {
   481  		name string
   482  		args args
   483  		want *bool
   484  	}{
   485  		{
   486  			name: "no SSL Passthrough port annotation",
   487  			args: args{
   488  				ingress: &networkingv1.Ingress{},
   489  			},
   490  			want: nil,
   491  		},
   492  		{
   493  			name: "SSL Passthrough annotation present and enabled",
   494  			args: args{
   495  				ingress: &networkingv1.Ingress{
   496  					ObjectMeta: metav1.ObjectMeta{
   497  						Annotations: map[string]string{
   498  							"ingress.cilium.io/force-https": "enabled",
   499  						},
   500  					},
   501  				},
   502  			},
   503  			want: model.AddressOf(true),
   504  		},
   505  		{
   506  			name: "SSL Passthrough annotation present and disabled",
   507  			args: args{
   508  				ingress: &networkingv1.Ingress{
   509  					ObjectMeta: metav1.ObjectMeta{
   510  						Annotations: map[string]string{
   511  							"ingress.cilium.io/force-https": "disabled",
   512  						},
   513  					},
   514  				},
   515  			},
   516  			want: model.AddressOf(false),
   517  		},
   518  		{
   519  			name: "SSL Passthrough annotation present and true",
   520  			args: args{
   521  				ingress: &networkingv1.Ingress{
   522  					ObjectMeta: metav1.ObjectMeta{
   523  						Annotations: map[string]string{
   524  							"ingress.cilium.io/force-https": "true",
   525  						},
   526  					},
   527  				},
   528  			},
   529  			want: model.AddressOf(true),
   530  		},
   531  		{
   532  			name: "SSL Passthrough annotation present and false",
   533  			args: args{
   534  				ingress: &networkingv1.Ingress{
   535  					ObjectMeta: metav1.ObjectMeta{
   536  						Annotations: map[string]string{
   537  							"ingress.cilium.io/force-https": "false",
   538  						},
   539  					},
   540  				},
   541  			},
   542  			want: model.AddressOf(false),
   543  		},
   544  		{
   545  			name: "SSL Passthrough annotation present and invalid",
   546  			args: args{
   547  				ingress: &networkingv1.Ingress{
   548  					ObjectMeta: metav1.ObjectMeta{
   549  						Annotations: map[string]string{
   550  							"ingress.cilium.io/force-https": "invalid",
   551  						},
   552  					},
   553  				},
   554  			},
   555  			want: nil,
   556  		},
   557  	}
   558  	for _, tt := range tests {
   559  		t.Run(tt.name, func(t *testing.T) {
   560  			got := GetAnnotationForceHTTPSEnabled(tt.args.ingress)
   561  			if !reflect.DeepEqual(got, tt.want) {
   562  				t.Errorf("GetAnnotationForceHTTPSEnabled() got = %v, want %v", got, tt.want)
   563  			}
   564  		})
   565  	}
   566  }
   567  
   568  func TestGetAnnotationLoadBalancerClass(t *testing.T) {
   569  	type args struct {
   570  		ingress *networkingv1.Ingress
   571  	}
   572  	tests := []struct {
   573  		name string
   574  		args args
   575  		want *string
   576  	}{
   577  		{
   578  			name: "no load balancer class annotation",
   579  			args: args{
   580  				ingress: &networkingv1.Ingress{},
   581  			},
   582  			want: nil,
   583  		},
   584  		{
   585  			name: "load balancer class annotation present",
   586  			args: args{
   587  				ingress: &networkingv1.Ingress{
   588  					ObjectMeta: metav1.ObjectMeta{
   589  						Annotations: map[string]string{
   590  							"ingress.cilium.io/loadbalancer-class": "foo",
   591  						},
   592  					},
   593  				},
   594  			},
   595  			want: stringp("foo"),
   596  		},
   597  	}
   598  	for _, tt := range tests {
   599  		t.Run(tt.name, func(t *testing.T) {
   600  			got := GetAnnotationLoadBalancerClass(tt.args.ingress)
   601  			if !isStringpEqual(got, tt.want) {
   602  				t.Errorf("GetAnnotationLoadBalancerClass() = %v, want %v", got, tt.want)
   603  			}
   604  		})
   605  	}
   606  }
   607  
   608  func uint32p(u uint32) *uint32 {
   609  	return &u
   610  }
   611  
   612  func stringp(s string) *string {
   613  	return &s
   614  }
   615  
   616  func isStringpEqual(a, b *string) bool {
   617  	if a == nil && b == nil {
   618  		return true
   619  	}
   620  	if a == nil || b == nil {
   621  		return false
   622  	}
   623  	return *a == *b
   624  }