A module the catalogue no longer holds ends deleted instead of failing the plan; the unsent hint names release-backlog (issue 1922)
This commit is contained in:
@@ -328,8 +328,8 @@ func applied(module string, builtAt time.Time, running []string, reports []inven
|
||||
|
||||
// askTier asks the build machine for the named modules of the plan's tier — all of it, or what of it is still
|
||||
// unasked (novox/hq issue 754) — and marks each asked. A module
|
||||
// the catalogue no longer holds, or whose ask could not be made, is a failure of the plan: a tier
|
||||
// half asked is a tier that will never complete.
|
||||
// the catalogue no longer holds ends as deleted (issue 1922); one whose ask could not be made is a failure of the
|
||||
// plan: a tier half asked is a tier that will never complete.
|
||||
func askTier(ctx context.Context, inv *inventory.Inventory, p *inventory.Plan, names []string) error {
|
||||
entries, err := inv.Catalogued(ctx)
|
||||
if err != nil {
|
||||
@@ -390,10 +390,10 @@ func askModule(ctx context.Context, p *inventory.Plan, name string, byName map[s
|
||||
}
|
||||
e, known := byName[name]
|
||||
if !known {
|
||||
state.State = "failed"
|
||||
// **A module the catalogue no longer holds ends as deleted** (issue 1922): the plan's own merge removed it, so
|
||||
// there is nothing to build or send; it is no failure, and a retry of a plan failed that way resumes.
|
||||
state.State = planDeleted
|
||||
state.Why = "no longer in the catalogue"
|
||||
p.State = inventory.PlanFailed
|
||||
p.Note = name + " is no longer in the catalogue"
|
||||
return
|
||||
}
|
||||
// **Every module is taken from the builder's done key, asking no build** (novox/hq ADR 0503 §6, ADR 0501, ADR 0453 §5;
|
||||
@@ -1647,7 +1647,7 @@ func sayUnsent(p *inventory.Plan, rollsOut func(string) bool) {
|
||||
return
|
||||
}
|
||||
sort.Strings(unsent)
|
||||
p.Note += "; built and never sent: " + strings.Join(unsent, ", ") + " — `push --behind` sends them"
|
||||
p.Note += "; built and never sent: " + strings.Join(unsent, ", ") + " — `upgrade release-backlog --why <text>` releases them"
|
||||
}
|
||||
|
||||
// planLine is one plan as `status` says it, given the least bound of a tier.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// 1922/AC1: a tier naming a module the catalogue no longer holds asks it without failing the plan: the module ends
|
||||
// as deleted (not built, not sent) and the tier's other modules go on.
|
||||
func TestAModuleTheCatalogueNoLongerHoldsEndsDeletedAndTheTierGoesOn(t *testing.T) {
|
||||
p, byName := aWalkOfOne("sudo")
|
||||
p.Tiers = [][]string{{"gone", "sudo"}}
|
||||
for _, m := range p.Tiers[0] {
|
||||
askModule(t.Context(), p, m, byName)
|
||||
}
|
||||
if g := p.Modules["gone"]; g == nil || g.State != planDeleted || g.Build != "" || g.SentAt != nil {
|
||||
t.Fatalf("the removed module is not deleted: %+v", g)
|
||||
}
|
||||
if p.State == inventory.PlanFailed {
|
||||
t.Fatalf("the plan failed: %q", p.Note)
|
||||
}
|
||||
if s := p.Modules["sudo"]; s == nil || s.State != "asked" {
|
||||
t.Fatalf("the other module of the tier did not go on: %+v", s)
|
||||
}
|
||||
}
|
||||
|
||||
// 1922/AC2: a plan that failed on such a module before the fix is retried: the removed module ends deleted and the
|
||||
// plan is building again, to go on to its next tier.
|
||||
func TestARetryOfAPlanFailedOnARemovedModuleResumes(t *testing.T) {
|
||||
p := inventory.Plan{ID: "plan-1", State: inventory.PlanFailed, Note: "gone is no longer in the catalogue",
|
||||
Tiers: [][]string{{"gone"}, {"next"}},
|
||||
Modules: map[string]*inventory.PlanModule{
|
||||
"gone": {State: "failed", Why: "no longer in the catalogue"},
|
||||
}}
|
||||
failed := toRetry(&p, nil, nil)
|
||||
if len(failed) != 1 || failed[0] != "gone" {
|
||||
t.Fatalf("the failed set is %v", failed)
|
||||
}
|
||||
for _, m := range failed {
|
||||
askModule(t.Context(), &p, m, map[string]inventory.Entry{})
|
||||
}
|
||||
resumed(&p, "retried")
|
||||
if p.State != inventory.PlanBuilding || p.Modules["gone"].State != planDeleted {
|
||||
t.Fatalf("the retry did not resume: %s %+v", p.State, p.Modules["gone"])
|
||||
}
|
||||
}
|
||||
|
||||
// 1922/AC3: an ended plan's note names the verb that releases the modules waiting for a gate, not `push --behind`.
|
||||
func TestAnEndedPlansHintNamesTheReleaseOfTheBacklog(t *testing.T) {
|
||||
p := inventory.Plan{State: inventory.PlanFailed, Note: "failed",
|
||||
Modules: map[string]*inventory.PlanModule{"agent": {State: "built"}}}
|
||||
sayUnsent(&p, func(string) bool { return true })
|
||||
if strings.Contains(p.Note, "push --behind") || !strings.Contains(p.Note, "upgrade release-backlog") {
|
||||
t.Fatalf("the note reads %q", p.Note)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,7 @@ func TestAnEndedPlanSaysWhatItBuiltAndNeverSent(t *testing.T) {
|
||||
rollsOut := func(m string) bool { return m != "notes" }
|
||||
sayUnsent(&p, rollsOut)
|
||||
sayUnsent(&p, rollsOut)
|
||||
if p.Note != "closed by hand at tier 1; built and never sent: agent — `push --behind` sends them" {
|
||||
if p.Note != "closed by hand at tier 1; built and never sent: agent — `upgrade release-backlog --why <text>` releases them" {
|
||||
t.Fatalf("the note reads %q", p.Note)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user