diff --git a/pkg/composetransform/compose.go b/pkg/composetransform/compose.go index dc83915a0f..adfdc8a57c 100644 --- a/pkg/composetransform/compose.go +++ b/pkg/composetransform/compose.go @@ -40,12 +40,12 @@ func AddStackLabel(namespace Namespace, labels map[string]string) map[string]str return labels } -type networks map[string]composetypes.NetworkConfig +type networkMap map[string]composetypes.NetworkConfig // ConvertNetworks from the compose-file type to the engine API type func ConvertNetworks( namespace Namespace, - networks networks, + networks networkMap, servicesNetworks map[string]struct{}, ) (map[string]types.NetworkCreate, []string) { if networks == nil { diff --git a/pkg/composetransform/compose_test.go b/pkg/composetransform/compose_test.go index b09750e891..8ba78a9b70 100644 --- a/pkg/composetransform/compose_test.go +++ b/pkg/composetransform/compose_test.go @@ -28,7 +28,7 @@ func TestAddStackLabel(t *testing.T) { func TestConvertNetworks(t *testing.T) { namespace := Namespace{name: "foo"} - source := networks{ + source := networkMap{ "normal": composetypes.NetworkConfig{ Driver: "overlay", DriverOpts: map[string]string{ diff --git a/pkg/composetransform/service.go b/pkg/composetransform/service.go index 1946b21955..0a675001d4 100644 --- a/pkg/composetransform/service.go +++ b/pkg/composetransform/service.go @@ -127,7 +127,7 @@ func convertService( func convertServiceNetworks( networks map[string]*composetypes.ServiceNetworkConfig, - networkConfigs networks, + networkConfigs networkMap, namespace Namespace, name string, ) ([]swarm.NetworkAttachmentConfig, error) { @@ -144,7 +144,8 @@ func convertServiceNetworks( for networkName, network := range networks { networkConfig, ok := networkConfigs[networkName] if !ok { - return []swarm.NetworkAttachmentConfig{}, fmt.Errorf("invalid network: %s", networkName) + return []swarm.NetworkAttachmentConfig{}, fmt.Errorf( + "service %q references network %q, which is not declared", name, networkName) } var aliases []string if network != nil { @@ -181,7 +182,7 @@ func convertHealthcheck(healthcheck *composetypes.HealthCheckConfig) (*container ) if healthcheck.Disable { if len(healthcheck.Test) != 0 { - return nil, fmt.Errorf("command and disable key can't be set at the same time") + return nil, fmt.Errorf("test and disable can't be set at the same time") } return &container.HealthConfig{ Test: []string{"NONE"}, diff --git a/pkg/composetransform/service_test.go b/pkg/composetransform/service_test.go index 8d713c6ba8..b2e55f6c8d 100644 --- a/pkg/composetransform/service_test.go +++ b/pkg/composetransform/service_test.go @@ -1,17 +1,21 @@ package composetransform import ( + "sort" + "strings" "testing" + "time" + composetypes "github.com/aanand/compose-file/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/testutil/assert" ) func TestConvertRestartPolicyFromNone(t *testing.T) { policy, err := convertRestartPolicy("no", nil) - var expected *swarm.RestartPolicy assert.NilError(t, err) - assert.Equal(t, policy, expected) + assert.Equal(t, policy, (*swarm.RestartPolicy)(nil)) } func TestConvertRestartPolicyFromUnknown(t *testing.T) { @@ -38,3 +42,152 @@ func TestConvertRestartPolicyFromFailure(t *testing.T) { assert.NilError(t, err) assert.DeepEqual(t, policy, expected) } + +func TestConvertEnvironment(t *testing.T) { + source := map[string]string{ + "foo": "bar", + "key": "value", + } + env := convertEnvironment(source) + sort.Strings(env) + assert.DeepEqual(t, env, []string{"foo=bar", "key=value"}) +} + +func TestConvertResourcesFull(t *testing.T) { + source := composetypes.Resources{ + Limits: &composetypes.Resource{ + NanoCPUs: "0.003", + MemoryBytes: composetypes.UnitBytes(300000000), + }, + Reservations: &composetypes.Resource{ + NanoCPUs: "0.002", + MemoryBytes: composetypes.UnitBytes(200000000), + }, + } + resources, err := convertResources(source) + assert.NilError(t, err) + + expected := &swarm.ResourceRequirements{ + Limits: &swarm.Resources{ + NanoCPUs: 3000000, + MemoryBytes: 300000000, + }, + Reservations: &swarm.Resources{ + NanoCPUs: 2000000, + MemoryBytes: 200000000, + }, + } + assert.DeepEqual(t, resources, expected) +} + +func TestConvertHealthcheck(t *testing.T) { + retries := uint64(10) + source := &composetypes.HealthCheckConfig{ + Test: []string{"EXEC", "touch", "/foo"}, + Timeout: "30s", + Interval: "2ms", + Retries: &retries, + } + expected := &container.HealthConfig{ + Test: source.Test, + Timeout: 30 * time.Second, + Interval: 2 * time.Millisecond, + Retries: 10, + } + + healthcheck, err := convertHealthcheck(source) + assert.NilError(t, err) + assert.DeepEqual(t, healthcheck, expected) +} + +func TestConvertHealthcheckDisable(t *testing.T) { + source := &composetypes.HealthCheckConfig{Disable: true} + expected := &container.HealthConfig{ + Test: []string{"NONE"}, + } + + healthcheck, err := convertHealthcheck(source) + assert.NilError(t, err) + assert.DeepEqual(t, healthcheck, expected) +} + +func TestConvertHealthcheckDisableWithTest(t *testing.T) { + source := &composetypes.HealthCheckConfig{ + Disable: true, + Test: []string{"EXEC", "touch"}, + } + _, err := convertHealthcheck(source) + assert.Error(t, err, "test and disable can't be set") +} + +func TestConvertServiceNetworksOnlyDefault(t *testing.T) { + networkConfigs := networkMap{} + networks := map[string]*composetypes.ServiceNetworkConfig{} + + configs, err := convertServiceNetworks( + networks, networkConfigs, NewNamespace("foo"), "service") + + expected := []swarm.NetworkAttachmentConfig{ + { + Target: "foo_default", + Aliases: []string{"service"}, + }, + } + + assert.NilError(t, err) + assert.DeepEqual(t, configs, expected) +} + +func TestConvertServiceNetworks(t *testing.T) { + networkConfigs := networkMap{ + "front": composetypes.NetworkConfig{ + External: composetypes.External{ + External: true, + Name: "fronttier", + }, + }, + "back": composetypes.NetworkConfig{}, + } + networks := map[string]*composetypes.ServiceNetworkConfig{ + "front": { + Aliases: []string{"something"}, + }, + "back": { + Aliases: []string{"other"}, + }, + } + + configs, err := convertServiceNetworks( + networks, networkConfigs, NewNamespace("foo"), "service") + + expected := []swarm.NetworkAttachmentConfig{ + { + Target: "foo_back", + Aliases: []string{"other", "service"}, + }, + { + Target: "fronttier", + Aliases: []string{"something", "service"}, + }, + } + + sortedConfigs := byTargetSort(configs) + sort.Sort(&sortedConfigs) + + assert.NilError(t, err) + assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected) +} + +type byTargetSort []swarm.NetworkAttachmentConfig + +func (s byTargetSort) Len() int { + return len(s) +} + +func (s byTargetSort) Less(i, j int) bool { + return strings.Compare(s[i].Target, s[j].Target) < 0 +} + +func (s byTargetSort) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} diff --git a/pkg/composetransform/volume_test.go b/pkg/composetransform/volume_test.go index fd5a2a84b3..1b3f056058 100644 --- a/pkg/composetransform/volume_test.go +++ b/pkg/composetransform/volume_test.go @@ -23,15 +23,15 @@ func TestIsNoCopy(t *testing.T) { assert.Equal(t, isNoCopy([]string{"foo", "rw"}), false) } -func TesTGetBindOptions(t *testing.T) { +func TestGetBindOptions(t *testing.T) { opts := getBindOptions([]string{"slave"}) - expected := &mount.BindOptions{Propagation: mount.PropagationSlave} - assert.Equal(t, opts, expected) + expected := mount.BindOptions{Propagation: mount.PropagationSlave} + assert.Equal(t, *opts, expected) } -func TesTGetBindOptionsNone(t *testing.T) { +func TestGetBindOptionsNone(t *testing.T) { opts := getBindOptions([]string{"ro"}) - assert.Equal(t, opts, nil) + assert.Equal(t, opts, (*mount.BindOptions)(nil)) } func TestConvertVolumeToMountNamedVolume(t *testing.T) {