github.com/cspotcode/docker-cli@v20.10.0-rc1.0.20201201121459-3faad7acc5b8+incompatible/cli/command/registry/login_test.go (about) 1 package registry 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "testing" 8 9 configtypes "github.com/docker/cli/cli/config/types" 10 "github.com/docker/cli/internal/test" 11 "github.com/docker/docker/api/types" 12 registrytypes "github.com/docker/docker/api/types/registry" 13 "github.com/docker/docker/client" 14 "gotest.tools/v3/assert" 15 is "gotest.tools/v3/assert/cmp" 16 "gotest.tools/v3/fs" 17 ) 18 19 const userErr = "userunknownError" 20 const testAuthErrMsg = "UNKNOWN_ERR" 21 22 var testAuthErrors = map[string]error{ 23 userErr: fmt.Errorf(testAuthErrMsg), 24 } 25 26 var expiredPassword = "I_M_EXPIRED" 27 var useToken = "I_M_TOKEN" 28 29 type fakeClient struct { 30 client.Client 31 } 32 33 func (c fakeClient) Info(ctx context.Context) (types.Info, error) { 34 return types.Info{}, nil 35 } 36 37 func (c fakeClient) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) { 38 if auth.Password == expiredPassword { 39 return registrytypes.AuthenticateOKBody{}, fmt.Errorf("Invalid Username or Password") 40 } 41 if auth.Password == useToken { 42 return registrytypes.AuthenticateOKBody{ 43 IdentityToken: auth.Password, 44 }, nil 45 } 46 err := testAuthErrors[auth.Username] 47 return registrytypes.AuthenticateOKBody{}, err 48 } 49 50 func TestLoginWithCredStoreCreds(t *testing.T) { 51 testCases := []struct { 52 inputAuthConfig types.AuthConfig 53 expectedMsg string 54 expectedErr string 55 }{ 56 { 57 inputAuthConfig: types.AuthConfig{}, 58 expectedMsg: "Authenticating with existing credentials...\n", 59 }, 60 { 61 inputAuthConfig: types.AuthConfig{ 62 Username: userErr, 63 }, 64 expectedMsg: "Authenticating with existing credentials...\n", 65 expectedErr: fmt.Sprintf("Login did not succeed, error: %s\n", testAuthErrMsg), 66 }, 67 // can't easily test the 401 case because client.IsErrUnauthorized(err) involving 68 // creating an error of a private type 69 } 70 ctx := context.Background() 71 for _, tc := range testCases { 72 cli := test.NewFakeCli(&fakeClient{}) 73 errBuf := new(bytes.Buffer) 74 cli.SetErr(errBuf) 75 loginWithCredStoreCreds(ctx, cli, &tc.inputAuthConfig) 76 outputString := cli.OutBuffer().String() 77 assert.Check(t, is.Equal(tc.expectedMsg, outputString)) 78 errorString := errBuf.String() 79 assert.Check(t, is.Equal(tc.expectedErr, errorString)) 80 } 81 } 82 83 func TestRunLogin(t *testing.T) { 84 const storedServerAddress = "reg1" 85 const validUsername = "u1" 86 const validPassword = "p1" 87 const validPassword2 = "p2" 88 89 validAuthConfig := configtypes.AuthConfig{ 90 ServerAddress: storedServerAddress, 91 Username: validUsername, 92 Password: validPassword, 93 } 94 expiredAuthConfig := configtypes.AuthConfig{ 95 ServerAddress: storedServerAddress, 96 Username: validUsername, 97 Password: expiredPassword, 98 } 99 validIdentityToken := configtypes.AuthConfig{ 100 ServerAddress: storedServerAddress, 101 Username: validUsername, 102 IdentityToken: useToken, 103 } 104 testCases := []struct { 105 inputLoginOption loginOptions 106 inputStoredCred *configtypes.AuthConfig 107 expectedErr string 108 expectedSavedCred configtypes.AuthConfig 109 }{ 110 { 111 inputLoginOption: loginOptions{ 112 serverAddress: storedServerAddress, 113 }, 114 inputStoredCred: &validAuthConfig, 115 expectedErr: "", 116 expectedSavedCred: validAuthConfig, 117 }, 118 { 119 inputLoginOption: loginOptions{ 120 serverAddress: storedServerAddress, 121 }, 122 inputStoredCred: &expiredAuthConfig, 123 expectedErr: "Error: Cannot perform an interactive login from a non TTY device", 124 }, 125 { 126 inputLoginOption: loginOptions{ 127 serverAddress: storedServerAddress, 128 user: validUsername, 129 password: validPassword2, 130 }, 131 inputStoredCred: &validAuthConfig, 132 expectedErr: "", 133 expectedSavedCred: configtypes.AuthConfig{ 134 ServerAddress: storedServerAddress, 135 Username: validUsername, 136 Password: validPassword2, 137 }, 138 }, 139 { 140 inputLoginOption: loginOptions{ 141 serverAddress: storedServerAddress, 142 user: userErr, 143 password: validPassword, 144 }, 145 inputStoredCred: &validAuthConfig, 146 expectedErr: testAuthErrMsg, 147 }, 148 { 149 inputLoginOption: loginOptions{ 150 serverAddress: storedServerAddress, 151 user: validUsername, 152 password: useToken, 153 }, 154 inputStoredCred: &validIdentityToken, 155 expectedErr: "", 156 expectedSavedCred: validIdentityToken, 157 }, 158 } 159 for i, tc := range testCases { 160 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { 161 tmpFile := fs.NewFile(t, "test-run-login") 162 defer tmpFile.Remove() 163 cli := test.NewFakeCli(&fakeClient{}) 164 configfile := cli.ConfigFile() 165 configfile.Filename = tmpFile.Path() 166 167 if tc.inputStoredCred != nil { 168 cred := *tc.inputStoredCred 169 assert.NilError(t, configfile.GetCredentialsStore(cred.ServerAddress).Store(cred)) 170 } 171 loginErr := runLogin(cli, tc.inputLoginOption) 172 if tc.expectedErr != "" { 173 assert.Error(t, loginErr, tc.expectedErr) 174 return 175 } 176 assert.NilError(t, loginErr) 177 savedCred, credStoreErr := configfile.GetCredentialsStore(tc.inputStoredCred.ServerAddress).Get(tc.inputStoredCred.ServerAddress) 178 assert.Check(t, credStoreErr) 179 assert.DeepEqual(t, tc.expectedSavedCred, savedCred) 180 }) 181 } 182 }