From 836b899e7e042988a5ddeaba8a18f5297ea9e4d4 Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Wed, 3 Apr 2019 19:23:38 +0200 Subject: [PATCH] Fix external auth unit tests --- system/internal/service/auth.go | 37 +++++++++++------- system/internal/service/auth_test.go | 57 ++++++++++++++++++---------- system/internal/service/main_test.go | 4 -- 3 files changed, 61 insertions(+), 37 deletions(-) diff --git a/system/internal/service/auth.go b/system/internal/service/auth.go index 87b314269..079705848 100644 --- a/system/internal/service/auth.go +++ b/system/internal/service/auth.go @@ -19,6 +19,9 @@ type ( credentials repository.CredentialsRepository users repository.UserRepository + + providerValidator func(string) error + now func() *time.Time } AuthService interface { @@ -33,6 +36,11 @@ type ( } ) +func defaultProviderValidator(provider string) error { + _, err := goth.GetProvider(provider) + return err +} + func Auth(ctx context.Context) AuthService { return (&auth{}).With(ctx) } @@ -45,6 +53,12 @@ func (svc *auth) With(ctx context.Context) AuthService { credentials: repository.Credentials(ctx, db), users: repository.User(ctx, db), + + providerValidator: defaultProviderValidator, + now: func() *time.Time { + var now = time.Now() + return &now + }, } } @@ -52,9 +66,7 @@ func (svc *auth) With(ctx context.Context) AuthService { // // It does not update user's info func (svc *auth) External(profile goth.User) (u *types.User, err error) { - var lastUsedAt = time.Now() - - if _, err := goth.GetProvider(profile.Provider); err != nil { + if err = svc.providerValidator(profile.Provider); err != nil { return nil, err } @@ -119,23 +131,20 @@ func (svc *auth) External(profile goth.User) (u *types.User, err error) { } if u, err = svc.users.Create(u); err != nil { - return errors.Wrap(err, "could not create user after successful social auth") + return errors.Wrap(err, "could not create user after successful external authentication") } - log.Printf("Created new user after successful social auth (%v, %v)", u.ID, u.Email) - - // Owner created - return nil + log.Printf("created new user after successful social auth (%v, %v)", u.ID, u.Email) } else if err != nil { return err } else if !u.Valid() { return errors.Errorf( - "Social login to an invalid/suspended user (user ID: %v)", + "can not use invalid user (user ID: %v)", u.ID, ) } else { log.Printf( - "Autheticated user (%v, %v) via %s, existing user", + "autheticated user (%v, %v) via %s, existing user", u.ID, u.Email, profile.Provider, @@ -147,7 +156,7 @@ func (svc *auth) External(profile goth.User) (u *types.User, err error) { Kind: profile.Provider, OwnerID: u.ID, Credentials: profile.UserID, - LastUsedAt: &lastUsedAt, + LastUsedAt: svc.now(), } if !profile.ExpiresAt.IsZero() { @@ -160,7 +169,7 @@ func (svc *auth) External(profile goth.User) (u *types.User, err error) { } log.Printf( - "Creating new credential entry (%v, %v) for exisintg user (%v, %v)", + "creating new credential entry (%v, %v) for exisintg user (%v, %v)", c.ID, profile.Provider, u.ID, @@ -172,13 +181,13 @@ func (svc *auth) External(profile goth.User) (u *types.User, err error) { c.ExpiresAt = &profile.ExpiresAt } - c.LastUsedAt = &lastUsedAt + c.LastUsedAt = svc.now() if c, err = svc.credentials.Update(c); err != nil { return err } log.Printf( - "Updating credential entry (%v, %v) for exisintg user (%v, %v)", + "updating credential entry (%v, %v) for exisintg user (%v, %v)", c.ID, profile.Provider, u.ID, diff --git a/system/internal/service/auth_test.go b/system/internal/service/auth_test.go index 26c9b07f3..8661373b7 100644 --- a/system/internal/service/auth_test.go +++ b/system/internal/service/auth_test.go @@ -4,6 +4,7 @@ package service import ( "testing" + "time" "github.com/golang/mock/gomock" "github.com/markbates/goth" @@ -14,37 +15,59 @@ import ( "github.com/crusttech/crust/system/types" ) -func TestSocialSigninWithExistingCredentials(t *testing.T) { +// @todo this mockDB will be probably be used by other tests, move it to some common place +type mockDB struct{} + +func (mockDB) Transaction(callback func() error) error { return callback() } + +// Mock auth service with nil for current time, dummy provider validator and mock db +func makeMockAuthService(u repository.UserRepository, c repository.CredentialsRepository) *auth { + return &auth{ + db: &mockDB{}, + users: u, + credentials: c, + + providerValidator: func(s string) error { + // All providers are valid. + return nil + }, + + now: func() *time.Time { + return nil + }, + } +} + +func TestAuth_External_Existing(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() + // Create some virtual user and credentials var u = &types.User{ID: 300000, Email: "foo@example.tld"} var c = &types.Credentials{ID: 200000, OwnerID: u.ID} + + // Profile to be used. make sure email matches var p = goth.User{UserID: "some-profile-id", Provider: "gplus", Email: u.Email} crdRpoMock := repomock.NewMockCredentialsRepository(mockCtrl) crdRpoMock.EXPECT(). - FindByCredentials("g+", p.UserID). + FindByCredentials("gplus", p.UserID). Times(1). Return(types.CredentialsSet{c}, nil) usrRpoMock := repomock.NewMockUserRepository(mockCtrl) usrRpoMock.EXPECT().FindByID(u.ID).Times(1).Return(u, nil) - svc := &auth{ - db: &mockDB{}, - users: usrRpoMock, - credentials: crdRpoMock, - } + svc := makeMockAuthService(usrRpoMock, crdRpoMock) { - auser, err := svc.Social(p) - test.Assert(t, err == nil, "Auth.Social error: %+v", err) + auser, err := svc.External(p) + test.NoError(t, err, "unexpected error from auth.External", err) test.Assert(t, auser.ID == u.ID, "Did not receive expected user") } } -func TestSocialSigninWithNewUserCredentials(t *testing.T) { +func TestAuth_External_NonExisting(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -54,12 +77,12 @@ func TestSocialSigninWithNewUserCredentials(t *testing.T) { crdRpoMock := repomock.NewMockCredentialsRepository(mockCtrl) crdRpoMock.EXPECT(). - FindByCredentials("g+", p.UserID). + FindByCredentials("gplus", p.UserID). Times(1). Return(types.CredentialsSet{}, nil) crdRpoMock.EXPECT(). - Create(&types.Credentials{Kind: "g+", OwnerID: u.ID, Credentials: p.UserID}). + Create(&types.Credentials{Kind: "gplus", OwnerID: u.ID, Credentials: p.UserID}). Times(1). Return(c, nil) @@ -74,15 +97,11 @@ func TestSocialSigninWithNewUserCredentials(t *testing.T) { Times(1). Return(u, nil) - svc := &auth{ - db: &mockDB{}, - users: usrRpoMock, - credentials: crdRpoMock, - } + svc := makeMockAuthService(usrRpoMock, crdRpoMock) { - auser, err := svc.Social(p) - test.Assert(t, err == nil, "Auth.Social error: %+v", err) + auser, err := svc.External(p) + test.NoError(t, err, "unexpected error from auth.External", err) test.Assert(t, auser.ID == u.ID, "Did not receive expected user") } } diff --git a/system/internal/service/main_test.go b/system/internal/service/main_test.go index 4184f9d5c..c1f129b14 100644 --- a/system/internal/service/main_test.go +++ b/system/internal/service/main_test.go @@ -13,10 +13,6 @@ import ( systemMigrate "github.com/crusttech/crust/system/db" ) -type mockDB struct{} - -func (mockDB) Transaction(callback func() error) error { return callback() } - func TestMain(m *testing.M) { dsn := "" flag.StringVar(&dsn, "db-dsn", "crust:crust@tcp(crust-db:3306)/crust?collation=utf8mb4_general_ci", "DSN for database connection")