github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/compose/loader/merge_test.go (about)

     1  package loader
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/docker/cli/cli/compose/types"
     7  	"gotest.tools/assert"
     8  )
     9  
    10  func TestLoadTwoDifferentVersion(t *testing.T) {
    11  	configDetails := types.ConfigDetails{
    12  		ConfigFiles: []types.ConfigFile{
    13  			{Filename: "base.yml", Config: map[string]interface{}{
    14  				"version": "3.1",
    15  			}},
    16  			{Filename: "override.yml", Config: map[string]interface{}{
    17  				"version": "3.4",
    18  			}},
    19  		},
    20  	}
    21  	_, err := Load(configDetails)
    22  	assert.Error(t, err, "version mismatched between two composefiles : 3.1 and 3.4")
    23  }
    24  
    25  func TestLoadLogging(t *testing.T) {
    26  	loggingCases := []struct {
    27  		name            string
    28  		loggingBase     map[string]interface{}
    29  		loggingOverride map[string]interface{}
    30  		expected        *types.LoggingConfig
    31  	}{
    32  		{
    33  			name: "no_override_driver",
    34  			loggingBase: map[string]interface{}{
    35  				"logging": map[string]interface{}{
    36  					"driver": "json-file",
    37  					"options": map[string]interface{}{
    38  						"frequency": "2000",
    39  						"timeout":   "23",
    40  					},
    41  				},
    42  			},
    43  			loggingOverride: map[string]interface{}{
    44  				"logging": map[string]interface{}{
    45  					"options": map[string]interface{}{
    46  						"timeout":      "360",
    47  						"pretty-print": "on",
    48  					},
    49  				},
    50  			},
    51  			expected: &types.LoggingConfig{
    52  				Driver: "json-file",
    53  				Options: map[string]string{
    54  					"frequency":    "2000",
    55  					"timeout":      "360",
    56  					"pretty-print": "on",
    57  				},
    58  			},
    59  		},
    60  		{
    61  			name: "override_driver",
    62  			loggingBase: map[string]interface{}{
    63  				"logging": map[string]interface{}{
    64  					"driver": "json-file",
    65  					"options": map[string]interface{}{
    66  						"frequency": "2000",
    67  						"timeout":   "23",
    68  					},
    69  				},
    70  			},
    71  			loggingOverride: map[string]interface{}{
    72  				"logging": map[string]interface{}{
    73  					"driver": "syslog",
    74  					"options": map[string]interface{}{
    75  						"timeout":      "360",
    76  						"pretty-print": "on",
    77  					},
    78  				},
    79  			},
    80  			expected: &types.LoggingConfig{
    81  				Driver: "syslog",
    82  				Options: map[string]string{
    83  					"timeout":      "360",
    84  					"pretty-print": "on",
    85  				},
    86  			},
    87  		},
    88  		{
    89  			name: "no_base_driver",
    90  			loggingBase: map[string]interface{}{
    91  				"logging": map[string]interface{}{
    92  					"options": map[string]interface{}{
    93  						"frequency": "2000",
    94  						"timeout":   "23",
    95  					},
    96  				},
    97  			},
    98  			loggingOverride: map[string]interface{}{
    99  				"logging": map[string]interface{}{
   100  					"driver": "json-file",
   101  					"options": map[string]interface{}{
   102  						"timeout":      "360",
   103  						"pretty-print": "on",
   104  					},
   105  				},
   106  			},
   107  			expected: &types.LoggingConfig{
   108  				Driver: "json-file",
   109  				Options: map[string]string{
   110  					"frequency":    "2000",
   111  					"timeout":      "360",
   112  					"pretty-print": "on",
   113  				},
   114  			},
   115  		},
   116  		{
   117  			name: "no_driver",
   118  			loggingBase: map[string]interface{}{
   119  				"logging": map[string]interface{}{
   120  					"options": map[string]interface{}{
   121  						"frequency": "2000",
   122  						"timeout":   "23",
   123  					},
   124  				},
   125  			},
   126  			loggingOverride: map[string]interface{}{
   127  				"logging": map[string]interface{}{
   128  					"options": map[string]interface{}{
   129  						"timeout":      "360",
   130  						"pretty-print": "on",
   131  					},
   132  				},
   133  			},
   134  			expected: &types.LoggingConfig{
   135  				Options: map[string]string{
   136  					"frequency":    "2000",
   137  					"timeout":      "360",
   138  					"pretty-print": "on",
   139  				},
   140  			},
   141  		},
   142  		{
   143  			name: "no_override_options",
   144  			loggingBase: map[string]interface{}{
   145  				"logging": map[string]interface{}{
   146  					"driver": "json-file",
   147  					"options": map[string]interface{}{
   148  						"frequency": "2000",
   149  						"timeout":   "23",
   150  					},
   151  				},
   152  			},
   153  			loggingOverride: map[string]interface{}{
   154  				"logging": map[string]interface{}{
   155  					"driver": "syslog",
   156  				},
   157  			},
   158  			expected: &types.LoggingConfig{
   159  				Driver: "syslog",
   160  			},
   161  		},
   162  		{
   163  			name:        "no_base",
   164  			loggingBase: map[string]interface{}{},
   165  			loggingOverride: map[string]interface{}{
   166  				"logging": map[string]interface{}{
   167  					"driver": "json-file",
   168  					"options": map[string]interface{}{
   169  						"frequency": "2000",
   170  					},
   171  				},
   172  			},
   173  			expected: &types.LoggingConfig{
   174  				Driver: "json-file",
   175  				Options: map[string]string{
   176  					"frequency": "2000",
   177  				},
   178  			},
   179  		},
   180  	}
   181  
   182  	for _, tc := range loggingCases {
   183  		t.Run(tc.name, func(t *testing.T) {
   184  			configDetails := types.ConfigDetails{
   185  				ConfigFiles: []types.ConfigFile{
   186  					{
   187  						Filename: "base.yml",
   188  						Config: map[string]interface{}{
   189  							"version": "3.4",
   190  							"services": map[string]interface{}{
   191  								"foo": tc.loggingBase,
   192  							},
   193  						},
   194  					},
   195  					{
   196  						Filename: "override.yml",
   197  						Config: map[string]interface{}{
   198  							"version": "3.4",
   199  							"services": map[string]interface{}{
   200  								"foo": tc.loggingOverride,
   201  							},
   202  						},
   203  					},
   204  				},
   205  			}
   206  			config, err := Load(configDetails)
   207  			assert.NilError(t, err)
   208  			assert.DeepEqual(t, &types.Config{
   209  				Filename: "base.yml",
   210  				Version:  "3.4",
   211  				Services: []types.ServiceConfig{
   212  					{
   213  						Name:        "foo",
   214  						Logging:     tc.expected,
   215  						Environment: types.MappingWithEquals{},
   216  					},
   217  				},
   218  				Networks: map[string]types.NetworkConfig{},
   219  				Volumes:  map[string]types.VolumeConfig{},
   220  				Secrets:  map[string]types.SecretConfig{},
   221  				Configs:  map[string]types.ConfigObjConfig{},
   222  			}, config)
   223  		})
   224  	}
   225  }
   226  
   227  func TestLoadMultipleServicePorts(t *testing.T) {
   228  	portsCases := []struct {
   229  		name         string
   230  		portBase     map[string]interface{}
   231  		portOverride map[string]interface{}
   232  		expected     []types.ServicePortConfig
   233  	}{
   234  		{
   235  			name: "no_override",
   236  			portBase: map[string]interface{}{
   237  				"ports": []interface{}{
   238  					"8080:80",
   239  				},
   240  			},
   241  			portOverride: map[string]interface{}{},
   242  			expected: []types.ServicePortConfig{
   243  				{
   244  					Mode:      "ingress",
   245  					Published: 8080,
   246  					Target:    80,
   247  					Protocol:  "tcp",
   248  				},
   249  			},
   250  		},
   251  		{
   252  			name: "override_different_published",
   253  			portBase: map[string]interface{}{
   254  				"ports": []interface{}{
   255  					"8080:80",
   256  				},
   257  			},
   258  			portOverride: map[string]interface{}{
   259  				"ports": []interface{}{
   260  					"8081:80",
   261  				},
   262  			},
   263  			expected: []types.ServicePortConfig{
   264  				{
   265  					Mode:      "ingress",
   266  					Published: 8080,
   267  					Target:    80,
   268  					Protocol:  "tcp",
   269  				},
   270  				{
   271  					Mode:      "ingress",
   272  					Published: 8081,
   273  					Target:    80,
   274  					Protocol:  "tcp",
   275  				},
   276  			},
   277  		},
   278  		{
   279  			name: "override_same_published",
   280  			portBase: map[string]interface{}{
   281  				"ports": []interface{}{
   282  					"8080:80",
   283  				},
   284  			},
   285  			portOverride: map[string]interface{}{
   286  				"ports": []interface{}{
   287  					"8080:81",
   288  				},
   289  			},
   290  			expected: []types.ServicePortConfig{
   291  				{
   292  					Mode:      "ingress",
   293  					Published: 8080,
   294  					Target:    81,
   295  					Protocol:  "tcp",
   296  				},
   297  			},
   298  		},
   299  	}
   300  
   301  	for _, tc := range portsCases {
   302  		t.Run(tc.name, func(t *testing.T) {
   303  			configDetails := types.ConfigDetails{
   304  				ConfigFiles: []types.ConfigFile{
   305  					{
   306  						Filename: "base.yml",
   307  						Config: map[string]interface{}{
   308  							"version": "3.4",
   309  							"services": map[string]interface{}{
   310  								"foo": tc.portBase,
   311  							},
   312  						},
   313  					},
   314  					{
   315  						Filename: "override.yml",
   316  						Config: map[string]interface{}{
   317  							"version": "3.4",
   318  							"services": map[string]interface{}{
   319  								"foo": tc.portOverride,
   320  							},
   321  						},
   322  					},
   323  				},
   324  			}
   325  			config, err := Load(configDetails)
   326  			assert.NilError(t, err)
   327  			assert.DeepEqual(t, &types.Config{
   328  				Filename: "base.yml",
   329  				Version:  "3.4",
   330  				Services: []types.ServiceConfig{
   331  					{
   332  						Name:        "foo",
   333  						Ports:       tc.expected,
   334  						Environment: types.MappingWithEquals{},
   335  					},
   336  				},
   337  				Networks: map[string]types.NetworkConfig{},
   338  				Volumes:  map[string]types.VolumeConfig{},
   339  				Secrets:  map[string]types.SecretConfig{},
   340  				Configs:  map[string]types.ConfigObjConfig{},
   341  			}, config)
   342  		})
   343  	}
   344  }
   345  
   346  func TestLoadMultipleSecretsConfig(t *testing.T) {
   347  	portsCases := []struct {
   348  		name           string
   349  		secretBase     map[string]interface{}
   350  		secretOverride map[string]interface{}
   351  		expected       []types.ServiceSecretConfig
   352  	}{
   353  		{
   354  			name: "no_override",
   355  			secretBase: map[string]interface{}{
   356  				"secrets": []interface{}{
   357  					"my_secret",
   358  				},
   359  			},
   360  			secretOverride: map[string]interface{}{},
   361  			expected: []types.ServiceSecretConfig{
   362  				{
   363  					Source: "my_secret",
   364  				},
   365  			},
   366  		},
   367  		{
   368  			name: "override_simple",
   369  			secretBase: map[string]interface{}{
   370  				"secrets": []interface{}{
   371  					"foo_secret",
   372  				},
   373  			},
   374  			secretOverride: map[string]interface{}{
   375  				"secrets": []interface{}{
   376  					"bar_secret",
   377  				},
   378  			},
   379  			expected: []types.ServiceSecretConfig{
   380  				{
   381  					Source: "bar_secret",
   382  				},
   383  				{
   384  					Source: "foo_secret",
   385  				},
   386  			},
   387  		},
   388  		{
   389  			name: "override_same_source",
   390  			secretBase: map[string]interface{}{
   391  				"secrets": []interface{}{
   392  					"foo_secret",
   393  					map[string]interface{}{
   394  						"source": "bar_secret",
   395  						"target": "waw_secret",
   396  					},
   397  				},
   398  			},
   399  			secretOverride: map[string]interface{}{
   400  				"secrets": []interface{}{
   401  					map[string]interface{}{
   402  						"source": "bar_secret",
   403  						"target": "bof_secret",
   404  					},
   405  					map[string]interface{}{
   406  						"source": "baz_secret",
   407  						"target": "waw_secret",
   408  					},
   409  				},
   410  			},
   411  			expected: []types.ServiceSecretConfig{
   412  				{
   413  					Source: "bar_secret",
   414  					Target: "bof_secret",
   415  				},
   416  				{
   417  					Source: "baz_secret",
   418  					Target: "waw_secret",
   419  				},
   420  				{
   421  					Source: "foo_secret",
   422  				},
   423  			},
   424  		},
   425  	}
   426  
   427  	for _, tc := range portsCases {
   428  		t.Run(tc.name, func(t *testing.T) {
   429  			configDetails := types.ConfigDetails{
   430  				ConfigFiles: []types.ConfigFile{
   431  					{
   432  						Filename: "base.yml",
   433  						Config: map[string]interface{}{
   434  							"version": "3.4",
   435  							"services": map[string]interface{}{
   436  								"foo": tc.secretBase,
   437  							},
   438  						},
   439  					},
   440  					{
   441  						Filename: "override.yml",
   442  						Config: map[string]interface{}{
   443  							"version": "3.4",
   444  							"services": map[string]interface{}{
   445  								"foo": tc.secretOverride,
   446  							},
   447  						},
   448  					},
   449  				},
   450  			}
   451  			config, err := Load(configDetails)
   452  			assert.NilError(t, err)
   453  			assert.DeepEqual(t, &types.Config{
   454  				Filename: "base.yml",
   455  				Version:  "3.4",
   456  				Services: []types.ServiceConfig{
   457  					{
   458  						Name:        "foo",
   459  						Secrets:     tc.expected,
   460  						Environment: types.MappingWithEquals{},
   461  					},
   462  				},
   463  				Networks: map[string]types.NetworkConfig{},
   464  				Volumes:  map[string]types.VolumeConfig{},
   465  				Secrets:  map[string]types.SecretConfig{},
   466  				Configs:  map[string]types.ConfigObjConfig{},
   467  			}, config)
   468  		})
   469  	}
   470  }
   471  
   472  func TestLoadMultipleConfigobjsConfig(t *testing.T) {
   473  	portsCases := []struct {
   474  		name           string
   475  		configBase     map[string]interface{}
   476  		configOverride map[string]interface{}
   477  		expected       []types.ServiceConfigObjConfig
   478  	}{
   479  		{
   480  			name: "no_override",
   481  			configBase: map[string]interface{}{
   482  				"configs": []interface{}{
   483  					"my_config",
   484  				},
   485  			},
   486  			configOverride: map[string]interface{}{},
   487  			expected: []types.ServiceConfigObjConfig{
   488  				{
   489  					Source: "my_config",
   490  				},
   491  			},
   492  		},
   493  		{
   494  			name: "override_simple",
   495  			configBase: map[string]interface{}{
   496  				"configs": []interface{}{
   497  					"foo_config",
   498  				},
   499  			},
   500  			configOverride: map[string]interface{}{
   501  				"configs": []interface{}{
   502  					"bar_config",
   503  				},
   504  			},
   505  			expected: []types.ServiceConfigObjConfig{
   506  				{
   507  					Source: "bar_config",
   508  				},
   509  				{
   510  					Source: "foo_config",
   511  				},
   512  			},
   513  		},
   514  		{
   515  			name: "override_same_source",
   516  			configBase: map[string]interface{}{
   517  				"configs": []interface{}{
   518  					"foo_config",
   519  					map[string]interface{}{
   520  						"source": "bar_config",
   521  						"target": "waw_config",
   522  					},
   523  				},
   524  			},
   525  			configOverride: map[string]interface{}{
   526  				"configs": []interface{}{
   527  					map[string]interface{}{
   528  						"source": "bar_config",
   529  						"target": "bof_config",
   530  					},
   531  					map[string]interface{}{
   532  						"source": "baz_config",
   533  						"target": "waw_config",
   534  					},
   535  				},
   536  			},
   537  			expected: []types.ServiceConfigObjConfig{
   538  				{
   539  					Source: "bar_config",
   540  					Target: "bof_config",
   541  				},
   542  				{
   543  					Source: "baz_config",
   544  					Target: "waw_config",
   545  				},
   546  				{
   547  					Source: "foo_config",
   548  				},
   549  			},
   550  		},
   551  	}
   552  
   553  	for _, tc := range portsCases {
   554  		t.Run(tc.name, func(t *testing.T) {
   555  			configDetails := types.ConfigDetails{
   556  				ConfigFiles: []types.ConfigFile{
   557  					{
   558  						Filename: "base.yml",
   559  						Config: map[string]interface{}{
   560  							"version": "3.4",
   561  							"services": map[string]interface{}{
   562  								"foo": tc.configBase,
   563  							},
   564  						},
   565  					},
   566  					{
   567  						Filename: "override.yml",
   568  						Config: map[string]interface{}{
   569  							"version": "3.4",
   570  							"services": map[string]interface{}{
   571  								"foo": tc.configOverride,
   572  							},
   573  						},
   574  					},
   575  				},
   576  			}
   577  			config, err := Load(configDetails)
   578  			assert.NilError(t, err)
   579  			assert.DeepEqual(t, &types.Config{
   580  				Filename: "base.yml",
   581  				Version:  "3.4",
   582  				Services: []types.ServiceConfig{
   583  					{
   584  						Name:        "foo",
   585  						Configs:     tc.expected,
   586  						Environment: types.MappingWithEquals{},
   587  					},
   588  				},
   589  				Networks: map[string]types.NetworkConfig{},
   590  				Volumes:  map[string]types.VolumeConfig{},
   591  				Secrets:  map[string]types.SecretConfig{},
   592  				Configs:  map[string]types.ConfigObjConfig{},
   593  			}, config)
   594  		})
   595  	}
   596  }
   597  
   598  func TestLoadMultipleUlimits(t *testing.T) {
   599  	ulimitCases := []struct {
   600  		name           string
   601  		ulimitBase     map[string]interface{}
   602  		ulimitOverride map[string]interface{}
   603  		expected       map[string]*types.UlimitsConfig
   604  	}{
   605  		{
   606  			name: "no_override",
   607  			ulimitBase: map[string]interface{}{
   608  				"ulimits": map[string]interface{}{
   609  					"noproc": 65535,
   610  				},
   611  			},
   612  			ulimitOverride: map[string]interface{}{},
   613  			expected: map[string]*types.UlimitsConfig{
   614  				"noproc": {
   615  					Single: 65535,
   616  				},
   617  			},
   618  		},
   619  		{
   620  			name: "override_simple",
   621  			ulimitBase: map[string]interface{}{
   622  				"ulimits": map[string]interface{}{
   623  					"noproc": 65535,
   624  				},
   625  			},
   626  			ulimitOverride: map[string]interface{}{
   627  				"ulimits": map[string]interface{}{
   628  					"noproc": 44444,
   629  				},
   630  			},
   631  			expected: map[string]*types.UlimitsConfig{
   632  				"noproc": {
   633  					Single: 44444,
   634  				},
   635  			},
   636  		},
   637  		{
   638  			name: "override_different_notation",
   639  			ulimitBase: map[string]interface{}{
   640  				"ulimits": map[string]interface{}{
   641  					"nofile": map[string]interface{}{
   642  						"soft": 11111,
   643  						"hard": 99999,
   644  					},
   645  					"noproc": 44444,
   646  				},
   647  			},
   648  			ulimitOverride: map[string]interface{}{
   649  				"ulimits": map[string]interface{}{
   650  					"nofile": 55555,
   651  					"noproc": map[string]interface{}{
   652  						"soft": 22222,
   653  						"hard": 33333,
   654  					},
   655  				},
   656  			},
   657  			expected: map[string]*types.UlimitsConfig{
   658  				"noproc": {
   659  					Soft: 22222,
   660  					Hard: 33333,
   661  				},
   662  				"nofile": {
   663  					Single: 55555,
   664  				},
   665  			},
   666  		},
   667  	}
   668  
   669  	for _, tc := range ulimitCases {
   670  		t.Run(tc.name, func(t *testing.T) {
   671  			configDetails := types.ConfigDetails{
   672  				ConfigFiles: []types.ConfigFile{
   673  					{
   674  						Filename: "base.yml",
   675  						Config: map[string]interface{}{
   676  							"version": "3.4",
   677  							"services": map[string]interface{}{
   678  								"foo": tc.ulimitBase,
   679  							},
   680  						},
   681  					},
   682  					{
   683  						Filename: "override.yml",
   684  						Config: map[string]interface{}{
   685  							"version": "3.4",
   686  							"services": map[string]interface{}{
   687  								"foo": tc.ulimitOverride,
   688  							},
   689  						},
   690  					},
   691  				},
   692  			}
   693  			config, err := Load(configDetails)
   694  			assert.NilError(t, err)
   695  			assert.DeepEqual(t, &types.Config{
   696  				Filename: "base.yml",
   697  				Version:  "3.4",
   698  				Services: []types.ServiceConfig{
   699  					{
   700  						Name:        "foo",
   701  						Ulimits:     tc.expected,
   702  						Environment: types.MappingWithEquals{},
   703  					},
   704  				},
   705  				Networks: map[string]types.NetworkConfig{},
   706  				Volumes:  map[string]types.VolumeConfig{},
   707  				Secrets:  map[string]types.SecretConfig{},
   708  				Configs:  map[string]types.ConfigObjConfig{},
   709  			}, config)
   710  		})
   711  	}
   712  }
   713  
   714  func TestLoadMultipleServiceNetworks(t *testing.T) {
   715  	networkCases := []struct {
   716  		name            string
   717  		networkBase     map[string]interface{}
   718  		networkOverride map[string]interface{}
   719  		expected        map[string]*types.ServiceNetworkConfig
   720  	}{
   721  		{
   722  			name: "no_override",
   723  			networkBase: map[string]interface{}{
   724  				"networks": []interface{}{
   725  					"net1",
   726  					"net2",
   727  				},
   728  			},
   729  			networkOverride: map[string]interface{}{},
   730  			expected: map[string]*types.ServiceNetworkConfig{
   731  				"net1": nil,
   732  				"net2": nil,
   733  			},
   734  		},
   735  		{
   736  			name: "override_simple",
   737  			networkBase: map[string]interface{}{
   738  				"networks": []interface{}{
   739  					"net1",
   740  					"net2",
   741  				},
   742  			},
   743  			networkOverride: map[string]interface{}{
   744  				"networks": []interface{}{
   745  					"net1",
   746  					"net3",
   747  				},
   748  			},
   749  			expected: map[string]*types.ServiceNetworkConfig{
   750  				"net1": nil,
   751  				"net2": nil,
   752  				"net3": nil,
   753  			},
   754  		},
   755  		{
   756  			name: "override_with_aliases",
   757  			networkBase: map[string]interface{}{
   758  				"networks": map[string]interface{}{
   759  					"net1": map[string]interface{}{
   760  						"aliases": []interface{}{
   761  							"alias1",
   762  						},
   763  					},
   764  					"net2": nil,
   765  				},
   766  			},
   767  			networkOverride: map[string]interface{}{
   768  				"networks": map[string]interface{}{
   769  					"net1": map[string]interface{}{
   770  						"aliases": []interface{}{
   771  							"alias2",
   772  							"alias3",
   773  						},
   774  					},
   775  					"net3": map[string]interface{}{},
   776  				},
   777  			},
   778  			expected: map[string]*types.ServiceNetworkConfig{
   779  				"net1": {
   780  					Aliases: []string{"alias2", "alias3"},
   781  				},
   782  				"net2": nil,
   783  				"net3": {},
   784  			},
   785  		},
   786  	}
   787  
   788  	for _, tc := range networkCases {
   789  		t.Run(tc.name, func(t *testing.T) {
   790  			configDetails := types.ConfigDetails{
   791  				ConfigFiles: []types.ConfigFile{
   792  					{
   793  						Filename: "base.yml",
   794  						Config: map[string]interface{}{
   795  							"version": "3.4",
   796  							"services": map[string]interface{}{
   797  								"foo": tc.networkBase,
   798  							},
   799  						},
   800  					},
   801  					{
   802  						Filename: "override.yml",
   803  						Config: map[string]interface{}{
   804  							"version": "3.4",
   805  							"services": map[string]interface{}{
   806  								"foo": tc.networkOverride,
   807  							},
   808  						},
   809  					},
   810  				},
   811  			}
   812  			config, err := Load(configDetails)
   813  			assert.NilError(t, err)
   814  			assert.DeepEqual(t, &types.Config{
   815  				Filename: "base.yml",
   816  				Version:  "3.4",
   817  				Services: []types.ServiceConfig{
   818  					{
   819  						Name:        "foo",
   820  						Networks:    tc.expected,
   821  						Environment: types.MappingWithEquals{},
   822  					},
   823  				},
   824  				Networks: map[string]types.NetworkConfig{},
   825  				Volumes:  map[string]types.VolumeConfig{},
   826  				Secrets:  map[string]types.SecretConfig{},
   827  				Configs:  map[string]types.ConfigObjConfig{},
   828  			}, config)
   829  		})
   830  	}
   831  }
   832  
   833  func TestLoadMultipleConfigs(t *testing.T) {
   834  	base := map[string]interface{}{
   835  		"version": "3.4",
   836  		"services": map[string]interface{}{
   837  			"foo": map[string]interface{}{
   838  				"image": "foo",
   839  				"build": map[string]interface{}{
   840  					"context":    ".",
   841  					"dockerfile": "bar.Dockerfile",
   842  				},
   843  				"ports": []interface{}{
   844  					"8080:80",
   845  					"9090:90",
   846  				},
   847  				"labels": []interface{}{
   848  					"foo=bar",
   849  				},
   850  				"cap_add": []interface{}{
   851  					"NET_ADMIN",
   852  				},
   853  			},
   854  		},
   855  		"volumes":  map[string]interface{}{},
   856  		"networks": map[string]interface{}{},
   857  		"secrets":  map[string]interface{}{},
   858  		"configs":  map[string]interface{}{},
   859  	}
   860  	override := map[string]interface{}{
   861  		"version": "3.4",
   862  		"services": map[string]interface{}{
   863  			"foo": map[string]interface{}{
   864  				"image": "baz",
   865  				"build": map[string]interface{}{
   866  					"dockerfile": "foo.Dockerfile",
   867  					"args": []interface{}{
   868  						"buildno=1",
   869  						"password=secret",
   870  					},
   871  				},
   872  				"ports": []interface{}{
   873  					map[string]interface{}{
   874  						"target":    81,
   875  						"published": 8080,
   876  					},
   877  				},
   878  				"labels": map[string]interface{}{
   879  					"foo": "baz",
   880  				},
   881  				"cap_add": []interface{}{
   882  					"SYS_ADMIN",
   883  				},
   884  			},
   885  			"bar": map[string]interface{}{
   886  				"image": "bar",
   887  			},
   888  		},
   889  		"volumes":  map[string]interface{}{},
   890  		"networks": map[string]interface{}{},
   891  		"secrets":  map[string]interface{}{},
   892  		"configs":  map[string]interface{}{},
   893  	}
   894  	configDetails := types.ConfigDetails{
   895  		ConfigFiles: []types.ConfigFile{
   896  			{Filename: "base.yml", Config: base},
   897  			{Filename: "override.yml", Config: override},
   898  		},
   899  	}
   900  	config, err := Load(configDetails)
   901  	assert.NilError(t, err)
   902  	assert.DeepEqual(t, &types.Config{
   903  		Filename: "base.yml",
   904  		Version:  "3.4",
   905  		Services: []types.ServiceConfig{
   906  			{
   907  				Name:        "bar",
   908  				Image:       "bar",
   909  				Environment: types.MappingWithEquals{},
   910  			},
   911  			{
   912  				Name:  "foo",
   913  				Image: "baz",
   914  				Build: types.BuildConfig{
   915  					Context:    ".",
   916  					Dockerfile: "foo.Dockerfile",
   917  					Args: types.MappingWithEquals{
   918  						"buildno":  strPtr("1"),
   919  						"password": strPtr("secret"),
   920  					},
   921  				},
   922  				Ports: []types.ServicePortConfig{
   923  					{
   924  						Target:    81,
   925  						Published: 8080,
   926  					},
   927  					{
   928  						Mode:      "ingress",
   929  						Target:    90,
   930  						Published: 9090,
   931  						Protocol:  "tcp",
   932  					},
   933  				},
   934  				Labels: types.Labels{
   935  					"foo": "baz",
   936  				},
   937  				CapAdd:      []string{"NET_ADMIN", "SYS_ADMIN"},
   938  				Environment: types.MappingWithEquals{},
   939  			}},
   940  		Networks: map[string]types.NetworkConfig{},
   941  		Volumes:  map[string]types.VolumeConfig{},
   942  		Secrets:  map[string]types.SecretConfig{},
   943  		Configs:  map[string]types.ConfigObjConfig{},
   944  	}, config)
   945  }
   946  
   947  // Issue#972
   948  func TestLoadMultipleNetworks(t *testing.T) {
   949  	base := map[string]interface{}{
   950  		"version": "3.4",
   951  		"services": map[string]interface{}{
   952  			"foo": map[string]interface{}{
   953  				"image": "baz",
   954  			},
   955  		},
   956  		"volumes": map[string]interface{}{},
   957  		"networks": map[string]interface{}{
   958  			"hostnet": map[string]interface{}{
   959  				"driver": "overlay",
   960  				"ipam": map[string]interface{}{
   961  					"driver": "default",
   962  					"config": []interface{}{
   963  						map[string]interface{}{
   964  							"subnet": "10.0.0.0/20",
   965  						},
   966  					},
   967  				},
   968  			},
   969  		},
   970  		"secrets": map[string]interface{}{},
   971  		"configs": map[string]interface{}{},
   972  	}
   973  	override := map[string]interface{}{
   974  		"version":  "3.4",
   975  		"services": map[string]interface{}{},
   976  		"volumes":  map[string]interface{}{},
   977  		"networks": map[string]interface{}{
   978  			"hostnet": map[string]interface{}{
   979  				"external": map[string]interface{}{
   980  					"name": "host",
   981  				},
   982  			},
   983  		},
   984  		"secrets": map[string]interface{}{},
   985  		"configs": map[string]interface{}{},
   986  	}
   987  	configDetails := types.ConfigDetails{
   988  		ConfigFiles: []types.ConfigFile{
   989  			{Filename: "base.yml", Config: base},
   990  			{Filename: "override.yml", Config: override},
   991  		},
   992  	}
   993  	config, err := Load(configDetails)
   994  	assert.NilError(t, err)
   995  	assert.DeepEqual(t, &types.Config{
   996  		Filename: "base.yml",
   997  		Version:  "3.4",
   998  		Services: []types.ServiceConfig{
   999  			{
  1000  				Name:        "foo",
  1001  				Image:       "baz",
  1002  				Environment: types.MappingWithEquals{},
  1003  			}},
  1004  		Networks: map[string]types.NetworkConfig{
  1005  			"hostnet": {
  1006  				Name: "host",
  1007  				External: types.External{
  1008  					External: true,
  1009  				},
  1010  			},
  1011  		},
  1012  		Volumes: map[string]types.VolumeConfig{},
  1013  		Secrets: map[string]types.SecretConfig{},
  1014  		Configs: map[string]types.ConfigObjConfig{},
  1015  	}, config)
  1016  }