- RecordSaved with a change outside golem15.sitemap.lastmod_ignore moves the lastmod of the record's rows (only the changed locale's for a translated change); a no-op save, an ignored change or a rebuild does not - RecordDeleted takes the record's rows out of the files at once - record events queue one rebuild per golem15.sitemap.rebuild_delay_seconds (rebuild_pending_until, P33-12); the job clears it when it starts - sitemap:rebuild [--queue], scheduled nightly at 03:00 (pact.HasSchedule)
73 lines
2.1 KiB
Go
73 lines
2.1 KiB
Go
package classes
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestAssignSlots pins stable numbering without a database (D-30, RESEARCH
|
|
// Pitfall 5): appends fill the last file of their group, a left-out row
|
|
// keeps its number as a hole, only a renumber packs the listed rows again,
|
|
// and groups are numbered apart.
|
|
func TestAssignSlots(t *testing.T) {
|
|
t0 := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)
|
|
rows := []*Slot{}
|
|
add := func(id uint64, grp string, at time.Duration) *Slot {
|
|
s := &Slot{ID: id, Grp: grp, FirstSeen: t0.Add(at), Listed: true}
|
|
rows = append(rows, s)
|
|
return s
|
|
}
|
|
files := func(grp string) []int {
|
|
var out []int
|
|
for _, r := range rows {
|
|
if r.Grp == grp && r.Listed && r.FileNo != nil {
|
|
out = append(out, *r.FileNo)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
eq := func(a []int, b ...int) bool {
|
|
if len(a) != len(b) {
|
|
return false
|
|
}
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
for i := uint64(1); i <= 5; i++ {
|
|
add(i, "pages", 0)
|
|
}
|
|
add(9, "posts", 0)
|
|
if !AssignSlots(rows, 2, true) || !eq(files("pages"), 1, 1, 2, 2, 3) || !eq(files("posts"), 1) {
|
|
t.Fatalf("first numbering: pages %v posts %v", files("pages"), files("posts"))
|
|
}
|
|
if AssignSlots(rows, 2, false) {
|
|
t.Fatal("a second pass changed numbers")
|
|
}
|
|
rows[1].Listed = false
|
|
if AssignSlots(rows, 2, false) || !eq(files("pages"), 1, 2, 2, 3) || *rows[1].FileNo != 1 {
|
|
t.Fatalf("after a delete: %v, hole %v", files("pages"), rows[1].FileNo)
|
|
}
|
|
add(6, "pages", time.Hour)
|
|
add(7, "pages", 2*time.Hour)
|
|
AssignSlots(rows, 2, false)
|
|
if *rows[len(rows)-2].FileNo != 3 || *rows[len(rows)-1].FileNo != 4 {
|
|
t.Fatalf("appends: %v %v", *rows[len(rows)-2].FileNo, *rows[len(rows)-1].FileNo)
|
|
}
|
|
AssignSlots(rows, 3, true)
|
|
if !eq(files("pages"), 1, 1, 1, 2, 2, 2) || rows[1].FileNo != nil {
|
|
t.Fatalf("renumber: %v, left-out row %v", files("pages"), rows[1].FileNo)
|
|
}
|
|
// A returning row fills its own hole when it still has one.
|
|
rows[1].Listed = true
|
|
n := 1
|
|
rows[1].FileNo = &n
|
|
AssignSlots(rows, 3, false)
|
|
if *rows[1].FileNo != 1 {
|
|
t.Fatalf("returning row moved to %d", *rows[1].FileNo)
|
|
}
|
|
}
|