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 enforceTokenCaps bool 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 } if s.enforceTokenCaps { for _, p := range policies { if p.MaxTokens != nil && req.EstimatedTokens > *p.MaxTokens { return nil, &store.UsageCapExceededError{PolicyID: p.ID, Reason: "max_tokens"} } } } 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 } // TestPreflightCountsExtraInputTokens proves an out-of-band media charge reaches // the reservation, not just the context-window guard. Without it the reservation // under-reserves by the whole payload. func TestPreflightCountsExtraInputTokens(t *testing.T) { providerID := uuid.New() tenantID := uuid.New() newService := func() (*Service, *fakeUsageCapStore) { policy := store.UsageCapPolicy{ID: uuid.New(), TenantID: tenantID, MaxTokens: int64Ptr(1_000_000), 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", }} return NewService(usageStore, providerStore), usageStore } request := func(extra int) Request { return Request{ TenantID: tenantID, ProviderName: "openrouter", ModelID: "some/model", ReservationKey: "extra-input", Messages: []providers.Message{{Role: "user", Content: "describe this video"}}, MaxOutputTokens: 10, ExtraInputTokens: extra, } } svcBase, storeBase := newService() if _, err := svcBase.Preflight(context.Background(), request(0)); err != nil { t.Fatalf("Preflight without extra tokens returned error: %v", err) } svcExtra, storeExtra := newService() if _, err := svcExtra.Preflight(context.Background(), request(1600)); err != nil { t.Fatalf("Preflight with extra tokens returned error: %v", err) } if got := storeExtra.reserved.EstimatedTokens - storeBase.reserved.EstimatedTokens; got != 1600 { t.Fatalf("EstimatedTokens grew by %d, want 1600", got) } } // TestPreflightDeniesWhenMediaChargeExceedsTokenCap proves an out-of-band media // payload is refused by a tenant token cap the same request passes without it. // Counting the charge is not enough on its own: what has to hold is that the // call is denied before transport. func TestPreflightDeniesWhenMediaChargeExceedsTokenCap(t *testing.T) { providerID := uuid.New() tenantID := uuid.New() policyID := uuid.New() newService := func() *Service { policy := store.UsageCapPolicy{ID: policyID, TenantID: tenantID, MaxTokens: int64Ptr(1_000), Enabled: true} usageStore := &fakeUsageCapStore{ policies: []store.UsageCapPolicy{policy}, resolveErr: sql.ErrNoRows, enforceTokenCaps: true, } providerStore := &fakeProviderStore{provider: &store.LLMProviderData{ BaseModel: store.BaseModel{ID: providerID}, Name: "openrouter", ProviderType: store.ProviderOpenRouter, APIKey: "sk-test", }} return NewService(usageStore, providerStore) } request := func(extra int) Request { return Request{ TenantID: tenantID, ProviderName: "openrouter", ModelID: "some/model", ReservationKey: "media-cap", Messages: []providers.Message{{Role: "user", Content: "describe this video"}}, MaxOutputTokens: 10, ExtraInputTokens: extra, } } if _, err := newService().Preflight(context.Background(), request(0)); err != nil { t.Fatalf("Preflight without the media charge must pass the 1000-token cap, got %v", err) } reservation, err := newService().Preflight(context.Background(), request(5_000)) if !errors.Is(err, ErrCapExceeded) { t.Fatalf("Preflight with the media charge returned %v, want ErrCapExceeded", err) } metadata := reservation.TraceMetadata() if metadata.Decision != store.UsageCapEventBlock { t.Fatalf("Decision = %q, want block", metadata.Decision) } }