github.com/click2cloud/libcompose@v0.4.1-0.20170816121048-7c20f79ac6b9/docker/network/network_test.go (about)

     1  package network
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"golang.org/x/net/context"
     8  
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/network"
    11  	"github.com/docker/docker/client"
    12  	"github.com/Click2Cloud/libcompose/config"
    13  	"github.com/Click2Cloud/libcompose/test"
    14  	"github.com/Click2Cloud/libcompose/yaml"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  type networkNotFound struct {
    19  	network string
    20  }
    21  
    22  func (e networkNotFound) Error() string {
    23  	return fmt.Sprintf("network %s not found", e.network)
    24  }
    25  
    26  func (e networkNotFound) NotFound() bool {
    27  	return true
    28  }
    29  
    30  func TestNetworksFromServices(t *testing.T) {
    31  	cases := []struct {
    32  		networkConfigs   map[string]*config.NetworkConfig
    33  		services         map[string]*config.ServiceConfig
    34  		networkEnabled   bool
    35  		expectedNetworks []*Network
    36  		expectedError    bool
    37  	}{
    38  		{
    39  			expectedNetworks: []*Network{
    40  				{
    41  					name:        "default",
    42  					projectName: "prj",
    43  				},
    44  			},
    45  		},
    46  		{
    47  			networkConfigs: map[string]*config.NetworkConfig{
    48  				"net1": {},
    49  			},
    50  			services: map[string]*config.ServiceConfig{},
    51  			expectedNetworks: []*Network{
    52  				{
    53  					name:        "net1",
    54  					projectName: "prj",
    55  				},
    56  			},
    57  			expectedError: true,
    58  		},
    59  		{
    60  			networkConfigs: map[string]*config.NetworkConfig{
    61  				"net1": {},
    62  				"net2": {},
    63  			},
    64  			services: map[string]*config.ServiceConfig{
    65  				"svc1": {
    66  					Networks: &yaml.Networks{
    67  						Networks: []*yaml.Network{
    68  							{
    69  								Name: "net1",
    70  							},
    71  						},
    72  					},
    73  				},
    74  			},
    75  			expectedNetworks: []*Network{
    76  				{
    77  					name:        "default",
    78  					projectName: "prj",
    79  				},
    80  				{
    81  					name:        "net1",
    82  					projectName: "prj",
    83  				},
    84  				{
    85  					name:        "net2",
    86  					projectName: "prj",
    87  				},
    88  			},
    89  			expectedError: true,
    90  		},
    91  		{
    92  			networkConfigs: map[string]*config.NetworkConfig{
    93  				"net1": {},
    94  				"net2": {},
    95  			},
    96  			services: map[string]*config.ServiceConfig{
    97  				"svc1": {
    98  					Networks: &yaml.Networks{
    99  						Networks: []*yaml.Network{
   100  							{
   101  								Name: "net1",
   102  							},
   103  						},
   104  					},
   105  				},
   106  				"svc2": {
   107  					Networks: &yaml.Networks{
   108  						Networks: []*yaml.Network{
   109  							{
   110  								Name: "net1",
   111  							},
   112  							{
   113  								Name: "net2",
   114  							},
   115  						},
   116  					},
   117  				},
   118  			},
   119  			expectedNetworks: []*Network{
   120  				{
   121  					name:        "net1",
   122  					projectName: "prj",
   123  				},
   124  				{
   125  					name:        "net2",
   126  					projectName: "prj",
   127  				},
   128  			},
   129  			expectedError: false,
   130  		},
   131  		{
   132  			networkConfigs: map[string]*config.NetworkConfig{
   133  				"net1": {},
   134  				"net2": {},
   135  			},
   136  			services: map[string]*config.ServiceConfig{
   137  				"svc1": {
   138  					Networks: &yaml.Networks{
   139  						Networks: []*yaml.Network{
   140  							{
   141  								Name: "net1",
   142  							},
   143  						},
   144  					},
   145  				},
   146  				"svc2": {
   147  					Networks: &yaml.Networks{
   148  						Networks: []*yaml.Network{
   149  							{
   150  								Name: "net1",
   151  							},
   152  							{
   153  								Name: "net2",
   154  							},
   155  						},
   156  					},
   157  				},
   158  				"svc3": {
   159  					NetworkMode: "host",
   160  					Networks: &yaml.Networks{
   161  						Networks: []*yaml.Network{
   162  							{
   163  								Name: "net3",
   164  							},
   165  						},
   166  					},
   167  				},
   168  			},
   169  			expectedNetworks: []*Network{
   170  				{
   171  					name:        "net1",
   172  					projectName: "prj",
   173  				},
   174  				{
   175  					name:        "net2",
   176  					projectName: "prj",
   177  				},
   178  			},
   179  			expectedError: false,
   180  		},
   181  	}
   182  	for index, c := range cases {
   183  		services := config.NewServiceConfigs()
   184  		for name, service := range c.services {
   185  			services.Add(name, service)
   186  		}
   187  		networks, err := NetworksFromServices(&networkClient{}, "prj", c.networkConfigs, services, c.networkEnabled)
   188  		if c.expectedError {
   189  			if err == nil {
   190  				t.Fatalf("%d: expected an error, got nothing", index)
   191  			}
   192  		} else {
   193  			if err != nil {
   194  				t.Fatalf("%d: didn't expect an error, got one %s", index, err.Error())
   195  			}
   196  			if networks.networkEnabled != c.networkEnabled {
   197  				t.Fatalf("%d: expected network enabled %v, got %v", index, c.networkEnabled, networks.networkEnabled)
   198  			}
   199  			if len(networks.networks) != len(c.expectedNetworks) {
   200  				t.Fatalf("%d: expected %v, got %v", index, c.expectedNetworks, networks.networks)
   201  			}
   202  			for _, network := range networks.networks {
   203  				testExpectedContainsNetwork(t, index, c.expectedNetworks, network)
   204  			}
   205  		}
   206  	}
   207  }
   208  
   209  func testExpectedContainsNetwork(t *testing.T, index int, expected []*Network, network *Network) {
   210  	found := false
   211  	for _, e := range expected {
   212  		if e.name == network.name && e.projectName == network.projectName {
   213  			found = true
   214  			break
   215  		}
   216  	}
   217  	if !found {
   218  		t.Fatalf("%d: network %v not found in %v", index, network, expected)
   219  	}
   220  }
   221  
   222  type networkClient struct {
   223  	client.Client
   224  	expectedNetworkCreate   types.NetworkCreate
   225  	expectedRemoveNetworkID string
   226  	expectedName            string
   227  	inspectError            error
   228  	inspectNetworkDriver    string
   229  	inspectNetworkOptions   map[string]string
   230  	removeError             error
   231  }
   232  
   233  func (c *networkClient) NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error) {
   234  	if c.inspectError != nil {
   235  		return types.NetworkResource{}, c.inspectError
   236  	}
   237  	return types.NetworkResource{
   238  		ID:      "network_id",
   239  		Driver:  c.inspectNetworkDriver,
   240  		Options: c.inspectNetworkOptions,
   241  	}, nil
   242  }
   243  
   244  func (c *networkClient) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) {
   245  	if c.expectedName != "" {
   246  		if options.Driver != c.expectedNetworkCreate.Driver {
   247  			return types.NetworkCreateResponse{}, fmt.Errorf("Invalid network create, expected driver %q, got %q", c.expectedNetworkCreate.Driver, options.Driver)
   248  		}
   249  		if c.expectedNetworkCreate.IPAM != nil && options.IPAM.Driver != c.expectedNetworkCreate.IPAM.Driver {
   250  			return types.NetworkCreateResponse{}, fmt.Errorf("Invalid network create, expected ipam %q, got %q", c.expectedNetworkCreate.IPAM, options.IPAM)
   251  		}
   252  		if c.expectedNetworkCreate.IPAM != nil && len(options.IPAM.Config) != len(c.expectedNetworkCreate.IPAM.Config) {
   253  			return types.NetworkCreateResponse{}, fmt.Errorf("Invalid network create, expected ipam %q, got %q", c.expectedNetworkCreate.Driver, options.Driver)
   254  		}
   255  		return types.NetworkCreateResponse{
   256  			ID: c.expectedName,
   257  		}, nil
   258  	}
   259  	return types.NetworkCreateResponse{}, errors.New("Engine no longer exists")
   260  }
   261  
   262  func (c *networkClient) NetworkRemove(ctx context.Context, networkID string) error {
   263  	if c.expectedRemoveNetworkID != "" {
   264  		if networkID != c.expectedRemoveNetworkID {
   265  			return fmt.Errorf("Invalid network id for removing, expected %q, got %q", c.expectedRemoveNetworkID, networkID)
   266  		}
   267  		return nil
   268  	}
   269  	return errors.New("Engine no longer exists")
   270  }
   271  
   272  func TestNetworksInitialize(t *testing.T) {
   273  	errorCases := []struct {
   274  		networkEnabled        bool
   275  		network               *Network
   276  		inspectError          error
   277  		inspectNetworkDriver  string
   278  		inspectNetworkOptions map[string]string
   279  		expectedNetworkCreate types.NetworkCreate
   280  		expectedName          string
   281  	}{
   282  		// NetworkNotEnabled, never an error
   283  		{
   284  			networkEnabled: false,
   285  			network: &Network{
   286  				name:   "net1",
   287  				driver: "driver1",
   288  			},
   289  			inspectError: networkNotFound{
   290  				network: "net1",
   291  			},
   292  		},
   293  		// External
   294  		{
   295  			networkEnabled: true,
   296  			network: &Network{
   297  				name:     "net1",
   298  				external: true,
   299  			},
   300  		},
   301  		// NotFound, will create a new one
   302  		{
   303  			networkEnabled: true,
   304  			network: &Network{
   305  				name:   "net1",
   306  				driver: "driver1",
   307  			},
   308  			inspectError: networkNotFound{
   309  				network: "net1",
   310  			},
   311  			expectedName: "net1",
   312  			expectedNetworkCreate: types.NetworkCreate{
   313  				Driver: "driver1",
   314  			},
   315  		},
   316  		// NotFound, will create a new one
   317  		// with IPAM
   318  		{
   319  			networkEnabled: true,
   320  			network: &Network{
   321  				name:   "net1",
   322  				driver: "driver1",
   323  				ipam: config.Ipam{
   324  					Driver: "ipamDriver",
   325  					Config: []config.IpamConfig{
   326  						{
   327  							Subnet:  "subnet",
   328  							IPRange: "iprange",
   329  						},
   330  					},
   331  				},
   332  			},
   333  			inspectError: networkNotFound{
   334  				network: "net1",
   335  			},
   336  			expectedName: "net1",
   337  			expectedNetworkCreate: types.NetworkCreate{
   338  				Driver: "driver1",
   339  				IPAM: &network.IPAM{
   340  					Driver: "ipamDriver",
   341  					Config: []network.IPAMConfig{
   342  						{
   343  							Subnet:  "subnet",
   344  							IPRange: "iprange",
   345  						},
   346  					},
   347  				},
   348  			},
   349  		},
   350  		{
   351  			networkEnabled: true,
   352  			network: &Network{
   353  				name:   "net1",
   354  				driver: "driver1",
   355  			},
   356  			inspectNetworkDriver: "driver1",
   357  		},
   358  		{
   359  			networkEnabled: true,
   360  			network: &Network{
   361  				name:   "net1",
   362  				driver: "driver1",
   363  				driverOptions: map[string]string{
   364  					"key1": "value1",
   365  					"key2": "value2",
   366  				},
   367  			},
   368  			inspectNetworkDriver: "driver1",
   369  			inspectNetworkOptions: map[string]string{
   370  				"key1": "value1",
   371  				"key2": "value2",
   372  			},
   373  		},
   374  	}
   375  	for _, e := range errorCases {
   376  		cli := &networkClient{
   377  			expectedName:          e.expectedName,
   378  			expectedNetworkCreate: e.expectedNetworkCreate,
   379  			inspectError:          e.inspectError,
   380  			inspectNetworkDriver:  e.inspectNetworkDriver,
   381  			inspectNetworkOptions: e.inspectNetworkOptions,
   382  		}
   383  		e.network.client = cli
   384  		networks := &Networks{
   385  			networkEnabled: e.networkEnabled,
   386  			networks: []*Network{
   387  				e.network,
   388  			},
   389  		}
   390  		err := networks.Initialize(context.Background())
   391  		if err != nil {
   392  			t.Error(err)
   393  		}
   394  	}
   395  }
   396  
   397  func TestNetworksInitializeErrors(t *testing.T) {
   398  	errorCases := []struct {
   399  		network               *Network
   400  		inspectError          error
   401  		inspectNetworkDriver  string
   402  		inspectNetworkOptions map[string]string
   403  		expectedNetworkCreate types.NetworkCreate
   404  		expectedName          string
   405  		expectedError         string
   406  	}{
   407  		{
   408  			network: &Network{
   409  				projectName: "prj",
   410  				name:        "net1",
   411  			},
   412  			inspectError:  fmt.Errorf("any error"),
   413  			expectedError: "any error",
   414  		},
   415  		{
   416  			network: &Network{
   417  				projectName: "prj",
   418  				name:        "net1",
   419  				external:    true,
   420  			},
   421  			inspectError: networkNotFound{
   422  				network: "net1",
   423  			},
   424  			expectedError: "Network net1 declared as external, but could not be found. Please create the network manually using docker network create net1 and try again",
   425  		},
   426  		{
   427  			network: &Network{
   428  				projectName: "prj",
   429  				name:        "net1",
   430  			},
   431  			inspectError: networkNotFound{
   432  				network: "net1",
   433  			},
   434  			expectedError: "Engine no longer exists", // default error
   435  		},
   436  		{
   437  			network: &Network{
   438  				projectName: "prj",
   439  				name:        "net1",
   440  				driver:      "driver1",
   441  			},
   442  			inspectNetworkDriver: "driver2",
   443  			expectedError:        `Network "prj_net1" needs to be recreated - driver has changed`,
   444  		},
   445  		{
   446  			network: &Network{
   447  				projectName: "prj",
   448  				name:        "net1",
   449  				driver:      "driver1",
   450  				driverOptions: map[string]string{
   451  					"key1": "value1",
   452  					"key2": "value2",
   453  				},
   454  			},
   455  			inspectNetworkDriver: "driver1",
   456  			inspectNetworkOptions: map[string]string{
   457  				"key1": "value1",
   458  				"key2": "anothervalue",
   459  			},
   460  			expectedError: `Network "prj_net1" needs to be recreated - options have changed`,
   461  		},
   462  	}
   463  	for index, e := range errorCases {
   464  		cli := &networkClient{
   465  			expectedName:          e.expectedName,
   466  			expectedNetworkCreate: e.expectedNetworkCreate,
   467  			inspectError:          e.inspectError,
   468  			inspectNetworkDriver:  e.inspectNetworkDriver,
   469  			inspectNetworkOptions: e.inspectNetworkOptions,
   470  		}
   471  		e.network.client = cli
   472  		networks := &Networks{
   473  			networkEnabled: true,
   474  			networks: []*Network{
   475  				e.network,
   476  			},
   477  		}
   478  		err := networks.Initialize(context.Background())
   479  		if err == nil || err.Error() != e.expectedError {
   480  			t.Errorf("%d: expected an error %v, got %v", index, e.expectedError, err)
   481  		}
   482  	}
   483  }
   484  
   485  func TestNetworksRemove(t *testing.T) {
   486  	removeCases := []struct {
   487  		networkEnabled          bool
   488  		expectedRemoveNetworkID string
   489  		network                 *Network
   490  	}{
   491  		// Network not enabled, always no error
   492  		{
   493  			networkEnabled: false,
   494  			network: &Network{
   495  				projectName: "prj",
   496  				name:        "net1",
   497  				driver:      "driver1",
   498  			},
   499  		},
   500  		// Network enabled
   501  		{
   502  			networkEnabled:          true,
   503  			expectedRemoveNetworkID: "prj_net1",
   504  			network: &Network{
   505  				projectName: "prj",
   506  				name:        "net1",
   507  				driver:      "driver1",
   508  			},
   509  		},
   510  	}
   511  	for _, c := range removeCases {
   512  		cli := &networkClient{
   513  			expectedRemoveNetworkID: c.expectedRemoveNetworkID,
   514  		}
   515  		c.network.client = cli
   516  		networks := &Networks{
   517  			networkEnabled: c.networkEnabled,
   518  			networks: []*Network{
   519  				c.network,
   520  			},
   521  		}
   522  		err := networks.Remove(context.Background())
   523  		if err != nil {
   524  			t.Error(err)
   525  		}
   526  	}
   527  }
   528  
   529  func TestNetworksRemoveErrors(t *testing.T) {
   530  	cli := &networkClient{}
   531  	networks := &Networks{
   532  		networkEnabled: true,
   533  		networks: []*Network{
   534  			{
   535  				client:      cli,
   536  				projectName: "prj",
   537  				name:        "net1",
   538  			},
   539  		},
   540  	}
   541  	err := networks.Remove(context.Background())
   542  	if err == nil {
   543  		t.Errorf("Expected a error, got nothing.")
   544  	}
   545  }