Feature 02 integration fix: repository coverage and boot-path tests (#15)
CI / ci (push) Successful in 1m22s
CI / ci (pull_request) Successful in 1m24s
Independent review Codex gpt-6-sol high: APPROVED (0 high/medium; 1 low)

Co-authored-by: dev_agent <dev_agent@cubecraftlabs.com>
Co-committed-by: dev_agent <dev_agent@cubecraftlabs.com>
This commit was merged in pull request #15.
This commit is contained in:
2026-10-03 09:27:22 -04:00
committed by approver_agent
parent 17a69f4de7
commit c1a868c48b
4 changed files with 352 additions and 4 deletions
+96
View File
@@ -0,0 +1,96 @@
package main
import (
"bytes"
"context"
"io/fs"
"log/slog"
"net/url"
"strings"
"testing"
"testing/fstest"
"time"
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/config"
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/migrations"
)
// useBootMigrations swaps bootMigrations for the test and restores it after.
// Tests that call it must not run in parallel.
func useBootMigrations(t *testing.T, m fstest.MapFS) {
t.Helper()
saved := bootMigrations
bootMigrations = m
t.Cleanup(func() { bootMigrations = saved })
}
var brokenMigrations = fstest.MapFS{
"0000_good.sql": {Data: []byte("CREATE TABLE good (id INTEGER PRIMARY KEY);")},
"0001_broken.sql": {Data: []byte("CREATE TABLE broken (id INTEGER PRIMARY KEY;")},
}
func TestOpenStoreMigrationFailureStopsBoot(t *testing.T) {
useBootMigrations(t, brokenMigrations)
db, err := openStore(context.Background(), t.TempDir())
if err == nil {
db.Close()
t.Fatal("openStore succeeded with a broken migration")
}
if db != nil {
t.Error("openStore returned a store alongside the error")
}
if !strings.Contains(err.Error(), "0001_broken.sql") {
t.Errorf("error does not name the broken migration: %v", err)
}
}
func TestOpenStoreAppliesEmbeddedMigrations(t *testing.T) {
ctx := context.Background()
db, err := openStore(ctx, t.TempDir())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
if err := db.Close(); err != nil {
t.Error(err)
}
})
var n int
if err := db.Reader.QueryRowContext(ctx, "SELECT count(*) FROM schema_migrations").Scan(&n); err != nil {
t.Fatal(err)
}
files, err := fs.Glob(migrations.FS, "*.sql")
if err != nil {
t.Fatal(err)
}
if n != len(files) {
t.Errorf("schema_migrations has %d rows, want %d", n, len(files))
}
}
func TestRunMigrationFailureReturnsBeforeListening(t *testing.T) {
useBootMigrations(t, brokenMigrations)
var logs bytes.Buffer
cfg := config.Config{
HTTPAddr: "127.0.0.1:0",
PublicURL: &url.URL{Scheme: "http", Host: "localhost"},
DataDir: t.TempDir(),
ShutdownTimeout: time.Second,
}
errc := make(chan error, 1)
go func() { errc <- run(cfg, slog.New(slog.NewJSONHandler(&logs, nil))) }()
select {
case err := <-errc:
if err == nil || !strings.Contains(err.Error(), "0001_broken.sql") {
t.Fatalf("run error = %v, want the broken migration's error", err)
}
case <-time.After(10 * time.Second):
t.Fatal("run kept going after a migration failure")
}
if strings.Contains(logs.String(), `"listening"`) {
t.Errorf("run started listening despite the migration failure: %s", logs.String())
}
}
+19 -4
View File
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"io/fs"
"log/slog"
"net/http"
"os"
@@ -40,7 +41,7 @@ func run(cfg config.Config, logger *slog.Logger) error {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
db, err := store.Open(ctx, cfg.DataDir)
db, err := openStore(ctx, cfg.DataDir)
if err != nil {
return err
}
@@ -49,9 +50,6 @@ func run(cfg config.Config, logger *slog.Logger) error {
logger.Error("close database", "error", err)
}
}()
if err := store.Migrate(ctx, db.Writer, migrations.FS); err != nil {
return err
}
router, err := server.NewRouter(logger, version, frontend.Assets())
if err != nil {
@@ -88,6 +86,23 @@ func run(cfg config.Config, logger *slog.Logger) error {
return nil
}
// bootMigrations is the migration set applied at boot. Tests replace it to
// prove a failing migration stops the boot.
var bootMigrations fs.FS = migrations.FS
// openStore opens the database in dataDir and applies bootMigrations. On a
// migration failure it closes the database and returns the error.
func openStore(ctx context.Context, dataDir string) (*store.Store, error) {
db, err := store.Open(ctx, dataDir)
if err != nil {
return nil, err
}
if err := store.Migrate(ctx, db.Writer, bootMigrations); err != nil {
return nil, errors.Join(err, db.Close())
}
return db, nil
}
// logListening logs the startup line. Only the public URL's origin is logged
// so no credential-bearing URL component can reach the log.
func logListening(logger *slog.Logger, cfg config.Config) {