package controllers import ( "context" "slices" "strconv" "testing" "git.golem15.com/jakub/sm-bm-plugin/models" "gorm.io/gorm" ) // recordingIndex records the after-commit calls of the materials admin. type recordingIndex struct { calls []string txs []*gorm.DB } func (r *recordingIndex) SyncAfterCommit(_ context.Context, tx *gorm.DB, id uint) { r.calls = append(r.calls, "sync "+itoa(id)) r.txs = append(r.txs, tx) } func (r *recordingIndex) RemoveAfterCommit(_ context.Context, tx *gorm.DB, id uint) { r.calls = append(r.calls, "remove "+itoa(id)) r.txs = append(r.txs, tx) } func (r *recordingIndex) QueueExtract(_ context.Context, tx *gorm.DB, id uint) { r.calls = append(r.calls, "queue "+itoa(id)) r.txs = append(r.txs, tx) } func itoa(id uint) string { return strconv.FormatUint(uint64(id), 10) } func TestMaterialsAdminHooks(t *testing.T) { t.Cleanup(func() { UseMaterialIndex(nil) }) var c materialsAdmin ctx := context.Background() m := &models.Material{ID: 7} // No index installed: nothing to do, and no error. UseMaterialIndex(nil) for name, fn := range map[string]func(context.Context, any) error{"create": c.FormAfterCreate, "update": c.FormAfterUpdate, "delete": c.FormAfterDelete} { if err := fn(ctx, m); err != nil { t.Errorf("%s without an index: %v", name, err) } } rec := &recordingIndex{} UseMaterialIndex(rec) if err := c.FormAfterCreate(ctx, m); err != nil { t.Fatal(err) } if err := c.FormAfterUpdate(ctx, m); err != nil { t.Fatal(err) } if err := c.FormAfterDelete(ctx, m); err != nil { t.Fatal(err) } // Create and update queue the file text job (in the save transaction) // before the after-commit sync; delete queues nothing. if want := []string{"queue 7", "sync 7", "queue 7", "sync 7", "remove 7"}; !slices.Equal(rec.calls, want) { t.Errorf("calls = %v, want %v", rec.calls, want) } // Outside a cabana write there is no transaction: the index then runs // at once (lagoon.AfterCommit with a nil handle). for i, tx := range rec.txs { if tx != nil { t.Errorf("call %d got a transaction outside a write", i) } } // A model of another type is an error and schedules nothing. rec.calls = nil for name, fn := range map[string]func(context.Context, any) error{"create": c.FormAfterCreate, "update": c.FormAfterUpdate, "delete": c.FormAfterDelete} { if err := fn(ctx, &models.Course{ID: 7}); err == nil { t.Errorf("%s with a course: no error", name) } } var nilMaterial *models.Material if err := c.FormAfterUpdate(ctx, nilMaterial); err == nil { t.Error("update with a nil material: no error") } if len(rec.calls) != 0 { t.Errorf("calls for a wrong model = %v", rec.calls) } }