Named JOURNAL-001/002 fillable, FormatHTML unsafe tags, rollback/remigrate, RSS/categories/tags/media, and TestSearchGateOff with zero Typesense HTTP. Co-authored-by: Cursor <cursoragent@cursor.com>
171 lines
5.0 KiB
Go
171 lines
5.0 KiB
Go
package updates
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/lagoon"
|
|
"github.com/go-gormigrate/gormigrate/v2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var journalTables = []string{
|
|
"golem15_journal_posts",
|
|
"golem15_journal_categories",
|
|
"golem15_journal_tags",
|
|
"golem15_journal_posts_categories",
|
|
"golem15_journal_posts_tags",
|
|
"golem15_journal_settings",
|
|
}
|
|
|
|
func TestJournalMigrationsRollbackAndRemigrate(t *testing.T) {
|
|
sqlDB := dedicatedDB(t, fmt.Sprintf("journal_mig_%d", time.Now().UnixNano()))
|
|
gdb, err := lagoon.Use(t.Context(), sqlDB)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
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)
|
|
}
|
|
m := journalMigrator(gdb)
|
|
if err := m.Migrate(); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
assertJournalSchema(t, gdb)
|
|
|
|
for i := 0; i < len(All()); i++ {
|
|
if err := m.RollbackLast(); err != nil {
|
|
t.Fatalf("rollback %d: %v", i, err)
|
|
}
|
|
}
|
|
for _, table := range journalTables {
|
|
if gdb.Migrator().HasTable(table) {
|
|
t.Fatalf("%s survived rollback", table)
|
|
}
|
|
}
|
|
if gdb.Migrator().HasColumn("backend_users", "golem15_bloghub_author_slug") {
|
|
t.Fatal("golem15_bloghub_author_slug survived rollback")
|
|
}
|
|
assertNoRainlabJournalTables(t, gdb)
|
|
if err := m.Migrate(); err != nil {
|
|
t.Fatalf("re-migrate: %v", err)
|
|
}
|
|
assertJournalSchema(t, gdb)
|
|
}
|
|
|
|
func journalMigrator(gdb *gorm.DB) *gormigrate.Gormigrate {
|
|
return gormigrate.New(gdb, &gormigrate.Options{
|
|
TableName: "summer_migrations_golem15_journal",
|
|
UseTransaction: true,
|
|
}, All())
|
|
}
|
|
|
|
func assertJournalSchema(t *testing.T, gdb *gorm.DB) {
|
|
t.Helper()
|
|
for _, name := range journalTables {
|
|
if !gdb.Migrator().HasTable(name) {
|
|
t.Fatalf("missing table %s", name)
|
|
}
|
|
}
|
|
assertNoRainlabJournalTables(t, gdb)
|
|
if !gdb.Migrator().HasColumn("backend_users", "golem15_bloghub_author_slug") {
|
|
t.Fatal("backend_users.golem15_bloghub_author_slug missing")
|
|
}
|
|
|
|
wantPosts := []string{
|
|
"id", "user_id", "redactor_id", "title", "slug", "excerpt", "content",
|
|
"content_html", "published_at", "published", "is_pinned", "metadata",
|
|
"sources", "created_at", "updated_at",
|
|
}
|
|
for _, col := range wantPosts {
|
|
if !gdb.Migrator().HasColumn("golem15_journal_posts", col) {
|
|
t.Fatalf("golem15_journal_posts missing column %s", col)
|
|
}
|
|
}
|
|
assertUdt(t, gdb, "golem15_journal_posts", "metadata", "jsonb")
|
|
assertUdt(t, gdb, "golem15_journal_posts", "sources", "jsonb")
|
|
assertIndex(t, gdb, "golem15_journal_posts_slug_unique")
|
|
assertIndex(t, gdb, "golem15_journal_categories_slug_unique")
|
|
assertIndex(t, gdb, "golem15_journal_tags_slug_unique")
|
|
|
|
var typesense bool
|
|
if err := gdb.WithContext(t.Context()).
|
|
Raw(`SELECT search_use_typesense FROM golem15_journal_settings WHERE id = 1`).
|
|
Scan(&typesense).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if typesense {
|
|
t.Fatal("search_use_typesense default must be false")
|
|
}
|
|
var showAll bool
|
|
if err := gdb.WithContext(t.Context()).
|
|
Raw(`SELECT show_all_posts FROM golem15_journal_settings WHERE id = 1`).
|
|
Scan(&showAll).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !showAll {
|
|
t.Fatal("show_all_posts default must be true")
|
|
}
|
|
}
|
|
|
|
func assertNoRainlabJournalTables(t *testing.T, gdb *gorm.DB) {
|
|
t.Helper()
|
|
var leftover []string
|
|
if err := gdb.WithContext(t.Context()).
|
|
Raw(`SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND (tablename LIKE 'rainlab\_journal\_%' OR tablename LIKE 'winter\_journal\_%')`).
|
|
Scan(&leftover).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(leftover) != 0 {
|
|
t.Fatalf("rainlab/winter-era journal tables present: %v", leftover)
|
|
}
|
|
}
|
|
|
|
func assertUdt(t *testing.T, gdb *gorm.DB, table, column, want string) {
|
|
t.Helper()
|
|
var udt string
|
|
if err := gdb.WithContext(t.Context()).Raw(
|
|
`SELECT udt_name FROM information_schema.columns WHERE table_name = ? AND column_name = ?`,
|
|
table, column,
|
|
).Scan(&udt).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if udt != want {
|
|
t.Fatalf("%s.%s udt = %q, want %q", table, column, udt, want)
|
|
}
|
|
}
|
|
|
|
func assertIndex(t *testing.T, gdb *gorm.DB, name string) {
|
|
t.Helper()
|
|
var n int64
|
|
if err := gdb.WithContext(t.Context()).Raw(
|
|
`SELECT COUNT(*) FROM pg_indexes WHERE schemaname = 'public' AND indexname = ?`,
|
|
name,
|
|
).Scan(&n).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 1 {
|
|
t.Fatalf("index %s count = %d, want 1", name, n)
|
|
}
|
|
}
|
|
|
|
func assertUniqueSlug(t *testing.T, gdb *gorm.DB, table, slug string) {
|
|
t.Helper()
|
|
if err := gdb.Exec(`INSERT INTO `+table+` (slug) VALUES (?)`, slug).Error; err != nil {
|
|
t.Fatalf("first insert %s.%s: %v", table, slug, err)
|
|
}
|
|
err := gdb.Exec(`INSERT INTO `+table+` (slug) VALUES (?)`, slug).Error
|
|
if err == nil {
|
|
t.Fatalf("duplicate slug on %s was accepted", table)
|
|
}
|
|
if !strings.Contains(strings.ToLower(err.Error()), "unique") && !strings.Contains(strings.ToLower(err.Error()), "duplicate") {
|
|
t.Fatalf("duplicate slug error = %v", err)
|
|
}
|
|
}
|