fix(r5): address the seventh /code-review high round — 7 findings
Five of them sit where round 6 turned F from a Fullscreen API call into a CSS maximise: the guards around it still asked `isFullscreen`, which that pivot made permanently false. - Arrow-key volume was dead in the maximised view: the scroll-deference checked only `isFullscreenRef`, so the (now hidden but still scrollable) card kept swallowing Up/Down. Both flags now count as "the video fills the screen". Measured: 87px of scroll room on the focused card, ArrowDown moves 80 -> 75 and scrolls nothing. - The maximised view had no way out once the pointer touched the video. Reaching YouTube's controls means clicking into the cross-origin iframe, which takes keyboard focus with it, and the re-arm paths (stage mouseleave, window focus) need the pointer to leave the browser entirely while the stage fills it. So the exit now lives on screen, in our DOM: a button that un-maximises AND pulls focus back, re-arming every shortcut. - WebKit fires only `webkitfullscreenchange`/`webkitFullscreenElement`, so on Safari/iPadOS YouTube's own fullscreen never registered — no overlay yield, no focus reclaim. One `fullscreenEl()` reader, both event spellings. - The stage claimed `z-index: 9999`, the glass tuner's reserved level, for a job that only needs to beat the modal chrome it is nested in (its siblings top out at z-menu). Dropped to rail-level; nothing escapes the modal's stacking context either way. - `inset: 0` already sizes a fixed layer — the inherited `100vw`/`100vh` over-constrained it, which is how a classic scrollbar gets a horizontal overflow and a mobile URL bar hides the bottom edge (YouTube's control bar). - The shortcut hint still promised "F: fullscreen" in both locales. Backend, both "the fix stopped one layer short": - The startup HLS sweep was awaited inside lifespan, so uvicorn still served nothing until it finished — a thread doesn't help when nothing is listening yet. Fire-and-forget task instead, cancelled on shutdown. Measured with 200 planted segments: "Application startup complete" now precedes "swept 1". - An RSS poll where every channel failed returned normally, so the scheduler recorded `ok` with the outage buried in the summary string. `failed == total` now raises: a run that reached nothing is a failed run. Suites: backend 147 -> 150.
This commit is contained in:
@@ -106,34 +106,71 @@ class TestRssPollResult:
|
||||
Counting only the fetch failures would move the "a broken run looks like a quiet hour" blind
|
||||
spot rather than remove it."""
|
||||
|
||||
def _run(self, monkeypatch, *, fetch, apply_):
|
||||
def _run(self, monkeypatch, *, fetch, apply_, channels=("UC1", "UC2")):
|
||||
monkeypatch.setattr(runner, "fetch_channel_feed", fetch)
|
||||
monkeypatch.setattr(runner, "apply_rss_feed", apply_)
|
||||
return runner.run_rss_poll(_StubDb(), [_StubChannel("UC1"), _StubChannel("UC2")])
|
||||
return runner.run_rss_poll(_StubDb(), [_StubChannel(c) for c in channels])
|
||||
|
||||
def test_a_healthy_run_reports_no_failures(self, monkeypatch):
|
||||
out = self._run(monkeypatch, fetch=lambda cid: [{"id": "v"}], apply_=lambda db, ch, e: 1)
|
||||
assert out == {"new": 2, "failed": 0}
|
||||
|
||||
def test_unreadable_feeds_are_counted(self, monkeypatch):
|
||||
def boom(cid):
|
||||
raise rss.RssError("404")
|
||||
# One dead channel among healthy ones: counted, but the run itself is still a run.
|
||||
def fetch(cid):
|
||||
if cid == "UC_dead":
|
||||
raise rss.RssError("404")
|
||||
return [{"id": "v"}]
|
||||
|
||||
out = self._run(monkeypatch, fetch=boom, apply_=lambda db, ch, e: 1)
|
||||
assert out == {"new": 0, "failed": 2}
|
||||
out = self._run(
|
||||
monkeypatch, fetch=fetch, apply_=lambda db, ch, e: 1, channels=("UC1", "UC_dead")
|
||||
)
|
||||
assert out == {"new": 1, "failed": 1}
|
||||
|
||||
def test_apply_failures_are_counted_too(self, monkeypatch):
|
||||
# A read-only database: every feed reads fine, nothing can be stored.
|
||||
def boom(db, ch, entries):
|
||||
raise RuntimeError("read-only transaction")
|
||||
# A per-row write failure (a constraint clash on one channel) while the rest store fine.
|
||||
def apply_(db, ch, entries):
|
||||
if ch.id == "UC_bad":
|
||||
raise RuntimeError("constraint")
|
||||
return 1
|
||||
|
||||
out = self._run(monkeypatch, fetch=lambda cid: [{"id": "v"}], apply_=boom)
|
||||
assert out == {"new": 0, "failed": 2}, "a run where nothing was stored must not read as ok"
|
||||
out = self._run(
|
||||
monkeypatch,
|
||||
fetch=lambda cid: [{"id": "v"}],
|
||||
apply_=apply_,
|
||||
channels=("UC1", "UC_bad"),
|
||||
)
|
||||
assert out == {"new": 1, "failed": 1}, "an unstored channel must not read as ok"
|
||||
|
||||
def test_a_quiet_hour_is_distinguishable_from_an_outage(self, monkeypatch):
|
||||
quiet = self._run(monkeypatch, fetch=lambda cid: [], apply_=lambda db, ch, e: 0)
|
||||
assert quiet == {"new": 0, "failed": 0} # same "new", different "failed" — that's the point
|
||||
|
||||
def test_a_total_outage_raises_instead_of_returning_ok(self, monkeypatch):
|
||||
# Every feed unreachable (the tinyproxy-lost-the-boot-race incident). Returning a result
|
||||
# here recorded the scheduler run as "ok", with the outage only visible inside the summary
|
||||
# text — a green pill for a run that did nothing at all.
|
||||
def boom(cid):
|
||||
raise rss.RssError("Connection refused")
|
||||
|
||||
with pytest.raises(RuntimeError, match="all 2 channels"):
|
||||
self._run(monkeypatch, fetch=boom, apply_=lambda db, ch, e: 1)
|
||||
|
||||
def test_a_read_only_database_is_a_total_outage_too(self, monkeypatch):
|
||||
# Every feed reads fine, nothing can be stored: just as un-polled, just as red.
|
||||
def boom(db, ch, entries):
|
||||
raise RuntimeError("read-only transaction")
|
||||
|
||||
with pytest.raises(RuntimeError, match="all 2 channels"):
|
||||
self._run(monkeypatch, fetch=lambda cid: [{"id": "v"}], apply_=boom)
|
||||
|
||||
def test_no_channels_at_all_is_not_an_outage(self, monkeypatch):
|
||||
# A fresh instance with nothing subscribed must not report an error every poll.
|
||||
out = self._run(
|
||||
monkeypatch, fetch=lambda cid: [], apply_=lambda db, ch, e: 0, channels=()
|
||||
)
|
||||
assert out == {"new": 0, "failed": 0}
|
||||
|
||||
|
||||
class TestRssErrorVsEmpty:
|
||||
"""A failed poll must RAISE (so the caller leaves `last_rss_at` alone); only a genuinely
|
||||
|
||||
Reference in New Issue
Block a user