test(storage): guard against duplicate goose migration version prefixes (#336)

* test(storage): guard against duplicate goose migration version prefixes

Statically scans embedded migration filenames for repeated numeric
version prefixes and fails with a clear message, catching the class
of bug from #333 (two PRs adding 0014_*.sql independently) before
goose.Up() would panic at runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(storage): dedupe migration versions by goose's parsed int64, not raw string

versionPrefix compared raw filename prefixes, so 014_x.sql and 0014_y.sql
were treated as distinct even though goose.NumericComponent parses both
to version 14 and panics on the collision. Use goose.NumericComponent
directly so the test enforces goose's actual collision rule.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(storage): trim PR-specific framing from migration version test comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
neversettle 2026-06-20 12:49:59 +05:30 committed by GitHub
parent f98c5e56cc
commit c53c4af8bd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 39 additions and 0 deletions

View File

@ -0,0 +1,39 @@
package sqlite
import (
"testing"
"github.com/pressly/goose/v3"
)
// TestMigrationVersionsAreUnique scans the embedded migration filenames and
// parses each version with goose.NumericComponent — the same function goose
// itself uses — so prefixes that parse to the same int64 (e.g. "014" vs
// "0014") are caught as a collision, not just identical strings. Catches the
// conflict with a clear message instead of a goose panic at runtime.
func TestMigrationVersionsAreUnique(t *testing.T) {
entries, err := migrationsFS.ReadDir("migrations")
if err != nil {
t.Fatalf("read migrations dir: %v", err)
}
seen := map[int64]string{} // parsed version -> filename
for _, e := range entries {
name := e.Name()
if e.IsDir() {
continue
}
version, err := goose.NumericComponent(name)
if err != nil {
t.Errorf("migration %q has no version goose can parse: %v", name, err)
continue
}
if other, dup := seen[version]; dup {
t.Errorf("duplicate migration version %d: %s vs %s", version, other, name)
continue
}
seen[version] = name
}
}