package server import ( "context" "encoding/json" "strings" "testing" "time" "net/http" "net/http/httptest" "scm.bstein.dev/bstein/soteria/internal/api" "scm.bstein.dev/bstein/soteria/internal/config" ) func TestRefreshB2UsageRecordsCredentialResolutionErrors(t *testing.T) { srv := &Server{ cfg: &config.Config{ B2Enabled: true, B2ScanTimeout: time.Second, }, client: &fakeKubeClient{}, metrics: newTelemetry(), } srv.refreshB2Usage(context.Background()) usage := srv.getB2Usage() if !usage.Enabled || usage.Error == "" || !strings.Contains(usage.Error, "B2 endpoint is not configured") { t.Fatalf("expected B2 credential resolution error snapshot, got %#v", usage) } if usage.ScannedAt == "" { t.Fatalf("expected failed refresh to record scanned timestamp, got %#v", usage) } if srv.metrics.b2ScanSuccess != 0 || srv.metrics.b2ScanTimestamp == 0 { t.Fatalf("expected failed B2 scan metrics to be recorded, got success=%f timestamp=%f", srv.metrics.b2ScanSuccess, srv.metrics.b2ScanTimestamp) } } func TestRefreshB2UsageHandlesDisabledAndSuccessfulScans(t *testing.T) { t.Run("disabled", func(t *testing.T) { srv := &Server{ cfg: &config.Config{ B2Enabled: false, B2Endpoint: "https://cached-endpoint", B2Region: "us-west-001", B2ScanTimeout: time.Second, }, client: &fakeKubeClient{}, metrics: newTelemetry(), } srv.refreshB2Usage(context.Background()) usage := srv.getB2Usage() if usage.Enabled || usage.Error != "" || usage.Endpoint != "https://cached-endpoint" { t.Fatalf("expected disabled snapshot without scan error, got %#v", usage) } if srv.metrics.b2ScanSuccess != 0 || srv.metrics.b2AccountBytes != 0 { t.Fatalf("expected disabled metrics snapshot, got success=%f bytes=%f", srv.metrics.b2ScanSuccess, srv.metrics.b2AccountBytes) } }) t.Run("successful scan", func(t *testing.T) { now := time.Now().UTC() server := newFakeS3Server(t, []string{"atlas"}, map[string][]fakeS3Object{ "atlas": { {key: "fresh", size: 7, lastModified: now.Add(-1 * time.Hour)}, {key: "stale", size: 11, lastModified: now.Add(-48 * time.Hour)}, }, }, nil, ) defer server.Close() srv := &Server{ cfg: &config.Config{ B2Enabled: true, B2Endpoint: server.URL, B2Region: "us-west-001", B2AccessKeyID: "atlas-key", B2SecretAccessKey: "atlas-secret", B2ScanTimeout: 2 * time.Second, }, client: &fakeKubeClient{}, metrics: newTelemetry(), } srv.refreshB2Usage(context.Background()) usage := srv.getB2Usage() if !usage.Enabled || !usage.Available || usage.Error != "" { t.Fatalf("expected successful B2 scan snapshot, got %#v", usage) } if usage.Endpoint != server.URL || usage.Region != "us-west-001" || usage.TotalObjects != 2 || usage.RecentObjects24h != 1 { t.Fatalf("expected successful usage totals, got %#v", usage) } if usage.ScannedAt == "" || usage.ScanDurationMS < 0 { t.Fatalf("expected scan metadata, got %#v", usage) } if srv.metrics.b2ScanSuccess != 1 || srv.metrics.b2AccountBytes != 18 { t.Fatalf("expected success metrics to be recorded, got success=%f bytes=%f", srv.metrics.b2ScanSuccess, srv.metrics.b2AccountBytes) } }) } func TestRefreshB2UsageRecordsScanErrorsAfterCredentialsResolve(t *testing.T) { srv := &Server{ cfg: &config.Config{ B2Enabled: true, B2Endpoint: "https://", B2AccessKeyID: "atlas-key", B2SecretAccessKey: "atlas-secret", B2ScanTimeout: time.Second, }, client: &fakeKubeClient{}, metrics: newTelemetry(), } srv.refreshB2Usage(context.Background()) usage := srv.getB2Usage() if usage.Endpoint != "https://" { t.Fatalf("expected resolved endpoint to be preserved in failed snapshot, got %#v", usage) } if usage.Error == "" || !strings.Contains(usage.Error, "S3 endpoint host is empty") { t.Fatalf("expected B2 scan error snapshot, got %#v", usage) } if usage.ScannedAt == "" || usage.ScanDurationMS < 0 { t.Fatalf("expected scan metadata on failure, got %#v", usage) } if srv.metrics.b2ScanSuccess != 0 || srv.metrics.b2ScanDurationSeconds < 0 { t.Fatalf("expected failure metrics after scan error, got success=%f duration=%f", srv.metrics.b2ScanSuccess, srv.metrics.b2ScanDurationSeconds) } } func TestHandleB2UsageRefreshesWhenForcedAndQueryBoolRecognizesTruthyValues(t *testing.T) { for _, raw := range []string{"1", "true", "yes", "y", "on", "TRUE"} { if !queryBool(raw) { t.Fatalf("expected %q to be treated as truthy", raw) } } if queryBool("nope") { t.Fatalf("expected invalid truthy value to be false") } srv := &Server{ cfg: &config.Config{ B2Enabled: true, B2Endpoint: "https://", B2AccessKeyID: "atlas-key", B2SecretAccessKey: "atlas-secret", B2ScanTimeout: time.Second, }, client: &fakeKubeClient{}, metrics: newTelemetry(), } srv.handler = http.HandlerFunc(srv.route) srv.setB2Usage(api.B2UsageResponse{ Enabled: true, Available: true, ScannedAt: time.Now().UTC().Add(-1 * time.Hour).Format(time.RFC3339), Endpoint: "cached-endpoint", }) req := httptest.NewRequest(http.MethodGet, "/v1/b2?refresh=yes", nil) res := httptest.NewRecorder() srv.Handler().ServeHTTP(res, req) if res.Code != http.StatusOK { t.Fatalf("expected forced refresh request to succeed, got %d: %s", res.Code, res.Body.String()) } var payload api.B2UsageResponse if err := json.Unmarshal(res.Body.Bytes(), &payload); err != nil { t.Fatalf("decode forced refresh payload: %v", err) } if payload.Error == "" || !strings.Contains(payload.Error, "S3 endpoint host is empty") { t.Fatalf("expected refreshed B2 failure payload, got %#v", payload) } if payload.Endpoint != "https://" { t.Fatalf("expected refreshed endpoint to replace cached snapshot, got %#v", payload) } }