Skip to content

Commit

Permalink
Merge pull request #7 from isd-sgcu/feature/signin
Browse files Browse the repository at this point in the history
[Feature] SignIn
  • Loading branch information
bookpanda authored Dec 25, 2023
2 parents e6559a7 + 02bb870 commit bd9b138
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/internal/constant/error.constant.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package constant

const IncorrectEmailPasswordErrorMessage = "Incorrect email or password"
const DuplicateEmailErrorMessage = "Duplicate email"
const InternalServerErrorMessage = "Internal server error"
4 changes: 4 additions & 0 deletions src/internal/repository/user/user.repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ func (r *repositoryImpl) FindById(id string, user *model.User) error {
return r.Db.First(user, "id = ?", id).Error
}

func (r *repositoryImpl) FindByEmail(email string, user *model.User) error {
return r.Db.First(user, "email = ?", email).Error
}

func (r *repositoryImpl) Create(user *model.User) error {
return r.Db.Create(user).Error
}
Expand Down
15 changes: 15 additions & 0 deletions src/internal/repository/user/user.repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ func (t *UserRepositoryTest) TestFindByIdNotFound() {
assert.Equal(t.T(), gorm.ErrRecordNotFound, err)
}

func (t *UserRepositoryTest) TestFindByEmailSuccess() {
user := &model.User{}
email := t.initialUser.Email
err := t.userRepo.FindByEmail(email, user)
assert.NoError(t.T(), err)
assert.Equal(t.T(), t.initialUser.ID, user.ID)
}

func (t *UserRepositoryTest) TestFindByEmailNotFound() {
user := &model.User{}
notFoundEmail := faker.Email()
err := t.userRepo.FindByEmail(notFoundEmail, user)
assert.Equal(t.T(), gorm.ErrRecordNotFound, err)
}

func (t *UserRepositoryTest) TestCreateSuccess() {
createUser := &model.User{
Email: faker.Email(),
Expand Down
28 changes: 23 additions & 5 deletions src/internal/service/auth/auth.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,27 @@ func (s *serviceImpl) Signup(_ context.Context, request *authProto.SignupRequest
}

func (s *serviceImpl) SignIn(_ context.Context, request *authProto.SignInRequest) (*authProto.SignInResponse, error) {
// find user with email
// compare password with hashed password
// if matched, then call tokenService.CreateCredential
// update refreshToken in db
return nil, nil
user := &model.User{}
err := s.userRepo.FindByEmail(request.Email, user)
if err != nil {
return nil, status.Error(codes.PermissionDenied, constant.IncorrectEmailPasswordErrorMessage)
}

err = s.bcryptUtil.CompareHashedPassword(user.Password, request.Password)
if err != nil {
return nil, status.Error(codes.PermissionDenied, constant.IncorrectEmailPasswordErrorMessage)
}

credential, err := s.tokenService.CreateCredential(user.ID.String(), user.Role)
if err != nil {
return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage)
}

updateUser := &model.User{RefreshToken: credential.RefreshToken}
err = s.userRepo.Update(user.ID.String(), updateUser)
if err != nil {
return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage)
}

return &authProto.SignInResponse{Credential: credential}, nil
}
178 changes: 172 additions & 6 deletions src/internal/service/auth/auth.service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ type AuthServiceTest struct {
suite.Suite
ctx context.Context
signupRequest *authProto.SignupRequest
signInRequest *authProto.SignInRequest
}

func TestAuthService(t *testing.T) {
suite.Run(t, new(AuthServiceTest))

}

func (t *AuthServiceTest) SetupTest() {
Expand All @@ -39,9 +39,14 @@ func (t *AuthServiceTest) SetupTest() {
Email: faker.Email(),
Password: faker.Password(),
}
signInRequest := &authProto.SignInRequest{
Email: faker.Email(),
Password: faker.Password(),
}

t.ctx = ctx
t.signupRequest = signupRequest
t.signInRequest = signInRequest
}

