The account page (was "Your keys") shows the last thirty days of the person's own use - requests, tokens, spend and tokens per day - and, for each place they can spend, what they used there and a bar for every budget that applies: their own, a per-member one, or a project's, team's or organization's shared with others, named as such. Bars turn amber past four-fifths and red when spent. It sits under the keys now, above the password form. Spend is read from the usage table for the pool each limit counts against, from the start of its period. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
|
|
)
|
|
|
|
func TestAPersonSeesTheirUseAndWhatIsLeftOfTheirBudget(t *testing.T) {
|
|
ctx := context.Background()
|
|
st, err := store.OpenSQLite(ctx, filepath.Join(t.TempDir(), "s.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = st.Close() })
|
|
budget := int64(50e6)
|
|
st.SetPersonalDefaults(&store.Limits{Budget: &budget, BudgetPeriod: store.PeriodMonth})
|
|
// 45 of 50 units this month: past four-fifths, so the bar says so.
|
|
if err := st.WriteUsage(ctx, []store.Usage{
|
|
{At: time.Now(), KeyID: "session:ada", UserID: "ada", Model: "m", ServedModel: "m",
|
|
PromptTokens: 1200, CompletionTokens: 300, CostMicros: 45e6, Status: 200},
|
|
{At: time.Now(), KeyID: "session:bob", UserID: "bob", Model: "m", ServedModel: "m",
|
|
PromptTokens: 9, CompletionTokens: 9, CostMicros: 1e6, Status: 200},
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a := fakeAccounts{user: store.User{ID: "ada", Email: "ada@example.com"}}
|
|
p := NewAccountPages(a, st, nil, "v0", slog.New(slog.NewTextHandler(io.Discard, nil)))
|
|
mux := http.NewServeMux()
|
|
p.Register(mux)
|
|
req := httptest.NewRequest("GET", "/profile", nil)
|
|
req.AddCookie(&http.Cookie{Name: SessionCookie, Value: "good"})
|
|
rec := httptest.NewRecorder()
|
|
mux.ServeHTTP(rec, req)
|
|
body := rec.Body.String()
|
|
|
|
for _, want := range []string{
|
|
"Your use and limits",
|
|
// Ada's 1.5k tokens, and none of Bob's.
|
|
">1.5k</div>", "tokens · 30 days", "Tokens per day",
|
|
"Your budget, across everything you use", "<b>45.00</b> of 50.00 this month",
|
|
`class="budget near"`, "width: 90%",
|
|
} {
|
|
if !strings.Contains(body, want) {
|
|
t.Errorf("missing %q", want)
|
|
}
|
|
}
|
|
}
|