package service import ( "context" "encoding/json" "testing" "github.com/Wei-Shaw/sub2api/internal/config" ) func TestGetOpsAdvancedSettings_DefaultHidesOpenAITokenStats(t *testing.T) { repo := newRuntimeSettingRepoStub() svc := &OpsService{settingRepo: repo} cfg, err := svc.GetOpsAdvancedSettings(context.Background()) if err != nil { t.Fatalf("GetOpsAdvancedSettings() error = %v", err) } if cfg.DisplayOpenAITokenStats { t.Fatalf("DisplayOpenAITokenStats = true, want false by default") } if !cfg.DisplayAlertEvents { t.Fatalf("DisplayAlertEvents = false, want true by default") } if repo.setCalls != 1 { t.Fatalf("expected defaults to be persisted once, got %d", repo.setCalls) } } func TestUpdateOpsAdvancedSettings_PersistsOpenAITokenStatsVisibility(t *testing.T) { repo := newRuntimeSettingRepoStub() svc := &OpsService{settingRepo: repo} cfg := defaultOpsAdvancedSettings() cfg.DisplayOpenAITokenStats = true cfg.DisplayAlertEvents = false updated, err := svc.UpdateOpsAdvancedSettings(context.Background(), cfg) if err != nil { t.Fatalf("UpdateOpsAdvancedSettings() error = %v", err) } if !updated.DisplayOpenAITokenStats { t.Fatalf("DisplayOpenAITokenStats = false, want true") } if updated.DisplayAlertEvents { t.Fatalf("DisplayAlertEvents = true, want false") } reloaded, err := svc.GetOpsAdvancedSettings(context.Background()) if err != nil { t.Fatalf("GetOpsAdvancedSettings() after update error = %v", err) } if !reloaded.DisplayOpenAITokenStats { t.Fatalf("reloaded DisplayOpenAITokenStats = false, want true") } if reloaded.DisplayAlertEvents { t.Fatalf("reloaded DisplayAlertEvents = true, want false") } } func TestGetOpsAdvancedSettings_BackfillsNewDisplayFlagsFromDefaults(t *testing.T) { repo := newRuntimeSettingRepoStub() svc := &OpsService{settingRepo: repo} legacyCfg := map[string]any{ "data_retention": map[string]any{ "cleanup_enabled": false, "cleanup_schedule": "0 2 * * *", "error_log_retention_days": 30, "minute_metrics_retention_days": 30, "hourly_metrics_retention_days": 30, }, "aggregation": map[string]any{ "aggregation_enabled": false, }, "ignore_count_tokens_errors": true, "ignore_context_canceled": true, "ignore_no_available_accounts": false, "ignore_invalid_api_key_errors": false, "auto_refresh_enabled": false, "auto_refresh_interval_seconds": 30, } raw, err := json.Marshal(legacyCfg) if err != nil { t.Fatalf("marshal legacy config: %v", err) } repo.values[SettingKeyOpsAdvancedSettings] = string(raw) cfg, err := svc.GetOpsAdvancedSettings(context.Background()) if err != nil { t.Fatalf("GetOpsAdvancedSettings() error = %v", err) } if cfg.DisplayOpenAITokenStats { t.Fatalf("DisplayOpenAITokenStats = true, want false default backfill") } if !cfg.DisplayAlertEvents { t.Fatalf("DisplayAlertEvents = false, want true default backfill") } } func TestGetOpenAIQuotaAutoPauseSettings_ReadsDefaultsFromOpsAdvancedSettings(t *testing.T) { repo := newRuntimeSettingRepoStub() repo.values[SettingKeyOpsAdvancedSettings] = `{"openai_account_quota_auto_pause":{"default_threshold_5h":0.95,"default_threshold_7d":0.9}}` svc := NewSettingService(repo, &config.Config{}) settings := svc.GetOpenAIQuotaAutoPauseSettings(context.Background()) if settings.DefaultThreshold5h != 0.95 { t.Fatalf("DefaultThreshold5h = %v, want 0.95", settings.DefaultThreshold5h) } if settings.DefaultThreshold7d != 0.9 { t.Fatalf("DefaultThreshold7d = %v, want 0.9", settings.DefaultThreshold7d) } }