...

Source file src/k8s.io/kubernetes/pkg/proxy/util/utils_test.go

Documentation: k8s.io/kubernetes/pkg/proxy/util

     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  			var ipStr []string
   342  			for _, ip := range ipMap[ipFamily] {
   343  				ipStr = append(ipStr, ip.String())
   344  			}
   345  			if !reflect.DeepEqual(testcase.expectCorrect, ipStr) {
   346  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, ipMap[ipFamily])
   347  			}
   348  			ipStr = nil
   349  			for _, ip := range ipMap[otherIPFamily] {
   350  				ipStr = append(ipStr, ip.String())
   351  			}
   352  			if !reflect.DeepEqual(testcase.expectIncorrect, ipStr) {
   353  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, ipMap[otherIPFamily])
   354  			}
   355  		})
   356  	}
   357  }
   358  
   359  func TestMapCIDRsByIPFamily(t *testing.T) {
   360  	testCases := []struct {
   361  		desc            string
   362  		ipString        []string
   363  		wantIPv6        bool
   364  		expectCorrect   []string
   365  		expectIncorrect []string
   366  	}{
   367  		{
   368  			desc:            "empty input IPv4",
   369  			ipString:        []string{},
   370  			wantIPv6:        false,
   371  			expectCorrect:   nil,
   372  			expectIncorrect: nil,
   373  		},
   374  		{
   375  			desc:            "empty input IPv6",
   376  			ipString:        []string{},
   377  			wantIPv6:        true,
   378  			expectCorrect:   nil,
   379  			expectIncorrect: nil,
   380  		},
   381  		{
   382  			desc:            "want IPv4 and receive IPv6",
   383  			ipString:        []string{"fd00:20::/64"},
   384  			wantIPv6:        false,
   385  			expectCorrect:   nil,
   386  			expectIncorrect: []string{"fd00:20::/64"},
   387  		},
   388  		{
   389  			desc:            "want IPv6 and receive IPv4",
   390  			ipString:        []string{"192.168.200.0/24"},
   391  			wantIPv6:        true,
   392  			expectCorrect:   nil,
   393  			expectIncorrect: []string{"192.168.200.0/24"},
   394  		},
   395  		{
   396  			desc:            "want IPv6 and receive IPv4 and IPv6",
   397  			ipString:        []string{"192.168.200.0/24", "192.1.34.0/24", "fd00:20::/64", "2001:db9::/64"},
   398  			wantIPv6:        true,
   399  			expectCorrect:   []string{"fd00:20::/64", "2001:db9::/64"},
   400  			expectIncorrect: []string{"192.168.200.0/24", "192.1.34.0/24"},
   401  		},
   402  		{
   403  			desc:            "want IPv4 and receive IPv4 and IPv6",
   404  			ipString:        []string{"192.168.200.0/24", "192.1.34.0/24", "fd00:20::/64", "2001:db9::/64"},
   405  			wantIPv6:        false,
   406  			expectCorrect:   []string{"192.168.200.0/24", "192.1.34.0/24"},
   407  			expectIncorrect: []string{"fd00:20::/64", "2001:db9::/64"},
   408  		},
   409  		{
   410  			desc:            "want IPv4 and receive IPv4 only",
   411  			ipString:        []string{"192.168.200.0/24", "192.1.34.0/24"},
   412  			wantIPv6:        false,
   413  			expectCorrect:   []string{"192.168.200.0/24", "192.1.34.0/24"},
   414  			expectIncorrect: nil,
   415  		},
   416  		{
   417  			desc:            "want IPv6 and receive IPv4 only",
   418  			ipString:        []string{"192.168.200.0/24", "192.1.34.0/24"},
   419  			wantIPv6:        true,
   420  			expectCorrect:   nil,
   421  			expectIncorrect: []string{"192.168.200.0/24", "192.1.34.0/24"},
   422  		},
   423  		{
   424  			desc:            "want IPv4 and receive IPv6 only",
   425  			ipString:        []string{"fd00:20::/64", "2001:db9::/64"},
   426  			wantIPv6:        false,
   427  			expectCorrect:   nil,
   428  			expectIncorrect: []string{"fd00:20::/64", "2001:db9::/64"},
   429  		},
   430  		{
   431  			desc:            "want IPv6 and receive IPv6 only",
   432  			ipString:        []string{"fd00:20::/64", "2001:db9::/64"},
   433  			wantIPv6:        true,
   434  			expectCorrect:   []string{"fd00:20::/64", "2001:db9::/64"},
   435  			expectIncorrect: nil,
   436  		},
   437  	}
   438  
   439  	for _, testcase := range testCases {
   440  		t.Run(testcase.desc, func(t *testing.T) {
   441  			ipFamily := v1.IPv4Protocol
   442  			otherIPFamily := v1.IPv6Protocol
   443  
   444  			if testcase.wantIPv6 {
   445  				ipFamily = v1.IPv6Protocol
   446  				otherIPFamily = v1.IPv4Protocol
   447  			}
   448  
   449  			cidrMap := MapCIDRsByIPFamily(testcase.ipString)
   450  
   451  			var cidrStr []string
   452  			for _, cidr := range cidrMap[ipFamily] {
   453  				cidrStr = append(cidrStr, cidr.String())
   454  			}
   455  			var cidrStrOther []string
   456  			for _, cidr := range cidrMap[otherIPFamily] {
   457  				cidrStrOther = append(cidrStrOther, cidr.String())
   458  			}
   459  
   460  			if !reflect.DeepEqual(testcase.expectCorrect, cidrStr) {
   461  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectCorrect, cidrStr)
   462  			}
   463  			if !reflect.DeepEqual(testcase.expectIncorrect, cidrStrOther) {
   464  				t.Errorf("Test %v failed: expected %v, got %v", testcase.desc, testcase.expectIncorrect, cidrStrOther)
   465  			}
   466  		})
   467  	}
   468  }
   469  
   470  func TestGetClusterIPByFamily(t *testing.T) {
   471  	testCases := []struct {
   472  		name           string
   473  		service        v1.Service
   474  		requestFamily  v1.IPFamily
   475  		expectedResult string
   476  	}{
   477  		{
   478  			name:           "old style service ipv4. want ipv4",
   479  			requestFamily:  v1.IPv4Protocol,
   480  			expectedResult: "10.0.0.10",
   481  			service: v1.Service{
   482  				Spec: v1.ServiceSpec{
   483  					ClusterIP: "10.0.0.10",
   484  				},
   485  			},
   486  		},
   487  
   488  		{
   489  			name:           "old style service ipv4. want ipv6",
   490  			requestFamily:  v1.IPv6Protocol,
   491  			expectedResult: "",
   492  			service: v1.Service{
   493  				Spec: v1.ServiceSpec{
   494  					ClusterIP: "10.0.0.10",
   495  				},
   496  			},
   497  		},
   498  
   499  		{
   500  			name:           "old style service ipv6. want ipv6",
   501  			requestFamily:  v1.IPv6Protocol,
   502  			expectedResult: "2000::1",
   503  			service: v1.Service{
   504  				Spec: v1.ServiceSpec{
   505  					ClusterIP: "2000::1",
   506  				},
   507  			},
   508  		},
   509  
   510  		{
   511  			name:           "old style service ipv6. want ipv4",
   512  			requestFamily:  v1.IPv4Protocol,
   513  			expectedResult: "",
   514  			service: v1.Service{
   515  				Spec: v1.ServiceSpec{
   516  					ClusterIP: "2000::1",
   517  				},
   518  			},
   519  		},
   520  
   521  		{
   522  			name:           "service single stack ipv4. want ipv4",
   523  			requestFamily:  v1.IPv4Protocol,
   524  			expectedResult: "10.0.0.10",
   525  			service: v1.Service{
   526  				Spec: v1.ServiceSpec{
   527  					ClusterIPs: []string{"10.0.0.10"},
   528  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
   529  				},
   530  			},
   531  		},
   532  
   533  		{
   534  			name:           "service single stack ipv4. want ipv6",
   535  			requestFamily:  v1.IPv6Protocol,
   536  			expectedResult: "",
   537  			service: v1.Service{
   538  				Spec: v1.ServiceSpec{
   539  					ClusterIPs: []string{"10.0.0.10"},
   540  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol},
   541  				},
   542  			},
   543  		},
   544  
   545  		{
   546  			name:           "service single stack ipv6. want ipv6",
   547  			requestFamily:  v1.IPv6Protocol,
   548  			expectedResult: "2000::1",
   549  			service: v1.Service{
   550  				Spec: v1.ServiceSpec{
   551  					ClusterIPs: []string{"2000::1"},
   552  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol},
   553  				},
   554  			},
   555  		},
   556  
   557  		{
   558  			name:           "service single stack ipv6. want ipv4",
   559  			requestFamily:  v1.IPv4Protocol,
   560  			expectedResult: "",
   561  			service: v1.Service{
   562  				Spec: v1.ServiceSpec{
   563  					ClusterIPs: []string{"2000::1"},
   564  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol},
   565  				},
   566  			},
   567  		},
   568  		// dual stack
   569  		{
   570  			name:           "service dual stack ipv4,6. want ipv4",
   571  			requestFamily:  v1.IPv4Protocol,
   572  			expectedResult: "10.0.0.10",
   573  			service: v1.Service{
   574  				Spec: v1.ServiceSpec{
   575  					ClusterIPs: []string{"10.0.0.10", "2000::1"},
   576  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
   577  				},
   578  			},
   579  		},
   580  
   581  		{
   582  			name:           "service dual stack ipv4,6. want ipv6",
   583  			requestFamily:  v1.IPv6Protocol,
   584  			expectedResult: "2000::1",
   585  			service: v1.Service{
   586  				Spec: v1.ServiceSpec{
   587  					ClusterIPs: []string{"10.0.0.10", "2000::1"},
   588  					IPFamilies: []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol},
   589  				},
   590  			},
   591  		},
   592  
   593  		{
   594  			name:           "service dual stack ipv6,4. want ipv6",
   595  			requestFamily:  v1.IPv6Protocol,
   596  			expectedResult: "2000::1",
   597  			service: v1.Service{
   598  				Spec: v1.ServiceSpec{
   599  					ClusterIPs: []string{"2000::1", "10.0.0.10"},
   600  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
   601  				},
   602  			},
   603  		},
   604  
   605  		{
   606  			name:           "service dual stack ipv6,4. want ipv4",
   607  			requestFamily:  v1.IPv4Protocol,
   608  			expectedResult: "10.0.0.10",
   609  			service: v1.Service{
   610  				Spec: v1.ServiceSpec{
   611  					ClusterIPs: []string{"2000::1", "10.0.0.10"},
   612  					IPFamilies: []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol},
   613  				},
   614  			},
   615  		},
   616  	}
   617  
   618  	for _, testCase := range testCases {
   619  		t.Run(testCase.name, func(t *testing.T) {
   620  			ip := GetClusterIPByFamily(testCase.requestFamily, &testCase.service)
   621  			if ip != testCase.expectedResult {
   622  				t.Fatalf("expected ip:%v got %v", testCase.expectedResult, ip)
   623  			}
   624  		})
   625  	}
   626  }
   627  
   628  type fakeClosable struct {
   629  	closed bool
   630  }
   631  
   632  func (c *fakeClosable) Close() error {
   633  	c.closed = true
   634  	return nil
   635  }
   636  
   637  func TestRevertPorts(t *testing.T) {
   638  	testCases := []struct {
   639  		replacementPorts []netutils.LocalPort
   640  		existingPorts    []netutils.LocalPort
   641  		expectToBeClose  []bool
   642  	}{
   643  		{
   644  			replacementPorts: []netutils.LocalPort{
   645  				{Port: 5001},
   646  				{Port: 5002},
   647  				{Port: 5003},
   648  			},
   649  			existingPorts:   []netutils.LocalPort{},
   650  			expectToBeClose: []bool{true, true, true},
   651  		},
   652  		{
   653  			replacementPorts: []netutils.LocalPort{},
   654  			existingPorts: []netutils.LocalPort{
   655  				{Port: 5001},
   656  				{Port: 5002},
   657  				{Port: 5003},
   658  			},
   659  			expectToBeClose: []bool{},
   660  		},
   661  		{
   662  			replacementPorts: []netutils.LocalPort{
   663  				{Port: 5001},
   664  				{Port: 5002},
   665  				{Port: 5003},
   666  			},
   667  			existingPorts: []netutils.LocalPort{
   668  				{Port: 5001},
   669  				{Port: 5002},
   670  				{Port: 5003},
   671  			},
   672  			expectToBeClose: []bool{false, false, false},
   673  		},
   674  		{
   675  			replacementPorts: []netutils.LocalPort{
   676  				{Port: 5001},
   677  				{Port: 5002},
   678  				{Port: 5003},
   679  			},
   680  			existingPorts: []netutils.LocalPort{
   681  				{Port: 5001},
   682  				{Port: 5003},
   683  			},
   684  			expectToBeClose: []bool{false, true, false},
   685  		},
   686  		{
   687  			replacementPorts: []netutils.LocalPort{
   688  				{Port: 5001},
   689  				{Port: 5002},
   690  				{Port: 5003},
   691  			},
   692  			existingPorts: []netutils.LocalPort{
   693  				{Port: 5001},
   694  				{Port: 5002},
   695  				{Port: 5003},
   696  				{Port: 5004},
   697  			},
   698  			expectToBeClose: []bool{false, false, false},
   699  		},
   700  	}
   701  
   702  	for i, tc := range testCases {
   703  		replacementPortsMap := make(map[netutils.LocalPort]netutils.Closeable)
   704  		for _, lp := range tc.replacementPorts {
   705  			replacementPortsMap[lp] = &fakeClosable{}
   706  		}
   707  		existingPortsMap := make(map[netutils.LocalPort]netutils.Closeable)
   708  		for _, lp := range tc.existingPorts {
   709  			existingPortsMap[lp] = &fakeClosable{}
   710  		}
   711  		RevertPorts(replacementPortsMap, existingPortsMap)
   712  		for j, expectation := range tc.expectToBeClose {
   713  			if replacementPortsMap[tc.replacementPorts[j]].(*fakeClosable).closed != expectation {
   714  				t.Errorf("Expect replacement localport %v to be %v in test case %v", tc.replacementPorts[j], expectation, i)
   715  			}
   716  		}
   717  		for _, lp := range tc.existingPorts {
   718  			if existingPortsMap[lp].(*fakeClosable).closed {
   719  				t.Errorf("Expect existing localport %v to be false in test case %v", lp, i)
   720  			}
   721  		}
   722  	}
   723  }
   724  
   725  func mustParseIPAddr(str string) net.Addr {
   726  	a, err := net.ResolveIPAddr("ip", str)
   727  	if err != nil {
   728  		panic("mustParseIPAddr")
   729  	}
   730  	return a
   731  }
   732  func mustParseIPNet(str string) net.Addr {
   733  	_, n, err := netutils.ParseCIDRSloppy(str)
   734  	if err != nil {
   735  		panic("mustParseIPNet")
   736  	}
   737  	return n
   738  }
   739  func mustParseUnix(str string) net.Addr {
   740  	n, err := net.ResolveUnixAddr("unix", str)
   741  	if err != nil {
   742  		panic("mustParseUnix")
   743  	}
   744  	return n
   745  }
   746  
   747  type cidrValidator struct {
   748  	cidr *net.IPNet
   749  }
   750  
   751  func (v *cidrValidator) isValid(ip net.IP) bool {
   752  	return v.cidr.Contains(ip)
   753  }
   754  func newCidrValidator(cidr string) func(ip net.IP) bool {
   755  	_, n, err := netutils.ParseCIDRSloppy(cidr)
   756  	if err != nil {
   757  		panic("mustParseIPNet")
   758  	}
   759  	obj := cidrValidator{n}
   760  	return obj.isValid
   761  }
   762  
   763  func TestAddressSet(t *testing.T) {
   764  	testCases := []struct {
   765  		name      string
   766  		validator func(ip net.IP) bool
   767  		input     []net.Addr
   768  		expected  sets.Set[string]
   769  	}{
   770  		{
   771  			"Empty",
   772  			func(ip net.IP) bool { return false },
   773  			nil,
   774  			nil,
   775  		},
   776  		{
   777  			"Reject IPAddr x 2",
   778  			func(ip net.IP) bool { return false },
   779  			[]net.Addr{
   780  				mustParseIPAddr("8.8.8.8"),
   781  				mustParseIPAddr("1000::"),
   782  			},
   783  			nil,
   784  		},
   785  		{
   786  			"Accept IPAddr x 2",
   787  			func(ip net.IP) bool { return true },
   788  			[]net.Addr{
   789  				mustParseIPAddr("8.8.8.8"),
   790  				mustParseIPAddr("1000::"),
   791  			},
   792  			sets.New("8.8.8.8", "1000::"),
   793  		},
   794  		{
   795  			"Accept IPNet x 2",
   796  			func(ip net.IP) bool { return true },
   797  			[]net.Addr{
   798  				mustParseIPNet("8.8.8.8/32"),
   799  				mustParseIPNet("1000::/128"),
   800  			},
   801  			sets.New("8.8.8.8", "1000::"),
   802  		},
   803  		{
   804  			"Accept Unix x 2",
   805  			func(ip net.IP) bool { return true },
   806  			[]net.Addr{
   807  				mustParseUnix("/tmp/sock1"),
   808  				mustParseUnix("/tmp/sock2"),
   809  			},
   810  			nil,
   811  		},
   812  		{
   813  			"Cidr IPv4",
   814  			newCidrValidator("192.168.1.0/24"),
   815  			[]net.Addr{
   816  				mustParseIPAddr("8.8.8.8"),
   817  				mustParseIPAddr("1000::"),
   818  				mustParseIPAddr("192.168.1.1"),
   819  			},
   820  			sets.New("192.168.1.1"),
   821  		},
   822  		{
   823  			"Cidr IPv6",
   824  			newCidrValidator("1000::/64"),
   825  			[]net.Addr{
   826  				mustParseIPAddr("8.8.8.8"),
   827  				mustParseIPAddr("1000::"),
   828  				mustParseIPAddr("192.168.1.1"),
   829  			},
   830  			sets.New("1000::"),
   831  		},
   832  	}
   833  
   834  	for _, tc := range testCases {
   835  		if !tc.expected.Equal(AddressSet(tc.validator, tc.input)) {
   836  			t.Errorf("%s", tc.name)
   837  		}
   838  	}
   839  }
   840  
   841  func TestIsZeroCIDR(t *testing.T) {
   842  	testCases := []struct {
   843  		name     string
   844  		input    string
   845  		expected bool
   846  	}{
   847  		{
   848  			name:     "invalide cidr",
   849  			input:    "",
   850  			expected: false,
   851  		},
   852  		{
   853  			name:     "ipv4 cidr",
   854  			input:    "172.10.0.0/16",
   855  			expected: false,
   856  		},
   857  		{
   858  			name:     "ipv4 zero cidr",
   859  			input:    IPv4ZeroCIDR,
   860  			expected: true,
   861  		},
   862  		{
   863  			name:     "ipv6 cidr",
   864  			input:    "::/128",
   865  			expected: false,
   866  		},
   867  		{
   868  			name:     "ipv6 zero cidr",
   869  			input:    IPv6ZeroCIDR,
   870  			expected: true,
   871  		},
   872  	}
   873  	for _, tc := range testCases {
   874  		t.Run(tc.name, func(t *testing.T) {
   875  			if got := IsZeroCIDR(tc.input); tc.expected != got {
   876  				t.Errorf("IsZeroCIDR() = %t, want %t", got, tc.expected)
   877  			}
   878  		})
   879  	}
   880  }
   881  

View as plain text