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 }