3
0

Fix external auth unit tests

This commit is contained in:
Denis Arh
2019-04-03 19:23:38 +02:00
parent b8a3dd367a
commit 836b899e7e
3 changed files with 61 additions and 37 deletions

View File

@@ -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,

View File

@@ -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")
}
}

View File

@@ -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")