Files
mesh-catalog/modules/mesh-delivery/cmd/mesh-delivery/checks_test.go
T
jochen 13894744a7
mesh/merge-gate pass: builds gitea, mesh-delivery → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
mesh/delivery-group group feat/delivery-checks-verb delivered: every member is delivered
Answer what the mesh's checks said of a pull request, as mesh-delivery's checks verb (hq ADR 0239)
Reading a pull request's mesh/merge-gate and mesh/repo-check meant scraping the controller's journal:
the forge clips each status to 140 characters and nothing returned the verdict whole. mesh-delivery
already keeps the verdict; it now keeps the machine that ran it, the layers' modules and the report,
and its checks verb joins that to the forge's statuses, read through a new gitea_commit_statuses tool
that also says whether the base's protection lets the commit merge.

after: novox/mesh-controller
2026-10-07 19:36:41 +02:00

243 lines
10 KiB
Go

package main
import (
"encoding/json"
"strings"
"testing"
)
// The `checks` verb (novox/hq ADR 0239): what the mesh's checks said of a pull request's head or a commit —
// the forge's statuses, the verdict whole as the controller said it, and whether the base's protection lets
// it merge.
// checkedAs is the controller's `checked` as it comes off the bus, both layers said.
func checkedAs(t *testing.T, repo string, number int, sha, gate, gateSaid, repoVerdict, repoSaid string) CheckedEvent {
t.Helper()
owner, name, _ := strings.Cut(repo, "/")
raw := map[string]any{"owner": owner, "repo": name, "number": number, "commit": sha, "verdict": gate,
"summary": gateSaid, "id": "build-" + sha[:8], "on": "the-build-node", "report": "== compose\n" + gateSaid,
"gate": map[string]any{"verdict": gate, "summary": gateSaid, "modules": []string{"app"}, "dependents": []string{"web"}},
"repo-check": map[string]any{"verdict": repoVerdict, "summary": repoSaid}}
var c CheckedEvent
if err := json.Unmarshal(mustJSON(raw), &c); err != nil {
t.Fatal(err)
}
return c
}
// statusesAsTheForgeSets puts the two statuses the forge's holder sets from a verdict: clipped, as it keeps them.
func statusesAsTheForgeSets(w *world, repo, sha string, c CheckedEvent) {
owner, name, _ := strings.Cut(repo, "/")
_ = w.forge.Status(owner, name, sha, ctxGate, forgeStateOf(c.Gate.Verdict), clip(c.Gate.Verdict+": "+c.Gate.Summary, 40), "https://forge.invalid/pr")
_ = w.forge.Status(owner, name, sha, ctxRepo, forgeStateOf(c.RepoCheck.Verdict), clip(c.RepoCheck.Verdict+": "+c.RepoCheck.Summary, 40), "https://forge.invalid/pr")
}
func statusNamed(a *ChecksAnswer, name string) *CheckStatus {
for i := range a.Statuses {
if a.Statuses[i].Name == name {
return &a.Statuses[i]
}
}
return nil
}
func TestChecksOfAPullRequestSayEveryStatusTheVerdictWholeAndWhetherItMerges(t *testing.T) {
w := newWorld(t)
w.forge.required = []string{ctxGate, ctxRepo}
w.forge.pulls["novox/app#7"] = ForgePull{Number: 7, Title: "a change", State: "open", Base: "main", Head: "feat/x", HeadSHA: head}
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x", "src/a.go"))
said := "0 of 4 compose: anchor refuses app's manifest — a provision nothing provides, and three more machines alike"
c := checkedAs(t, "novox/app", 7, head, "fail", said, "pass", "its merge-check.sh passed")
w.h.Checked(c)
w.settleAll()
statusesAsTheForgeSets(w, "novox/app", head, c)
a, err := w.h.Checks("novox/app", 7, "")
if err != nil {
t.Fatal(err)
}
if a.Commit != head || a.Pull == nil || a.Pull.Number != 7 || a.Forge != "" {
t.Fatalf("the head read is %q, pull %+v, forge %q", a.Commit, a.Pull, a.Forge)
}
gate := statusNamed(a, ctxGate)
if gate == nil || gate.State != "failure" || gate.Source != "the forge" || gate.SetBy != "mesh-admin" {
t.Fatalf("the gate's status is %+v", gate)
}
// The forge clipped it; the verdict says it whole, with the machine, the build and the modules.
if strings.Contains(gate.Description, "three more machines") {
t.Fatalf("the fake forge did not clip: %q", gate.Description)
}
if !strings.Contains(gate.Verdict, "FAIL — 0 of 4 compose") || !strings.Contains(gate.Verdict, "three more machines") ||
!strings.Contains(gate.Verdict, "modules: app; built after them: web") {
t.Fatalf("the gate's verdict is %q", gate.Verdict)
}
if gate.Build != "build-"+head[:8] || gate.CheckedOn != "the-build-node" || gate.CheckedAt == "" {
t.Fatalf("the gate was checked as %q on %q at %q", gate.Build, gate.CheckedOn, gate.CheckedAt)
}
repo := statusNamed(a, ctxRepo)
if repo == nil || repo.State != "success" || repo.Verdict != "PASS — its merge-check.sh passed" || repo.CheckedOn != "the-build-node" {
t.Fatalf("the repository check's status is %+v", repo)
}
if d := statusNamed(a, ctxDelivery); d == nil || !strings.HasPrefix(d.Verdict, "rejected: waits for a new head") {
t.Fatalf("the delivery's status is %+v", d)
}
if a.Verdict == nil || !strings.Contains(a.Verdict.Report, "== compose") {
t.Fatalf("the verdict whole is %+v", a.Verdict)
}
if a.Delivery == nil || a.Delivery.ID != IDOf("novox/app", head) || a.Delivery.State != Rejected {
t.Fatalf("the delivery is %+v", a.Delivery)
}
if a.Merge.Mergeable == nil || *a.Merge.Mergeable || len(a.Merge.Blocking) != 1 || a.Merge.Blocking[0].Context != ctxGate {
t.Fatalf("the merge is %+v", a.Merge)
}
if !strings.Contains(a.Says, "novox/app#7 at aaaaaaaa") || !strings.Contains(a.Says, "NOT mergeable") {
t.Fatalf("it says %q", a.Says)
}
// The forge was asked for the pull request, with the base this owner knew.
if len(w.forge.asked) != 1 || w.forge.asked[0] != "novox/app#7@ base=main" {
t.Fatalf("the forge was asked %v", w.forge.asked)
}
}
func TestANewHeadIsReadWithItsOwnVerdictNeverTheOlderOnes(t *testing.T) {
w := newWorld(t)
w.forge.required = []string{ctxGate, ctxRepo}
newer := "bbbbbbbbbbbb2222"
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x"))
w.h.Checked(checkedAs(t, "novox/app", 7, head, "fail", "0 of 4 compose", "pass", "passed"))
w.h.PullUpdated(pr("novox/app", 7, newer, "feat/x"))
w.forge.pulls["novox/app#7"] = ForgePull{Number: 7, State: "open", Base: "main", HeadSHA: newer}
a, err := w.h.Checks("novox/app", 7, "")
if err != nil {
t.Fatal(err)
}
if a.Commit != newer || a.Delivery == nil || a.Delivery.ID != IDOf("novox/app", newer) || a.Delivery.State != Proposed {
t.Fatalf("the new head reads as %q, %+v", a.Commit, a.Delivery)
}
if a.Verdict != nil {
t.Fatalf("the older head's verdict was given for the newer: %+v", a.Verdict)
}
if a.Merge.Mergeable == nil || *a.Merge.Mergeable || len(a.Merge.Blocking) != 2 || a.Merge.Blocking[0].State != "missing" {
t.Fatalf("a head not checked yet merges as %+v", a.Merge)
}
// Passed, it merges.
c := checkedAs(t, "novox/app", 7, newer, "pass", "every machine composes", "pass", "its merge-check.sh passed")
w.h.Checked(c)
statusesAsTheForgeSets(w, "novox/app", newer, c)
a, _ = w.h.Checks("novox/app", 7, "")
if a.Merge.Mergeable == nil || !*a.Merge.Mergeable || !strings.Contains(a.Says, "mergeable") || strings.Contains(a.Says, "NOT") {
t.Fatalf("a head that passed: %+v, says %q", a.Merge, a.Says)
}
if g := statusNamed(a, ctxGate); g == nil || g.Verdict != "PASS — every machine composes (modules: app; built after them: web)" {
t.Fatalf("its gate: %+v", g)
}
}
func TestACommitIsReadByTheStartOfItsShaAndAMergeByItsDelivery(t *testing.T) {
w := newWorld(t)
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x"))
c := checkedAs(t, "novox/app", 7, head, "pass", "every machine composes", "pass", "passed")
w.h.Checked(c)
statusesAsTheForgeSets(w, "novox/app", head, c)
a, err := w.h.Checks("Novox/App.git", 0, head[:8])
if err != nil {
t.Fatal(err)
}
if a.Commit != head || a.Verdict == nil || a.Delivery == nil || a.Pull != nil {
t.Fatalf("by the start of its sha: %q, %+v, %+v", a.Commit, a.Verdict, a.Delivery)
}
// No protection: nothing is required, so it merges.
if a.Merge.Mergeable == nil || !*a.Merge.Mergeable {
t.Fatalf("with no protection: %+v", a.Merge)
}
mergedAs := "dddddddddddd9999"
w.h.PullMerged(merged("novox/app", 7, head, mergedAs))
_ = w.forge.Status("novox", "app", mergedAs, ctxDelivery, "pending", "published", "")
a, err = w.h.Checks("novox/app", 0, mergedAs)
if err != nil {
t.Fatal(err)
}
if a.Delivery == nil || a.Delivery.ID != IDOf("novox/app", head) {
t.Fatalf("the merge commit's delivery is %+v", a.Delivery)
}
if a.Verdict != nil {
t.Fatalf("the head's verdict was given for the merge commit: %+v", a.Verdict)
}
if s := statusNamed(a, ctxDelivery); s == nil || s.State != "pending" || s.Verdict == "" {
t.Fatalf("the merge's delivery status: %+v", s)
}
}
func TestWithTheForgeAwayTheVerdictIsSaidAndWhetherItMergesIsNotKnown(t *testing.T) {
w := newWorld(t)
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x"))
w.h.Checked(checkedAs(t, "novox/app", 7, head, "warning", "every machine composes, with a note", "error", "the toolchain was not there"))
w.forge.down = true
a, err := w.h.Checks("novox/app", 7, "")
if err != nil {
t.Fatal(err)
}
if a.Forge == "" || a.Commit != head || a.Verdict == nil {
t.Fatalf("with the forge away: forge %q, commit %q, verdict %+v", a.Forge, a.Commit, a.Verdict)
}
gate, repo := statusNamed(a, ctxGate), statusNamed(a, ctxRepo)
if gate == nil || gate.State != "success" || !strings.Contains(gate.Source, "could not be read") ||
repo == nil || repo.State != "error" || repo.Verdict != "ERROR — the toolchain was not there" {
t.Fatalf("the statuses from the verdict: %+v %+v", gate, repo)
}
if a.Merge.Mergeable != nil || !strings.Contains(a.Says, "mergeable: not known") {
t.Fatalf("whether it merges, with the forge away: %+v, %q", a.Merge, a.Says)
}
// The protection unreadable: the statuses are said, and whether it merges is not known.
w.forge.down, w.forge.protectionDown = false, true
w.forge.pulls["novox/app#7"] = ForgePull{Number: 7, Base: "main", HeadSHA: head}
a, _ = w.h.Checks("novox/app", 7, "")
if a.Merge.Mergeable != nil || a.Forge != "" {
t.Fatalf("with the protection unreadable: %+v", a.Merge)
}
}
func TestChecksRefuseWhatNamesNoCommit(t *testing.T) {
w := newWorld(t)
for _, c := range []struct {
repo string
number int
commit string
says string
}{
{"novox/app", 0, "", "number or a commit"},
{"app", 7, "", "owner/repository"},
{"novox/app/x", 7, "", "owner/repository"},
{"novox/app", 0, "abc", "not a commit"},
{"novox/app", 0, "zzzzzzzzzz", "not a commit"},
{"novox/app", -1, "", "not a pull request's number"},
} {
if _, err := w.h.Checks(c.repo, c.number, c.commit); err == nil || !strings.Contains(err.Error(), c.says) {
t.Errorf("%s #%d %q: %v", c.repo, c.number, c.commit, err)
}
}
if len(w.forge.asked) != 0 {
t.Fatalf("the forge was asked for what names nothing: %v", w.forge.asked)
}
}
func TestANumberIsTakenAsANumberOrAsText(t *testing.T) {
for _, c := range []struct {
in any
want int
ok bool
}{{float64(168), 168, true}, {"168", 168, true}, {"#168", 168, true}, {nil, 0, true}, {"", 0, true},
{"x", 0, false}, {1.5, 0, false}} {
got, err := intArg(map[string]any{"number": c.in}, "number")
if (err == nil) != c.ok || got != c.want {
t.Errorf("%v → %d %v", c.in, got, err)
}
}
}