85 lines
2.4 KiB
Go
85 lines
2.4 KiB
Go
package database_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
|
|
"git.k6n.net/mats/fullstack-template/internal/config"
|
|
"git.k6n.net/mats/fullstack-template/internal/database"
|
|
"git.k6n.net/mats/fullstack-template/internal/items"
|
|
)
|
|
|
|
// The whole persistence stack against an in-memory SQLite database:
|
|
// migrations produce a working schema and the real BunRepository
|
|
// round-trips items. This is also the cheapest way to catch dialect drift
|
|
// between the model and the migrations — no Postgres container required.
|
|
func TestSQLiteSchemaRoundTrip(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
db, err := database.Open(config.Config{DatabaseURL: "sqlite:file:mem?mode=memory&cache=shared"})
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
// One connection keeps the shared in-memory database stable across
|
|
// the pool (and mirrors how single-writer sqlite behaves anyway).
|
|
db.SetMaxOpenConns(1)
|
|
|
|
migrator := database.NewMigrator(db)
|
|
if err := migrator.Init(ctx); err != nil {
|
|
t.Fatalf("migrator init: %v", err)
|
|
}
|
|
if _, err := migrator.Migrate(ctx); err != nil {
|
|
t.Fatalf("migrate up: %v", err)
|
|
}
|
|
|
|
svc := items.NewService(items.NewBunRepository(db))
|
|
|
|
created, err := svc.Create(ctx, items.CreateInput{Title: "first", Description: "from sqlite"})
|
|
if err != nil {
|
|
t.Fatalf("create: %v", err)
|
|
}
|
|
if created.ID == 0 || created.Status != items.StatusActive {
|
|
t.Fatalf("create returned %+v", created)
|
|
}
|
|
|
|
got, err := svc.Get(ctx, created.ID)
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
if got.Title != "first" || got.CreatedAt.IsZero() {
|
|
t.Fatalf("get returned %+v", got)
|
|
}
|
|
|
|
archived, err := svc.Update(ctx, created.ID, items.UpdateInput{Status: ptr(items.StatusArchived)})
|
|
if err != nil {
|
|
t.Fatalf("update: %v", err)
|
|
}
|
|
if archived.Status != items.StatusArchived {
|
|
t.Fatalf("update returned %+v", archived)
|
|
}
|
|
|
|
listed, err := svc.List(ctx, items.Filter{Status: items.StatusArchived})
|
|
if err != nil {
|
|
t.Fatalf("list: %v", err)
|
|
}
|
|
if len(listed) != 1 {
|
|
t.Fatalf("list archived len = %d, want 1", len(listed))
|
|
}
|
|
|
|
if err := svc.Delete(ctx, created.ID); err != nil {
|
|
t.Fatalf("delete: %v", err)
|
|
}
|
|
if _, err := svc.Get(ctx, created.ID); !errors.Is(err, items.ErrNotFound) {
|
|
t.Fatalf("get after delete: got %v, want ErrNotFound", err)
|
|
}
|
|
|
|
// The down migration must undo the up migration cleanly.
|
|
if _, err := migrator.Rollback(ctx); err != nil {
|
|
t.Fatalf("rollback: %v", err)
|
|
}
|
|
}
|
|
|
|
func ptr[T any](v T) *T { return &v }
|