Files
llmgw/internal/web/admin_people_test.go
T
Ilker ManapandClaude Opus 5.5 9f479b9a70 Show each team's first-token and latency percentiles, errors and refusals
Percentiles are read from the histograms kept with the usage sums and shown
per group on the usage tab and in the people page's panels. Requests refused
by a limit are recorded as 429s against their owner, free of charge, so a team
hitting its limits shows as such. Usage can be grouped by model.

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

112 lines
4.3 KiB
Go

package web
import (
"io"
"log/slog"
"net/http"
"net/url"
"strings"
"testing"
"time"
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
)
// peoplePage mounts all three tabs, as the server does.
func peoplePage(t *testing.T, q *fakeQuotas, u *fakeScopeSeries) *http.ServeMux {
t.Helper()
a := fakeAccounts{user: store.User{ID: "u1", Email: "a@example.com", IsAdmin: true}}
p := NewAccountPages(a, nil, nil, "v0", slog.New(slog.NewTextHandler(io.Discard, nil)))
mux := http.NewServeMux()
p.RegisterAdminUsers(mux, &fakeAdmin{orgs: q.orgs})
p.RegisterAdminQuotas(mux, q, pricedYes{})
p.RegisterAdminUsage(mux, u, pricedYes{})
return mux
}
func TestABranchChosenInTheTreeShowsItsLimitsAndUseTogether(t *testing.T) {
// People, their limits and their use were three pages: a team's members
// on one, its quota on another, its spend on a third.
q := oneTeam()
rpm := 60
q.limits["org:org-1"] = store.Limits{Scope: store.ScopeOrg, ScopeID: "org-1", RPM: &rpm}
u := &fakeScopeSeries{byGroup: map[store.Grouping][]store.UsageSeries{
store.GroupByOrg: {{Grouping: store.GroupByOrg, ID: "org-1", Name: "Scania", Requests: 1234,
Buckets: []store.Bucket{{Start: time.Now().Add(-time.Hour), Requests: 1234}}}},
}}
body := strings.Join(strings.Fields(
mirrorGet(t, peoplePage(t, q, u), "/admin/users?sel=org:org-1").Body.String()), " ")
for _, want := range []string{
`class="people-detail"`, "<h2>Scania</h2>",
"<dt>Requests/min</dt><dd>60</dd>", // its own limit
"1.2k requests", // its use over the week
`name="sel" value="org:org-1"`, // changing it comes back here
`aria-current="page">Organizations &amp; people`,
} {
if !strings.Contains(body, want) {
t.Errorf("the panel lacks %q", want)
}
}
if u.asked[len(u.asked)-1] != store.GroupByOrg {
t.Errorf("use was read by %v, not by organization", u.asked)
}
}
func TestAChangeMadeInAPanelComesBackToThePanel(t *testing.T) {
q := oneTeam()
body := mirrorPost(t, peoplePage(t, q, &fakeScopeSeries{}), "/admin/quotas", url.Values{
"csrf": {"tok"}, "scope": {"org"}, "id": {"org-1"}, "rpm": {"30"},
"tab": {"people"}, "sel": {"org:org-1"},
}).Body.String()
if len(q.put) != 1 || *q.put[0].RPM != 30 {
t.Fatalf("the limit was not saved: %+v", q.put)
}
if !strings.Contains(body, `class="people-detail"`) || !strings.Contains(body, "rpm 30") {
t.Error("saving from the panel did not come back to it with the result")
}
}
func TestEachOldAddressOpensItsTab(t *testing.T) {
mux := peoplePage(t, oneTeam(), &fakeScopeSeries{})
for path, tab := range map[string]string{
"/admin/users": "Organizations &amp; people", "/admin/quotas": "Limits", "/admin/usage": "Usage",
} {
body := mirrorGet(t, mux, path).Body.String()
if !strings.Contains(body, `aria-current="page">`+tab) {
t.Errorf("%s does not open the %s tab", path, tab)
}
}
}
func TestSomethingNotInTheTreeOpensNoPanel(t *testing.T) {
body := mirrorGet(t, peoplePage(t, oneTeam(), &fakeScopeSeries{}), "/admin/users?sel=org:gone").Body.String()
if strings.Contains(body, `class="people-detail"`) {
t.Error("a panel opened for an organization that does not exist")
}
}
func TestHowRequestsFaredIsShownBesideWhatTheyCost(t *testing.T) {
stats := map[string]store.GroupStats{"org-1": {ID: "org-1", Requests: 200, Errors: 30, Limited: 25,
TTFT: store.Quantiles{P50: 180, P95: 900, P99: 2400, N: 150},
Latency: store.Quantiles{P50: 3000, P95: 8000, P99: 120000, N: 200, Over: true}}}
u := &fakeScopeSeries{stats: stats, byGroup: map[store.Grouping][]store.UsageSeries{
store.GroupByOrg: {{Grouping: store.GroupByOrg, ID: "org-1", Name: "Scania", Requests: 200,
Buckets: []store.Bucket{{Start: time.Now().Add(-time.Hour), Requests: 200}}}},
}}
mux := peoplePage(t, oneTeam(), u)
table := strings.Join(strings.Fields(mirrorGet(t, mux, "/admin/usage?by=org").Body.String()), " ")
for _, want := range []string{"15.0%", ">25<", "180 ms / 900 ms", "8.0 s"} {
if !strings.Contains(table, want) {
t.Errorf("the usage table lacks %q", want)
}
}
panel := strings.Join(strings.Fields(mirrorGet(t, mux, "/admin/users?sel=org:org-1").Body.String()), " ")
for _, want := range []string{"<dt>Refused by a limit</dt>", "p95 900 ms", "p99 &gt; 120 s"} {
if !strings.Contains(panel, want) {
t.Errorf("the panel lacks %q", want)
}
}
}