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 }