The builder finds a build module as the indexer's seed does: the build seat whose acting rule `build` has an `on` matching the artifact's language or kind:image, and that seat's holder, read from the seat list's definitions and the claims of the catalog half's manifests. Task.Module, every lane key, the unpublished modules, the toolchain sources, the ends watched, the sayer and builder_stuck (through `<seat>.steps`) derive from it; the floor's sources are the holders of the seats git and mesh-catalog. buildrun.GoBuildModule, NodeBuildModule, LanguageOf, buildstep.BuildModuleOf use, build.ImageBuildModule and StuckBuildModules are gone from the builder (the checker keeps its own names in two small files until its part reads them from the list). Builds: design 47 G §7, §428, §704, §204, A-82 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
88 lines
4.1 KiB
Go
88 lines
4.1 KiB
Go
package build
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
|
|
|
|
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
|
|
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
func haveValue(t *testing.T, phase, health string) []byte {
|
|
t.Helper()
|
|
b, err := nodeengineclient.EncodeHave(nodeengine.HaveByNodeModuleValue{Phase: phase, Health: health})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// 1. A module of an archive only: the real indexer gives an archive no language (inputs.go languagesOf), so its
|
|
// fingerprint names no toolchain, and the builder builds it on the build module's nodes with no toolchain agreed.
|
|
func TestAnArchiveOnlyModuleIsBuiltAlthoughItsFingerprintNamesNoToolchain(t *testing.T) { // review round 4, 1
|
|
r := newRig(t, archiveA)
|
|
v := func() builds.BuilderBuild {
|
|
r.b.Module(context.Background(), "m", moduleValueWith(t, "modules/m", nil))
|
|
r.b.Wait()
|
|
if _, ok := r.st.vals[r.key]; !ok {
|
|
t.Fatal("no build key was written for the archive-only module")
|
|
}
|
|
return valueOf(t, r.st, r.key)
|
|
}()
|
|
if v.State != builds.BuildDone || len(v.Artifacts) != 1 || v.Artifacts[0].Kind != "archive" || len(v.Toolchains) != 0 {
|
|
t.Fatalf("build = %+v, want done with the archive and no toolchain named", v)
|
|
}
|
|
if n := len(r.bm.callsOf("build_go_build")); n != 1 {
|
|
t.Errorf("%d go builds, want one, on one node (ADR 0478 clause 4)", n)
|
|
}
|
|
}
|
|
|
|
func TestABundleAndAnArchiveOfOneBuildModuleStillNeedTheAgreedToolchain(t *testing.T) { // review round 4, 1
|
|
p, err := PlanOf(catalogue.Manifest{Module: "m", Build: &catalogue.Build{Artifacts: []catalogue.Artifact{goBundle, archiveA}}}, testSeats())
|
|
if err != nil || !p.NeedsToolchain(testGo) {
|
|
t.Errorf("a plan with a Go bundle: %v, %v", p.NeedsToolchain(testGo), err)
|
|
}
|
|
p, _ = PlanOf(catalogue.Manifest{Module: "m", Build: &catalogue.Build{Artifacts: []catalogue.Artifact{archiveA}}}, testSeats())
|
|
if p.NeedsToolchain(testGo) {
|
|
t.Error("a plan of an archive needs a toolchain")
|
|
}
|
|
}
|
|
|
|
func TestClaimLeavesAKeyFailedForDifferingDigestsAlone(t *testing.T) { // review round 4, 2
|
|
st := newMem()
|
|
seed(t, st, builds.BuilderBuild{State: builds.BuildFailed, Error: buildrun.DigestsDifferPrefix + " the nodes built tool to different digests: ace x; novox y"})
|
|
writes := st.writes
|
|
got, err := (Claimer{Store: st, By: "novox.a"}).Claim(context.Background(), "m", fp1, "", ClaimOptions{TakeOver: true})
|
|
if err != nil || got != nil || st.writes != writes {
|
|
t.Errorf("claim = %v, %v, %d writes (was %d), want none and no write", got, err, st.writes, writes)
|
|
}
|
|
}
|
|
|
|
// 6. A key found building is taken over, whoever holds it.
|
|
func TestABuildLeftBuildingByAnyBuilderIsTakenOverAtStart(t *testing.T) { // review round 4, 6; 1607/AC3, ADR 0478 clauses 5, 6
|
|
st := newMem()
|
|
seed(t, st, builds.BuilderBuild{State: builds.BuildBuilding, By: "novox.a"})
|
|
if got, err := (Claimer{Store: st, By: "novox.a"}).Claim(context.Background(), "m", fp1, "", ClaimOptions{}); err != nil || got == nil {
|
|
t.Errorf("own building key: claim = %v, %v, want it taken again", got, err)
|
|
}
|
|
if got, err := (Claimer{Store: st, By: "ace.b"}).Claim(context.Background(), "m", fp1, "", ClaimOptions{TakeOver: true}); err != nil || got == nil || got.Build.By != "novox.a" {
|
|
t.Errorf("another node's building key at start: claim = %v, %v, want it taken over", got, err)
|
|
}
|
|
if got, _ := (Claimer{Store: st, By: "ace.b"}).Claim(context.Background(), "m", fp1, "", ClaimOptions{}); got != nil {
|
|
t.Errorf("another builder's building key after the start was taken: a running builder's key is its own")
|
|
}
|
|
}
|
|
|
|
func TestABuilderFindingAKeyBuildingByAnotherNodeBuildsItOnStart(t *testing.T) { // review round 4, 6
|
|
r := newRig(t, goBundle)
|
|
seed(t, r.st, builds.BuilderBuild{State: builds.BuildBuilding, By: "ace.builder", Manifest: manifestD})
|
|
v := r.consider(t, "modules/m")
|
|
if v.State != builds.BuildDone || v.By != "novox.builder" {
|
|
t.Errorf("build = %+v, want it taken over and done by novox.builder", v)
|
|
}
|
|
}
|