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