package main import ( "context" "strings" "testing" "time" "github.com/novox/mesh-controller/internal/inventory" ) // **Every verb that repairs by hand takes a required why** (novox/hq to-be 45 §7): refused before // anything is done, through the seat, through `command`, and at a shell where nothing automated runs // the verb. func TestARepairByHandWithoutAReasonIsRefused(t *testing.T) { for _, c := range []struct { verb string args map[string]any }{ {"push", map[string]any{"node": "anchor"}}, {"push", map[string]any{}}, {"plans", map[string]any{"close": "plan-1"}}, {"plans", map[string]any{"stop": "plan-1"}}, {"hand-act", map[string]any{"what": "restarted the proxy", "cause": "proxy-stuck"}}, } { argv, err := argvFor(c.verb, c.args) if c.verb == "plans" && err == nil { // The seat composes the command line; the command refuses it, before opening anything. err = plansCommand(context.Background(), argv[1:]) } if err == nil || !strings.Contains(err.Error(), "why") { t.Errorf("%s %v was not refused for want of why: %v %v", c.verb, c.args, argv, err) } } for _, args := range [][]string{{"EVENTS", "controller"}} { if err := consumerReset(context.Background(), args); err == nil || !strings.Contains(err.Error(), "--why") { t.Errorf("consumer-reset without why: %v", err) } } if err := handActCommand(context.Background(), []string{"record", "restarted the proxy", "--cause", "x"}); err == nil || !strings.Contains(err.Error(), "--why") { t.Errorf("hand-act record without why: %v", err) } if err := handActCommand(context.Background(), []string{"record", "restarted the proxy", "--why", "it hung"}); err == nil || !strings.Contains(err.Error(), "--cause") { t.Errorf("hand-act record without a cause: %v", err) } } // With a reason, the seat passes it to the command, and a verb that only reads is not held to one. func TestARepairByHandCarriesItsReason(t *testing.T) { for _, c := range []struct { verb string args map[string]any want string }{ {"push", map[string]any{"node": "anchor", "why": "stuck", "cause": "sent-not-reported"}, "push anchor --wait 0s --why stuck --cause sent-not-reported"}, {"plans", map[string]any{"close": "plan-1", "why": "the report will not come"}, "plans close plan-1 --why the report will not come"}, {"plans", map[string]any{"retry": "plan-1"}, "plans retry plan-1"}, {"hand-act", map[string]any{"what": "restarted", "why": "hung", "cause": "proxy", "condition": "machine.a.silent"}, "hand-act record restarted --why hung --cause proxy --condition machine.a.silent"}, {"command", map[string]any{"command": "plans plan-1"}, "plans plan-1"}, } { argv, err := argvFor(c.verb, c.args) if err != nil || strings.Join(argv, " ") != c.want { t.Errorf("%s %v: %v %v, want %q", c.verb, c.args, argv, err, c.want) } } } // The summary of durations says, per kind and subject, what a bound would be set from. func TestDurationsAreSummarisedPerSubject(t *testing.T) { var ds []inventory.Duration for i := 1; i <= 10; i++ { ds = append(ds, inventory.Duration{Kind: inventory.DurationApply, Subject: "anchor", Took: time.Duration(i) * time.Second}) } ds = append(ds, inventory.Duration{Kind: inventory.DurationHeartbeatGap, Subject: "anchor", Took: time.Minute}) got := summarise(ds) if len(got) != 2 || got[0].Kind != inventory.DurationApply || got[0].Count != 10 || got[0].Max != "10s" || got[0].Median != "5s" || got[0].P90 != "9s" { t.Fatalf("%+v", got) } if !strings.Contains(got[1].Suggests, "3m0s") { t.Fatalf("a minute between words suggests %q", got[1].Suggests) } } // **A drill has its own verb** — `hand-act drill`, the seat's `drill` — and `hand-act record` refuses // the cause, so a repair cannot pass for a drill by the word it gives. func TestADrillIsRecordedThroughItsOwnVerb(t *testing.T) { err := handActCommand(context.Background(), []string{"record", "stopped searxng", "--why", "a test", "--cause", "drill"}) if err == nil || !strings.Contains(err.Error(), "hand-act drill") { t.Errorf("hand-act record --cause drill was not sent to the drill verb: %v", err) } if err := handActCommand(context.Background(), []string{"drill", "stopped searxng"}); err == nil || !strings.Contains(err.Error(), "--why") { t.Errorf("a drill without what it tests: %v", err) } if err := handActCommand(context.Background(), []string{"drill", "--why", "a test"}); err == nil || !strings.Contains(err.Error(), "hand-act drill