- Add unit tests for database operations and optimization - Test external data source loading and caching - Add callsign manager functionality tests - Create test helpers for database testing utilities - Ensure database reliability and performance validation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
307 lines
No EOL
8.1 KiB
Go
307 lines
No EOL
8.1 KiB
Go
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")
|
|
}
|
|
} |