Files
llmgw/internal/cli/ctl_status_test.go
Ilker ManapandClaude Opus 5.5 6e815ca21a Draw the console's overview in its panel, not over the screen
The summary's GPU, fabric and idle tables were written to standard output
regardless of the writer they were given, so on a cluster with a GPU the
console printed the GPU table across its full screen every three seconds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 23:09:40 +02:00

87 lines
2.6 KiB
Go

package cli
import (
"bytes"
"io"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
"github.com/spf13/cobra"
)
func TestAQueuedChangeIsNotReportedAsAnError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusAccepted)
_, _ = w.Write([]byte(`{"queued":["r1"]}`))
}))
defer srv.Close()
var out struct {
Queued []string `json:"queued"`
}
if err := newCtlClient(srv.URL).post(t.Context(), "/api/v1/restart", []byte(`{}`), &out); err != nil {
t.Fatalf("202 read as a failure: %v", err)
}
if len(out.Queued) != 1 {
t.Errorf("the body of a 202 was not read: %+v", out)
}
}
func TestStatusSaysWhoLeadsTheStoreAndWhetherTheRestKeepUp(t *testing.T) {
render := func(s adminapi.Summary) string {
cmd := &cobra.Command{}
var b bytes.Buffer
cmd.SetOut(&b)
printSummary(cmd, s)
return b.String()
}
out := render(adminapi.Summary{Store: []adminapi.StoreMember{
{Name: "llmgw-ctl02", Role: "replica", State: "streaming", Lag: 2048},
{Name: "llmgw-pg01", Role: "leader", State: "running"},
}})
if !strings.Contains(out, "STORE llmgw-ctl02 streaming (2 KB behind), llmgw-pg01 leads") {
t.Errorf("status:\n%s", out)
}
out = render(adminapi.Summary{Store: []adminapi.StoreMember{{Name: "llmgw-pg01", Role: "replica", State: "stopped"}}})
if !strings.Contains(out, "NO LEADER") {
t.Errorf("a store with no leader was not called out:\n%s", out)
}
if out := render(adminapi.Summary{}); strings.Contains(out, "STORE") {
t.Error("a single database got a store line")
}
}
func TestTheSummaryIsWrittenWhereItIsToldNotToTheTerminal(t *testing.T) {
// The console draws the summary into its panel. Its GPU table went to
// the terminal instead, through the full screen, every three seconds —
// on a cluster with a GPU, which the test cluster did not have.
r, w, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
stdout := os.Stdout
os.Stdout = w
var b bytes.Buffer
cmd := &cobra.Command{}
cmd.SetOut(&b)
printSummary(cmd, adminapi.Summary{
GPUs: []adminapi.ClassUse{{Class: "6000-24g", Total: 1, Used: 1}},
Fabrics: []adminapi.FabricUse{{Fabric: "ib-a", Nodes: 2}},
IdleReplicas: []adminapi.IdleReplica{{ID: "r1", Model: "m", IdleSec: 3600, GPUs: 1}},
})
os.Stdout = stdout
_ = w.Close()
leaked, _ := io.ReadAll(r)
if len(leaked) > 0 {
t.Errorf("written to the terminal: %q", leaked)
}
for _, want := range []string{"6000-24g", "ib-a", "r1"} {
if !strings.Contains(b.String(), want) {
t.Errorf("the summary lacks %q:\n%s", want, b.String())
}
}
}