// Package pgtest starts one Postgres container per test binary for the // plugin's database tests and migrates golem15.user, golem15.feedback and // the framework tables (system_files, the job queue) into it. The test // binary must link the golem15.feedback plugin (its package or an // importer of it), which registers itself in init. package pgtest import ( "bytes" "context" "database/sql" "os" "path/filepath" "sync" "testing" "time" _ "git.golem15.com/golem15/sm-user-plugin" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/compass" "git.golem15.com/golem15/summercms/modules/lagoon" "git.golem15.com/golem15/summercms/modules/party" "github.com/testcontainers/testcontainers-go/modules/postgres" "gorm.io/gorm" ) // PluginIDs are the plugins the database is migrated for. var PluginIDs = []string{"golem15.user", "golem15.feedback"} var ( once sync.Once gdb *gorm.DB sqlDB *sql.DB err error ) // DB returns the shared, migrated database. Tests that need an empty // table delete its rows first. func DB(t testing.TB) *gorm.DB { t.Helper() once.Do(func() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) defer cancel() if err = lagoon.PublishEncryptionKeys(nil, bytes.Repeat([]byte("F"), 32), nil); err != nil { return } var ctr *postgres.PostgresContainer ctr, err = postgres.Run(ctx, "postgres:16-alpine", postgres.WithDatabase("feedback"), postgres.WithUsername("feedback"), postgres.WithPassword("feedback"), postgres.BasicWaitStrategies(), ) if err != nil { return } var dsn string if dsn, err = ctr.ConnectionString(ctx, "sslmode=disable"); err != nil { return } if sqlDB, err = sql.Open("pgx", dsn); err != nil { return } if gdb, err = lagoon.Use(ctx, sqlDB); err != nil { return } var dir string if dir, err = os.MkdirTemp("", "feedback-pgtest-"); err != nil { return } defer os.RemoveAll(dir) if err = os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: feedback-pgtest\n"), 0o644); err != nil { return } var cfg *compass.Config if cfg, err = compass.Open(compass.Options{Dir: dir, Environ: []string{ "SUMMER_ENV=development", // A throwaway secret: golem15.user refuses to boot without one. "SUMMER_GOLEM15__USER__JWT__SECRET=pgtest-only-jwt-secret-0123456789abcdef", }}); err != nil { return } var plugins []party.Plugin if plugins, err = party.Activate(backpack.New(cfg), PluginIDs); err != nil { return } err = lagoon.Migrate(gdb, plugins) }) if err != nil { t.Fatalf("pgtest: %v", err) } return gdb } // SQL is the database's *sql.DB. func SQL(t testing.TB) *sql.DB { DB(t) return sqlDB }