k8s.io/kubernetes@v1.29.3/pkg/proxy/util/utils_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 util
    18  
    19  import (
    20  	"net"
    21  	"reflect"
    22  	"testing"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/sets"
    27  	netutils "k8s.io/utils/net"
    28  )
    29  
    30  func TestValidateWorks(t *testing.T) {
    31  	if isValidEndpoint("", 0) {
    32  		t.Errorf("Didn't fail for empty set")
    33  	}
    34  	if isValidEndpoint("foobar", 0) {
    35  		t.Errorf("Didn't fail with invalid port")
    36  	}
    37  	if isValidEndpoint("foobar", -1) {
    38  		t.Errorf("Didn't fail with a negative port")
    39  	}
    40  	if !isValidEndpoint("foobar", 8080) {
    41  		t.Errorf("Failed a valid config.")
    42  	}
    43  }
    44  
    45  func TestBuildPortsToEndpointsMap(t *testing.T) {
    46  	endpoints := &v1.Endpoints{
    47  		ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "testnamespace"},
    48  		Subsets: []v1.EndpointSubset{
    49  			{
    50  				Addresses: []v1.EndpointAddress{
    51  					{IP: "10.0.0.1"},
    52  					{IP: "10.0.0.2"},
    53  				},
    54  				Ports: []v1.EndpointPort{
    55  					{Name: "http", Port: 80},
    56  					{Name: "https", Port: 443},
    57  				},
    58  			},
    59  			{
    60  				Addresses: []v1.EndpointAddress{
    61  					{IP: "10.0.0.1"},
    62  					{IP: "10.0.0.3"},
    63  				},
    64  				Ports: []v1.EndpointPort{
    65  					{Name: "http", Port: 8080},
    66  					{Name: "dns", Port: 53},
    67  				},
    68  			},
    69  			{
    70  				Addresses: []v1.EndpointAddress{},
    71  				Ports: []v1.EndpointPort{
    72  					{Name: "http", Port: 8888},
    73  					{Name: "ssh", Port: 22},
    74  				},
    75  			},
    76  			{
    77  				Addresses: []v1.EndpointAddress{
    78  					{IP: "10.0.0.1"},
    79  				},
    80  				Ports: []v1.EndpointPort{},
    81  			},
    82  		},
    83  	}
    84  	expectedPortsToEndpoints := map[string][]string{
    85  		"http":  {"10.0.0.1:80", "10.0.0.2:80", "10.0.0.1:8080", "10.0.0.3:8080"},
    86  		"https": {"10.0.0.1:443", "10.0.0.2:443"},
    87  		"dns":   {"10.0.0.1:53", "10.0.0.3:53"},
    88  	}
    89  
    90  	portsToEndpoints := BuildPortsToEndpointsMap(endpoints)
    91  	if !reflect.DeepEqual(expectedPortsToEndpoints, portsToEndpoints) {
    92  		t.Errorf("expected ports to endpoints not seen")
    93  	}
    94  }
    95  
    96  func TestShouldSkipService(t *testing.T) {
    97  	testCases := []struct {
    98  		service    *v1.Service
    99  		shouldSkip bool
   100  	}{
   101  		{
   102  			// Cluster IP is None
   103  			service: &v1.Service{
   104  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   105  				Spec: v1.ServiceSpec{
   106  					ClusterIP: v1.ClusterIPNone,
   107  				},
   108  			},
   109  			shouldSkip: true,
   110  		},
   111  		{
   112  			// Cluster IP is empty
   113  			service: &v1.Service{
   114  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   115  				Spec: v1.ServiceSpec{
   116  					ClusterIP: "",
   117  				},
   118  			},
   119  			shouldSkip: true,
   120  		},
   121  		{
   122  			// ExternalName type service
   123  			service: &v1.Service{
   124  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   125  				Spec: v1.ServiceSpec{
   126  					ClusterIP: "1.2.3.4",
   127  					Type:      v1.ServiceTypeExternalName,
   128  				},
   129  			},
   130  			shouldSkip: true,
   131  		},
   132  		{
   133  			// ClusterIP type service with ClusterIP set
   134  			service: &v1.Service{
   135  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   136  				Spec: v1.ServiceSpec{
   137  					ClusterIP: "1.2.3.4",
   138  					Type:      v1.ServiceTypeClusterIP,
   139  				},
   140  			},
   141  			shouldSkip: false,
   142  		},
   143  		{
   144  			// NodePort type service with ClusterIP set
   145  			service: &v1.Service{
   146  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   147  				Spec: v1.ServiceSpec{
   148  					ClusterIP: "1.2.3.4",
   149  					Type:      v1.ServiceTypeNodePort,
   150  				},
   151  			},
   152  			shouldSkip: false,
   153  		},
   154  		{
   155  			// LoadBalancer type service with ClusterIP set
   156  			service: &v1.Service{
   157  				ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "bar"},
   158  				Spec: v1.ServiceSpec{
   159  					ClusterIP: "1.2.3.4",
   160  					Type:      v1.ServiceTypeLoadBalancer,
   161  				},
   162  			},
   163  			shouldSkip: false,
   164  		},
   165  	}
   166  
   167  	for i := range testCases {
   168  		skip := ShouldSkipService(testCases[i].service)
   169  		if skip != testCases[i].shouldSkip {
   170  			t.Errorf("case %d: expect %v, got %v", i, testCases[i].shouldSkip, skip)
   171  		}
   172  	}
   173  }
   174  
   175  func TestAppendPortIfNeeded(t *testing.T) {
   176  	testCases := []struct {
   177  		name   string
   178  		addr   string
   179  		port   int32
   180  		expect string
   181  	}{
   182  		{
   183  			name:   "IPv4 all-zeros bind address has port",
   184  			addr:   "0.0.0.0:12345",
   185  			port:   23456,
   186  			expect: "0.0.0.0:12345",
   187  		},
   188  		{
   189  			name:   "non-zeros IPv4 config",
   190  			addr:   "9.8.7.6",
   191  			port:   12345,
   192  			expect: "9.8.7.6:12345",
   193  		},
   194  		{
   195  			name:   "IPv6 \"[::]\" bind address has port",
   196  			addr:   "[::]:12345",
   197  			port:   23456,
   198  			expect: "[::]:12345",
   199  		},
   200  		{
   201  			name:   "IPv6 config",
   202  			addr:   "fd00:1::5",
   203  			port:   23456,
   204  			expect: "[fd00:1::5]:23456",
   205  		},
   206  		{
   207  			name:   "Invalid IPv6 Config",
   208  			addr:   "[fd00:1::5]",
   209  			port:   12345,
   210  			expect: "[fd00:1::5]",
   211  		},
   212  	}
   213  
   214  	for i := range testCases {
   215  		got := AppendPortIfNeeded(testCases[i].addr, testCases[i].port)
   216  		if testCases[i].expect != got {
   217  			t.Errorf("case %s: expected %v, got %v", testCases[i].name, testCases[i].expect, got)
   218  		}
   219  	}
   220  }
   221  
   222  func TestShuffleStrings(t *testing.T) {
   223  	var src []string
   224  	dest := ShuffleStrings(src)
   225  
   226  	if dest != nil {
   227  		t.Errorf("ShuffleStrings for a nil slice got a non-nil slice")
   228  	}
   229  
   230  	src = []string{"a", "b", "c", "d", "e", "f"}
   231  	dest = ShuffleStrings(src)
   232  
   233  	if len(src) != len(dest) {
   234  		t.Errorf("Shuffled slice is wrong length, expected %v got %v", len(src), len(dest))
   235  	}
   236  
   237  	m := make(map[string]bool, len(dest))
   238  	for _, s := range dest {
   239  		m[s] = true
   240  	}
   241  
   242  	for _, k := range src {
   243  		if _, exists := m[k]; !exists {
   244  			t.Errorf("Element %v missing from shuffled slice", k)
   245  		}
   246  	}
   247  }
   248  
   249  func TestMapIPsByIPFamily(t *testing.T) {
   250  	testCases := []struct {
   251  		desc            string
   252  		ipString        []string
   253  		wantIPv6        bool
   254  		expectCorrect   []string
   255  		expectIncorrect []string
   256  	}{
   257  		{
   258  			desc:            "empty input IPv4",
   259  			ipString:        []string{},
   260  			wantIPv6:        false,
   261  			expectCorrect:   nil,
   262  			expectIncorrect: nil,
   263  		},
   264  		{
   265  			desc:            "empty input IPv6",
   266  			ipString:        []string{},
   267  			wantIPv6:        true,
   268  			expectCorrect:   nil,
   269  			expectIncorrect: nil,
   270  		},
   271  		{
   272  			desc:            "want IPv4 and receive IPv6",
   273  			ipString:        []string{"fd00:20::1"},
   274  			wantIPv6:        false,
   275  			expectCorrect:   nil,
   276  			expectIncorrect: []string{"fd00:20::1"},
   277  		},
   278  		{
   279  			desc:            "want IPv6 and receive IPv4",
   280  			ipString:        []string{"192.168.200.2"},
   281  			wantIPv6:        true,
   282  			expectCorrect:   nil,
   283  			expectIncorrect: []string{"192.168.200.2"},
   284  		},
   285  		{
   286  			desc:            "want IPv6 and receive IPv4 and IPv6",
   287  			ipString:        []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"},
   288  			wantIPv6:        true,
   289  			expectCorrect:   []string{"fd00:20::1", "2001:db9::3"},
   290  			expectIncorrect: []string{"192.168.200.2", "192.1.34.23"},
   291  		},
   292  		{
   293  			desc:            "want IPv4 and receive IPv4 and IPv6",
   294  			ipString:        []string{"192.168.200.2", "192.1.34.23", "fd00:20::1", "2001:db9::3"},
   295  			wantIPv6:        false,
   296  			expectCorrect:   []string{"192.168.200.2", "192.1.34.23"},
   297  			expectIncorrect: []string{"fd00:20::1", "2001:db9::3"},
   298  		},
   299  		{
   300  			desc:            "want IPv4 and receive IPv4 only",
   301  			ipString:        []string{"192.168.200.2", "192.1.34.23"},
   302  			wantIPv6:        false,
   303  			expectCorrect:   []string{"192.168.200.2", "192.1.34.23"},
   304  			expectIncorrect: nil,
   305  		},
   306  		{
   307  			desc:            "want IPv6 and receive IPv4 only",
   308  			ipString:        []string{"192.168.200.2", "192.1.34.23"},
   309  			wantIPv6:        true,
   310  			expectCorrect:   nil,
   311  			expectIncorrect: []string{"192.168.200.2", "192.1.34.23"},
   312  		},
   313  		{
   314  			desc:            "want IPv4 and receive IPv6 only",
   315  			ipString:        []string{"fd00:20::1", "2001:db9::3"},
   316  			wantIPv6:        false,
   317  			expectCorrect:   nil,
   318  			expectIncorrect: []string{"fd00:20::1", "2001:db9::3"},
   319  		},
   320  		{
   321  			desc:            "want IPv6 and receive IPv6 only",
   322  			ipString:        []string{"fd00:20::1", "2001:db9::3"},
   323  			wantIPv6:        true,
   324  			expectCorrect:   []string{"fd00:20::1", "2001:db9::3"},
   325  			expectIncorrect: nil,
   326  		},
   327  	}
   328  
   329  	for _, testcase := range testCases {
   330  		t.Run(testcase.desc, func(t *testing.T) {
   331  			ipFamily := v1.IPv4Protocol
   332  			otherIPFamily := v1.IPv6Protocol
   333  
   334  			if testcase.wantIPv6 {
   335  				ipFamily = v1.IPv6Protocol
   336  				otherIPFamily = v1.IPv4Protocol
   337  			}
   338  
   339  			ipMap := MapIPsByIPFamily(testcase.ipString)
   340  
   341  			if !reflect.DeepEqual(testcase.expectCorrect, ipMap[ipFamily]) {
   342  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, ipMap[ipFamily])
   343  			}
   344  			if !reflect.DeepEqual(testcase.expectIncorrect, ipMap[otherIPFamily]) {
   345  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, ipMap[otherIPFamily])
   346  			}
   347  		})
   348  	}
   349  }
   350  
   351  func TestMapCIDRsByIPFamily(t *testing.T) {
   352  	testCases := []struct {
   353  		desc            string
   354  		ipString        []string
   355  		wantIPv6        bool
   356  		expectCorrect   []string
   357  		expectIncorrect []string
   358  	}{
   359  		{
   360  			desc:            "empty input IPv4",
   361  			ipString:        []string{},
   362  			wantIPv6:        false,
   363  			expectCorrect:   nil,
   364  			expectIncorrect: nil,
   365  		},
   366  		{
   367  			desc:            "empty input IPv6",
   368  			ipString:        []string{},
   369  			wantIPv6:        true,
   370  			expectCorrect:   nil,
   371  			expectIncorrect: nil,
   372  		},
   373  		{
   374  			desc:            "want IPv4 and receive IPv6",
   375  			ipString:        []string{"fd00:20::1/64"},
   376  			wantIPv6:        false,
   377  			expectCorrect:   nil,
   378  			expectIncorrect: []string{"fd00:20::1/64"},
   379  		},
   380  		{
   381  			desc:            "want IPv6 and receive IPv4",
   382  			ipString:        []string{"192.168.200.2/24"},
   383  			wantIPv6:        true,
   384  			expectCorrect:   nil,
   385  			expectIncorrect: []string{"192.168.200.2/24"},
   386  		},
   387  		{
   388  			desc:            "want IPv6 and receive IPv4 and IPv6",
   389  			ipString:        []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"},
   390  			wantIPv6:        true,
   391  			expectCorrect:   []string{"fd00:20::1/64", "2001:db9::3/64"},
   392  			expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
   393  		},
   394  		{
   395  			desc:            "want IPv4 and receive IPv4 and IPv6",
   396  			ipString:        []string{"192.168.200.2/24", "192.1.34.23/24", "fd00:20::1/64", "2001:db9::3/64"},
   397  			wantIPv6:        false,
   398  			expectCorrect:   []string{"192.168.200.2/24", "192.1.34.23/24"},
   399  			expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
   400  		},
   401  		{
   402  			desc:            "want IPv4 and receive IPv4 only",
   403  			ipString:        []string{"192.168.200.2/24", "192.1.34.23/24"},
   404  			wantIPv6:        false,
   405  			expectCorrect:   []string{"192.168.200.2/24", "192.1.34.23/24"},
   406  			expectIncorrect: nil,
   407  		},
   408  		{
   409  			desc:            "want IPv6 and receive IPv4 only",
   410  			ipString:        []string{"192.168.200.2/24", "192.1.34.23/24"},
   411  			wantIPv6:        true,
   412  			expectCorrect:   nil,
   413  			expectIncorrect: []string{"192.168.200.2/24", "192.1.34.23/24"},
   414  		},
   415  		{
   416  			desc:            "want IPv4 and receive IPv6 only",
   417  			ipString:        []string{"fd00:20::1/64", "2001:db9::3/64"},
   418  			wantIPv6:        false,
   419  			expectCorrect:   nil,
   420  			expectIncorrect: []string{"fd00:20::1/64", "2001:db9::3/64"},
   421  		},
   422  		{
   423  			desc:            "want IPv6 and receive IPv6 only",
   424  			ipString:        []string{"fd00:20::1/64", "2001:db9::3/64"},
   425  			wantIPv6:        true,
   426  			expectCorrect:   []string{"fd00:20::1/64", "2001:db9::3/64"},
   427  			expectIncorrect: nil,
   428  		},
   429  	}
   430  
   431  	for _, testcase := range testCases {
   432  		t.Run(testcase.desc, func(t *testing.T) {
   433  			ipFamily := v1.IPv4Protocol
   434  			otherIPFamily := v1.IPv6Protocol
   435  
   436  			if testcase.wantIPv6 {
   437  				ipFamily = v1.IPv6Protocol
   438  				otherIPFamily = v1.IPv4Protocol
   439  			}
   440  
   441  			cidrMap := MapCIDRsByIPFamily(testcase.ipString)
   442  
   443  			if !reflect.DeepEqual(testcase.expectCorrect, cidrMap[ipFamily]) {
   444  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, cidrMap[ipFamily])
   445  			}
   446  			if !reflect.DeepEqual(testcase.expectIncorrect, cidrMap[otherIPFamily]) {
   447  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, cidrMap[otherIPFamily])
   448  			}
   449  		})
   450  	}
   451  }
   452  
   453  func TestGetClusterIPByFamily(t *testing.T) {
   454  	testCases := []struct {
   455  		name           string
   456  		service        v1.Service
   457  		requestFamily  v1.IPFamily
   458  		expectedResult string
   459  	}{
   460  		{
   461  			name:           "old style service ipv4. want ipv4",
   462  			requestFamily:  v1.IPv4Protocol,
   463  			expectedResult: "10.0.0.10",
   464  			service: v1.Service{
   465  				Spec: v1.ServiceSpec{
   466  					ClusterIP: "10.0.0.10",
   467  				},
   468  			},
   469  		},
   470  
   471  		{
   472  			name:           "old style service ipv4. want ipv6",
   473  			requestFamily:  v1.IPv6Protocol,
   474  			expectedResult: "",
   475  			service: v1.Service{
   476  				Spec: v1.ServiceSpec{
   477  					ClusterIP: "10.0.0.10",
   478  				},
   479  			},
   480  		},
   481  
   482  		{
   483  			name:           "old style service ipv6. want ipv6",
   484  			requestFamily:  v1.IPv6Protocol,
   485  			expectedResult: "2000::1",
   486  			service: v1.Service{
   487  				Spec: v1.ServiceSpec{
   488  					ClusterIP: "2000::1",
   489  				},
   490  			},
   491  		},
   492  
   493  		{
   494  			name:           "old style service ipv6. want ipv4",
   495  			requestFamily:  v1.IPv4Protocol,
   496  			expectedResult: "",
   497  			service: v1.Service{
   498  				Spec: v1.ServiceSpec{
   499  					ClusterIP: "2000::1",
   500  				},
   501  			},
   502  		},
   503  
   504  		{
   505  			name:           "service single stack ipv4. want ipv4",
   506  			requestFamily:  v1.IPv4Protocol,
   507  			expectedResult: "10.0.0.10",
   508  			service: v1.Service{
   509  				Spec: v1.ServiceSpec{
   510  					ClusterIPs: []string{"10.0.0.10"},
   511  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
   512  				},
   513  			},
   514  		},
   515  
   516  		{
   517  			name:           "service single stack ipv4. want ipv6",
   518  			requestFamily:  v1.IPv6Protocol,
   519  			expectedResult: "",
   520  			service: v1.Service{
   521  				Spec: v1.ServiceSpec{
   522  					ClusterIPs: []string{"10.0.0.10"},
   523  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
   524  				},
   525  			},
   526  		},
   527  
   528  		{
   529  			name:           "service single stack ipv6. want ipv6",
   530  			requestFamily:  v1.IPv6Protocol,
   531  			expectedResult: "2000::1",
   532  			service: v1.Service{
   533  				Spec: v1.ServiceSpec{
   534  					ClusterIPs: []string{"2000::1"},
   535  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol},
   536  				},
   537  			},
   538  		},
   539  
   540  		{
   541  			name:           "service single stack ipv6. want ipv4",
   542  			requestFamily:  v1.IPv4Protocol,
   543  			expectedResult: "",
   544  			service: v1.Service{
   545  				Spec: v1.ServiceSpec{
   546  					ClusterIPs: []string{"2000::1"},
   547  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol},
   548  				},
   549  			},
   550  		},
   551  		// dual stack
   552  		{
   553  			name:           "service dual stack ipv4,6. want ipv4",
   554  			requestFamily:  v1.IPv4Protocol,
   555  			expectedResult: "10.0.0.10",
   556  			service: v1.Service{
   557  				Spec: v1.ServiceSpec{
   558  					ClusterIPs: []string{"10.0.0.10", "2000::1"},
   559  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
   560  				},
   561  			},
   562  		},
   563  
   564  		{
   565  			name:           "service dual stack ipv4,6. want ipv6",
   566  			requestFamily:  v1.IPv6Protocol,
   567  			expectedResult: "2000::1",
   568  			service: v1.Service{
   569  				Spec: v1.ServiceSpec{
   570  					ClusterIPs: []string{"10.0.0.10", "2000::1"},
   571  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
   572  				},
   573  			},
   574  		},
   575  
   576  		{
   577  			name:           "service dual stack ipv6,4. want ipv6",
   578  			requestFamily:  v1.IPv6Protocol,
   579  			expectedResult: "2000::1",
   580  			service: v1.Service{
   581  				Spec: v1.ServiceSpec{
   582  					ClusterIPs: []string{"2000::1", "10.0.0.10"},
   583  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
   584  				},
   585  			},
   586  		},
   587  
   588  		{
   589  			name:           "service dual stack ipv6,4. want ipv4",
   590  			requestFamily:  v1.IPv4Protocol,
   591  			expectedResult: "10.0.0.10",
   592  			service: v1.Service{
   593  				Spec: v1.ServiceSpec{
   594  					ClusterIPs: []string{"2000::1", "10.0.0.10"},
   595  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
   596  				},
   597  			},
   598  		},
   599  	}
   600  
   601  	for _, testCase := range testCases {
   602  		t.Run(testCase.name, func(t *testing.T) {
   603  			ip := GetClusterIPByFamily(testCase.requestFamily, &testCase.service)
   604  			if ip != testCase.expectedResult {
   605  				t.Fatalf("expected ip:%v got %v", testCase.expectedResult, ip)
   606  			}
   607  		})
   608  	}
   609  }
   610  
   611  type fakeClosable struct {
   612  	closed bool
   613  }
   614  
   615  func (c *fakeClosable) Close() error {
   616  	c.closed = true
   617  	return nil
   618  }
   619  
   620  func TestRevertPorts(t *testing.T) {
   621  	testCases := []struct {
   622  		replacementPorts []netutils.LocalPort
   623  		existingPorts    []netutils.LocalPort
   624  		expectToBeClose  []bool
   625  	}{
   626  		{
   627  			replacementPorts: []netutils.LocalPort{
   628  				{Port: 5001},
   629  				{Port: 5002},
   630  				{Port: 5003},
   631  			},
   632  			existingPorts:   []netutils.LocalPort{},
   633  			expectToBeClose: []bool{true, true, true},
   634  		},
   635  		{
   636  			replacementPorts: []netutils.LocalPort{},
   637  			existingPorts: []netutils.LocalPort{
   638  				{Port: 5001},
   639  				{Port: 5002},
   640  				{Port: 5003},
   641  			},
   642  			expectToBeClose: []bool{},
   643  		},
   644  		{
   645  			replacementPorts: []netutils.LocalPort{
   646  				{Port: 5001},
   647  				{Port: 5002},
   648  				{Port: 5003},
   649  			},
   650  			existingPorts: []netutils.LocalPort{
   651  				{Port: 5001},
   652  				{Port: 5002},
   653  				{Port: 5003},
   654  			},
   655  			expectToBeClose: []bool{false, false, false},
   656  		},
   657  		{
   658  			replacementPorts: []netutils.LocalPort{
   659  				{Port: 5001},
   660  				{Port: 5002},
   661  				{Port: 5003},
   662  			},
   663  			existingPorts: []netutils.LocalPort{
   664  				{Port: 5001},
   665  				{Port: 5003},
   666  			},
   667  			expectToBeClose: []bool{false, true, false},
   668  		},
   669  		{
   670  			replacementPorts: []netutils.LocalPort{
   671  				{Port: 5001},
   672  				{Port: 5002},
   673  				{Port: 5003},
   674  			},
   675  			existingPorts: []netutils.LocalPort{
   676  				{Port: 5001},
   677  				{Port: 5002},
   678  				{Port: 5003},
   679  				{Port: 5004},
   680  			},
   681  			expectToBeClose: []bool{false, false, false},
   682  		},
   683  	}
   684  
   685  	for i, tc := range testCases {
   686  		replacementPortsMap := make(map[netutils.LocalPort]netutils.Closeable)
   687  		for _, lp := range tc.replacementPorts {
   688  			replacementPortsMap[lp] = &fakeClosable{}
   689  		}
   690  		existingPortsMap := make(map[netutils.LocalPort]netutils.Closeable)
   691  		for _, lp := range tc.existingPorts {
   692  			existingPortsMap[lp] = &fakeClosable{}
   693  		}
   694  		RevertPorts(replacementPortsMap, existingPortsMap)
   695  		for j, expectation := range tc.expectToBeClose {
   696  			if replacementPortsMap[tc.replacementPorts[j]].(*fakeClosable).closed != expectation {
   697  				t.Errorf("Expect replacement localport %v to be %v in test case %v", tc.replacementPorts[j], expectation, i)
   698  			}
   699  		}
   700  		for _, lp := range tc.existingPorts {
   701  			if existingPortsMap[lp].(*fakeClosable).closed {
   702  				t.Errorf("Expect existing localport %v to be false in test case %v", lp, i)
   703  			}
   704  		}
   705  	}
   706  }
   707  
   708  func mustParseIPAddr(str string) net.Addr {
   709  	a, err := net.ResolveIPAddr("ip", str)
   710  	if err != nil {
   711  		panic("mustParseIPAddr")
   712  	}
   713  	return a
   714  }
   715  func mustParseIPNet(str string) net.Addr {
   716  	_, n, err := netutils.ParseCIDRSloppy(str)
   717  	if err != nil {
   718  		panic("mustParseIPNet")
   719  	}
   720  	return n
   721  }
   722  func mustParseUnix(str string) net.Addr {
   723  	n, err := net.ResolveUnixAddr("unix", str)
   724  	if err != nil {
   725  		panic("mustParseUnix")
   726  	}
   727  	return n
   728  }
   729  
   730  type cidrValidator struct {
   731  	cidr *net.IPNet
   732  }
   733  
   734  func (v *cidrValidator) isValid(ip net.IP) bool {
   735  	return v.cidr.Contains(ip)
   736  }
   737  func newCidrValidator(cidr string) func(ip net.IP) bool {
   738  	_, n, err := netutils.ParseCIDRSloppy(cidr)
   739  	if err != nil {
   740  		panic("mustParseIPNet")
   741  	}
   742  	obj := cidrValidator{n}
   743  	return obj.isValid
   744  }
   745  
   746  func TestAddressSet(t *testing.T) {
   747  	testCases := []struct {
   748  		name      string
   749  		validator func(ip net.IP) bool
   750  		input     []net.Addr
   751  		expected  sets.Set[string]
   752  	}{
   753  		{
   754  			"Empty",
   755  			func(ip net.IP) bool { return false },
   756  			nil,
   757  			nil,
   758  		},
   759  		{
   760  			"Reject IPAddr x 2",
   761  			func(ip net.IP) bool { return false },
   762  			[]net.Addr{
   763  				mustParseIPAddr("8.8.8.8"),
   764  				mustParseIPAddr("1000::"),
   765  			},
   766  			nil,
   767  		},
   768  		{
   769  			"Accept IPAddr x 2",
   770  			func(ip net.IP) bool { return true },
   771  			[]net.Addr{
   772  				mustParseIPAddr("8.8.8.8"),
   773  				mustParseIPAddr("1000::"),
   774  			},
   775  			sets.New("8.8.8.8", "1000::"),
   776  		},
   777  		{
   778  			"Accept IPNet x 2",
   779  			func(ip net.IP) bool { return true },
   780  			[]net.Addr{
   781  				mustParseIPNet("8.8.8.8/32"),
   782  				mustParseIPNet("1000::/128"),
   783  			},
   784  			sets.New("8.8.8.8", "1000::"),
   785  		},
   786  		{
   787  			"Accept Unix x 2",
   788  			func(ip net.IP) bool { return true },
   789  			[]net.Addr{
   790  				mustParseUnix("/tmp/sock1"),
   791  				mustParseUnix("/tmp/sock2"),
   792  			},
   793  			nil,
   794  		},
   795  		{
   796  			"Cidr IPv4",
   797  			newCidrValidator("192.168.1.0/24"),
   798  			[]net.Addr{
   799  				mustParseIPAddr("8.8.8.8"),
   800  				mustParseIPAddr("1000::"),
   801  				mustParseIPAddr("192.168.1.1"),
   802  			},
   803  			sets.New("192.168.1.1"),
   804  		},
   805  		{
   806  			"Cidr IPv6",
   807  			newCidrValidator("1000::/64"),
   808  			[]net.Addr{
   809  				mustParseIPAddr("8.8.8.8"),
   810  				mustParseIPAddr("1000::"),
   811  				mustParseIPAddr("192.168.1.1"),
   812  			},
   813  			sets.New("1000::"),
   814  		},
   815  	}
   816  
   817  	for _, tc := range testCases {
   818  		if !tc.expected.Equal(AddressSet(tc.validator, tc.input)) {
   819  			t.Errorf("%s", tc.name)
   820  		}
   821  	}
   822  }
   823  
   824  func TestIsZeroCIDR(t *testing.T) {
   825  	testCases := []struct {
   826  		name     string
   827  		input    string
   828  		expected bool
   829  	}{
   830  		{
   831  			name:     "invalide cidr",
   832  			input:    "",
   833  			expected: false,
   834  		},
   835  		{
   836  			name:     "ipv4 cidr",
   837  			input:    "172.10.0.0/16",
   838  			expected: false,
   839  		},
   840  		{
   841  			name:     "ipv4 zero cidr",
   842  			input:    IPv4ZeroCIDR,
   843  			expected: true,
   844  		},
   845  		{
   846  			name:     "ipv6 cidr",
   847  			input:    "::/128",
   848  			expected: false,
   849  		},
   850  		{
   851  			name:     "ipv6 zero cidr",
   852  			input:    IPv6ZeroCIDR,
   853  			expected: true,
   854  		},
   855  	}
   856  	for _, tc := range testCases {
   857  		t.Run(tc.name, func(t *testing.T) {
   858  			if got := IsZeroCIDR(tc.input); tc.expected != got {
   859  				t.Errorf("IsZeroCIDR() = %t, want %t", got, tc.expected)
   860  			}
   861  		})
   862  	}
   863  }