package database import ( "os" "testing" "time" ) func TestOptimizationManager_VacuumDatabase(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) err := optimizer.VacuumDatabase() if err != nil { t.Fatal("VacuumDatabase failed:", err) } // Verify vacuum was successful by checking database integrity conn := db.GetConnection() var result string err = conn.QueryRow("PRAGMA integrity_check").Scan(&result) if err != nil { t.Error("Failed to run integrity check:", err) } if result != "ok" { t.Errorf("Database integrity check failed: %s", result) } } func TestOptimizationManager_OptimizeDatabase(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) err := optimizer.OptimizeDatabase() if err != nil { t.Fatal("OptimizeDatabase failed:", err) } // Check that auto_vacuum was set conn := db.GetConnection() var autoVacuum int err = conn.QueryRow("PRAGMA auto_vacuum").Scan(&autoVacuum) if err != nil { t.Error("Failed to check auto_vacuum setting:", err) } // Should be 2 (INCREMENTAL) after optimization if autoVacuum != 2 { t.Errorf("Expected auto_vacuum = 2 (INCREMENTAL), got %d", autoVacuum) } } func TestOptimizationManager_OptimizePageSize(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) // Get current page size conn := db.GetConnection() var currentPageSize int err := conn.QueryRow("PRAGMA page_size").Scan(¤tPageSize) if err != nil { t.Fatal("Failed to get current page size:", err) } // Set a different page size targetPageSize := 8192 if currentPageSize == targetPageSize { targetPageSize = 4096 // Use different size if already at target } err = optimizer.OptimizePageSize(targetPageSize) if err != nil { t.Fatal("OptimizePageSize failed:", err) } // Verify page size was changed var newPageSize int err = conn.QueryRow("PRAGMA page_size").Scan(&newPageSize) if err != nil { t.Error("Failed to get new page size:", err) } if newPageSize != targetPageSize { t.Errorf("Expected page size %d, got %d", targetPageSize, newPageSize) } // Test setting same page size (should be no-op) err = optimizer.OptimizePageSize(targetPageSize) if err != nil { t.Error("OptimizePageSize failed for same page size:", err) } } func TestOptimizationManager_GetOptimizationStats(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) // Insert some test data to make stats more meaningful conn := db.GetConnection() _, err := conn.Exec(` INSERT INTO airlines (id, name, alias, iata_code, icao_code, callsign, country, active, data_source) VALUES (1, 'Test Airways', 'Test', 'TA', 'TST', 'TESTAIR', 'United States', 1, 'test') `) if err != nil { t.Error("Failed to insert test data:", err) } stats, err := optimizer.GetOptimizationStats() if err != nil { t.Fatal("GetOptimizationStats failed:", err) } if stats == nil { t.Fatal("Expected stats, got nil") } // Check basic stats if stats.DatabaseSize <= 0 { t.Error("Database size should be greater than 0") } if stats.PageSize <= 0 { t.Error("Page size should be greater than 0") } if stats.PageCount <= 0 { t.Error("Page count should be greater than 0") } if stats.UsedPages < 0 { t.Error("Used pages should be non-negative") } if stats.FreePages < 0 { t.Error("Free pages should be non-negative") } if stats.Efficiency < 0 || stats.Efficiency > 100 { t.Errorf("Efficiency should be between 0-100%%, got %.2f%%", stats.Efficiency) } t.Logf("Database stats: Size=%d bytes, Pages=%d (used=%d, free=%d), Efficiency=%.1f%%", stats.DatabaseSize, stats.PageCount, stats.UsedPages, stats.FreePages, stats.Efficiency) } func TestOptimizationManager_PerformMaintenance(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{ Path: db.config.Path, VacuumInterval: time.Millisecond, // Very short interval for testing } optimizer := NewOptimizationManager(db, config) // Should perform vacuum due to short interval err := optimizer.PerformMaintenance() if err != nil { t.Fatal("PerformMaintenance failed:", err) } // Check that lastVacuum was updated if optimizer.lastVacuum.IsZero() { t.Error("lastVacuum should be set after maintenance") } // Wait a bit and run again with longer interval config.VacuumInterval = time.Hour // Long interval err = optimizer.PerformMaintenance() if err != nil { t.Fatal("Second PerformMaintenance failed:", err) } } func TestOptimizationManager_getDatabaseSize(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) size, err := optimizer.getDatabaseSize() if err != nil { t.Fatal("getDatabaseSize failed:", err) } if size <= 0 { t.Error("Database size should be greater than 0") } // Verify size matches actual file size stat, err := os.Stat(db.config.Path) if err != nil { t.Fatal("Failed to stat database file:", err) } if size != stat.Size() { t.Errorf("getDatabaseSize returned %d, but file size is %d", size, stat.Size()) } } func TestOptimizationManager_InvalidPath(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() // Test with invalid path config := &Config{Path: "/nonexistent/path/database.db"} optimizer := NewOptimizationManager(db, config) _, err := optimizer.getDatabaseSize() if err == nil { t.Error("getDatabaseSize should fail with invalid path") } } func TestOptimizationStats_JSON(t *testing.T) { stats := &OptimizationStats{ DatabaseSize: 1024000, PageSize: 4096, PageCount: 250, UsedPages: 200, FreePages: 50, Efficiency: 80.0, AutoVacuumEnabled: true, LastVacuum: time.Now(), } // Test that all fields are accessible if stats.DatabaseSize != 1024000 { t.Error("DatabaseSize not preserved") } if stats.PageSize != 4096 { t.Error("PageSize not preserved") } if stats.Efficiency != 80.0 { t.Error("Efficiency not preserved") } if !stats.AutoVacuumEnabled { t.Error("AutoVacuumEnabled not preserved") } } func TestOptimizationManager_WithRealData(t *testing.T) { db, cleanup := setupTestDatabase(t) defer cleanup() // Load some real data to make optimization more realistic // Skip actual data loading in tests as it requires network access // Just insert minimal test data conn := db.GetConnection() _, err := conn.Exec(`INSERT INTO airlines (id, name, alias, iata_code, icao_code, callsign, country, active, data_source) VALUES (1, 'Test Airways', 'Test', 'TA', 'TST', 'TESTAIR', 'United States', 1, 'test')`) if err != nil { t.Fatal("Failed to insert test data:", err) } config := &Config{Path: db.config.Path} optimizer := NewOptimizationManager(db, config) // Get stats before optimization statsBefore, err := optimizer.GetOptimizationStats() if err != nil { t.Fatal("Failed to get stats before optimization:", err) } // Run optimization err = optimizer.OptimizeDatabase() if err != nil { t.Fatal("OptimizeDatabase failed:", err) } err = optimizer.VacuumDatabase() if err != nil { t.Fatal("VacuumDatabase failed:", err) } // Get stats after optimization statsAfter, err := optimizer.GetOptimizationStats() if err != nil { t.Fatal("Failed to get stats after optimization:", err) } // Compare efficiency t.Logf("Optimization results: %.2f%% → %.2f%% efficiency", statsBefore.Efficiency, statsAfter.Efficiency) // After optimization, we should have auto-vacuum enabled if !statsAfter.AutoVacuumEnabled { t.Error("Auto-vacuum should be enabled after optimization") } // Database should still be functional conn = db.GetConnection() var count int err = conn.QueryRow("SELECT COUNT(*) FROM airlines").Scan(&count) if err != nil { t.Error("Database not functional after optimization:", err) } if count == 0 { t.Error("Data lost during optimization") } }