CI / test (push) Successful in 1m28s
Reported after watching a model appear in ctl models before it could answer anything. Checked: clients are not told early — /v1/models listed it only once a replica was ready, and the chat picker reads the same source. The operator view showing it is deliberate, because a model coming up is exactly what someone running the cluster wants to see. But the report pointed at something real. That view distinguished "a replica is coming up" from "nothing could be placed" by a parenthetical — "0/1 ready (1 total)" against "0/1 ready" — and those need opposite responses: one means wait, the other means look at explain-placement. On four models the difference is findable. On forty it is invisible, and a model that will never start reads exactly like one that is thirty seconds away. SERVING now answers the question that was being asked of the replica counts — can a client use this right now — and STATUS says which of ready, starting, not placed or stopped is the case. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
62 lines
2.1 KiB
Go
62 lines
2.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
|
|
)
|
|
|
|
func TestBarStaysWithinItsWidth(t *testing.T) {
|
|
// It is drawn from counts that can disagree briefly — a GPU freed between
|
|
// two reads — and a bar that overruns its column wrecks the table it is in.
|
|
for _, tc := range [][2]int{{0, 0}, {0, 8}, {8, 8}, {9, 8}, {100, 8}} {
|
|
got := bar(tc[0], tc[1])
|
|
if tc[1] == 0 {
|
|
if got != "" {
|
|
t.Errorf("bar(%d,%d) = %q, want empty for an empty class", tc[0], tc[1], got)
|
|
}
|
|
continue
|
|
}
|
|
if n := strings.Count(got, "#") + strings.Count(got, "."); n != 20 {
|
|
t.Errorf("bar(%d,%d) drew %d cells: %q", tc[0], tc[1], n, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIdleColumnDistinguishesUnknownFromIdle(t *testing.T) {
|
|
// Every replica looks unreported before its first request and after a
|
|
// router restart. Showing that as a very large duration would make an
|
|
// untouched fleet read as an abandoned one.
|
|
if got := idleColumn(-1); got != "-" {
|
|
t.Errorf("idleColumn(-1) = %q, want a dash", got)
|
|
}
|
|
if got := idleColumn(90); got != "1m30s" {
|
|
t.Errorf("idleColumn(90) = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestModelStatusSeparatesWaitingFromBroken(t *testing.T) {
|
|
// These used to differ by a parenthetical — "0/1 ready (1 total)" against
|
|
// "0/1 ready" — and they need opposite responses: one means wait, the other
|
|
// means look at explain-placement. On forty models that difference is
|
|
// invisible.
|
|
for _, tc := range []struct {
|
|
name string
|
|
view adminapi.ModelView
|
|
want string
|
|
}{
|
|
{"serving what it asked for", adminapi.ModelView{Min: 2, Ready: 2, Total: 2}, "ready"},
|
|
{"a replica is coming up", adminapi.ModelView{Min: 1, Ready: 0, Total: 1}, "starting"},
|
|
{"nothing could be placed", adminapi.ModelView{Min: 1, Ready: 0, Total: 0}, "not placed"},
|
|
{"deliberately not running", adminapi.ModelView{Min: 0, Ready: 0, Total: 0}, "stopped"},
|
|
{"short but rebuilding", adminapi.ModelView{Min: 2, Ready: 1, Total: 2}, "starting"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := modelStatus(tc.view); got != tc.want {
|
|
t.Errorf("modelStatus(%+v) = %q, want %q", tc.view, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|