mesh/delivery-group group feat/774-l3-reland rejected: composed together: the checker's verdict at the members' heads (b48c90fea31f): integration: mesh-self-ch…
mesh/delivery closed: a newer head of the same pull request
mesh/check failed: integration: mesh-self-check/cmd/mesh-self-check.TestTheSelfCheckWholeRunsOnTheBus: the run answered {Run:doctor-1793351737-1 At:20…
One commit with exactly the tree of the reviewed head35b4509c0a, on main12c2574c9d, so two compiled programs added and removed on the branch leave no trace in history (issue 1577).
145 lines
6.2 KiB
Go
145 lines
6.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"git.novox.be/novox/mesh-sdk/go/health"
|
|
)
|
|
|
|
type memStore struct{ m map[string]json.RawMessage }
|
|
|
|
func (s *memStore) Get(k string) (json.RawMessage, error) { return s.m[k], nil }
|
|
func (s *memStore) Put(k string, v any) error {
|
|
raw, _ := json.Marshal(v)
|
|
s.m[k] = raw
|
|
return nil
|
|
}
|
|
func (s *memStore) Keys() ([]string, error) {
|
|
var out []string
|
|
for k := range s.m {
|
|
out = append(out, k)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// A round measures what the data file declares but caches, keeps the readings, writes nothing the second time, and a
|
|
// walk is not repeated within a day unless asked.
|
|
func TestARoundMeasuresTheDeclaredItemsAndWritesWhatChanged(t *testing.T) {
|
|
text := "# pg\nitem data valuable /srv/pg /srv/pg backup walk\nitem tmp cache /srv/tmp - none\n# bad-line-module\nitem logs rebuildable /srv/logs - none shallow\n"
|
|
placed, err := catalogue.ParseDataItems(text)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
walks := 0
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
switch {
|
|
case name == "test":
|
|
return "", nil
|
|
case name == "findmnt":
|
|
return "", os.ErrNotExist
|
|
case name == "bash" && strings.Contains(args[1], "-maxdepth 1"):
|
|
return "1760000000 2\n", nil
|
|
case name == "bash":
|
|
walks++
|
|
return "4096 1760000000 3\n0\n", nil
|
|
}
|
|
return "", os.ErrNotExist
|
|
}
|
|
now := time.Date(2026, 10, 29, 12, 0, 0, 0, time.UTC)
|
|
store := &memStore{m: map[string]json.RawMessage{}}
|
|
k := &Keeper{Node: "ace", Items: func(context.Context) (map[string][]catalogue.PlacedDataItem, error) { return placed, nil }, Store: store, Say: func(string, ...any) {},
|
|
Measurer: Measurer{Run: run, Now: func() time.Time { return now }}}
|
|
w, kept, err := k.Round(context.Background(), false)
|
|
if err != nil || w != 2 || kept != 0 || len(store.m) != 2 {
|
|
t.Fatalf("first round: %d written %d kept %v, keys %d", w, kept, err, len(store.m))
|
|
}
|
|
now = now.Add(time.Hour)
|
|
if w, kept, _ := k.Round(context.Background(), false); w != 0 || kept != 2 || walks != 1 {
|
|
t.Fatalf("second round: %d written, %d kept, %d walks; wanted none written and the walk not repeated", w, kept, walks)
|
|
}
|
|
if _, _, err := k.MeasureNow(context.Background(), "pg", "data"); err != nil || walks != 2 {
|
|
t.Fatalf("measure now: %v, %d walks", err, walks)
|
|
}
|
|
// An item no longer declared is kept, retired with when and why; declared again, it is not retired any more.
|
|
delete(placed, "pg")
|
|
if _, _, err := k.Round(context.Background(), false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gone, _ := health.DecodeReading(store.m["ace.pg.data"])
|
|
if gone.RetiredAt.IsZero() || !strings.Contains(gone.RetiredWhy, "no longer declared on ace") || gone.FirstSeen.IsZero() {
|
|
t.Fatalf("a reading of an item no longer declared: %+v", gone)
|
|
}
|
|
placed["pg"] = []catalogue.PlacedDataItem{{Module: "pg", ID: "data", Class: "valuable", Path: "/srv/pg", Measure: catalogue.MeasureWalk}}
|
|
if _, _, err := k.Round(context.Background(), false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if back, _ := health.DecodeReading(store.m["ace.pg.data"]); !back.RetiredAt.IsZero() {
|
|
t.Fatalf("a reading declared again is still retired: %+v", back)
|
|
}
|
|
if _, _, err := k.MeasureNow(context.Background(), "pg", "tmp"); err == nil {
|
|
t.Fatal("a cache was measured")
|
|
}
|
|
}
|
|
|
|
// The redundant storage under an item is read: a ZFS pool healthy, then degraded; an md array with a member missing; and
|
|
// plain storage, which is no redundancy at all. A dataset is measured from the filesystem's counters and a shallow item
|
|
// from its top-level entries only; a walk that meets more than its bound stops and says so.
|
|
func TestTheStorageUnderAnItemAndTheLargeMethodsAreRead(t *testing.T) {
|
|
poolHealth, statusX, fs := "ONLINE\n", "pool 'storage' is healthy\n", "storage/media zfs\n"
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
line := name + " " + strings.Join(args, " ")
|
|
switch {
|
|
case name == "test":
|
|
return "", nil
|
|
case name == "findmnt":
|
|
return fs, nil
|
|
case name == "zpool" && args[0] == "list":
|
|
return poolHealth, nil
|
|
case name == "zpool":
|
|
return statusX, nil
|
|
case name == "cat":
|
|
return "Personalities : [raid1]\nmd127 : active raid1 sdb1[1] sda1[0]\n 976630464 blocks super 1.2 [2/1] [U_]\n\nunused devices: <none>\n", nil
|
|
case name == "zfs" && args[len(args)-1] == "/storage/media/movies":
|
|
return "storage/media\t97067690722560\n", nil
|
|
case name == "zfs":
|
|
return "", os.ErrNotExist
|
|
case name == "bash" && strings.Contains(line, "-maxdepth 1"):
|
|
return "1759744800 12673\n", nil
|
|
case name == "bash":
|
|
return "123 1759700000 2000000\n141\n", nil
|
|
}
|
|
return "", nil
|
|
}
|
|
m := Measurer{Run: run, Now: time.Now}
|
|
ctx := context.Background()
|
|
got := m.Measure(ctx, catalogue.PlacedDataItem{Module: "media", ID: "movies", Path: "/storage/media/movies", Measure: catalogue.MeasureDataset})
|
|
if got.SizeBytes == nil || *got.SizeBytes != 97067690722560 || !strings.HasPrefix(got.Precision, "dataset storage/media") ||
|
|
got.LastWrite == nil || got.Redundancy == nil || got.Redundancy.Kind != "zfs" || got.Redundancy.Healthy == nil || !*got.Redundancy.Healthy {
|
|
t.Fatalf("the library from its dataset: %+v", got)
|
|
}
|
|
poolHealth, statusX = "DEGRADED\n", " pool: storage\n state: DEGRADED\nstatus: One or more devices has been removed\n"
|
|
if r := m.redundancyOf(ctx, "/storage/media/movies"); r.Healthy == nil || *r.Healthy || !strings.Contains(r.Said, "DEGRADED") {
|
|
t.Fatalf("a degraded pool: %+v", r)
|
|
}
|
|
fs = "/dev/md127 ext4\n"
|
|
if r := m.redundancyOf(ctx, "/srv/x"); r == nil || r.Kind != "md" || r.Healthy == nil || *r.Healthy {
|
|
t.Fatalf("an array missing a member: %+v", r)
|
|
}
|
|
fs = "/dev/nvme0n1p3 ext4\n"
|
|
if r := m.redundancyOf(ctx, "/var/lib/x"); r != nil {
|
|
t.Fatalf("plain storage read as redundant: %+v", r)
|
|
}
|
|
if s := m.Measure(ctx, catalogue.PlacedDataItem{Path: "/mnt/plex/config", Measure: catalogue.MeasureShallow}); s.SizeBytes != nil || !strings.HasPrefix(s.Precision, "no size") {
|
|
t.Fatalf("a shallow item: %+v", s)
|
|
}
|
|
if w := m.Measure(ctx, catalogue.PlacedDataItem{Path: "/srv/big", Measure: catalogue.MeasureWalk}); !strings.HasPrefix(w.Precision, "partial") {
|
|
t.Fatalf("a walk stopped at its bound: %+v", w)
|
|
}
|
|
}
|