Make the rollout tests wait for the plan look to return before their cleanups restore what it reads, which raced (issue 1338)
mesh/merge-gate head c07f604047be merged into trunk 70cb217601f9 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head c07f604047be merged into trunk 70cb217601f9 — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/merge-gate head c07f604047be merged into trunk 70cb217601f9 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head c07f604047be merged into trunk 70cb217601f9 — pass: its merge-check.sh passed
mesh/delivery delivered
This commit is contained in:
@@ -174,7 +174,9 @@ func TestAPlanGoesOnWithoutAMachineAwayWhenItsTierIsSent(t *testing.T) {
|
|||||||
}}
|
}}
|
||||||
first, stopFirst := context.WithCancel(ctx)
|
first, stopFirst := context.WithCancel(ctx)
|
||||||
defer stopFirst()
|
defer stopFirst()
|
||||||
startRolloutEvents(first, open, js)
|
waitFirst := startRolloutEvents(first, open, js)
|
||||||
|
// Ends with the test before the cleanups restore what the look reads, which run after it (issue 1338).
|
||||||
|
t.Cleanup(func() { stopFirst(); waitFirst() })
|
||||||
if err := inv.SavePlan(ctx, &p); err != nil {
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,9 @@ func askToLook() {
|
|||||||
|
|
||||||
// startPlanLooks starts the look at the open plans, and asks for the first: the controller took the lease, and a
|
// startPlanLooks starts the look at the open plans, and asks for the first: the controller took the lease, and a
|
||||||
// plan left by a replaced controller resumes from there (ADR 0406 §6). It replaces the rollout's 30 second ticker.
|
// plan left by a replaced controller resumes from there (ADR 0406 §6). It replaces the rollout's 30 second ticker.
|
||||||
func startPlanLooks(ctx context.Context, open *stores) {
|
// It answers a channel that is closed once the look has returned after the context ended, for a test that restores what
|
||||||
|
// the look reads (issue 1338).
|
||||||
|
func startPlanLooks(ctx context.Context, open *stores) <-chan struct{} {
|
||||||
l := newLooker(func(ctx context.Context) bool { return lookAtPlans(ctx, open) })
|
l := newLooker(func(ctx context.Context) bool { return lookAtPlans(ctx, open) })
|
||||||
l.first = func(ctx context.Context) { rearmWalkEnds(ctx, open) }
|
l.first = func(ctx context.Context) { rearmWalkEnds(ctx, open) }
|
||||||
lookerMu.Lock()
|
lookerMu.Lock()
|
||||||
@@ -152,8 +154,13 @@ func startPlanLooks(ctx context.Context, open *stores) {
|
|||||||
}
|
}
|
||||||
lookerMu.Unlock()
|
lookerMu.Unlock()
|
||||||
}()
|
}()
|
||||||
go l.run(ctx)
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
l.run(ctx)
|
||||||
|
}()
|
||||||
l.ask()
|
l.ask()
|
||||||
|
return done
|
||||||
}
|
}
|
||||||
|
|
||||||
// applySilentAfter is how long a machine may say nothing on a send before the plan names it silent: the mesh's
|
// applySilentAfter is how long a machine may say nothing on a send before the plan names it silent: the mesh's
|
||||||
@@ -163,8 +170,10 @@ var applySilentAfter = inventory.ApplySilentAfter
|
|||||||
// startRolloutEvents starts what a rollout advances on, for as long as the context lives (novox/hq ADR 0406 §5, issue 974):
|
// startRolloutEvents starts what a rollout advances on, for as long as the context lives (novox/hq ADR 0406 §5, issue 974):
|
||||||
// the wait for each machine's report as a key on the bus that expires (where the bus will not take it a timer of its own
|
// the wait for each machine's report as a key on the bus that expires (where the bus will not take it a timer of its own
|
||||||
// for that wait looks instead), a provisioner client's words, and the look at the plans, asked for first so a plan left
|
// for that wait looks instead), a provisioner client's words, and the look at the plans, asked for first so a plan left
|
||||||
// by a replaced controller resumes. The serving controller's start and the tests of a rollout call this one.
|
// by a replaced controller resumes. The serving controller's start and the tests of a rollout call this one. It answers
|
||||||
func startRolloutEvents(ctx context.Context, open *stores, js *broker.JetStream) {
|
// a function that waits until the look at the plans has returned, which only a test that ends the context needs (issue
|
||||||
|
// 1338): the serving controller ignores it.
|
||||||
|
func startRolloutEvents(ctx context.Context, open *stores, js *broker.JetStream) (wait func()) {
|
||||||
if err := startRolloutSilent(ctx, js); err != nil {
|
if err := startRolloutSilent(ctx, js); err != nil {
|
||||||
fmt.Printf("plans: the wait for the machines' reports could not be put on the bus (%v); each is looked at by a timer of its own\n", err)
|
fmt.Printf("plans: the wait for the machines' reports could not be put on the bus (%v); each is looked at by a timer of its own\n", err)
|
||||||
}
|
}
|
||||||
@@ -174,7 +183,8 @@ func startRolloutEvents(ctx context.Context, open *stores, js *broker.JetStream)
|
|||||||
if err := startPlanMovedLooks(ctx, js); err != nil {
|
if err := startPlanMovedLooks(ctx, js); err != nil {
|
||||||
fmt.Printf("plans: the plans moved by other processes could not be followed (%v)\n", err)
|
fmt.Printf("plans: the plans moved by other processes could not be followed (%v)\n", err)
|
||||||
}
|
}
|
||||||
startPlanLooks(ctx, open)
|
done := startPlanLooks(ctx, open)
|
||||||
|
return func() { <-done }
|
||||||
}
|
}
|
||||||
|
|
||||||
// servingPlanSaved is what the serving controller does for each plan it keeps: said as plan-moved, looked at (a build, a
|
// servingPlanSaved is what the serving controller does for each plan it keeps: said as plan-moved, looked at (a build, a
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ func TestARolloutAdvancesOnEventsAndAReplacedControllerResumesIt(t *testing.T) {
|
|||||||
// The first controller. Its plan has tier 0 built and tier 1 not asked: nothing but the save asks anything.
|
// The first controller. Its plan has tier 0 built and tier 1 not asked: nothing but the save asks anything.
|
||||||
first, stopFirst := context.WithCancel(ctx)
|
first, stopFirst := context.WithCancel(ctx)
|
||||||
defer stopFirst()
|
defer stopFirst()
|
||||||
startRolloutEvents(first, open, js)
|
waitFirst := startRolloutEvents(first, open, js)
|
||||||
built := time.Now().UTC()
|
built := time.Now().UTC()
|
||||||
p := inventory.Plan{ID: "plan-974", Repository: "novox/mesh-catalog", Branch: "main", Commit: "c2", Created: built,
|
p := inventory.Plan{ID: "plan-974", Repository: "novox/mesh-catalog", Branch: "main", Commit: "c2", Created: built,
|
||||||
State: inventory.PlanBuilding, Tiers: [][]string{{"a"}, {"b"}},
|
State: inventory.PlanBuilding, Tiers: [][]string{{"a"}, {"b"}},
|
||||||
@@ -199,12 +199,15 @@ func TestARolloutAdvancesOnEventsAndAReplacedControllerResumesIt(t *testing.T) {
|
|||||||
|
|
||||||
// The controller is replaced: its looks and its watcher end. anchor reports meanwhile, to nobody.
|
// The controller is replaced: its looks and its watcher end. anchor reports meanwhile, to nobody.
|
||||||
stopFirst()
|
stopFirst()
|
||||||
|
waitFirst()
|
||||||
time.Sleep(300 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
reports("anchor")
|
reports("anchor")
|
||||||
|
|
||||||
second, stopSecond := context.WithCancel(ctx)
|
second, stopSecond := context.WithCancel(ctx)
|
||||||
defer stopSecond()
|
defer stopSecond()
|
||||||
startRolloutEvents(second, open, js)
|
waitSecond := startRolloutEvents(second, open, js)
|
||||||
|
// Ends with the test before the cleanups restore what the look reads, which run after it (issue 1338).
|
||||||
|
t.Cleanup(func() { stopSecond(); waitSecond() })
|
||||||
// Its first look finds anchor reported, so its key goes; laptop's stays, and is the new controller's to hear expire.
|
// Its first look finds anchor reported, so its key goes; laptop's stays, and is the new controller's to hear expire.
|
||||||
eventually(t, "the new controller's first look deletes the key of the machine that reported", func() bool {
|
eventually(t, "the new controller's first look deletes the key of the machine that reported", func() bool {
|
||||||
h := heldKeys()
|
h := heldKeys()
|
||||||
@@ -321,7 +324,7 @@ func TestAWalkLetGoByTheDeliverVerbIsAskedWithNoOtherEvent(t *testing.T) {
|
|||||||
t.Cleanup(func() { inventory.PlanSaved = wasSaved })
|
t.Cleanup(func() { inventory.PlanSaved = wasSaved })
|
||||||
started, stop := context.WithCancel(ctx)
|
started, stop := context.WithCancel(ctx)
|
||||||
defer stop()
|
defer stop()
|
||||||
startRolloutEvents(started, open, js)
|
wait := startRolloutEvents(started, open, js)
|
||||||
time.Sleep(500 * time.Millisecond) // the first look: the walk waits, and is asked nothing
|
time.Sleep(500 * time.Millisecond) // the first look: the walk waits, and is asked nothing
|
||||||
|
|
||||||
// The verb as its child process runs it: the delivery command, whose saves are not the serving controller's.
|
// The verb as its child process runs it: the delivery command, whose saves are not the serving controller's.
|
||||||
@@ -333,6 +336,9 @@ func TestAWalkLetGoByTheDeliverVerbIsAskedWithNoOtherEvent(t *testing.T) {
|
|||||||
return verbAnswer{}, deliveryCommand(ctx, []string{"go", waiting.ID, "--why", "its turn"})
|
return verbAnswer{}, deliveryCommand(ctx, []string{"go", waiting.ID, "--why", "its turn"})
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { runTheVerb = wasRun })
|
t.Cleanup(func() { runTheVerb = wasRun })
|
||||||
|
// Registered after every variable cleanup above, so it runs before them (last in, first out): the look at the plans
|
||||||
|
// has returned when checkEvents, inventory.PlanSaved and runTheVerb are restored (issue 1338).
|
||||||
|
t.Cleanup(func() { stop(); wait() })
|
||||||
handlers, _, err := seatToolHandlers()
|
handlers, _, err := seatToolHandlers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -171,7 +171,9 @@ func TestAPlanPassesATierWhoseMachineNeverReportsAfterTheBoundAndSendsTheNextToT
|
|||||||
}}
|
}}
|
||||||
first, stopFirst := context.WithCancel(ctx)
|
first, stopFirst := context.WithCancel(ctx)
|
||||||
defer stopFirst()
|
defer stopFirst()
|
||||||
startRolloutEvents(first, open, js)
|
waitFirst := startRolloutEvents(first, open, js)
|
||||||
|
// Ends with the test before the cleanups restore what the look reads, which run after it (issue 1338).
|
||||||
|
t.Cleanup(func() { stopFirst(); waitFirst() })
|
||||||
if err := inv.SavePlan(ctx, &p); err != nil {
|
if err := inv.SavePlan(ctx, &p); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user