ADR 0573 §4 makes refusing a member for its mesh-sdk pin a fault of the check (issue 1585, S14). Every Go check ask now carries the latest published version of each package, or the head of the group member that publishes it, so the pin check, its forge reads and its tests go, and the controller's tests read mesh-sdk at the version it is built with. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
203 lines
9.4 KiB
Go
203 lines
9.4 KiB
Go
package check
|
|
|
|
import (
|
|
"maps"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/buildstep"
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// published is the latest published version of each mesh package, as the indexer's modules say (Examiner.Published).
|
|
type published delivery.PackageVersions
|
|
|
|
func (p published) LatestPackages() delivery.PackageVersions {
|
|
return maps.Clone(delivery.PackageVersions(p))
|
|
}
|
|
|
|
// packagesOfFetch is the package versions the fetch of repository was handed (delivery.StepAsk.Packages, issue 1585).
|
|
func packagesOfFetch(t *testing.T, b *bench, repository string) delivery.PackageVersions {
|
|
t.Helper()
|
|
for _, f := range b.steps.tool("fetch") {
|
|
if f.args["repository"] == repository {
|
|
p, err := buildstep.PackagesArg(f.args["packages"])
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return p
|
|
}
|
|
}
|
|
t.Fatalf("%s was not fetched", repository)
|
|
return nil
|
|
}
|
|
|
|
// ADR 0573 §4 (issue 1585 S14): a group's Go member is built against the head of the group's mesh-sdk member, whatever its
|
|
// go.mod names (an older head of it included, which issue 1624's pin check refused), and never refused for its pin; a
|
|
// pull request alone is built against the latest published version of each package, and its own repository's packages
|
|
// come with its tree.
|
|
func TestAGroupMemberIsBuiltAgainstTheSDKMembersHeadWhateverItsGoModNames(t *testing.T) { // 1624/AC2, AC4 as ADR 0573 §4 changes them
|
|
const contract = "git.novox.be/novox/mesh-delivery/contract"
|
|
b := newBench(t)
|
|
b.fetch.Modules = []string{"modules/m"}
|
|
b.ex.Published = published{SDKModulePath: trunkS, contract: trunkA}
|
|
v := b.judge(t, caseOf(t, pullOf(repoA, 7, head1), pullOf(repoSDK, 12, head2))).Verdict
|
|
if v.State != delivery.VerdictPass {
|
|
t.Fatalf("verdict = %+v", v)
|
|
}
|
|
if got := packagesOfFetch(t, b, repoA); len(got) != 1 || got[SDKModulePath] != head2 {
|
|
t.Errorf("the member's packages = %v, want mesh-sdk at the group's head %s alone (its own contract comes with its tree)", got, head2)
|
|
}
|
|
if s := besideOf(t, b, repoA)[repoSDK]; s.Commit != head2 {
|
|
t.Error("mesh-delivery's tests were not given the SDK member at its head")
|
|
}
|
|
b = newBench(t)
|
|
b.ex.Published = published{SDKModulePath: trunkS, contract: trunkA}
|
|
if v := b.judge(t, caseOf(t, pullOf("novox/mesh-catalog", 7, head1))).Verdict; v.State != delivery.VerdictPass {
|
|
t.Fatalf("a pull request alone: verdict = %+v", v)
|
|
}
|
|
if got := packagesOfFetch(t, b, "novox/mesh-catalog"); len(got) != 2 || got[SDKModulePath] != trunkS || got[contract] != trunkA {
|
|
t.Errorf("a pull request alone is built against %v, want every package at its latest published version", got)
|
|
}
|
|
}
|
|
|
|
type runsAt map[string]string
|
|
|
|
func (r runsAt) CommitOf(module string) string { return r[module] }
|
|
|
|
func besideOf(t *testing.T, b *bench, repository string) map[string]BesideRef {
|
|
t.Helper()
|
|
out := map[string]BesideRef{}
|
|
for _, f := range b.steps.tool("fetch") {
|
|
if f.args["repository"] == repository {
|
|
refs, _ := refsOf(f.args["beside"]), true
|
|
for _, r := range refs {
|
|
out[r.Repository] = r
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestTheSiblingsAreWhereTheTestsStateThem(t *testing.T) { // review D2, ADR 0484 clause 4
|
|
const controller, catalogue, host = "novox/mesh-controller", "novox/mesh-catalog", "novox/mesh-host"
|
|
hostRuns := strings.Repeat("7", 40)
|
|
b := newBench(t)
|
|
b.ex.Trunks = trunksOf(t, map[string]string{controller: trunkA, catalogue: trunkS, host: trunkA2, SDKRepository: "9999999999999999999999999999999999999999"})
|
|
b.ex.Runs = runsAt{"mesh-host": hostRuns}
|
|
// A group of the controller and the catalogue: the controller's tests read the catalogue's trunk, not the group's head.
|
|
out := b.judge(t, caseOf(t, pullOf(controller, 7, head1), pullOf(catalogue, 12, head2)))
|
|
// ADR 0548 §6, issue 568's own example: the verdict names the node-engine at the commit the mesh runs, and mesh-sdk at the
|
|
// trunk the catalogue's tests read it at; the catalogue, a member here, is not named.
|
|
if out.Beside[host] != hostRuns || out.Beside[catalogue] != "" || out.Beside[SDKRepository] != "9999999999999999999999999999999999999999" {
|
|
t.Errorf("the siblings named for the verdict = %v, want the node-engine at %s and mesh-sdk at its trunk", out.Beside, hostRuns[:12])
|
|
}
|
|
got := besideOf(t, b, controller)
|
|
if c := got[catalogue]; c.Commit != trunkS || c.Ref != "" {
|
|
t.Errorf("the catalogue beside the controller = %+v, want its trunk %s", c, trunkS)
|
|
}
|
|
if h := got[host]; h.Commit != hostRuns {
|
|
t.Errorf("the node-engine beside the controller = %+v, want the commit the mesh runs %s", h, hostRuns)
|
|
}
|
|
// ADR 0573 §2: the controller is built against mesh-sdk's latest published version, so its tests read that one too,
|
|
// not the commit its go.mod names.
|
|
if s := got[SDKRepository]; s.Commit != "9999999999999999999999999999999999999999" {
|
|
t.Errorf("mesh-sdk beside the controller = %+v, want its trunk", s)
|
|
}
|
|
}
|
|
|
|
// 1295/R4g: the node-engine's tests read the controller's manifest, so a mesh-host pull request has mesh-controller beside it:
|
|
// at the group member's head when the group holds one, else at its trunk.
|
|
func hostCase(t *testing.T, pulls ...delivery.CandidatePull) *Case {
|
|
t.Helper()
|
|
c, err := delivery.DecodeCandidate(candidateOf(t, "feat/x", pulls...))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cs := CaseOf(c, map[string]string{"novox/mesh-host": trunkA, controllerRepo: trunkA2})
|
|
if cs == nil {
|
|
t.Fatal("no case")
|
|
}
|
|
return cs
|
|
}
|
|
|
|
func TestTheNodeEnginesTestsHaveTheControllerBesideThem(t *testing.T) {
|
|
const host = "novox/mesh-host"
|
|
b := newBench(t)
|
|
b.ex.Trunks = trunksOf(t, map[string]string{host: trunkA, controllerRepo: trunkA2, catalogueRepository: trunkS, SDKRepository: trunkS})
|
|
b.judge(t, hostCase(t, pullOf(host, 5, head1)))
|
|
if c := besideOf(t, b, host)[controllerRepo]; c.Commit != trunkA2 || c.Ref != "" {
|
|
t.Errorf("the controller beside the node-engine alone = %+v, want its trunk %s", c, trunkA2)
|
|
}
|
|
b = newBench(t)
|
|
b.ex.Trunks = trunksOf(t, map[string]string{host: trunkA, controllerRepo: trunkA2, catalogueRepository: trunkS, SDKRepository: trunkS})
|
|
b.judge(t, hostCase(t, pullOf(host, 5, head1), pullOf(controllerRepo, 9, head2)))
|
|
if c := besideOf(t, b, host)[controllerRepo]; c.Commit != head2 || c.Ref != "refs/pull/9/head" {
|
|
t.Errorf("the controller beside the node-engine in a group = %+v, want the member's head %s", c, head2)
|
|
}
|
|
}
|
|
|
|
// 1887/A12: the change's own repository is placed beside it at the trunk it is merged onto, for every repository, so a
|
|
// shrink-only list test reads the trunk's copy at $MESH_CHECK_BESIDE/<name>.
|
|
func TestTheChangesOwnRepositoryIsBesideItAtItsTrunk(t *testing.T) {
|
|
b := newBench(t)
|
|
b.judge(t, caseOf(t, pullOf(repoA, 7, head1)))
|
|
got := besideOf(t, b, repoA)
|
|
if own := got[repoA]; own.Commit != trunkA || own.Ref != "" {
|
|
t.Fatalf("the repository beside its own change = %+v, want its trunk %s", own, trunkA)
|
|
}
|
|
}
|
|
|
|
// 1887/A12: a catalogue change's siblings hold the catalogue itself at the trunk it is merged onto, beside mesh-sdk and
|
|
// mesh-controller, so the catalogue's shrink-only list tests read $MESH_CHECK_BESIDE/mesh-catalog.
|
|
func TestACatalogueChangeHasTheCatalogueBesideItAtItsTrunk(t *testing.T) {
|
|
b := newBench(t)
|
|
b.ex.Trunks = trunksOf(t, map[string]string{catalogueRepository: trunkA, SDKRepository: trunkS, controllerRepo: trunkA2})
|
|
out := b.judge(t, caseOf(t, pullOf(catalogueRepository, 12, head1)))
|
|
// ADR 0548 §6: the outcome names the siblings read at their trunk's head, never the repository it merges.
|
|
if out.Beside[SDKRepository] != trunkS || out.Beside[controllerRepo] != trunkA2 || out.Beside[catalogueRepository] != "" {
|
|
t.Errorf("the siblings named for the verdict = %v, want mesh-sdk and mesh-controller at their trunks and not the catalogue", out.Beside)
|
|
}
|
|
got := besideOf(t, b, catalogueRepository)
|
|
if c := got[catalogueRepository]; c.Commit != trunkA || c.Ref != "" {
|
|
t.Fatalf("the catalogue beside its own change = %+v, want its trunk %s", c, trunkA)
|
|
}
|
|
if _, ok := got[SDKRepository]; !ok {
|
|
t.Errorf("mesh-sdk is no longer beside a catalogue change: %v", got)
|
|
}
|
|
}
|
|
|
|
// 1887/A12: a mesh-lab head gets a check: with its trunk known it is judged like any repository, its Go fetch finding
|
|
// the nested modules itself.
|
|
func TestAMeshLabHeadGetsACheck(t *testing.T) {
|
|
const lab = "novox/mesh-lab"
|
|
raw := candidateOf(t, "fix/x", pullOf(lab, 3, head1))
|
|
c, err := delivery.DecodeCandidate(raw)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cs := CaseOf(c, map[string]string{lab: trunkA})
|
|
if cs == nil || len(cs.Pulls) != 1 || cs.Pulls[0].Repository != lab || len(cs.Left) != 0 {
|
|
t.Fatalf("the case = %+v, want mesh-lab#3 judged", cs)
|
|
}
|
|
b := newBench(t)
|
|
if v := b.judge(t, cs).Verdict; v.State != delivery.VerdictPass {
|
|
t.Fatalf("verdict = %+v", v)
|
|
}
|
|
if fetched := b.steps.tool("fetch"); len(fetched) == 0 || fetched[0].args["repository"] != lab {
|
|
t.Fatalf("mesh-lab was not fetched: %+v", fetched)
|
|
}
|
|
}
|
|
|
|
// 1295: the node-engine's step-nine test fails without the controller beside it, so a checker that knows no trunk head of the
|
|
// controller fails the check at the placing, loudly, and does not place none.
|
|
func TestTheNodeEnginesCheckFailsWhereTheControllersTrunkIsNotKnown(t *testing.T) {
|
|
const host = "novox/mesh-host"
|
|
b := newBench(t)
|
|
b.ex.Trunks = trunksOf(t, map[string]string{host: trunkA, catalogueRepository: trunkS, SDKRepository: trunkS})
|
|
v := b.judge(t, hostCase(t, pullOf(host, 5, head1))).Verdict
|
|
if v.State != delivery.VerdictFail || !strings.Contains(v.Failed.Words, "mesh-controller") || !strings.Contains(v.Failed.Words, "cannot be placed") {
|
|
t.Fatalf("verdict = %+v", v)
|
|
}
|
|
}
|