github.com/moby/docker@v26.1.3+incompatible/api/types/network/endpoint_test.go (about)

     1  package network
     2  
     3  import (
     4  	"net"
     5  	"testing"
     6  
     7  	"gotest.tools/v3/assert"
     8  	is "gotest.tools/v3/assert/cmp"
     9  )
    10  
    11  type subnetStub struct {
    12  	static   bool
    13  	contains map[string]bool
    14  }
    15  
    16  func (stub subnetStub) IsStatic() bool {
    17  	return stub.static
    18  }
    19  
    20  func (stub subnetStub) Contains(addr net.IP) bool {
    21  	v, ok := stub.contains[addr.String()]
    22  	return ok && v
    23  }
    24  
    25  func TestEndpointIPAMConfigWithOutOfRangeAddrs(t *testing.T) {
    26  	testcases := []struct {
    27  		name           string
    28  		ipamConfig     *EndpointIPAMConfig
    29  		v4Subnets      []NetworkSubnet
    30  		v6Subnets      []NetworkSubnet
    31  		expectedErrors []string
    32  	}{
    33  		{
    34  			name: "valid config",
    35  			ipamConfig: &EndpointIPAMConfig{
    36  				IPv4Address:  "192.168.100.10",
    37  				IPv6Address:  "2a01:d2:af:420b:25c1:1816:bb33:855c",
    38  				LinkLocalIPs: []string{"169.254.169.254", "fe80::42:a8ff:fe33:6230"},
    39  			},
    40  			v4Subnets: []NetworkSubnet{
    41  				subnetStub{static: true, contains: map[string]bool{"192.168.100.10": true}},
    42  			},
    43  			v6Subnets: []NetworkSubnet{
    44  				subnetStub{static: true, contains: map[string]bool{"2a01:d2:af:420b:25c1:1816:bb33:855c": true}},
    45  			},
    46  		},
    47  		{
    48  			name: "static addresses out of range",
    49  			ipamConfig: &EndpointIPAMConfig{
    50  				IPv4Address: "192.168.100.10",
    51  				IPv6Address: "2a01:d2:af:420b:25c1:1816:bb33:855c",
    52  			},
    53  			v4Subnets: []NetworkSubnet{
    54  				subnetStub{static: true, contains: map[string]bool{"192.168.100.10": false}},
    55  			},
    56  			v6Subnets: []NetworkSubnet{
    57  				subnetStub{static: true, contains: map[string]bool{"2a01:d2:af:420b:25c1:1816:bb33:855c": false}},
    58  			},
    59  			expectedErrors: []string{
    60  				"no configured subnet or ip-range contain the IP address 192.168.100.10",
    61  				"no configured subnet or ip-range contain the IP address 2a01:d2:af:420b:25c1:1816:bb33:855c",
    62  			},
    63  		},
    64  		{
    65  			name: "static addresses with dynamic network subnets",
    66  			ipamConfig: &EndpointIPAMConfig{
    67  				IPv4Address: "192.168.100.10",
    68  				IPv6Address: "2a01:d2:af:420b:25c1:1816:bb33:855c",
    69  			},
    70  			v4Subnets: []NetworkSubnet{
    71  				subnetStub{static: false},
    72  			},
    73  			v6Subnets: []NetworkSubnet{
    74  				subnetStub{static: false},
    75  			},
    76  			expectedErrors: []string{
    77  				"user specified IP address is supported only when connecting to networks with user configured subnets",
    78  				"user specified IP address is supported only when connecting to networks with user configured subnets",
    79  			},
    80  		},
    81  	}
    82  
    83  	for _, tc := range testcases {
    84  		tc := tc
    85  		t.Run(tc.name, func(t *testing.T) {
    86  			t.Parallel()
    87  
    88  			err := tc.ipamConfig.IsInRange(tc.v4Subnets, tc.v6Subnets)
    89  			if tc.expectedErrors == nil {
    90  				assert.NilError(t, err)
    91  				return
    92  			}
    93  
    94  			if _, ok := err.(interface{ Unwrap() []error }); !ok {
    95  				t.Fatal("returned error isn't a multierror")
    96  			}
    97  			errs := err.(interface{ Unwrap() []error }).Unwrap()
    98  			assert.Check(t, len(errs) == len(tc.expectedErrors), "errs: %+v", errs)
    99  
   100  			for _, expected := range tc.expectedErrors {
   101  				assert.Check(t, is.ErrorContains(err, expected))
   102  			}
   103  		})
   104  	}
   105  
   106  }
   107  
   108  func TestEndpointIPAMConfigWithInvalidConfig(t *testing.T) {
   109  	testcases := []struct {
   110  		name           string
   111  		ipamConfig     *EndpointIPAMConfig
   112  		expectedErrors []string
   113  	}{
   114  		{
   115  			name: "valid config",
   116  			ipamConfig: &EndpointIPAMConfig{
   117  				IPv4Address:  "192.168.100.10",
   118  				IPv6Address:  "2a01:d2:af:420b:25c1:1816:bb33:855c",
   119  				LinkLocalIPs: []string{"169.254.169.254", "fe80::42:a8ff:fe33:6230"},
   120  			},
   121  		},
   122  		{
   123  			name: "invalid IP addresses",
   124  			ipamConfig: &EndpointIPAMConfig{
   125  				IPv4Address:  "foo",
   126  				IPv6Address:  "bar",
   127  				LinkLocalIPs: []string{"baz", "foobar"},
   128  			},
   129  			expectedErrors: []string{
   130  				"invalid IPv4 address: foo",
   131  				"invalid IPv6 address: bar",
   132  				"invalid link-local IP address: baz",
   133  				"invalid link-local IP address: foobar",
   134  			},
   135  		},
   136  		{
   137  			name:       "ipv6 address with a zone",
   138  			ipamConfig: &EndpointIPAMConfig{IPv6Address: "fe80::1cc0:3e8c:119f:c2e1%ens18"},
   139  			expectedErrors: []string{
   140  				"invalid IPv6 address: fe80::1cc0:3e8c:119f:c2e1%ens18",
   141  			},
   142  		},
   143  		{
   144  			name: "unspecified address is invalid",
   145  			ipamConfig: &EndpointIPAMConfig{
   146  				IPv4Address:  "0.0.0.0",
   147  				IPv6Address:  "::",
   148  				LinkLocalIPs: []string{"0.0.0.0", "::"},
   149  			},
   150  			expectedErrors: []string{
   151  				"invalid IPv4 address: 0.0.0.0",
   152  				"invalid IPv6 address: ::",
   153  				"invalid link-local IP address: 0.0.0.0",
   154  				"invalid link-local IP address: ::",
   155  			},
   156  		},
   157  		{
   158  			name: "empty link-local",
   159  			ipamConfig: &EndpointIPAMConfig{
   160  				LinkLocalIPs: []string{""},
   161  			},
   162  			expectedErrors: []string{"invalid link-local IP address:"},
   163  		},
   164  	}
   165  
   166  	for _, tc := range testcases {
   167  		tc := tc
   168  		t.Run(tc.name, func(t *testing.T) {
   169  			t.Parallel()
   170  
   171  			err := tc.ipamConfig.Validate()
   172  			if tc.expectedErrors == nil {
   173  				assert.NilError(t, err)
   174  				return
   175  			}
   176  
   177  			if _, ok := err.(interface{ Unwrap() []error }); !ok {
   178  				t.Fatal("returned error isn't a multierror")
   179  			}
   180  			errs := err.(interface{ Unwrap() []error }).Unwrap()
   181  			assert.Check(t, len(errs) == len(tc.expectedErrors), "errs: %+v", errs)
   182  
   183  			for _, expected := range tc.expectedErrors {
   184  				assert.Check(t, is.ErrorContains(err, expected))
   185  			}
   186  		})
   187  	}
   188  }