From 5f002441b7f01266ae11b5bf6ac3078131d3bdb8 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 18 Oct 2026 12:28:03 +0200 Subject: [PATCH] mesh-delivery takes an empty answer to a check ask as a refusal (issue 1115) --- .../cmd/mesh-delivery/fakes_test.go | 5 +++++ .../mesh-delivery/cmd/mesh-delivery/holder.go | 4 ++++ .../cmd/mesh-delivery/timers_test.go | 17 +++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/modules/mesh-delivery/cmd/mesh-delivery/fakes_test.go b/modules/mesh-delivery/cmd/mesh-delivery/fakes_test.go index f48b1a76..c2f355bc 100644 --- a/modules/mesh-delivery/cmd/mesh-delivery/fakes_test.go +++ b/modules/mesh-delivery/cmd/mesh-delivery/fakes_test.go @@ -109,6 +109,8 @@ type fakeController struct { moves map[string][]string plans int down bool + // emptyCheck makes Check answer with no id and no error, as the port does when the answer holds none. + emptyCheck bool // walkReads counts the reads of the controller's walks (Walks). walkReads int // checkReady is the ready flag of each member of each check asked. @@ -185,6 +187,9 @@ func (c *fakeController) Check(group string, ms []Member) (string, error) { } c.asked++ id := fmt.Sprintf("check-%d", c.asked) + if c.emptyCheck { + id = "" + } var heads []string for _, m := range ms { heads = append(heads, m.ID) diff --git a/modules/mesh-delivery/cmd/mesh-delivery/holder.go b/modules/mesh-delivery/cmd/mesh-delivery/holder.go index d02478a7..41aaf4aa 100644 --- a/modules/mesh-delivery/cmd/mesh-delivery/holder.go +++ b/modules/mesh-delivery/cmd/mesh-delivery/holder.go @@ -1942,6 +1942,10 @@ func (h *Holder) askOwnCheck(id string, m Member, why string) { h.Logf("[mesh-delivery] %s's check cannot be asked yet: %v", id, err) return } + if asked == "" { + h.Logf("[mesh-delivery] %s's check was asked and the controller's answer held no id: taken as refused, asked again in a minute at most", id) + return + } delete(h.askTried, id) d := h.deliveries[id] if d == nil || d.State != Proposed || d.Check != nil || askedCheck(d) { diff --git a/modules/mesh-delivery/cmd/mesh-delivery/timers_test.go b/modules/mesh-delivery/cmd/mesh-delivery/timers_test.go index 4d378110..648c88cd 100644 --- a/modules/mesh-delivery/cmd/mesh-delivery/timers_test.go +++ b/modules/mesh-delivery/cmd/mesh-delivery/timers_test.go @@ -192,3 +192,20 @@ func TestAKeptAskWithNoIdAndNoStandingVerdictIsAskedAgainAtOnce(t *testing.T) { t.Fatalf("not asked again: %+v %v", d.CheckAsk, w.ctl.checks) } } + +func TestAnEmptyAnswerToACheckAskIsARefusalAskedAtMostOnceAMinute(t *testing.T) { + w := newWorld(t) + w.ctl.emptyCheck = true + w.h.PullUpdated(pr("novox/app", 7, readyHead, "feat/x", "src/a.go")) + id := IDOf("novox/app", readyHead) + w.settleAll() + w.settleAll() + if len(w.ctl.checks) != 1 || w.delivery(id).CheckAsk != nil || len(w.forge.notesOn(readyHead)) > 1 { + t.Fatalf("asked %v, ask kept %v; wanted one ask and none kept", w.ctl.checks, w.delivery(id).CheckAsk) + } + w.later(time.Minute) + w.settleAll() + if len(w.ctl.checks) != 2 { + t.Fatalf("not asked again after the minute: %v", w.ctl.checks) + } +}