286 lines
7.1 KiB
Go
286 lines
7.1 KiB
Go
package service_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/user-management-system/internal/domain"
|
|
"github.com/user-management-system/internal/service"
|
|
)
|
|
|
|
// =============================================================================
|
|
// Auth Login Tests - Phase 1
|
|
// =============================================================================
|
|
|
|
func TestAuthService_Login(t *testing.T) {
|
|
env := setupAuthTestEnv(t)
|
|
if env == nil {
|
|
return
|
|
}
|
|
ctx := context.Background()
|
|
|
|
t.Run("Login success", func(t *testing.T) {
|
|
// Register user first
|
|
req := &service.RegisterRequest{
|
|
Username: "loginuser",
|
|
Password: "Test123!",
|
|
Email: "login@test.com",
|
|
}
|
|
_, err := env.authSvc.Register(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("Register failed: %v", err)
|
|
}
|
|
|
|
// Login
|
|
resp, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "loginuser",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err != nil {
|
|
t.Fatalf("Login failed: %v", err)
|
|
}
|
|
if resp.AccessToken == "" {
|
|
t.Error("Expected access token")
|
|
}
|
|
if resp.User.Username != "loginuser" {
|
|
t.Errorf("Expected username 'loginuser', got %s", resp.User.Username)
|
|
}
|
|
})
|
|
|
|
t.Run("Login with wrong password", func(t *testing.T) {
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "loginuser",
|
|
Password: "wrongpassword",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for wrong password")
|
|
}
|
|
})
|
|
|
|
t.Run("Login with non-existent user", func(t *testing.T) {
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "nonexistent",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for non-existent user")
|
|
}
|
|
})
|
|
|
|
t.Run("Login with empty username", func(t *testing.T) {
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for empty username")
|
|
}
|
|
})
|
|
|
|
t.Run("Login with empty password", func(t *testing.T) {
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "loginuser",
|
|
Password: "",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for empty password")
|
|
}
|
|
})
|
|
|
|
t.Run("Login with nil request", func(t *testing.T) {
|
|
_, err := env.authSvc.Login(ctx, nil, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for nil request")
|
|
}
|
|
})
|
|
|
|
t.Run("Login for locked user", func(t *testing.T) {
|
|
// Register and lock user
|
|
req := &service.RegisterRequest{
|
|
Username: "lockeduser",
|
|
Password: "Test123!",
|
|
}
|
|
resp, _ := env.authSvc.Register(ctx, req)
|
|
env.userSvc.UpdateStatus(ctx, resp.ID, domain.UserStatusLocked)
|
|
|
|
// Try to login
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "lockeduser",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for locked user")
|
|
}
|
|
})
|
|
|
|
t.Run("Login for disabled user", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "disableduser",
|
|
Password: "Test123!",
|
|
}
|
|
resp, _ := env.authSvc.Register(ctx, req)
|
|
env.userSvc.UpdateStatus(ctx, resp.ID, domain.UserStatusDisabled)
|
|
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "disableduser",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for disabled user")
|
|
}
|
|
})
|
|
|
|
t.Run("Login for inactive user", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "inactiveuser",
|
|
Password: "Test123!",
|
|
}
|
|
resp, _ := env.authSvc.Register(ctx, req)
|
|
env.userSvc.UpdateStatus(ctx, resp.ID, domain.UserStatusInactive)
|
|
|
|
_, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "inactiveuser",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for inactive user")
|
|
}
|
|
})
|
|
|
|
t.Run("nil service Login", func(t *testing.T) {
|
|
var nilSvc *service.AuthService
|
|
_, err := nilSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "test",
|
|
Password: "test",
|
|
}, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("nil service should return error")
|
|
}
|
|
})
|
|
|
|
t.Run("login with totp enabled returns temporary challenge token", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "totploginuser",
|
|
Password: "Test123!",
|
|
Email: "totplogin@test.com",
|
|
}
|
|
user, err := env.authSvc.Register(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("Register failed: %v", err)
|
|
}
|
|
if err := env.db.Model(&domain.User{}).Where("id = ?", user.ID).Updates(map[string]interface{}{
|
|
"totp_enabled": true,
|
|
"totp_secret": "JBSWY3DPEHPK3PXP",
|
|
}).Error; err != nil {
|
|
t.Fatalf("enable totp failed: %v", err)
|
|
}
|
|
|
|
resp, err := env.authSvc.Login(ctx, &service.LoginRequest{
|
|
Username: "totploginuser",
|
|
Password: "Test123!",
|
|
}, "127.0.0.1")
|
|
if err != nil {
|
|
t.Fatalf("Login failed: %v", err)
|
|
}
|
|
if !resp.RequiresTOTP {
|
|
t.Fatal("expected requires_totp response")
|
|
}
|
|
if resp.TempToken == "" {
|
|
t.Fatal("expected temp_token for second-factor challenge")
|
|
}
|
|
if resp.AccessToken != "" || resp.RefreshToken != "" {
|
|
t.Fatal("totp challenge should not mint full session tokens before second factor verification")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestAuthService_Register(t *testing.T) {
|
|
env := setupAuthTestEnv(t)
|
|
if env == nil {
|
|
return
|
|
}
|
|
ctx := context.Background()
|
|
|
|
t.Run("Register success", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "newuser",
|
|
Password: "Test123!",
|
|
Email: "new@test.com",
|
|
Nickname: "New User",
|
|
}
|
|
resp, err := env.authSvc.Register(ctx, req)
|
|
if err != nil {
|
|
t.Fatalf("Register failed: %v", err)
|
|
}
|
|
if resp.Username != "newuser" {
|
|
t.Errorf("Expected username 'newuser', got %s", resp.Username)
|
|
}
|
|
})
|
|
|
|
t.Run("Register with duplicate username", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "dupuser",
|
|
Password: "Test123!",
|
|
}
|
|
env.authSvc.Register(ctx, req)
|
|
|
|
// Try again
|
|
_, err := env.authSvc.Register(ctx, req)
|
|
if err == nil {
|
|
t.Error("Expected error for duplicate username")
|
|
}
|
|
})
|
|
|
|
t.Run("Register with empty username", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "",
|
|
Password: "Test123!",
|
|
}
|
|
_, err := env.authSvc.Register(ctx, req)
|
|
if err == nil {
|
|
t.Error("Expected error for empty username")
|
|
}
|
|
})
|
|
|
|
t.Run("Register with empty password", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "nopass",
|
|
Password: "",
|
|
}
|
|
_, err := env.authSvc.Register(ctx, req)
|
|
if err == nil {
|
|
t.Error("Expected error for empty password")
|
|
}
|
|
})
|
|
|
|
t.Run("Register with weak password", func(t *testing.T) {
|
|
req := &service.RegisterRequest{
|
|
Username: "weakpass",
|
|
Password: "123",
|
|
}
|
|
_, err := env.authSvc.Register(ctx, req)
|
|
if err == nil {
|
|
t.Error("Expected error for weak password")
|
|
}
|
|
})
|
|
|
|
t.Run("Register with nil request", func(t *testing.T) {
|
|
_, err := env.authSvc.Register(ctx, nil)
|
|
if err == nil {
|
|
t.Error("Expected error for nil request")
|
|
}
|
|
})
|
|
|
|
t.Run("nil service Register", func(t *testing.T) {
|
|
var nilSvc *service.AuthService
|
|
req := &service.RegisterRequest{
|
|
Username: "test",
|
|
Password: "Test123!",
|
|
}
|
|
_, err := nilSvc.Register(ctx, req)
|
|
if err == nil {
|
|
t.Error("nil service should return error")
|
|
}
|
|
})
|
|
}
|