0560684b35
Technitium read down on one poll and up on the next, sixty seconds apart, and the sev4 arrived after the service was already back. mavpoll writes a service_down fact only when the state changes, so the fact's timestamp IS the moment the monitor went down and its age is how long it has stayed there. The debounce is that age against MinDownAge, 90s — one poll interval plus jitter. No history to keep and no counter to persist. It bounds the alarm and not the truth: DownServices still reports a monitor the instant it goes down, because /dash showing a fresh outage is right even when phoning him about it is not. Existing fixtures that seeded a one-minute-old down fact now seed five, which is what they always meant.
50 lines
1.4 KiB
Go
50 lines
1.4 KiB
Go
package loop
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/kami/maven/internal/store"
|
|
)
|
|
|
|
// The gatherer is the only impure piece, and a rule over a prefix has no keys
|
|
// to declare at wiring time. This is the end of that path: mavpoll's per-monitor
|
|
// facts reach the snapshot, and the rule fires on the one that is down.
|
|
func TestGatherStateLoadsPrefixFamilies(t *testing.T) {
|
|
ctx := context.Background()
|
|
s, err := store.Open(ctx, filepath.Join(t.TempDir(), "loop_test.db"))
|
|
if err != nil {
|
|
t.Fatalf("Open: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = s.Close() })
|
|
|
|
now := time.Now().UTC().Truncate(time.Millisecond)
|
|
for key, val := range map[string]string{
|
|
"service_down:db": "down",
|
|
"service_down:web": "up",
|
|
} {
|
|
// Older than MinDownAge, so this tests the gather path and not the
|
|
// flap debounce.
|
|
if _, err := s.SetValue(ctx, store.KindEnv, key, ServiceDownSource, val, now.Add(-5*time.Minute)); err != nil {
|
|
t.Fatalf("SetValue %s: %v", key, err)
|
|
}
|
|
}
|
|
|
|
rules := []Rule{ServiceDownRule()}
|
|
st, _, err := NewGatherer(s, rules).GatherState(ctx, now)
|
|
if err != nil {
|
|
t.Fatalf("GatherState: %v", err)
|
|
}
|
|
if _, ok := st.Facts["service_down:db"]; !ok {
|
|
t.Fatalf("prefix family not gathered: %v", st.Facts)
|
|
}
|
|
if got := DownServices(st); len(got) != 1 || got[0] != "db" {
|
|
t.Fatalf("DownServices = %v, want [db]", got)
|
|
}
|
|
if !rules[0].Predicate(st) {
|
|
t.Fatal("the rule must fire on a gathered per-monitor fact")
|
|
}
|
|
}
|