281 lines
7.4 KiB
Go
281 lines
7.4 KiB
Go
package auth
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"cardverse/config"
|
|
"cardverse/internal/modules/user"
|
|
"cardverse/internal/pkg/utils"
|
|
)
|
|
|
|
func setupTestConfig() {
|
|
config.Cfg = &config.Config{
|
|
JWTSecret: "test-secret-key",
|
|
JWTExpiresHours: 1,
|
|
JWTRefreshSecret: "test-refresh-secret-key",
|
|
JWTRefreshExpiresHours: 168,
|
|
}
|
|
}
|
|
|
|
func TestService_Register_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return nil, errors.New("record not found")
|
|
},
|
|
createFunc: func(u *user.User) error {
|
|
u.ID = 1
|
|
return nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
req := RegisterRequest{
|
|
Name: "User Test",
|
|
Email: "register@mail.com",
|
|
Password: "password123",
|
|
ConfirmPassword: "password123",
|
|
}
|
|
u, token, err := svc.Register(req)
|
|
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got: %v", err)
|
|
}
|
|
if token == "" {
|
|
t.Error("verification token should not be empty")
|
|
}
|
|
if u.Status != user.StatusUnverified {
|
|
t.Errorf("expected status 'unverified', got: %s", u.Status)
|
|
}
|
|
}
|
|
|
|
func TestService_Register_PasswordMismatch(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
userRepo := &mockUserRepository{}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
req := RegisterRequest{
|
|
Name: "User Test",
|
|
Email: "mismatch@mail.com",
|
|
Password: "password123",
|
|
ConfirmPassword: "differentpassword",
|
|
}
|
|
_, _, err := svc.Register(req)
|
|
|
|
if !errors.Is(err, ErrPasswordMismatch) {
|
|
t.Fatalf("expected ErrPasswordMismatch, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestService_Register_EmailAlreadyExists(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return &user.User{ID: 1, Email: email}, nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
req := RegisterRequest{
|
|
Name: "User Test",
|
|
Email: "existing@mail.com",
|
|
Password: "password123",
|
|
ConfirmPassword: "password123",
|
|
}
|
|
_, _, err := svc.Register(req)
|
|
|
|
if !errors.Is(err, ErrEmailAlreadyExists) {
|
|
t.Fatalf("expected ErrEmailAlreadyExists, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestService_Login_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
hashedPassword, _ := utils.HashPassword("rahasia123")
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return &user.User{ID: 1, Name: "Budi", Email: email, Password: hashedPassword, Role: user.RoleUser, Status: user.StatusActive}, nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{
|
|
createRefreshTokenFunc: func(token *RefreshToken) error {
|
|
return nil
|
|
},
|
|
}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
result, err := svc.Login(LoginRequest{Email: "budi@mail.com", Password: "rahasia123"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got: %v", err)
|
|
}
|
|
if result.AccessToken == "" {
|
|
t.Error("access_token should not be empty")
|
|
}
|
|
if result.RefreshToken == "" {
|
|
t.Error("refresh_token should not be empty")
|
|
}
|
|
if result.User.Email != "budi@mail.com" {
|
|
t.Errorf("expected email budi@mail.com, got %s", result.User.Email)
|
|
}
|
|
}
|
|
|
|
func TestService_Login_SuspendedAccount(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
hashedPassword, _ := utils.HashPassword("rahasia123")
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return &user.User{ID: 1, Name: "Budi", Email: email, Password: hashedPassword, Status: user.StatusSuspended}, nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
_, err := svc.Login(LoginRequest{Email: "budi@mail.com", Password: "rahasia123"})
|
|
|
|
if !errors.Is(err, ErrAccountSuspended) {
|
|
t.Fatalf("expected ErrAccountSuspended, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestService_Login_InvalidPassword(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
hashedPassword, _ := utils.HashPassword("rahasia123")
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return &user.User{ID: 1, Email: email, Password: hashedPassword}, nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
_, err := svc.Login(LoginRequest{Email: "budi@mail.com", Password: "wrong_password"})
|
|
|
|
if !errors.Is(err, ErrInvalidCredentials) {
|
|
t.Fatalf("expected ErrInvalidCredentials, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestService_RefreshToken_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
validRefreshToken, _ := utils.GenerateRefreshToken(42)
|
|
|
|
userRepo := &mockUserRepository{
|
|
findByIDFunc: func(id uint) (*user.User, error) {
|
|
return &user.User{ID: 42, Email: "test@mail.com", Role: user.RoleUser, Status: user.StatusActive}, nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{
|
|
findByTokenFunc: func(token string) (*RefreshToken, error) {
|
|
return &RefreshToken{
|
|
UserID: 42,
|
|
Token: token,
|
|
ExpiresAt: time.Now().Add(1 * time.Hour),
|
|
}, nil
|
|
},
|
|
}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
res, err := svc.RefreshToken(RefreshTokenRequest{RefreshToken: validRefreshToken})
|
|
if err != nil {
|
|
t.Fatalf("RefreshToken expected no error, got: %v", err)
|
|
}
|
|
if res.AccessToken == "" || res.RefreshToken == "" {
|
|
t.Error("new access_token and refresh_token should not be empty")
|
|
}
|
|
}
|
|
|
|
func TestService_Logout_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
deleted := false
|
|
authRepo := &mockAuthRepository{
|
|
deleteByTokenFunc: func(token string) error {
|
|
deleted = true
|
|
return nil
|
|
},
|
|
}
|
|
svc := NewService(&mockUserRepository{}, authRepo)
|
|
|
|
err := svc.Logout("token-to-delete")
|
|
if err != nil {
|
|
t.Fatalf("Logout expected no error, got: %v", err)
|
|
}
|
|
if !deleted {
|
|
t.Error("deleteByTokenFunc should have been called")
|
|
}
|
|
}
|
|
|
|
func TestService_VerifyEmail_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
userRepo := &mockUserRepository{
|
|
findByVerificationTokenFunc: func(token string) (*user.User, error) {
|
|
return &user.User{ID: 1, Status: user.StatusUnverified, IsEmailVerified: false, VerificationToken: token}, nil
|
|
},
|
|
updateFunc: func(u *user.User) error {
|
|
return nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
err := svc.VerifyEmail("valid-token")
|
|
if err != nil {
|
|
t.Fatalf("expected no error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestService_ForgotPassword_AndResetPassword_Success(t *testing.T) {
|
|
setupTestConfig()
|
|
|
|
var storedToken string
|
|
userRepo := &mockUserRepository{
|
|
findByEmailFunc: func(email string) (*user.User, error) {
|
|
return &user.User{ID: 1, Email: email}, nil
|
|
},
|
|
findByResetTokenFunc: func(token string) (*user.User, error) {
|
|
expiry := time.Now().Add(1 * time.Hour)
|
|
return &user.User{ID: 1, ResetPasswordToken: token, ResetPasswordExpiresAt: &expiry}, nil
|
|
},
|
|
updateFunc: func(u *user.User) error {
|
|
storedToken = u.ResetPasswordToken
|
|
return nil
|
|
},
|
|
}
|
|
authRepo := &mockAuthRepository{}
|
|
svc := NewService(userRepo, authRepo)
|
|
|
|
resetToken, err := svc.ForgotPassword("user@mail.com")
|
|
if err != nil {
|
|
t.Fatalf("ForgotPassword expected no error, got: %v", err)
|
|
}
|
|
if resetToken == "" {
|
|
t.Fatal("resetToken should not be empty")
|
|
}
|
|
if storedToken != resetToken {
|
|
t.Errorf("expected storedToken to be %s, got %s", resetToken, storedToken)
|
|
}
|
|
|
|
err = svc.ResetPassword(ResetPasswordRequest{
|
|
Token: resetToken,
|
|
NewPassword: "newpassword123",
|
|
ConfirmNewPassword: "newpassword123",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResetPassword expected no error, got: %v", err)
|
|
}
|
|
}
|