Files
Redflag/aggregator-server/internal/database/migrations/migration024_test.go
jpetree331 ab676c3b83 test(database): B-1 pre-fix tests for migration and schema bugs
Pre-fix test suite documenting 9 database migration and schema
integrity bugs. Tests FAIL where they assert correct post-fix
behavior, PASS where they document current buggy state.

Tests added:
- F-B1-11 P0: main.go swallows migration errors (3 tests)
- F-B1-13: Duplicate migration numbers 009/012 (2 tests)
- F-B1-1: Migration 024 self-insert into schema_migrations (2 tests)
- F-B1-2: Migration 024 references non-existent column (2 tests)
- F-B1-3: Migration 018 wrong file suffix (2 tests)
- F-B1-4: Migration 018 GRANT to wrong role (1 test)
- F-B1-15: 7+ migrations not idempotent (2 tests)
- F-B1-5: Missing agent_commands sent_at index (2 tests)
- F-B1-6: N+1 query in GetDashboardStats (2 tests)
- F-B1-10: No background refresh token cleanup (2 tests)

Current state: 10 PASS, 10 FAIL, 0 SKIP.
All A-series tests continue to pass (no regressions).
See docs/B1_PreFix_Tests.md for full inventory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 06:42:19 -04:00

143 lines
5.1 KiB
Go

package migrations_test
// migration024_test.go — Pre-fix tests for migration 024 bugs.
//
// F-B1-1 CRITICAL: Migration 024 self-inserts into schema_migrations,
// causing duplicate key when the runner also inserts.
// 024_disable_updates_subsystem.up.sql:18-19
//
// F-B1-2 CRITICAL: Migration 024 references non-existent `deprecated`
// column on agent_subsystems. The column was never added.
//
// Run: cd aggregator-server && go test ./internal/database/migrations/... -v -run TestMigration024
import (
"os"
"strings"
"testing"
)
// ---------------------------------------------------------------------------
// Test 2.1 — Migration 024 contains self-insert (documents F-B1-1)
//
// Category: PASS-NOW (documents the bug)
// ---------------------------------------------------------------------------
func TestMigration024HasSelfInsert(t *testing.T) {
content, err := os.ReadFile("024_disable_updates_subsystem.up.sql")
if err != nil {
t.Fatalf("failed to read migration 024: %v", err)
}
src := string(content)
if !strings.Contains(src, "INSERT INTO schema_migrations") {
t.Error("[ERROR] [server] [database] F-B1-1 already fixed: " +
"migration 024 no longer contains self-insert. Update this test.")
}
t.Log("[INFO] [server] [database] F-B1-1 confirmed: migration 024 self-inserts into schema_migrations")
t.Log("[INFO] [server] [database] the runner also inserts, causing duplicate key violation")
t.Log("[INFO] [server] [database] result: migration 024 is never applied")
}
// ---------------------------------------------------------------------------
// Test 2.2 — Migration 024 should NOT have self-insert (assert fix)
//
// Category: FAIL-NOW / PASS-AFTER-FIX
// ---------------------------------------------------------------------------
func TestMigration024ShouldNotHaveSelfInsert(t *testing.T) {
content, err := os.ReadFile("024_disable_updates_subsystem.up.sql")
if err != nil {
t.Fatalf("failed to read migration 024: %v", err)
}
src := string(content)
if strings.Contains(src, "INSERT INTO schema_migrations") {
t.Errorf("[ERROR] [server] [database] migration 024 contains self-insert into schema_migrations.\n"+
"F-B1-1: the migration runner handles schema_migrations tracking.\n"+
"Migration SQL must not manage its own tracking entry.\n"+
"After fix: remove the INSERT INTO schema_migrations line.")
}
}
// ---------------------------------------------------------------------------
// Test 2.3 — Migration 024 references `deprecated` column (documents F-B1-2)
//
// Category: PASS-NOW (documents the bug)
// ---------------------------------------------------------------------------
func TestMigration024ReferencesDeprecatedColumn(t *testing.T) {
content, err := os.ReadFile("024_disable_updates_subsystem.up.sql")
if err != nil {
t.Fatalf("failed to read migration 024: %v", err)
}
src := string(content)
if !strings.Contains(src, "deprecated") {
t.Error("[ERROR] [server] [database] F-B1-2 already fixed: " +
"migration 024 no longer references `deprecated` column")
}
t.Log("[INFO] [server] [database] F-B1-2 confirmed: migration 024 sets `deprecated = true`")
t.Log("[INFO] [server] [database] but `deprecated` column does not exist on agent_subsystems")
}
// ---------------------------------------------------------------------------
// Test 2.4 — `deprecated` column must be defined before migration 024 uses it
//
// Category: FAIL-NOW / PASS-AFTER-FIX
// ---------------------------------------------------------------------------
func TestMigration024ColumnExistsInSchema(t *testing.T) {
// Read migration 015 (creates agent_subsystems table)
content015, err := os.ReadFile("015_agent_subsystems.up.sql")
if err != nil {
t.Fatalf("failed to read migration 015: %v", err)
}
// Read migration 024
content024, err := os.ReadFile("024_disable_updates_subsystem.up.sql")
if err != nil {
t.Fatalf("failed to read migration 024: %v", err)
}
// Check if 024 uses `deprecated`
uses024 := strings.Contains(string(content024), "deprecated")
// Check if `deprecated` column is defined in 015 or any intermediate migration
// that touches agent_subsystems
definedInSchema := strings.Contains(string(content015), "deprecated")
// Also check if any migration between 015 and 024 adds a `deprecated` column
// to agent_subsystems specifically (not other tables)
files, _ := os.ReadDir(".")
for _, f := range files {
if !strings.HasSuffix(f.Name(), ".up.sql") {
continue
}
if f.Name() > "015" && f.Name() < "024" {
c, err := os.ReadFile(f.Name())
if err != nil {
continue
}
src := string(c)
// Must be ADD COLUMN deprecated on agent_subsystems, not other tables
if strings.Contains(src, "agent_subsystems") &&
strings.Contains(src, "ADD COLUMN") &&
strings.Contains(src, "deprecated") {
definedInSchema = true
}
}
}
if uses024 && !definedInSchema {
t.Errorf("[ERROR] [server] [database] migration 024 uses `deprecated` column but it is not defined.\n"+
"F-B1-2: the `deprecated` column must exist on agent_subsystems before migration 024 runs.\n"+
"After fix: either add the column in a prior migration or rewrite 024 to not use it.")
}
}