Files
mesh-delivery/modules/mesh-delivery-builder/internal/build/waits_test.go
T
jschoubben 524fbb02ef WM13 (builder half): a key queued behind a package says wait-held and wait-ended in the one wait form
The builder says wait-held for a key queued behind a package, the package as its part and on (package:<ref>), on its
stream waits, and wait-ended published once the key is claimed; a toolchain wait never ends by that, and a package wait
never by a toolchain's end. Files: internal/build/waits.go (Package, On, WaitPublished), internal/build/run.go (Hold at
the queued result, End at the claim), cmd/mesh-delivery-builder/waits.go (Part in the body, the End rule).

Builds: design 47 G A-192, §499

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-12 05:52:10 +01:00

86 lines
2.9 KiB
Go

package build
import (
"context"
"sync"
"testing"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
)
// memWaits records the waits held and ended.
type memWaits struct {
mu sync.Mutex
held map[string]ToolchainWait
ended []string
}
func (w *memWaits) Hold(_ context.Context, t ToolchainWait) {
w.mu.Lock()
defer w.mu.Unlock()
if w.held == nil {
w.held = map[string]ToolchainWait{}
}
w.held[t.Module+"."+t.Fingerprint] = t
}
func (w *memWaits) End(_ context.Context, module, fp, how string) bool {
w.mu.Lock()
defer w.mu.Unlock()
k := module + "." + fp
t, ok := w.held[k]
if !ok || (t.Package != "") != (how == WaitPublished) { // as the builder's waitsKept ends them: a package wait by its publishing alone
return false
}
delete(w.held, k)
w.ended = append(w.ended, how)
return true
}
// Design 47 G §672, §267, §276: an entry whose fingerprint names a toolchain version other than the agreed one is held,
// built and ended `ran` when the agreed toolchain moves to that version; and one held is built with the running build
// module by Release and ended `released`.
func TestAnEntryWhoseFingerprintNamesAnotherToolchainWaitsAndIsBuiltWhenItIsAgreedOrReleased(t *testing.T) {
old := map[string]builds.ToolchainUsed{"go": {Version: "go1.26.0", Recipe: "1"}}
t.Run("ran", func(t *testing.T) {
r := newRig(t, goBundle)
w := &memWaits{}
r.b.Waits = w
r.b.Module(context.Background(), "m", moduleValueWith(t, "modules/m", old))
r.b.Wait()
if len(w.held) != 1 || len(r.st.vals) != 0 {
t.Fatalf("held %v, keys %v: want one wait and nothing written", w.held, r.st.vals)
}
for _, h := range w.held {
if h.On() != "toolchain:go@go1.26.0" {
t.Errorf("the wait is on %s", h.On())
}
}
r.tools.Set("ace", tcOf("go", "go1.26.0"))
r.tools.Set("novox", tcOf("go", "go1.26.0"))
r.b.Reconsider(context.Background())
r.b.Wait()
if v := valueOf(t, r.st, r.key); v.State != builds.BuildDone || len(w.held) != 0 || len(w.ended) != 1 || w.ended[0] != WaitRan {
t.Errorf("build %+v, held %v, ended %v: want done and one wait ended ran", v, w.held, w.ended)
}
})
t.Run("released", func(t *testing.T) {
r := newRig(t, goBundle)
w := &memWaits{}
r.b.Waits = w
v := moduleValueWith(t, "modules/m", old)
r.b.Module(context.Background(), "m", v)
r.b.Wait()
if why := r.b.Release(context.Background(), "m", fp1, "the build module runs", "operator"); why != "" {
t.Fatalf("release refused: %s", why)
}
r.b.Wait()
if got := valueOf(t, r.st, r.key); got.State != builds.BuildDone || got.Toolchains["go"].Version != "go1.27.1" || len(w.ended) != 1 || w.ended[0] != WaitReleased {
t.Errorf("build %+v, ended %v: want done with the running toolchain and a wait ended released", got, w.ended)
}
if why := r.b.Release(context.Background(), "m", fp1, "again", "operator"); why == "" {
t.Error("a second release of an entry that is not held was taken")
}
})
}