package handlers import ( "fmt" "net/http" "net/http/httptest" "testing" "time" "github.com/gin-gonic/gin" "github.com/glebarez/sqlite" "github.com/starfleetcptn/gomft/internal/db" "github.com/starfleetcptn/gomft/internal/email" "github.com/starfleetcptn/gomft/internal/scheduler" "github.com/stretchr/testify/assert" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) // Static counter to ensure unique emails for each test var testEmailCounter int = 0 func setupTestHandlers(t *testing.T) (*Handlers, *gin.Engine) { // Set Gin to test mode gin.SetMode(gin.TestMode) // Create a test DB testDB := setupTestDB(t) // Create a mock scheduler mockScheduler := &scheduler.Scheduler{} // Create a mock email service mockEmailService := &email.Service{} // Create test handlers handlers := NewHandlers( testDB, mockScheduler, "test-jwt-secret", "test-db-path", "test-backup-dir", "test-logs-dir", mockEmailService, ) // Create a test router router := gin.New() return handlers, router } // setupTestDB creates a test database for handler tests func setupTestDB(t *testing.T) *db.DB { // Set up an in-memory SQLite DB gormDB, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{}) if err != nil { t.Fatalf("Failed to open in-memory database: %v", err) } // Run migrations err = gormDB.AutoMigrate( &db.User{}, &db.PasswordHistory{}, &db.PasswordResetToken{}, &db.TransferConfig{}, &db.Job{}, &db.JobHistory{}, &db.FileMetadata{}, ) if err != nil { t.Fatalf("Failed to migrate database: %v", err) } // Create a test admin user with a unique email testEmailCounter++ testEmail := fmt.Sprintf("test%d@example.com", testEmailCounter) // Generate a hashed password for "admin" hashedPassword, err := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.DefaultCost) if err != nil { t.Fatalf("Failed to hash password: %v", err) } testUser := &db.User{ Email: testEmail, PasswordHash: string(hashedPassword), IsAdmin: true, LastPasswordChange: time.Now(), } if result := gormDB.Create(testUser); result.Error != nil { t.Fatalf("Failed to create test user: %v", result.Error) } return &db.DB{DB: gormDB} } func TestHandleHome(t *testing.T) { // Setup handlers, router := setupTestHandlers(t) // Register the home route router.GET("/", handlers.HandleHome) // Create a test request req, err := http.NewRequest(http.MethodGet, "/", nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } // Create a response recorder recorder := httptest.NewRecorder() // Serve the request router.ServeHTTP(recorder, req) // Assert response assert.Equal(t, http.StatusOK, recorder.Code, "Expected status code 200") // In a real test we would also assert that the correct template was rendered // This might involve checking specific patterns in the response body } func TestHandleHomeWithValidToken(t *testing.T) { // Setup handlers, router := setupTestHandlers(t) // Register the home route router.GET("/", handlers.HandleHome) // Create a test request with a valid JWT token cookie req, err := http.NewRequest(http.MethodGet, "/", nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } // Set a mock JWT token in the cookie // In a real test, we would generate a valid token req.AddCookie(&http.Cookie{ Name: "jwt_token", Value: "mock-valid-token", // In a real test, this would be a valid token }) // Create a response recorder recorder := httptest.NewRecorder() // Serve the request router.ServeHTTP(recorder, req) // Since we're not actually validating the token in this mock setup, // we expect a 200 status. In a real test with proper token handling, // we would expect a redirect to the dashboard (302) assert.Equal(t, http.StatusOK, recorder.Code, "Expected status code 200") } // Note: In a real implementation, we would need to: // 1. Set up a real database (or a proper mock) // 2. Create real JWT tokens for auth tests // 3. Mock the components.Home() templ component // 4. Properly handle redirects in tests