Deep-review round 4, backend half. - The periodic HLS reaper (round 3) applied the "finished and unfetched for 30 s" rule that only a NEW session request may apply. A remux finishes long before the film, and a paused player with a full buffer fetches nothing, so a one-minute pause killed the session and playback died ~30 s after resuming. The periodic pass is `reap_abandoned` now (the long idle limit, finished or not). - A subtitle `publish` that could not keep its output (full / read-only cache volume) returned quietly, so every poll queued the window and the whole-container pass again. It reports failure and the pass is backed off like a failed read; a cached VTT that cannot be READ is answered `unavailable` (`cache_unreadable`) instead of scheduling reads that can never land. - The subtitle routes bound `rating_key` / `sub_ord` (they become a cache file name: a 250-digit one was ENAMETOOLONG, which pathlib's exists() re-raises -> a 500), and the cache helpers no longer throw on such a name. - One app-wide handler turns psycopg's "text fields cannot contain NUL" DataError into a 422: round 3 guarded only the by-rating_key lookup, and `contains=`, `contains_group=`, reorder/bulk key lists and the collection search still 500'd. - The hand-written `db.get(...) is None -> 404 "Unknown ..."` siblings use `get_or_404` with a `what` (channel / video / user), so the Hungarian UI no longer shows English for a gone row.
54 lines
2.7 KiB
Python
54 lines
2.7 KiB
Python
"""A row that is gone answers with a reason the bilingual UI can translate (deep-review round 3).
|
|
|
|
The 404 a user actually meets is the one for something deleted in another tab or on another device.
|
|
`owned_or_404` / `get_or_404` sent it as a bare English string ("Unknown view", "Not found"), and the
|
|
Hungarian UI toasted it verbatim. The structured-404 fix had gone into one ad-hoc helper instead of
|
|
the shared one, so every other owner check kept the English. Needs the DB.
|
|
"""
|
|
|
|
|
|
def test_a_gone_view_tag_or_pin_says_what_is_gone(db, make_user, as_user):
|
|
client = as_user(make_user())
|
|
for method, url, what in [
|
|
("patch", "/api/saved-views/999999", "view"),
|
|
("delete", "/api/saved-views/999999", "view"),
|
|
("delete", "/api/tags/999999", "tag"),
|
|
("delete", "/api/discover/pins/999999", "pin"),
|
|
]:
|
|
r = getattr(client, method)(url, **({"json": {"name": "x"}} if method == "patch" else {}))
|
|
assert r.status_code == 404, (url, r.text)
|
|
assert r.json()["detail"] == {"code": "not_found", "reason": what}, url
|
|
|
|
|
|
def test_a_gone_channel_video_or_user_says_what_is_gone(db, make_user, as_user):
|
|
"""The siblings that still hand-wrote `db.get(...) is None → 404 "Unknown …"` (deep-review
|
|
round 4): the same gone row, but the Hungarian UI showed the English."""
|
|
admin = make_user(role="admin")
|
|
client = as_user(admin)
|
|
for method, url, body, what in [
|
|
("post", "/api/channels/UCgone000000000000000000/block", None, "channel"),
|
|
("post", "/api/videos/gone0000000/state", {"status": "watched"}, "video"),
|
|
(
|
|
"post",
|
|
"/api/videos/gone0000000/progress",
|
|
{"position_seconds": 60, "duration_seconds": 600},
|
|
"video",
|
|
),
|
|
("put", "/api/admin/downloads/quota/999999", {"max_bytes": 1}, "user"),
|
|
]:
|
|
r = getattr(client, method)(url, **({"json": body} if body is not None else {}))
|
|
assert r.status_code == 404, (url, r.text)
|
|
assert r.json()["detail"] == {"code": "not_found", "reason": what}, url
|
|
|
|
|
|
def test_a_nul_in_a_request_string_is_a_422_not_a_500(db, make_user, as_user):
|
|
"""Postgres cannot hold NUL in text, so the driver refuses the query outright: a DataError, i.e.
|
|
a 500 with a traceback, wherever a `%00` or an escaped NUL reached a comparison (deep-review
|
|
round 4 — round 3 had guarded only the by-rating_key lookup). One app-wide handler now answers
|
|
all of them."""
|
|
client = as_user(make_user())
|
|
r = client.get("/api/plex/playlists?contains=%00")
|
|
assert r.status_code == 422, r.text
|
|
assert r.json()["detail"] == {"code": "invalid_input", "reason": "nul"}
|
|
assert client.get("/api/plex/playlists?contains_group=1,%00").status_code == 422
|