"""Feed cursor endpoint: a malformed ?cursor= must be a clean HTTP 400, not a 500. Locks the refactor that split cursor handling across modules — feedquery.decode_cursor raises a plain ValueError and routes/feed.get_feed translates it to 400 — so a future regression (a dropped try/except, or a new decode_cursor caller without its own catch) turns the 400 back into a 500 and fails right here. DB lane (`db` fixture) — skipped without Postgres. """ from fastapi.testclient import TestClient import app.state as state from app.auth import current_user from app.db import get_db from app.main import app from app.models import User def _get(db, user, monkeypatch, path): monkeypatch.setattr( state, "_configured_cache", True ) # the request gate 503s an unconfigured app app.dependency_overrides[get_db] = lambda: db app.dependency_overrides[current_user] = lambda: user try: client = TestClient(app) # no context manager: skip lifespan (scheduler/HLS sweep) return client.get(path) finally: app.dependency_overrides.clear() def test_malformed_feed_cursor_returns_400(db, monkeypatch): user = User(email="feedcursor@example.com") db.add(user) db.commit() resp = _get(db, user, monkeypatch, "/api/feed?cursor=not-a-real-cursor") assert resp.status_code == 400 assert resp.json()["detail"] == "Invalid feed cursor" def test_feed_without_cursor_is_200(db, monkeypatch): # Sanity: the same endpoint without a cursor is a normal 200 (proves the 400 above is the # cursor path, not a globally-broken request). A fresh user has no subscriptions → empty feed. user = User(email="feednocursor@example.com") db.add(user) db.commit() resp = _get(db, user, monkeypatch, "/api/feed") assert resp.status_code == 200 assert resp.json()["items"] == []