diff --git a/cmd/mesh-controller/delivery_conditions.go b/cmd/mesh-controller/delivery_conditions.go index 942bd9aa..d5fefbe8 100644 --- a/cmd/mesh-controller/delivery_conditions.go +++ b/cmd/mesh-controller/delivery_conditions.go @@ -55,6 +55,17 @@ type stalledLine struct { Bound string `json:"bound"` H2 string `json:"h2"` Says string `json:"says"` + // Severity is "urgent" for a group held or half merged and a refused member (novox/hq issues 1275, 1278); empty + // or anything else is a warning, as before. + Severity string `json:"severity,omitempty"` +} + +// severity is the condition's severity a stalled line asks: urgent when it says so, a warning otherwise. +func (l stalledLine) severity() conditions.Severity { + if l.Severity == string(conditions.Urgent) { + return conditions.Urgent + } + return conditions.Warning } // waitingCheck is one merge check a stalled line waits on, as mesh-delivery gives it: its context, its state — @@ -165,7 +176,7 @@ func stalledObservations(lines []stalledLine) []conditions.Observation { out := make([]conditions.Observation, 0, len(lines)) for _, l := range lines { o := conditions.Observation{Scope: conditions.ScopeDelivery, ID: l.ID, Kind: kindDeliveryStalled, - Severity: conditions.Warning, + Severity: l.severity(), Summary: fmt.Sprintf("the delivery %s has been %s for %s, past its bound of %s (%s): healer H2 may %s — "+ "`mesh-delivery.show %s`", l.ID, l.State, l.For, l.Bound, l.Says, l.H2, l.ID), Said: fmt.Sprintf("%s for %s", l.State, l.For)} diff --git a/cmd/mesh-controller/delivery_stalled_severity_test.go b/cmd/mesh-controller/delivery_stalled_severity_test.go new file mode 100644 index 00000000..d59eb346 --- /dev/null +++ b/cmd/mesh-controller/delivery_stalled_severity_test.go @@ -0,0 +1,37 @@ +package main + +import ( + "encoding/json" + "testing" + + "github.com/novox/mesh-controller/internal/conditions" +) + +func severityRaisedFor(t *testing.T, line string) conditions.Severity { + t.Helper() + var l stalledLine + if err := json.Unmarshal([]byte(line), &l); err != nil { + t.Fatal(err) + } + got := stalledObservations([]stalledLine{l}) + if len(got) != 1 { + t.Fatalf("%d conditions", len(got)) + } + return got[0].Severity +} + +func TestAnUrgentStalledLineRaisesAnUrgentCondition(t *testing.T) { // 1278/AC1 + line := `{"id":"novox/mesh-delivery#5","state":"held","for":"3m0s","bound":"0s","h2":"close","says":"held","severity":"urgent"}` + if got := severityRaisedFor(t, line); got != conditions.Urgent { + t.Errorf("an urgent line raised %q", got) + } +} + +func TestAStalledLineWithoutOrWithAnUnknownSeverityRaisesAWarning(t *testing.T) { // 1278/AC2 + for _, extra := range []string{``, `,"severity":""`, `,"severity":"critical"`, `,"severity":"warning"`} { + line := `{"id":"novox/a#1","state":"unanswered","for":"3m0s","bound":"2m0s","h2":"close","says":"x"` + extra + `}` + if got := severityRaisedFor(t, line); got != conditions.Warning { + t.Errorf("the line %s raised %q", extra, got) + } + } +}