package store import ( "context" "path/filepath" "testing" ) // openTestStore opens an isolated file-backed db in a t.TempDir. // In-memory + shared-cache works too but file makes failures easier // to inspect when a test panics. func openTestStore(t *testing.T) *Store { t.Helper() dir := t.TempDir() s, err := Open(context.Background(), filepath.Join(dir, "rm.db")) if err != nil { t.Fatalf("open: %v", err) } t.Cleanup(func() { _ = s.Close() }) return s } func TestOpenAppliesMigrations(t *testing.T) { t.Parallel() s := openTestStore(t) row := s.DB().QueryRow(`SELECT MAX(version) FROM schema_version`) var v int if err := row.Scan(&v); err != nil { t.Fatalf("scan: %v", err) } if v < 1 { t.Fatalf("expected at least migration 1 applied, got %d", v) } // Spot-check a few tables exist with expected columns. tables := []string{ "users", "sessions", "hosts", "repos", "credentials", "schedules", "jobs", "job_logs", "snapshots", "alerts", "audit_log", "enrollment_tokens", "host_schedule_version", } for _, tbl := range tables { row := s.DB().QueryRow( `SELECT name FROM sqlite_master WHERE type='table' AND name = ?`, tbl) var got string if err := row.Scan(&got); err != nil { t.Errorf("table %q missing: %v", tbl, err) } } } func TestMigrateIsIdempotent(t *testing.T) { t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "rm.db") for i := 0; i < 3; i++ { s, err := Open(context.Background(), path) if err != nil { t.Fatalf("open #%d: %v", i, err) } _ = s.Close() } s, err := Open(context.Background(), path) if err != nil { t.Fatalf("final open: %v", err) } defer s.Close() row := s.DB().QueryRow(`SELECT COUNT(*) FROM schema_version`) var n int if err := row.Scan(&n); err != nil { t.Fatalf("scan: %v", err) } migs, err := loadMigrations() if err != nil { t.Fatalf("load migrations: %v", err) } if n != len(migs) { t.Errorf("re-running migrations should not insert duplicate rows; want %d, got %d", len(migs), n) } } func TestForeignKeysEnforced(t *testing.T) { t.Parallel() s := openTestStore(t) // Inserting a session with a non-existent user should fail because // FKs are on. Without the pragma, SQLite silently accepts this. _, err := s.DB().Exec( `INSERT INTO sessions (id, user_id, created_at, expires_at) VALUES (?, ?, datetime('now'), datetime('now','+1 hour'))`, "sess1", "no-such-user") if err == nil { t.Fatal("expected FK violation, got nil") } }