Say a walk's start or end when a person stops, closes, retries or releases it, and a hand stop as stopped
plans stop|close, plans retry and upgrade release-backlog kept a walk's start or end mark without saying it, so the router would hold what the walk touched until its bound; each now runs on the bus as plans go does. A hand stop keeps who stopped it, so its outcome is stopped, not failed (review 15, ADR 0308, issue 532).
This commit is contained in:
@@ -236,24 +236,7 @@ func TestPlanMovedCarriesTheWalkWholeAndOnItsStartWhatItTouches(t *testing.T) {
|
||||
func TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
url := testbus.URL(t)
|
||||
js, err := broker.Dial(url)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(js.Close)
|
||||
if err := broker.AssertMeshStreams(js); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before := handActConn
|
||||
handActConn = js.Conn()
|
||||
t.Cleanup(func() { handActConn = before })
|
||||
heard := make(chan *nats.Msg, 8)
|
||||
sub, err := js.Conn().ChanSubscribe(link.SeatEventSubject(link.MeshControllerSeat, link.KeyPlanMoved), heard)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = sub.Unsubscribe() })
|
||||
next := planMovedHeard(t)
|
||||
register(t, open, catalogue.Manifest{Module: "app", Version: "1"})
|
||||
if _, err := assign(ctx, open, "anchor", "app"); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -267,24 +250,6 @@ func TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded(t *testing.T) {
|
||||
if err := open.inventory.SavePlan(ctx, &waiting); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
next := func(phase string) map[string]any {
|
||||
t.Helper()
|
||||
deadline := time.After(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case m := <-heard:
|
||||
var said map[string]any
|
||||
if err := json.Unmarshal(m.Data, &said); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if said["phase"] == phase {
|
||||
return said
|
||||
}
|
||||
case <-deadline:
|
||||
t.Fatalf("the walk was not said %s", phase)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := deliveryCommand(ctx, []string{"go", waiting.ID, "--why", "its turn"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -304,3 +269,123 @@ func TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded(t *testing.T) {
|
||||
t.Fatalf("the end, which sent nothing: %v", ended)
|
||||
}
|
||||
}
|
||||
|
||||
// planMovedHeard raises a bus of the test's own, points the verbs' hand-act connection at it, and returns what
|
||||
// waits for the next plan-moved said with the given phase, failing the test when none comes within 5 s.
|
||||
func planMovedHeard(t *testing.T) func(phase string) map[string]any {
|
||||
t.Helper()
|
||||
js, err := broker.Dial(testbus.URL(t))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(js.Close)
|
||||
if err := broker.AssertMeshStreams(js); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before := handActConn
|
||||
handActConn = js.Conn()
|
||||
t.Cleanup(func() { handActConn = before })
|
||||
heard := make(chan *nats.Msg, 64)
|
||||
sub, err := js.Conn().ChanSubscribe(link.SeatEventSubject(link.MeshControllerSeat, link.KeyPlanMoved), heard)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = sub.Unsubscribe() })
|
||||
return func(phase string) map[string]any {
|
||||
t.Helper()
|
||||
deadline := time.After(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case m := <-heard:
|
||||
var said map[string]any
|
||||
if err := json.Unmarshal(m.Data, &said); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if said["phase"] == phase {
|
||||
return said
|
||||
}
|
||||
case <-deadline:
|
||||
t.Fatalf("no walk was said %s", phase)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Live, with the store and a bus: a walk a person stops with `plans stop` is said ended, outcome stopped, by the
|
||||
// verb itself, and is kept stopped by that person; `plans close` ends one the same way (novox/hq ADR 0308
|
||||
// decision 1, review 15 on mesh-controller#247).
|
||||
func TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
next := planMovedHeard(t)
|
||||
register(t, open, catalogue.Manifest{Module: "app", Version: "1"})
|
||||
if _, err := assign(ctx, open, "anchor", "app"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, verb := range []string{"stop", "close"} {
|
||||
cut := time.Now().UTC()
|
||||
walk := inventory.Plan{ID: "plan-308-" + verb, Repository: "novox/mesh-catalog", Branch: "main",
|
||||
Commit: "c8c8c8c8", Created: cut, State: inventory.PlanBuilding, Tiers: [][]string{{"app"}},
|
||||
Modules: map[string]*inventory.PlanModule{"app": {}},
|
||||
Times: &inventory.PlanTimes{Cut: &cut, Started: &cut, Class: inventory.ClassLeaf}}
|
||||
if err := open.inventory.SavePlan(ctx, &walk); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := plansCommand(ctx, []string{verb, walk.ID, "--why", "a test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ended := next(inventory.WalkEnded)
|
||||
if ended["walk"] != walk.ID || ended["outcome"] != inventory.WalkStopped {
|
||||
t.Fatalf("plans %s: the end is %v", verb, ended)
|
||||
}
|
||||
p, err := open.inventory.PlanByID(ctx, walk.ID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if p.Outcome() != inventory.WalkStopped || p.Delivery == nil || p.Delivery.StoppedWhy != "a test" {
|
||||
t.Fatalf("plans %s kept the walk %s, %+v", verb, p.Outcome(), p.Delivery)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Live, with the store and a bus: a failed walk retried with `plans retry` starts again, and the verb says its
|
||||
// start (novox/hq ADR 0308 decision 1, review 15 on mesh-controller#247).
|
||||
func TestAWalkRetriedByAPersonIsSaidStartedAgain(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
asksRecorded(t)
|
||||
next := planMovedHeard(t)
|
||||
twoTiers(t, open)
|
||||
before := time.Now().UTC().Add(-time.Hour)
|
||||
ended := before.Add(time.Minute)
|
||||
failed := inventory.Plan{ID: "plan-308-retry", Repository: "novox/a", Branch: "main", Commit: "c0ffee",
|
||||
Created: before, State: inventory.PlanFailed, Tier: 0, Tiers: [][]string{{"a"}, {"b"}},
|
||||
Note: "a failed to build in tier 0",
|
||||
Modules: map[string]*inventory.PlanModule{"a": {State: "failed", AskedAt: &before, Build: "build-1",
|
||||
Why: link.KilledByHand}},
|
||||
Times: &inventory.PlanTimes{Cut: &before, Started: &before, Ended: &ended, Class: inventory.ClassLeaf}}
|
||||
if err := open.inventory.SavePlan(ctx, &failed); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := plansCommand(ctx, []string{"retry", failed.ID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
started := next(inventory.WalkStarted)
|
||||
if started["walk"] != failed.ID || started["budget_class"] != inventory.ClassLeaf {
|
||||
t.Fatalf("the retried start: %v", started)
|
||||
}
|
||||
}
|
||||
|
||||
// Live, with the store and a bus: the release plan `upgrade release-backlog` opens is said started by the verb
|
||||
// (novox/hq ADR 0308 decision 1, review 15 on mesh-controller#247).
|
||||
func TestABacklogReleasedByAPersonIsSaidStarted(t *testing.T) {
|
||||
b := aBacklog(t)
|
||||
next := planMovedHeard(t)
|
||||
if err := backlogCommand(t.Context(), "release-backlog", []string{"--why", "a test"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
started := next(inventory.WalkStarted)
|
||||
if p := b.release(t); started["walk"] != p.ID {
|
||||
t.Fatalf("the release's start: %v", started)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user