Files
gpt-load/internal/control/usage_time_range_test.go
tbphp d79180fda2 feat(subscriptions): refine credential trend insights (#684)
* feat(subscriptions): refine credential trend insights

* fix(classic): accept health identity fields (#682)

* fix(ui): standardize English unit abbreviations (#683)

* feat(subscriptions): refine credential trend insights

* fix(subscriptions): address trend review findings
2026-09-17 23:34:56 +08:00

94 lines
3.4 KiB
Go

package control
import (
"encoding/json"
"fmt"
"net/http"
"testing"
"time"
)
func TestUsageAPIExplicitTimeRange(t *testing.T) {
t.Parallel()
const hourMS int64 = 60 * 60 * 1000
const dayMS = 24 * hourMS
from := time.Date(2026, time.September, 8, 9, 15, 7, 123_000_000, time.UTC).UnixMilli()
for _, test := range []struct {
name string
span int64
width int64
grain string
}{
{"one millisecond", 1, 5 * 60 * 1000, "minute"},
{"one hour", hourMS, 5 * 60 * 1000, "minute"},
{"over one hour", hourMS + 1, 5 * 60 * 1000, "minute"},
{"six hours", 6 * hourMS, 5 * 60 * 1000, "minute"},
{"one day", dayMS, hourMS, "hour"},
{"three days", 3 * dayMS, 3 * hourMS, "hour"},
{"seven days", 7 * dayMS, 6 * hourMS, "hour"},
{"fifteen days", 15 * dayMS, 12 * hourMS, "hour"},
{"thirty days", 30 * dayMS, dayMS, "day"},
{"over thirty days", 30*dayMS + 1, 2 * dayMS, "day"},
{"one year", 365 * dayMS, 13 * dayMS, "day"},
{"future four hundred years", 400 * 365 * dayMS, 4867 * dayMS, "day"},
} {
t.Run(test.name, func(t *testing.T) {
reader := &recordingUsageStatReader{}
engine, _ := newUsageTestEngine(t, time.UnixMilli(from), reader)
query := fmt.Sprintf("from_ms=%d&to_ms=%d&group_id=7&channel_id=openai&credential_id=11&upstream_model=usage-model", from, from+test.span)
recorder := performUsageRequest(engine, "test-auth-key", query)
if recorder.Code != http.StatusOK {
t.Fatalf("explicit interval response = %d %s", recorder.Code, recorder.Body.String())
}
var envelope struct {
Data map[string]json.RawMessage `json:"data"`
}
if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
t.Fatal(err)
}
if _, exists := envelope.Data["range"]; exists {
t.Fatal("explicit interval response must not expose a preset range")
}
var data usageResponse
rawData, err := json.Marshal(envelope.Data)
if err != nil {
t.Fatal(err)
}
if err := json.Unmarshal(rawData, &data); err != nil {
t.Fatal(err)
}
if data.FromMS != from || data.ToMS != from+test.span ||
data.BucketWidthMS != test.width || string(data.Granularity) != test.grain {
t.Fatalf("explicit interval changed: %+v", data)
}
if len(reader.queries) != 1 {
t.Fatalf("reader calls = %d, want 1", len(reader.queries))
}
actual := reader.queries[0]
if actual.FromMS != from || actual.ToMS != from+test.span ||
actual.GroupID == nil || *actual.GroupID != 7 || actual.ChannelID != "openai" ||
actual.CredentialID == nil || *actual.CredentialID != 11 || actual.UpstreamModel != "usage-model" {
t.Fatalf("reader interval or filters changed: %+v", actual)
}
})
}
}
func TestUsageAPIRequiresExplicitTimeRange(t *testing.T) {
t.Parallel()
for _, query := range []string{
"", "from_ms=0", "to_ms=3600000", "range=1h", "range=24h&from_ms=0&to_ms=3600000",
"from_ms=0&to_ms=0", "from_ms=2&to_ms=1", "from_ms=-1&to_ms=1",
"from_ms=0&to_ms=9007199254740992", "from_ms=0&from_ms=1&to_ms=3600000",
} {
t.Run(query, func(t *testing.T) {
reader := &recordingUsageStatReader{}
engine, _ := newUsageTestEngine(t, time.Now(), reader)
recorder := performUsageRequest(engine, "test-auth-key", query)
if recorder.Code != http.StatusBadRequest || len(reader.queries) != 0 {
t.Fatalf("invalid interval response = %d %s, reader calls %d", recorder.Code, recorder.Body.String(), len(reader.queries))
}
})
}
}