package main import ( "bytes" "context" "fmt" "net/http" "net/http/httptest" "strings" "testing" ) // TestPrintStatusInstancesLabelsPlatformAndStatesItsLimits is the CLI half of // what the console door promises. Two things have to survive rendering. // // A row that matched no route is the box's own overhead — the console, the // agent, a system unit — and it prints under its unit name and the word // (platform) rather than as two blank cells a reader would take for missing // data. // // And the table is followed, every time, by the two ways it misleads: a // hibernating instance has no process and so no reading, and the readings are // fleet-wide while the account each is attributed to comes from the console's // own box's registry. Neither caveat is conditional, because both are ways a // SHORT list reads as a complete one, and short is exactly when nobody thinks // to ask. func TestPrintStatusInstancesLabelsPlatformAndStatesItsLimits(t *testing.T) { rows := []statusInstanceRow{ {Box: "box-a", Host: "app.example.com", Account: "cdef", App: "widgets", CPU: f64(0.25), Mem: i64(1 << 20)}, {Box: "box-a", Unit: "console.service", Account: "bab", Platform: true}, } var buf bytes.Buffer printStatusInstances(&buf, rows, "") out := buf.String() for _, want := range []string{ "app.example.com", "cdef", "widgets", "0.250", "1MB", "console.service", "(platform)", "awake instances only", "console's own box's route registry", } { if !strings.Contains(out, want) { t.Errorf("missing %q in:\n%s", want, out) } } } // TestPrintStatusLayoutRendersSortedAndMarksStale pins the CLI table for // `carlos status --layout` (R21): the approved heading, byte for byte; rows // sorted by box then host regardless of the order the door answered in; and // a stale box's name suffixed with the approved stale marker. func TestPrintStatusLayoutRendersSortedAndMarksStale(t *testing.T) { boxes := []statusLayoutBox{ {Box: "zeta", Mode: "flat", Stale: false, Rows: []statusLayoutRow{ {Host: "z.example.com", Layout: "flat"}, }}, {Box: "alpha", Mode: "nested", Stale: true, Rows: []statusLayoutRow{ {Host: "b.example.com", Layout: "foreign", Reason: "db and socket are neither default"}, {Host: "a.example.com", Layout: "nested"}, }}, } var buf bytes.Buffer printStatusLayout(&buf, boxes) out := buf.String() if !strings.Contains(out, "BOX HOST LAYOUT REASON") { t.Fatalf("missing the approved heading:\n%s", out) } if !strings.Contains(out, "alpha (stale)") { t.Errorf("stale box not marked:\n%s", out) } if strings.Contains(out, "zeta (stale)") { t.Errorf("fresh box marked stale:\n%s", out) } // Sorted by box then host: alpha's two rows (host-sorted) come before // zeta's, regardless of the door's own order. aIdx := strings.Index(out, "a.example.com") bIdx := strings.Index(out, "b.example.com") zIdx := strings.Index(out, "z.example.com") if aIdx < 0 || bIdx < 0 || zIdx < 0 || !(aIdx < bIdx && bIdx < zIdx) { t.Fatalf("rows not sorted box-then-host:\n%s", out) } if !strings.Contains(out, "db and socket are neither default") { t.Errorf("missing the foreign row's reason:\n%s", out) } if strings.Contains(out, "WARNING") { t.Errorf("no box is mixed, yet a warning printed:\n%s", out) } } // A box the door marks mixed (nested rows beside flat ones) gets a warning // after the table naming it: on that box the nested rows are not isolated // from the flat tenant that still shares the agent's uid. func TestPrintStatusLayoutWarnsOnAMixedBox(t *testing.T) { boxes := []statusLayoutBox{ {Box: "kass-1", Mode: "nested", Mixed: true, Rows: []statusLayoutRow{ {Host: "a.example.com", Layout: "nested"}, {Host: "b.example.com", Layout: "flat", Reason: "awake (stopped for the move in 40m0s unless it sleeps first)"}, }}, {Box: "kass-2", Mode: "nested", Rows: []statusLayoutRow{{Host: "c.example.com", Layout: "nested"}}}, } var buf bytes.Buffer printStatusLayout(&buf, boxes) out := buf.String() if !strings.Contains(out, "WARNING: kass-1 runs nested instances beside flat, foreign or external ones") { t.Fatalf("mixed box not warned about:\n%s", out) } if strings.Contains(out, "WARNING: kass-2") { t.Errorf("an all-nested box warned about:\n%s", out) } } // TestStatusLayoutListTranslatesNotFound pins the approved 404 message // (cli.status.layout.notfound), byte for byte — the same "not found" this // console gives a non-operator or predates the door with, which is why the // message covers both readings. func TestStatusLayoutListTranslatesNotFound(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) })) defer ts.Close() _, err := newTestSession(ts.URL).statusLayoutList(context.Background()) if err == nil { t.Fatal("want an error on 404") } want := "not found. this needs the fleet-operator bit on your account, or this console predates `carlos status --layout` (deploy a console built from current main)" if err.Error() != want { t.Fatalf("error = %q, want %q", err.Error(), want) } } // TestStatusLayoutListDecodesBoxes pins the fetch half: the door's // {"boxes":[...]} shape decodes into statusLayoutBox/statusLayoutRow. func TestStatusLayoutListDecodesBoxes(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/api/cli/status/layout" { t.Errorf("path = %s", r.URL.Path) } w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, `{"boxes":[{"box":"ie","mode":"nested","stale":false,"rows":[{"host":"h.example.com","layout":"nested"}]}]}`) })) defer ts.Close() boxes, err := newTestSession(ts.URL).statusLayoutList(context.Background()) if err != nil { t.Fatal(err) } if len(boxes) != 1 || boxes[0].Box != "ie" || boxes[0].Mode != "nested" || boxes[0].Stale || len(boxes[0].Rows) != 1 || boxes[0].Rows[0].Host != "h.example.com" || boxes[0].Rows[0].Layout != "nested" { t.Fatalf("boxes = %+v", boxes) } } // Boxes that disagree about their mode get one warning naming both // sides; a stale box is left out of it, and agreement gets none. func TestPrintStatusLayoutWarnsWhenBoxesDisagreeAboutTheMode(t *testing.T) { boxes := []statusLayoutBox{ {Box: "kass-1", Mode: "nested", Rows: []statusLayoutRow{{Host: "a.example.com", Layout: "nested"}}}, {Box: "kass-2", Mode: "none", Rows: []statusLayoutRow{{Host: "b.example.com", Layout: "flat"}}}, {Box: "kass-3", Mode: "flat", Rows: []statusLayoutRow{{Host: "c.example.com", Layout: "flat"}}}, {Box: "kass-4", Mode: "none", Stale: true, Rows: []statusLayoutRow{{Host: "d.example.com", Layout: "flat"}}}, } var buf bytes.Buffer printStatusLayout(&buf, boxes) out := buf.String() want := "WARNING: kass-1 is nested while kass-2 and kass-3 are not: an instance placed or moved onto a box that is not nested starts flat there." if !strings.Contains(out, want) { t.Fatalf("disagreeing boxes not warned about:\n%s", out) } if strings.Contains(out, "kass-4") && strings.Contains(out[strings.Index(out, "WARNING"):], "kass-4") { t.Errorf("a stale box was counted:\n%s", out) } buf.Reset() printStatusLayout(&buf, boxes[:1]) if strings.Contains(buf.String(), "WARNING") { t.Errorf("an agreeing fleet warned:\n%s", buf.String()) } } // A box nested by default is marked on its name; a box the default has not // reached says why under the table; a stale box's reason is not repeated. func TestPrintStatusLayoutSaysNestedByDefaultAndWhyNot(t *testing.T) { boxes := []statusLayoutBox{ {Box: "kass-1", Mode: "nested", Default: true, Rows: []statusLayoutRow{{Host: "a.example.com", Layout: "nested"}}}, {Box: "kass-2", Mode: "none", DefaultBlocked: "isolation not ready: probe: pid1 fail", Rows: []statusLayoutRow{{Host: "b.example.com", Layout: "flat"}}}, {Box: "kass-3", Mode: "none", Stale: true, DefaultBlocked: "no activator is armed on this box, so nothing could wake nested", Rows: []statusLayoutRow{{Host: "c.example.com", Layout: "flat"}}}, } var buf bytes.Buffer printStatusLayout(&buf, boxes) out := buf.String() if !strings.Contains(out, "kass-1 (nested by default) a.example.com nested") { t.Errorf("nested by default not marked on the box:\n%s", out) } if !strings.Contains(out, "kass-2 is not nested by default: isolation not ready: probe: pid1 fail") { t.Errorf("blocked reason missing:\n%s", out) } if strings.Contains(out, "kass-3 is not nested by default") { t.Errorf("a stale box's reason was repeated:\n%s", out) } }