feat: funciones impuras migration_create, migration_up, migration_down, migration_status
Fase 2 del issue 0015. MigrationCreate (crea archivo .sql template con version auto-calculada), MigrationUp (aplica migraciones pendientes en transacciones individuales), MigrationDown (revierte ultimas N via down_sql de _migrations), MigrationGetStatus (cruza disco con BD, detecta orphaned). Tests de integracion: ciclo completo create->up->status->down->status. 26 tests, todos pasan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package infra
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMigrationCreate(t *testing.T) {
|
||||
t.Run("directorio vacio crea archivo con version 001", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path, err := MigrationCreate(dir, "create_users")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
base := filepath.Base(path)
|
||||
if base != "001_create_users.sql" {
|
||||
t.Errorf("filename: got %q, want %q", base, "001_create_users.sql")
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read created file: %v", err)
|
||||
}
|
||||
if !strings.Contains(string(content), "-- +up") {
|
||||
t.Errorf("file missing -- +up marker")
|
||||
}
|
||||
if !strings.Contains(string(content), "-- +down") {
|
||||
t.Errorf("file missing -- +down marker")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("directorio con migraciones existentes calcula siguiente version", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
// Create existing files
|
||||
os.WriteFile(filepath.Join(dir, "001_create_users.sql"), []byte("-- +up\nCREATE TABLE users (id TEXT);\n-- +down\nDROP TABLE users;\n"), 0o644)
|
||||
os.WriteFile(filepath.Join(dir, "002_add_email.sql"), []byte("-- +up\nALTER TABLE users ADD COLUMN email TEXT;\n-- +down\n\n"), 0o644)
|
||||
|
||||
path, err := MigrationCreate(dir, "add_index")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
base := filepath.Base(path)
|
||||
if base != "003_add_index.sql" {
|
||||
t.Errorf("filename: got %q, want %q", base, "003_add_index.sql")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nombre invalido retorna error", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_, err := MigrationCreate(dir, "123invalid")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid name, got nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("directorio inexistente se crea automaticamente", func(t *testing.T) {
|
||||
base := t.TempDir()
|
||||
dir := filepath.Join(base, "nested", "migrations")
|
||||
|
||||
path, err := MigrationCreate(dir, "init")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
t.Errorf("directory was not created: %s", dir)
|
||||
}
|
||||
|
||||
if filepath.Dir(path) != dir {
|
||||
t.Errorf("file not in expected dir: %s", path)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user