CAT-N6: the keeper's health tool nats_keeper_health, which the process keeper's tool check asks
It reads the keeper's status from its own state asked, what the keeper holds, and how many accepted verdicts wait on its consumer <node>_nats_keeper on EVENTS from the monitoring endpoint, and answers HealthOf's judgement: unhealthy, naming why, past the three-minute bound; the entries refused, waiting and past the raise mark named beside. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -4,8 +4,11 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
|
||||
"nats-tools/internal/keeper"
|
||||
)
|
||||
|
||||
// The keeper's inputs (design 25 § 12.2; CAT-N2): a manifest-accepted read with the indexer's revision when it carries
|
||||
@@ -63,3 +66,30 @@ func line(module, digest string, revision uint64, entries []catalogue.BusStateEn
|
||||
}
|
||||
return fmt.Sprintf("%s %s %d [%s]", module, digest, revision, strings.Join(es, " "))
|
||||
}
|
||||
|
||||
// The keeper's health tool (CAT-N6): healthy naming its pass; unhealthy, naming why, when its pass is old or verdicts
|
||||
// wait on its consumer `<node>_nats_keeper` past the bound.
|
||||
func TestTheKeepersHealthToolReadsItsStatusAndItsConsumer(t *testing.T) {
|
||||
at := time.Date(2026, 11, 4, 12, 0, 0, 0, time.UTC)
|
||||
jsz := `{"account_details":[{"stream_detail":[{"name":"EVENTS","consumer_detail":[{"name":"anchor_nats_keeper","num_pending":3},{"name":"anchor_nats","num_pending":9}]}]}]}`
|
||||
status := keeper.Status{Started: at.Add(-time.Hour), Pass: at.Add(-time.Minute), Heard: at.Add(-time.Minute),
|
||||
FirstView: keeper.FirstViewStatus{Owner: keeper.FirstViewOwner, Verb: keeper.FirstViewVerb, Answered: at.Add(-time.Hour)}}
|
||||
none := func() (map[string]keeper.Asked, error) { return nil, nil }
|
||||
for _, row := range []struct {
|
||||
name string
|
||||
now time.Time
|
||||
state string
|
||||
why string
|
||||
}{
|
||||
{"its pass is fresh", at, "healthy", "last pass 2026-11-04T11:59:00Z"},
|
||||
{"its pass and its verdicts are old", at.Add(5 * time.Minute), "unhealthy", "3 accepted verdict(s) wait on its consumer"},
|
||||
} {
|
||||
t.Run(row.name, func(t *testing.T) {
|
||||
a := keeperHealth(func() (keeper.Status, error) { return status, nil }, none,
|
||||
func() ([]byte, error) { return []byte(jsz), nil }, func() time.Time { return row.now })
|
||||
if a.State != row.state || !strings.Contains(a.Why, row.why) {
|
||||
t.Errorf("answered %+v: %s, naming %q", a, row.state, row.why)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user