Files
llmgw/internal/store/keyusage_test.go
T
Ilker ManapandClaude Opus 5.5 9b663eb23c Name people and projects in usage reports, and total a usage legend
The cluster page's usage table showed session:usr-... and proj-... ids;
it now shows the person's email, whether it came through a key or the
chat page, and the project's path or "personal". Times read "3 hours
ago" rather than "3h7m25s ago", everywhere.

The usage page's legend gave each line's latest slice, which was 0
beside a table of hundreds; it gives the window's total, and the table's
numbers are right-aligned like everywhere else.

The PostgreSQL placeholder rewriting skips line comments. An apostrophe
in one opened a string that swallowed every placeholder after it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 22:37:21 +02:00

62 lines
1.7 KiB
Go

package store
import (
"context"
"path/filepath"
"testing"
"time"
)
// checkUsageNamesWhoAndWhere is run against both dialects: a report that
// named people by id and projects by id was a table nobody could read.
func checkUsageNamesWhoAndWhere(t *testing.T, s *DB) {
t.Helper()
ctx := context.Background()
must := func(err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
must(s.PutOrg(ctx, Org{ID: "o", Name: "Acme"}))
must(s.PutTeam(ctx, Team{ID: "t", OrgID: "o", Name: "ml"}))
must(s.PutProject(ctx, Project{ID: "p", TeamID: "t", Name: "training"}))
must(s.CreateUser(ctx, User{ID: "usr-1", Email: "ada@example.com", CreatedAt: time.Now()}))
now := time.Now()
must(s.WriteUsage(ctx, []Usage{
{At: now, KeyID: "session:usr-1", UserID: "usr-1", ProjectID: "p", Model: "m", ServedModel: "m", Status: 200},
{At: now, KeyID: "session:usr-1", UserID: "usr-1", Model: "m", ServedModel: "m", Status: 200},
}))
rows, err := s.UsageSince(ctx, now.Add(-time.Hour))
if err != nil {
t.Fatal(err)
}
if len(rows) != 2 {
t.Fatalf("expected two rows, got %+v", rows)
}
places := map[string]bool{}
for _, r := range rows {
if r.Email != "ada@example.com" || !r.Chat() {
t.Errorf("row %+v should name ada and read as the chat page", r)
}
places[r.ProjectPath] = true
}
if !places["Acme / ml / training"] || !places[""] {
t.Errorf("places = %v, expected the project's path and personal", places)
}
}
func TestUsageNamesWhoAndWhere(t *testing.T) {
s, err := OpenSQLite(context.Background(), filepath.Join(t.TempDir(), "u.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = s.Close() })
checkUsageNamesWhoAndWhere(t, s)
}
func TestPostgresUsageNamesWhoAndWhere(t *testing.T) {
checkUsageNamesWhoAndWhere(t, openPG(t))
}