package plugin import ( "context" "encoding/base64" "encoding/json" "fmt" "path/filepath" "sync" "testing" "time" managedaccess "billing/internal/access" "billing/internal/repository" ) func lifecycleRequest(t *testing.T, schema uint32, config string) []byte { t.Helper() raw, err := json.Marshal(LifecycleRequest{ConfigYAML: []byte(config), SchemaVersion: schema}) if err != nil { t.Fatal(err) } return raw } func testConfig(t *testing.T, config string) string { t.Helper() return fmt.Sprintf("database_path: %q\n%s", filepath.Join(t.TempDir(), "usage.db"), config) } func TestRegisterNegotiatesSchemaAndDeclaresManagedAccessCapabilities(t *testing.T) { app := NewApp() raw, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, 99, testConfig(t, "enabled: true\ncodex_only: true\n"))) if err != nil { t.Fatal(err) } var env Envelope if err := json.Unmarshal(raw, &env); err != nil { t.Fatal(err) } if !env.OK { t.Fatalf("register failed: %s", raw) } var got Registration if err := json.Unmarshal(env.Result, &got); err != nil { t.Fatal(err) } if got.SchemaVersion != SchemaVersion || !got.Capabilities.FrontendAuthProvider || !got.Capabilities.FrontendAuthProviderExclusive || !got.Capabilities.Scheduler || !got.Capabilities.RequestInterceptor || !got.Capabilities.RequestLifecyclePlugin || !got.Capabilities.UsagePlugin || !got.Capabilities.ManagementAPI { t.Fatalf("unexpected registration: %+v", got) } } func TestLifecycleConfigYAMLUsesBase64WireEncoding(t *testing.T) { raw := lifecycleRequest(t, SchemaVersion, "enabled: true\n") if !json.Valid(raw) { t.Fatal("invalid JSON") } var wire map[string]any _ = json.Unmarshal(raw, &wire) want := base64.StdEncoding.EncodeToString([]byte("enabled: true\n")) if wire["config_yaml"] != want { t.Fatalf("config_yaml = %v, want %q", wire["config_yaml"], want) } } func TestConfigRejectsShortBootstrapKey(t *testing.T) { if _, err := decodeConfig([]byte("bootstrap_key: 12345\n")); err == nil { t.Fatal("short bootstrap_key unexpectedly accepted") } } func TestConfigDerivesCatalogCacheBesideDatabaseAndValidatesURL(t *testing.T) { databasePath := filepath.Join(t.TempDir(), "nested", "usage.db") cfg, err := decodeConfig([]byte(fmt.Sprintf("database_path: %q\n", databasePath))) if err != nil { t.Fatal(err) } if cfg.CatalogPath != filepath.Join(filepath.Dir(databasePath), "models-dev-catalog.json") { t.Fatalf("catalog path = %q", cfg.CatalogPath) } if _, err := decodeConfig([]byte("models_dev_url: file:///tmp/catalog.json\n")); err == nil { t.Fatal("non-HTTP models_dev_url unexpectedly accepted") } } func TestUsageRecordWireFieldsMatchTargetContract(t *testing.T) { raw, err := json.Marshal(UsageRecord{}) if err != nil { t.Fatal(err) } var fields map[string]json.RawMessage if err := json.Unmarshal(raw, &fields); err != nil { t.Fatal(err) } want := []string{ "RequestID", "TraceID", "Provider", "ExecutorType", "Model", "Alias", "APIKey", "AuthID", "AuthIndex", "AuthType", "Source", "ReasoningEffort", "ServiceTier", "Generate", "RequestedAt", "Latency", "TTFT", "Failed", "Failure", "Detail", "ResponseHeaders", } if len(fields) != len(want) { t.Fatalf("UsageRecord fields=%v", fields) } for _, name := range want { if _, ok := fields[name]; !ok { t.Fatalf("UsageRecord missing target field %s", name) } } } func TestUsageRecordIdentityReconcilesLifecycleExactly(t *testing.T) { app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, testConfig(t, "enabled: true\ncodex_only: false\n"))); err != nil { t.Fatal(err) } defer app.Shutdown() startedAt := time.Now().UTC() completionRaw, _ := json.Marshal(RequestCompletion{ RequestID: "request-identity", TraceID: "trace-identity", Model: "deepseek-v4-flash", StartedAt: startedAt, CompletedAt: startedAt.Add(time.Second), Outcome: RequestCompletionSucceeded, }) if _, err := app.HandleMethod(MethodRequestComplete, completionRaw); err != nil { t.Fatal(err) } usageRaw, _ := json.Marshal(UsageRecord{ RequestID: "request-identity", TraceID: "trace-identity", Provider: "openai", Model: "deepseek-v4-flash", RequestedAt: startedAt.Add(5 * time.Millisecond), Detail: UsageDetail{InputTokens: 10, OutputTokens: 2, TotalTokens: 12}, }) if _, err := app.HandleMethod(MethodUsageHandle, usageRaw); err != nil { t.Fatal(err) } records, err := app.store.ListRecent(context.Background(), 10) if err != nil { t.Fatal(err) } if len(records) != 1 || records[0].RequestID != "request-identity" || records[0].TraceID != "trace-identity" || records[0].TotalTokens != 12 { t.Fatalf("records = %+v", records) } } func TestReconfigureIsAtomicAndFiltersUsage(t *testing.T) { app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, testConfig(t, "enabled: true\ncodex_only: true\n"))); err != nil { t.Fatal(err) } for _, record := range []UsageRecord{{Provider: "codex", Model: "gpt-5.5"}, {Provider: "gemini", Model: "gemini-pro"}} { raw, _ := json.Marshal(record) if _, err := app.HandleMethod(MethodUsageHandle, raw); err != nil { t.Fatal(err) } } if got := app.Seen(); got != 1 { t.Fatalf("seen = %d, want 1", got) } if _, err := app.HandleMethod(MethodPluginReconfigure, lifecycleRequest(t, SchemaVersion, "enabled: [invalid")); err == nil { t.Fatal("invalid reconfiguration unexpectedly succeeded") } raw, _ := json.Marshal(UsageRecord{Provider: "codex", Model: "gpt-5.5"}) _, _ = app.HandleMethod(MethodUsageHandle, raw) if got := app.Seen(); got != 2 { t.Fatalf("last valid config was not retained: seen = %d", got) } } func TestReconfigureReleasesAdmissionsWhenDatabaseChanges(t *testing.T) { directory := t.TempDir() firstPath := filepath.Join(directory, "first.db") secondPath := filepath.Join(directory, "second.db") store, err := repository.OpenSQLiteUsage(secondPath) if err != nil { t.Fatal(err) } if _, err := store.BootstrapManagedKey(context.Background(), "default", "000000"); err != nil { t.Fatal(err) } if _, err := store.UpdateBilling(context.Background(), "key_default", managedaccess.BillingSettings{ QuotaMicros: 1_000_000, ResetPeriod: managedaccess.ResetNone, MaxConcurrency: 4, }, time.Now()); err != nil { t.Fatal(err) } if _, err := store.AuthorizeBilling(context.Background(), "key_default", "stale-request", time.Now()); err != nil { t.Fatal(err) } if err := store.Close(); err != nil { t.Fatal(err) } app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, fmt.Sprintf("database_path: %q\n", firstPath))); err != nil { t.Fatal(err) } if _, err := app.store.UpdateBilling(context.Background(), "key_default", managedaccess.BillingSettings{ QuotaMicros: 1_000_000, ResetPeriod: managedaccess.ResetNone, MaxConcurrency: 4, }, time.Now()); err != nil { t.Fatal(err) } if _, err := app.store.AuthorizeBilling(context.Background(), "key_default", "live-request", time.Now()); err != nil { t.Fatal(err) } if _, err := app.HandleMethod(MethodPluginReconfigure, lifecycleRequest(t, SchemaVersion, fmt.Sprintf("database_path: %q\n", firstPath))); err != nil { t.Fatal(err) } state, err := app.store.BillingState(context.Background(), "key_default", time.Now()) if err != nil || state.ActiveRequests != 1 { t.Fatalf("same-database reconfiguration released live admission: state=%+v err=%v", state, err) } if _, err := app.HandleMethod(MethodPluginReconfigure, lifecycleRequest(t, SchemaVersion, fmt.Sprintf("database_path: %q\n", secondPath))); err != nil { t.Fatal(err) } state, err = app.store.BillingState(context.Background(), "key_default", time.Now()) if err != nil || state.ActiveRequests != 0 { t.Fatalf("reconfigured billing state=%+v err=%v", state, err) } } func TestConcurrentUsage(t *testing.T) { app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, testConfig(t, "enabled: true\ncodex_only: true\n"))); err != nil { t.Fatal(err) } raw, _ := json.Marshal(UsageRecord{Provider: "codex", Model: "gpt-5.5"}) var wg sync.WaitGroup for range 100 { wg.Add(1) go func() { defer wg.Done() if _, err := app.HandleMethod(MethodUsageHandle, raw); err != nil { t.Errorf("handle usage: %v", err) } }() } wg.Wait() if got := app.Seen(); got != 100 { t.Fatalf("seen = %d, want 100", got) } } func TestSSELifecycleCleanupDoesNotAccumulatePendingState(t *testing.T) { app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, testConfig(t, "enabled: true\ncodex_only: false\n"))); err != nil { t.Fatal(err) } defer app.Shutdown() if _, err := app.store.UpdateBilling(context.Background(), "key_default", managedaccess.BillingSettings{ QuotaMicros: 1_000_000_000, ResetPeriod: managedaccess.ResetNone, MaxConcurrency: 64, }, time.Now().UTC()); err != nil { t.Fatal(err) } scope := managedaccess.CallerScope("key_default") outcomes := [...]RequestCompletionOutcome{ RequestCompletionSucceeded, RequestCompletionFailed, RequestCompletionCanceled, RequestCompletionRejected, } for index := range 128 { requestID := fmt.Sprintf("sse-%d", index) beforeRaw, _ := json.Marshal(RequestInterceptRequest{ RequestID: requestID, Model: "deepseek-v4-flash", RequestedModel: "deepseek-v4-flash", Stream: true, Metadata: map[string]any{callerScopeMetadata: scope}, }) beforeResponse, err := app.HandleMethod(MethodRequestBefore, beforeRaw) if err != nil { t.Fatal(err) } var beforeEnvelope Envelope _ = json.Unmarshal(beforeResponse, &beforeEnvelope) var beforeResult RequestInterceptResponse _ = json.Unmarshal(beforeEnvelope.Result, &beforeResult) if beforeResult.Terminate { t.Fatalf("SSE request %s was denied: %+v", requestID, beforeResult) } completionRaw, _ := json.Marshal(RequestCompletion{ RequestID: requestID, Model: "deepseek-v4-flash", Stream: true, StartedAt: time.Now().Add(-time.Second), CompletedAt: time.Now(), Outcome: outcomes[index%len(outcomes)], Metadata: map[string]any{callerScopeMetadata: scope}, }) if _, err := app.HandleMethod(MethodRequestComplete, completionRaw); err != nil { t.Fatal(err) } } pending := 0 app.pending.Range(func(_, _ any) bool { pending++; return true }) if pending != 0 { t.Fatalf("pending SSE requests = %d", pending) } state, err := app.store.BillingState(context.Background(), "key_default", time.Now().UTC()) if err != nil || state.ActiveRequests != 0 { t.Fatalf("SSE billing state=%+v err=%v", state, err) } } func TestFailedSSECompletionStillClearsPendingState(t *testing.T) { app := NewApp() if _, err := app.HandleMethod(MethodPluginRegister, lifecycleRequest(t, SchemaVersion, testConfig(t, "enabled: true\ncodex_only: false\n"))); err != nil { t.Fatal(err) } if _, err := app.store.UpdateBilling(context.Background(), "key_default", managedaccess.BillingSettings{ QuotaMicros: 1_000_000, ResetPeriod: managedaccess.ResetNone, MaxConcurrency: 4, }, time.Now().UTC()); err != nil { t.Fatal(err) } scope := managedaccess.CallerScope("key_default") beforeRaw, _ := json.Marshal(RequestInterceptRequest{ RequestID: "sse-database-failure", Model: "deepseek-v4-flash", Stream: true, Metadata: map[string]any{callerScopeMetadata: scope}, }) beforeResponse, err := app.HandleMethod(MethodRequestBefore, beforeRaw) if err != nil { t.Fatal(err) } var beforeEnvelope Envelope _ = json.Unmarshal(beforeResponse, &beforeEnvelope) var beforeResult RequestInterceptResponse _ = json.Unmarshal(beforeEnvelope.Result, &beforeResult) if beforeResult.Terminate { t.Fatalf("SSE request was denied: %+v", beforeResult) } if err := app.store.Close(); err != nil { t.Fatal(err) } completionRaw, _ := json.Marshal(RequestCompletion{ RequestID: "sse-database-failure", Stream: true, Outcome: RequestCompletionCanceled, CompletedAt: time.Now(), Metadata: map[string]any{callerScopeMetadata: scope}, }) if _, err := app.HandleMethod(MethodRequestComplete, completionRaw); err == nil { t.Fatal("completion unexpectedly succeeded against a closed database") } pending := 0 app.pending.Range(func(_, _ any) bool { pending++; return true }) if pending != 0 { t.Fatalf("pending requests after failed completion = %d", pending) } } func TestUnknownMethodReturnsErrorEnvelope(t *testing.T) { raw, err := NewApp().HandleMethod("missing", nil) if err != nil { t.Fatal(err) } var env Envelope if err := json.Unmarshal(raw, &env); err != nil { t.Fatal(err) } if env.OK || env.Error == nil || env.Error.Code != "unknown_method" { t.Fatalf("unexpected envelope: %s", raw) } }