mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Make release health-gate tests synchronize on observed state
Wait for the agent supervisor to check false readiness before asserting its commit gate, and give the race-instrumented fixture a non-expiring window. Hold the monitoring request at target resolution after its history snapshot so replacement is deterministic. Keep production paths and assertions unchanged. Change-source: pulse-maintainer
This commit is contained in:
@@ -1901,11 +1901,13 @@ func (s *pendingUpdateSupervisorStub) Rollback(_ context.Context, activation age
|
||||
func testPendingUpdate(t *testing.T, stateDir string) *agentupdate.PendingPrivilegedUpdate {
|
||||
t.Helper()
|
||||
activation := agenthelper.UpdateResult{
|
||||
Action: "pending",
|
||||
ActivationID: "pulse-agent-0123456789abcdef0123456789abcdef:0123456789abcdef",
|
||||
ActiveSHA256: strings.Repeat("a", 64),
|
||||
RollbackSHA256: strings.Repeat("b", 64),
|
||||
RollbackDeadline: time.Now().Add(2 * time.Second).UTC(),
|
||||
Action: "pending",
|
||||
ActivationID: "pulse-agent-0123456789abcdef0123456789abcdef:0123456789abcdef",
|
||||
ActiveSHA256: strings.Repeat("a", 64),
|
||||
RollbackSHA256: strings.Repeat("b", 64),
|
||||
// Leave enough time for the race-instrumented supervisor to be scheduled.
|
||||
// The test below checks the health gates, not the expiry path.
|
||||
RollbackDeadline: time.Now().Add(30 * time.Second).UTC(),
|
||||
}
|
||||
if err := agentupdate.PersistPendingPrivilegedUpdate(stateDir, "1.0.0", activation); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -1932,14 +1934,38 @@ func TestPendingPrivilegedUpdateCommitsOnlyAfterReadinessAndAcceptedReport(t *te
|
||||
reportAccepted := make(chan struct{})
|
||||
close(reportAccepted)
|
||||
var ready atomic.Bool
|
||||
notReadyChecks := make(chan struct{}, 2)
|
||||
locallyReady := func() bool {
|
||||
if ready.Load() {
|
||||
return true
|
||||
}
|
||||
select {
|
||||
case notReadyChecks <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
return false
|
||||
}
|
||||
result := make(chan error, 1)
|
||||
go func() {
|
||||
result <- supervisePendingPrivilegedUpdate(context.Background(), stub, pending, stateDir, pending.Activation.ActiveSHA256, ready.Load, reportAccepted, time.Millisecond, nil)
|
||||
result <- supervisePendingPrivilegedUpdate(context.Background(), stub, pending, stateDir, pending.Activation.ActiveSHA256, locallyReady, reportAccepted, time.Millisecond, nil)
|
||||
}()
|
||||
// Observe the supervisor checking the false readiness state on two passes.
|
||||
// A sleep cannot prove it started before we flip readiness under -race.
|
||||
for range 2 {
|
||||
select {
|
||||
case <-notReadyChecks:
|
||||
case <-stub.commitCalls:
|
||||
t.Fatal("pending update committed before local readiness")
|
||||
case err := <-result:
|
||||
t.Fatalf("pending update supervisor stopped before local readiness: %v", err)
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("pending update supervisor did not check local readiness")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case <-stub.commitCalls:
|
||||
t.Fatal("pending update committed before local readiness")
|
||||
case <-time.After(20 * time.Millisecond):
|
||||
default:
|
||||
}
|
||||
ready.Store(true)
|
||||
select {
|
||||
@@ -1947,7 +1973,9 @@ func TestPendingPrivilegedUpdateCommitsOnlyAfterReadinessAndAcceptedReport(t *te
|
||||
if activation != pending.Activation {
|
||||
t.Fatalf("commit activation = %#v", activation)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
case err := <-result:
|
||||
t.Fatalf("pending update supervisor stopped before committing: %v", err)
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("pending update was not committed after both health signals")
|
||||
}
|
||||
if err := <-result; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user