Files
summercms/modules/lagoon/connection_test.go
Jakub Zych 037dc53030 feat(lagoon): per-query collation for OrderBy, drop the database locale check
- 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
2026-10-01 09:51:03 +02:00

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")
}
}