package middleware import ( "context" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" "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" _ "modernc.org/sqlite" ) func TestAuthMiddleware_AcceptsBootstrapAdminTokenImmediately(t *testing.T) { t.Helper() gin.SetMode(gin.TestMode) db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{ DriverName: "sqlite", DSN: "file:middleware_bootstrap_test?mode=memory&cache=shared", }), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) if err != nil { t.Fatalf("open sqlite failed: %v", err) } if err := db.AutoMigrate(&domain.User{}, &domain.Role{}, &domain.UserRole{}); err != nil { t.Fatalf("migrate failed: %v", err) } if err := db.Create(&domain.Role{ Name: "管理员", Code: "admin", IsSystem: true, Status: domain.RoleStatusEnabled, }).Error; err != nil { t.Fatalf("seed admin role failed: %v", err) } jwtManager, err := auth.NewJWTWithOptions(auth.JWTOptions{ HS256Secret: "test-bootstrap-token-secret-at-least-32-chars", AccessTokenExpire: 15 * time.Minute, RefreshTokenExpire: 7 * 24 * time.Hour, }) if err != nil { t.Fatalf("create jwt manager failed: %v", err) } l1Cache := cache.NewL1Cache() l2Cache := cache.NewRedisCache(false) cacheManager := cache.NewCacheManager(l1Cache, l2Cache) userRepo := repository.NewUserRepository(db) roleRepo := repository.NewRoleRepository(db) userRoleRepo := repository.NewUserRoleRepository(db) authService := service.NewAuthService(userRepo, nil, jwtManager, cacheManager, 8, 5, 15*time.Minute) authService.SetRoleRepositories(userRoleRepo, roleRepo) loginResponse, err := authService.BootstrapAdmin(context.Background(), &service.BootstrapAdminRequest{ Username: "bootstrap_admin", Email: "bootstrap_admin@example.com", Password: "AdminPass123!", }, "127.0.0.1") if err != nil { t.Fatalf("bootstrap admin failed: %v", err) } if loginResponse == nil || loginResponse.AccessToken == "" { t.Fatalf("expected bootstrap access token, got %+v", loginResponse) } if _, err := jwtManager.ValidateAccessToken(loginResponse.AccessToken); err != nil { t.Fatalf("bootstrap access token should validate immediately: %v", err) } authMiddleware := NewAuthMiddleware(jwtManager, userRepo, userRoleRepo, l1Cache) authMiddleware.SetCacheManager(cacheManager) recorder := httptest.NewRecorder() ctx, engine := gin.CreateTestContext(recorder) ctx.Request = httptest.NewRequest(http.MethodGet, "/protected", nil) ctx.Request.Header.Set("Authorization", "Bearer "+loginResponse.AccessToken) engine.Use(authMiddleware.Required()) engine.GET("/protected", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"code": 0}) }) engine.ServeHTTP(recorder, ctx.Request) if recorder.Code != http.StatusOK { t.Fatalf("expected bootstrap token to pass auth middleware immediately, got %d body: %s", recorder.Code, recorder.Body.String()) } }