Files
llmgw/internal/store/export_test.go
T
Ilker ManapandClaude Opus 5.5 eaea671f23 The usage sums and exports count pictures
The five-minute, hourly and daily sums gain images (migration 0042), and
the CSV and JSON exports a column for them: once request rows were past
their retention, an export said what pictures cost but not how many there
were. The pictures made before are added to the sums from their rows.

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

82 lines
3.0 KiB
Go

package store
import (
"testing"
"time"
)
func TestUsageIsExportedByPeriodAndWhatWasAskedFor(t *testing.T) {
db := capacityStore(t)
ctx := t.Context()
org, _ := db.CreateOrg(ctx, "acme")
team, _ := db.CreateTeam(ctx, org, "ml")
project, _ := db.CreateProject(ctx, team, "train")
day1 := time.Date(2026, 9, 30, 10, 0, 0, 0, time.UTC)
day2 := time.Date(2026, 10, 1, 9, 0, 0, 0, time.UTC)
var rows []Usage
for _, r := range []struct {
at time.Time
model string
p int64
}{{day1, "a", 10}, {day1, "b", 20}, {day2, "a", 5}, {day2.Add(time.Hour), "a", 5}} {
rows = append(rows, Usage{At: r.at, KeyID: "k", ProjectID: project, Model: r.model, ServedModel: r.model,
PromptTokens: r.p, CompletionTokens: 1, CostMicros: 100, Status: 200})
}
if err := db.WriteUsage(ctx, rows); err != nil {
t.Fatal(err)
}
from, to := day1.Add(-24*time.Hour), day2.Add(48*time.Hour)
byDay, err := db.UsageExport(ctx, from, to, "day", []string{"project", "model"})
if err != nil || len(byDay) != 3 {
t.Fatalf("%+v %v", byDay, err)
}
last := byDay[2]
if last.Project != "train" || last.Model != "a" || last.Prompt != 10 || last.Requests != 2 || !last.Period.Equal(time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)) {
t.Errorf("%+v", last)
}
byMonth, _ := db.UsageExport(ctx, from, to, "month", []string{"org"})
if len(byMonth) != 2 || byMonth[0].Org != "acme" || byMonth[0].Prompt != 30 || byMonth[1].CostMicros != 200 {
t.Errorf("by month: %+v", byMonth)
}
if _, err := db.UsageExport(ctx, from, to, "week", nil); err == nil {
t.Error("a week was taken")
}
if _, err := db.UsageExport(ctx, from, to, "day", []string{"planet"}); err == nil {
t.Error("an unknown dimension was taken")
}
}
func TestPicturesAreCountedInTheSumsAndTheExport(t *testing.T) {
// The request rows said how many pictures each made, and the sums did
// not: once the rows were past their retention, an export said what the
// pictures cost and not how many there were.
db := capacityStore(t)
ctx := t.Context()
at := time.Date(2026, 10, 10, 9, 0, 0, 0, time.UTC)
if err := db.WriteUsage(ctx, []Usage{
{At: at, KeyID: "k", Model: "flux", ServedModel: "flux", PromptTokens: 9, Images: 2, CostMicros: 40000, Status: 200},
{At: at.Add(time.Minute), KeyID: "k", Model: "flux", ServedModel: "flux", PromptTokens: 9, Images: 3, CostMicros: 60000, Status: 200},
{At: at.Add(2 * time.Minute), KeyID: "k", Model: "chat", ServedModel: "chat", PromptTokens: 9, Status: 200},
}); err != nil {
t.Fatal(err)
}
// Past their retention: only the sums are left.
if _, err := db.PruneUsage(ctx, at.Add(time.Hour)); err != nil {
t.Fatal(err)
}
for _, period := range []string{"hour", "day"} {
rows, err := db.UsageExport(ctx, at.Add(-24*time.Hour), at.Add(48*time.Hour), period, []string{"model"})
if err != nil {
t.Fatal(err)
}
got := map[string]int64{}
for _, r := range rows {
got[r.Model] += r.Images
}
if got["flux"] != 5 || got["chat"] != 0 {
t.Errorf("%s: pictures by model %v, want flux 5", period, got)
}
}
}