alt/services/worker/internal/storage/postgres/migrate_test.go
toki c0db4b24c1 feat(live-trading): 계좌 동기화와 감사 추적을 추가한다
Live Trading Boundary의 남은 account-sync/audit-trail 작업을 완료해 운영자 headless workflow와 roadmap 완료 후보 상태를 함께 반영한다.
2026-06-08 11:18:41 +09:00

126 lines
3.7 KiB
Go

package postgres
import (
"strconv"
"strings"
"testing"
)
func TestMigrationsAreEmbeddedInOrder(t *testing.T) {
entries, err := migrationsFS.ReadDir("migrations")
if err != nil {
t.Fatalf("failed to read migrations directory: %v", err)
}
var upFiles []string
var downFiles []string
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if strings.HasSuffix(name, ".up.sql") {
upFiles = append(upFiles, name)
} else if strings.HasSuffix(name, ".down.sql") {
downFiles = append(downFiles, name)
}
}
if len(upFiles) == 0 {
t.Error("expected at least one up migration file, found none")
}
if len(downFiles) == 0 {
t.Error("expected at least one down migration file, found none")
}
if len(upFiles) != len(downFiles) {
t.Errorf("mismatched migration count: %d up files, %d down files", len(upFiles), len(downFiles))
}
// Verify up and down files match and are in numerical order
for i := 0; i < len(upFiles); i++ {
up := upFiles[i]
partsUp := strings.Split(up, "_")
if len(partsUp) < 2 {
t.Errorf("invalid up migration file name: %s", up)
continue
}
versionUp, err := strconv.ParseInt(partsUp[0], 10, 64)
if err != nil {
t.Errorf("failed to parse up version from %s: %v", up, err)
}
if versionUp != int64(i+1) {
t.Errorf("expected version %d for file %s, got %d", i+1, up, versionUp)
}
// Find corresponding down file
var foundDown bool
for _, down := range downFiles {
if strings.Split(down, "_")[0] == partsUp[0] {
foundDown = true
break
}
}
if !foundDown {
t.Errorf("missing corresponding down migration for: %s", up)
}
}
}
func TestMigrationStatementsAreNamed(t *testing.T) {
// Check if migrate.go FS variable is populated
entries, err := migrationsFS.ReadDir("migrations")
if err != nil {
t.Fatalf("failed to read migrations: %v", err)
}
if len(entries) == 0 {
t.Error("migrations FS has no entries")
}
}
func TestLiveAuditEventsMigrationPairing(t *testing.T) {
up, err := migrationsFS.ReadFile("migrations/000004_live_audit_events.up.sql")
if err != nil {
t.Fatalf("failed to read 000004 up migration: %v", err)
}
down, err := migrationsFS.ReadFile("migrations/000004_live_audit_events.down.sql")
if err != nil {
t.Fatalf("failed to read 000004 down migration: %v", err)
}
for _, col := range []string{"event_id", "account_id", "event_type", "payload", "created_at"} {
if !strings.Contains(string(up), col) {
t.Errorf("000004 up migration missing column %q", col)
}
}
if !strings.Contains(string(down), "live_audit_events") {
t.Error("000004 down migration must drop live_audit_events table")
}
}
func TestAnalysisResultColumnsAddedInVersionedMigration(t *testing.T) {
// The analysis result columns must arrive through the v2 migration so databases
// already at version 1 receive them, rather than being edited into 000001.
content, err := migrationsFS.ReadFile("migrations/000002_backtest_analysis_results.up.sql")
if err != nil {
t.Fatalf("failed to read 000002 up migration: %v", err)
}
up := string(content)
for _, column := range []string{"total_return", "trade_count", "equity_curve"} {
if !strings.Contains(up, column) {
t.Errorf("000002 up migration missing column %q", column)
}
}
// The originally applied 000001 migration must not carry the analysis columns.
backbone, err := migrationsFS.ReadFile("migrations/000001_worker_backbone.up.sql")
if err != nil {
t.Fatalf("failed to read 000001 up migration: %v", err)
}
for _, column := range []string{"total_return", "trade_count", "equity_curve"} {
if strings.Contains(string(backbone), column) {
t.Errorf("000001 up migration should not contain analysis column %q", column)
}
}
}