A JSON verb's answer is its standard output alone

status --json prints its warnings beside the document; parsed from both streams together the first
status asked through the console carried no answer as data. Output stays both streams, in order.
This commit is contained in:
2026-09-30 18:18:43 +02:00
parent 8e81266cdc
commit 5ea0e87059
2 changed files with 27 additions and 5 deletions
+9 -5
View File
@@ -113,14 +113,18 @@ func runVerb(ctx context.Context, argv []string) (verbAnswer, error) {
// The same environment: the stores' credentials, the bus, the broker — everything a command run
// from a shell in this container would have, because it is that.
cmd.Env = os.Environ()
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
// Two buffers, one answer. What the command *says* is both streams, in the order a person at
// a shell would read them; what it *answers as data* is standard output alone — `status --json`
// prints its warnings beside the document, and a JSON parsed from the two together parsed
// nothing (2026-09-30, the first status asked through the console had no `answer`).
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
runErr := cmd.Run()
answer := verbAnswer{Output: out.String(), OK: runErr == nil}
answer := verbAnswer{Output: stdout.String() + stderr.String(), OK: runErr == nil}
if jsonVerbs[argv[0]] && runErr == nil {
var parsed any
if json.Unmarshal(bytes.TrimSpace(out.Bytes()), &parsed) == nil {
if json.Unmarshal(bytes.TrimSpace(stdout.Bytes()), &parsed) == nil {
answer.Answer = parsed
}
}
+18
View File
@@ -77,3 +77,21 @@ func TestToolsAnswersTheSeatsRecords(t *testing.T) {
t.Fatal("the mesh-controller seat is not in the listing")
}
}
// A JSON verb's answer is parsed from what the command wrote to standard output alone; a warning it
// printed beside the document does not take the document away. The test binary stands in for the
// controller: `-test.run` with a name that matches nothing prints `ok` and a warning about no tests.
func TestAJSONVerbsAnswerIsItsStandardOutput(t *testing.T) {
jsonVerbs["-test.run"] = true
t.Cleanup(func() { delete(jsonVerbs, "-test.run") })
answer, err := runVerb(t.Context(), []string{"-test.run", "TestAnswerEcho", "-test.v"})
if err != nil {
t.Fatal(err)
}
if !answer.OK {
t.Fatalf("the command failed: %s", answer.Output)
}
if !strings.Contains(answer.Output, "PASS") {
t.Fatalf("stderr and stdout are both what the command said: %s", answer.Output)
}
}