Files
sm-menu-plugin/testmain_test.go
Jakub Zych 08f99b8aad feat(17-04): menu plugin admin with registry types, URL checks and tree reorder
- golem15.menu plugin, tables golem15_menu_menus and golem15_menu_menu_entries with the PHP columns plus a nullable url_pattern (D-02)
- MenuEntry BeforeSave ports PHP beforeSave: nest columns 0, menu from the parent, sort_order after the menu's last
- entry type dropdown: url, divider and the signpost registry types; reference depends on type through signpost.ReferenceOptions
- URL scheme allowlist (errors.url_scheme), target _self or _blank, menu and parent cycle checks
- menu filter, toolbar reorder/create/delete and config_reorder.yaml partitioned by menu
- navigation Menus with Menus and Menu entries, permission golem15.menu.manage_menu, en and pl phrasebooks
- TestMenuAdminSmoke
2026-10-12 17:30:50 +02:00

116 lines
2.6 KiB
Go

package menu_test
import (
"context"
"database/sql"
"flag"
"fmt"
"net/url"
"os"
"strings"
"testing"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
)
var (
pgContainer *postgres.PostgresContainer
pgAdmin *sql.DB
pgDSN string
pgErr error
)
// TestMain starts one Postgres container for the smoke tests unless the run
// is -short. go test passes -test.short=true, so the flag is parsed and read
// through testing.Short, never by scanning os.Args.
func TestMain(m *testing.M) {
flag.Parse()
if !testing.Short() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
pgErr = startPostgres(ctx)
cancel()
if pgErr != nil {
fmt.Fprintf(os.Stderr, "golem15.menu: testcontainers postgres: %v\n", pgErr)
}
}
code := m.Run()
stopPostgres()
os.Exit(code)
}
func startPostgres(ctx context.Context) error {
ctr, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("golem15_menu"),
postgres.WithUsername("golem15_menu"),
postgres.WithPassword("golem15_menu"),
postgres.BasicWaitStrategies(),
)
if err != nil {
return err
}
pgContainer = ctr
dsn, err := ctr.ConnectionString(ctx, "sslmode=disable")
if err != nil {
return err
}
db, err := sql.Open("pgx", dsn)
if err != nil {
return err
}
if err := db.PingContext(ctx); err != nil {
_ = db.Close()
return err
}
pgAdmin, pgDSN = db, dsn
return nil
}
func stopPostgres() {
if pgAdmin != nil {
_ = pgAdmin.Close()
}
if pgContainer != nil {
_ = testcontainers.TerminateContainer(pgContainer)
}
}
// freshDB creates a database of its own for one test and drops it after.
func freshDB(t *testing.T) *sql.DB {
t.Helper()
if testing.Short() {
t.Skip("requires testcontainers postgres")
}
if pgErr != nil {
t.Fatalf("postgres unavailable: %v", pgErr)
}
if pgAdmin == nil {
t.Fatal("postgres unavailable: container was not started")
}
name := fmt.Sprintf("menu_%d", time.Now().UnixNano())
quoted := `"` + strings.ReplaceAll(name, `"`, `""`) + `"`
if _, err := pgAdmin.ExecContext(t.Context(), `CREATE DATABASE `+quoted+` TEMPLATE template0 ENCODING 'UTF8'`); err != nil {
t.Fatalf("create %s: %v", name, err)
}
u, err := url.Parse(pgDSN)
if err != nil {
t.Fatal(err)
}
u.Path = "/" + name
db, err := sql.Open("pgx", u.String())
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
_ = db.Close()
_, _ = pgAdmin.ExecContext(context.Background(), `DROP DATABASE IF EXISTS `+quoted+` WITH (FORCE)`)
})
if err := db.PingContext(t.Context()); err != nil {
t.Fatal(err)
}
return db
}