- conga: TestOutcome*, TestCancelQueuedNeverRuns, TestCancelRunningCancelsCtx, TestStopJobFromWorker, TestManagerPHPSemantics, principal, delay, registration, worker and queue-setting branches; TestQueueClear and TestQueueWork move to commands_test.go with the batch/state and queue-filter cases (coverage 92.5%) - scheduler: validation, ordering, missing catalog, log writer, dueAt - lagoon: TestQueueMigrationsUpDown (River v7 + summer_jobs, rollback, idempotent rerun), OnDatabase isolation, Transaction edges - bonfire TestCallEdges, pact TestCadence
133 lines
3.9 KiB
Go
133 lines
3.9 KiB
Go
package lagoon
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// TestOnDatabaseAfterActivate covers the production boot order: plugins
|
|
// register database hooks at Boot, before serve publishes the database.
|
|
func TestOnDatabaseAfterActivate(t *testing.T) {
|
|
db, _ := dedicatedDB(t, "lagoon_ondatabase")
|
|
gdb, err := Use(t.Context(), db)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
t.Run("before_publish_runs_on_publish", func(t *testing.T) {
|
|
app := backpack.New(nil)
|
|
calls := 0
|
|
var gotSQL *sql.DB
|
|
var gotGDB *gorm.DB
|
|
if err := OnDatabase(app, func(s *sql.DB, g *gorm.DB) error {
|
|
calls++
|
|
gotSQL, gotGDB = s, g
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if calls != 0 {
|
|
t.Fatalf("hook ran %d times before Publish", calls)
|
|
}
|
|
if err := Publish(app, db, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if calls != 1 || gotSQL != db || gotGDB != gdb {
|
|
t.Fatalf("after Publish: calls=%d sql=%v gdb=%v", calls, gotSQL == db, gotGDB == gdb)
|
|
}
|
|
})
|
|
|
|
t.Run("after_publish_runs_now", func(t *testing.T) {
|
|
app := backpack.New(nil)
|
|
if err := Publish(app, db, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
calls := 0
|
|
if err := OnDatabase(app, func(*sql.DB, *gorm.DB) error { calls++; return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if calls != 1 {
|
|
t.Fatalf("hook ran %d times, want 1", calls)
|
|
}
|
|
})
|
|
|
|
t.Run("gorm_only_published_runs_now", func(t *testing.T) {
|
|
app := backpack.New(nil)
|
|
if err := app.Publish(gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var gotSQL *sql.DB
|
|
if err := OnDatabase(app, func(s *sql.DB, _ *gorm.DB) error { gotSQL = s; return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if gotSQL != db {
|
|
t.Fatal("hook did not receive the pool behind the published *gorm.DB")
|
|
}
|
|
})
|
|
|
|
t.Run("errors_surface", func(t *testing.T) {
|
|
boom := errors.New("boom")
|
|
app := backpack.New(nil)
|
|
if err := OnDatabase(app, func(*sql.DB, *gorm.DB) error { return boom }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Publish(app, db, gdb); !errors.Is(err, boom) {
|
|
t.Fatalf("Publish err = %v, want the hook error", err)
|
|
}
|
|
if err := OnDatabase(app, func(*sql.DB, *gorm.DB) error { return boom }); !errors.Is(err, boom) {
|
|
t.Fatalf("OnDatabase err = %v, want the hook error", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestOnDatabaseIsolationAndErrors covers the per-app hook queue: two apps
|
|
// keep separate queues, a published app runs later hooks at once, and nil
|
|
// arguments are refused.
|
|
func TestOnDatabaseIsolationAndErrors(t *testing.T) {
|
|
db, _ := dedicatedDB(t, "lagoon_ondatabase_isolation")
|
|
gdb, err := Use(t.Context(), db)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a, b := backpack.New(nil), backpack.New(nil)
|
|
var ranA, ranB int
|
|
if err := OnDatabase(a, func(*sql.DB, *gorm.DB) error { ranA++; return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := OnDatabase(b, func(*sql.DB, *gorm.DB) error { ranB++; return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Publish(a, db, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ranA != 1 || ranB != 0 {
|
|
t.Fatalf("after publishing app a: a ran %d, b ran %d; want 1 and 0", ranA, ranB)
|
|
}
|
|
if err := Publish(b, db, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ranA != 1 || ranB != 1 {
|
|
t.Fatalf("after publishing app b: a ran %d, b ran %d; want 1 and 1", ranA, ranB)
|
|
}
|
|
if err := OnDatabase(nil, func(*sql.DB, *gorm.DB) error { return nil }); err == nil {
|
|
t.Fatal("nil app accepted")
|
|
}
|
|
if err := OnDatabase(a, nil); err == nil {
|
|
t.Fatal("nil hook accepted")
|
|
}
|
|
// A second failing queued hook is never reached: Publish returns the
|
|
// first error.
|
|
c := backpack.New(nil)
|
|
boom := errors.New("first")
|
|
second := false
|
|
_ = OnDatabase(c, func(*sql.DB, *gorm.DB) error { return boom })
|
|
_ = OnDatabase(c, func(*sql.DB, *gorm.DB) error { second = true; return nil })
|
|
if err := Publish(c, db, gdb); !errors.Is(err, boom) || second {
|
|
t.Fatalf("Publish = %v (second ran %v), want the first error only", err, second)
|
|
}
|
|
}
|