Spaces:
Running
Running
File size: 4,149 Bytes
b034029 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | package api
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"cpa-usage-keeper/internal/cpa"
"cpa-usage-keeper/internal/redact"
"cpa-usage-keeper/internal/service"
)
type usageAnalysisStub struct {
analysis *service.UsageAnalysisSnapshot
err error
lastFilter service.UsageFilter
analysisCalls int
}
func (s *usageAnalysisStub) GetUsageWithFilter(context.Context, service.UsageFilter) (*cpa.StatisticsSnapshot, error) {
return nil, nil
}
func (s *usageAnalysisStub) GetUsageOverview(context.Context, service.UsageFilter) (*service.UsageOverviewSnapshot, error) {
return nil, nil
}
func (s *usageAnalysisStub) ListUsageEvents(context.Context, service.UsageFilter) (*service.UsageEventsPage, error) {
return nil, nil
}
func (s *usageAnalysisStub) ListUsageEventFilterOptions(context.Context, service.UsageFilter) (*service.UsageEventFilterOptions, error) {
return nil, nil
}
func (s *usageAnalysisStub) ListUsageCredentialStats(context.Context, service.UsageFilter) ([]service.UsageCredentialStat, error) {
return nil, nil
}
func (s *usageAnalysisStub) GetUsageAnalysis(_ context.Context, filter service.UsageFilter) (*service.UsageAnalysisSnapshot, error) {
s.lastFilter = filter
s.analysisCalls++
return s.analysis, s.err
}
func TestUsageAnalysisReturnsAggregatedRows(t *testing.T) {
provider := &usageAnalysisStub{analysis: &service.UsageAnalysisSnapshot{
APIs: []service.UsageAnalysisAPIStat{{
APIKey: "provider-a",
DisplayName: "provider-a",
TotalRequests: 2,
SuccessCount: 1,
FailureCount: 1,
TotalTokens: 42,
Models: []service.UsageAnalysisModelStat{{
Model: "claude-sonnet",
TotalRequests: 2,
SuccessCount: 1,
FailureCount: 1,
InputTokens: 30,
OutputTokens: 9,
ReasoningTokens: 2,
CachedTokens: 1,
TotalTokens: 42,
TotalLatencyMS: 350,
LatencySampleCount: 2,
}},
}},
Models: []service.UsageAnalysisModelStat{{
Model: "claude-sonnet",
TotalRequests: 2,
SuccessCount: 1,
FailureCount: 1,
InputTokens: 30,
OutputTokens: 9,
ReasoningTokens: 2,
CachedTokens: 1,
TotalTokens: 42,
TotalLatencyMS: 350,
LatencySampleCount: 2,
}},
}}
router := NewRouter(nil, nil, provider, nil, AuthConfig{}, nil, "")
req := httptest.NewRequest(http.MethodGet, "/api/v1/usage/analysis?range=24h", nil)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
if resp.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d", resp.Code)
}
body := resp.Body.String()
if !contains(body, `"apis":[`) || !contains(body, `"models":[`) {
t.Fatalf("unexpected response body: %s", body)
}
if !contains(body, `"display_name":"prov**er-a"`) {
t.Fatalf("expected display name in response body: %s", body)
}
if !contains(body, `"api_key":"`+redact.APIAlias("provider-a")+`"`) {
t.Fatalf("expected redacted api key alias in response body: %s", body)
}
if !contains(body, `"model":"claude-sonnet"`) || !contains(body, `"latency_sample_count":2`) || !contains(body, `"total_latency_ms":350`) {
t.Fatalf("expected model latency aggregates in response body: %s", body)
}
if provider.analysisCalls != 1 {
t.Fatalf("expected GetUsageAnalysis to be called once, got %d", provider.analysisCalls)
}
if provider.lastFilter.Range != "24h" {
t.Fatalf("expected range to be passed through, got %+v", provider.lastFilter)
}
if provider.lastFilter.StartTime == nil || provider.lastFilter.EndTime == nil {
t.Fatalf("expected resolved time bounds in filter, got %+v", provider.lastFilter)
}
}
func TestUsageAnalysisRequiresAuthWhenEnabled(t *testing.T) {
router := NewRouter(nil, nil, &usageAnalysisStub{}, nil, AuthConfig{Enabled: true, LoginPassword: "secret", SessionTTL: time.Hour}, nil, "")
req := httptest.NewRequest(http.MethodGet, "/api/v1/usage/analysis", nil)
resp := httptest.NewRecorder()
router.ServeHTTP(resp, req)
if resp.Code != http.StatusUnauthorized {
t.Fatalf("expected status 401, got %d", resp.Code)
}
}
|