func (t *AuthServiceTest) TestSignupSuccess() {
Expand Down Expand Up @@ -175,15 +180,176 @@ func (t *AuthServiceTest) TestSignupCreateUserInternalFailed() {
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *AuthServiceTest) TestSignInSuccess() {}
func (t *AuthServiceTest) TestSignInSuccess() {
existUser := &model.User{
Base: model.Base{
ID: uuid.New(),
},
Email: t.signInRequest.Email,
Password: faker.Password(),
Firstname: faker.FirstName(),
Lastname: faker.LastName(),
Role: constant.USER,
RefreshToken: "",
}
credential := &authProto.Credential{
AccessToken: faker.Word(),
RefreshToken: faker.Word(),
ExpiresIn: 3600,
}
updateUser := &model.User{
RefreshToken: credential.RefreshToken,
}

func (t *AuthServiceTest) TestSignInUserNotFound() {}
expected := &authProto.SignInResponse{Credential: credential}

func (t *AuthServiceTest) TestSignInUnmatchedPassword() {}
userRepo := user.UserRepositoryMock{}
tokenService := token.TokenServiceMock{}
bcryptUtil := utils.BcryptUtilMock{}

func (t *AuthServiceTest) TestSignInCreateCredentialFailed() {}
userRepo.On("FindByEmail", t.signInRequest.Email, &model.User{}).Return(existUser, nil)
bcryptUtil.On("CompareHashedPassword", existUser.Password, t.signInRequest.Password).Return(nil)
tokenService.On("CreateCredential", existUser.ID.String(), existUser.Role).Return(credential, nil)
userRepo.On("Update", existUser.ID.String(), updateUser).Return(updateUser, nil)

func (t *AuthServiceTest) TestSignInUpdateTokenFailed() {}
authSvc := NewService(&userRepo, &tokenService, &bcryptUtil)
actual, err := authSvc.SignIn(t.ctx, t.signInRequest)

assert.Nil(t.T(), err)
assert.Equal(t.T(), expected.Credential.AccessToken, actual.Credential.AccessToken)
assert.Equal(t.T(), expected.Credential.RefreshToken, actual.Credential.RefreshToken)
}

func (t *AuthServiceTest) TestSignInUserNotFound() {
findUserErr := gorm.ErrRecordNotFound

expected := status.Error(codes.PermissionDenied, constant.IncorrectEmailPasswordErrorMessage)

userRepo := user.UserRepositoryMock{}
tokenService := token.TokenServiceMock{}
bcryptUtil := utils.BcryptUtilMock{}

userRepo.On("FindByEmail", t.signInRequest.Email, &model.User{}).Return(nil, findUserErr)

authSvc := NewService(&userRepo, &tokenService, &bcryptUtil)
actual, err := authSvc.SignIn(t.ctx, t.signInRequest)

status, ok := status.FromError(err)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.PermissionDenied, status.Code())
assert.True(t.T(), ok)
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *AuthServiceTest) TestSignInUnmatchedPassword() {
existUser := &model.User{
Base: model.Base{
ID: uuid.New(),
},
Email: t.signInRequest.Email,
Password: faker.Password(),
Firstname: faker.FirstName(),
Lastname: faker.LastName(),
Role: constant.USER,
RefreshToken: "",
}
comparePwdErr := errors.New("Unmatched password")

expected := status.Error(codes.PermissionDenied, constant.IncorrectEmailPasswordErrorMessage)

userRepo := user.UserRepositoryMock{}
tokenService := token.TokenServiceMock{}
bcryptUtil := utils.BcryptUtilMock{}

userRepo.On("FindByEmail", t.signInRequest.Email, &model.User{}).Return(existUser, nil)
bcryptUtil.On("CompareHashedPassword", existUser.Password, t.signInRequest.Password).Return(comparePwdErr)

authSvc := NewService(&userRepo, &tokenService, &bcryptUtil)
actual, err := authSvc.SignIn(t.ctx, t.signInRequest)

status, ok := status.FromError(err)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.PermissionDenied, status.Code())
assert.True(t.T(), ok)
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *AuthServiceTest) TestSignInCreateCredentialFailed() {
existUser := &model.User{
Base: model.Base{
ID: uuid.New(),
},
Email: t.signInRequest.Email,
Password: faker.Password(),
Firstname: faker.FirstName(),
Lastname: faker.LastName(),
Role: constant.USER,
RefreshToken: "",
}
createCredentialErr := errors.New("Failed to create credential")

expected := status.Error(codes.Internal, constant.InternalServerErrorMessage)

userRepo := user.UserRepositoryMock{}
tokenService := token.TokenServiceMock{}
bcryptUtil := utils.BcryptUtilMock{}

userRepo.On("FindByEmail", t.signInRequest.Email, &model.User{}).Return(existUser, nil)
bcryptUtil.On("CompareHashedPassword", existUser.Password, t.signInRequest.Password).Return(nil)
tokenService.On("CreateCredential", existUser.ID.String(), existUser.Role).Return(nil, createCredentialErr)

authSvc := NewService(&userRepo, &tokenService, &bcryptUtil)
actual, err := authSvc.SignIn(t.ctx, t.signInRequest)

status, ok := status.FromError(err)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.Internal, status.Code())
assert.True(t.T(), ok)
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *AuthServiceTest) TestSignInUpdateTokenFailed() {
existUser := &model.User{
Base: model.Base{
ID: uuid.New(),
},
Email: t.signInRequest.Email,
Password: faker.Password(),
Firstname: faker.FirstName(),
Lastname: faker.LastName(),
Role: constant.USER,
RefreshToken: "",
}
credential := &authProto.Credential{
AccessToken: faker.Word(),
RefreshToken: faker.Word(),
ExpiresIn: 3600,
}
updateUser := &model.User{
RefreshToken: credential.RefreshToken,
}
updateUserErr := errors.New("Internal server error")

expected := status.Error(codes.Internal, constant.InternalServerErrorMessage)

userRepo := user.UserRepositoryMock{}
tokenService := token.TokenServiceMock{}
bcryptUtil := utils.BcryptUtilMock{}

userRepo.On("FindByEmail", t.signInRequest.Email, &model.User{}).Return(existUser, nil)
bcryptUtil.On("CompareHashedPassword", existUser.Password, t.signInRequest.Password).Return(nil)
tokenService.On("CreateCredential", existUser.ID.String(), existUser.Role).Return(credential, nil)
userRepo.On("Update", existUser.ID.String(), updateUser).Return(nil, updateUserErr)

authSvc := NewService(&userRepo, &tokenService, &bcryptUtil)
actual, err := authSvc.SignIn(t.ctx, t.signInRequest)

status, ok := status.FromError(err)
assert.Nil(t.T(), actual)
assert.Equal(t.T(), codes.Internal, status.Code())
assert.True(t.T(), ok)
assert.Equal(t.T(), expected.Error(), err.Error())
}

