Files
user-system/internal/service/auth_core_test.go
long-agent 582ad7a069 test: add comprehensive test coverage and improve code quality
- Add new test files for auth, service, and handler modules
- Improve test organization and coverage
- Refactor code for better maintainability
- Add captcha, settings, stats, and theme handler tests
- Add auth module tests (CAS, OAuth, password, SSO, state)
- Add service layer tests for auth, export, permissions, roles
- All Go tests pass (exit code 0)
- All frontend tests pass (325 tests in 59 files)
2026-04-17 20:43:50 +08:00

303 lines
7.8 KiB
Go

package service_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/user-management-system/internal/auth"
"github.com/user-management-system/internal/cache"
"github.com/user-management-system/internal/domain"
"github.com/user-management-system/internal/repository"
"github.com/user-management-system/internal/service"
gormsqlite "gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// =============================================================================
// Auth Core Methods Tests - Phase 1: Coverage to 35%
// =============================================================================
type authTestEnv struct {
db *gorm.DB
authSvc *service.AuthService
userSvc *service.UserService
}
func setupAuthTestEnv(t *testing.T) *authTestEnv {
t.Helper()
dsn := fmt.Sprintf("file:authtest_%s_%d?mode=memory&cache=shared", sanitizeTestName(t.Name()), time.Now().UnixNano())
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
DriverName: "sqlite",
DSN: dsn,
}), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Skipf("skipping test (SQLite unavailable): %v", err)
return nil
}
db.Exec("PRAGMA journal_mode=WAL")
if err := db.AutoMigrate(
&domain.User{},
&domain.Role{},
&domain.UserRole{},
&domain.LoginLog{},
&domain.PasswordHistory{},
); err != nil {
t.Fatalf("db migration failed: %v", err)
}
// Seed roles
for _, role := range domain.PredefinedRoles {
if err := db.Create(&role).Error; err != nil {
t.Fatalf("seed role %s failed: %v", role.Code, err)
}
}
jwtManager, _ := auth.NewJWTWithOptions(auth.JWTOptions{
HS256Secret: fmt.Sprintf("test-secret-%d", time.Now().UnixNano()),
AccessTokenExpire: 15 * time.Minute,
RefreshTokenExpire: 7 * 24 * time.Hour,
})
l1Cache := cache.NewL1Cache()
l2Cache := cache.NewRedisCache(false)
cacheManager := cache.NewCacheManager(l1Cache, l2Cache)
userRepo := repository.NewUserRepository(db)
roleRepo := repository.NewRoleRepository(db)
userRoleRepo := repository.NewUserRoleRepository(db)
passwordHistoryRepo := repository.NewPasswordHistoryRepository(db)
authSvc := service.NewAuthService(userRepo, nil, jwtManager, cacheManager, 8, 5, 15*time.Minute)
authSvc.SetRoleRepositories(userRoleRepo, roleRepo)
userSvc := service.NewUserService(userRepo, userRoleRepo, roleRepo, passwordHistoryRepo)
t.Cleanup(func() {
if sqlDB, err := db.DB(); err == nil {
sqlDB.Close()
}
})
return &authTestEnv{
db: db,
authSvc: authSvc,
userSvc: userSvc,
}
}
// Test RefreshToken method
func TestAuthService_RefreshToken(t *testing.T) {
env := setupAuthTestEnv(t)
if env == nil {
return
}
ctx := context.Background()
// First register a user
req := &service.RegisterRequest{
Username: "refreshuser",
Password: "Test123!",
Email: "refresh@test.com",
}
authResp, err := env.authSvc.Register(ctx, req)
if err != nil {
t.Fatalf("Register failed: %v", err)
}
userID := authResp.ID
// Login to get refresh token
loginResp, err := env.authSvc.Login(ctx, &service.LoginRequest{
Username: "refreshuser",
Password: "Test123!",
}, "127.0.0.1")
if err != nil {
t.Fatalf("Login failed: %v", err)
}
refreshToken := loginResp.RefreshToken
t.Run("Refresh token success", func(t *testing.T) {
resp, err := env.authSvc.RefreshToken(ctx, refreshToken)
if err != nil {
t.Fatalf("RefreshToken failed: %v", err)
}
if resp.AccessToken == "" {
t.Error("Expected access token to be returned")
}
if resp.RefreshToken == "" {
t.Error("Expected refresh token to be returned")
}
})
t.Run("Refresh token with invalid token", func(t *testing.T) {
_, err := env.authSvc.RefreshToken(ctx, "invalid-token")
if err == nil {
t.Error("Expected error for invalid token")
}
})
t.Run("Refresh token with empty token", func(t *testing.T) {
_, err := env.authSvc.RefreshToken(ctx, "")
if err == nil {
t.Error("Expected error for empty token")
}
})
t.Run("Refresh token for locked user", func(t *testing.T) {
// Lock the user
env.userSvc.UpdateStatus(ctx, userID, domain.UserStatusLocked)
// Try to refresh token - should fail
_, err := env.authSvc.RefreshToken(ctx, refreshToken)
if err == nil {
t.Error("Expected error for locked user")
}
// Unlock user for cleanup
env.userSvc.UpdateStatus(ctx, userID, domain.UserStatusActive)
})
t.Run("Refresh token with nil service", func(t *testing.T) {
var nilSvc *service.AuthService
_, err := nilSvc.RefreshToken(ctx, refreshToken)
if err == nil {
t.Error("Expected error for nil service")
}
})
}
// Test GetUserInfo method
func TestAuthService_GetUserInfo(t *testing.T) {
env := setupAuthTestEnv(t)
if env == nil {
return
}
ctx := context.Background()
// Register a user
req := &service.RegisterRequest{
Username: "infouser",
Password: "Test123!",
Email: "info@test.com",
Nickname: "Info User",
}
authResp, err := env.authSvc.Register(ctx, req)
if err != nil {
t.Fatalf("Register failed: %v", err)
}
userID := authResp.ID
t.Run("Get user info success", func(t *testing.T) {
info, err := env.authSvc.GetUserInfo(ctx, userID)
if err != nil {
t.Fatalf("GetUserInfo failed: %v", err)
}
if info.ID != userID {
t.Errorf("Expected user ID %d, got %d", userID, info.ID)
}
if info.Username != "infouser" {
t.Errorf("Expected username 'infouser', got %s", info.Username)
}
if info.Nickname != "Info User" {
t.Errorf("Expected nickname 'Info User', got %s", info.Nickname)
}
if info.Email != "info@test.com" {
t.Errorf("Expected email 'info@test.com', got %s", info.Email)
}
})
t.Run("Get user info from cache", func(t *testing.T) {
// Second call should hit cache
info, err := env.authSvc.GetUserInfo(ctx, userID)
if err != nil {
t.Fatalf("GetUserInfo from cache failed: %v", err)
}
if info.ID != userID {
t.Errorf("Expected user ID %d, got %d", userID, info.ID)
}
})
t.Run("Get user info for non-existent user", func(t *testing.T) {
_, err := env.authSvc.GetUserInfo(ctx, 99999)
if err == nil {
t.Error("Expected error for non-existent user")
}
})
t.Run("Get user info with nil service", func(t *testing.T) {
var nilSvc *service.AuthService
_, err := nilSvc.GetUserInfo(ctx, userID)
if err == nil {
t.Error("Expected error for nil service")
}
})
t.Run("Get user info with zero ID", func(t *testing.T) {
_, err := env.authSvc.GetUserInfo(ctx, 0)
if err == nil {
t.Error("Expected error for zero user ID")
}
})
}
// Test Logout method
func TestAuthService_Logout(t *testing.T) {
env := setupAuthTestEnv(t)
if env == nil {
return
}
ctx := context.Background()
// Register and login a user
req := &service.RegisterRequest{
Username: "logoutuser",
Password: "Test123!",
}
_, err := env.authSvc.Register(ctx, req)
if err != nil {
t.Fatalf("Register failed: %v", err)
}
loginResp, err := env.authSvc.Login(ctx, &service.LoginRequest{
Username: "logoutuser",
Password: "Test123!",
}, "127.0.0.1")
if err != nil {
t.Fatalf("Login failed: %v", err)
}
t.Run("Logout success", func(t *testing.T) {
err := env.authSvc.Logout(ctx, "logoutuser", &service.LogoutRequest{
AccessToken: loginResp.AccessToken,
RefreshToken: loginResp.RefreshToken,
})
if err != nil {
t.Errorf("Logout failed: %v", err)
}
})
t.Run("Logout with nil request", func(t *testing.T) {
err := env.authSvc.Logout(ctx, "logoutuser", nil)
if err != nil {
t.Errorf("Logout with nil request should not error: %v", err)
}
})
t.Run("Logout with nil service", func(t *testing.T) {
var nilSvc *service.AuthService
err := nilSvc.Logout(ctx, "logoutuser", &service.LogoutRequest{
AccessToken: loginResp.AccessToken,
RefreshToken: loginResp.RefreshToken,
})
if err != nil {
t.Errorf("Logout with nil service should not error: %v", err)
}
})
}