package infra import ( "testing" ) func TestMigrationStatus(t *testing.T) { t.Run("migraciones en disco pero no en BD aparecen como pending", func(t *testing.T) { db := openMigrationTestDB(t) dir := t.TempDir() writeMigrationFile(t, dir, "001_create_users.sql", "-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n") writeMigrationFile(t, dir, "002_create_roles.sql", "-- +up\nCREATE TABLE roles (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS roles;\n") statuses, err := MigrationGetStatus(db, dir) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(statuses) != 2 { t.Fatalf("expected 2 statuses, got %d", len(statuses)) } for _, s := range statuses { if s.Applied { t.Errorf("version %d should be pending, got applied", s.Version) } } }) t.Run("migraciones aplicadas aparecen con Applied=true y AppliedAt", func(t *testing.T) { db := openMigrationTestDB(t) dir := t.TempDir() writeMigrationFile(t, dir, "001_create_users.sql", "-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n") writeMigrationFile(t, dir, "002_create_roles.sql", "-- +up\nCREATE TABLE roles (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS roles;\n") if _, err := MigrationUp(db, dir); err != nil { t.Fatalf("up failed: %v", err) } statuses, err := MigrationGetStatus(db, dir) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(statuses) != 2 { t.Fatalf("expected 2 statuses, got %d", len(statuses)) } for _, s := range statuses { if !s.Applied { t.Errorf("version %d should be applied, got pending", s.Version) } if s.AppliedAt.IsZero() { t.Errorf("version %d AppliedAt should not be zero", s.Version) } } }) t.Run("migraciones aplicadas sin archivo en disco aparecen como orphaned", func(t *testing.T) { db := openMigrationTestDB(t) dir := t.TempDir() writeMigrationFile(t, dir, "001_create_users.sql", "-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n") if _, err := MigrationUp(db, dir); err != nil { t.Fatalf("up failed: %v", err) } // Remove file from disk but migration is applied in DB // Now check status with an empty dir emptyDir := t.TempDir() statuses, err := MigrationGetStatus(db, emptyDir) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(statuses) != 1 { t.Fatalf("expected 1 status (orphaned), got %d", len(statuses)) } s := statuses[0] if !s.Applied { t.Errorf("orphaned migration should have Applied=true") } if !containsStr(s.Name, "orphaned") { t.Errorf("orphaned migration name should contain 'orphaned', got %q", s.Name) } }) t.Run("base de datos sin tabla _migrations retorna todas como pending", func(t *testing.T) { db := openMigrationTestDB(t) dir := t.TempDir() writeMigrationFile(t, dir, "001_create_users.sql", "-- +up\nCREATE TABLE users (id TEXT PRIMARY KEY);\n-- +down\nDROP TABLE IF EXISTS users;\n") // Do NOT call MigrationUp — _migrations table doesn't exist statuses, err := MigrationGetStatus(db, dir) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(statuses) != 1 { t.Fatalf("expected 1 status, got %d", len(statuses)) } if statuses[0].Applied { t.Errorf("migration should be pending when _migrations does not exist") } }) }