k8s.io/kubernetes@v1.29.3/pkg/proxy/service_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package proxy
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	"k8s.io/apimachinery/pkg/util/dump"
    28  	"k8s.io/apimachinery/pkg/util/intstr"
    29  	"k8s.io/apimachinery/pkg/util/sets"
    30  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    31  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    32  	"k8s.io/kubernetes/pkg/features"
    33  	netutils "k8s.io/utils/net"
    34  )
    35  
    36  const testHostname = "test-hostname"
    37  
    38  func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*BaseServicePortInfo)) *BaseServicePortInfo {
    39  	bsvcPortInfo := &BaseServicePortInfo{
    40  		clusterIP: netutils.ParseIPSloppy(clusterIP),
    41  		port:      port,
    42  		protocol:  v1.Protocol(protocol),
    43  	}
    44  	if healthcheckNodePort != 0 {
    45  		bsvcPortInfo.healthCheckNodePort = healthcheckNodePort
    46  	}
    47  	for _, svcInfoFunc := range svcInfoFuncs {
    48  		svcInfoFunc(bsvcPortInfo)
    49  	}
    50  	return bsvcPortInfo
    51  }
    52  
    53  func makeTestService(namespace, name string, svcFunc func(*v1.Service)) *v1.Service {
    54  	svc := &v1.Service{
    55  		ObjectMeta: metav1.ObjectMeta{
    56  			Name:        name,
    57  			Namespace:   namespace,
    58  			Annotations: map[string]string{},
    59  		},
    60  		Spec:   v1.ServiceSpec{},
    61  		Status: v1.ServiceStatus{},
    62  	}
    63  	svcFunc(svc)
    64  	return svc
    65  }
    66  
    67  func addTestPort(array []v1.ServicePort, name string, protocol v1.Protocol, port, nodeport int32, targetPort int) []v1.ServicePort {
    68  	svcPort := v1.ServicePort{
    69  		Name:       name,
    70  		Protocol:   protocol,
    71  		Port:       port,
    72  		NodePort:   nodeport,
    73  		TargetPort: intstr.FromInt32(int32(targetPort)),
    74  	}
    75  	return append(array, svcPort)
    76  }
    77  
    78  func makeNSN(namespace, name string) types.NamespacedName {
    79  	return types.NamespacedName{Namespace: namespace, Name: name}
    80  }
    81  
    82  func makeServicePortName(ns, name, port string, protocol v1.Protocol) ServicePortName {
    83  	return ServicePortName{
    84  		NamespacedName: makeNSN(ns, name),
    85  		Port:           port,
    86  		Protocol:       protocol,
    87  	}
    88  }
    89  
    90  func TestServiceToServiceMap(t *testing.T) {
    91  	testClusterIPv4 := "10.0.0.1"
    92  	testExternalIPv4 := "8.8.8.8"
    93  	testSourceRangeIPv4 := "0.0.0.0/1"
    94  	testClusterIPv6 := "2001:db8:85a3:0:0:8a2e:370:7334"
    95  	testExternalIPv6 := "2001:db8:85a3:0:0:8a2e:370:7335"
    96  	testSourceRangeIPv6 := "2001:db8::/32"
    97  	ipModeVIP := v1.LoadBalancerIPModeVIP
    98  	ipModeProxy := v1.LoadBalancerIPModeProxy
    99  
   100  	testCases := []struct {
   101  		desc          string
   102  		service       *v1.Service
   103  		expected      map[ServicePortName]*BaseServicePortInfo
   104  		ipFamily      v1.IPFamily
   105  		ipModeEnabled bool
   106  	}{
   107  		{
   108  			desc:     "nothing",
   109  			ipFamily: v1.IPv4Protocol,
   110  
   111  			service:  nil,
   112  			expected: map[ServicePortName]*BaseServicePortInfo{},
   113  		},
   114  		{
   115  			desc:     "headless service",
   116  			ipFamily: v1.IPv4Protocol,
   117  
   118  			service: makeTestService("ns2", "headless", func(svc *v1.Service) {
   119  				svc.Spec.Type = v1.ServiceTypeClusterIP
   120  				svc.Spec.ClusterIP = v1.ClusterIPNone
   121  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
   122  			}),
   123  			expected: map[ServicePortName]*BaseServicePortInfo{},
   124  		},
   125  		{
   126  			desc:     "headless sctp service",
   127  			ipFamily: v1.IPv4Protocol,
   128  
   129  			service: makeTestService("ns2", "headless", func(svc *v1.Service) {
   130  				svc.Spec.Type = v1.ServiceTypeClusterIP
   131  				svc.Spec.ClusterIP = v1.ClusterIPNone
   132  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "sip", "SCTP", 7777, 0, 0)
   133  			}),
   134  			expected: map[ServicePortName]*BaseServicePortInfo{},
   135  		},
   136  		{
   137  			desc:     "headless service without port",
   138  			ipFamily: v1.IPv4Protocol,
   139  
   140  			service: makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
   141  				svc.Spec.Type = v1.ServiceTypeClusterIP
   142  				svc.Spec.ClusterIP = v1.ClusterIPNone
   143  			}),
   144  			expected: map[ServicePortName]*BaseServicePortInfo{},
   145  		},
   146  		{
   147  			desc:     "cluster ip service",
   148  			ipFamily: v1.IPv4Protocol,
   149  
   150  			service: makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
   151  				svc.Spec.Type = v1.ServiceTypeClusterIP
   152  				svc.Spec.ClusterIP = "172.16.55.4"
   153  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
   154  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
   155  			}),
   156  			expected: map[ServicePortName]*BaseServicePortInfo{
   157  				makeServicePortName("ns2", "cluster-ip", "p1", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.4", 1234, "UDP", 0),
   158  				makeServicePortName("ns2", "cluster-ip", "p2", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.4", 1235, "UDP", 0),
   159  			},
   160  		},
   161  		{
   162  			desc:     "nodeport service",
   163  			ipFamily: v1.IPv4Protocol,
   164  
   165  			service: makeTestService("ns2", "node-port", func(svc *v1.Service) {
   166  				svc.Spec.Type = v1.ServiceTypeNodePort
   167  				svc.Spec.ClusterIP = "172.16.55.10"
   168  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
   169  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
   170  			}),
   171  			expected: map[ServicePortName]*BaseServicePortInfo{
   172  				makeServicePortName("ns2", "node-port", "port1", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.10", 345, "UDP", 0),
   173  				makeServicePortName("ns2", "node-port", "port2", v1.ProtocolTCP): makeTestServiceInfo("172.16.55.10", 344, "TCP", 0),
   174  			},
   175  		},
   176  		{
   177  			desc:     "load balancer service",
   178  			ipFamily: v1.IPv4Protocol,
   179  
   180  			service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   181  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   182  				svc.Spec.ClusterIP = "172.16.55.11"
   183  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   184  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
   185  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
   186  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4"}}
   187  			}),
   188  			expected: map[ServicePortName]*BaseServicePortInfo{
   189  				makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   190  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   191  				}),
   192  				makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   193  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   194  				}),
   195  			},
   196  		},
   197  		{
   198  			desc:     "load balancer service ipMode VIP feature gate disable",
   199  			ipFamily: v1.IPv4Protocol,
   200  
   201  			service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   202  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   203  				svc.Spec.ClusterIP = "172.16.55.11"
   204  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   205  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
   206  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
   207  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeVIP}}
   208  			}),
   209  			expected: map[ServicePortName]*BaseServicePortInfo{
   210  				makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   211  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   212  				}),
   213  				makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   214  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   215  				}),
   216  			},
   217  		},
   218  		{
   219  			desc:     "load balancer service ipMode Proxy feature gate disable",
   220  			ipFamily: v1.IPv4Protocol,
   221  
   222  			service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   223  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   224  				svc.Spec.ClusterIP = "172.16.55.11"
   225  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   226  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
   227  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
   228  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeProxy}}
   229  			}),
   230  			expected: map[ServicePortName]*BaseServicePortInfo{
   231  				makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   232  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   233  				}),
   234  				makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   235  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   236  				}),
   237  			},
   238  		},
   239  		{
   240  			desc:          "load balancer service ipMode VIP feature gate enabled",
   241  			ipFamily:      v1.IPv4Protocol,
   242  			ipModeEnabled: true,
   243  
   244  			service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   245  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   246  				svc.Spec.ClusterIP = "172.16.55.11"
   247  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   248  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
   249  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
   250  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeVIP}}
   251  			}),
   252  			expected: map[ServicePortName]*BaseServicePortInfo{
   253  				makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   254  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   255  				}),
   256  				makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   257  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.4"}
   258  				}),
   259  			},
   260  		},
   261  		{
   262  			desc:          "load balancer service ipMode Proxy feature gate enabled",
   263  			ipFamily:      v1.IPv4Protocol,
   264  			ipModeEnabled: true,
   265  
   266  			service: makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   267  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   268  				svc.Spec.ClusterIP = "172.16.55.11"
   269  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   270  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port3", "UDP", 8675, 30061, 7000)
   271  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port4", "UDP", 8676, 30062, 7001)
   272  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.4", IPMode: &ipModeProxy}}
   273  			}),
   274  			expected: map[ServicePortName]*BaseServicePortInfo{
   275  				makeServicePortName("ns1", "load-balancer", "port3", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   276  				}),
   277  				makeServicePortName("ns1", "load-balancer", "port4", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   278  				}),
   279  			},
   280  		},
   281  		{
   282  			desc:     "load balancer service with only local traffic policy",
   283  			ipFamily: v1.IPv4Protocol,
   284  
   285  			service: makeTestService("ns1", "only-local-load-balancer", func(svc *v1.Service) {
   286  				svc.Spec.Type = v1.ServiceTypeLoadBalancer
   287  				svc.Spec.ClusterIP = "172.16.55.12"
   288  				svc.Spec.LoadBalancerIP = "5.6.7.8"
   289  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portx", "UDP", 8677, 30063, 7002)
   290  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "porty", "UDP", 8678, 30064, 7003)
   291  				svc.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.1.2.3"}}
   292  				svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   293  				svc.Spec.HealthCheckNodePort = 345
   294  			}),
   295  			expected: map[ServicePortName]*BaseServicePortInfo{
   296  				makeServicePortName("ns1", "only-local-load-balancer", "portx", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.12", 8677, "UDP", 345, func(bsvcPortInfo *BaseServicePortInfo) {
   297  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.3"}
   298  				}),
   299  				makeServicePortName("ns1", "only-local-load-balancer", "porty", v1.ProtocolUDP): makeTestServiceInfo("172.16.55.12", 8678, "UDP", 345, func(bsvcPortInfo *BaseServicePortInfo) {
   300  					bsvcPortInfo.loadBalancerVIPs = []string{"10.1.2.3"}
   301  				}),
   302  			},
   303  		},
   304  		{
   305  			desc:     "external name service",
   306  			ipFamily: v1.IPv4Protocol,
   307  
   308  			service: makeTestService("ns2", "external-name", func(svc *v1.Service) {
   309  				svc.Spec.Type = v1.ServiceTypeExternalName
   310  				svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
   311  				svc.Spec.ExternalName = "foo2.bar.com"
   312  				svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portz", "UDP", 1235, 5321, 0)
   313  			}),
   314  			expected: map[ServicePortName]*BaseServicePortInfo{},
   315  		},
   316  		{
   317  			desc:     "service with ipv6 clusterIP under ipv4 mode, service should be filtered",
   318  			ipFamily: v1.IPv4Protocol,
   319  
   320  			service: &v1.Service{
   321  				ObjectMeta: metav1.ObjectMeta{
   322  					Name:      "invalidIPv6InIPV4Mode",
   323  					Namespace: "test",
   324  				},
   325  				Spec: v1.ServiceSpec{
   326  					ClusterIP: testClusterIPv6,
   327  					Ports: []v1.ServicePort{
   328  						{
   329  							Name:     "testPort",
   330  							Port:     int32(12345),
   331  							Protocol: v1.ProtocolTCP,
   332  						},
   333  					},
   334  				},
   335  				Status: v1.ServiceStatus{
   336  					LoadBalancer: v1.LoadBalancerStatus{
   337  						Ingress: []v1.LoadBalancerIngress{
   338  							{IP: testExternalIPv4},
   339  							{IP: testExternalIPv6},
   340  						},
   341  					},
   342  				},
   343  			},
   344  		},
   345  		{
   346  			desc:     "service with ipv4 clusterIP under ipv6 mode, service should be filtered",
   347  			ipFamily: v1.IPv6Protocol,
   348  
   349  			service: &v1.Service{
   350  				ObjectMeta: metav1.ObjectMeta{
   351  					Name:      "invalidIPv4InIPV6Mode",
   352  					Namespace: "test",
   353  				},
   354  				Spec: v1.ServiceSpec{
   355  					ClusterIP: testClusterIPv4,
   356  					Ports: []v1.ServicePort{
   357  						{
   358  							Name:     "testPort",
   359  							Port:     int32(12345),
   360  							Protocol: v1.ProtocolTCP,
   361  						},
   362  					},
   363  				},
   364  				Status: v1.ServiceStatus{
   365  					LoadBalancer: v1.LoadBalancerStatus{
   366  						Ingress: []v1.LoadBalancerIngress{
   367  							{IP: testExternalIPv4},
   368  							{IP: testExternalIPv6},
   369  						},
   370  					},
   371  				},
   372  			},
   373  		},
   374  		{
   375  			desc:     "service with ipv4 configurations under ipv4 mode",
   376  			ipFamily: v1.IPv4Protocol,
   377  
   378  			service: &v1.Service{
   379  				ObjectMeta: metav1.ObjectMeta{
   380  					Name:      "validIPv4",
   381  					Namespace: "test",
   382  				},
   383  				Spec: v1.ServiceSpec{
   384  					ClusterIP:                testClusterIPv4,
   385  					ExternalIPs:              []string{testExternalIPv4},
   386  					LoadBalancerSourceRanges: []string{testSourceRangeIPv4},
   387  					Ports: []v1.ServicePort{
   388  						{
   389  							Name:     "testPort",
   390  							Port:     int32(12345),
   391  							Protocol: v1.ProtocolTCP,
   392  						},
   393  					},
   394  				},
   395  				Status: v1.ServiceStatus{
   396  					LoadBalancer: v1.LoadBalancerStatus{
   397  						Ingress: []v1.LoadBalancerIngress{
   398  							{IP: testExternalIPv4},
   399  							{IP: testExternalIPv6},
   400  						},
   401  					},
   402  				},
   403  			},
   404  			expected: map[ServicePortName]*BaseServicePortInfo{
   405  				makeServicePortName("test", "validIPv4", "testPort", v1.ProtocolTCP): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   406  					bsvcPortInfo.externalIPs = []string{testExternalIPv4}
   407  					bsvcPortInfo.loadBalancerSourceRanges = []string{testSourceRangeIPv4}
   408  					bsvcPortInfo.loadBalancerVIPs = []string{testExternalIPv4}
   409  				}),
   410  			},
   411  		},
   412  		{
   413  			desc:     "service with ipv6 configurations under ipv6 mode",
   414  			ipFamily: v1.IPv6Protocol,
   415  
   416  			service: &v1.Service{
   417  				ObjectMeta: metav1.ObjectMeta{
   418  					Name:      "validIPv6",
   419  					Namespace: "test",
   420  				},
   421  				Spec: v1.ServiceSpec{
   422  					ClusterIP:                testClusterIPv6,
   423  					ExternalIPs:              []string{testExternalIPv6},
   424  					LoadBalancerSourceRanges: []string{testSourceRangeIPv6},
   425  					Ports: []v1.ServicePort{
   426  						{
   427  							Name:     "testPort",
   428  							Port:     int32(12345),
   429  							Protocol: v1.ProtocolTCP,
   430  						},
   431  					},
   432  				},
   433  				Status: v1.ServiceStatus{
   434  					LoadBalancer: v1.LoadBalancerStatus{
   435  						Ingress: []v1.LoadBalancerIngress{
   436  							{IP: testExternalIPv4},
   437  							{IP: testExternalIPv6},
   438  						},
   439  					},
   440  				},
   441  			},
   442  			expected: map[ServicePortName]*BaseServicePortInfo{
   443  				makeServicePortName("test", "validIPv6", "testPort", v1.ProtocolTCP): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   444  					bsvcPortInfo.externalIPs = []string{testExternalIPv6}
   445  					bsvcPortInfo.loadBalancerSourceRanges = []string{testSourceRangeIPv6}
   446  					bsvcPortInfo.loadBalancerVIPs = []string{testExternalIPv6}
   447  				}),
   448  			},
   449  		},
   450  		{
   451  			desc:     "service with both ipv4 and ipv6 configurations under ipv4 mode, ipv6 fields should be filtered",
   452  			ipFamily: v1.IPv4Protocol,
   453  
   454  			service: &v1.Service{
   455  				ObjectMeta: metav1.ObjectMeta{
   456  					Name:      "filterIPv6InIPV4Mode",
   457  					Namespace: "test",
   458  				},
   459  				Spec: v1.ServiceSpec{
   460  					ClusterIP:                testClusterIPv4,
   461  					ExternalIPs:              []string{testExternalIPv4, testExternalIPv6},
   462  					LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
   463  					Ports: []v1.ServicePort{
   464  						{
   465  							Name:     "testPort",
   466  							Port:     int32(12345),
   467  							Protocol: v1.ProtocolTCP,
   468  						},
   469  					},
   470  				},
   471  				Status: v1.ServiceStatus{
   472  					LoadBalancer: v1.LoadBalancerStatus{
   473  						Ingress: []v1.LoadBalancerIngress{
   474  							{IP: testExternalIPv4},
   475  							{IP: testExternalIPv6},
   476  						},
   477  					},
   478  				},
   479  			},
   480  			expected: map[ServicePortName]*BaseServicePortInfo{
   481  				makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort", v1.ProtocolTCP): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   482  					bsvcPortInfo.externalIPs = []string{testExternalIPv4}
   483  					bsvcPortInfo.loadBalancerSourceRanges = []string{testSourceRangeIPv4}
   484  					bsvcPortInfo.loadBalancerVIPs = []string{testExternalIPv4}
   485  				}),
   486  			},
   487  		},
   488  		{
   489  			desc:     "service with both ipv4 and ipv6 configurations under ipv6 mode, ipv4 fields should be filtered",
   490  			ipFamily: v1.IPv6Protocol,
   491  
   492  			service: &v1.Service{
   493  				ObjectMeta: metav1.ObjectMeta{
   494  					Name:      "filterIPv4InIPV6Mode",
   495  					Namespace: "test",
   496  				},
   497  				Spec: v1.ServiceSpec{
   498  					ClusterIP:                testClusterIPv6,
   499  					ExternalIPs:              []string{testExternalIPv4, testExternalIPv6},
   500  					LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6},
   501  					Ports: []v1.ServicePort{
   502  						{
   503  							Name:     "testPort",
   504  							Port:     int32(12345),
   505  							Protocol: v1.ProtocolTCP,
   506  						},
   507  					},
   508  				},
   509  				Status: v1.ServiceStatus{
   510  					LoadBalancer: v1.LoadBalancerStatus{
   511  						Ingress: []v1.LoadBalancerIngress{
   512  							{IP: testExternalIPv4},
   513  							{IP: testExternalIPv6},
   514  						},
   515  					},
   516  				},
   517  			},
   518  			expected: map[ServicePortName]*BaseServicePortInfo{
   519  				makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort", v1.ProtocolTCP): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   520  					bsvcPortInfo.externalIPs = []string{testExternalIPv6}
   521  					bsvcPortInfo.loadBalancerSourceRanges = []string{testSourceRangeIPv6}
   522  					bsvcPortInfo.loadBalancerVIPs = []string{testExternalIPv6}
   523  				}),
   524  			},
   525  		},
   526  		{
   527  			desc:     "service with extra space in LoadBalancerSourceRanges",
   528  			ipFamily: v1.IPv4Protocol,
   529  
   530  			service: &v1.Service{
   531  				ObjectMeta: metav1.ObjectMeta{
   532  					Name:      "extra-space",
   533  					Namespace: "test",
   534  				},
   535  				Spec: v1.ServiceSpec{
   536  					ClusterIP:                testClusterIPv4,
   537  					LoadBalancerSourceRanges: []string{" 10.1.2.0/28"},
   538  					Ports: []v1.ServicePort{
   539  						{
   540  							Name:     "testPort",
   541  							Port:     int32(12345),
   542  							Protocol: v1.ProtocolTCP,
   543  						},
   544  					},
   545  				},
   546  			},
   547  			expected: map[ServicePortName]*BaseServicePortInfo{
   548  				makeServicePortName("test", "extra-space", "testPort", v1.ProtocolTCP): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(bsvcPortInfo *BaseServicePortInfo) {
   549  					bsvcPortInfo.loadBalancerSourceRanges = []string{"10.1.2.0/28"}
   550  				}),
   551  			},
   552  		},
   553  	}
   554  
   555  	for _, tc := range testCases {
   556  		t.Run(tc.desc, func(t *testing.T) {
   557  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.LoadBalancerIPMode, tc.ipModeEnabled)()
   558  			svcTracker := NewServiceChangeTracker(nil, tc.ipFamily, nil, nil)
   559  			// outputs
   560  			newServices := svcTracker.serviceToServiceMap(tc.service)
   561  
   562  			if len(newServices) != len(tc.expected) {
   563  				t.Fatalf("expected %d new, got %d: %v", len(tc.expected), len(newServices), dump.Pretty(newServices))
   564  			}
   565  			for svcKey, expectedInfo := range tc.expected {
   566  				svcInfo, exists := newServices[svcKey].(*BaseServicePortInfo)
   567  				if !exists {
   568  					t.Fatalf("[%s] expected to find key %s", tc.desc, svcKey)
   569  				}
   570  
   571  				if !svcInfo.clusterIP.Equal(expectedInfo.clusterIP) ||
   572  					svcInfo.port != expectedInfo.port ||
   573  					svcInfo.protocol != expectedInfo.protocol ||
   574  					svcInfo.healthCheckNodePort != expectedInfo.healthCheckNodePort ||
   575  					!sets.New[string](svcInfo.externalIPs...).Equal(sets.New[string](expectedInfo.externalIPs...)) ||
   576  					!sets.New[string](svcInfo.loadBalancerSourceRanges...).Equal(sets.New[string](expectedInfo.loadBalancerSourceRanges...)) ||
   577  					!reflect.DeepEqual(svcInfo.loadBalancerVIPs, expectedInfo.loadBalancerVIPs) {
   578  					t.Errorf("[%s] expected new[%v]to be %v, got %v", tc.desc, svcKey, expectedInfo, *svcInfo)
   579  				}
   580  				for svcKey, expectedInfo := range tc.expected {
   581  					svcInfo, _ := newServices[svcKey].(*BaseServicePortInfo)
   582  					if !svcInfo.clusterIP.Equal(expectedInfo.clusterIP) ||
   583  						svcInfo.port != expectedInfo.port ||
   584  						svcInfo.protocol != expectedInfo.protocol ||
   585  						svcInfo.healthCheckNodePort != expectedInfo.healthCheckNodePort ||
   586  						!sets.New[string](svcInfo.externalIPs...).Equal(sets.New[string](expectedInfo.externalIPs...)) ||
   587  						!sets.New[string](svcInfo.loadBalancerSourceRanges...).Equal(sets.New[string](expectedInfo.loadBalancerSourceRanges...)) ||
   588  						!reflect.DeepEqual(svcInfo.loadBalancerVIPs, expectedInfo.loadBalancerVIPs) {
   589  						t.Errorf("expected new[%v]to be %v, got %v", svcKey, expectedInfo, *svcInfo)
   590  					}
   591  				}
   592  			}
   593  		})
   594  	}
   595  }
   596  
   597  type FakeProxier struct {
   598  	endpointsChanges *EndpointsChangeTracker
   599  	serviceChanges   *ServiceChangeTracker
   600  	svcPortMap       ServicePortMap
   601  	endpointsMap     EndpointsMap
   602  	hostname         string
   603  }
   604  
   605  func newFakeProxier(ipFamily v1.IPFamily, t time.Time) *FakeProxier {
   606  	return &FakeProxier{
   607  		svcPortMap:     make(ServicePortMap),
   608  		serviceChanges: NewServiceChangeTracker(nil, ipFamily, nil, nil),
   609  		endpointsMap:   make(EndpointsMap),
   610  		endpointsChanges: &EndpointsChangeTracker{
   611  			lastChangeTriggerTimes:    make(map[types.NamespacedName][]time.Time),
   612  			trackerStartTime:          t,
   613  			processEndpointsMapChange: nil,
   614  			endpointSliceCache:        NewEndpointSliceCache(testHostname, ipFamily, nil, nil),
   615  		},
   616  	}
   617  }
   618  
   619  func makeServiceMap(fake *FakeProxier, allServices ...*v1.Service) {
   620  	for i := range allServices {
   621  		fake.addService(allServices[i])
   622  	}
   623  }
   624  
   625  func (proxier *FakeProxier) addService(service *v1.Service) {
   626  	proxier.serviceChanges.Update(nil, service)
   627  }
   628  
   629  func (proxier *FakeProxier) updateService(oldService *v1.Service, service *v1.Service) {
   630  	proxier.serviceChanges.Update(oldService, service)
   631  }
   632  
   633  func (proxier *FakeProxier) deleteService(service *v1.Service) {
   634  	proxier.serviceChanges.Update(service, nil)
   635  }
   636  
   637  func TestServiceMapUpdateHeadless(t *testing.T) {
   638  	fp := newFakeProxier(v1.IPv4Protocol, time.Time{})
   639  
   640  	makeServiceMap(fp,
   641  		makeTestService("ns2", "headless", func(svc *v1.Service) {
   642  			svc.Spec.Type = v1.ServiceTypeClusterIP
   643  			svc.Spec.ClusterIP = v1.ClusterIPNone
   644  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0)
   645  		}),
   646  		makeTestService("ns2", "headless-without-port", func(svc *v1.Service) {
   647  			svc.Spec.Type = v1.ServiceTypeClusterIP
   648  			svc.Spec.ClusterIP = v1.ClusterIPNone
   649  		}),
   650  	)
   651  
   652  	// Headless service should be ignored
   653  	result := fp.svcPortMap.Update(fp.serviceChanges)
   654  	if len(fp.svcPortMap) != 0 {
   655  		t.Errorf("expected service map length 0, got %d", len(fp.svcPortMap))
   656  	}
   657  
   658  	if len(result.UpdatedServices) != 0 {
   659  		t.Errorf("expected 0 updated services, got %d", len(result.UpdatedServices))
   660  	}
   661  	if len(result.DeletedUDPClusterIPs) != 0 {
   662  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
   663  	}
   664  
   665  	// No proxied services, so no healthchecks
   666  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
   667  	if len(healthCheckNodePorts) != 0 {
   668  		t.Errorf("expected healthcheck ports length 0, got %d", len(healthCheckNodePorts))
   669  	}
   670  }
   671  
   672  func TestUpdateServiceTypeExternalName(t *testing.T) {
   673  	fp := newFakeProxier(v1.IPv4Protocol, time.Time{})
   674  
   675  	makeServiceMap(fp,
   676  		makeTestService("ns2", "external-name", func(svc *v1.Service) {
   677  			svc.Spec.Type = v1.ServiceTypeExternalName
   678  			svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored
   679  			svc.Spec.ExternalName = "foo2.bar.com"
   680  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "blah", "UDP", 1235, 5321, 0)
   681  		}),
   682  	)
   683  
   684  	result := fp.svcPortMap.Update(fp.serviceChanges)
   685  	if len(fp.svcPortMap) != 0 {
   686  		t.Errorf("expected service map length 0, got %v", fp.svcPortMap)
   687  	}
   688  	if len(result.UpdatedServices) != 0 {
   689  		t.Errorf("expected 0 updated services, got %v", result.UpdatedServices)
   690  	}
   691  	if len(result.DeletedUDPClusterIPs) != 0 {
   692  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs)
   693  	}
   694  
   695  	// No proxied services, so no healthchecks
   696  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
   697  	if len(healthCheckNodePorts) != 0 {
   698  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
   699  	}
   700  }
   701  
   702  func TestBuildServiceMapAddRemove(t *testing.T) {
   703  	fp := newFakeProxier(v1.IPv4Protocol, time.Time{})
   704  
   705  	services := []*v1.Service{
   706  		makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
   707  			svc.Spec.Type = v1.ServiceTypeClusterIP
   708  			svc.Spec.ClusterIP = "172.16.55.4"
   709  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 1234, 4321, 0)
   710  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "UDP", 1235, 5321, 0)
   711  		}),
   712  		makeTestService("ns2", "node-port", func(svc *v1.Service) {
   713  			svc.Spec.Type = v1.ServiceTypeNodePort
   714  			svc.Spec.ClusterIP = "172.16.55.10"
   715  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0)
   716  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0)
   717  		}),
   718  		makeTestService("ns1", "load-balancer", func(svc *v1.Service) {
   719  			svc.Spec.Type = v1.ServiceTypeLoadBalancer
   720  			svc.Spec.ClusterIP = "172.16.55.11"
   721  			svc.Spec.LoadBalancerIP = "5.6.7.8"
   722  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar", "UDP", 8675, 30061, 7000)
   723  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8676, 30062, 7001)
   724  			svc.Status.LoadBalancer = v1.LoadBalancerStatus{
   725  				Ingress: []v1.LoadBalancerIngress{
   726  					{IP: "10.1.2.4"},
   727  				},
   728  			}
   729  		}),
   730  		makeTestService("ns1", "only-local-load-balancer", func(svc *v1.Service) {
   731  			svc.Spec.Type = v1.ServiceTypeLoadBalancer
   732  			svc.Spec.ClusterIP = "172.16.55.12"
   733  			svc.Spec.LoadBalancerIP = "5.6.7.8"
   734  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "foobar2", "UDP", 8677, 30063, 7002)
   735  			svc.Spec.Ports = addTestPort(svc.Spec.Ports, "baz", "UDP", 8678, 30064, 7003)
   736  			svc.Status.LoadBalancer = v1.LoadBalancerStatus{
   737  				Ingress: []v1.LoadBalancerIngress{
   738  					{IP: "10.1.2.3"},
   739  				},
   740  			}
   741  			svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   742  			svc.Spec.HealthCheckNodePort = 345
   743  		}),
   744  	}
   745  
   746  	for i := range services {
   747  		fp.addService(services[i])
   748  	}
   749  
   750  	result := fp.svcPortMap.Update(fp.serviceChanges)
   751  	if len(fp.svcPortMap) != 8 {
   752  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
   753  	}
   754  	for i := range services {
   755  		name := makeNSN(services[i].Namespace, services[i].Name)
   756  		if !result.UpdatedServices.Has(name) {
   757  			t.Errorf("expected updated service for %q", name)
   758  		}
   759  	}
   760  	if len(result.UpdatedServices) != len(services) {
   761  		t.Errorf("expected %d updated services, got %d", len(services), len(result.UpdatedServices))
   762  	}
   763  	if len(result.DeletedUDPClusterIPs) != 0 {
   764  		// Services only added, so nothing stale yet
   765  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
   766  	}
   767  
   768  	// The only-local-loadbalancer ones get added
   769  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
   770  	if len(healthCheckNodePorts) != 1 {
   771  		t.Errorf("expected 1 healthcheck port, got %v", healthCheckNodePorts)
   772  	} else {
   773  		nsn := makeNSN("ns1", "only-local-load-balancer")
   774  		if port, found := healthCheckNodePorts[nsn]; !found || port != 345 {
   775  			t.Errorf("expected healthcheck port [%q]=345: got %v", nsn, healthCheckNodePorts)
   776  		}
   777  	}
   778  
   779  	// Remove some stuff
   780  	// oneService is a modification of services[0] with removed first port.
   781  	oneService := makeTestService("ns2", "cluster-ip", func(svc *v1.Service) {
   782  		svc.Spec.Type = v1.ServiceTypeClusterIP
   783  		svc.Spec.ClusterIP = "172.16.55.4"
   784  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0)
   785  	})
   786  
   787  	fp.updateService(services[0], oneService)
   788  	fp.deleteService(services[1])
   789  	fp.deleteService(services[2])
   790  	fp.deleteService(services[3])
   791  
   792  	result = fp.svcPortMap.Update(fp.serviceChanges)
   793  	if len(fp.svcPortMap) != 1 {
   794  		t.Errorf("expected service map length 1, got %v", fp.svcPortMap)
   795  	}
   796  	if len(result.UpdatedServices) != 4 {
   797  		t.Errorf("expected 4 updated services, got %d", len(result.UpdatedServices))
   798  	}
   799  
   800  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
   801  	if len(healthCheckNodePorts) != 0 {
   802  		t.Errorf("expected 0 healthcheck ports, got %v", healthCheckNodePorts)
   803  	}
   804  
   805  	// All services but one were deleted. While you'd expect only the ClusterIPs
   806  	// from the three deleted services here, we still have the ClusterIP for
   807  	// the not-deleted service, because one of it's ServicePorts was deleted.
   808  	expectedDeletedUDPClusterIPs := []string{"172.16.55.10", "172.16.55.4", "172.16.55.11", "172.16.55.12"}
   809  	if len(result.DeletedUDPClusterIPs) != len(expectedDeletedUDPClusterIPs) {
   810  		t.Errorf("expected stale UDP services length %d, got %v", len(expectedDeletedUDPClusterIPs), result.DeletedUDPClusterIPs.UnsortedList())
   811  	}
   812  	for _, ip := range expectedDeletedUDPClusterIPs {
   813  		if !result.DeletedUDPClusterIPs.Has(ip) {
   814  			t.Errorf("expected stale UDP service service %s", ip)
   815  		}
   816  	}
   817  }
   818  
   819  func TestBuildServiceMapServiceUpdate(t *testing.T) {
   820  	fp := newFakeProxier(v1.IPv4Protocol, time.Time{})
   821  
   822  	servicev1 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
   823  		svc.Spec.Type = v1.ServiceTypeClusterIP
   824  		svc.Spec.ClusterIP = "172.16.55.4"
   825  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0)
   826  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 0)
   827  	})
   828  	servicev2 := makeTestService("ns1", "svc1", func(svc *v1.Service) {
   829  		svc.Spec.Type = v1.ServiceTypeLoadBalancer
   830  		svc.Spec.ClusterIP = "172.16.55.4"
   831  		svc.Spec.LoadBalancerIP = "5.6.7.8"
   832  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 7002)
   833  		svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "TCP", 1235, 5321, 7003)
   834  		svc.Status.LoadBalancer = v1.LoadBalancerStatus{
   835  			Ingress: []v1.LoadBalancerIngress{
   836  				{IP: "10.1.2.3"},
   837  			},
   838  		}
   839  		svc.Spec.ExternalTrafficPolicy = v1.ServiceExternalTrafficPolicyLocal
   840  		svc.Spec.HealthCheckNodePort = 345
   841  	})
   842  
   843  	fp.addService(servicev1)
   844  
   845  	result := fp.svcPortMap.Update(fp.serviceChanges)
   846  	if len(fp.svcPortMap) != 2 {
   847  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
   848  	}
   849  	if len(result.UpdatedServices) != 1 {
   850  		t.Errorf("expected 1 updated service, got %d", len(result.UpdatedServices))
   851  	}
   852  	if len(result.DeletedUDPClusterIPs) != 0 {
   853  		// Services only added, so nothing stale yet
   854  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
   855  	}
   856  
   857  	healthCheckNodePorts := fp.svcPortMap.HealthCheckNodePorts()
   858  	if len(healthCheckNodePorts) != 0 {
   859  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
   860  	}
   861  
   862  	// Change service to load-balancer
   863  	fp.updateService(servicev1, servicev2)
   864  	result = fp.svcPortMap.Update(fp.serviceChanges)
   865  	if len(fp.svcPortMap) != 2 {
   866  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
   867  	}
   868  	if len(result.UpdatedServices) != 1 {
   869  		t.Errorf("expected 1 updated service, got %d", len(result.UpdatedServices))
   870  	}
   871  	if len(result.DeletedUDPClusterIPs) != 0 {
   872  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs.UnsortedList())
   873  	}
   874  
   875  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
   876  	if len(healthCheckNodePorts) != 1 {
   877  		t.Errorf("expected healthcheck ports length 1, got %v", healthCheckNodePorts)
   878  	}
   879  
   880  	// No change; make sure the service map stays the same and there are
   881  	// no health-check changes
   882  	fp.updateService(servicev2, servicev2)
   883  	result = fp.svcPortMap.Update(fp.serviceChanges)
   884  	if len(fp.svcPortMap) != 2 {
   885  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
   886  	}
   887  	if len(result.UpdatedServices) != 0 {
   888  		t.Errorf("expected 0 updated services, got %d", len(result.UpdatedServices))
   889  	}
   890  	if len(result.DeletedUDPClusterIPs) != 0 {
   891  		t.Errorf("expected stale UDP services length 0, got %v", result.DeletedUDPClusterIPs.UnsortedList())
   892  	}
   893  
   894  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
   895  	if len(healthCheckNodePorts) != 1 {
   896  		t.Errorf("expected healthcheck ports length 1, got %v", healthCheckNodePorts)
   897  	}
   898  
   899  	// And back to ClusterIP
   900  	fp.updateService(servicev2, servicev1)
   901  	result = fp.svcPortMap.Update(fp.serviceChanges)
   902  	if len(fp.svcPortMap) != 2 {
   903  		t.Errorf("expected service map length 2, got %v", fp.svcPortMap)
   904  	}
   905  	if len(result.UpdatedServices) != 1 {
   906  		t.Errorf("expected 1 updated service, got %d", len(result.UpdatedServices))
   907  	}
   908  	if len(result.DeletedUDPClusterIPs) != 0 {
   909  		// Services only added, so nothing stale yet
   910  		t.Errorf("expected stale UDP services length 0, got %d", len(result.DeletedUDPClusterIPs))
   911  	}
   912  
   913  	healthCheckNodePorts = fp.svcPortMap.HealthCheckNodePorts()
   914  	if len(healthCheckNodePorts) != 0 {
   915  		t.Errorf("expected healthcheck ports length 0, got %v", healthCheckNodePorts)
   916  	}
   917  }