github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/config/configfile/file_test.go (about)

     1  package configfile
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"testing"
     8  
     9  	"github.com/docker/cli/cli/config/credentials"
    10  	"github.com/docker/docker/api/types"
    11  	"gotest.tools/assert"
    12  	is "gotest.tools/assert/cmp"
    13  )
    14  
    15  func TestEncodeAuth(t *testing.T) {
    16  	newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"}
    17  	authStr := encodeAuth(newAuthConfig)
    18  
    19  	expected := &types.AuthConfig{}
    20  	var err error
    21  	expected.Username, expected.Password, err = decodeAuth(authStr)
    22  	assert.NilError(t, err)
    23  	assert.Check(t, is.DeepEqual(expected, newAuthConfig))
    24  }
    25  
    26  func TestProxyConfig(t *testing.T) {
    27  	httpProxy := "http://proxy.mycorp.com:3128"
    28  	httpsProxy := "https://user:password@proxy.mycorp.com:3129"
    29  	ftpProxy := "http://ftpproxy.mycorp.com:21"
    30  	noProxy := "*.intra.mycorp.com"
    31  	defaultProxyConfig := ProxyConfig{
    32  		HTTPProxy:  httpProxy,
    33  		HTTPSProxy: httpsProxy,
    34  		FTPProxy:   ftpProxy,
    35  		NoProxy:    noProxy,
    36  	}
    37  
    38  	cfg := ConfigFile{
    39  		Proxies: map[string]ProxyConfig{
    40  			"default": defaultProxyConfig,
    41  		},
    42  	}
    43  
    44  	proxyConfig := cfg.ParseProxyConfig("/var/run/docker.sock", []string{})
    45  	expected := map[string]*string{
    46  		"HTTP_PROXY":  &httpProxy,
    47  		"http_proxy":  &httpProxy,
    48  		"HTTPS_PROXY": &httpsProxy,
    49  		"https_proxy": &httpsProxy,
    50  		"FTP_PROXY":   &ftpProxy,
    51  		"ftp_proxy":   &ftpProxy,
    52  		"NO_PROXY":    &noProxy,
    53  		"no_proxy":    &noProxy,
    54  	}
    55  	assert.Check(t, is.DeepEqual(expected, proxyConfig))
    56  }
    57  
    58  func TestProxyConfigOverride(t *testing.T) {
    59  	httpProxy := "http://proxy.mycorp.com:3128"
    60  	overrideHTTPProxy := "http://proxy.example.com:3128"
    61  	overrideNoProxy := ""
    62  	httpsProxy := "https://user:password@proxy.mycorp.com:3129"
    63  	ftpProxy := "http://ftpproxy.mycorp.com:21"
    64  	noProxy := "*.intra.mycorp.com"
    65  	defaultProxyConfig := ProxyConfig{
    66  		HTTPProxy:  httpProxy,
    67  		HTTPSProxy: httpsProxy,
    68  		FTPProxy:   ftpProxy,
    69  		NoProxy:    noProxy,
    70  	}
    71  
    72  	cfg := ConfigFile{
    73  		Proxies: map[string]ProxyConfig{
    74  			"default": defaultProxyConfig,
    75  		},
    76  	}
    77  
    78  	ropts := []string{
    79  		fmt.Sprintf("HTTP_PROXY=%s", overrideHTTPProxy),
    80  		"NO_PROXY=",
    81  	}
    82  	proxyConfig := cfg.ParseProxyConfig("/var/run/docker.sock", ropts)
    83  	expected := map[string]*string{
    84  		"HTTP_PROXY":  &overrideHTTPProxy,
    85  		"http_proxy":  &httpProxy,
    86  		"HTTPS_PROXY": &httpsProxy,
    87  		"https_proxy": &httpsProxy,
    88  		"FTP_PROXY":   &ftpProxy,
    89  		"ftp_proxy":   &ftpProxy,
    90  		"NO_PROXY":    &overrideNoProxy,
    91  		"no_proxy":    &noProxy,
    92  	}
    93  	assert.Check(t, is.DeepEqual(expected, proxyConfig))
    94  }
    95  
    96  func TestProxyConfigPerHost(t *testing.T) {
    97  	httpProxy := "http://proxy.mycorp.com:3128"
    98  	httpsProxy := "https://user:password@proxy.mycorp.com:3129"
    99  	ftpProxy := "http://ftpproxy.mycorp.com:21"
   100  	noProxy := "*.intra.mycorp.com"
   101  
   102  	extHTTPProxy := "http://proxy.example.com:3128"
   103  	extHTTPSProxy := "https://user:password@proxy.example.com:3129"
   104  	extFTPProxy := "http://ftpproxy.example.com:21"
   105  	extNoProxy := "*.intra.example.com"
   106  
   107  	defaultProxyConfig := ProxyConfig{
   108  		HTTPProxy:  httpProxy,
   109  		HTTPSProxy: httpsProxy,
   110  		FTPProxy:   ftpProxy,
   111  		NoProxy:    noProxy,
   112  	}
   113  	externalProxyConfig := ProxyConfig{
   114  		HTTPProxy:  extHTTPProxy,
   115  		HTTPSProxy: extHTTPSProxy,
   116  		FTPProxy:   extFTPProxy,
   117  		NoProxy:    extNoProxy,
   118  	}
   119  
   120  	cfg := ConfigFile{
   121  		Proxies: map[string]ProxyConfig{
   122  			"default":                       defaultProxyConfig,
   123  			"tcp://example.docker.com:2376": externalProxyConfig,
   124  		},
   125  	}
   126  
   127  	proxyConfig := cfg.ParseProxyConfig("tcp://example.docker.com:2376", []string{})
   128  	expected := map[string]*string{
   129  		"HTTP_PROXY":  &extHTTPProxy,
   130  		"http_proxy":  &extHTTPProxy,
   131  		"HTTPS_PROXY": &extHTTPSProxy,
   132  		"https_proxy": &extHTTPSProxy,
   133  		"FTP_PROXY":   &extFTPProxy,
   134  		"ftp_proxy":   &extFTPProxy,
   135  		"NO_PROXY":    &extNoProxy,
   136  		"no_proxy":    &extNoProxy,
   137  	}
   138  	assert.Check(t, is.DeepEqual(expected, proxyConfig))
   139  }
   140  
   141  func TestConfigFile(t *testing.T) {
   142  	configFilename := "configFilename"
   143  	configFile := New(configFilename)
   144  
   145  	assert.Check(t, is.Equal(configFilename, configFile.Filename))
   146  }
   147  
   148  type mockNativeStore struct {
   149  	GetAllCallCount int
   150  	authConfigs     map[string]types.AuthConfig
   151  }
   152  
   153  func (c *mockNativeStore) Erase(registryHostname string) error {
   154  	delete(c.authConfigs, registryHostname)
   155  	return nil
   156  }
   157  
   158  func (c *mockNativeStore) Get(registryHostname string) (types.AuthConfig, error) {
   159  	return c.authConfigs[registryHostname], nil
   160  }
   161  
   162  func (c *mockNativeStore) GetAll() (map[string]types.AuthConfig, error) {
   163  	c.GetAllCallCount = c.GetAllCallCount + 1
   164  	return c.authConfigs, nil
   165  }
   166  
   167  func (c *mockNativeStore) Store(authConfig types.AuthConfig) error {
   168  	return nil
   169  }
   170  
   171  // make sure it satisfies the interface
   172  var _ credentials.Store = (*mockNativeStore)(nil)
   173  
   174  func NewMockNativeStore(authConfigs map[string]types.AuthConfig) credentials.Store {
   175  	return &mockNativeStore{authConfigs: authConfigs}
   176  }
   177  
   178  func TestGetAllCredentialsFileStoreOnly(t *testing.T) {
   179  	configFile := New("filename")
   180  	exampleAuth := types.AuthConfig{
   181  		Username: "user",
   182  		Password: "pass",
   183  	}
   184  	configFile.AuthConfigs["example.com/foo"] = exampleAuth
   185  
   186  	authConfigs, err := configFile.GetAllCredentials()
   187  	assert.NilError(t, err)
   188  
   189  	expected := make(map[string]types.AuthConfig)
   190  	expected["example.com/foo"] = exampleAuth
   191  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   192  }
   193  
   194  func TestGetAllCredentialsCredsStore(t *testing.T) {
   195  	configFile := New("filename")
   196  	configFile.CredentialsStore = "test_creds_store"
   197  	testRegistryHostname := "example.com"
   198  	expectedAuth := types.AuthConfig{
   199  		Username: "user",
   200  		Password: "pass",
   201  	}
   202  
   203  	testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedAuth})
   204  
   205  	tmpNewNativeStore := newNativeStore
   206  	defer func() { newNativeStore = tmpNewNativeStore }()
   207  	newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
   208  		return testCredsStore
   209  	}
   210  
   211  	authConfigs, err := configFile.GetAllCredentials()
   212  	assert.NilError(t, err)
   213  
   214  	expected := make(map[string]types.AuthConfig)
   215  	expected[testRegistryHostname] = expectedAuth
   216  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   217  	assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
   218  }
   219  
   220  func TestGetAllCredentialsCredHelper(t *testing.T) {
   221  	testCredHelperSuffix := "test_cred_helper"
   222  	testCredHelperRegistryHostname := "credhelper.com"
   223  	testExtraCredHelperRegistryHostname := "somethingweird.com"
   224  
   225  	unexpectedCredHelperAuth := types.AuthConfig{
   226  		Username: "file_store_user",
   227  		Password: "file_store_pass",
   228  	}
   229  	expectedCredHelperAuth := types.AuthConfig{
   230  		Username: "cred_helper_user",
   231  		Password: "cred_helper_pass",
   232  	}
   233  
   234  	configFile := New("filename")
   235  	configFile.CredentialHelpers = map[string]string{testCredHelperRegistryHostname: testCredHelperSuffix}
   236  
   237  	testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{
   238  		testCredHelperRegistryHostname: expectedCredHelperAuth,
   239  		// Add in an extra auth entry which doesn't appear in CredentialHelpers section of the configFile.
   240  		// This verifies that only explicitly configured registries are being requested from the cred helpers.
   241  		testExtraCredHelperRegistryHostname: unexpectedCredHelperAuth,
   242  	})
   243  
   244  	tmpNewNativeStore := newNativeStore
   245  	defer func() { newNativeStore = tmpNewNativeStore }()
   246  	newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
   247  		return testCredHelper
   248  	}
   249  
   250  	authConfigs, err := configFile.GetAllCredentials()
   251  	assert.NilError(t, err)
   252  
   253  	expected := make(map[string]types.AuthConfig)
   254  	expected[testCredHelperRegistryHostname] = expectedCredHelperAuth
   255  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   256  	assert.Check(t, is.Equal(0, testCredHelper.(*mockNativeStore).GetAllCallCount))
   257  }
   258  
   259  func TestGetAllCredentialsFileStoreAndCredHelper(t *testing.T) {
   260  	testFileStoreRegistryHostname := "example.com"
   261  	testCredHelperSuffix := "test_cred_helper"
   262  	testCredHelperRegistryHostname := "credhelper.com"
   263  
   264  	expectedFileStoreAuth := types.AuthConfig{
   265  		Username: "file_store_user",
   266  		Password: "file_store_pass",
   267  	}
   268  	expectedCredHelperAuth := types.AuthConfig{
   269  		Username: "cred_helper_user",
   270  		Password: "cred_helper_pass",
   271  	}
   272  
   273  	configFile := New("filename")
   274  	configFile.CredentialHelpers = map[string]string{testCredHelperRegistryHostname: testCredHelperSuffix}
   275  	configFile.AuthConfigs[testFileStoreRegistryHostname] = expectedFileStoreAuth
   276  
   277  	testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth})
   278  
   279  	newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
   280  		return testCredHelper
   281  	}
   282  
   283  	tmpNewNativeStore := newNativeStore
   284  	defer func() { newNativeStore = tmpNewNativeStore }()
   285  	authConfigs, err := configFile.GetAllCredentials()
   286  	assert.NilError(t, err)
   287  
   288  	expected := make(map[string]types.AuthConfig)
   289  	expected[testFileStoreRegistryHostname] = expectedFileStoreAuth
   290  	expected[testCredHelperRegistryHostname] = expectedCredHelperAuth
   291  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   292  	assert.Check(t, is.Equal(0, testCredHelper.(*mockNativeStore).GetAllCallCount))
   293  }
   294  
   295  func TestGetAllCredentialsCredStoreAndCredHelper(t *testing.T) {
   296  	testCredStoreSuffix := "test_creds_store"
   297  	testCredStoreRegistryHostname := "credstore.com"
   298  	testCredHelperSuffix := "test_cred_helper"
   299  	testCredHelperRegistryHostname := "credhelper.com"
   300  
   301  	configFile := New("filename")
   302  	configFile.CredentialsStore = testCredStoreSuffix
   303  	configFile.CredentialHelpers = map[string]string{testCredHelperRegistryHostname: testCredHelperSuffix}
   304  
   305  	expectedCredStoreAuth := types.AuthConfig{
   306  		Username: "cred_store_user",
   307  		Password: "cred_store_pass",
   308  	}
   309  	expectedCredHelperAuth := types.AuthConfig{
   310  		Username: "cred_helper_user",
   311  		Password: "cred_helper_pass",
   312  	}
   313  
   314  	testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth})
   315  	testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testCredStoreRegistryHostname: expectedCredStoreAuth})
   316  
   317  	tmpNewNativeStore := newNativeStore
   318  	defer func() { newNativeStore = tmpNewNativeStore }()
   319  	newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
   320  		if helperSuffix == testCredHelperSuffix {
   321  			return testCredHelper
   322  		}
   323  		return testCredsStore
   324  	}
   325  
   326  	authConfigs, err := configFile.GetAllCredentials()
   327  	assert.NilError(t, err)
   328  
   329  	expected := make(map[string]types.AuthConfig)
   330  	expected[testCredStoreRegistryHostname] = expectedCredStoreAuth
   331  	expected[testCredHelperRegistryHostname] = expectedCredHelperAuth
   332  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   333  	assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
   334  	assert.Check(t, is.Equal(0, testCredHelper.(*mockNativeStore).GetAllCallCount))
   335  }
   336  
   337  func TestGetAllCredentialsCredHelperOverridesDefaultStore(t *testing.T) {
   338  	testCredStoreSuffix := "test_creds_store"
   339  	testCredHelperSuffix := "test_cred_helper"
   340  	testRegistryHostname := "example.com"
   341  
   342  	configFile := New("filename")
   343  	configFile.CredentialsStore = testCredStoreSuffix
   344  	configFile.CredentialHelpers = map[string]string{testRegistryHostname: testCredHelperSuffix}
   345  
   346  	unexpectedCredStoreAuth := types.AuthConfig{
   347  		Username: "cred_store_user",
   348  		Password: "cred_store_pass",
   349  	}
   350  	expectedCredHelperAuth := types.AuthConfig{
   351  		Username: "cred_helper_user",
   352  		Password: "cred_helper_pass",
   353  	}
   354  
   355  	testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedCredHelperAuth})
   356  	testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: unexpectedCredStoreAuth})
   357  
   358  	tmpNewNativeStore := newNativeStore
   359  	defer func() { newNativeStore = tmpNewNativeStore }()
   360  	newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
   361  		if helperSuffix == testCredHelperSuffix {
   362  			return testCredHelper
   363  		}
   364  		return testCredsStore
   365  	}
   366  
   367  	authConfigs, err := configFile.GetAllCredentials()
   368  	assert.NilError(t, err)
   369  
   370  	expected := make(map[string]types.AuthConfig)
   371  	expected[testRegistryHostname] = expectedCredHelperAuth
   372  	assert.Check(t, is.DeepEqual(expected, authConfigs))
   373  	assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
   374  	assert.Check(t, is.Equal(0, testCredHelper.(*mockNativeStore).GetAllCallCount))
   375  }
   376  
   377  func TestCheckKubernetesConfigurationRaiseAnErrorOnInvalidValue(t *testing.T) {
   378  	testCases := []struct {
   379  		name        string
   380  		config      *KubernetesConfig
   381  		expectError bool
   382  	}{
   383  		{
   384  			"no kubernetes config is valid",
   385  			nil,
   386  			false,
   387  		},
   388  		{
   389  			"enabled is valid",
   390  			&KubernetesConfig{AllNamespaces: "enabled"},
   391  			false,
   392  		},
   393  		{
   394  			"disabled is valid",
   395  			&KubernetesConfig{AllNamespaces: "disabled"},
   396  			false,
   397  		},
   398  		{
   399  			"empty string is valid",
   400  			&KubernetesConfig{AllNamespaces: ""},
   401  			false,
   402  		},
   403  		{
   404  			"other value is invalid",
   405  			&KubernetesConfig{AllNamespaces: "unknown"},
   406  			true,
   407  		},
   408  	}
   409  	for _, test := range testCases {
   410  		err := checkKubernetesConfiguration(test.config)
   411  		if test.expectError {
   412  			assert.Assert(t, err != nil, test.name)
   413  		} else {
   414  			assert.NilError(t, err, test.name)
   415  		}
   416  	}
   417  }
   418  
   419  func TestSave(t *testing.T) {
   420  	configFile := New("test-save")
   421  	defer os.Remove("test-save")
   422  	err := configFile.Save()
   423  	assert.NilError(t, err)
   424  	cfg, err := ioutil.ReadFile("test-save")
   425  	assert.NilError(t, err)
   426  	assert.Check(t, is.Equal(string(cfg), "{\n	\"auths\": {}\n}"))
   427  }