- the materials admin syncs after create and update and removes after delete, once the save transaction commits (UseMaterialIndex, set at Boot) - POST and PUT /api/v1/bm/materials sync after the transaction, DELETE removes the document (its statement has no primary key, so no callback) - bm:materials-reindex [--fresh] [--if-configured] ensures the index and syncs every material; it refuses without an engine and runs nightly at 04:15 with --if-configured - TestMaterialSearchAgainstDatabase (Postgres) is written for the final verification phase
90 lines
3.0 KiB
Go
90 lines
3.0 KiB
Go
package console_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/bonfire"
|
|
"git.golem15.com/golem15/summercms/modules/lagoon"
|
|
"git.golem15.com/jakub/sm-bm-plugin/classes"
|
|
"git.golem15.com/jakub/sm-bm-plugin/console"
|
|
"git.golem15.com/jakub/sm-bm-plugin/internal/searchtest"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestMaterialsReindexRefuses(t *testing.T) {
|
|
asked := false
|
|
deps := console.MaterialsReindexDeps{
|
|
DB: func(context.Context) (*gorm.DB, func(), error) {
|
|
asked = true
|
|
return nil, func() {}, nil
|
|
},
|
|
Index: classes.NewMaterialIndexer(searchtest.App(t)),
|
|
}
|
|
cmds := []bonfire.Command{console.MaterialsReindexCommand(deps)}
|
|
var out bytes.Buffer
|
|
err := bonfire.Call(context.Background(), cmds, console.MaterialsReindexName, nil, &out)
|
|
if err == nil || !strings.Contains(err.Error(), "search.driver") || !strings.Contains(err.Error(), "search.typesense.api_key") {
|
|
t.Errorf("unconfigured engine: err = %v, want the configuration hint", err)
|
|
}
|
|
out.Reset()
|
|
if err := bonfire.Call(context.Background(), cmds, console.MaterialsReindexName, []string{"--if-configured"}, &out); err != nil {
|
|
t.Errorf("--if-configured: %v", err)
|
|
}
|
|
if !strings.Contains(out.String(), "not configured") {
|
|
t.Errorf("--if-configured output %q, want the notice", out.String())
|
|
}
|
|
if asked {
|
|
t.Error("the command opened the database without an engine")
|
|
}
|
|
}
|
|
|
|
func TestMaterialsReindexFresh(t *testing.T) {
|
|
stub := &searchtest.Stub{}
|
|
app := searchtest.App(t, searchtest.Start(t, stub)...)
|
|
gdb, err := gorm.Open(postgres.New(postgres.Config{DSN: "host=127.0.0.1"}), &gorm.Config{DryRun: true, DisableAutomaticPing: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sqlDB, err := gdb.DB()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := lagoon.Publish(app, sqlDB, gdb); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deps := console.MaterialsReindexDeps{
|
|
DB: func(context.Context) (*gorm.DB, func(), error) { return gdb, func() {}, nil },
|
|
Index: classes.NewMaterialIndexer(app),
|
|
}
|
|
cmds := []bonfire.Command{console.MaterialsReindexCommand(deps)}
|
|
coll := "/collections/" + searchtest.Index
|
|
var out bytes.Buffer
|
|
for run := 1; run <= 2; run++ {
|
|
before := len(stub.Requests())
|
|
out.Reset()
|
|
if err := bonfire.Call(context.Background(), cmds, console.MaterialsReindexName, []string{"--fresh"}, &out); err != nil {
|
|
t.Fatalf("run %d: %v\n%s", run, err, out.String())
|
|
}
|
|
var sent []string
|
|
for _, r := range stub.Requests()[before:] {
|
|
sent = append(sent, r.Method+" "+r.Path)
|
|
}
|
|
if want := []string{http.MethodDelete + " " + coll, http.MethodGet + " " + coll, http.MethodPost + " /collections"}; !slices.Equal(sent, want) {
|
|
t.Errorf("run %d sent %v, want %v", run, sent, want)
|
|
}
|
|
if !strings.Contains(out.String(), "Reindexed: 0 synced, 0 failed") {
|
|
t.Errorf("run %d output %q", run, out.String())
|
|
}
|
|
}
|
|
// The second run dropped the collection the first one created.
|
|
if !strings.Contains(out.String(), "Dropped "+searchtest.Index) {
|
|
t.Errorf("second run output %q, want Dropped", out.String())
|
|
}
|
|
}
|