mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-26 16:19:02 +00:00
528 lines
19 KiB
Go
528 lines
19 KiB
Go
package caps
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/nextlevelbuilder/goclaw/internal/providers"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
func TestShouldEnforceProvider(t *testing.T) {
|
|
cases := []struct {
|
|
providerType string
|
|
hasKey bool
|
|
want bool
|
|
}{
|
|
{store.ProviderChatGPTOAuth, false, false},
|
|
{store.ProviderClaudeCLI, false, false},
|
|
{store.ProviderBailian, false, false},
|
|
{store.ProviderOllama, false, false},
|
|
{store.ProviderACP, false, false},
|
|
{store.ProviderOpenAICompat, true, true},
|
|
{store.ProviderOpenRouter, true, true},
|
|
{store.ProviderOpenRouter, false, false},
|
|
}
|
|
for _, tc := range cases {
|
|
if got := ShouldEnforceProvider(tc.providerType, tc.hasKey); got != tc.want {
|
|
t.Fatalf("ShouldEnforceProvider(%q,%v) = %v, want %v", tc.providerType, tc.hasKey, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPreflightTokenOnlyCapDoesNotRequirePricing(t *testing.T) {
|
|
providerID := uuid.New()
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxTokens: int64Ptr(1000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{policies: []store.UsageCapPolicy{policy}, resolveErr: sql.ErrNoRows}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: providerID},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "missing/model",
|
|
ReservationKey: "token-only", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
if reservation == nil || reservation.skipped {
|
|
t.Fatalf("Preflight skipped token-only policy")
|
|
}
|
|
if usageStore.resolveCalls != 0 {
|
|
t.Fatalf("ResolvePricing called %d time(s), want 0", usageStore.resolveCalls)
|
|
}
|
|
if usageStore.reserved.EstimatedCostMicros != 0 {
|
|
t.Fatalf("EstimatedCostMicros = %d, want 0", usageStore.reserved.EstimatedCostMicros)
|
|
}
|
|
metadata := reservation.TraceMetadata()
|
|
if metadata.Decision != store.UsageCapEventAllow {
|
|
t.Fatalf("Decision = %q, want allow", metadata.Decision)
|
|
}
|
|
if metadata.PolicyCount != 1 {
|
|
t.Fatalf("PolicyCount = %d, want 1", metadata.PolicyCount)
|
|
}
|
|
}
|
|
|
|
func TestPreflightIncludesRequestPricingWhenConfigured(t *testing.T) {
|
|
zero := "0"
|
|
requestPrice := "0.01"
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxCostMicros: int64Ptr(20_000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{
|
|
policies: []store.UsageCapPolicy{policy},
|
|
resolved: &store.ResolvedUsagePricing{
|
|
ModelID: "priced/model",
|
|
Source: "catalog",
|
|
Pricing: store.UsagePricingFields{Input: &zero, Output: &zero, Request: &requestPrice},
|
|
},
|
|
}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}, requireTenant: policy.TenantID}
|
|
svc := NewService(usageStore, providerStore)
|
|
|
|
_, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "priced/model",
|
|
ReservationKey: "request-fee", Messages: []providers.Message{{Role: "user", Content: "abcd"}},
|
|
MaxOutputTokens: 1,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
if got := usageStore.reserved.EstimatedCostMicros; got != 10_000 {
|
|
t.Fatalf("EstimatedCostMicros = %d, want 10000", got)
|
|
}
|
|
}
|
|
|
|
func TestPreflightFallsBackToMasterProviderMetadata(t *testing.T) {
|
|
tenantID := uuid.New()
|
|
masterProviderID := uuid.New()
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: tenantID, MaxTokens: int64Ptr(1000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{policies: []store.UsageCapPolicy{policy}}
|
|
providerStore := &fakeProviderStore{
|
|
masterProvider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: masterProviderID},
|
|
TenantID: store.MasterTenantID,
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
},
|
|
}
|
|
svc := NewService(usageStore, providerStore)
|
|
|
|
reservation, err := svc.Preflight(store.WithTenantID(context.Background(), tenantID), Request{
|
|
TenantID: tenantID, ProviderName: "openrouter", ModelID: "openai/gpt-test",
|
|
ReservationKey: "master-provider", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
if reservation == nil || reservation.skipped {
|
|
t.Fatal("Preflight skipped master provider fallback")
|
|
}
|
|
if usageStore.reserved.ProviderID != masterProviderID {
|
|
t.Fatalf("ProviderID = %s, want %s", usageStore.reserved.ProviderID, masterProviderID)
|
|
}
|
|
}
|
|
|
|
func TestReservationReconcileUsesDetachedContext(t *testing.T) {
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxTokens: int64Ptr(1000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{policies: []store.UsageCapPolicy{policy}}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "token/model",
|
|
ReservationKey: "reconcile", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
reservation.Reconcile(ctx, &providers.ChatResponse{Usage: &providers.Usage{PromptTokens: 2, CompletionTokens: 3}}, nil)
|
|
|
|
if usageStore.reconcileCalls != 1 {
|
|
t.Fatalf("ReconcileUsage calls = %d, want 1", usageStore.reconcileCalls)
|
|
}
|
|
if usageStore.reconcileCtxCanceled {
|
|
t.Fatal("ReconcileUsage received canceled context")
|
|
}
|
|
}
|
|
|
|
func TestReservationReconcileStreamKeepsEstimateAfterPartialError(t *testing.T) {
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxTokens: int64Ptr(1000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{policies: []store.UsageCapPolicy{policy}}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "token/model",
|
|
ReservationKey: "partial-stream", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
|
|
reservation.ReconcileStream(context.Background(), nil, context.Canceled, true)
|
|
|
|
if usageStore.reconciled.ActualTokens == 0 {
|
|
t.Fatal("ReconcileStream zeroed actual tokens after partial stream error")
|
|
}
|
|
if usageStore.reconciled.Status != "failed" {
|
|
t.Fatalf("Status = %q, want failed", usageStore.reconciled.Status)
|
|
}
|
|
}
|
|
|
|
func TestReservationReconcileIgnoresUnpricedRequestCount(t *testing.T) {
|
|
tokenPrice := "0.000001"
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxCostMicros: int64Ptr(1_000_000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{
|
|
policies: []store.UsageCapPolicy{policy},
|
|
resolved: &store.ResolvedUsagePricing{
|
|
ModelID: "priced/model",
|
|
Source: "catalog",
|
|
Pricing: store.UsagePricingFields{Input: &tokenPrice, Output: &tokenPrice},
|
|
},
|
|
}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "priced/model",
|
|
ReservationKey: "unpriced-request", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 100,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Preflight returned error: %v", err)
|
|
}
|
|
|
|
reservation.Reconcile(context.Background(), &providers.ChatResponse{Usage: &providers.Usage{
|
|
PromptTokens: 2,
|
|
CompletionTokens: 3,
|
|
RequestCount: 1,
|
|
}}, nil)
|
|
|
|
if usageStore.reconciled.ActualCostMicros != 5 {
|
|
t.Fatalf("ActualCostMicros = %d, want 5", usageStore.reconciled.ActualCostMicros)
|
|
}
|
|
metadata := reservation.TraceMetadata()
|
|
if metadata.ActualTokens != 5 {
|
|
t.Fatalf("ActualTokens = %d, want 5", metadata.ActualTokens)
|
|
}
|
|
if metadata.ReconcileStatus != "reconciled" {
|
|
t.Fatalf("ReconcileStatus = %q, want reconciled", metadata.ReconcileStatus)
|
|
}
|
|
}
|
|
|
|
func TestPreflightTraceMetadataForCapExceeded(t *testing.T) {
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxTokens: int64Ptr(10), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{
|
|
policies: []store.UsageCapPolicy{policy},
|
|
reserveErr: &store.UsageCapExceededError{PolicyID: policy.ID, Reason: "token_cap_exceeded"},
|
|
}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "token/model",
|
|
ReservationKey: "blocked", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if !errors.Is(err, ErrCapExceeded) {
|
|
t.Fatalf("Preflight error = %v, want ErrCapExceeded", err)
|
|
}
|
|
metadata := reservation.TraceMetadata()
|
|
if metadata.Decision != store.UsageCapEventBlock {
|
|
t.Fatalf("Decision = %q, want block", metadata.Decision)
|
|
}
|
|
if metadata.Reason != "token_cap_exceeded" {
|
|
t.Fatalf("Reason = %q, want token_cap_exceeded", metadata.Reason)
|
|
}
|
|
if metadata.ReservationKey != "blocked" {
|
|
t.Fatalf("ReservationKey = %q, want blocked", metadata.ReservationKey)
|
|
}
|
|
if len(metadata.PolicyIDs) != 1 || metadata.PolicyIDs[0] != policy.ID.String() {
|
|
t.Fatalf("PolicyIDs = %v, want [%s]", metadata.PolicyIDs, policy.ID)
|
|
}
|
|
}
|
|
|
|
func TestPreflightRecordsPricingUnknownBlockEvent(t *testing.T) {
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxCostMicros: int64Ptr(1000), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{
|
|
policies: []store.UsageCapPolicy{policy},
|
|
resolveErr: sql.ErrNoRows,
|
|
}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}}
|
|
svc := NewService(usageStore, providerStore)
|
|
|
|
reservation, err := svc.Preflight(context.Background(), Request{
|
|
TenantID: policy.TenantID, ProviderName: "openrouter", ModelID: "missing/model",
|
|
ReservationKey: "pricing-missing", Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
MaxOutputTokens: 10,
|
|
})
|
|
if !errors.Is(err, ErrPricingUnknown) {
|
|
t.Fatalf("Preflight error = %v, want ErrPricingUnknown", err)
|
|
}
|
|
if reservation == nil {
|
|
t.Fatal("Preflight returned nil reservation")
|
|
}
|
|
metadata := reservation.TraceMetadata()
|
|
if metadata.Reason != "pricing_unknown" {
|
|
t.Fatalf("reservation metadata = %+v, want pricing_unknown", metadata)
|
|
}
|
|
if len(usageStore.events) != 1 {
|
|
t.Fatalf("events = %d, want 1", len(usageStore.events))
|
|
}
|
|
event := usageStore.events[0]
|
|
if event.Decision != store.UsageCapEventBlock || event.Reason != "pricing_unknown" {
|
|
t.Fatalf("event decision/reason = %q/%q, want block/pricing_unknown", event.Decision, event.Reason)
|
|
}
|
|
if event.ReservationKey != "pricing-missing" {
|
|
t.Fatalf("event reservation_key = %q, want pricing-missing", event.ReservationKey)
|
|
}
|
|
}
|
|
|
|
func TestServiceChatBlocksBeforeProviderCall(t *testing.T) {
|
|
policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: uuid.New(), MaxTokens: int64Ptr(10), Enabled: true}
|
|
usageStore := &fakeUsageCapStore{
|
|
policies: []store.UsageCapPolicy{policy},
|
|
reserveErr: &store.UsageCapExceededError{PolicyID: policy.ID, Reason: "token_cap_exceeded"},
|
|
}
|
|
providerStore := &fakeProviderStore{provider: &store.LLMProviderData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "openrouter",
|
|
ProviderType: store.ProviderOpenRouter,
|
|
APIKey: "sk-test",
|
|
}, requireTenant: policy.TenantID}
|
|
svc := NewService(usageStore, providerStore)
|
|
provider := &fakeChatProvider{name: "openrouter", model: "token/model"}
|
|
|
|
_, err := svc.Chat(context.Background(), provider, providers.ChatRequest{
|
|
Messages: []providers.Message{{Role: "user", Content: "hello"}},
|
|
Model: "token/model",
|
|
Options: map[string]any{providers.OptMaxTokens: 20},
|
|
}, ChatOptions{
|
|
TenantID: policy.TenantID,
|
|
ProviderName: "openrouter",
|
|
Purpose: "test-block",
|
|
})
|
|
if !errors.Is(err, ErrCapExceeded) {
|
|
t.Fatalf("Chat error = %v, want ErrCapExceeded", err)
|
|
}
|
|
if provider.calls != 0 {
|
|
t.Fatalf("provider calls = %d, want 0", provider.calls)
|
|
}
|
|
}
|
|
|
|
func TestMergeTraceMetadataPreservesExistingSections(t *testing.T) {
|
|
existing := json.RawMessage(`{"thinking":{"effort":"high"}}`)
|
|
merged := MergeTraceMetadata(existing, []TraceMetadata{{
|
|
Decision: store.UsageCapEventAllow,
|
|
Reason: "reserved",
|
|
ModelID: "openai/gpt-test",
|
|
}})
|
|
|
|
var payload map[string]json.RawMessage
|
|
if err := json.Unmarshal(merged, &payload); err != nil {
|
|
t.Fatalf("Unmarshal merged metadata: %v", err)
|
|
}
|
|
if len(payload["thinking"]) == 0 {
|
|
t.Fatal("existing thinking metadata was removed")
|
|
}
|
|
var usagePayload struct {
|
|
Attempts []TraceMetadata `json:"attempts"`
|
|
}
|
|
if err := json.Unmarshal(payload[TraceMetadataKey], &usagePayload); err != nil {
|
|
t.Fatalf("Unmarshal usage caps metadata: %v", err)
|
|
}
|
|
if len(usagePayload.Attempts) != 1 || usagePayload.Attempts[0].Decision != store.UsageCapEventAllow {
|
|
t.Fatalf("usage cap attempts = %+v, want one allow attempt", usagePayload.Attempts)
|
|
}
|
|
}
|
|
|
|
func TestCountImagesOnlyCountsImageMIMEs(t *testing.T) {
|
|
messages := []providers.Message{{
|
|
Role: "user",
|
|
Images: []providers.ImageContent{
|
|
{MimeType: "image/png"},
|
|
{MimeType: "application/pdf"},
|
|
{MimeType: "video/mp4"},
|
|
},
|
|
}}
|
|
if got := CountImages(messages); got != 1 {
|
|
t.Fatalf("CountImages = %d, want 1", got)
|
|
}
|
|
}
|
|
|
|
type fakeChatProvider struct {
|
|
name string
|
|
model string
|
|
calls int
|
|
resp *providers.ChatResponse
|
|
err error
|
|
}
|
|
|
|
func (p *fakeChatProvider) Chat(context.Context, providers.ChatRequest) (*providers.ChatResponse, error) {
|
|
p.calls++
|
|
if p.resp != nil || p.err != nil {
|
|
return p.resp, p.err
|
|
}
|
|
return &providers.ChatResponse{
|
|
Content: "ok",
|
|
Usage: &providers.Usage{PromptTokens: 1, CompletionTokens: 1, TotalTokens: 2},
|
|
}, nil
|
|
}
|
|
|
|
func (p *fakeChatProvider) ChatStream(ctx context.Context, req providers.ChatRequest, _ func(providers.StreamChunk)) (*providers.ChatResponse, error) {
|
|
return p.Chat(ctx, req)
|
|
}
|
|
|
|
func (p *fakeChatProvider) DefaultModel() string { return p.model }
|
|
func (p *fakeChatProvider) Name() string { return p.name }
|
|
|
|
type fakeUsageCapStore struct {
|
|
policies []store.UsageCapPolicy
|
|
resolved *store.ResolvedUsagePricing
|
|
resolveErr error
|
|
resolveCalls int
|
|
reserveErr error
|
|
reserved store.UsageReserveRequest
|
|
reconciled store.UsageReconcileRequest
|
|
reconcileCalls int
|
|
reconcileCtxCanceled bool
|
|
events []store.UsageCapEvent
|
|
}
|
|
|
|
func (s *fakeUsageCapStore) UpsertPricingCatalog(context.Context, []store.UsagePricingCatalogEntry) (int, error) {
|
|
return 0, nil
|
|
}
|
|
func (s *fakeUsageCapStore) ListPricingCatalog(context.Context, store.UsagePricingQuery) ([]store.UsagePricingCatalogEntry, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeUsageCapStore) PutPricingOverride(context.Context, *store.UsagePricingOverride) error {
|
|
return nil
|
|
}
|
|
func (s *fakeUsageCapStore) ListPricingOverrides(context.Context, store.UsagePricingQuery) ([]store.UsagePricingOverride, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeUsageCapStore) DeletePricingOverride(context.Context, uuid.UUID, uuid.UUID) error {
|
|
return nil
|
|
}
|
|
func (s *fakeUsageCapStore) ResolvePricing(context.Context, uuid.UUID, uuid.UUID, string, string, string) (*store.ResolvedUsagePricing, error) {
|
|
s.resolveCalls++
|
|
if s.resolveErr != nil {
|
|
return nil, s.resolveErr
|
|
}
|
|
return s.resolved, nil
|
|
}
|
|
func (s *fakeUsageCapStore) CreateUsageCapPolicy(context.Context, *store.UsageCapPolicy) error {
|
|
return nil
|
|
}
|
|
func (s *fakeUsageCapStore) ListUsageCapPolicies(context.Context, store.UsageCapScope, bool) ([]store.UsageCapPolicy, error) {
|
|
return s.policies, nil
|
|
}
|
|
func (s *fakeUsageCapStore) UpdateUsageCapPolicy(context.Context, uuid.UUID, uuid.UUID, store.UsageCapPolicyPatch) (*store.UsageCapPolicy, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeUsageCapStore) DeleteUsageCapPolicy(context.Context, uuid.UUID, uuid.UUID) error {
|
|
return nil
|
|
}
|
|
func (s *fakeUsageCapStore) ReserveUsage(_ context.Context, req store.UsageReserveRequest, policies []store.UsageCapPolicy) (*store.UsageReservationResult, error) {
|
|
s.reserved = req
|
|
if s.reserveErr != nil {
|
|
return nil, s.reserveErr
|
|
}
|
|
return &store.UsageReservationResult{ReservationKey: req.ReservationKey, Policies: policies}, nil
|
|
}
|
|
func (s *fakeUsageCapStore) ReconcileUsage(ctx context.Context, req store.UsageReconcileRequest) error {
|
|
s.reconciled = req
|
|
s.reconcileCalls++
|
|
s.reconcileCtxCanceled = ctx.Err() != nil
|
|
return nil
|
|
}
|
|
func (s *fakeUsageCapStore) ListUsageCapUtilization(context.Context, uuid.UUID) ([]store.UsageCapUtilization, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeUsageCapStore) ListUsageCapEvents(context.Context, uuid.UUID, int) ([]store.UsageCapEvent, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeUsageCapStore) InsertUsageCapEvent(_ context.Context, event *store.UsageCapEvent) error {
|
|
if event != nil {
|
|
s.events = append(s.events, *event)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type fakeProviderStore struct {
|
|
provider *store.LLMProviderData
|
|
masterProvider *store.LLMProviderData
|
|
requireTenant uuid.UUID
|
|
}
|
|
|
|
func (s *fakeProviderStore) CreateProvider(context.Context, *store.LLMProviderData) error { return nil }
|
|
func (s *fakeProviderStore) GetProvider(context.Context, uuid.UUID) (*store.LLMProviderData, error) {
|
|
return s.provider, nil
|
|
}
|
|
func (s *fakeProviderStore) GetProviderByName(ctx context.Context, _ string) (*store.LLMProviderData, error) {
|
|
if s.requireTenant != uuid.Nil && store.TenantIDFromContext(ctx) != s.requireTenant {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
if store.TenantIDFromContext(ctx) == store.MasterTenantID && s.masterProvider != nil {
|
|
return s.masterProvider, nil
|
|
}
|
|
if s.provider == nil {
|
|
return nil, sql.ErrNoRows
|
|
}
|
|
return s.provider, nil
|
|
}
|
|
func (s *fakeProviderStore) ListProviders(context.Context) ([]store.LLMProviderData, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeProviderStore) ListAllProviders(context.Context) ([]store.LLMProviderData, error) {
|
|
return nil, nil
|
|
}
|
|
func (s *fakeProviderStore) UpdateProvider(context.Context, uuid.UUID, map[string]any) error {
|
|
return nil
|
|
}
|
|
func (s *fakeProviderStore) DeleteProvider(context.Context, uuid.UUID) error { return nil }
|
|
|
|
func int64Ptr(v int64) *int64 { return &v }
|