Add repository and boot-path tests for Feature 02 review
Addresses feature-review findings F1 and F2 on PR #14. F1: internal/store/repository_test.go inserts, reads back and updates a row in week_plans, plan_days, suggestions, shopping_lists, shopping_groups and shopping_items against a migrated temp database, using raw SQL and seeding foreign-key parents. F2: TestMigrateReopenSameDataDirIsNoOp reopens the same data directory and proves Migrate leaves schema_migrations and the schema unchanged. cmd/server extracts the open+migrate boot step into openStore over an injectable bootMigrations set; tests prove a broken migration makes openStore and run return the error before listening. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"io/fs"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
@@ -201,3 +202,62 @@ func TestMigrateBootstrapThenEmbeddedInitApplies(t *testing.T) {
|
||||
t.Error("table from 0001_init was not created")
|
||||
}
|
||||
}
|
||||
|
||||
// schemaSQL returns every schema object's definition, so a test can prove a
|
||||
// later Migrate created or altered nothing.
|
||||
func schemaSQL(t *testing.T, s *Store) []string {
|
||||
t.Helper()
|
||||
rows, err := s.Reader.Query("SELECT type || ' ' || name || ': ' || coalesce(sql, '') FROM sqlite_schema ORDER BY type, name")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []string
|
||||
for rows.Next() {
|
||||
var def string
|
||||
if err := rows.Scan(&def); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = append(out, def)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestMigrateReopenSameDataDirIsNoOp(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
dir := t.TempDir()
|
||||
|
||||
first, err := Open(ctx, dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := Migrate(ctx, first.Writer, migrations.FS); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before, beforeSchema := migrationRows(t, first), schemaSQL(t, first)
|
||||
if err := first.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
second, err := Open(ctx, dir)
|
||||
if err != nil {
|
||||
t.Fatalf("reopen: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := second.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
if err := Migrate(ctx, second.Writer, migrations.FS); err != nil {
|
||||
t.Fatalf("migrate after reopen: %v", err)
|
||||
}
|
||||
if after := migrationRows(t, second); !slices.Equal(after, before) {
|
||||
t.Errorf("schema_migrations changed on reopen:\n got %v\nwant %v", after, before)
|
||||
}
|
||||
if afterSchema := schemaSQL(t, second); !slices.Equal(afterSchema, beforeSchema) {
|
||||
t.Errorf("schema changed on reopen:\n got %v\nwant %v", afterSchema, beforeSchema)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user