package link import ( "encoding/json" "sort" "strings" "testing" ) // The node-engine's request and the answer it hands mesh-cli hold these field names; the engine's side holds the // same list (mesh-host internal/meshcli, TestTheRequestToTheControllerKeepsItsFieldNames). func TestTheMeshCLIRequestAndAnswerKeepTheirFieldNames(t *testing.T) { body, _ := json.Marshal(CLIAsked{Line: []string{"status"}, Account: "a", UID: 1}) if got := keysIn(t, body); got != "account line uid" { t.Fatalf("the request's fields are %q", got) } body, _ = json.Marshal(CLIAnswer{Stdout: []byte("o"), Stderr: []byte("e"), Exit: 1, Terminal: true, Why: "w", Refused: "r", Cut: true}) if got := keysIn(t, body); got != "cut exit refused stderr stdout terminal why" { t.Fatalf("the answer's fields are %q", got) } } func keysIn(t *testing.T, body []byte) string { t.Helper() var m map[string]any if err := json.Unmarshal(body, &m); err != nil { t.Fatal(err) } var keys []string for k := range m { keys = append(keys, k) } sort.Strings(keys) return strings.Join(keys, " ") } // A node's mesh-cli subject names the node, and no other subject does. func TestTheMeshCLISubjectNamesItsNode(t *testing.T) { if node, ok := CLINode(CLISubject("laptop")); !ok || node != "laptop" { t.Fatalf("CLINode(%q) = %q %v", CLISubject("laptop"), node, ok) } for _, s := range []string{"mesh.control.laptop.report", "mesh.control..cli", "mesh.control.a.b.cli", "mesh.node.a.cli"} { if _, ok := CLINode(s); ok { t.Fatalf("%s was read as a mesh-cli subject", s) } } } // An answer larger than one bus message is cut to fit, and the cut is said. func TestALargeMeshCLIAnswerIsCutAndSaysSo(t *testing.T) { a := CLIAnswer{Stdout: []byte(strings.Repeat("o", 200000)), Stderr: []byte(strings.Repeat("e", 1000)), Why: "the terminal"} body := FitCLIAnswer(a, 64<<10) if len(body) > 64<<10 { t.Fatalf("the answer is %d bytes, over the bound", len(body)) } var got CLIAnswer if err := json.Unmarshal(body, &got); err != nil { t.Fatal(err) } if !got.Cut || got.Why != "the terminal" || len(got.Stdout) == 0 || string(got.Stderr) != strings.Repeat("e", 1000) { t.Fatalf("the cut answer is %+v", got) } if small := FitCLIAnswer(CLIAnswer{Stdout: []byte("ok")}, 64<<10); strings.Contains(string(small), `"cut"`) { t.Fatal("an answer that fits was said to be cut") } }