Files
mesh-delivery/modules/mesh-delivery-builder/internal/build/buildread_test.go
T
jschoubben 12e3f2dc48 BL17d: builder_build answers a module's build keys whole; builder_builds_since takes module; builder_stuck's fingerprint pinned whole
builder_build reads the builds and asked states, and the tools bundle follows the catalog half itself (registrations for the
watched branches, revision per branch) for `newest`; the manifest names the tool and the two seat verbs.

Builds: design 47 G §589, A-87
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-11 23:28:08 +01:00

84 lines
4.0 KiB
Go

package build
import (
"encoding/json"
"sort"
"strings"
"testing"
"time"
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
)
const fp2 = "src2:2222222222222222222222222222222222222222222222222222222222222222"
func stateOf(vals map[string][]byte) StateRead {
return StateRead{
Keys: func() ([]string, error) {
var ks []string
for k := range vals {
ks = append(ks, k)
}
sort.Strings(ks)
return ks, nil
},
Get: func(k string) (json.RawMessage, time.Time, error) { return vals[k], time.Time{}, nil }}
}
// Design 47 G §589: builder_build by module answers its keys newest first with whole fingerprints, event-builds and the open
// ask, and names the watched branches whose newest entry names a key's fingerprint; a module none of whose keys the newest
// entry names says so; with a fingerprint, that key alone.
func TestBuilderBuildAnswersAModulesKeysWhole(t *testing.T) {
failed, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildFailed, EventBuilds: 3, Manifest: mdigest('a'),
Error: "transport fault: connection, node-build-go ace, dial tcp: connection refused"})
done, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: mdigest('a'), Artifacts: []builds.BuiltArtifact{{Name: "x", Kind: "file", Digest: "sha256:" + strings.Repeat("a", 64)}}})
k1, _ := builds.BuilderBuildKey("m", fp1)
k2, _ := builds.BuilderBuildKey("m", fp2)
other, _ := builds.BuilderBuildKey("other", fp1)
vals := map[string][]byte{k1: failed, k2: done, other: done}
ask := occ.Kept{Ask: oc.Ask{ID: "retake-1", About: k1, Expires: occ.FormatTime(time.Now().Add(time.Hour))}, Asked: time.Now()}
askRaw, _ := json.Marshal(ask)
r := &BuildReader{Builds: stateOf(vals), Asked: stateOf(map[string][]byte{"ask.retake-1": askRaw}),
Newest: func(string) (map[string]string, error) { return map[string]string{"main": fp1, "feature": fp2}, nil }}
a, err := r.Build("m", "")
if err != nil || len(a.Builds) != 2 {
t.Fatalf("builds = %+v, %v, want the module's two keys", a, err)
}
var row BuildRow
for _, b := range a.Builds {
if b.Fingerprint == fp1 {
row = b
}
}
if row.Fingerprint != fp1 || len(row.Fingerprint) != len("src2:")+64 || row.State != builds.BuildFailed || row.EventBuilds != 3 || row.Node != "ace" ||
!strings.HasPrefix(row.Error, "transport fault: connection, node-build-go ace, dial tcp") || row.Ask == nil || row.Ask.ID != "retake-1" || len(row.Newest) != 1 || row.Newest[0] != "main" {
t.Errorf("the failed key = %+v, want its fingerprint whole, its error whole, event-builds 3, the open ask and newest main", row)
}
if one, err := r.Build("m", fp2); err != nil || len(one.Builds) != 1 || one.Builds[0].Fingerprint != fp2 || one.Builds[0].Newest[0] != "feature" {
t.Errorf("one key = %+v, %v", one, err)
}
r.Newest = func(string) (map[string]string, error) {
return map[string]string{"main": "src2:" + strings.Repeat("c", 64)}, nil
}
if n, err := r.Build("m", ""); err != nil || !strings.Contains(n.Note, "no build key of m is the newest entry's") || !strings.Contains(n.Note, "main names src2:"+strings.Repeat("c", 64)) {
t.Errorf("a module none of whose keys the newest entry names: %+v, %v", n, err)
}
}
// Design 47 G §589: builder_stuck answers each key's fingerprint whole, as the build-input fingerprint the catalog graph entry carries it.
func TestBuilderStuckAnswersTheFingerprintWhole(t *testing.T) {
building, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildBuilding, Step: "asked", Manifest: mdigest('a')})
k, _ := builds.BuilderBuildKey("m", fp1)
out, err := StuckReader{Builds: stateOf(map[string][]byte{k: building})}.Stuck("m")
if err != nil {
t.Fatal(err)
}
rows := out["stuck"].([]Stuck)
if len(rows) != 1 || rows[0].FP != fp1 {
t.Fatalf("stuck = %+v, want the fingerprint %s whole", rows, fp1)
}
}