Files
mesh-catalog/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/issue1274_test.go
T
jschoubben fbbf28d21c
mesh/merge-gate head fbbf28d21c37 merged into trunk c3d3194bc8d4 — pass: builds mesh-delivery-gate → novox; no bus step; every machine composes with the ch…
mesh/repo-check head fbbf28d21c37 merged into trunk c3d3194bc8d4 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
mesh/check failed: unit: modules/gitea.test: [gitea] where the poll of merges last looked from could not be read, so none is kept — no runtime | fbbf2…
mesh-delivery-gate: read the queue's state word as the controller says it, in flight (issue 1274)
2026-10-22 16:36:23 +02:00

154 lines
5.8 KiB
Go

package main
import (
"strings"
"testing"
"time"
)
// Issue 1274: a proposed delivery whose asked check the build queue no longer holds is asked again, and a recheck from
// proposed is taken when no check of its head is waiting or in flight.
// 1274/AC1: the queue holds nothing for the ask, the sweep runs after the bound: the check is asked once more and the
// transition says the earlier ask was lost.
func TestACheckTheQueueLostIsAskedAgainBySweepAfterTheBound(t *testing.T) {
w := newWorld(t)
id := IDOf("novox/app", head)
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x", "src/a.go"))
w.settleAll()
first := w.delivery(id).CheckAsk
if len(w.ctl.checks) != 1 || first == nil {
t.Fatalf("asked %v, ask %+v", w.ctl.checks, first)
}
w.ctl.queue = nil // the queue lost it
w.later(9 * time.Minute)
w.settleAll()
if len(w.ctl.checks) != 1 {
t.Fatalf("asked again inside the bound: %v", w.ctl.checks)
}
w.later(2 * time.Minute)
w.settleAll()
d := w.delivery(id)
last := d.Transitions[len(d.Transitions)-1]
if len(w.ctl.checks) != 2 || d.CheckAsk == nil || d.CheckAsk.ID == first.ID || last.Event != EvLost ||
!strings.Contains(last.Why, first.ID) || !strings.Contains(last.Why, "lost") {
t.Fatalf("asked %v; ask %+v; last transition %+v", w.ctl.checks, d.CheckAsk, last)
}
w.later(time.Hour)
w.settleAll()
if len(w.ctl.checks) != 2 {
t.Fatalf("an ask the queue holds was asked again: %v", w.ctl.checks)
}
}
// 1274/AC1: a verdict that went out of date, its check against the trunk's head asked and lost, is asked again too (the
// case of novox/mesh-controller@28a278c1462a), and the ask's bound runs from the new ask.
func TestACheckAgainstTheTrunkTheQueueLostIsAskedAgain(t *testing.T) {
w := approvedGroup(t)
id := IDOf(gCtl, gHc)
w.h.PullMerged(merged(gCtl, 5, "5555555555555555", gT1))
w.settleAll()
d := w.delivery(id)
if d.State != Proposed || d.AskedAgain == nil {
t.Fatalf("it is %s, asked again %v", d.State, d.AskedAgain)
}
asked := len(w.ctl.checks)
w.ctl.queue = nil
w.later(11 * time.Minute)
w.settleAll()
d = w.delivery(id)
last := d.Transitions[len(d.Transitions)-1]
if len(w.ctl.checks) != asked+1 || last.Event != EvLost || d.AskedAgain == nil || !d.AskedAgain.After(w.now.Add(-time.Minute)) {
t.Fatalf("asked %v; last transition %+v; asked again %v", w.ctl.checks[asked:], last, d.AskedAgain)
}
}
// 1274/AC2: the queue still holds the ask, waiting or in flight, or cannot be read: nothing is asked again.
func TestACheckTheQueueStillHoldsIsNotAskedAgain(t *testing.T) {
w := newWorld(t)
id := IDOf("novox/app", head)
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x", "src/a.go"))
w.settleAll()
w.ctl.queue[0].State = "in flight"
w.later(3 * time.Hour)
w.settleAll()
if len(w.ctl.checks) != 1 {
t.Fatalf("an ask in flight was asked again: %v", w.ctl.checks)
}
w.ctl.queue = nil
w.ctl.queueDown = true
w.later(time.Hour)
w.settleAll()
if len(w.ctl.checks) != 1 || w.delivery(id).State != Proposed {
t.Fatalf("an unreadable queue asked again: %v", w.ctl.checks)
}
w.ctl.queueDown = false
w.later(3 * time.Minute)
w.ctl.queue = []QueuedAsk{{ID: "elsewhere", State: "dead", Kind: "check", Repository: "novox/app", Commit: head}}
w.settleAll()
if len(w.ctl.checks) != 2 {
t.Fatalf("a dead ask counted as held: %v", w.ctl.checks)
}
}
// 1274/AC3: recheck of a proposed delivery with no check waiting or in flight is taken and asks its check; with one
// held it is refused naming it.
func TestARecheckFromProposedIsTakenOnlyWhenNoCheckOfItsHeadIsHeld(t *testing.T) {
w := newWorld(t)
id := IDOf("novox/app", head)
w.h.PullUpdated(pr("novox/app", 7, head, "feat/x", "src/a.go"))
w.settleAll()
held := w.delivery(id).CheckAsk.ID
if _, err := w.h.Recheck(id, "nothing came", "jochen"); err == nil || !strings.Contains(err.Error(), held) {
t.Fatalf("a recheck with a check waiting: %v", err)
}
if _, err := w.h.Recheck(id, "", "jochen"); err == nil {
t.Fatal("a recheck with no why was taken")
}
if len(w.ctl.checks) != 1 {
t.Fatalf("a refused recheck asked: %v", w.ctl.checks)
}
w.ctl.queue = nil
said, err := w.h.Recheck(id, "nothing came", "jochen")
d := w.delivery(id)
last := d.Transitions[len(d.Transitions)-1]
if err != nil || len(w.ctl.checks) != 2 || d.State != Proposed || last.Event != EvLost || last.By != "jochen" ||
!strings.Contains(last.Why, "nothing came") || d.CheckAsk.ID != "check-2" || !strings.Contains(said, "check-2") {
t.Fatalf("%q %v; asked %v; last transition %+v", said, err, w.ctl.checks, last)
}
// Taken, it is now held: a second recheck is refused.
if _, err := w.h.Recheck(id, "again", "jochen"); err == nil || !strings.Contains(err.Error(), "check-2") {
t.Fatalf("a second recheck: %v", err)
}
}
// 1274/AC4: a group member re-asked this way has its group's composed check asked again at the members' heads once its
// own check answers.
func TestAGroupMemberReaskedAfterALostCheckHasTheComposedCheckAskedAgain(t *testing.T) {
w := approvedGroup(t)
id := IDOf(gCat, gHk)
if _, err := w.h.Recheck(id, "its verdict is wanted again", "jochen"); err != nil {
t.Fatal(err)
}
w.settleAll() // its own check is recorded as asked
w.h.mu.Lock()
w.h.groups["feat/g"].Check.OutOfDate = "" // as if the composed check stood: only the lost ask's own act marks it
w.h.mu.Unlock()
w.ctl.queue = nil
w.later(11 * time.Minute)
w.settleAll()
g := w.h.groups["feat/g"]
if g.Check.OutOfDate == "" || !strings.Contains(g.Check.OutOfDate, "lost") {
t.Fatalf("the composed check stands: %+v", g.Check)
}
first := g.Check.Asked
asked := len(w.ctl.checks)
w.later(time.Minute)
w.h.Checked(judged(gCat, 2, gHk, "pass", gTrunk0))
w.settleAll()
last := w.ctl.checks[len(w.ctl.checks)-1]
if len(w.ctl.checks) <= asked || !strings.HasPrefix(last, "feat/g:") || w.h.groups["feat/g"].Check.Asked == first {
t.Fatalf("the composed check was not asked again: %v", w.ctl.checks[asked:])
}
}