Files
mesh-controller/internal/inventory/looks_test.go
T
jochen dcdafd37f0
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
Keep a condition's looks in the store, so a look that changes nothing writes no bucket (issue 420)
Every look rewrote the condition's value in the conditions bucket, because the
value carried the count of looks, the last look and the newest evidence: 131 647
writes in four days for twelve open conditions, against ADR 0289's rule that a
bucket is written only when what it describes changed. The looks now live in the
controller's store (migration 0095, condition_looks), the bucket holds what a
condition says and is written only when that changes, and the conditions verb and
the condition events put the looks back.
2026-10-12 12:11:13 +02:00

54 lines
2.0 KiB
Go

package inventory
import (
"context"
"encoding/json"
"errors"
"testing"
"time"
)
// **A condition's looks are kept in the store, replaced on every look and forgotten when it clears**
// (novox/hq issue 420): written under the lease, read back whole.
func TestAConditionsLooksAreKeptBesideTheBucket(t *testing.T) {
inv := ForTest(t)
ctx := t.Context()
inv.ActsUnder(func(context.Context) (uint64, error) { return 0, errors.New("the lease is not held") })
if err := inv.KeepConditionLooks(ctx, ConditionLooks{Key: "machine.ace.silent", Observations: 1,
LastObserved: time.Now()}); err == nil {
t.Fatal("looks were kept by a process that may not act")
}
inv.ActsUnder(func(context.Context) (uint64, error) { return 57, nil })
at := time.Now().UTC().Truncate(time.Microsecond)
for n := 1; n <= 3; n++ {
evidence, _ := json.Marshal([]map[string]any{{"at": at, "said": "ace has not been heard from"}})
if err := inv.KeepConditionLooks(ctx, ConditionLooks{Key: "machine.ace.silent", Observations: n,
LastObserved: at, Evidence: evidence}); err != nil {
t.Fatal(err)
}
}
if err := inv.KeepConditionLooks(ctx, ConditionLooks{Key: "machine.ace.late", Observations: 2,
LastObserved: at}); err != nil {
t.Fatal(err)
}
got, kept, err := inv.ConditionLooksOf(ctx, "machine.ace.silent")
if err != nil || !kept || got.Observations != 3 || !got.LastObserved.Equal(at) {
t.Fatalf("read %+v kept %v: %v", got, kept, err)
}
var evidence []map[string]any
if err := json.Unmarshal(got.Evidence, &evidence); err != nil || len(evidence) != 1 {
t.Fatalf("evidence %s: %v", got.Evidence, err)
}
all, err := inv.AllConditionLooks(ctx)
if err != nil || len(all) != 2 || all["machine.ace.late"].Observations != 2 ||
string(all["machine.ace.late"].Evidence) != "[]" {
t.Fatalf("all %+v: %v", all, err)
}
if err := inv.ForgetConditionLooks(ctx, "machine.ace.silent"); err != nil {
t.Fatal(err)
}
if _, kept, err := inv.ConditionLooksOf(ctx, "machine.ace.silent"); kept || err != nil {
t.Fatalf("a cleared condition's looks kept %v: %v", kept, err)
}
}