package inventory import ( "testing" "time" ) func size(n int64) *int64 { return &n } func at(t time.Time) *time.Time { return &t } // What a machine declares is kept with what its holder measured; an irreplaceable item it no longer // declares — its module unassigned — is RETIRED and kept, never forgotten, and comes back as it was when // declared again; anything else no longer declared is forgotten (novox/hq ADR 0233). func TestAnUndeclaredIrreplaceableItemIsRetiredNotForgotten(t *testing.T) { inv := fresh(t) ctx := t.Context() now := time.Date(2026, 10, 6, 12, 0, 0, 0, time.UTC) declared := []DeclaredData{ {Module: "home-assistant", Item: "config", Class: "irreplaceable", Owned: true}, {Module: "searxng", Item: "valkey", Class: "cache"}, {Module: "ollama", Item: "models", Class: "rebuildable"}, } measured := map[string]map[string]Measurement{"home-assistant": {"config": {Path: "/var/lib/home-assistant/config", Size: size(900 << 20), LastWrite: at(now.Add(-time.Minute)), MeasuredAt: at(now), LastBackup: at(now.Add(-6 * time.Hour))}}} if _, err := inv.RecordData(ctx, "home", declared, measured, "", now); err != nil { t.Fatal(err) } all, err := inv.Data(ctx) if err != nil || len(all) != 3 { t.Fatalf("%+v, %v", all, err) } // Unassigned: nothing of it is declared any more. later := now.Add(time.Hour) change, err := inv.RecordData(ctx, "home", nil, nil, "home-assistant unassigned", later) if err != nil { t.Fatal(err) } if len(change.Retired) != 1 || change.Retired[0].Item != "config" { t.Fatalf("retired %+v", change.Retired) } all, err = inv.Data(ctx) if err != nil { t.Fatal(err) } if len(all) != 1 || !all[0].Retired() || all[0].Path != "/var/lib/home-assistant/config" || *all[0].Size != 900<<20 || all[0].RetiredWhy != "home-assistant unassigned" { t.Fatalf("the irreplaceable item is not kept retired with where it is: %+v", all) } // A second run that still does not declare it changes nothing: retired once, not again. change, err = inv.RecordData(ctx, "home", nil, nil, "again", later.Add(time.Hour)) if err != nil || len(change.Retired) != 0 { t.Fatalf("retired twice: %+v, %v", change, err) } // Deleting needs it retired; assigned again it is not retired any more, and its history stays. if err := inv.MarkDataDeleted(ctx, "home", "searxng", "valkey", "p", "w", later); err == nil { t.Fatal("deleting something the mesh does not hold retired was recorded") } change, err = inv.RecordData(ctx, "home", declared[:1], nil, "", later.Add(2*time.Hour)) if err != nil || len(change.Reenabled) != 1 { t.Fatalf("declared again: %+v, %v", change, err) } r, err := inv.DataOf(ctx, "home", "home-assistant", "config") if err != nil || r.Retired() || !r.FirstSeen.Equal(now) || r.Size == nil { t.Fatalf("declared again lost what was known: %+v, %v", r, err) } // Retired and then deleted by a person: recorded, never by dropping the row. if _, err := inv.RecordData(ctx, "home", nil, nil, "unassigned again", later.Add(3*time.Hour)); err != nil { t.Fatal(err) } if err := inv.MarkDataDeleted(ctx, "home", "home-assistant", "config", "jochen", "moved to the anchor", later.Add(4*time.Hour)); err != nil { t.Fatal(err) } r, err = inv.DataOf(ctx, "home", "home-assistant", "config") if err != nil || r.DeletedAt == nil || r.DeletedBy != "jochen" || r.Retired() { t.Fatalf("a deletion is not on record: %+v, %v", r, err) } } // A reading is kept at most once an hour, and the peak is read over the window asked. func TestReadingsAreHourlyAndThePeakIsTheLargest(t *testing.T) { inv := fresh(t) ctx := t.Context() now := time.Date(2026, 10, 6, 0, 0, 0, 0, time.UTC) declared := []DeclaredData{{Module: "grafana", Item: "data", Class: "valuable", Owned: true}} for i, s := range []int64{100, 120, 999, 130, 40} { when := now.Add(time.Duration(i) * 20 * time.Minute) if _, err := inv.RecordData(ctx, "ace", declared, map[string]map[string]Measurement{"grafana": {"data": { Path: "/var/lib/grafana/data", Size: size(s), MeasuredAt: at(when)}}}, "", when); err != nil { t.Fatal(err) } } var n int if err := inv.store.Pool().QueryRow(ctx, `select count(*) from data_reading`).Scan(&n); err != nil || n != 2 { t.Fatalf("%d readings kept for five measurements over 80 minutes, want 2 (one an hour): %v", n, err) } peaks, err := inv.DataPeaks(ctx, now.Add(-time.Hour)) if err != nil || peaks["ace/grafana/data"] != 130 { t.Fatalf("peak %v, %v", peaks, err) } r, _ := inv.DataOf(ctx, "ace", "grafana", "data") if r.Size == nil || *r.Size != 40 { t.Fatalf("the newest measurement is not the one on record: %+v", r) } } // A partial walk's lower bound is kept as the newest measurement, said as partial, and never kept as a // reading a shrink would be read against. func TestAPartialMeasurementIsNeverAReading(t *testing.T) { inv := fresh(t) ctx := t.Context() now := time.Date(2026, 10, 6, 0, 0, 0, 0, time.UTC) declared := []DeclaredData{{Module: "big", Item: "data", Class: "valuable", Owned: true}} if _, err := inv.RecordData(ctx, "home", declared, map[string]map[string]Measurement{"big": {"data": { Path: "/srv/big", Size: size(5), MeasuredAt: at(now), Precision: "partial: stopped"}}}, "", now); err != nil { t.Fatal(err) } var n int if err := inv.store.Pool().QueryRow(ctx, `select count(*) from data_reading`).Scan(&n); err != nil || n != 0 { t.Fatalf("%d readings from a partial measurement: %v", n, err) } r, err := inv.DataOf(ctx, "home", "big", "data") if err != nil || r.Precision != "partial: stopped" || Comparable(r.Precision) { t.Fatalf("%+v, %v", r, err) } }