DockerCLI/cli/command/registry/login_test.go

157 lines
4.3 KiB
Go
Raw Normal View History

package registry
import (
"bytes"
"context"
"fmt"
"testing"
"github.com/docker/cli/internal/test"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
"gotest.tools/fs"
)
const userErr = "userunknownError"
const testAuthErrMsg = "UNKNOWN_ERR"
var testAuthErrors = map[string]error{
userErr: fmt.Errorf(testAuthErrMsg),
}
var expiredPassword = "I_M_EXPIRED"
type fakeClient struct {
client.Client
}
func (c fakeClient) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
if auth.Password == expiredPassword {
return registrytypes.AuthenticateOKBody{}, fmt.Errorf("Invalid Username or Password")
}
err := testAuthErrors[auth.Username]
return registrytypes.AuthenticateOKBody{}, err
}
func TestLoginWithCredStoreCreds(t *testing.T) {
testCases := []struct {
inputAuthConfig types.AuthConfig
expectedMsg string
expectedErr string
}{
{
inputAuthConfig: types.AuthConfig{},
expectedMsg: "Authenticating with existing credentials...\n",
},
{
inputAuthConfig: types.AuthConfig{
Username: userErr,
},
expectedMsg: "Authenticating with existing credentials...\n",
expectedErr: fmt.Sprintf("Login did not succeed, error: %s\n", testAuthErrMsg),
},
// can't easily test the 401 case because client.IsErrUnauthorized(err) involving
// creating an error of a private type
}
ctx := context.Background()
for _, tc := range testCases {
cli := (*test.FakeCli)(test.NewFakeCli(&fakeClient{}))
errBuf := new(bytes.Buffer)
cli.SetErr(errBuf)
loginWithCredStoreCreds(ctx, cli, &tc.inputAuthConfig)
outputString := cli.OutBuffer().String()
assert.Check(t, is.Equal(tc.expectedMsg, outputString))
errorString := errBuf.String()
assert.Check(t, is.Equal(tc.expectedErr, errorString))
}
}
func TestRunLogin(t *testing.T) {
const storedServerAddress = "reg1"
const validUsername = "u1"
const validPassword = "p1"
const validPassword2 = "p2"
validAuthConfig := types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: validPassword,
}
expiredAuthConfig := types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: expiredPassword,
}
testCases := []struct {
inputLoginOption loginOptions
inputStoredCred *types.AuthConfig
expectedErr string
expectedSavedCred types.AuthConfig
}{
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
},
inputStoredCred: &validAuthConfig,
expectedErr: "",
expectedSavedCred: validAuthConfig,
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
},
inputStoredCred: &expiredAuthConfig,
expectedErr: "Error: Cannot perform an interactive login from a non TTY device",
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
user: validUsername,
password: validPassword2,
},
inputStoredCred: &validAuthConfig,
expectedErr: "",
expectedSavedCred: types.AuthConfig{
ServerAddress: storedServerAddress,
Username: validUsername,
Password: validPassword2,
},
},
{
inputLoginOption: loginOptions{
serverAddress: storedServerAddress,
user: userErr,
password: validPassword,
},
inputStoredCred: &validAuthConfig,
expectedErr: testAuthErrMsg,
},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
tmpFile := fs.NewFile(t, "test-run-login")
defer tmpFile.Remove()
cli := test.NewFakeCli(&fakeClient{})
configfile := cli.ConfigFile()
configfile.Filename = tmpFile.Path()
if tc.inputStoredCred != nil {
cred := *tc.inputStoredCred
configfile.GetCredentialsStore(cred.ServerAddress).Store(cred)
}
loginErr := runLogin(cli, tc.inputLoginOption)
if tc.expectedErr != "" {
assert.Error(t, loginErr, tc.expectedErr)
return
}
assert.NilError(t, loginErr)
savedCred, credStoreErr := configfile.GetCredentialsStore(tc.inputStoredCred.ServerAddress).Get(tc.inputStoredCred.ServerAddress)
assert.Check(t, credStoreErr)
assert.DeepEqual(t, tc.expectedSavedCred, savedCred)
})
}
}