package monitor import ( "strings" "testing" "gitea.dooplex.hu/admin/felhom-hub/internal/store" ) // Scenarios D, E and F of the R-260 / G-1 session, asserted on the CONSEQUENCE (does the check // report degraded, and does it name the right thing) rather than on the mechanism. func healthyRow() store.HostOOBRow { return store.HostOOBRow{ HostID: "h1", CustomerID: "c1", Present: true, FelhomSshdActive: true, Reachable: true, ConfigInvalid: false, OperatorPeerConfigured: true, OperatorKeyConfigured: true, OperatorKeyReported: true, } } // Scenario D — the box this session exists for: everything up, no operator key. func TestOOBDegraded_NoOperatorKey_IsDegradedAndSaysSo(t *testing.T) { r := healthyRow() r.OperatorKeyConfigured = false // reported, and false if !oobDegraded(r) { t.Fatal("a box with felhom-sshd active, reachable, a valid config, a configured peer and NO OPERATOR KEY reported ok — that is R-260, the exact question this check exists to answer") } reason := oobDegradedReason(r) // §7.4: the operator reads this at 07:00 and must know WHICH of the five things is wrong. if !strings.Contains(reason, "authorized_key") { t.Errorf("the reason must NAME the missing operator key, not just say access is degraded; got %q", reason) } for _, wrong := range []string{"unreachable", "config invalid"} { if strings.Contains(reason, wrong) { t.Errorf("the reason names %q, which is not what is wrong: %q", wrong, reason) } } } // Scenario E — a healthy box must be unchanged. No new alert on a box that is fine. func TestOOBDegraded_HealthyBoxUnchanged(t *testing.T) { if oobDegraded(healthyRow()) { t.Fatalf("a fully healthy box alerted: %q", oobDegradedReason(healthyRow())) } if got := oobDegradedReason(healthyRow()); got != "" { t.Errorf("healthy box produced a reason %q", got) } } // Scenario F — an agent too old to report the field. Absence must NOT read as "the key is // installed". This project has watched an absence read as a fact four times. func TestOOBDegraded_StanzaWithoutKeyField_IsNotOK(t *testing.T) { r := healthyRow() r.OperatorKeyReported = false r.OperatorKeyConfigured = false // the zero value an absent field leaves behind if !oobDegraded(r) { t.Fatal("an agent that never said whether the operator key is installed was reported ok — that is the defect returning through the version door") } reason := oobDegradedReason(r) if !strings.Contains(reason, "too old") || !strings.Contains(reason, "UNPROVEN") { t.Errorf("the unknown case must be reported DISTINCTLY from a known-missing key, and must not claim the key is absent; got %q", reason) } // and it must NOT be worded as the known-missing-key case if strings.Contains(reason, "nobody can log in") { t.Errorf("unknown was reported as if it were a known-missing key: %q", reason) } } // The peer gate is preserved: a box where OOB was never set up is not "broken", and this session // must not widen the check beyond the fact that is now arriving. func TestOOBDegraded_NoOperatorPeer_StillNotEvaluated(t *testing.T) { r := healthyRow() r.OperatorPeerConfigured = false r.OperatorKeyConfigured = false r.OperatorKeyReported = true if oobDegraded(r) { t.Errorf("a box with no operator peer configured must not alert on a missing key: %q", oobDegradedReason(r)) } } // The pre-existing faults must still fire, and still name themselves correctly. func TestOOBDegraded_ExistingFaultsUnchanged(t *testing.T) { for _, tc := range []struct { name string mutate func(*store.HostOOBRow) expect string }{ {"config invalid", func(r *store.HostOOBRow) { r.ConfigInvalid = true }, "config invalid"}, {"not active", func(r *store.HostOOBRow) { r.FelhomSshdActive = false }, "not active"}, {"unreachable", func(r *store.HostOOBRow) { r.Reachable = false }, "unreachable"}, } { t.Run(tc.name, func(t *testing.T) { r := healthyRow() tc.mutate(&r) if !oobDegraded(r) { t.Fatalf("%s no longer degrades", tc.name) } if got := oobDegradedReason(r); !strings.Contains(got, tc.expect) { t.Errorf("reason %q does not contain %q", got, tc.expect) } }) } } // A host with no oob stanza at all is never evaluated — pre-H1 or feature off. func TestOOBDegraded_AbsentStanzaNeverAlerts(t *testing.T) { if oobDegraded(store.HostOOBRow{HostID: "h1"}) { t.Error("a host with no oob stanza alerted") } }