- lagoon.OrderBy takes variadic lagoon.OrderOption values; lagoon.Collate(name) emits a validated, double-quoted COLLATE clause (e.g. "pl-x-icu") - remove the exported CheckLocale and the ICU pl-PL check from Open and Use - framework test containers and per-test databases are plain PostgreSQL - lagoon README, root README and docs pages drop the locale requirement; queries-and-pagination gains a "Sorting with a collation" section backed by ExampleCollate
134 lines
3.1 KiB
Go
134 lines
3.1 KiB
Go
package lagoon
|
|
|
|
import (
|
|
"bytes"
|
|
"database/sql"
|
|
"encoding/base64"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/compass"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestUseRejectsNilSQL(t *testing.T) {
|
|
_, err := Use(t.Context(), nil)
|
|
if err == nil || !strings.Contains(err.Error(), "sql db is nil") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPublishRejectsNilHandles(t *testing.T) {
|
|
app := backpack.New(nil)
|
|
if err := Publish(nil, nil, nil); err == nil {
|
|
t.Fatal("want nil app error")
|
|
}
|
|
if err := Publish(app, nil, &gorm.DB{}); err == nil || !strings.Contains(err.Error(), "nil") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDSNEmptyWithoutConfig(t *testing.T) {
|
|
if DSN(nil) != "" {
|
|
t.Fatal("nil config must yield empty DSN")
|
|
}
|
|
}
|
|
|
|
func TestOpenFromAppMissingConfig(t *testing.T) {
|
|
_, _, err := OpenFromApp(t.Context(), nil)
|
|
if err == nil || !strings.Contains(err.Error(), "app config is missing") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
_, _, err = OpenFromApp(t.Context(), backpack.New(nil))
|
|
if err == nil || !strings.Contains(err.Error(), "app config is missing") {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSharedSQLPoolUsedByGORMAndClosed(t *testing.T) {
|
|
_, dsn := dedicatedDB(t, "lagoon_shared")
|
|
sqlDB, gdb, err := Open(t.Context(), dsn)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw, err := gdb.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if raw != sqlDB {
|
|
t.Fatal("GORM is not using the shared *sql.DB")
|
|
}
|
|
|
|
app := backpack.New(nil)
|
|
if err := Publish(app, sqlDB, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gotSQL, ok := app.Lookup[*sql.DB]()
|
|
if !ok || gotSQL != sqlDB {
|
|
t.Fatal("published *sql.DB is not the shared pool")
|
|
}
|
|
gotGORM, ok := app.Lookup[*gorm.DB]()
|
|
if !ok || gotGORM != gdb {
|
|
t.Fatal("published *gorm.DB is missing")
|
|
}
|
|
|
|
viaUse, err := Use(t.Context(), sqlDB)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
useRaw, err := viaUse.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if useRaw != sqlDB {
|
|
t.Fatal("Use must open GORM on the caller pool, not a second connection")
|
|
}
|
|
|
|
if err := sqlDB.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := sqlDB.PingContext(t.Context()); err == nil {
|
|
t.Fatal("closed pool must reject Ping")
|
|
}
|
|
if _, err := Use(t.Context(), sqlDB); err == nil {
|
|
t.Fatal("Use must fail after the shared pool is closed")
|
|
}
|
|
}
|
|
|
|
func TestOpenFromAppReadsDSN(t *testing.T) {
|
|
_, dsn := dedicatedDB(t, "lagoon_from_app")
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: lagoon-test\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cfg, err := compass.Open(compass.Options{
|
|
Dir: dir,
|
|
Environ: []string{
|
|
"SUMMER_ENV=development",
|
|
"SUMMER_DATABASE__DSN=" + dsn,
|
|
"SUMMER_APP__KEY=" + base64.StdEncoding.EncodeToString(bytes.Repeat([]byte("T"), 32)),
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := DSN(cfg); got != dsn {
|
|
t.Fatalf("DSN = %q want %q", got, dsn)
|
|
}
|
|
sqlDB, gdb, err := OpenFromApp(t.Context(), backpack.New(cfg))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = sqlDB.Close() })
|
|
raw, err := gdb.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if raw != sqlDB {
|
|
t.Fatal("OpenFromApp must share the same *sql.DB with GORM")
|
|
}
|
|
}
|