From 9afe9ae4c7ed73ba06efc9dc99b5f13fab3aaa7b Mon Sep 17 00:00:00 2001 From: NitiwatOwen Date: Wed, 3 Jan 2024 00:55:25 +0700 Subject: [PATCH 1/4] feat: implement FindRefreshTokenCache in token service --- internal/service/token/token.service.go | 15 +++++ internal/service/token/token.service_test.go | 63 ++++++++++++++++++++ mocks/service/token/token.mock.go | 9 +++ pkg/service/token/token.service.go | 1 + 4 files changed, 88 insertions(+) diff --git a/internal/service/token/token.service.go b/internal/service/token/token.service.go index bd6a016..662b033 100644 --- a/internal/service/token/token.service.go +++ b/internal/service/token/token.service.go @@ -11,6 +11,8 @@ import ( authProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/auth/v1" "github.com/pkg/errors" "github.com/redis/go-redis/v9" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "time" ) @@ -109,6 +111,19 @@ func (s *serviceImpl) CreateRefreshToken() string { return s.uuidUtil.GetNewUUID().String() } +func (s *serviceImpl) FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) { + refreshTokenCache := &tokenDto.RefreshTokenCache{} + err := s.refreshTokenCache.GetValue(refreshToken, refreshTokenCache) + if err != nil { + if err != redis.Nil { + return nil, status.Error(codes.Internal, err.Error()) + } + return nil, status.Error(codes.InvalidArgument, err.Error()) + } + + return refreshTokenCache, nil +} + func (s *serviceImpl) RemoveTokenCache(refreshToken string) error { refreshTokenCache := &tokenDto.RefreshTokenCache{} err := s.refreshTokenCache.GetValue(refreshToken, refreshTokenCache) diff --git a/internal/service/token/token.service_test.go b/internal/service/token/token.service_test.go index d16cae0..49576e6 100644 --- a/internal/service/token/token.service_test.go +++ b/internal/service/token/token.service_test.go @@ -16,6 +16,8 @@ import ( "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "testing" "time" ) @@ -424,6 +426,67 @@ func (t *TokenServiceTest) TestCreateRefreshTokenSuccess() { assert.Equal(t.T(), expected, actual) } +func (t *TokenServiceTest) TestFindRefreshTokenCacheSuccess() { + expected := &tokenDto.RefreshTokenCache{} + + controller := gomock.NewController(t.T()) + + jwtService := jwt.JwtServiceMock{} + accessTokenRepo := mock_cache.NewMockRepository(controller) + refreshTokenRepo := mock_cache.NewMockRepository(controller) + uuidUtil := utils.UuidUtilMock{} + + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(nil) + + tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) + actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + + assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) +} + +func (t *TokenServiceTest) TestFindRefreshTokenCacheInvalid() { + getCacheErr := redis.Nil + + expected := status.Error(codes.InvalidArgument, getCacheErr.Error()) + + controller := gomock.NewController(t.T()) + + jwtService := jwt.JwtServiceMock{} + accessTokenRepo := mock_cache.NewMockRepository(controller) + refreshTokenRepo := mock_cache.NewMockRepository(controller) + uuidUtil := utils.UuidUtilMock{} + + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) + + tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) + actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + +func (t *TokenServiceTest) TestFindRefreshTokenCacheInternalError() { + getCacheErr := errors.New("internal server error") + + expected := status.Error(codes.Internal, getCacheErr.Error()) + + controller := gomock.NewController(t.T()) + + jwtService := jwt.JwtServiceMock{} + accessTokenRepo := mock_cache.NewMockRepository(controller) + refreshTokenRepo := mock_cache.NewMockRepository(controller) + uuidUtil := utils.UuidUtilMock{} + + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) + + tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) + actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) +} + func (t *TokenServiceTest) TestRemoveTokenCacheSuccess() { refreshTokenCache := &tokenDto.RefreshTokenCache{} diff --git a/mocks/service/token/token.mock.go b/mocks/service/token/token.mock.go index 0be8264..a1525d1 100644 --- a/mocks/service/token/token.mock.go +++ b/mocks/service/token/token.mock.go @@ -34,6 +34,15 @@ func (m *TokenServiceMock) CreateRefreshToken() string { return args.Get(0).(string) } +func (m *TokenServiceMock) FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) { + args := m.Called(refreshToken) + if args.Get(0) != nil { + return args.Get(0).(*tokenDto.RefreshTokenCache), nil + } + + return nil, args.Error(1) +} + func (m *TokenServiceMock) RemoveTokenCache(refreshToken string) error { args := m.Called(refreshToken) return args.Error(0) diff --git a/pkg/service/token/token.service.go b/pkg/service/token/token.service.go index 9e2921a..96d6aae 100644 --- a/pkg/service/token/token.service.go +++ b/pkg/service/token/token.service.go @@ -10,5 +10,6 @@ type Service interface { CreateCredential(userId string, role constant.Role, authSessionId string) (*authProto.Credential, error) Validate(token string) (*tokenDto.UserCredential, error) CreateRefreshToken() string + FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) RemoveTokenCache(refreshToken string) error } From 44b804b15b032a2186f04c710cf72125b27c15b3 Mon Sep 17 00:00:00 2001 From: NitiwatOwen Date: Wed, 3 Jan 2024 01:15:29 +0700 Subject: [PATCH 2/4] feat: implement RefreshToken service --- internal/service/auth/auth.service.go | 50 ++++--- internal/service/auth/auth.service_test.go | 163 +++++++++++++++++++-- 2 files changed, 186 insertions(+), 27 deletions(-) diff --git a/internal/service/auth/auth.service.go b/internal/service/auth/auth.service.go index d6bd0b2..4317539 100644 --- a/internal/service/auth/auth.service.go +++ b/internal/service/auth/auth.service.go @@ -9,7 +9,6 @@ import ( "github.com/isd-sgcu/johnjud-auth/pkg/repository/user" "github.com/isd-sgcu/johnjud-auth/pkg/service/token" - "github.com/google/uuid" authProto "github.com/isd-sgcu/johnjud-go-proto/johnjud/auth/auth/v1" "github.com/pkg/errors" "google.golang.org/grpc/codes" @@ -47,10 +46,29 @@ func (s *serviceImpl) Validate(_ context.Context, request *authProto.ValidateReq } func (s *serviceImpl) RefreshToken(_ context.Context, request *authProto.RefreshTokenRequest) (*authProto.RefreshTokenResponse, error) { - // find user with refreshToken - // create new Credential - // update refreshToken in db - return nil, nil + refreshTokenCache, err := s.tokenService.FindRefreshTokenCache(request.RefreshToken) + if err != nil { + st, _ := status.FromError(err) + switch st.Code() { + case codes.InvalidArgument: + return nil, status.Error(codes.InvalidArgument, constant.InvalidTokenErrorMessage) + default: + return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) + } + } + credential, err := s.tokenService.CreateCredential(refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID) + if err != nil { + return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) + } + + err = s.tokenService.RemoveTokenCache(request.RefreshToken) + if err != nil { + return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) + } + + return &authProto.RefreshTokenResponse{ + Credential: credential, + }, nil } func (s *serviceImpl) SignUp(_ context.Context, request *authProto.SignUpRequest) (*authProto.SignUpResponse, error) { @@ -94,7 +112,15 @@ func (s *serviceImpl) SignIn(_ context.Context, request *authProto.SignInRequest return nil, status.Error(codes.PermissionDenied, constant.IncorrectEmailPasswordErrorMessage) } - credential, err := s.createAuthSession(user.ID, user.Role) + createAuthSession := &model.AuthSession{ + UserID: user.ID, + } + err = s.authRepo.Create(createAuthSession) + if err != nil { + return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) + } + + credential, err := s.tokenService.CreateCredential(user.ID.String(), user.Role, createAuthSession.ID.String()) if err != nil { return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) } @@ -120,15 +146,3 @@ func (s *serviceImpl) SignOut(_ context.Context, request *authProto.SignOutReque return &authProto.SignOutResponse{IsSuccess: true}, nil } - -func (s *serviceImpl) createAuthSession(userId uuid.UUID, role constant.Role) (*authProto.Credential, error) { - createAuthSession := &model.AuthSession{ - UserID: userId, - } - err := s.authRepo.Create(createAuthSession) - if err != nil { - return nil, errors.New("Internal server error") - } - - return s.tokenService.CreateCredential(userId.String(), role, createAuthSession.ID.String()) -} diff --git a/internal/service/auth/auth.service_test.go b/internal/service/auth/auth.service_test.go index d31eba9..676a615 100644 --- a/internal/service/auth/auth.service_test.go +++ b/internal/service/auth/auth.service_test.go @@ -26,11 +26,12 @@ import ( type AuthServiceTest struct { suite.Suite - ctx context.Context - signupRequest *authProto.SignUpRequest - signInRequest *authProto.SignInRequest - signOutRequest *authProto.SignOutRequest - validateRequest *authProto.ValidateRequest + ctx context.Context + signupRequest *authProto.SignUpRequest + signInRequest *authProto.SignInRequest + signOutRequest *authProto.SignOutRequest + refreshTokenRequest *authProto.RefreshTokenRequest + validateRequest *authProto.ValidateRequest } func TestAuthService(t *testing.T) { @@ -55,12 +56,16 @@ func (t *AuthServiceTest) SetupTest() { validateRequest := &authProto.ValidateRequest{ Token: faker.Word(), } + refreshTokenRequest := &authProto.RefreshTokenRequest{ + RefreshToken: faker.UUIDDigit(), + } t.ctx = ctx t.signupRequest = signupRequest t.signInRequest = signInRequest t.signOutRequest = signOutRequest t.validateRequest = validateRequest + t.refreshTokenRequest = refreshTokenRequest } func (t *AuthServiceTest) TestSignupSuccess() { @@ -434,13 +439,153 @@ func (t *AuthServiceTest) TestValidateFailed() { assert.Equal(t.T(), expected.Error(), err.Error()) } -func (t *AuthServiceTest) TestRefreshTokenSuccess() {} +func (t *AuthServiceTest) TestRefreshTokenSuccess() { + refreshTokenCache := &tokenDto.RefreshTokenCache{ + AuthSessionID: faker.UUIDDigit(), + UserID: faker.UUIDDigit(), + Role: constant.USER, + } + credential := &authProto.Credential{ + AccessToken: faker.Word(), + RefreshToken: faker.UUIDDigit(), + ExpiresIn: 3600, + } + + expected := &authProto.RefreshTokenResponse{ + Credential: credential, + } + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} + + tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(refreshTokenCache, nil) + tokenService.On("CreateCredential", refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID).Return(credential, nil) + tokenService.On("RemoveTokenCache", t.refreshTokenRequest.RefreshToken).Return(nil) + + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) + + assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) +} + +func (t *AuthServiceTest) TestRefreshTokenInvalid() { + findTokenErr := status.Error(codes.InvalidArgument, "token not found") + + expected := status.Error(codes.InvalidArgument, constant.InvalidTokenErrorMessage) + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} + + tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(nil, findTokenErr) + + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) + + st, ok := status.FromError(err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), codes.InvalidArgument, st.Code()) + assert.True(t.T(), ok) + assert.Equal(t.T(), expected.Error(), err.Error()) +} + +func (t *AuthServiceTest) TestRefreshTokenFindTokenFailed() { + findTokenErr := status.Error(codes.Internal, "internal error") + + expected := status.Error(codes.Internal, constant.InternalServerErrorMessage) + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} + + tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(nil, findTokenErr) + + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) + + st, ok := status.FromError(err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), codes.Internal, st.Code()) + assert.True(t.T(), ok) + assert.Equal(t.T(), expected.Error(), err.Error()) +} + +func (t *AuthServiceTest) TestRefreshTokenCreateCredentialFailed() { + refreshTokenCache := &tokenDto.RefreshTokenCache{ + AuthSessionID: faker.UUIDDigit(), + UserID: faker.UUIDDigit(), + Role: constant.USER, + } + createCredentialErr := errors.New("internal error") + + expected := status.Error(codes.Internal, constant.InternalServerErrorMessage) + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} + + tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(refreshTokenCache, nil) + tokenService.On("CreateCredential", refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID).Return(nil, createCredentialErr) + + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) + + st, ok := status.FromError(err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), codes.Internal, st.Code()) + assert.True(t.T(), ok) + assert.Equal(t.T(), expected.Error(), err.Error()) +} + +func (t *AuthServiceTest) TestRefreshTokenRemoveTokenFailed() { + refreshTokenCache := &tokenDto.RefreshTokenCache{ + AuthSessionID: faker.UUIDDigit(), + UserID: faker.UUIDDigit(), + Role: constant.USER, + } + credential := &authProto.Credential{ + AccessToken: faker.Word(), + RefreshToken: faker.UUIDDigit(), + ExpiresIn: 3600, + } + removeTokenErr := errors.New("internal error") + + expected := status.Error(codes.Internal, constant.InternalServerErrorMessage) + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} -func (t *AuthServiceTest) TestRefreshTokenNotFound() {} + tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(refreshTokenCache, nil) + tokenService.On("CreateCredential", refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID).Return(credential, nil) + tokenService.On("RemoveTokenCache", t.refreshTokenRequest.RefreshToken).Return(removeTokenErr) -func (t *AuthServiceTest) TestRefreshTokenCreateCredentialFailed() {} + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) -func (t *AuthServiceTest) TestRefreshTokenUpdateTokenFailed() {} + st, ok := status.FromError(err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), codes.Internal, st.Code()) + assert.True(t.T(), ok) + assert.Equal(t.T(), expected.Error(), err.Error()) +} func (t *AuthServiceTest) TestSignOutSuccess() { userCredential := &tokenDto.UserCredential{ From b1258d142ffc1294bfba1f0f65106d9fb77fa08d Mon Sep 17 00:00:00 2001 From: NitiwatOwen Date: Wed, 3 Jan 2024 01:35:51 +0700 Subject: [PATCH 3/4] feat: separate RemoveToken method --- internal/service/token/token.service.go | 27 ++--- internal/service/token/token.service_test.go | 103 +++++++------------ pkg/service/token/token.service.go | 3 +- 3 files changed, 48 insertions(+), 85 deletions(-) diff --git a/internal/service/token/token.service.go b/internal/service/token/token.service.go index 662b033..ea4dee7 100644 --- a/internal/service/token/token.service.go +++ b/internal/service/token/token.service.go @@ -111,37 +111,32 @@ func (s *serviceImpl) CreateRefreshToken() string { return s.uuidUtil.GetNewUUID().String() } -func (s *serviceImpl) FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - err := s.refreshTokenCache.GetValue(refreshToken, refreshTokenCache) +func (s *serviceImpl) RemoveAccessTokenCache(authSessionId string) error { + err := s.accessTokenCache.DeleteValue(authSessionId) if err != nil { if err != redis.Nil { - return nil, status.Error(codes.Internal, err.Error()) + return err } - return nil, status.Error(codes.InvalidArgument, err.Error()) } - return refreshTokenCache, nil + return nil } -func (s *serviceImpl) RemoveTokenCache(refreshToken string) error { +func (s *serviceImpl) FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) { refreshTokenCache := &tokenDto.RefreshTokenCache{} err := s.refreshTokenCache.GetValue(refreshToken, refreshTokenCache) if err != nil { if err != redis.Nil { - return err + return nil, status.Error(codes.Internal, err.Error()) } - return nil + return nil, status.Error(codes.InvalidArgument, err.Error()) } - err = s.refreshTokenCache.DeleteValue(refreshToken) - if err != nil { - if err != redis.Nil { - return err - } - } + return refreshTokenCache, nil +} - err = s.accessTokenCache.DeleteValue(refreshTokenCache.AuthSessionID) +func (s *serviceImpl) RemoveRefreshTokenCache(refreshToken string) error { + err := s.refreshTokenCache.DeleteValue(refreshToken) if err != nil { if err != redis.Nil { return err diff --git a/internal/service/token/token.service_test.go b/internal/service/token/token.service_test.go index 49576e6..a0e0255 100644 --- a/internal/service/token/token.service_test.go +++ b/internal/service/token/token.service_test.go @@ -426,9 +426,7 @@ func (t *TokenServiceTest) TestCreateRefreshTokenSuccess() { assert.Equal(t.T(), expected, actual) } -func (t *TokenServiceTest) TestFindRefreshTokenCacheSuccess() { - expected := &tokenDto.RefreshTokenCache{} - +func (t *TokenServiceTest) TestRemoveAccessTokenCacheSuccess() { controller := gomock.NewController(t.T()) jwtService := jwt.JwtServiceMock{} @@ -436,19 +434,18 @@ func (t *TokenServiceTest) TestFindRefreshTokenCacheSuccess() { refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(nil) + accessTokenRepo.EXPECT().DeleteValue(t.authSessionId).Return(nil) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + err := tokenSvc.RemoveAccessTokenCache(t.authSessionId) assert.Nil(t.T(), err) - assert.Equal(t.T(), expected, actual) } -func (t *TokenServiceTest) TestFindRefreshTokenCacheInvalid() { - getCacheErr := redis.Nil +func (t *TokenServiceTest) TestRemoveAccessTokenCacheDeleteInternalFailed() { + deleteAccessTokenCacheErr := errors.New("internal server error") - expected := status.Error(codes.InvalidArgument, getCacheErr.Error()) + expected := deleteAccessTokenCacheErr controller := gomock.NewController(t.T()) @@ -457,19 +454,16 @@ func (t *TokenServiceTest) TestFindRefreshTokenCacheInvalid() { refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) + accessTokenRepo.EXPECT().DeleteValue(t.authSessionId).Return(deleteAccessTokenCacheErr) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + err := tokenSvc.RemoveAccessTokenCache(t.authSessionId) - assert.Nil(t.T(), actual) assert.Equal(t.T(), expected, err) } -func (t *TokenServiceTest) TestFindRefreshTokenCacheInternalError() { - getCacheErr := errors.New("internal server error") - - expected := status.Error(codes.Internal, getCacheErr.Error()) +func (t *TokenServiceTest) TestFindRefreshTokenCacheSuccess() { + expected := &tokenDto.RefreshTokenCache{} controller := gomock.NewController(t.T()) @@ -478,38 +472,19 @@ func (t *TokenServiceTest) TestFindRefreshTokenCacheInternalError() { refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(nil) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) - assert.Nil(t.T(), actual) - assert.Equal(t.T(), expected, err) -} - -func (t *TokenServiceTest) TestRemoveTokenCacheSuccess() { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - - controller := gomock.NewController(t.T()) - - jwtService := jwt.JwtServiceMock{} - accessTokenRepo := mock_cache.NewMockRepository(controller) - refreshTokenRepo := mock_cache.NewMockRepository(controller) - uuidUtil := utils.UuidUtilMock{} - - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), refreshTokenCache).Return(nil) - refreshTokenRepo.EXPECT().DeleteValue(t.refreshToken.String()).Return(nil) - accessTokenRepo.EXPECT().DeleteValue(refreshTokenCache.AuthSessionID).Return(nil) - - tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - err := tokenSvc.RemoveTokenCache(t.refreshToken.String()) - assert.Nil(t.T(), err) + assert.Equal(t.T(), expected, actual) } -func (t *TokenServiceTest) TestRemoveTokenCacheGetRefreshTokenNotFound() { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - getRefreshTokenCacheErr := redis.Nil +func (t *TokenServiceTest) TestFindRefreshTokenCacheInvalid() { + getCacheErr := redis.Nil + + expected := status.Error(codes.InvalidArgument, getCacheErr.Error()) controller := gomock.NewController(t.T()) @@ -518,19 +493,19 @@ func (t *TokenServiceTest) TestRemoveTokenCacheGetRefreshTokenNotFound() { refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), refreshTokenCache).Return(getRefreshTokenCacheErr) + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - err := tokenSvc.RemoveTokenCache(t.refreshToken.String()) + actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) - assert.Nil(t.T(), err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), expected, err) } -func (t *TokenServiceTest) TestRemoveTokenCacheGetRefreshTokenInternalFailed() { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - getRefreshTokenCacheErr := errors.New("internal server error") +func (t *TokenServiceTest) TestFindRefreshTokenCacheInternalError() { + getCacheErr := errors.New("internal server error") - expected := getRefreshTokenCacheErr + expected := status.Error(codes.Internal, getCacheErr.Error()) controller := gomock.NewController(t.T()) @@ -539,20 +514,16 @@ func (t *TokenServiceTest) TestRemoveTokenCacheGetRefreshTokenInternalFailed() { refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), refreshTokenCache).Return(getRefreshTokenCacheErr) + refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), &tokenDto.RefreshTokenCache{}).Return(getCacheErr) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - err := tokenSvc.RemoveTokenCache(t.refreshToken.String()) + actual, err := tokenSvc.FindRefreshTokenCache(t.refreshToken.String()) + assert.Nil(t.T(), actual) assert.Equal(t.T(), expected, err) } -func (t *TokenServiceTest) TestRemoveTokenCacheDeleteRefreshTokenInternalFailed() { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - deleteRefreshTokenCacheErr := errors.New("internal server error") - - expected := deleteRefreshTokenCacheErr - +func (t *TokenServiceTest) TestRemoveRefreshTokenCacheSuccess() { controller := gomock.NewController(t.T()) jwtService := jwt.JwtServiceMock{} @@ -560,20 +531,18 @@ func (t *TokenServiceTest) TestRemoveTokenCacheDeleteRefreshTokenInternalFailed( refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), refreshTokenCache).Return(nil) - refreshTokenRepo.EXPECT().DeleteValue(t.refreshToken.String()).Return(deleteRefreshTokenCacheErr) + refreshTokenRepo.EXPECT().DeleteValue(t.refreshToken.String()).Return(nil) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - err := tokenSvc.RemoveTokenCache(t.refreshToken.String()) + err := tokenSvc.RemoveRefreshTokenCache(t.refreshToken.String()) - assert.Equal(t.T(), expected, err) + assert.Nil(t.T(), err) } -func (t *TokenServiceTest) TestRemoveTokenCacheDeleteAccessTokenInternalFailed() { - refreshTokenCache := &tokenDto.RefreshTokenCache{} - deleteAccessTokenCacheErr := errors.New("internal server error") +func (t *TokenServiceTest) TestRemoveRefreshTokenCacheDeleteInternalFailed() { + deleteRefreshTokenCacheErr := errors.New("internal server error") - expected := deleteAccessTokenCacheErr + expected := deleteRefreshTokenCacheErr controller := gomock.NewController(t.T()) @@ -582,12 +551,10 @@ func (t *TokenServiceTest) TestRemoveTokenCacheDeleteAccessTokenInternalFailed() refreshTokenRepo := mock_cache.NewMockRepository(controller) uuidUtil := utils.UuidUtilMock{} - refreshTokenRepo.EXPECT().GetValue(t.refreshToken.String(), refreshTokenCache).Return(nil) - refreshTokenRepo.EXPECT().DeleteValue(t.refreshToken.String()).Return(nil) - accessTokenRepo.EXPECT().DeleteValue(refreshTokenCache.AuthSessionID).Return(deleteAccessTokenCacheErr) + refreshTokenRepo.EXPECT().DeleteValue(t.refreshToken.String()).Return(deleteRefreshTokenCacheErr) tokenSvc := NewService(&jwtService, accessTokenRepo, refreshTokenRepo, &uuidUtil) - err := tokenSvc.RemoveTokenCache(t.refreshToken.String()) + err := tokenSvc.RemoveRefreshTokenCache(t.refreshToken.String()) assert.Equal(t.T(), expected, err) } diff --git a/pkg/service/token/token.service.go b/pkg/service/token/token.service.go index 96d6aae..7ba74b3 100644 --- a/pkg/service/token/token.service.go +++ b/pkg/service/token/token.service.go @@ -10,6 +10,7 @@ type Service interface { CreateCredential(userId string, role constant.Role, authSessionId string) (*authProto.Credential, error) Validate(token string) (*tokenDto.UserCredential, error) CreateRefreshToken() string + RemoveAccessTokenCache(authSessionId string) error FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) - RemoveTokenCache(refreshToken string) error + RemoveRefreshTokenCache(refreshToken string) error } From 12e82d8609c66f2b0e75d03ae1a1bad93acdd52d Mon Sep 17 00:00:00 2001 From: NitiwatOwen Date: Wed, 3 Jan 2024 01:41:37 +0700 Subject: [PATCH 4/4] feat: update auth service --- internal/service/auth/auth.service.go | 9 ++++- internal/service/auth/auth.service_test.go | 46 +++++++++++++++++++--- mocks/service/token/token.mock.go | 7 +++- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/internal/service/auth/auth.service.go b/internal/service/auth/auth.service.go index 4317539..2695458 100644 --- a/internal/service/auth/auth.service.go +++ b/internal/service/auth/auth.service.go @@ -61,7 +61,7 @@ func (s *serviceImpl) RefreshToken(_ context.Context, request *authProto.Refresh return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) } - err = s.tokenService.RemoveTokenCache(request.RefreshToken) + err = s.tokenService.RemoveRefreshTokenCache(request.RefreshToken) if err != nil { return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) } @@ -134,7 +134,12 @@ func (s *serviceImpl) SignOut(_ context.Context, request *authProto.SignOutReque return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) } - err = s.tokenService.RemoveTokenCache(userCredential.RefreshToken) + err = s.tokenService.RemoveRefreshTokenCache(userCredential.RefreshToken) + if err != nil { + return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) + } + + err = s.tokenService.RemoveAccessTokenCache(userCredential.AuthSessionID) if err != nil { return nil, status.Error(codes.Internal, constant.InternalServerErrorMessage) } diff --git a/internal/service/auth/auth.service_test.go b/internal/service/auth/auth.service_test.go index 676a615..bd9325f 100644 --- a/internal/service/auth/auth.service_test.go +++ b/internal/service/auth/auth.service_test.go @@ -464,7 +464,7 @@ func (t *AuthServiceTest) TestRefreshTokenSuccess() { tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(refreshTokenCache, nil) tokenService.On("CreateCredential", refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID).Return(credential, nil) - tokenService.On("RemoveTokenCache", t.refreshTokenRequest.RefreshToken).Return(nil) + tokenService.On("RemoveRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(nil) authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) @@ -575,7 +575,7 @@ func (t *AuthServiceTest) TestRefreshTokenRemoveTokenFailed() { tokenService.On("FindRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(refreshTokenCache, nil) tokenService.On("CreateCredential", refreshTokenCache.UserID, refreshTokenCache.Role, refreshTokenCache.AuthSessionID).Return(credential, nil) - tokenService.On("RemoveTokenCache", t.refreshTokenRequest.RefreshToken).Return(removeTokenErr) + tokenService.On("RemoveRefreshTokenCache", t.refreshTokenRequest.RefreshToken).Return(removeTokenErr) authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) actual, err := authSvc.RefreshToken(t.ctx, t.refreshTokenRequest) @@ -607,7 +607,8 @@ func (t *AuthServiceTest) TestSignOutSuccess() { bcryptUtil := utils.BcryptUtilMock{} tokenService.On("Validate", t.signOutRequest.Token).Return(userCredential, nil) - tokenService.On("RemoveTokenCache", userCredential.RefreshToken).Return(nil) + tokenService.On("RemoveRefreshTokenCache", userCredential.RefreshToken).Return(nil) + tokenService.On("RemoveAccessTokenCache", userCredential.AuthSessionID).Return(nil) authRepo.EXPECT().Delete(userCredential.AuthSessionID).Return(nil) authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) @@ -639,7 +640,7 @@ func (t *AuthServiceTest) TestSignOutValidateFailed() { assert.Equal(t.T(), expected.Error(), err.Error()) } -func (t *AuthServiceTest) TestSignOutRemoveTokenCacheFailed() { +func (t *AuthServiceTest) TestSignOutRemoveRefreshTokenCacheFailed() { userCredential := &tokenDto.UserCredential{ UserID: faker.UUIDDigit(), Role: constant.USER, @@ -658,7 +659,39 @@ func (t *AuthServiceTest) TestSignOutRemoveTokenCacheFailed() { bcryptUtil := utils.BcryptUtilMock{} tokenService.On("Validate", t.signOutRequest.Token).Return(userCredential, nil) - tokenService.On("RemoveTokenCache", userCredential.RefreshToken).Return(removeTokenErr) + tokenService.On("RemoveRefreshTokenCache", userCredential.RefreshToken).Return(removeTokenErr) + + authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) + actual, err := authSvc.SignOut(t.ctx, t.signOutRequest) + + st, ok := status.FromError(err) + assert.Nil(t.T(), actual) + assert.Equal(t.T(), codes.Internal, st.Code()) + assert.True(t.T(), ok) + assert.Equal(t.T(), expected.Error(), err.Error()) +} + +func (t *AuthServiceTest) TestSignOutRemoveAccessTokenCacheFailed() { + userCredential := &tokenDto.UserCredential{ + UserID: faker.UUIDDigit(), + Role: constant.USER, + AuthSessionID: faker.UUIDDigit(), + RefreshToken: faker.UUIDDigit(), + } + removeTokenErr := errors.New("internal server error") + + expected := status.Error(codes.Internal, constant.InternalServerErrorMessage) + + controller := gomock.NewController(t.T()) + + authRepo := mock_auth.NewMockRepository(controller) + userRepo := user.UserRepositoryMock{} + tokenService := token.TokenServiceMock{} + bcryptUtil := utils.BcryptUtilMock{} + + tokenService.On("Validate", t.signOutRequest.Token).Return(userCredential, nil) + tokenService.On("RemoveRefreshTokenCache", userCredential.RefreshToken).Return(nil) + tokenService.On("RemoveAccessTokenCache", userCredential.AuthSessionID).Return(removeTokenErr) authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) actual, err := authSvc.SignOut(t.ctx, t.signOutRequest) @@ -689,7 +722,8 @@ func (t *AuthServiceTest) TestSignOutDeleteAuthSessionFailed() { bcryptUtil := utils.BcryptUtilMock{} tokenService.On("Validate", t.signOutRequest.Token).Return(userCredential, nil) - tokenService.On("RemoveTokenCache", userCredential.RefreshToken).Return(nil) + tokenService.On("RemoveRefreshTokenCache", userCredential.RefreshToken).Return(nil) + tokenService.On("RemoveAccessTokenCache", userCredential.AuthSessionID).Return(nil) authRepo.EXPECT().Delete(userCredential.AuthSessionID).Return(deleteAuthErr) authSvc := NewService(authRepo, &userRepo, &tokenService, &bcryptUtil) diff --git a/mocks/service/token/token.mock.go b/mocks/service/token/token.mock.go index a1525d1..df64d75 100644 --- a/mocks/service/token/token.mock.go +++ b/mocks/service/token/token.mock.go @@ -34,6 +34,11 @@ func (m *TokenServiceMock) CreateRefreshToken() string { return args.Get(0).(string) } +func (m *TokenServiceMock) RemoveAccessTokenCache(authSessionId string) error { + args := m.Called(authSessionId) + return args.Error(0) +} + func (m *TokenServiceMock) FindRefreshTokenCache(refreshToken string) (*tokenDto.RefreshTokenCache, error) { args := m.Called(refreshToken) if args.Get(0) != nil { @@ -43,7 +48,7 @@ func (m *TokenServiceMock) FindRefreshTokenCache(refreshToken string) (*tokenDto return nil, args.Error(1) } -func (m *TokenServiceMock) RemoveTokenCache(refreshToken string) error { +func (m *TokenServiceMock) RemoveRefreshTokenCache(refreshToken string) error { args := m.Called(refreshToken) return args.Error(0) }