func (t *AuthServiceTest) TestValidateSuccess() {}

Expand Down
10 changes: 10 additions & 0 deletions src/mocks/repository/user/user.mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ func (m *UserRepositoryMock) FindById(id string, user *model.User) error {
return args.Error(1)
}

func (m *UserRepositoryMock) FindByEmail(email string, user *model.User) error {
args := m.Called(email, user)
if args.Get(0) != nil {
*user = *args.Get(0).(*model.User)
return nil
}

return args.Error(1)
}

func (m *UserRepositoryMock) Create(user *model.User) error {
args := m.Called(user)
if args.Get(0) != nil {
Expand Down
4 changes: 2 additions & 2 deletions src/mocks/utils/bcrypt.mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ func (m *BcryptUtilMock) GenerateHashedPassword(password string) (string, error)

func (m *BcryptUtilMock) CompareHashedPassword(hashedPassword string, plainPassword string) error {
args := m.Called(hashedPassword, plainPassword)
if args.Get(0) != nil {
if args.Get(0) == nil {
return nil
}

return args.Error(1)
return args.Error(0)
}
1 change: 1 addition & 0 deletions src/pkg/repository/user/user.repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type Repository interface {
FindAll(user *[]*model.User) error
FindById(id string, user *model.User) error
FindByEmail(email string, user *model.User) error
Create(user *model.User) error
Update(id string, user *model.User) error
Delete(id string) error
Expand Down

0 comments on commit bd9b138

Please sign in to comment.