package main import ( "reflect" "strings" "testing" "time" "github.com/novox/mesh-controller/internal/inventory" ) // novox/hq issue 254, ADR 0218: a newer plan takes over what the older open plans of its repository // and branch had not built, and closes them as superseded; another repository's plan, another // branch's, and a plan made after it are left alone. func TestANewerPlanSupersedesTheOlderOpenPlansOfItsRepository(t *testing.T) { at := time.Date(2026, 10, 5, 12, 0, 0, 0, time.UTC) sent := at.Add(time.Minute) plan := func(id, repository, branch string, created time.Time, modules map[string]*inventory.PlanModule) inventory.Plan { return inventory.Plan{ID: id, Repository: repository, Branch: branch, Commit: id + "-commit", Created: created, State: inventory.PlanRolling, Modules: modules} } older := plan("plan-1", "novox/mesh-catalog", "main", at, map[string]*inventory.PlanModule{ "gitea": {State: "built", SentAt: &sent}, // done with: stays done "keycloak": {State: "asked"}, // asked, not answered: folded "plex": {}, // not yet asked: folded "agent": {State: "built"}, // built, rolls out, not sent: folded "notes": {State: "built"}, // built, records: nothing to send }) stuck := plan("plan-0", "Novox/Mesh-Catalog", "", at.Add(-time.Hour), map[string]*inventory.PlanModule{ "runtime": {State: "asked"}, }) other := plan("plan-2", "novox/mesh-controller", "main", at, map[string]*inventory.PlanModule{"mesh-controller": {}}) release := plan("plan-3", "novox/mesh-catalog", "release", at, map[string]*inventory.PlanModule{"lemurs": {}}) later := plan("plan-5", "novox/mesh-catalog", "main", at.Add(2*time.Hour), map[string]*inventory.PlanModule{"later": {}}) done := plan("plan-6", "novox/mesh-catalog", "main", at, map[string]*inventory.PlanModule{"finished": {}}) done.State = inventory.PlanDone newer := plan("plan-4", "novox/mesh-catalog", "main", at.Add(time.Hour), nil) newer.Commit = "97b1b2b0c0ffee" rollsOut := func(m string) bool { return m != "notes" } folded, closed := supersededBy(newer, []inventory.Plan{stuck, older, other, release, later, done, newer}, rollsOut) if want := []string{"agent", "keycloak", "plex", "runtime"}; !reflect.DeepEqual(folded, want) { t.Fatalf("folded %v, wanted %v", folded, want) } var ids []string for _, p := range closed { ids = append(ids, p.ID) if p.State != inventory.PlanSuperseded || p.Open() { t.Errorf("%s was left %s", p.ID, p.State) } if !strings.Contains(p.Note, "plan-4") || !strings.Contains(p.Note, "97b1b2b0") { t.Errorf("%s does not name the plan that superseded it: %q", p.ID, p.Note) } } if want := []string{"plan-0", "plan-1"}; !reflect.DeepEqual(ids, want) { t.Fatalf("superseded %v, wanted %v — another repository, another branch, a later plan and a "+ "finished one are left alone", ids, want) } if other.State != inventory.PlanRolling { t.Fatal("the plan handed in was changed in place") } if line := planLine(closed[1], time.Now()); !strings.Contains(line, "superseded") { t.Fatalf("a superseded plan reads %q", line) } } // novox/hq issue 254: a person closes a plan that will not move again, by its id. func TestAPersonClosesAStuckPlan(t *testing.T) { open := aMesh(t) ctx := t.Context() stuck := inventory.Plan{ID: "plan-97b1b2b", Repository: "novox/mesh-catalog", Commit: "97b1b2b", Created: time.Now().UTC(), State: inventory.PlanRolling, Tier: 1, Tiers: [][]string{{"a"}, {"b"}}, Modules: map[string]*inventory.PlanModule{"a": {State: "built"}, "b": {}}} if err := open.inventory.SavePlan(ctx, &stuck); err != nil { t.Fatal(err) } if err := plansCommand(ctx, []string{"close", stuck.ID}); err == nil || !strings.Contains(err.Error(), "--why") { t.Fatalf("a plan was closed by hand without saying why: %v", err) } if err := plansCommand(ctx, []string{"close", stuck.ID, "--why", "its report will not come"}); err != nil { t.Fatal(err) } closed, err := open.inventory.PlanByID(ctx, stuck.ID) if err != nil { t.Fatal(err) } if closed.State != inventory.PlanFailed || !strings.Contains(closed.Note, "closed by hand") || !strings.Contains(closed.Note, "its report will not come") { t.Fatalf("the plan was left %s: %q", closed.State, closed.Note) } if err := plansCommand(ctx, []string{"close", stuck.ID, "--why", "again"}); err == nil { t.Fatal("a plan already closed was closed again") } if argv, err := argvFor("plans", map[string]any{"close": stuck.ID, "why": "w"}); err != nil || !reflect.DeepEqual(argv, []string{"plans", "close", stuck.ID, "--why", "w"}) { t.Fatalf("the seat's verb does not close a plan: %v %v", argv, err) } }