diff --git a/internal/cli/atlas/setup/setup_cmd_test.go b/internal/cli/atlas/setup/setup_cmd_test.go index d7b2d803bf..c5025fd48e 100644 --- a/internal/cli/atlas/setup/setup_cmd_test.go +++ b/internal/cli/atlas/setup/setup_cmd_test.go @@ -59,7 +59,6 @@ func TestBuilder(t *testing.T) { } func Test_setupOpts_PreRunWithAPIKeys(t *testing.T) { - t.Cleanup(test.CleanupConfig) ctrl := gomock.NewController(t) mockFlow := mocks.NewMockRefresher(ctrl) ctx := context.TODO() @@ -99,7 +98,6 @@ func Test_setupOpts_RunSkipRegister(t *testing.T) { } func TestCluster_Run(t *testing.T) { - t.Cleanup(test.CleanupConfig) ctrl := gomock.NewController(t) mockStore := mocks.NewMockAtlasClusterQuickStarter(ctrl) mockFlow := mocks.NewMockRefresher(ctrl) @@ -158,7 +156,6 @@ func TestCluster_Run(t *testing.T) { } func TestCluster_Run_CheckFlagsSet(t *testing.T) { - t.Cleanup(test.CleanupConfig) ctrl := gomock.NewController(t) mockStore := mocks.NewMockAtlasClusterQuickStarter(ctrl) mockFlow := mocks.NewMockRefresher(ctrl) diff --git a/internal/cli/auth/login.go b/internal/cli/auth/login.go index 2cf95594d0..463dfce723 100644 --- a/internal/cli/auth/login.go +++ b/internal/cli/auth/login.go @@ -39,6 +39,8 @@ import ( type LoginConfig interface { config.SetSaver AccessTokenSubject() (string, error) + OrgID() string + ProjectID() string } var ( @@ -137,11 +139,11 @@ func (opts *LoginOpts) checkProfile(ctx context.Context) error { if err := opts.InitStore(ctx); err != nil { return err } - if config.OrgID() != "" && !opts.OrgExists(config.OrgID()) { + if opts.config.OrgID() != "" && !opts.OrgExists(opts.config.OrgID()) { opts.config.Set("org_id", "") } - if config.ProjectID() != "" && !opts.ProjectExists(config.ProjectID()) { + if opts.config.ProjectID() != "" && !opts.ProjectExists(opts.config.ProjectID()) { opts.config.Set("project_id", "") } return nil @@ -158,7 +160,7 @@ func (opts *LoginOpts) setUpProfile(ctx context.Context) error { } } - if config.OrgID() == "" || !opts.OrgExists(config.OrgID()) { + if opts.config.OrgID() == "" || !opts.OrgExists(opts.config.OrgID()) { if err := opts.AskOrg(); err != nil { return err } @@ -166,7 +168,7 @@ func (opts *LoginOpts) setUpProfile(ctx context.Context) error { opts.SetUpOrg() - if config.ProjectID() == "" || !opts.ProjectExists(config.ProjectID()) { + if opts.config.ProjectID() == "" || !opts.ProjectExists(opts.config.ProjectID()) { if err := opts.AskProject(); err != nil { return err } @@ -175,11 +177,11 @@ func (opts *LoginOpts) setUpProfile(ctx context.Context) error { // Only make references to profile if user was asked about org or projects if opts.AskedOrgsOrProjects && opts.ProjectID != "" && opts.OrgID != "" { - if !opts.ProjectExists(config.ProjectID()) { + if !opts.ProjectExists(opts.config.ProjectID()) { return ErrProjectIDNotFound } - if !opts.OrgExists(config.OrgID()) { + if !opts.OrgExists(opts.config.OrgID()) { return ErrOrgIDNotFound } diff --git a/internal/cli/auth/login_test.go b/internal/cli/auth/login_test.go index 621c664364..2fd8a2d545 100644 --- a/internal/cli/auth/login_test.go +++ b/internal/cli/auth/login_test.go @@ -133,6 +133,8 @@ func Test_loginOpts_Run(t *testing.T) { mockConfig.EXPECT().Set("access_token", "asdf").Times(1) mockConfig.EXPECT().Set("refresh_token", "querty").Times(1) mockConfig.EXPECT().Set("ops_manager_url", gomock.Any()).Times(0) + mockConfig.EXPECT().OrgID().Return("").AnyTimes() + mockConfig.EXPECT().ProjectID().Return("").AnyTimes() mockConfig.EXPECT().AccessTokenSubject().Return("test@10gen.com", nil).Times(1) mockConfig.EXPECT().Save().Return(nil).Times(2) expectedOrgs := &admin.PaginatedOrganization{ diff --git a/internal/cli/auth/logout.go b/internal/cli/auth/logout.go index f67c09180f..ee120096bf 100644 --- a/internal/cli/auth/logout.go +++ b/internal/cli/auth/logout.go @@ -16,7 +16,6 @@ package auth import ( "context" - "fmt" "io" "github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli" @@ -29,24 +28,29 @@ import ( atlas "go.mongodb.org/atlas/mongodbatlas" ) -type logoutOpts struct { - *cli.DeleteOpts - OutWriter io.Writer - config ConfigDeleter - flow Revoker - keepConfig bool -} - //go:generate mockgen -destination=../../mocks/mock_logout.go -package=mocks github.com/mongodb/mongodb-atlas-cli/atlascli/internal/cli/auth Revoker,ConfigDeleter type ConfigDeleter interface { Delete() error + SetAccessToken(string) + SetRefreshToken(string) + SetProjectID(string) + SetOrgID(string) + Save() error } type Revoker interface { RevokeToken(context.Context, string, string) (*atlas.Response, error) } +type logoutOpts struct { + *cli.DeleteOpts + OutWriter io.Writer + config ConfigDeleter + flow Revoker + keepConfig bool +} + func (opts *logoutOpts) initFlow() error { var err error opts.flow, err = oauth.FlowWithConfig(config.Default()) @@ -62,11 +66,11 @@ func (opts *logoutOpts) Run(ctx context.Context) error { if !opts.keepConfig { return opts.Delete(opts.config.Delete) } - config.SetAccessToken("") - config.SetRefreshToken("") - config.SetProjectID("") - config.SetOrgID("") - return config.Save() + opts.config.SetAccessToken("") + opts.config.SetRefreshToken("") + opts.config.SetProjectID("") + opts.config.SetOrgID("") + return opts.config.Save() } func LogoutBuilder() *cobra.Command { @@ -77,9 +81,9 @@ func LogoutBuilder() *cobra.Command { cmd := &cobra.Command{ Use: "logout", Short: "Log out of the CLI.", - Example: fmt.Sprintf(` # To log out from the CLI: - %s auth logout -`, config.BinName()), + Example: ` # To log out from the CLI: + atlas auth logout +`, PreRunE: func(cmd *cobra.Command, _ []string) error { opts.OutWriter = cmd.OutOrStdout() opts.config = config.Default() diff --git a/internal/cli/auth/logout_test.go b/internal/cli/auth/logout_test.go index e1b698b1cb..21922068de 100644 --- a/internal/cli/auth/logout_test.go +++ b/internal/cli/auth/logout_test.go @@ -90,5 +90,27 @@ func Test_logoutOpts_Run_Keep(t *testing.T) { Return(nil, nil). Times(1) + mockConfig. + EXPECT(). + SetAccessToken(""). + Times(1) + mockConfig. + EXPECT(). + SetRefreshToken(""). + Times(1) + mockConfig. + EXPECT(). + SetProjectID(""). + Times(1) + mockConfig. + EXPECT(). + SetOrgID(""). + Times(1) + mockConfig. + EXPECT(). + Save(). + Return(nil). + Times(1) + require.NoError(t, opts.Run(ctx)) } diff --git a/internal/cli/auth/register.go b/internal/cli/auth/register.go index 09aa3919e8..2716c888bf 100644 --- a/internal/cli/auth/register.go +++ b/internal/cli/auth/register.go @@ -99,9 +99,9 @@ func RegisterBuilder() *cobra.Command { cmd := &cobra.Command{ Use: "register", Short: "Register with MongoDB Atlas.", - Example: fmt.Sprintf(` # To start the interactive setup: - %s auth register -`, config.BinName()), + Example: ` # To start the interactive setup: + atlas auth register +`, PreRunE: func(cmd *cobra.Command, _ []string) error { opts.OutWriter = cmd.OutOrStdout() defaultProfile := config.Default() diff --git a/internal/cli/auth/register_test.go b/internal/cli/auth/register_test.go index 2542538885..2379d97d07 100644 --- a/internal/cli/auth/register_test.go +++ b/internal/cli/auth/register_test.go @@ -43,7 +43,6 @@ func TestRegisterBuilder(t *testing.T) { } func Test_registerOpts_Run(t *testing.T) { - t.Cleanup(test.CleanupConfig) ctrl := gomock.NewController(t) mockFlow := mocks.NewMockRefresher(ctrl) mockConfig := mocks.NewMockLoginConfig(ctrl) @@ -96,6 +95,8 @@ func Test_registerOpts_Run(t *testing.T) { mockConfig.EXPECT().Set("access_token", "asdf").Times(1) mockConfig.EXPECT().Set("refresh_token", "querty").Times(1) mockConfig.EXPECT().Set("ops_manager_url", gomock.Any()).Times(0) + mockConfig.EXPECT().OrgID().Return("").AnyTimes() + mockConfig.EXPECT().ProjectID().Return("").AnyTimes() mockConfig.EXPECT().AccessTokenSubject().Return("test@10gen.com", nil).Times(1) mockConfig.EXPECT().Save().Return(nil).Times(2) expectedOrgs := &admin.PaginatedOrganization{ @@ -104,13 +105,21 @@ func Test_registerOpts_Run(t *testing.T) { {Id: pointer.Get("o1"), Name: "Org1"}, }, } - mockStore.EXPECT().Organizations(gomock.Any()).Return(expectedOrgs, nil).Times(1) + mockStore. + EXPECT(). + Organizations(gomock.Any()). + Return(expectedOrgs, nil). + Times(1) expectedProjects := &admin.PaginatedAtlasGroup{TotalCount: pointer.Get(1), Results: &[]admin.Group{ {Id: pointer.Get("p1"), Name: "Project1"}, }, } - mockStore.EXPECT().GetOrgProjects("o1", gomock.Any()).Return(expectedProjects, nil).Times(1) + mockStore. + EXPECT(). + GetOrgProjects("o1", gomock.Any()). + Return(expectedProjects, nil). + Times(1) require.NoError(t, opts.RegisterRun(ctx)) assert.Equal(t, ` diff --git a/internal/config/profile_test.go b/internal/config/profile_test.go index 5311767d55..2db21d5e5d 100644 --- a/internal/config/profile_test.go +++ b/internal/config/profile_test.go @@ -21,26 +21,19 @@ import ( "os" "testing" + "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestConfig_MongoCLIConfigHome(t *testing.T) { - t.Run("with env set", func(t *testing.T) { - expHome, err := os.UserConfigDir() - expected := fmt.Sprintf("%s/mongocli", expHome) - if err != nil { - t.Fatalf("os.UserConfigDir() unexpected error: %v", err) - } + expHome, err := os.UserConfigDir() + require.NoError(t, err) - home, err := MongoCLIConfigHome() - if err != nil { - t.Fatalf("MongoCLIConfigHome() unexpected error: %v", err) - } - if home != expected { - t.Errorf("MongoCLIConfigHome() = %s; want '%s'", home, expected) - } - }) + home, err := MongoCLIConfigHome() + require.NoError(t, err) + expected := fmt.Sprintf("%s/mongocli", expHome) + assert.Equal(t, expected, home) } func TestConfig_OldMongoCLIConfigHome(t *testing.T) { @@ -157,9 +150,12 @@ func TestConfig_IsTrue(t *testing.T) { }, } for _, tt := range tests { - if got := IsTrue(tt.input); got != tt.want { - t.Errorf("IsTrue() get: %v, want %v", got, tt.want) - } + t.Run("", func(t *testing.T) { + t.Parallel() + if got := IsTrue(tt.input); got != tt.want { + t.Errorf("IsTrue() get: %v, want %v", got, tt.want) + } + }) } } @@ -221,12 +217,12 @@ func Test_getConfigHostname(t *testing.T) { }, } for _, tt := range tests { - fields := tt.fields + f := tt.fields expectedHostName := tt.expectedHostName t.Run(tt.name, func(t *testing.T) { - t.Setenv(AtlasActionHostNameEnv, fields.atlasActionEnv) - t.Setenv(GitHubActionsHostNameEnv, fields.ghActionsEnv) - t.Setenv(ContainerizedHostNameEnv, fields.containerizedEnv) + t.Setenv(AtlasActionHostNameEnv, f.atlasActionEnv) + t.Setenv(GitHubActionsHostNameEnv, f.ghActionsEnv) + t.Setenv(ContainerizedHostNameEnv, f.containerizedEnv) actualHostName := getConfigHostnameFromEnvs() assert.Equal(t, expectedHostName, actualHostName) @@ -234,30 +230,80 @@ func Test_getConfigHostname(t *testing.T) { } } -func TestConfig_SetName(t *testing.T) { - t.Run("valid", func(t *testing.T) { - require.NoError(t, SetName("default")) - require.NoError(t, SetName("default-123")) - require.NoError(t, SetName("default-test")) - }) - - t.Run("invalid", func(t *testing.T) { - require.Error(t, SetName("d.efault")) - require.Error(t, SetName("default.123")) - require.Error(t, SetName("default.test")) - }) +func TestProfile_Rename(t *testing.T) { + tests := []struct { + name string + wantErr require.ErrorAssertionFunc + }{ + { + name: "default", + wantErr: require.NoError, + }, + { + name: "default-123", + wantErr: require.NoError, + }, + { + name: "default-test", + wantErr: require.NoError, + }, + { + name: "default.123", + wantErr: require.Error, + }, + { + name: "default.test", + wantErr: require.Error, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + p := &Profile{ + name: tt.name, + fs: afero.NewMemMapFs(), + } + tt.wantErr(t, p.Rename(tt.name), fmt.Sprintf("Rename(%v)", tt.name)) + }) + } } -func TestConfig_Rename(t *testing.T) { - t.Run("valid", func(t *testing.T) { - require.NoError(t, Rename("default")) - require.NoError(t, Rename("default-123")) - require.NoError(t, Rename("default-test")) - }) - - t.Run("invalid", func(t *testing.T) { - require.Error(t, Rename("d.efault")) - require.Error(t, Rename("default.123")) - require.Error(t, Rename("default.test")) - }) +func TestProfile_SetName(t *testing.T) { + tests := []struct { + name string + wantErr require.ErrorAssertionFunc + }{ + { + name: "default", + wantErr: require.NoError, + }, + { + name: "default-123", + wantErr: require.NoError, + }, + { + name: "default-test", + wantErr: require.NoError, + }, + { + name: "default.123", + wantErr: require.Error, + }, + { + name: "default.test", + wantErr: require.Error, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + p := &Profile{ + name: tt.name, + fs: afero.NewMemMapFs(), + } + tt.wantErr(t, p.SetName(tt.name), fmt.Sprintf("SetName(%v)", tt.name)) + }) + } } diff --git a/internal/mocks/mock_login.go b/internal/mocks/mock_login.go index e7a7defa26..176ebadfd7 100644 --- a/internal/mocks/mock_login.go +++ b/internal/mocks/mock_login.go @@ -48,6 +48,34 @@ func (mr *MockLoginConfigMockRecorder) AccessTokenSubject() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessTokenSubject", reflect.TypeOf((*MockLoginConfig)(nil).AccessTokenSubject)) } +// OrgID mocks base method. +func (m *MockLoginConfig) OrgID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OrgID") + ret0, _ := ret[0].(string) + return ret0 +} + +// OrgID indicates an expected call of OrgID. +func (mr *MockLoginConfigMockRecorder) OrgID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OrgID", reflect.TypeOf((*MockLoginConfig)(nil).OrgID)) +} + +// ProjectID mocks base method. +func (m *MockLoginConfig) ProjectID() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ProjectID") + ret0, _ := ret[0].(string) + return ret0 +} + +// ProjectID indicates an expected call of ProjectID. +func (mr *MockLoginConfigMockRecorder) ProjectID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProjectID", reflect.TypeOf((*MockLoginConfig)(nil).ProjectID)) +} + // Save mocks base method. func (m *MockLoginConfig) Save() error { m.ctrl.T.Helper() diff --git a/internal/mocks/mock_logout.go b/internal/mocks/mock_logout.go index 09b6ed7db2..42e1017b9c 100644 --- a/internal/mocks/mock_logout.go +++ b/internal/mocks/mock_logout.go @@ -86,3 +86,65 @@ func (mr *MockConfigDeleterMockRecorder) Delete() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockConfigDeleter)(nil).Delete)) } + +// Save mocks base method. +func (m *MockConfigDeleter) Save() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save") + ret0, _ := ret[0].(error) + return ret0 +} + +// Save indicates an expected call of Save. +func (mr *MockConfigDeleterMockRecorder) Save() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockConfigDeleter)(nil).Save)) +} + +// SetAccessToken mocks base method. +func (m *MockConfigDeleter) SetAccessToken(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetAccessToken", arg0) +} + +// SetAccessToken indicates an expected call of SetAccessToken. +func (mr *MockConfigDeleterMockRecorder) SetAccessToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessToken", reflect.TypeOf((*MockConfigDeleter)(nil).SetAccessToken), arg0) +} + +// SetOrgID mocks base method. +func (m *MockConfigDeleter) SetOrgID(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetOrgID", arg0) +} + +// SetOrgID indicates an expected call of SetOrgID. +func (mr *MockConfigDeleterMockRecorder) SetOrgID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetOrgID", reflect.TypeOf((*MockConfigDeleter)(nil).SetOrgID), arg0) +} + +// SetProjectID mocks base method. +func (m *MockConfigDeleter) SetProjectID(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetProjectID", arg0) +} + +// SetProjectID indicates an expected call of SetProjectID. +func (mr *MockConfigDeleterMockRecorder) SetProjectID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProjectID", reflect.TypeOf((*MockConfigDeleter)(nil).SetProjectID), arg0) +} + +// SetRefreshToken mocks base method. +func (m *MockConfigDeleter) SetRefreshToken(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetRefreshToken", arg0) +} + +// SetRefreshToken indicates an expected call of SetRefreshToken. +func (mr *MockConfigDeleterMockRecorder) SetRefreshToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRefreshToken", reflect.TypeOf((*MockConfigDeleter)(nil).SetRefreshToken), arg0) +}