7e21cd06b3
Stub and LLM paths both read loop.DownServices, so the message can never name a service the predicate did not fire on. Two down at once are both named — he needs the blast radius.
48 lines
1.3 KiB
Go
48 lines
1.3 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",
|
|
} {
|
|
if _, err := s.SetValue(ctx, store.KindEnv, key, ServiceDownSource, val, now.Add(-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")
|
|
}
|
|
}
|