diff --git a/test/e2e/accounts_test.go b/test/e2e/accounts_test.go index af623763d377e..b5f9a4160555a 100644 --- a/test/e2e/accounts_test.go +++ b/test/e2e/accounts_test.go @@ -4,6 +4,8 @@ import ( "context" "testing" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/account" + "github.com/argoproj/pkg/errors" "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" @@ -12,10 +14,31 @@ import ( argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + accountFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/account" "github.com/argoproj/argo-cd/v2/util/io" ) func TestCreateAndUseAccount(t *testing.T) { + ctx := accountFixture.Given(t) + ctx. + Name("test"). + When(). + Create(). + Then(). + And(func(account *account.Account, err error) { + assert.Equal(t, account.Name, ctx.GetName()) + assert.Equal(t, account.Capabilities, []string{"login"}) + }). + When(). + Login(). + Then(). + CurrentUser(func(user *session.GetUserInfoResponse, err error) { + assert.Equal(t, user.LoggedIn, true) + assert.Equal(t, user.Username, ctx.GetName()) + }) +} + +func TestCreateAndUseAccountCLI(t *testing.T) { EnsureCleanState(t) output, err := RunCli("account", "list") diff --git a/test/e2e/fixture/account/actions.go b/test/e2e/fixture/account/actions.go new file mode 100644 index 0000000000000..1966bdf8bcc26 --- /dev/null +++ b/test/e2e/fixture/account/actions.go @@ -0,0 +1,49 @@ +package project + +import ( + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" +) + +// this implements the "when" part of given/when/then +// +// none of the func implement error checks, and that is complete intended, you should check for errors +// using the Then() +type Actions struct { + context *Context + ignoreErrors bool +} + +func (a *Actions) IgnoreErrors() *Actions { + a.ignoreErrors = true + return a +} + +func (a *Actions) DoNotIgnoreErrors() *Actions { + a.ignoreErrors = false + return a +} + +func (a *Actions) prepareSetPasswordArgs(account string) []string { + a.context.t.Helper() + return []string{ + "account", "update-password", "--account", account, "--current-password", fixture.AdminPassword, "--new-password", fixture.DefaultTestUserPassword, "--plaintext", + } +} + +func (a *Actions) Create() *Actions { + fixture.SetAccounts(map[string][]string{ + a.context.name: {"login"}, + }) + _, _ = fixture.RunCli(a.prepareSetPasswordArgs(a.context.name)...) + return a +} + +func (a *Actions) Login() *Actions { + fixture.LoginAs(a.context.name) + return a +} + +func (a *Actions) Then() *Consequences { + a.context.t.Helper() + return &Consequences{a.context, a} +} diff --git a/test/e2e/fixture/account/consequences.go b/test/e2e/fixture/account/consequences.go new file mode 100644 index 0000000000000..20b0677f78821 --- /dev/null +++ b/test/e2e/fixture/account/consequences.go @@ -0,0 +1,60 @@ +package project + +import ( + "context" + "errors" + + "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" + + "github.com/argoproj/argo-cd/v2/pkg/apiclient/account" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + . "github.com/argoproj/argo-cd/v2/util/errors" + "github.com/argoproj/argo-cd/v2/util/io" +) + +// this implements the "then" part of given/when/then +type Consequences struct { + context *Context + actions *Actions +} + +func (c *Consequences) And(block func(account *account.Account, err error)) *Consequences { + c.context.t.Helper() + block(c.get()) + return c +} + +func (c *Consequences) CurrentUser(block func(user *session.GetUserInfoResponse, err error)) *Consequences { + c.context.t.Helper() + block(c.getCurrentUser()) + return c +} + +func (c *Consequences) get() (*account.Account, error) { + _, accountClient, _ := fixture.ArgoCDClientset.NewAccountClient() + accList, err := accountClient.ListAccounts(context.Background(), &account.ListAccountRequest{}) + if err != nil { + return nil, err + } + for _, acc := range accList.Items { + if acc.Name == c.context.name { + return acc, nil + } + } + return nil, errors.New("account not found") +} + +func (c *Consequences) getCurrentUser() (*session.GetUserInfoResponse, error) { + closer, client, err := fixture.ArgoCDClientset.NewSessionClient() + CheckError(err) + defer io.Close(closer) + return client.GetUserInfo(context.Background(), &session.GetUserInfoRequest{}) +} + +func (c *Consequences) Given() *Context { + return c.context +} + +func (c *Consequences) When() *Actions { + return c.actions +} diff --git a/test/e2e/fixture/account/context.go b/test/e2e/fixture/account/context.go new file mode 100644 index 0000000000000..99f3adb92d7fd --- /dev/null +++ b/test/e2e/fixture/account/context.go @@ -0,0 +1,45 @@ +package project + +import ( + "testing" + "time" + + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + "github.com/argoproj/argo-cd/v2/util/env" +) + +// this implements the "given" part of given/when/then +type Context struct { + t *testing.T + // seconds + timeout int + name string +} + +func Given(t *testing.T) *Context { + fixture.EnsureCleanState(t) + // ARGOCE_E2E_DEFAULT_TIMEOUT can be used to override the default timeout + // for any context. + timeout := env.ParseNumFromEnv("ARGOCD_E2E_DEFAULT_TIMEOUT", 10, 0, 180) + return &Context{t: t, name: fixture.Name(), timeout: timeout} +} + +func (c *Context) GetName() string { + return c.name +} + +func (c *Context) Name(name string) *Context { + c.name = name + return c +} + +func (c *Context) And(block func()) *Context { + block() + return c +} + +func (c *Context) When() *Actions { + // in case any settings have changed, pause for 1s, not great, but fine + time.Sleep(1 * time.Second) + return &Actions{context: c} +} diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go index 1b607e02d7bf4..5f340e96189a7 100644 --- a/test/e2e/fixture/fixture.go +++ b/test/e2e/fixture/fixture.go @@ -38,11 +38,12 @@ import ( ) const ( - defaultApiServer = "localhost:8080" - defaultAdminPassword = "password" - defaultAdminUsername = "admin" - testingLabel = "e2e.argoproj.io" - ArgoCDNamespace = "argocd-e2e" + defaultApiServer = "localhost:8080" + defaultAdminPassword = "password" + defaultAdminUsername = "admin" + DefaultTestUserPassword = "password" + testingLabel = "e2e.argoproj.io" + ArgoCDNamespace = "argocd-e2e" // ensure all repos are in one directory tree, so we can easily clean them up TmpDir = "/tmp/argo-e2e" @@ -69,7 +70,7 @@ var ( AppClientset appclientset.Interface ArgoCDClientset argocdclient.Client adminUsername string - adminPassword string + AdminPassword string apiServerAddress string token string plainText bool @@ -146,7 +147,7 @@ func init() { apiServerAddress = GetEnvWithDefault(argocdclient.EnvArgoCDServer, defaultApiServer) adminUsername = GetEnvWithDefault(EnvAdminUsername, defaultAdminUsername) - adminPassword = GetEnvWithDefault(EnvAdminPassword, defaultAdminPassword) + AdminPassword = GetEnvWithDefault(EnvAdminPassword, defaultAdminPassword) tlsTestResult, err := grpcutil.TestTLS(apiServerAddress) CheckError(err) @@ -154,24 +155,10 @@ func init() { ArgoCDClientset, err = argocdclient.NewClient(&argocdclient.ClientOptions{Insecure: true, ServerAddr: apiServerAddress, PlainText: !tlsTestResult.TLS}) CheckError(err) - closer, client, err := ArgoCDClientset.NewSessionClient() - CheckError(err) - defer io.Close(closer) - - sessionResponse, err := client.Create(context.Background(), &sessionpkg.SessionCreateRequest{Username: adminUsername, Password: adminPassword}) - CheckError(err) - - ArgoCDClientset, err = argocdclient.NewClient(&argocdclient.ClientOptions{ - Insecure: true, - ServerAddr: apiServerAddress, - AuthToken: sessionResponse.Token, - PlainText: !tlsTestResult.TLS, - }) - CheckError(err) - - token = sessionResponse.Token plainText = !tlsTestResult.TLS + LoginAs(adminUsername) + log.WithFields(log.Fields{"apiServerAddress": apiServerAddress}).Info("initialized") // Preload a list of tests that should be skipped @@ -196,6 +183,32 @@ func init() { } +func loginAs(username, password string) { + closer, client, err := ArgoCDClientset.NewSessionClient() + CheckError(err) + defer io.Close(closer) + + sessionResponse, err := client.Create(context.Background(), &sessionpkg.SessionCreateRequest{Username: username, Password: password}) + CheckError(err) + token = sessionResponse.Token + + ArgoCDClientset, err = argocdclient.NewClient(&argocdclient.ClientOptions{ + Insecure: true, + ServerAddr: apiServerAddress, + AuthToken: token, + PlainText: plainText, + }) + CheckError(err) +} + +func LoginAs(username string) { + password := DefaultTestUserPassword + if username == "admin" { + password = AdminPassword + } + loginAs(username, password) +} + func Name() string { return name } @@ -455,6 +468,9 @@ func EnsureCleanState(t *testing.T) { return nil }) + // We can switch user and as result in previous state we will have non-admin user, this case should be reset + LoginAs(adminUsername) + // reset gpg-keys config map updateGenericConfigMap(common.ArgoCDGPGKeysConfigMapName, func(cm *corev1.ConfigMap) error { cm.Data = map[string]string{}