github.com/cilium/cilium@v1.16.2/operator/pkg/model/translation/gateway-api/translator_test.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package gateway_api
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  
    10  	envoy_config_route_v3 "github.com/cilium/proxy/go/envoy/config/route/v3"
    11  	"github.com/google/go-cmp/cmp"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  	"google.golang.org/protobuf/testing/protocmp"
    15  	corev1 "k8s.io/api/core/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  	"k8s.io/apimachinery/pkg/types"
    18  	gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1"
    19  
    20  	"github.com/cilium/cilium/operator/pkg/model"
    21  	"github.com/cilium/cilium/operator/pkg/model/translation"
    22  	ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    23  	slim_metav1 "github.com/cilium/cilium/pkg/k8s/slim/k8s/apis/meta/v1"
    24  )
    25  
    26  func Test_translator_Translate(t *testing.T) {
    27  	type args struct {
    28  		m *model.Model
    29  	}
    30  	tests := []struct {
    31  		name    string
    32  		args    args
    33  		want    *ciliumv2.CiliumEnvoyConfig
    34  		wantErr bool
    35  	}{
    36  		{
    37  			name: "Basic HTTP Listener",
    38  			args: args{
    39  				m: &model.Model{
    40  					HTTP: basicHTTPListeners(80),
    41  				},
    42  			},
    43  			want: basicHTTPListenersCiliumEnvoyConfig,
    44  		},
    45  		{
    46  			name: "Basic TLS SNI Listener",
    47  			args: args{
    48  				m: &model.Model{
    49  					TLSPassthrough: basicTLSListeners,
    50  				},
    51  			},
    52  			want: basicTLSListenersCiliumEnvoyConfig,
    53  		},
    54  		{
    55  			name: "Conformance/HTTPRouteSimpleSameNamespace",
    56  			args: args{
    57  				m: &model.Model{
    58  					HTTP: simpleSameNamespaceHTTPListeners,
    59  				},
    60  			},
    61  			want: simpleSameNamespaceHTTPListenersCiliumEnvoyConfig,
    62  		},
    63  		{
    64  			name: "Conformance/HTTPRouteBackendProtocolH2C",
    65  			args: args{
    66  				m: &model.Model{
    67  					HTTP: backendProtocolDisabledH2CHTTPListeners,
    68  				},
    69  			},
    70  			want: simpleSameNamespaceHTTPListenersCiliumEnvoyConfig,
    71  		},
    72  		{
    73  			name: "Conformance/HTTPRouteCrossNamespace",
    74  			args: args{
    75  				m: &model.Model{
    76  					HTTP: crossNamespaceHTTPListeners,
    77  				},
    78  			},
    79  			want: crossNamespaceHTTPListenersCiliumEnvoyConfig,
    80  		},
    81  		{
    82  			name: "Conformance/HTTPExactPathMatching",
    83  			args: args{
    84  				m: &model.Model{
    85  					HTTP: exactPathMatchingHTTPListeners,
    86  				},
    87  			},
    88  			want: exactPathMatchingHTTPListenersCiliumEnvoyConfig,
    89  		},
    90  		{
    91  			name: "Conformance/HTTPRouteHeaderMatching",
    92  			args: args{
    93  				m: &model.Model{
    94  					HTTP: headerMatchingHTTPListeners,
    95  				},
    96  			},
    97  			want: headerMatchingHTTPCiliumEnvoyConfig,
    98  		},
    99  		{
   100  			name: "Conformance/HTTPRouteHostnameIntersection",
   101  			args: args{
   102  				m: &model.Model{
   103  					HTTP: hostnameIntersectionHTTPListeners,
   104  				},
   105  			},
   106  			want: hostnameIntersectionHTTPListenersCiliumEnvoyConfig,
   107  		},
   108  		{
   109  			name: "Conformance/HTTPRouteListenerHostnameMatching",
   110  			args: args{
   111  				m: &model.Model{
   112  					HTTP: listenerHostnameMatchingHTTPListeners,
   113  				},
   114  			},
   115  			want: listenerHostNameMatchingCiliumEnvoyConfig,
   116  		},
   117  		{
   118  			name: "Conformance/HTTPRouteMatchingAcrossRoutes",
   119  			args: args{
   120  				m: &model.Model{
   121  					HTTP: matchingAcrossHTTPListeners,
   122  				},
   123  			},
   124  			want: matchingAcrossHTTPListenersCiliumEnvoyConfig,
   125  		},
   126  		{
   127  			name: "Conformance/HTTPRouteMatching",
   128  			args: args{
   129  				m: &model.Model{
   130  					HTTP: matchingHTTPListeners,
   131  				},
   132  			},
   133  			want: matchingHTTPListenersCiliumEnvoyConfig,
   134  		},
   135  		{
   136  			name: "Conformance/HTTPRouteMethodMatching",
   137  			args: args{
   138  				m: &model.Model{
   139  					HTTP: methodMatchingHTTPListeners,
   140  				},
   141  			},
   142  			want: methodMatchingHTTPListenersHTTPListenersCiliumEnvoyConfig,
   143  		},
   144  		{
   145  			name: "Conformance/HTTPRouteQueryParamMatching",
   146  			args: args{
   147  				m: &model.Model{
   148  					HTTP: queryParamMatchingHTTPListeners,
   149  				},
   150  			},
   151  			want: queryParamMatchingHTTPListenersCiliumEnvoyConfig,
   152  		},
   153  		{
   154  			name: "Conformance/HTTPRouteRequestHeaderModifier",
   155  			args: args{
   156  				m: &model.Model{
   157  					HTTP: requestHeaderModifierHTTPListeners,
   158  				},
   159  			},
   160  			want: requestHeaderModifierHTTPListenersCiliumEnvoyConfig,
   161  		},
   162  		{
   163  			name: "Conformance/HTTPRouteBackendRefsRequestHeaderModifier",
   164  			args: args{
   165  				m: &model.Model{
   166  					HTTP: backendRefsRequestHeaderModifierHTTPListeners,
   167  				},
   168  			},
   169  			want: backendRefsRequestHeaderModifierHTTPListenersCiliumEnvoyConfig,
   170  		},
   171  		{
   172  			name: "Conformance/HTTPRouteRequestRedirect",
   173  			args: args{
   174  				m: &model.Model{
   175  					HTTP: requestRedirectHTTPListeners,
   176  				},
   177  			},
   178  			want: requestRedirectHTTPListenersCiliumEnvoyConfig,
   179  		},
   180  		{
   181  			name: "Conformance/HTTPRouteResponseHeaderModifier",
   182  			args: args{
   183  				m: &model.Model{
   184  					HTTP: responseHeaderModifierHTTPListeners,
   185  				},
   186  			},
   187  			want: responseHeaderModifierHTTPListenersCiliumEnvoyConfig,
   188  		},
   189  		{
   190  			name: "Conformance/HTTPRouteBackendRefsResponseHeaderModifier",
   191  			args: args{
   192  				m: &model.Model{
   193  					HTTP: backendRefsResponseHeaderModifierHTTPListeners,
   194  				},
   195  			},
   196  			want: backendRefsResponseHeaderModifierHTTPListenersCiliumEnvoyConfig,
   197  		},
   198  		{
   199  			name: "Conformance/HTTPRouteRewriteHost",
   200  			args: args{
   201  				m: &model.Model{
   202  					HTTP: rewriteHostHTTPListeners,
   203  				},
   204  			},
   205  			want: rewriteHostHTTPListenersCiliumEnvoyConfig,
   206  		},
   207  		{
   208  			name: "Conformance/HTTPRouteRewritePath",
   209  			args: args{
   210  				m: &model.Model{
   211  					HTTP: rewritePathHTTPListeners,
   212  				},
   213  			},
   214  			want: rewritePathHTTPListenersCiliumEnvoyConfig,
   215  		},
   216  		{
   217  			name: "Conformance/HTTPRouteRequestMirror",
   218  			args: args{
   219  				m: &model.Model{
   220  					HTTP: mirrorHTTPListeners,
   221  				},
   222  			},
   223  			want: mirrorHTTPListenersCiliumEnvoyConfig,
   224  		},
   225  		{
   226  			name: "Conformance/HTTPRouteRequestRedirectWithMultiHTTPListeners",
   227  			args: args{
   228  				m: &model.Model{
   229  					HTTP: requestRedirectWithMultiHTTPListeners,
   230  				},
   231  			},
   232  			want: requestRedirectWithMultiHTTPListenersCiliumEnvoyConfig,
   233  		},
   234  	}
   235  	for _, tt := range tests {
   236  		t.Run(tt.name, func(t *testing.T) {
   237  			trans := &gatewayAPITranslator{
   238  				cecTranslator: translation.NewCECTranslator("cilium-secrets", false, false, true, 60, false, nil, false, false, 0),
   239  			}
   240  			cec, _, _, err := trans.Translate(tt.args.m)
   241  			require.Equal(t, tt.wantErr, err != nil, "Error mismatch")
   242  			require.Equal(t, tt.want, cec, "CiliumEnvoyConfig did not match")
   243  		})
   244  	}
   245  }
   246  
   247  func Test_translator_TranslateResource(t *testing.T) {
   248  	type args struct {
   249  		m *model.Model
   250  	}
   251  	tests := []struct {
   252  		name          string
   253  		args          args
   254  		wantErr       bool
   255  		validateFuncs []func(config *ciliumv2.CiliumEnvoyConfig) bool
   256  	}{
   257  		{
   258  			name: "MultipleListenerGateway",
   259  			args: args{
   260  				m: &model.Model{
   261  					HTTP: multipleListenerGatewayListeners,
   262  				},
   263  			},
   264  			validateFuncs: []func(cec *ciliumv2.CiliumEnvoyConfig) bool{
   265  				func(cec *ciliumv2.CiliumEnvoyConfig) bool {
   266  					resource := ciliumv2.XDSResource{
   267  						Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   268  							Name: "listener-insecure",
   269  							VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   270  								{
   271  									Name: "example.com",
   272  									Domains: []string{
   273  										"example.com",
   274  										"example.com:*",
   275  									},
   276  									Routes: []*envoy_config_route_v3.Route{
   277  										{
   278  											Match: &envoy_config_route_v3.RouteMatch{
   279  												PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   280  													Prefix: "/",
   281  												},
   282  											},
   283  											Action: &envoy_config_route_v3.Route_Redirect{
   284  												Redirect: &envoy_config_route_v3.RedirectAction{
   285  													SchemeRewriteSpecifier: &envoy_config_route_v3.RedirectAction_SchemeRedirect{
   286  														SchemeRedirect: "https",
   287  													},
   288  													PortRedirect: 443,
   289  												},
   290  											},
   291  										},
   292  									},
   293  								},
   294  							},
   295  						}),
   296  					}
   297  
   298  					expected, _ := resource.MarshalJSON()
   299  					got, _ := cec.Spec.Resources[1].MarshalJSON()
   300  					return assert.Equal(t, string(expected), string(got), "Route Configuration mismatch")
   301  				},
   302  				func(cec *ciliumv2.CiliumEnvoyConfig) bool {
   303  					resource := ciliumv2.XDSResource{
   304  						Any: toAny(&envoy_config_route_v3.RouteConfiguration{
   305  							Name: "listener-secure",
   306  							VirtualHosts: []*envoy_config_route_v3.VirtualHost{
   307  								{
   308  									Name: "example.com",
   309  									Domains: []string{
   310  										"example.com",
   311  										"example.com:*",
   312  									},
   313  									Routes: []*envoy_config_route_v3.Route{
   314  										{
   315  											Match: &envoy_config_route_v3.RouteMatch{
   316  												PathSpecifier: &envoy_config_route_v3.RouteMatch_Prefix{
   317  													Prefix: "/",
   318  												},
   319  											},
   320  											Action: toRouteAction("default", "my-service", "8080"),
   321  										},
   322  									},
   323  								},
   324  							},
   325  						}),
   326  					}
   327  
   328  					expected, _ := resource.MarshalJSON()
   329  					got, _ := cec.Spec.Resources[2].MarshalJSON()
   330  					return assert.Equal(t, string(expected), string(got), "Route Configuration mismatch")
   331  				},
   332  			},
   333  		},
   334  	}
   335  
   336  	for _, tt := range tests {
   337  		t.Run(tt.name, func(t *testing.T) {
   338  			trans := &gatewayAPITranslator{
   339  				cecTranslator: translation.NewCECTranslator("cilium-secrets", false, false, true, 60, false, nil, false, false, 0),
   340  			}
   341  			cec, _, _, err := trans.Translate(tt.args.m)
   342  			require.Equal(t, tt.wantErr, err != nil, "Error mismatch")
   343  			for _, fn := range tt.validateFuncs {
   344  				require.True(t, fn(cec), "Validation failed")
   345  			}
   346  		})
   347  	}
   348  }
   349  
   350  func Test_translator_Translate_AppProtocol(t *testing.T) {
   351  	type args struct {
   352  		m *model.Model
   353  	}
   354  	tests := []struct {
   355  		name    string
   356  		args    args
   357  		want    *ciliumv2.CiliumEnvoyConfig
   358  		wantErr bool
   359  	}{
   360  		{
   361  			name: "Conformance/HTTPRouteBackendProtocolH2C",
   362  			args: args{
   363  				m: &model.Model{
   364  					HTTP: backendProtocolEnabledH2CHTTPListeners,
   365  				},
   366  			},
   367  			want: backendProtocolEnabledH2CHTTPListenersCiliumEnvoyConfig,
   368  		},
   369  	}
   370  	for _, tt := range tests {
   371  		t.Run(tt.name, func(t *testing.T) {
   372  			trans := &gatewayAPITranslator{
   373  				cecTranslator: translation.NewCECTranslator("cilium-secrets", false, true, true, 60, false, nil, false, false, 0),
   374  			}
   375  			cec, _, _, err := trans.Translate(tt.args.m)
   376  			require.Equal(t, tt.wantErr, err != nil, "Error mismatch")
   377  			require.Equal(t, tt.want, cec, "CiliumEnvoyConfig did not match")
   378  		})
   379  	}
   380  }
   381  
   382  func Test_translator_Translate_HostNetwork(t *testing.T) {
   383  	type args struct {
   384  		m *model.Model
   385  	}
   386  	tests := []struct {
   387  		name              string
   388  		args              args
   389  		nodeLabelSelector *slim_metav1.LabelSelector
   390  		ipv4Enabled       bool
   391  		ipv6Enabled       bool
   392  		want              *ciliumv2.CiliumEnvoyConfig
   393  		wantErr           bool
   394  	}{
   395  		{
   396  			name:        "Basic HTTP Listener",
   397  			ipv4Enabled: true,
   398  			args: args{
   399  				m: &model.Model{
   400  					HTTP: basicHTTPListeners(80),
   401  				},
   402  			},
   403  			want: basicHostPortHTTPListenersCiliumEnvoyConfig("0.0.0.0", 80, nil),
   404  		},
   405  		{
   406  			name:        "Basic HTTP Listener with different port",
   407  			ipv4Enabled: true,
   408  			args: args{
   409  				m: &model.Model{
   410  					HTTP: basicHTTPListeners(55555),
   411  				},
   412  			},
   413  			want: basicHostPortHTTPListenersCiliumEnvoyConfig("0.0.0.0", 55555, nil),
   414  		},
   415  		{
   416  			name:        "Basic HTTP Listener with different port and IPv6",
   417  			ipv4Enabled: false,
   418  			ipv6Enabled: true,
   419  			args: args{
   420  				m: &model.Model{
   421  					HTTP: basicHTTPListeners(55555),
   422  				},
   423  			},
   424  			want: basicHostPortHTTPListenersCiliumEnvoyConfig("::", 55555, nil),
   425  		},
   426  		{
   427  			name:        "Basic HTTP Listener with LabelSelector",
   428  			ipv4Enabled: true,
   429  			nodeLabelSelector: &slim_metav1.LabelSelector{
   430  				MatchLabels: map[string]slim_metav1.MatchLabelsValue{
   431  					"a": "b",
   432  				},
   433  			},
   434  			args: args{
   435  				m: &model.Model{
   436  					HTTP: basicHTTPListeners(55555),
   437  				},
   438  			},
   439  			want: basicHostPortHTTPListenersCiliumEnvoyConfig("0.0.0.0", 55555, &slim_metav1.LabelSelector{MatchLabels: map[string]slim_metav1.MatchLabelsValue{"a": "b"}}),
   440  		},
   441  	}
   442  	for _, tt := range tests {
   443  		translatorCases := []struct {
   444  			name                 string
   445  			gatewayAPITranslator *gatewayAPITranslator
   446  		}{
   447  			{
   448  				name: "Without externalTrafficPolicy",
   449  				gatewayAPITranslator: &gatewayAPITranslator{
   450  					cecTranslator:      translation.NewCECTranslator("cilium-secrets", false, false, true, 60, true, tt.nodeLabelSelector, tt.ipv4Enabled, tt.ipv6Enabled, 0),
   451  					hostNetworkEnabled: true,
   452  				},
   453  			},
   454  			{
   455  				name: "With externalTrafficPolicy",
   456  				gatewayAPITranslator: &gatewayAPITranslator{
   457  					cecTranslator:         translation.NewCECTranslator("cilium-secrets", false, false, true, 60, true, tt.nodeLabelSelector, tt.ipv4Enabled, tt.ipv6Enabled, 0),
   458  					hostNetworkEnabled:    true,
   459  					externalTrafficPolicy: "Cluster",
   460  				},
   461  			},
   462  		}
   463  
   464  		t.Run(tt.name, func(t *testing.T) {
   465  			for _, translatorCase := range translatorCases {
   466  				t.Run(translatorCase.name, func(t *testing.T) {
   467  					cec, svc, ep, err := translatorCase.gatewayAPITranslator.Translate(tt.args.m)
   468  					require.Equal(t, tt.wantErr, err != nil, "Error mismatch")
   469  
   470  					diffOutput := cmp.Diff(tt.want, cec, protocmp.Transform())
   471  					if len(diffOutput) != 0 {
   472  						t.Errorf("CiliumEnvoyConfigs did not match:\n%s\n", diffOutput)
   473  					}
   474  
   475  					require.NotNil(t, svc)
   476  					assert.Equal(t, corev1.ServiceTypeClusterIP, svc.Spec.Type)
   477  					require.Emptyf(t, svc.Spec.ExternalTrafficPolicy, "ClusterIP Services must not have an ExternalTrafficPolicy")
   478  
   479  					require.NotNil(t, ep)
   480  				})
   481  			}
   482  		})
   483  	}
   484  }
   485  
   486  func Test_translator_Translate_WithXffNumTrustedHops(t *testing.T) {
   487  	type args struct {
   488  		m *model.Model
   489  	}
   490  	tests := []struct {
   491  		name    string
   492  		args    args
   493  		want    *ciliumv2.CiliumEnvoyConfig
   494  		wantErr bool
   495  	}{
   496  		{
   497  			name: "Basic HTTP Listener with XffNumTrustedHops",
   498  			args: args{
   499  				m: &model.Model{
   500  					HTTP: basicHTTPListeners(80),
   501  				},
   502  			},
   503  			want: basicHTTPListenersCiliumEnvoyConfigWithXff,
   504  		},
   505  	}
   506  	for _, tt := range tests {
   507  		t.Run(tt.name, func(t *testing.T) {
   508  			trans := &gatewayAPITranslator{
   509  				cecTranslator:      translation.NewCECTranslator("cilium-secrets", false, false, true, 60, false, nil, false, false, 2),
   510  				hostNetworkEnabled: true,
   511  			}
   512  			cec, svc, ep, err := trans.Translate(tt.args.m)
   513  			require.Equal(t, tt.wantErr, err != nil, "Error mismatch")
   514  
   515  			diffOutput := cmp.Diff(tt.want, cec, protocmp.Transform())
   516  			if len(diffOutput) != 0 {
   517  				t.Errorf("CiliumEnvoyConfigs did not match:\n%s\n", diffOutput)
   518  			}
   519  
   520  			require.NotNil(t, svc)
   521  			assert.Equal(t, corev1.ServiceTypeClusterIP, svc.Spec.Type)
   522  
   523  			require.NotNil(t, ep)
   524  		})
   525  	}
   526  }
   527  
   528  func Test_getService(t *testing.T) {
   529  	type args struct {
   530  		resource              *model.FullyQualifiedResource
   531  		allPorts              []uint32
   532  		labels                map[string]string
   533  		annotations           map[string]string
   534  		externalTrafficPolicy string
   535  	}
   536  	tests := []struct {
   537  		name string
   538  		args args
   539  		want *corev1.Service
   540  	}{
   541  		{
   542  			name: "long name - more than 64 characters",
   543  			args: args{
   544  				resource: &model.FullyQualifiedResource{
   545  					Name:      "test-long-long-long-long-long-long-long-long-long-long-long-long-name",
   546  					Namespace: "default",
   547  					Version:   "v1",
   548  					Kind:      "Gateway",
   549  					UID:       "57889650-380b-4c05-9a2e-3baee7fd5271",
   550  				},
   551  				allPorts:              []uint32{80},
   552  				externalTrafficPolicy: "Cluster",
   553  			},
   554  			want: &corev1.Service{
   555  				ObjectMeta: metav1.ObjectMeta{
   556  					Name:      "cilium-gateway-test-long-long-long-long-long-long-lo-8tfth549c6",
   557  					Namespace: "default",
   558  					Labels: map[string]string{
   559  						owningGatewayLabel:                       "test-long-long-long-long-long-long-long-long-long-lo-4bftbgh5ht",
   560  						"gateway.networking.k8s.io/gateway-name": "test-long-long-long-long-long-long-long-long-long-lo-4bftbgh5ht",
   561  					},
   562  					OwnerReferences: []metav1.OwnerReference{
   563  						{
   564  							APIVersion: gatewayv1beta1.GroupVersion.String(),
   565  							Kind:       "Gateway",
   566  							Name:       "test-long-long-long-long-long-long-long-long-long-long-long-long-name",
   567  							UID:        types.UID("57889650-380b-4c05-9a2e-3baee7fd5271"),
   568  							Controller: model.AddressOf(true),
   569  						},
   570  					},
   571  				},
   572  				Spec: corev1.ServiceSpec{
   573  					Ports: []corev1.ServicePort{
   574  						{
   575  							Name:     fmt.Sprintf("port-%d", 80),
   576  							Port:     80,
   577  							Protocol: corev1.ProtocolTCP,
   578  						},
   579  					},
   580  					Type:                  corev1.ServiceTypeLoadBalancer,
   581  					ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyCluster,
   582  				},
   583  			},
   584  		},
   585  		{
   586  			name: "externaltrafficpolicy set to local",
   587  			args: args{
   588  				resource: &model.FullyQualifiedResource{
   589  					Name:      "test-externaltrafficpolicy-local",
   590  					Namespace: "default",
   591  					Version:   "v1",
   592  					Kind:      "Gateway",
   593  					UID:       "41b82697-2d8d-4776-81b6-44d0bbac7faa",
   594  				},
   595  				allPorts:              []uint32{80},
   596  				externalTrafficPolicy: "Local",
   597  			},
   598  			want: &corev1.Service{
   599  				ObjectMeta: metav1.ObjectMeta{
   600  					Name:      "cilium-gateway-test-externaltrafficpolicy-local",
   601  					Namespace: "default",
   602  					Labels: map[string]string{
   603  						owningGatewayLabel:                       "test-externaltrafficpolicy-local",
   604  						"gateway.networking.k8s.io/gateway-name": "test-externaltrafficpolicy-local",
   605  					},
   606  					OwnerReferences: []metav1.OwnerReference{
   607  						{
   608  							APIVersion: gatewayv1beta1.GroupVersion.String(),
   609  							Kind:       "Gateway",
   610  							Name:       "test-externaltrafficpolicy-local",
   611  							UID:        types.UID("41b82697-2d8d-4776-81b6-44d0bbac7faa"),
   612  							Controller: model.AddressOf(true),
   613  						},
   614  					},
   615  				},
   616  				Spec: corev1.ServiceSpec{
   617  					Ports: []corev1.ServicePort{
   618  						{
   619  							Name:     fmt.Sprintf("port-%d", 80),
   620  							Port:     80,
   621  							Protocol: corev1.ProtocolTCP,
   622  						},
   623  					},
   624  					Type:                  corev1.ServiceTypeLoadBalancer,
   625  					ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyLocal,
   626  				},
   627  			},
   628  		},
   629  	}
   630  	for _, tt := range tests {
   631  		t.Run(tt.name, func(t *testing.T) {
   632  			got := getService(tt.args.resource, tt.args.allPorts, tt.args.labels, tt.args.annotations, tt.args.externalTrafficPolicy)
   633  			assert.Equalf(t, tt.want, got, "getService(%v, %v, %v, %v)", tt.args.resource, tt.args.allPorts, tt.args.labels, tt.args.annotations)
   634  			assert.Equal(t, true, len(got.Name) <= 63, "Service name is too long")
   635  		})
   636  	}
   637  }