package main import ( "slices" "strings" "testing" "time" "github.com/novox/mesh-controller/internal/inventory" ) // A machine out of touch when a tier is sent is not sent to and not waited for (novox/hq ADR 0435 ยง1, issue 1161): the // walk judges it with the silent check's one verdict, machineFacts.silent, and a sleeping machine is away once presence says so. // 1161/AC1: away is the silent check's verdict; AC4: a machine heard is not away. func TestAMachineIsAwayAsTheSilentCheckJudgesIt(t *testing.T) { now := time.Now().UTC() machines := []machineFacts{ {name: "heard", lastHeard: now.Add(-time.Minute)}, {name: "quiet", lastHeard: now.Add(-silentBound - time.Minute)}, {name: "stuck", lastHeard: now, presence: presenceSilent}, {name: "back", lastHeard: now.Add(-time.Hour), presence: presenceHeard}, {name: "new"}, } got := awayOf(machines, now) for node, want := range map[string]bool{"heard": false, "quiet": true, "stuck": true, "back": false, "new": false} { if got[node] != want { t.Errorf("1161/AC1: %s away is %v; want %v (away: %v)", node, got[node], want, got) } } } // 1161/AC1, AC2: the plan keeps the machines of the tier it passed as away, sorted and once. func TestAPlanKeepsTheMachinesItPassedAsAway(t *testing.T) { p := &inventory.Plan{} away := map[string]bool{"g14": true, "ace": true} rememberAway(p, []string{"anchor", "g14"}, away) rememberAway(p, []string{"g14", "ace"}, away) if !slices.Equal(p.Away, []string{"ace", "g14"}) { t.Fatalf("1161/AC2: the plan keeps %v away; want ace, g14", p.Away) } } // 1161/AC2: the plan says it, where its other passed machines are said. func TestAPlanSaysTheMachinesItPassedAsAway(t *testing.T) { say := awaySaying(inventory.Plan{Away: []string{"g14"}}) if !strings.Contains(say, "g14 was away: sent when it is heard again") { t.Fatalf("1161/AC2: the plan says %q", say) } if got := awaySaying(inventory.Plan{}); got != "" { t.Fatalf("1161/AC2: a plan that passed no machine says %q", got) } } // 1161/AC1: the gate does not wait for a machine passed as away, unless a send reached it; AC4: a machine heard is waited for. func TestAGateDoesNotWaitForAMachinePassedAsAway(t *testing.T) { p := inventory.Plan{Away: []string{"g14"}} none := &inventory.PlanModule{} if got := runningHeard(p, []string{"anchor", "g14"}, none); !slices.Equal(got, []string{"anchor"}) { t.Fatalf("1161/AC1: the gate waits on %v; want anchor alone", got) } sent := &inventory.PlanModule{Rest: map[string]inventory.SentDeclaration{"g14": {Digest: "d"}}} if got := runningHeard(p, []string{"anchor", "g14"}, sent); !slices.Equal(got, []string{"anchor", "g14"}) { t.Fatalf("1161/AC4: a machine a send reached is waited for: %v", got) } }