test: a handler that flushes a write and never commits it fails its test
Helpers flush and handlers commit — but every test request shared the test's session, so a follow-up GET or an assertion read the flushed write and the suite stayed green over a handler whose commit was missing (production's get_db closes the session: the write is rolled back behind a 200). The db fixture now hands out `db.info["request"]`: the same session, recording each request that ends normally with a flushed, uncommitted write, and failing the test on it at teardown. All 28 get_db overrides use it (a convention test keeps it so); the full suite passes under it, and dropping the commit from add_item turns a playlist test red.
This commit is contained in:
@@ -21,7 +21,8 @@ from alembic import command
|
|||||||
from alembic.config import Config
|
from alembic.config import Config
|
||||||
from fastapi import HTTPException, Request
|
from fastapi import HTTPException, Request
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from sqlalchemy import create_engine, text
|
from sqlalchemy import create_engine, event, text
|
||||||
|
from starlette.requests import HTTPConnection
|
||||||
|
|
||||||
import app.models # noqa: F401 — register every model on Base.metadata
|
import app.models # noqa: F401 — register every model on Base.metadata
|
||||||
import app.state as app_state
|
import app.state as app_state
|
||||||
@@ -100,17 +101,57 @@ def pytest_configure(config):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _request_dep(db, unfinished: list[str]):
|
||||||
|
"""`get_db` for a test request: the test's own session, plus the check a shared session hides.
|
||||||
|
|
||||||
|
A route helper flushes and its HANDLER commits (CLAUDE.md). Production's `get_db` closes the
|
||||||
|
session after the request, which rolls back anything flushed but not committed — yet here every
|
||||||
|
request shares the test's session, so a follow-up GET or an assertion reads the flushed write
|
||||||
|
and the suite stays green over a handler that forgot to commit (deep review, debt burn). So a
|
||||||
|
request that ends normally with a flushed, uncommitted write is recorded, and the test fails on
|
||||||
|
it at teardown. The test's own staged rows are flushed before the request starts — they are the
|
||||||
|
test's business, not the handler's. A request that raises is exempt: its writes are meant to
|
||||||
|
roll back."""
|
||||||
|
|
||||||
|
def dep(conn: HTTPConnection):
|
||||||
|
db.flush()
|
||||||
|
state = {"dirty": False}
|
||||||
|
|
||||||
|
def flushed(session, ctx):
|
||||||
|
state["dirty"] = True
|
||||||
|
|
||||||
|
def ended(session):
|
||||||
|
state["dirty"] = False
|
||||||
|
|
||||||
|
hooks = (("after_flush", flushed), ("after_commit", ended), ("after_rollback", ended))
|
||||||
|
for name, fn in hooks:
|
||||||
|
event.listen(db, name, fn)
|
||||||
|
try:
|
||||||
|
yield db
|
||||||
|
if state["dirty"]:
|
||||||
|
unfinished.append(f"{conn.scope.get('method', 'WS')} {conn.url.path}")
|
||||||
|
finally:
|
||||||
|
for name, fn in hooks:
|
||||||
|
event.remove(db, name, fn)
|
||||||
|
|
||||||
|
return dep
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def db(_schema):
|
def db(_schema):
|
||||||
"""A real session against the test Postgres, on a clean (empty) database. The code under test
|
"""A real session against the test Postgres, on a clean (empty) database. The code under test
|
||||||
may commit freely."""
|
may commit freely. `db.info["request"]` is the `get_db` override for a request against it — the
|
||||||
|
one every test client uses — and a handler that left a write uncommitted fails the test here."""
|
||||||
_truncate_all()
|
_truncate_all()
|
||||||
session = SessionLocal()
|
session = SessionLocal()
|
||||||
|
unfinished: list[str] = []
|
||||||
|
session.info["request"] = _request_dep(session, unfinished)
|
||||||
try:
|
try:
|
||||||
yield session
|
yield session
|
||||||
finally:
|
finally:
|
||||||
session.rollback()
|
session.rollback()
|
||||||
session.close()
|
session.close()
|
||||||
|
assert unfinished == [], "a handler flushed a write and never committed it"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -168,7 +209,7 @@ def client(db, override_dep, _configured):
|
|||||||
`current_user` override — so login, the wallet gate and epoch revoke are exercised end to end.
|
`current_user` override — so login, the wallet gate and epoch revoke are exercised end to end.
|
||||||
Starlette's SessionMiddleware round-trips the signed cookie, so a login in one call authenticates
|
Starlette's SessionMiddleware round-trips the signed cookie, so a login in one call authenticates
|
||||||
the next on this same instance. No lifespan (the scheduler / HLS sweep stay off)."""
|
the next on this same instance. No lifespan (the scheduler / HLS sweep stay off)."""
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
@@ -187,7 +228,7 @@ def as_user(db, override_dep, _configured):
|
|||||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||||
return registry[uid]
|
return registry[uid]
|
||||||
|
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, _resolver)
|
override_dep(current_user, _resolver)
|
||||||
|
|
||||||
def _as(user: User) -> TestClient:
|
def _as(user: User) -> TestClient:
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ def test_channel_detail_returns_normal_shorts_live_counts(db, monkeypatch, overr
|
|||||||
|
|
||||||
# The request gate 503s an unconfigured instance; flip the process-level flag (auto-restored).
|
# The request gate 503s an unconfigured instance; flip the process-level flag (auto-restored).
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: me)
|
override_dep(current_user, lambda: me)
|
||||||
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ def test_channel_detail_surfaces_subscription_hidden_flag(db, monkeypatch, hidde
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: me)
|
override_dep(current_user, lambda: me)
|
||||||
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ def test_channel_detail_hidden_defaults_false_when_not_subscribed(db, monkeypatc
|
|||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: me)
|
override_dep(current_user, lambda: me)
|
||||||
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
resp = TestClient(app).get(f"/api/channels/{ch.id}")
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ def _patch_deep_requested(db, monkeypatch, override_dep, user):
|
|||||||
# background.add_task runs after the response in TestClient; record what would be scheduled.
|
# background.add_task runs after the response in TestClient; record what would be scheduled.
|
||||||
monkeypatch.setattr(channels_route, "backfill_channel_now", lambda *a, **k: calls.append(a))
|
monkeypatch.setattr(channels_route, "backfill_channel_now", lambda *a, **k: calls.append(a))
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
resp = TestClient(app).patch("/api/channels/UC_wire", json={"deep_requested": True})
|
resp = TestClient(app).patch("/api/channels/UC_wire", json={"deep_requested": True})
|
||||||
return resp, calls
|
return resp, calls
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ def test_channel_detail_returns_only_this_users_tag_ids(db, monkeypatch, overrid
|
|||||||
|
|
||||||
# The request gate 503s an unconfigured instance; flip the process-level flag (auto-restored).
|
# The request gate 503s an unconfigured instance; flip the process-level flag (auto-restored).
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: me)
|
override_dep(current_user, lambda: me)
|
||||||
client = TestClient(app) # no context-manager: skip lifespan (scheduler/HLS sweep)
|
client = TestClient(app) # no context-manager: skip lifespan (scheduler/HLS sweep)
|
||||||
resp = client.get(f"/api/channels/{ch.id}")
|
resp = client.get(f"/api/channels/{ch.id}")
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ def _get(db, user, monkeypatch, override_dep, path):
|
|||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
state, "_configured_cache", True
|
state, "_configured_cache", True
|
||||||
) # the request gate 503s an unconfigured app
|
) # the request gate 503s an unconfigured app
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
client = TestClient(app) # no context manager: skip lifespan (scheduler/HLS sweep)
|
client = TestClient(app) # no context manager: skip lifespan (scheduler/HLS sweep)
|
||||||
return client.get(path)
|
return client.get(path)
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ def _library_item(db, rating_key: str, *, playable: str = "remux"):
|
|||||||
|
|
||||||
|
|
||||||
def _client(db, user, override_dep):
|
def _client(db, user, override_dep):
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|||||||
@@ -21,3 +21,17 @@ def test_no_test_writes_dependency_overrides_directly():
|
|||||||
if "dependency_overrides" in line
|
if "dependency_overrides" in line
|
||||||
]
|
]
|
||||||
assert offenders == [], "use the override_dep fixture: " + ", ".join(offenders)
|
assert offenders == [], "use the override_dep fixture: " + ", ".join(offenders)
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_request_gets_the_session_that_checks_its_commit():
|
||||||
|
"""`get_db` is overridden with `db.info["request"]` — the test session plus the check that the
|
||||||
|
handler committed what it flushed (conftest `_request_dep`). A bare `lambda: db` hands the route
|
||||||
|
the same session without the check, and a handler that forgot its commit passes again."""
|
||||||
|
offenders = [
|
||||||
|
f"{p.name}:{n}"
|
||||||
|
for p in sorted(TESTS.rglob("*.py"))
|
||||||
|
if p.name != Path(__file__).name
|
||||||
|
for n, line in enumerate(p.read_text(encoding="utf-8").splitlines(), 1)
|
||||||
|
if "override_dep(get_db," in line and 'override_dep(get_db, db.info["request"])' not in line
|
||||||
|
]
|
||||||
|
assert offenders == [], 'override get_db with db.info["request"]: ' + ", ".join(offenders)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ def _clear(db, user, it, monkeypatch, override_dep) -> list[tuple]:
|
|||||||
"push_state_to_plex",
|
"push_state_to_plex",
|
||||||
lambda user_id, item_id, rating_key, action, *rest: pushes.append((rating_key, action)),
|
lambda user_id, item_id, rating_key, action, *rest: pushes.append((rating_key, action)),
|
||||||
)
|
)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
resp = TestClient(app).post(f"/api/plex/item/{it.rating_key}/state", json={"status": "new"})
|
resp = TestClient(app).post(f"/api/plex/item/{it.rating_key}/state", json={"status": "new"})
|
||||||
assert resp.status_code == 200, resp.text
|
assert resp.status_code == 200, resp.text
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ def test_create_collection_rejects_duplicate_name(db, monkeypatch, override_dep)
|
|||||||
user = User(email="dup@example.com")
|
user = User(email="dup@example.com")
|
||||||
db.add(user)
|
db.add(user)
|
||||||
db.commit()
|
db.commit()
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
override_dep(admin_user, lambda: user)
|
override_dep(admin_user, lambda: user)
|
||||||
r = TestClient(app).post(
|
r = TestClient(app).post(
|
||||||
@@ -273,7 +273,7 @@ def _admin_client(db, user, monkeypatch, override_dep, stub, resync=_resync_ok):
|
|||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
monkeypatch.setattr(coll_routes, "PlexClient", lambda db: stub)
|
monkeypatch.setattr(coll_routes, "PlexClient", lambda db: stub)
|
||||||
monkeypatch.setattr(coll_routes.plex_sync, "resync_collection", resync)
|
monkeypatch.setattr(coll_routes.plex_sync, "resync_collection", resync)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
override_dep(admin_user, lambda: user)
|
override_dep(admin_user, lambda: user)
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ def test_enrich_people_batch_persists_detail(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True) # pass the request gate
|
monkeypatch.setattr(state, "_configured_cache", True) # pass the request gate
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
client = TestClient(app) # no context manager: skip lifespan
|
client = TestClient(app) # no context manager: skip lifespan
|
||||||
return client.get(path)
|
return client.get(path)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def test_facets_returns_studio_vocabulary(db, monkeypatch, override_dep):
|
|||||||
db.add(user)
|
db.add(user)
|
||||||
db.commit()
|
db.commit()
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
resp = TestClient(app).get("/api/plex/facets?scope=movie")
|
resp = TestClient(app).get("/api/plex/facets?scope=movie")
|
||||||
assert resp.status_code == 200, resp.text
|
assert resp.status_code == 200, resp.text
|
||||||
@@ -58,7 +58,7 @@ def test_facets_survives_json_null_genres(db, monkeypatch, override_dep):
|
|||||||
db.execute(text("UPDATE plex_shows SET genres = 'null'::jsonb WHERE rating_key = 's1'"))
|
db.execute(text("UPDATE plex_shows SET genres = 'null'::jsonb WHERE rating_key = 's1'"))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
client = TestClient(app) # no context-manager: skip lifespan (scheduler/HLS sweep)
|
client = TestClient(app) # no context-manager: skip lifespan (scheduler/HLS sweep)
|
||||||
resp = client.get("/api/plex/facets?scope=show")
|
resp = client.get("/api/plex/facets?scope=show")
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def _get(db, user, monkeypatch, override_dep, path):
|
|||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
state, "_configured_cache", True
|
state, "_configured_cache", True
|
||||||
) # the request gate 503s an unconfigured app
|
) # the request gate 503s an unconfigured app
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
client = TestClient(app) # no context manager: skip lifespan
|
client = TestClient(app) # no context manager: skip lifespan
|
||||||
return client.get(path)
|
return client.get(path)
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ def _seed(db):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ NAME = "Robert De Niro"
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True) # pass the request gate
|
monkeypatch.setattr(state, "_configured_cache", True) # pass the request gate
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path) # no lifespan (skip scheduler/HLS sweep)
|
return TestClient(app).get(path) # no lifespan (skip scheduler/HLS sweep)
|
||||||
|
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ def test_enrich_person_noop_without_tmdb_id(db, monkeypatch):
|
|||||||
|
|
||||||
def _get(db, user, monkeypatch, override_dep, path):
|
def _get(db, user, monkeypatch, override_dep, path):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).get(path)
|
return TestClient(app).get(path)
|
||||||
|
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ def _seed_classes(db):
|
|||||||
|
|
||||||
def _client(db, user, monkeypatch, override_dep):
|
def _client(db, user, monkeypatch, override_dep):
|
||||||
monkeypatch.setattr(state, "_configured_cache", True)
|
monkeypatch.setattr(state, "_configured_cache", True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ def _post(db, user, monkeypatch, override_dep, rating_key, *, captured):
|
|||||||
)
|
)
|
||||||
|
|
||||||
monkeypatch.setattr(plex_stream, "start_session", fake_start)
|
monkeypatch.setattr(plex_stream, "start_session", fake_start)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
return TestClient(app).post(f"/api/plex/stream/{rating_key}/session")
|
return TestClient(app).post(f"/api/plex/stream/{rating_key}/session")
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ def _request(db, user, monkeypatch, override_dep, method, path, json=None):
|
|||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
state, "_configured_cache", True
|
state, "_configured_cache", True
|
||||||
) # the request gate 503s an unconfigured app
|
) # the request gate 503s an unconfigured app
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user)
|
override_dep(current_user, lambda: user)
|
||||||
client = TestClient(app) # no context manager: skip lifespan (scheduler/HLS sweep)
|
client = TestClient(app) # no context manager: skip lifespan (scheduler/HLS sweep)
|
||||||
return client.request(method, path, json=json)
|
return client.request(method, path, json=json)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def test_a_suspended_account_cannot_drive_the_subtitle_extractor(
|
|||||||
db, make_user, override_dep, monkeypatch, tmp_path
|
db, make_user, override_dep, monkeypatch, tmp_path
|
||||||
):
|
):
|
||||||
user = make_user(is_suspended=True)
|
user = make_user(is_suspended=True)
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
monkeypatch.setattr(app_state, "_configured_cache", True)
|
monkeypatch.setattr(app_state, "_configured_cache", True)
|
||||||
# A validly SIGNED cookie for that account — which is all the old gate looked at.
|
# A validly SIGNED cookie for that account — which is all the old gate looked at.
|
||||||
for mod in (auth, playback):
|
for mod in (auth, playback):
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ def _client(db, user, monkeypatch, override_dep):
|
|||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
state, "_configured_cache", True
|
state, "_configured_cache", True
|
||||||
) # the request gate 503s an unconfigured app
|
) # the request gate 503s an unconfigured app
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(current_user, lambda: user) # require_human resolves through this
|
override_dep(current_user, lambda: user) # require_human resolves through this
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ def test_search_youtube_route_returns_422_when_ingest_fails(db, monkeypatch, ove
|
|||||||
|
|
||||||
monkeypatch.setattr(search_mod, "_ingest_candidates", _boom)
|
monkeypatch.setattr(search_mod, "_ingest_candidates", _boom)
|
||||||
|
|
||||||
override_dep(get_db, lambda: db)
|
override_dep(get_db, db.info["request"])
|
||||||
override_dep(require_human, lambda: user)
|
override_dep(require_human, lambda: user)
|
||||||
resp = TestClient(app).get("/api/search/youtube?q=test+term")
|
resp = TestClient(app).get("/api/search/youtube?q=test+term")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user