D2 raised a resolver urgent on one query that timed out while its machine was loaded, and its summary carried the resolver's address and socket text, so the operator channel withheld the whole alert. - D2 asks every question up to three times, all at once; a resolver that answers nothing is held for the next run and raised urgent when two runs in a row find it silent. A wrong answer is still raised at once. - Findings a single look can be wrong about carry Confirm: raised on the second look in a row, kept while open, never cleared-and-reraised. Used by D2 silence, D3 (also asks discovery twice), D6 behind, D9, D13 unmeasured, probe-failed of the doctor, and blind watchdog rows. - Probe seat asks (D8, D13) are asked again when the bus brought no answer. - Summaries name machines and say things in words; addresses, paths, domains and raw errors move to the evidence (D2, D5, D8, D9, D13, S12). - internal/outward mirrors the messenger's content rule, allowing the mesh's machine names; the keeper rewords a summary that would be withheld and keeps it whole in the evidence; a TestMain lint fails the suite on any raised or linted finding that would be withheld.
47 lines
2.0 KiB
Go
47 lines
2.0 KiB
Go
package conditions
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/outward"
|
|
)
|
|
|
|
// **A summary the operator's channel would withhold is said in words, and kept whole in the evidence**
|
|
// (novox/hq issue 277, ADR 0234 §6): the condition that carried a resolver's address reached the
|
|
// operator as "its words are withheld" instead of the alert.
|
|
func TestASummaryCarryingAnAddressIsSaidInWordsAndKeptInTheEvidence(t *testing.T) {
|
|
k, _, _, _ := keeper(t)
|
|
before := Unsayable
|
|
var told []string
|
|
Unsayable = func(o Observation, field string, r outward.Refusal) { told = append(told, field+": "+r.What) }
|
|
t.Cleanup(func() { Unsayable = before })
|
|
|
|
raw := "AAAA for anchor.internal: no answer from 10.77.0.1: read udp 10.77.0.3:41234->10.77.0.1:53: i/o timeout"
|
|
c, err := k.Observe(t.Context(), Observation{Scope: ScopeSeat, ID: "mesh-dns-resolver.anchor", Token: "wrong",
|
|
Kind: "resolver-wrong", Machine: "anchor", Severity: Urgent, Source: "D2",
|
|
Summary: "the mesh's resolver on anchor does not answer: " + raw})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if r, ok := outward.Check(c.Summary, "anchor"); !ok {
|
|
t.Fatalf("the summary kept is still withheld (%s): %q", r, c.Summary)
|
|
}
|
|
if !strings.HasPrefix(c.Summary, "the mesh's resolver on anchor does not answer: ") {
|
|
t.Errorf("the summary's words were not kept: %q", c.Summary)
|
|
}
|
|
if !strings.Contains(c.Evidence[0].Said, raw) {
|
|
t.Errorf("the evidence lost what the summary carried: %q", c.Evidence[0].Said)
|
|
}
|
|
if len(told) != 1 || !strings.HasPrefix(told[0], "summary") {
|
|
t.Errorf("the producer was not named to the test: %v", told)
|
|
}
|
|
|
|
// A summary that may leave is kept as it is said, machine names and all.
|
|
ok, err := k.Observe(t.Context(), Observation{Scope: ScopeMachine, ID: "anchor", Kind: "silent", Machine: "anchor",
|
|
Severity: Warning, Source: "S1", Summary: "anchor has not been heard from since 12:00 UTC (bound 3m0s)"})
|
|
if err != nil || ok.Summary != "anchor has not been heard from since 12:00 UTC (bound 3m0s)" {
|
|
t.Fatalf("%q %v", ok.Summary, err)
|
|
}
|
|
}
|