github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/compose/convert/service_test.go (about)

     1  package convert
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"sort"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	composetypes "github.com/docker/cli/cli/compose/types"
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/container"
    14  	"github.com/docker/docker/api/types/swarm"
    15  	"github.com/docker/docker/client"
    16  	"github.com/pkg/errors"
    17  	"gotest.tools/assert"
    18  	is "gotest.tools/assert/cmp"
    19  )
    20  
    21  func TestConvertRestartPolicyFromNone(t *testing.T) {
    22  	policy, err := convertRestartPolicy("no", nil)
    23  	assert.NilError(t, err)
    24  	assert.Check(t, is.DeepEqual((*swarm.RestartPolicy)(nil), policy))
    25  }
    26  
    27  func TestConvertRestartPolicyFromUnknown(t *testing.T) {
    28  	_, err := convertRestartPolicy("unknown", nil)
    29  	assert.Error(t, err, "unknown restart policy: unknown")
    30  }
    31  
    32  func TestConvertRestartPolicyFromAlways(t *testing.T) {
    33  	policy, err := convertRestartPolicy("always", nil)
    34  	expected := &swarm.RestartPolicy{
    35  		Condition: swarm.RestartPolicyConditionAny,
    36  	}
    37  	assert.NilError(t, err)
    38  	assert.Check(t, is.DeepEqual(expected, policy))
    39  }
    40  
    41  func TestConvertRestartPolicyFromFailure(t *testing.T) {
    42  	policy, err := convertRestartPolicy("on-failure:4", nil)
    43  	attempts := uint64(4)
    44  	expected := &swarm.RestartPolicy{
    45  		Condition:   swarm.RestartPolicyConditionOnFailure,
    46  		MaxAttempts: &attempts,
    47  	}
    48  	assert.NilError(t, err)
    49  	assert.Check(t, is.DeepEqual(expected, policy))
    50  }
    51  
    52  func strPtr(val string) *string {
    53  	return &val
    54  }
    55  
    56  func TestConvertEnvironment(t *testing.T) {
    57  	source := map[string]*string{
    58  		"foo": strPtr("bar"),
    59  		"key": strPtr("value"),
    60  	}
    61  	env := convertEnvironment(source)
    62  	sort.Strings(env)
    63  	assert.Check(t, is.DeepEqual([]string{"foo=bar", "key=value"}, env))
    64  }
    65  
    66  func TestConvertExtraHosts(t *testing.T) {
    67  	source := composetypes.HostsList{
    68  		"zulu:127.0.0.2",
    69  		"alpha:127.0.0.1",
    70  		"zulu:ff02::1",
    71  	}
    72  	assert.Check(t, is.DeepEqual([]string{"127.0.0.2 zulu", "127.0.0.1 alpha", "ff02::1 zulu"}, convertExtraHosts(source)))
    73  }
    74  
    75  func TestConvertResourcesFull(t *testing.T) {
    76  	source := composetypes.Resources{
    77  		Limits: &composetypes.Resource{
    78  			NanoCPUs:    "0.003",
    79  			MemoryBytes: composetypes.UnitBytes(300000000),
    80  		},
    81  		Reservations: &composetypes.Resource{
    82  			NanoCPUs:    "0.002",
    83  			MemoryBytes: composetypes.UnitBytes(200000000),
    84  		},
    85  	}
    86  	resources, err := convertResources(source)
    87  	assert.NilError(t, err)
    88  
    89  	expected := &swarm.ResourceRequirements{
    90  		Limits: &swarm.Resources{
    91  			NanoCPUs:    3000000,
    92  			MemoryBytes: 300000000,
    93  		},
    94  		Reservations: &swarm.Resources{
    95  			NanoCPUs:    2000000,
    96  			MemoryBytes: 200000000,
    97  		},
    98  	}
    99  	assert.Check(t, is.DeepEqual(expected, resources))
   100  }
   101  
   102  func TestConvertResourcesOnlyMemory(t *testing.T) {
   103  	source := composetypes.Resources{
   104  		Limits: &composetypes.Resource{
   105  			MemoryBytes: composetypes.UnitBytes(300000000),
   106  		},
   107  		Reservations: &composetypes.Resource{
   108  			MemoryBytes: composetypes.UnitBytes(200000000),
   109  		},
   110  	}
   111  	resources, err := convertResources(source)
   112  	assert.NilError(t, err)
   113  
   114  	expected := &swarm.ResourceRequirements{
   115  		Limits: &swarm.Resources{
   116  			MemoryBytes: 300000000,
   117  		},
   118  		Reservations: &swarm.Resources{
   119  			MemoryBytes: 200000000,
   120  		},
   121  	}
   122  	assert.Check(t, is.DeepEqual(expected, resources))
   123  }
   124  
   125  func TestConvertHealthcheck(t *testing.T) {
   126  	retries := uint64(10)
   127  	timeout := composetypes.Duration(30 * time.Second)
   128  	interval := composetypes.Duration(2 * time.Millisecond)
   129  	source := &composetypes.HealthCheckConfig{
   130  		Test:     []string{"EXEC", "touch", "/foo"},
   131  		Timeout:  &timeout,
   132  		Interval: &interval,
   133  		Retries:  &retries,
   134  	}
   135  	expected := &container.HealthConfig{
   136  		Test:     source.Test,
   137  		Timeout:  time.Duration(timeout),
   138  		Interval: time.Duration(interval),
   139  		Retries:  10,
   140  	}
   141  
   142  	healthcheck, err := convertHealthcheck(source)
   143  	assert.NilError(t, err)
   144  	assert.Check(t, is.DeepEqual(expected, healthcheck))
   145  }
   146  
   147  func TestConvertHealthcheckDisable(t *testing.T) {
   148  	source := &composetypes.HealthCheckConfig{Disable: true}
   149  	expected := &container.HealthConfig{
   150  		Test: []string{"NONE"},
   151  	}
   152  
   153  	healthcheck, err := convertHealthcheck(source)
   154  	assert.NilError(t, err)
   155  	assert.Check(t, is.DeepEqual(expected, healthcheck))
   156  }
   157  
   158  func TestConvertHealthcheckDisableWithTest(t *testing.T) {
   159  	source := &composetypes.HealthCheckConfig{
   160  		Disable: true,
   161  		Test:    []string{"EXEC", "touch"},
   162  	}
   163  	_, err := convertHealthcheck(source)
   164  	assert.Error(t, err, "test and disable can't be set at the same time")
   165  }
   166  
   167  func TestConvertEndpointSpec(t *testing.T) {
   168  	source := []composetypes.ServicePortConfig{
   169  		{
   170  			Protocol:  "udp",
   171  			Target:    53,
   172  			Published: 1053,
   173  			Mode:      "host",
   174  		},
   175  		{
   176  			Target:    8080,
   177  			Published: 80,
   178  		},
   179  	}
   180  	endpoint, err := convertEndpointSpec("vip", source)
   181  
   182  	expected := swarm.EndpointSpec{
   183  		Mode: swarm.ResolutionMode(strings.ToLower("vip")),
   184  		Ports: []swarm.PortConfig{
   185  			{
   186  				TargetPort:    8080,
   187  				PublishedPort: 80,
   188  			},
   189  			{
   190  				Protocol:      "udp",
   191  				TargetPort:    53,
   192  				PublishedPort: 1053,
   193  				PublishMode:   "host",
   194  			},
   195  		},
   196  	}
   197  
   198  	assert.NilError(t, err)
   199  	assert.Check(t, is.DeepEqual(expected, *endpoint))
   200  }
   201  
   202  func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
   203  	networkConfigs := networkMap{}
   204  
   205  	configs, err := convertServiceNetworks(
   206  		nil, networkConfigs, NewNamespace("foo"), "service")
   207  
   208  	expected := []swarm.NetworkAttachmentConfig{
   209  		{
   210  			Target:  "foo_default",
   211  			Aliases: []string{"service"},
   212  		},
   213  	}
   214  
   215  	assert.NilError(t, err)
   216  	assert.Check(t, is.DeepEqual(expected, configs))
   217  }
   218  
   219  func TestConvertServiceNetworks(t *testing.T) {
   220  	networkConfigs := networkMap{
   221  		"front": composetypes.NetworkConfig{
   222  			External: composetypes.External{External: true},
   223  			Name:     "fronttier",
   224  		},
   225  		"back": composetypes.NetworkConfig{},
   226  	}
   227  	networks := map[string]*composetypes.ServiceNetworkConfig{
   228  		"front": {
   229  			Aliases: []string{"something"},
   230  		},
   231  		"back": {
   232  			Aliases: []string{"other"},
   233  		},
   234  	}
   235  
   236  	configs, err := convertServiceNetworks(
   237  		networks, networkConfigs, NewNamespace("foo"), "service")
   238  
   239  	expected := []swarm.NetworkAttachmentConfig{
   240  		{
   241  			Target:  "foo_back",
   242  			Aliases: []string{"other", "service"},
   243  		},
   244  		{
   245  			Target:  "fronttier",
   246  			Aliases: []string{"something", "service"},
   247  		},
   248  	}
   249  
   250  	assert.NilError(t, err)
   251  	assert.Check(t, is.DeepEqual(expected, configs))
   252  }
   253  
   254  func TestConvertServiceNetworksCustomDefault(t *testing.T) {
   255  	networkConfigs := networkMap{
   256  		"default": composetypes.NetworkConfig{
   257  			External: composetypes.External{External: true},
   258  			Name:     "custom",
   259  		},
   260  	}
   261  	networks := map[string]*composetypes.ServiceNetworkConfig{}
   262  
   263  	configs, err := convertServiceNetworks(
   264  		networks, networkConfigs, NewNamespace("foo"), "service")
   265  
   266  	expected := []swarm.NetworkAttachmentConfig{
   267  		{
   268  			Target:  "custom",
   269  			Aliases: []string{"service"},
   270  		},
   271  	}
   272  
   273  	assert.NilError(t, err)
   274  	assert.Check(t, is.DeepEqual(expected, []swarm.NetworkAttachmentConfig(configs)))
   275  }
   276  
   277  func TestConvertDNSConfigEmpty(t *testing.T) {
   278  	dnsConfig, err := convertDNSConfig(nil, nil)
   279  
   280  	assert.NilError(t, err)
   281  	assert.Check(t, is.DeepEqual((*swarm.DNSConfig)(nil), dnsConfig))
   282  }
   283  
   284  var (
   285  	nameservers = []string{"8.8.8.8", "9.9.9.9"}
   286  	search      = []string{"dc1.example.com", "dc2.example.com"}
   287  )
   288  
   289  func TestConvertDNSConfigAll(t *testing.T) {
   290  	dnsConfig, err := convertDNSConfig(nameservers, search)
   291  	assert.NilError(t, err)
   292  	assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
   293  		Nameservers: nameservers,
   294  		Search:      search,
   295  	}, dnsConfig))
   296  }
   297  
   298  func TestConvertDNSConfigNameservers(t *testing.T) {
   299  	dnsConfig, err := convertDNSConfig(nameservers, nil)
   300  	assert.NilError(t, err)
   301  	assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
   302  		Nameservers: nameservers,
   303  		Search:      nil,
   304  	}, dnsConfig))
   305  }
   306  
   307  func TestConvertDNSConfigSearch(t *testing.T) {
   308  	dnsConfig, err := convertDNSConfig(nil, search)
   309  	assert.NilError(t, err)
   310  	assert.Check(t, is.DeepEqual(&swarm.DNSConfig{
   311  		Nameservers: nil,
   312  		Search:      search,
   313  	}, dnsConfig))
   314  }
   315  
   316  func TestConvertCredentialSpec(t *testing.T) {
   317  	swarmSpec, err := convertCredentialSpec(composetypes.CredentialSpecConfig{})
   318  	assert.NilError(t, err)
   319  	assert.Check(t, is.Nil(swarmSpec))
   320  
   321  	swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
   322  		File: "/foo",
   323  	})
   324  	assert.NilError(t, err)
   325  	assert.Check(t, is.Equal(swarmSpec.File, "/foo"))
   326  	assert.Check(t, is.Equal(swarmSpec.Registry, ""))
   327  
   328  	swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
   329  		Registry: "foo",
   330  	})
   331  	assert.NilError(t, err)
   332  	assert.Check(t, is.Equal(swarmSpec.File, ""))
   333  	assert.Check(t, is.Equal(swarmSpec.Registry, "foo"))
   334  
   335  	swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
   336  		File:     "/asdf",
   337  		Registry: "foo",
   338  	})
   339  	assert.Check(t, is.ErrorContains(err, ""))
   340  	assert.Check(t, is.Nil(swarmSpec))
   341  }
   342  
   343  func TestConvertUpdateConfigOrder(t *testing.T) {
   344  	// test default behavior
   345  	updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
   346  	assert.Check(t, is.Equal("", updateConfig.Order))
   347  
   348  	// test start-first
   349  	updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
   350  		Order: "start-first",
   351  	})
   352  	assert.Check(t, is.Equal(updateConfig.Order, "start-first"))
   353  
   354  	// test stop-first
   355  	updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
   356  		Order: "stop-first",
   357  	})
   358  	assert.Check(t, is.Equal(updateConfig.Order, "stop-first"))
   359  }
   360  
   361  func TestConvertFileObject(t *testing.T) {
   362  	namespace := NewNamespace("testing")
   363  	config := composetypes.FileReferenceConfig{
   364  		Source: "source",
   365  		Target: "target",
   366  		UID:    "user",
   367  		GID:    "group",
   368  		Mode:   uint32Ptr(0644),
   369  	}
   370  	swarmRef, err := convertFileObject(namespace, config, lookupConfig)
   371  	assert.NilError(t, err)
   372  
   373  	expected := swarmReferenceObject{
   374  		Name: "testing_source",
   375  		File: swarmReferenceTarget{
   376  			Name: config.Target,
   377  			UID:  config.UID,
   378  			GID:  config.GID,
   379  			Mode: os.FileMode(0644),
   380  		},
   381  	}
   382  	assert.Check(t, is.DeepEqual(expected, swarmRef))
   383  }
   384  
   385  func lookupConfig(key string) (composetypes.FileObjectConfig, error) {
   386  	if key != "source" {
   387  		return composetypes.FileObjectConfig{}, errors.New("bad key")
   388  	}
   389  	return composetypes.FileObjectConfig{}, nil
   390  }
   391  
   392  func TestConvertFileObjectDefaults(t *testing.T) {
   393  	namespace := NewNamespace("testing")
   394  	config := composetypes.FileReferenceConfig{Source: "source"}
   395  	swarmRef, err := convertFileObject(namespace, config, lookupConfig)
   396  	assert.NilError(t, err)
   397  
   398  	expected := swarmReferenceObject{
   399  		Name: "testing_source",
   400  		File: swarmReferenceTarget{
   401  			Name: config.Source,
   402  			UID:  "0",
   403  			GID:  "0",
   404  			Mode: os.FileMode(0444),
   405  		},
   406  	}
   407  	assert.Check(t, is.DeepEqual(expected, swarmRef))
   408  }
   409  
   410  func TestServiceConvertsIsolation(t *testing.T) {
   411  	src := composetypes.ServiceConfig{
   412  		Isolation: "hyperv",
   413  	}
   414  	result, err := Service("1.35", Namespace{name: "foo"}, src, nil, nil, nil, nil)
   415  	assert.NilError(t, err)
   416  	assert.Check(t, is.Equal(container.IsolationHyperV, result.TaskTemplate.ContainerSpec.Isolation))
   417  }
   418  
   419  func TestConvertServiceSecrets(t *testing.T) {
   420  	namespace := Namespace{name: "foo"}
   421  	secrets := []composetypes.ServiceSecretConfig{
   422  		{Source: "foo_secret"},
   423  		{Source: "bar_secret"},
   424  	}
   425  	secretSpecs := map[string]composetypes.SecretConfig{
   426  		"foo_secret": {
   427  			Name: "foo_secret",
   428  		},
   429  		"bar_secret": {
   430  			Name: "bar_secret",
   431  		},
   432  	}
   433  	client := &fakeClient{
   434  		secretListFunc: func(opts types.SecretListOptions) ([]swarm.Secret, error) {
   435  			assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_secret"))
   436  			assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_secret"))
   437  			return []swarm.Secret{
   438  				{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "foo_secret"}}},
   439  				{Spec: swarm.SecretSpec{Annotations: swarm.Annotations{Name: "bar_secret"}}},
   440  			}, nil
   441  		},
   442  	}
   443  	refs, err := convertServiceSecrets(client, namespace, secrets, secretSpecs)
   444  	assert.NilError(t, err)
   445  	expected := []*swarm.SecretReference{
   446  		{
   447  			SecretName: "bar_secret",
   448  			File: &swarm.SecretReferenceFileTarget{
   449  				Name: "bar_secret",
   450  				UID:  "0",
   451  				GID:  "0",
   452  				Mode: 0444,
   453  			},
   454  		},
   455  		{
   456  			SecretName: "foo_secret",
   457  			File: &swarm.SecretReferenceFileTarget{
   458  				Name: "foo_secret",
   459  				UID:  "0",
   460  				GID:  "0",
   461  				Mode: 0444,
   462  			},
   463  		},
   464  	}
   465  	assert.DeepEqual(t, expected, refs)
   466  }
   467  
   468  func TestConvertServiceConfigs(t *testing.T) {
   469  	namespace := Namespace{name: "foo"}
   470  	configs := []composetypes.ServiceConfigObjConfig{
   471  		{Source: "foo_config"},
   472  		{Source: "bar_config"},
   473  	}
   474  	configSpecs := map[string]composetypes.ConfigObjConfig{
   475  		"foo_config": {
   476  			Name: "foo_config",
   477  		},
   478  		"bar_config": {
   479  			Name: "bar_config",
   480  		},
   481  	}
   482  	client := &fakeClient{
   483  		configListFunc: func(opts types.ConfigListOptions) ([]swarm.Config, error) {
   484  			assert.Check(t, is.Contains(opts.Filters.Get("name"), "foo_config"))
   485  			assert.Check(t, is.Contains(opts.Filters.Get("name"), "bar_config"))
   486  			return []swarm.Config{
   487  				{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "foo_config"}}},
   488  				{Spec: swarm.ConfigSpec{Annotations: swarm.Annotations{Name: "bar_config"}}},
   489  			}, nil
   490  		},
   491  	}
   492  	refs, err := convertServiceConfigObjs(client, namespace, configs, configSpecs)
   493  	assert.NilError(t, err)
   494  	expected := []*swarm.ConfigReference{
   495  		{
   496  			ConfigName: "bar_config",
   497  			File: &swarm.ConfigReferenceFileTarget{
   498  				Name: "bar_config",
   499  				UID:  "0",
   500  				GID:  "0",
   501  				Mode: 0444,
   502  			},
   503  		},
   504  		{
   505  			ConfigName: "foo_config",
   506  			File: &swarm.ConfigReferenceFileTarget{
   507  				Name: "foo_config",
   508  				UID:  "0",
   509  				GID:  "0",
   510  				Mode: 0444,
   511  			},
   512  		},
   513  	}
   514  	assert.DeepEqual(t, expected, refs)
   515  }
   516  
   517  type fakeClient struct {
   518  	client.Client
   519  	secretListFunc func(types.SecretListOptions) ([]swarm.Secret, error)
   520  	configListFunc func(types.ConfigListOptions) ([]swarm.Config, error)
   521  }
   522  
   523  func (c *fakeClient) SecretList(ctx context.Context, options types.SecretListOptions) ([]swarm.Secret, error) {
   524  	if c.secretListFunc != nil {
   525  		return c.secretListFunc(options)
   526  	}
   527  	return []swarm.Secret{}, nil
   528  }
   529  
   530  func (c *fakeClient) ConfigList(ctx context.Context, options types.ConfigListOptions) ([]swarm.Config, error) {
   531  	if c.configListFunc != nil {
   532  		return c.configListFunc(options)
   533  	}
   534  	return []swarm.Config{}, nil
   535  }
   536  
   537  func TestConvertUpdateConfigParallelism(t *testing.T) {
   538  	parallel := uint64(4)
   539  
   540  	// test default behavior
   541  	updateConfig := convertUpdateConfig(&composetypes.UpdateConfig{})
   542  	assert.Check(t, is.Equal(uint64(1), updateConfig.Parallelism))
   543  
   544  	// Non default value
   545  	updateConfig = convertUpdateConfig(&composetypes.UpdateConfig{
   546  		Parallelism: &parallel,
   547  	})
   548  	assert.Check(t, is.Equal(parallel, updateConfig.Parallelism))
   549  }