- 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)
246 lines
6.7 KiB
Go
246 lines
6.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"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"
|
|
gormsqlite "gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
// =============================================================================
|
|
// Auth Admin Bootstrap Internal Tests
|
|
// =============================================================================
|
|
|
|
func setupBootstrapInternalTestEnv(t *testing.T) (*AuthService, *gorm.DB) {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
|
|
DriverName: "sqlite",
|
|
DSN: "file:bootstrap_internal_test?mode=memory&cache=shared",
|
|
}), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("failed to connect database: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(&domain.User{}, &domain.Role{}, &domain.UserRole{}); err != nil {
|
|
t.Fatalf("failed to migrate: %v", err)
|
|
}
|
|
|
|
// Create admin role
|
|
adminRole := &domain.Role{
|
|
Name: "管理员",
|
|
Code: "admin",
|
|
Status: domain.RoleStatusEnabled,
|
|
}
|
|
db.Create(adminRole)
|
|
|
|
userRepo := repository.NewUserRepository(db)
|
|
userRoleRepo := repository.NewUserRoleRepository(db)
|
|
roleRepo := repository.NewRoleRepository(db)
|
|
socialRepo, _ := repository.NewSocialAccountRepository(db)
|
|
jwtManager, _ := auth.NewJWTWithOptions(auth.JWTOptions{
|
|
HS256Secret: "test-secret-for-bootstrap",
|
|
AccessTokenExpire: 15 * 60 * 1000 * 1000 * 1000,
|
|
RefreshTokenExpire: 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
|
})
|
|
|
|
l1Cache := cache.NewL1Cache()
|
|
l2Cache := cache.NewRedisCache(false)
|
|
cacheManager := cache.NewCacheManager(l1Cache, l2Cache)
|
|
|
|
svc := NewAuthService(userRepo, socialRepo, jwtManager, cacheManager, 8, 5, 15*60*1000*1000*1000)
|
|
svc.SetRoleRepositories(userRoleRepo, roleRepo)
|
|
|
|
return svc, db
|
|
}
|
|
|
|
func TestBootstrapAdmin_Internal(t *testing.T) {
|
|
svc, db := setupBootstrapInternalTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("BootstrapAdmin with nil request", func(t *testing.T) {
|
|
_, err := svc.BootstrapAdmin(ctx, nil, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for nil request")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin with empty username", func(t *testing.T) {
|
|
req := &BootstrapAdminRequest{
|
|
Username: "",
|
|
Password: "Admin123!",
|
|
}
|
|
_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for empty username")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin with empty password", func(t *testing.T) {
|
|
req := &BootstrapAdminRequest{
|
|
Username: "testadmin",
|
|
Password: "",
|
|
}
|
|
_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for empty password")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin with weak password", func(t *testing.T) {
|
|
req := &BootstrapAdminRequest{
|
|
Username: "testadmin",
|
|
Password: "123",
|
|
}
|
|
_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for weak password")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin success", func(t *testing.T) {
|
|
// Clean up
|
|
db.Exec("DELETE FROM user_roles")
|
|
db.Exec("DELETE FROM users")
|
|
|
|
req := &BootstrapAdminRequest{
|
|
Username: "newadmin",
|
|
Password: "Admin123!",
|
|
Email: "newadmin@test.com",
|
|
Nickname: "New Admin",
|
|
}
|
|
resp, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err != nil {
|
|
t.Fatalf("BootstrapAdmin failed: %v", err)
|
|
}
|
|
if resp.AccessToken == "" {
|
|
t.Error("Expected access token")
|
|
}
|
|
if resp.User.Username != "newadmin" {
|
|
t.Errorf("Expected username 'newadmin', got %s", resp.User.Username)
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin with duplicate username", func(t *testing.T) {
|
|
req := &BootstrapAdminRequest{
|
|
Username: "dupadmin",
|
|
Password: "Admin123!",
|
|
}
|
|
// First create
|
|
svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
// Second create should fail
|
|
_, err := svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for duplicate username")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin with duplicate email", func(t *testing.T) {
|
|
// Clean up
|
|
db.Exec("DELETE FROM user_roles WHERE user_id IN (SELECT id FROM users WHERE username LIKE 'emailtest%')")
|
|
db.Exec("DELETE FROM users WHERE username LIKE 'emailtest%'")
|
|
|
|
req1 := &BootstrapAdminRequest{
|
|
Username: "emailtest1",
|
|
Password: "Admin123!",
|
|
Email: "samemail@test.com",
|
|
}
|
|
svc.BootstrapAdmin(ctx, req1, "127.0.0.1")
|
|
|
|
req2 := &BootstrapAdminRequest{
|
|
Username: "emailtest2",
|
|
Password: "Admin123!",
|
|
Email: "samemail@test.com",
|
|
}
|
|
_, err := svc.BootstrapAdmin(ctx, req2, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for duplicate email")
|
|
}
|
|
})
|
|
|
|
t.Run("BootstrapAdmin when bootstrap unavailable", func(t *testing.T) {
|
|
// Create an existing admin to make bootstrap unavailable
|
|
db.Exec("DELETE FROM user_roles")
|
|
db.Exec("DELETE FROM users")
|
|
|
|
req := &BootstrapAdminRequest{
|
|
Username: "firstadmin",
|
|
Password: "Admin123!",
|
|
}
|
|
svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
|
|
// Now try again - should fail because admin already exists
|
|
req2 := &BootstrapAdminRequest{
|
|
Username: "secondadmin",
|
|
Password: "Admin123!",
|
|
}
|
|
_, err := svc.BootstrapAdmin(ctx, req2, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error when bootstrap unavailable")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestBootstrapAdmin_NilService(t *testing.T) {
|
|
var nilSvc *AuthService
|
|
ctx := context.Background()
|
|
|
|
t.Run("nil service returns error", func(t *testing.T) {
|
|
req := &BootstrapAdminRequest{
|
|
Username: "admin",
|
|
Password: "Admin123!",
|
|
}
|
|
_, err := nilSvc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
if err == nil {
|
|
t.Error("Expected error for nil service")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestIsAdminBootstrapRequired(t *testing.T) {
|
|
svc, db := setupBootstrapInternalTestEnv(t)
|
|
ctx := context.Background()
|
|
|
|
t.Run("returns true when no admin exists", func(t *testing.T) {
|
|
db.Exec("DELETE FROM user_roles")
|
|
db.Exec("DELETE FROM users")
|
|
|
|
required := svc.IsAdminBootstrapRequired(ctx)
|
|
if !required {
|
|
t.Error("Expected IsAdminBootstrapRequired to return true when no admin exists")
|
|
}
|
|
})
|
|
|
|
t.Run("returns false when admin exists", func(t *testing.T) {
|
|
db.Exec("DELETE FROM user_roles")
|
|
db.Exec("DELETE FROM users")
|
|
|
|
req := &BootstrapAdminRequest{
|
|
Username: "bootstrapadmin",
|
|
Password: "Admin123!",
|
|
}
|
|
svc.BootstrapAdmin(ctx, req, "127.0.0.1")
|
|
|
|
required := svc.IsAdminBootstrapRequired(ctx)
|
|
if required {
|
|
t.Error("Expected IsAdminBootstrapRequired to return false when admin exists")
|
|
}
|
|
})
|
|
|
|
t.Run("nil service returns false", func(t *testing.T) {
|
|
var nilSvc *AuthService
|
|
required := nilSvc.IsAdminBootstrapRequired(ctx)
|
|
if required {
|
|
t.Error("Expected IsAdminBootstrapRequired to return false for nil service")
|
|
}
|
|
})
|
|
}
|