Take an older bus module's allowed as held, and name only remedies that work (review 31 of PR 188, hq issue 353)
After mesh-catalog #166 merges and before the bus upgrade, the bus's machine cannot be pushed, so any change to the composed list made the list check read behind for good: every ask was withheld and the condition named a push that is refused. An older module's allowed now counts as held, the unconfirmed reload said once; the worst case is one ask refused in the seconds before a reload, which is asked again (issue 369). The list check stays for a module that says not allowed or cannot answer, and its remedy is the plan's own reason when the list cannot be composed, the bus upgrade while sends there wait on it, and a push otherwise. An in_force false is a wait only when the module gives both times; otherwise what is not known is named.
This commit is contained in:
@@ -871,34 +871,49 @@ func TestTheControllersOwnGrantToAskIsReadFromTheComposition(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The bus module's answer, judged with the check before it as the floor (the review of PR 188): an answer
|
||||
// without in_force is an older module, judged by whether the list sent to its machine is the one composed now;
|
||||
// each way it is not held names its own remedy.
|
||||
// The bus module's answer, with the record's word on the list sent as the check only where the answer does
|
||||
// not settle it (reviews 22 and 31 of PR 188); each way it is not held names its own remedy.
|
||||
func TestTheBusModulesAnswerNamesTheRemedyForEachCase(t *testing.T) {
|
||||
const (
|
||||
reloaded = `{"allowed":true,"in_force":true,"file_written":"2026-10-09T15:55:56Z","server_loaded":"2026-10-09T15:56:05Z"}`
|
||||
notLoaded = `{"allowed":true,"in_force":false,"why":"the user list on the machine allows it, and the server has not reloaded since it was written","file_written":"2026-10-09T15:55:56Z","server_loaded":"2026-10-09T15:50:00Z"}`
|
||||
noVarz = `{"allowed":true,"in_force":false,"why":"the server's last configuration load could not be read: refused"}`
|
||||
noStat = `{"allowed":true,"in_force":false,"why":"when the bus's user list was written could not be read inside mesh-broker-nats: exit 1"}`
|
||||
notAllowed = `{"allowed":false,"in_force":false,"why":"the user list on the machine does not allow it"}`
|
||||
)
|
||||
current := busListState{Machine: "anchor"}
|
||||
behind := busListState{Machine: "anchor", Behind: true}
|
||||
stepped := busListState{Machine: "anchor", Behind: true, BusStep: "sending anchor would replace the bus; `bus upgrade --why …`"}
|
||||
uncomposed := busListState{Machine: "anchor", Behind: true, Uncomposed: errors.New("module foo requires a provision nobody provides")}
|
||||
for _, c := range []struct {
|
||||
name, answer string
|
||||
behind bool
|
||||
behindErr error
|
||||
askErr error
|
||||
list busListState
|
||||
listErr error
|
||||
held bool
|
||||
says, not string
|
||||
}{
|
||||
{"in force", `{"allowed":true,"in_force":true}`, false, nil, true, "", "push"},
|
||||
{"in force, list behind by the record", `{"allowed":true,"in_force":true}`, true, nil, true, "", "push"},
|
||||
{"written, not reloaded", `{"allowed":true,"in_force":false,"why":"the server has not reloaded since it was written"}`,
|
||||
false, nil, false, "within about 5 s", "push"},
|
||||
{"not allowed", `{"allowed":false,"in_force":false}`, false, nil, false, "`push anchor` carries it", "5 s"},
|
||||
{"in force and not allowed", `{"allowed":false,"in_force":true}`, false, nil, false, "`push anchor`", "5 s"},
|
||||
{"older module, list current", `{"allowed":true}`, false, nil, true, "not confirmed", "push"},
|
||||
{"older module, list behind", `{"allowed":true}`, true, nil, false, "`push anchor` carries it", "5 s"},
|
||||
{"older module, list not allowed", `{"allowed":false}`, false, nil, false, "`push anchor` carries it", "5 s"},
|
||||
{"older module, list unknown", `{"allowed":true}`, false, errors.New("the store is away"), false, "`bus upgrade`", "push"},
|
||||
{"not json", `not json`, false, nil, false, "could not be read", ""},
|
||||
{"in force", reloaded, nil, behind, nil, true, "", "push"},
|
||||
{"written, not reloaded", notLoaded, nil, current, nil, false, "within about 5 s", "push"},
|
||||
{"in force not known: varz", noVarz, nil, current, nil, false, "is not known: the server's last configuration load", "wait"},
|
||||
{"in force not known: stat", noStat, nil, current, nil, false, "is not known: when the bus's user list was written", "wait"},
|
||||
{"not allowed, list behind", notAllowed, nil, behind, nil, false, "`push anchor` carries it", "5 s"},
|
||||
{"not allowed, bus step pending", notAllowed, nil, stepped, nil, false, "`bus upgrade", "`push anchor`"},
|
||||
{"not allowed, list uncomposed", notAllowed, nil, uncomposed, nil, false, "`plan anchor`", "`push anchor`"},
|
||||
{"older module, allowed, list current", `{"allowed":true}`, nil, current, nil, true, "not confirmed", "push"},
|
||||
{"older module, allowed, list behind", `{"allowed":true}`, nil, behind, nil, true, "not confirmed", "push"},
|
||||
{"older module, allowed, list unknown", `{"allowed":true}`, nil, current, errors.New("the store is away"), true, "`bus upgrade`", "push"},
|
||||
{"older module, not allowed, list behind", `{"allowed":false}`, nil, behind, nil, false, "`push anchor` carries it", "5 s"},
|
||||
{"module cannot answer, list current", "", errors.New("no responders"), current, nil, true, "could not answer", "push"},
|
||||
{"module cannot answer, list behind", "", errors.New("no responders"), behind, nil, false, "`push anchor` carries it", ""},
|
||||
{"module cannot answer, list unknown", "", errors.New("no responders"), current, errors.New("the store is away"), false, "could not be worked out", ""},
|
||||
{"answer unreadable, list behind", `not json`, nil, behind, nil, false, "could not be read", ""},
|
||||
} {
|
||||
judge := busGrantBy(
|
||||
func(context.Context) (string, json.RawMessage, error) {
|
||||
return "anchor", json.RawMessage(c.answer), nil
|
||||
return "anchor", json.RawMessage(c.answer), c.askErr
|
||||
},
|
||||
func(context.Context) (string, bool, error) { return "anchor", c.behind, c.behindErr })
|
||||
func(context.Context) (busListState, error) { return c.list, c.listErr })
|
||||
held, why, _ := judgeGrantOnce(judge)
|
||||
if held != c.held || !strings.Contains(why, c.says) || (c.not != "" && strings.Contains(why, c.not)) {
|
||||
t.Errorf("%s: held %v (%q)", c.name, held, why)
|
||||
@@ -916,23 +931,30 @@ func judgeGrantOnce(bus grantJudge) (bool, string, error) {
|
||||
return grantHeldBy(yes, bus, time.Now)(context.Background())
|
||||
}
|
||||
|
||||
// The order the review of PR 188 found: this controller live before the bus module that answers in_force. An
|
||||
// older module with the list sent current asks; with the list behind it asks nothing and the condition names the
|
||||
// push; a new module that has not reloaded names the wait, not a push.
|
||||
// The orders reviews 22 and 31 of PR 188 found: this controller live before the bus module that answers
|
||||
// in_force, with the bus's machine behind on its list — and, after mesh-catalog #166 merged, unpushable until a
|
||||
// person's bus upgrade. An older module that allows the ask asks (once, with the caveat said); a new module that
|
||||
// has not reloaded names the wait, not a push; one that cannot say whether it reloaded names what is not known.
|
||||
func TestAnOlderBusModuleNeitherSilencesTheAsksNorNamesTheWrongRemedy(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
name, answer string
|
||||
behind bool
|
||||
list busListState
|
||||
asks bool
|
||||
says, not string
|
||||
}{
|
||||
{"older module, list current", `{"allowed":true}`, false, true, "", ""},
|
||||
{"older module, list behind", `{"allowed":true}`, true, false, "`push anchor` carries it", "5 s"},
|
||||
{"new module, not reloaded", `{"allowed":true,"in_force":false,"why":"the server has not reloaded since it was written"}`,
|
||||
false, false, "within about 5 s", "push"},
|
||||
{"older module, list current", `{"allowed":true}`, busListState{Machine: "anchor"}, true, "not confirmed", ""},
|
||||
{"older module, list behind, bus step pending", `{"allowed":true}`,
|
||||
busListState{Machine: "anchor", Behind: true, BusStep: "a planned step"}, true, "not confirmed", ""},
|
||||
{"new module, not reloaded",
|
||||
`{"allowed":true,"in_force":false,"why":"not reloaded","file_written":"2026-10-09T15:55:56Z","server_loaded":"2026-10-09T15:50:00Z"}`,
|
||||
busListState{Machine: "anchor"}, false, "within about 5 s", "push"},
|
||||
{"new module, reload not known", `{"allowed":true,"in_force":false,"why":"the server's last configuration load could not be read: refused"}`,
|
||||
busListState{Machine: "anchor"}, false, "is not known", "wait"},
|
||||
} {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
r := newAskerRig(t)
|
||||
var said []string
|
||||
r.a.logf = func(f string, a ...any) { said = append(said, fmt.Sprintf(f, a...)) }
|
||||
var raised [][]conditions.Observation
|
||||
r.a.raise = func(_ context.Context, obs []conditions.Observation) error {
|
||||
raised = append(raised, obs)
|
||||
@@ -943,15 +965,25 @@ func TestAnOlderBusModuleNeitherSilencesTheAsksNorNamesTheWrongRemedy(t *testing
|
||||
func(context.Context) (string, json.RawMessage, error) {
|
||||
return "anchor", json.RawMessage(c.answer), nil
|
||||
},
|
||||
func(context.Context) (string, bool, error) { return "anchor", c.behind, nil }),
|
||||
func(context.Context) (busListState, error) { return c.list, nil }),
|
||||
func() time.Time { return r.now })
|
||||
r.open = []conditions.Condition{heldCondition()}
|
||||
_ = r.a.reconcile(context.Background())
|
||||
_ = r.a.reconcile(context.Background())
|
||||
sent := r.asksSent(t)
|
||||
if c.asks {
|
||||
if len(sent) != 1 || sent[0].About != heldCondition().Key {
|
||||
t.Fatalf("not asked: %+v", sent)
|
||||
}
|
||||
n := 0
|
||||
for _, s := range said {
|
||||
if strings.Contains(s, c.says) {
|
||||
n++
|
||||
}
|
||||
}
|
||||
if n != 1 {
|
||||
t.Errorf("the caveat said %d times: %q", n, said)
|
||||
}
|
||||
return
|
||||
}
|
||||
if len(sent) != 0 {
|
||||
|
||||
Reference in New Issue
Block a user