Files
mesh-catalog/modules/mesh-delivery/cmd/mesh-delivery/times_test.go
T
jschoubben 2711e812c8
mesh/merge-gate pass: builds mesh-delivery → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
mesh/delivery-group group feat/525-leaf-budget-three-minutes merged: every member is merged
Hold a leaf delivery to three minutes in times (hq ADR 0304 decision 4, issue 525)
ADR 0304 lowered a leaf module's delivery budget from five minutes to
three; times says each class against the controller's same budget.
2026-10-12 01:45:14 +02:00

262 lines
11 KiB
Go

package main
import (
"strings"
"testing"
"time"
)
// novox/hq ADR 0282 (issue 382): a delivery keeps its delivery time, class and phases from its walk, from its
// own merge; `times` answers each class's median and worst against its budget. Measurement only.
func ms(t time.Time) *time.Time { return &t }
// phasesOf is a walk's phases as the controller says them: its earliest merge at from, then each phase of the
// given lengths one after the other, the last ending the walk.
func phasesOf(class string, from time.Time, lengths ...struct {
name string
d time.Duration
}) *WalkPhases {
p := &WalkPhases{Class: class, From: ms(from)}
at := from
for _, l := range lengths {
start := at
at = at.Add(l.d)
p.Phases = append(p.Phases, WalkPhase{Name: l.name, Tier: -1, State: phaseMeasured, Start: ms(start), End: ms(at),
TookMS: l.d.Milliseconds()})
}
p.End = ms(at)
p.TotalMS = at.Sub(from).Milliseconds()
return p
}
type ph = struct {
name string
d time.Duration
}
// walkedOnce is a merge walked to the end, the walk's phases given: its delivery's id.
func walkedOnce(w *world, number int, head, merge string, phases *WalkPhases) string {
w.t.Helper()
repo := "novox/mesh-catalog"
p := pr(repo, number, head, "feat/x")
w.h.PullUpdated(p)
w.h.Checked(verdictMoving(repo, number, head, "app"))
w.h.PullMerged(mergedAt(p, merge, phases.From.Add(10*time.Second)))
walk := aWalk("plan-"+merge[:6], repo, merge, false)
walk.Delivery = &WalkDelivery{Merges: []WalkMerge{{Repository: repo, Commit: merge}}}
w.h.WalkMoved(w.ctl.put(walk))
w.settleAll()
walk = w.ctl.walk(walk.ID)
walk.State, walk.Revision = walkDone, walk.Revision+1
walk.Modules = map[string]*WalkModule{"app": {State: "built", SentAt: phases.End}}
walk.Phases = phases
w.h.WalkMoved(w.ctl.put(walk))
w.settleAll()
return IDOf(repo, head)
}
// A delivery's time runs from its own merge — ten seconds after the walk's earliest — to its walk's end, and its
// phases still add up to it.
func TestADeliveryKeepsItsTimeFromItsOwnMerge(t *testing.T) {
w := newWorld(t)
from := t0.Add(time.Minute)
id := walkedOnce(w, 7, "head7", "merge7aaaa", phasesOf("leaf", from, ph{"window", 90 * time.Second},
ph{"queued", 5 * time.Second}, ph{"build", 25 * time.Second}, ph{"judgement", 150 * time.Second},
ph{"apply", 20 * time.Second}))
d := w.delivery(id)
if d.Time == nil {
t.Fatalf("no delivery time kept: %+v", d)
}
if d.Time.TookMS != (280*time.Second).Milliseconds() || d.Time.Class != "leaf" || !d.Time.Over {
t.Fatalf("time %dms (want 280000, from its own merge, over a leaf's three minutes), class %s, over %v", d.Time.TookMS, d.Time.Class, d.Time.Over)
}
var sum int64
for _, p := range d.Time.Phases {
if p.State == phaseMeasured {
sum += p.TookMS
}
}
if sum+d.Time.UnknownMS != d.Time.TookMS {
t.Fatalf("the phases add up to %dms + %dms unknown, its time is %dms", sum, d.Time.UnknownMS, d.Time.TookMS)
}
if d.Time.Phases[0].TookMS != 80000 || !strings.HasPrefix(d.Time.Longest, "judgement") {
t.Fatalf("its window starts at its own merge (80s), longest judgement: %+v %s", d.Time.Phases[0], d.Time.Longest)
}
// Its own merge after a first phase whose start is unknown: the unknown time moves, the sum holds.
p := phasesOf("leaf", from, ph{"window", 90 * time.Second}, ph{"build", 30 * time.Second})
p.Phases[0] = WalkPhase{Name: "window", Tier: -1, State: phaseUnknown, End: p.Phases[0].End}
p.UnknownMS = 90000
dt := timeOf(&Delivery{MergedAt: from.Add(10 * time.Second)}, Walk{ID: "w", Phases: p})
if dt.UnknownMS != 80000 || dt.TookMS != 110000 {
t.Fatalf("unknown first phase: %+v", dt)
}
// Merged after the walk's first phase ended (a later merge carried by the walk, its window already running): that
// phase is before its merge, the next starts at its merge, and nothing is negative.
p = phasesOf("leaf", from, ph{"window", 30 * time.Second}, ph{"queued", 60 * time.Second}, ph{"build", 30 * time.Second})
p.Phases[0].State, p.Phases[0].Start, p.Phases[0].TookMS = phaseUnknown, nil, 0
dt = timeOf(&Delivery{MergedAt: from.Add(45 * time.Second)}, Walk{ID: "w", Phases: p})
if dt.Unreliable != "" || dt.UnknownMS != 0 || dt.TookMS != 75000 || dt.Phases[0].State != "none" ||
dt.Phases[1].TookMS != 45000 || dt.Phases[2].TookMS != 30000 {
t.Fatalf("merged inside the second phase: %+v", dt)
}
assertSums(t, dt)
// Merged before the walk's earliest merge: the wait is unknown time, and the sum holds.
dt = timeOf(&Delivery{MergedAt: from.Add(-20 * time.Second)}, Walk{ID: "w", Phases: p})
if dt.UnknownMS != 50000 || dt.TookMS != 140000 {
t.Fatalf("merged before the walk's first merge: %+v", dt)
}
assertSums(t, dt)
// Moments out of order: unreliable, and no number.
bad := phasesOf("leaf", from, ph{"window", 30 * time.Second}, ph{"build", 30 * time.Second})
early := from.Add(10 * time.Second)
bad.Phases[1].End = &early
bad.End = &early
dt = timeOf(&Delivery{MergedAt: from}, Walk{ID: "w", Phases: bad})
if dt.Unreliable == "" || dt.TookMS != 0 {
t.Fatalf("out of order is unreliable, with no time: %+v", dt)
}
for _, ph := range dt.Phases {
if ph.TookMS != 0 || ph.Start != nil || ph.State != phaseUnknown {
t.Fatalf("an unreliable time says no phase's time: %+v", ph)
}
}
// The walk's phases not reaching its end: unreliable.
short := phasesOf("leaf", from, ph{"window", 30 * time.Second})
later := from.Add(time.Minute)
short.End = &later
if dt := timeOf(&Delivery{MergedAt: from}, Walk{ID: "w", Phases: short}); dt.Unreliable == "" || dt.TookMS != 0 {
t.Fatalf("phases short of the walk's end: %+v", dt)
}
// Merged after the walk's end: unreliable.
if dt := timeOf(&Delivery{MergedAt: from.Add(time.Hour)}, Walk{ID: "w", Phases: p}); dt.Unreliable == "" || dt.TookMS != 0 {
t.Fatalf("merged after its walk's end: %+v", dt)
}
// Exactly its budget is within it.
p = phasesOf("leaf", from, ph{"build", 3*time.Minute + 10*time.Second})
if dt := timeOf(&Delivery{MergedAt: from.Add(10 * time.Second)}, Walk{ID: "w", Phases: p}); dt.Over || dt.TookMS != 180000 {
t.Fatalf("three minutes is within a leaf's budget: %+v", dt)
}
p = phasesOf("leaf", from, ph{"build", 3*time.Minute + 11*time.Second})
if dt := timeOf(&Delivery{MergedAt: from.Add(10 * time.Second)}, Walk{ID: "w", Phases: p}); !dt.Over {
t.Fatalf("a second past three minutes is over a leaf's budget: %+v", dt)
}
// Seen again, unchanged: not written again (issue 326).
before := w.store.puts
w.h.Reconcile()
w.settleAll()
if w.store.puts != before {
t.Fatalf("a delivery whose time did not change was written again")
}
}
// A walk whose end is not known gives no time; a phase unknown in the walk stays unknown, never a zero.
func TestNoEndNoTime(t *testing.T) {
w := newWorld(t)
p := phasesOf("core", t0, ph{"window", time.Minute}, ph{"build", time.Minute})
p.End, p.TotalMS = nil, 0
p.Phases = append(p.Phases, WalkPhase{Name: "apply", Tier: -1, State: phaseUnknown, Said: "waiting for ace"})
p.Said = "its end is unknown: apply (waiting for ace)"
id := walkedOnce(w, 8, "head8", "merge8bbbb", p)
if d := w.delivery(id); d.Time != nil {
t.Fatalf("a time without an end: %+v", d.Time)
}
got, err := w.h.Times(0, id)
if err != nil || !strings.Contains(mustString(got), "waiting for ace") {
t.Fatalf("the delivery's time says why it is not known: %v %v", got, err)
}
a := w.h.times(7)
if len(a.Unknown) != 1 || !strings.Contains(a.Unknown[0], "waiting for ace") {
t.Fatalf("a delivered delivery with no known time is said: %+v", a.Unknown)
}
}
// `times`: each class's median, worst, within and over its budget, its newest delivery, and every delivery over.
func TestTimesSaysEachClassAgainstItsBudget(t *testing.T) {
w := newWorld(t)
leaf := func(n int, d time.Duration, at time.Duration) string {
return walkedOnce(w, n, "head"+string(rune('a'+n)), "merge"+string(rune('a'+n))+"zzzz",
phasesOf("leaf", t0.Add(at), ph{"window", 10 * time.Second}, ph{"judgement", d}))
}
leaf(1, 1*time.Minute, 0)
leaf(2, 2*time.Minute, time.Hour)
over := leaf(3, 6*time.Minute, 2*time.Hour)
walkedOnce(w, 4, "headcore", "mergekore1", phasesOf("core", t0.Add(3*time.Hour), ph{"judgement", 9 * time.Minute}))
w.later(4 * time.Hour)
a := w.h.times(7)
if len(a.Classes) != 2 || a.Classes[0].Class != "leaf" {
t.Fatalf("classes: %+v", a.Classes)
}
l := a.Classes[0]
// Each delivery's time is from its own merge, ten seconds after the walk's: 1m, 2m, 6m.
if l.Count != 3 || l.Within != 2 || l.Over != 1 || l.MedianMS != (2*time.Minute).Milliseconds() ||
l.WorstMS != (6*time.Minute).Milliseconds() || l.WorstID != over {
t.Fatalf("leaf: %+v", l)
}
if l.Latest == nil || l.Latest.ID != over || !l.Latest.Over || !strings.HasPrefix(l.Latest.Longest, "judgement") {
t.Fatalf("the newest leaf delivery: %+v", l.Latest)
}
if c := a.Classes[1]; c.Count != 1 || c.Over != 0 || c.Latest == nil || c.Latest.Over {
t.Fatalf("core within ten minutes: %+v", c)
}
if len(a.Over) != 1 || a.Over[0].ID != over {
t.Fatalf("over: %+v", a.Over)
}
if !strings.Contains(a.Line, "leaf: median 2m0s, worst 6m0s, 2 of 3 within 3m0s") {
t.Fatalf("the line: %s", a.Line)
}
// Past the window, nothing.
w.later(8 * 24 * time.Hour)
if a := w.h.times(7); a.Classes[0].Count != 0 || a.Classes[0].Latest != nil {
t.Fatalf("deliveries older than the window are not counted: %+v", a.Classes[0])
}
}
func mustString(v any) string { return string(mustJSON(v)) }
// assertSums checks a delivery time's measured phases and unknown time add up to it, and none is negative.
func assertSums(t *testing.T, dt *DeliveryTime) {
t.Helper()
sum := dt.UnknownMS
if dt.UnknownMS < 0 {
t.Fatalf("negative unknown time: %+v", dt)
}
for _, p := range dt.Phases {
if p.TookMS < 0 {
t.Fatalf("negative phase %s: %+v", p.Name, p)
}
if p.State == phaseMeasured {
sum += p.TookMS
}
}
if sum != dt.TookMS {
t.Fatalf("the phases add up to %dms, the delivery time is %dms: %+v", sum, dt.TookMS, dt)
}
}
// An unreliable time is said among the unknown, never in a median, an over count or the newest of its class.
func TestAnUnreliableTimeIsNeverCounted(t *testing.T) {
w := newWorld(t)
good := walkedOnce(w, 11, "headgood", "mergegood1", phasesOf("leaf", t0, ph{"build", 2 * time.Minute}))
bad := phasesOf("leaf", t0.Add(time.Hour), ph{"window", 30 * time.Second}, ph{"build", 9 * time.Minute})
early := t0.Add(time.Hour + 10*time.Second)
bad.Phases[1].End, bad.End = &early, &early
unreliable := walkedOnce(w, 12, "headbad", "mergebad01", bad)
if d := w.delivery(unreliable); d.Time == nil || d.Time.Unreliable == "" {
t.Fatalf("the out-of-order walk gave a time: %+v", d.Time)
}
w.later(2 * time.Hour)
a := w.h.times(7)
l := a.Classes[0]
if l.Count != 1 || l.Over != 0 || l.Latest == nil || l.Latest.ID != good || l.WorstID != good {
t.Fatalf("an unreliable time was counted: %+v", l)
}
found := false
for _, u := range a.Unknown {
found = found || strings.HasPrefix(u, unreliable+": its time is unreliable")
}
if !found {
t.Fatalf("the unreliable delivery is not said among the unknown: %v", a.Unknown)
}
}