package api import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/ponzischeme89/memby/server/internal/config" "github.com/ponzischeme89/memby/server/internal/store" ) func TestFeatureEvaluationSupportsDefaultsOverridesAndSafeMode(t *testing.T) { definition, ok := knownFeature(featureSonarrPreroll) if !ok { t.Fatal("preroll is not registered") } if got := evaluateFeature(store.DefaultFeaturePolicy(), definition, 1); !got.Enabled || got.Source != "default" { t.Fatalf("default evaluation = %+v", got) } off := store.FeaturePolicy{Overrides: map[string]bool{featureSonarrPreroll: false}} if got := evaluateFeature(off, definition, 1); got.Enabled || got.Source != "override" { t.Fatalf("off evaluation = %+v", got) } safe := store.FeaturePolicy{Overrides: map[string]bool{featureSonarrPreroll: true}, SafeMode: true} if got := evaluateFeature(safe, definition, 1); got.Enabled || got.Source != "safe_mode" { t.Fatalf("safe-mode evaluation = %+v", got) } } func TestFeatureEvaluationFailsClosedForAnIncompatibleClient(t *testing.T) { definition := featureDefinition{Key: "future", DefaultEnabled: true, MinimumProtocol: 2} got := evaluateFeature(store.DefaultFeaturePolicy(), definition, 1) if got.Enabled || got.Compatible || got.Source != "incompatible_client" { t.Fatalf("incompatible evaluation = %+v", got) } } func TestHEVCDirectPlayIsVisibleAndServerControllable(t *testing.T) { definition, ok := knownFeature(featureHEVCDirectPlay) if !ok || definition.Area != "Playback" || definition.Capability != "video_hevc_decode" { t.Fatalf("HEVC feature definition = %+v, found=%v", definition, ok) } disabled := store.FeaturePolicy{Overrides: map[string]bool{featureHEVCDirectPlay: false}} if got := evaluateFeature(disabled, definition, 1); got.Enabled { t.Fatalf("HEVC override = %+v", got) } } func TestGenreBrowserIsServerControlledAndOffByDefault(t *testing.T) { definition, ok := knownFeature(featureGenreBrowser) if !ok || definition.Capability != "genre_browser_v1" { t.Fatalf("genre browser feature definition = %+v, found=%v", definition, ok) } if got := evaluateFeature(store.DefaultFeaturePolicy(), definition, 1); got.Enabled { t.Fatalf("genre browser default = %+v, want disabled", got) } enabled := store.FeaturePolicy{Overrides: map[string]bool{featureGenreBrowser: true}} if got := evaluateFeature(enabled, definition, 1); !got.Enabled || got.Source != "override" { t.Fatalf("genre browser override = %+v", got) } } func TestClientCapabilitiesAreNormalizedAndBounded(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/v1/status", nil) req.Header.Set("X-Memby-Capabilities", " Sonarr_Preroll_V1,server_features_v1,sonarr_preroll_v1,"+ "this-capability-name-is-deliberately-longer-than-sixty-four-characters-and-is-rejected") got := clientCapabilities(req) if len(got) != 2 || got[0] != "server_features_v1" || got[1] != "sonarr_preroll_v1" { t.Fatalf("capabilities = %#v", got) } } func TestFeatureAdminRejectsUnknownFlagsBeforeWriting(t *testing.T) { server := testServer(config.Config{}) req := httptest.NewRequest(http.MethodPost, "/admin/api/features", strings.NewReader(`{"action":"save","expectedRevision":0,"overrides":{"made_up":true}}`)) rec := httptest.NewRecorder() server.handleAdminFeaturePolicy(rec, req) if rec.Code != http.StatusBadRequest { t.Fatalf("status = %d, want 400", rec.Code) } }