go test passes -test.short=true, so scanning os.Args for -test.short never matched and every -short run started a Postgres container. The three TestMains now parse the flags and ask testing.Short.
254 lines
6.9 KiB
Go
254 lines
6.9 KiB
Go
package models_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/sm-journal-plugin"
|
|
"git.golem15.com/golem15/sm-journal-plugin/models"
|
|
"git.golem15.com/golem15/sm-translate-plugin"
|
|
"git.golem15.com/golem15/sm-translate-plugin/classes"
|
|
translatemodels "git.golem15.com/golem15/sm-translate-plugin/models"
|
|
"git.golem15.com/golem15/summercms/modules/lagoon"
|
|
"github.com/go-gormigrate/gormigrate/v2"
|
|
_ "github.com/jackc/pgx/v5/stdlib"
|
|
"github.com/testcontainers/testcontainers-go"
|
|
"github.com/testcontainers/testcontainers-go/modules/postgres"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var (
|
|
journalPG *postgres.PostgresContainer
|
|
journalSQL *sql.DB
|
|
journalPGErr error
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
code := 1
|
|
if !testShort() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
|
journalPGErr = startJournalPostgres(ctx)
|
|
cancel()
|
|
if journalPGErr != nil {
|
|
fmt.Fprintf(os.Stderr, "golem15.journal: testcontainers postgres: %v\n", journalPGErr)
|
|
stopJournalPostgres()
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
code = m.Run()
|
|
stopJournalPostgres()
|
|
os.Exit(code)
|
|
}
|
|
|
|
// testShort reports -short. go test passes -test.short=true, so the flags
|
|
// are parsed and read through testing.Short, never by scanning os.Args.
|
|
func testShort() bool {
|
|
flag.Parse()
|
|
return testing.Short()
|
|
}
|
|
|
|
func startJournalPostgres(ctx context.Context) error {
|
|
ctr, err := postgres.Run(ctx,
|
|
"postgres:16-alpine",
|
|
postgres.WithDatabase("golem15_journal"),
|
|
postgres.WithUsername("golem15_journal"),
|
|
postgres.WithPassword("golem15_journal"),
|
|
postgres.BasicWaitStrategies(),
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
journalPG = 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
|
|
}
|
|
journalSQL = db
|
|
return nil
|
|
}
|
|
|
|
func stopJournalPostgres() {
|
|
if journalSQL != nil {
|
|
_ = journalSQL.Close()
|
|
}
|
|
if journalPG != nil {
|
|
_ = testcontainers.TerminateContainer(journalPG)
|
|
}
|
|
}
|
|
|
|
func journalDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
if testing.Short() {
|
|
t.Skip("requires testcontainers postgres")
|
|
}
|
|
if journalPGErr != nil {
|
|
t.Fatalf("postgres unavailable: %v", journalPGErr)
|
|
}
|
|
if journalSQL == nil {
|
|
t.Fatal("postgres unavailable: container was not started")
|
|
}
|
|
gdb, err := lagoon.Use(t.Context(), journalSQL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return gdb
|
|
}
|
|
|
|
func migrateTranslateThenJournal(t *testing.T, gdb *gorm.DB) {
|
|
t.Helper()
|
|
backend := gormigrate.New(gdb, &gormigrate.Options{
|
|
TableName: "summer_migrations_summercms_cabana",
|
|
UseTransaction: true,
|
|
}, lagoon.BackendAdminMigrations)
|
|
if err := backend.Migrate(); err != nil {
|
|
t.Fatalf("backend_users migrations: %v", err)
|
|
}
|
|
translateMig := gormigrate.New(gdb, &gormigrate.Options{
|
|
TableName: "summer_migrations_golem15_translate",
|
|
UseTransaction: true,
|
|
}, (&translate.Plugin{}).Migrations())
|
|
if err := translateMig.Migrate(); err != nil {
|
|
t.Fatalf("translate migrations: %v", err)
|
|
}
|
|
journalMig := gormigrate.New(gdb, &gormigrate.Options{
|
|
TableName: "summer_migrations_golem15_journal",
|
|
UseTransaction: true,
|
|
}, (&journal.Plugin{}).Migrations())
|
|
if err := journalMig.Migrate(); err != nil {
|
|
t.Fatalf("journal migrations: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestJournalEndToEnd keeps `go test ./... -run TestJournalEndToEnd`
|
|
// from reporting [no tests to run] in this package. The production-path
|
|
// proof lives in package journal_test.
|
|
func TestJournalEndToEnd(t *testing.T) {}
|
|
|
|
func TestPostTranslatableSmoke(t *testing.T) {
|
|
gdb := journalDB(t)
|
|
migrateTranslateThenJournal(t, gdb)
|
|
|
|
if gdb.Migrator().HasTable("rainlab_journal_posts") {
|
|
t.Fatal("rainlab-era journal table must not be created")
|
|
}
|
|
if !gdb.Migrator().HasTable("golem15_journal_posts") {
|
|
t.Fatal("golem15_journal_posts was not created")
|
|
}
|
|
|
|
post := &models.Post{}
|
|
if post.MorphName() != `Golem15\Journal\Models\Post` {
|
|
t.Fatalf("MorphName = %q", post.MorphName())
|
|
}
|
|
indexes := post.TranslatableIndexes()
|
|
if len(indexes) != 1 || indexes[0] != "slug" {
|
|
t.Fatalf("TranslatableIndexes = %#v, want [slug]", indexes)
|
|
}
|
|
for _, name := range post.Fillable() {
|
|
if name == "redactor_id" || name == "content_html" || name == "user_id" {
|
|
t.Fatalf("Fillable includes forbidden %q", name)
|
|
}
|
|
}
|
|
|
|
ctx := t.Context()
|
|
post = &models.Post{
|
|
Title: "Hello",
|
|
Slug: "hello",
|
|
Excerpt: "English excerpt",
|
|
Content: "English content",
|
|
}
|
|
if err := gdb.WithContext(ctx).Create(post).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if post.ID == 0 {
|
|
t.Fatal("expected persisted post id")
|
|
}
|
|
|
|
if err := classes.SetTranslated(ctx, gdb, post, "title", "en", "Hello"); err != nil {
|
|
t.Fatalf("set en title: %v", err)
|
|
}
|
|
if err := classes.SetTranslated(ctx, gdb, post, "content", "en", "English content"); err != nil {
|
|
t.Fatalf("set en content: %v", err)
|
|
}
|
|
if err := classes.SetTranslated(ctx, gdb, post, "content_html", "en", "<p>English content</p>"); err != nil {
|
|
t.Fatalf("set en content_html: %v", err)
|
|
}
|
|
if err := classes.SetTranslated(ctx, gdb, post, "excerpt", "en", "English excerpt"); err != nil {
|
|
t.Fatalf("set en excerpt: %v", err)
|
|
}
|
|
if err := classes.SetTranslated(ctx, gdb, post, "title", "pl", "Witaj"); err != nil {
|
|
t.Fatalf("set pl title: %v", err)
|
|
}
|
|
if err := classes.SetTranslated(ctx, gdb, post, "slug", "pl", "witaj"); err != nil {
|
|
t.Fatalf("set pl slug: %v", err)
|
|
}
|
|
|
|
got, err := classes.Translated(ctx, gdb, post, "title", "pl")
|
|
if err != nil {
|
|
t.Fatalf("read pl title: %v", err)
|
|
}
|
|
if got != "Witaj" {
|
|
t.Fatalf("pl title = %#v, want Witaj", got)
|
|
}
|
|
|
|
var stored models.Post
|
|
if err := gdb.WithContext(ctx).First(&stored, post.ID).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if stored.Title != "Hello" {
|
|
t.Fatalf("host title = %q, want Hello", stored.Title)
|
|
}
|
|
if stored.Slug != "hello" {
|
|
t.Fatalf("host slug = %q, want hello", stored.Slug)
|
|
}
|
|
|
|
var attrs []translatemodels.Attribute
|
|
if err := gdb.WithContext(ctx).
|
|
Where("model_id = ? AND model_type = ?", fmt.Sprint(post.ID), post.MorphName()).
|
|
Find(&attrs).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(attrs) != 1 {
|
|
t.Fatalf("attribute rows = %d, want 1 (Polish only)", len(attrs))
|
|
}
|
|
if attrs[0].Locale != "pl" {
|
|
t.Fatalf("attribute locale = %q, want pl", attrs[0].Locale)
|
|
}
|
|
if attrs[0].AttributeData == nil {
|
|
t.Fatal("attribute_data is nil")
|
|
}
|
|
var data map[string]any
|
|
if err := json.Unmarshal([]byte(*attrs[0].AttributeData), &data); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if data["title"] != "Witaj" {
|
|
t.Fatalf("attribute_data.title = %#v", data["title"])
|
|
}
|
|
if data["slug"] != "witaj" {
|
|
t.Fatalf("attribute_data.slug = %#v", data["slug"])
|
|
}
|
|
|
|
var enCount int64
|
|
if err := gdb.WithContext(ctx).Model(&translatemodels.Attribute{}).
|
|
Where("locale = ? AND model_id = ?", "en", fmt.Sprint(post.ID)).
|
|
Count(&enCount).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if enCount != 0 {
|
|
t.Fatalf("en attribute rows = %d, want 0 (English lives on the host row)", enCount)
|
|
}
|
|
}
|