An entry whose fingerprint names a toolchain version of its language other than the agreed one is held in the state waits (one key <module>.<fingerprint>), says wait-held and wait-ended (ran when the agreed toolchain names the version, released by builder_release) on its stream waits, says wait-held again for every key at its start; builder_waits and builder_release; its setting toolchain-wait-minutes. Not built: the bound's finding toolchain-waits (its scope is not in the design). Builds: design 47 G §672, §267, §276, §633 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
85 lines
2.8 KiB
Go
85 lines
2.8 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
|
|
if _, ok := w.held[k]; !ok {
|
|
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")
|
|
}
|
|
})
|
|
}
|