phase: 02_sharp_capture
Build and Push Containers / test (push) Successful in 46s
Build and Push Containers / build-and-push-app (push) Successful in 8s

**Phase 02 final verification pass — complete, 100% green.**

**Verified (all 4 tasks in `complete/02_sharp_capture/`):**
- Task 1: `pickSurface()` requests `screen × devicePixelRatio` (capped 3840×2160) instead of window size
- Task 2: `degradationPreference: "maintain-resolution"` + per-leg `maxBitrate`, re-applied after `setLocalDescription` *and* on `connected` (both call sites asserted in `test_app.py`)
- Task 3: default cap raised to 25 Mbit/s — `config.py` constant, `net.js` offline fallback, `.env.example`, README, and the drift-guard test all agree
- Task 4: realdisplay sharpness floor (viewer decoded width ≥ 1152px = 90% of Xvfb 1280px) in `test_sharp_picture_reaches_the_wall`

**Gates (all green):**
- `uv run ruff check . && uv run ruff format --check .` → clean
- `uv run pyright` → 0 errors
- `uv run pytest` → 231 passed, 3 skipped (realdisplay), coverage 95%
- `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → 3 passed on a real Xvfb + headed Chromium

**Completion criteria:** (1) 90% width floor asserted on viewer's decoded pixels — PASS · (2) `/api/config` `maxBitrateBps: 25000000` default, net.js fallback agrees — PASS · (3) `#stat-resolution` matches viewer-decoded size incl. documented window downscale (1100×620, 1280×720 fake-device tests) — PASS · (4) both suites green, aspect-ratio guard (`1280/800` ± 0.06 + `≠ 1280×720`) still distinguishes real from fake capture — PASS · (5) README Configuration documents `25000000` — PASS; `PLAN.md` §6 "default 12 Mbit/s" left untouched as instructed — **flag for the user to amend**.

**Docs:** README — fixed suite timing `~20s → ~50s` (measured 49s); all other claims verified (CLI flags, dev extra, config table, kiosk key table vs. `watch.js`/`share.js` routers, kiosk commands vs. `docs/kiosk-silverblue.md`). AGENTS.md — same stale timing fixed, nothing else stale (all referenced test names/files exist).

**Notable:** `docs/kiosk-silverblue.md` + its scripts use `mirror.reeselink.com` while README/SECURITY.md/Containerfile use `mirror.reeseapps.com` — a pre-existing cross-file mismatch I could not resolve from the repo (both in same-day commits; live-infra fact). Left untouched; user should confirm the live kiosk URL. No live changes made.

**Next pending phase:** `03_audio_share`.
This commit is contained in:
2026-11-01 21:41:28 -05:00
parent 1e816da5a8
commit 1da466a412
36 changed files with 938 additions and 26 deletions
+170
View File
@@ -65,6 +65,176 @@ class TestShareThenWatch:
assert errors == [], f"uncaught browser errors: {errors}"
def test_the_screen_sized_request_does_not_break_the_fake_device(self, device):
"""Asking for screen x DPR (capped 3840x2160) must not break the fake
device's path.
The old "always 1280x720" expectation held only while the request
carried no size. Once a size is *named*, the fake UI clamps the capture
to the fake browser window (1100x720 context -> 1100x620 with chrome)
— PLAN §5's window scaling, even for the synthetic device. So the
assertion here is: the share starts, the viewer decodes exactly what
the sharer's delivered settings are, moving, and publish() reports
those delivered settings, not the request.
"""
errors: list = []
sharer = device("/mirror", errors)
start_sharing(sharer)
# What the page asked for vs what the fake device delivered.
reported = sharer.evaluate(
"""() => {
const track = document.querySelector('#preview').srcObject.getVideoTracks()[0];
const s = track.getSettings();
const dpr = window.devicePixelRatio || 1;
return {
requested: {
width: Math.min(Math.round(screen.width * dpr), 3840),
height: Math.min(Math.round(screen.height * dpr), 2160),
},
delivered: {width: s.width, height: s.height},
stat: document.querySelector('#stat-resolution').textContent,
};
}"""
)
assert reported["requested"] == {"width": 1100, "height": 720}, reported
# The full requested width is honoured; the height is clamped to the
# fake window's visible area (the 100px of chrome).
assert reported["delivered"]["width"] == 1100, reported
assert 0 < reported["delivered"]["height"] < 720, reported
# publish() reports the delivered settings, not the request.
# The page renders the separator as U+00D7 (multiplication sign).
w, h = reported["delivered"]["width"], reported["delivered"]["height"]
assert reported["stat"] == f"{w} \u00d7 {h}", reported
viewer = device("/watch", errors)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
frames = frames_matching(viewer, ".tile video")
assert (frames["width"], frames["height"]) == (w, h), (
f"the viewer must decode what the sharer reported: {frames} vs {reported}"
)
assert frames["distinct"] >= 2, f"the video is frozen: {frames}"
assert errors == [], f"uncaught browser errors: {errors}"
def test_the_fake_device_keeps_exactly_1280x720(self, base_url, browser, request, device):
"""The fake-device counterpart of the realdisplay sharpness floor.
With the sharer's window filling the fake 1280x720 monitor (a 1280x820
viewport: the ~100px of window chrome clamps the 820 request back to
720), the deterministic device delivers exactly 1280x720 — the classic
"always 1280x720" synthetic path. The phase 02 ``ideal`` size
constraints (screen x DPR, capped 3840x2160) must not change what the
synthetic path delivers: the viewer decodes exactly 1280x720, moving.
Measured on the reference host (phase 02, 2026-11-01): a 1280x820
sharer window requests 1280x820 and the fake device delivers exactly
1280x720; the viewer decodes 1280x720. (A 1100x720 window instead
delivers 1100x620 — the same window clamp, covered by the sibling
test.)
"""
errors: list = []
context = browser.new_context(viewport={"width": 1280, "height": 820})
request.addfinalizer(context.close)
sharer = context.new_page()
sharer.on("pageerror", lambda error: errors.append(str(error)))
sharer.goto(f"{base_url}/mirror", wait_until="domcontentloaded")
expect(sharer.locator("#net")).to_have_attribute("data-state", "online", timeout=10_000)
start_sharing(sharer)
delivered = sharer.evaluate(
"""() => {
const track = document.querySelector('#preview').srcObject.getVideoTracks()[0];
const s = track.getSettings();
return {width: s.width, height: s.height};
}"""
)
assert delivered == {"width": 1280, "height": 720}, delivered
# The page's own stats agree with the delivered settings.
expect(sharer.locator("#stat-resolution")).to_have_text("1280 \u00d7 720")
viewer = device("/watch", errors)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
frames = frames_matching(viewer, ".tile video")
assert (frames["width"], frames["height"]) == (1280, 720), (
f"the fake device must keep delivering exactly 1280x720: {frames}"
)
assert frames["distinct"] >= 2, f"the video is frozen: {frames}"
assert errors == [], f"uncaught browser errors: {errors}"
def test_the_staged_tile_bytes_keep_growing(self, base_url, browser, request, device):
"""Inbound-bitrate sanity on a staged tile: an observation, not an equality.
The viewer's ``inbound-rtp.bytesReceived`` must grow while a share is
live. With the default 25 Mbit/s per-leg cap, a live 1280x720 fake
share delivered ~126 KB over a ~2 s sample (≈ 0.5 Mbit/s) on the
reference host (phase 02, 2026-11-01) — the figure is
environment-dependent (codec, motion, cap), so the assertion is growth
from a non-zero start, never a specific number.
"""
context = browser.new_context(viewport={"width": 1100, "height": 720})
request.addfinalizer(context.close)
# Test scaffolding (AGENTS.md §6): collect the RTCPeerConnection
# instances watch.js creates so the test can read the viewer's
# inbound-rtp stats through the one allowed global, ``window.__probe``.
context.add_init_script(
"""
window.__probe = {pcs: []};
const RealPC = window.RTCPeerConnection;
window.RTCPeerConnection = function (config) {
const pc = new RealPC(config);
window.__probe.pcs.push(pc);
return pc;
};
window.RTCPeerConnection.prototype = RealPC.prototype;
window.RTCPeerConnection.static = RealPC.static;
"""
)
page = context.new_page()
page.goto(f"{base_url}/watch", wait_until="domcontentloaded")
expect(page.locator("#net")).to_have_attribute("data-state", "online", timeout=10_000)
sharer = device("/mirror")
start_sharing(sharer)
expect(page.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
# Take it fullscreen: the staged <video> is the same element moved onto
# the stage, so the peer connection — and its stats — survive.
page.locator(".tile").click()
expect(page.locator("body")).to_have_class(re.compile("staged"), timeout=5_000)
expect(page.locator("#watch-stage video")).to_have_count(1)
read_bytes = """async () => {
let total = 0;
for (const pc of window.__probe.pcs) {
try {
const stats = await pc.getStats();
stats.forEach((entry) => {
if (entry.type === 'inbound-rtp' && entry.kind === 'video') {
total += entry.bytesReceived || 0;
}
});
} catch { /* a closed pc has no stats; the live one does */ }
}
return total;
}"""
# Wait for the leg to actually be connected, then sample twice.
deadline = time.time() + 30
while time.time() < deadline:
states = page.evaluate("() => window.__probe.pcs.map(pc => pc.connectionState)")
if "connected" in states:
break
time.sleep(0.3)
first = page.evaluate(read_bytes)
assert first > 0, f"no bytes had arrived by the first sample: {first}"
time.sleep(2.0)
second = page.evaluate(read_bytes)
assert second > first, (
f"the viewer's inbound byte count did not grow while the share was "
f"live: {first} -> {second}"
)
def test_clicking_a_tile_takes_it_on_stage(self, device):
sharer = device("/mirror")
start_sharing(sharer)
+166
View File
@@ -0,0 +1,166 @@
"""End-to-end: the sharer's per-leg encoder settings, read back from the page.
The wall is a wall of *text*: the encoder must never buy frame rate with
resolution. `degradationPreference: "maintain-resolution"` is that trade, and
the per-leg `maxBitrate` cap must survive every renegotiation — a re-offer
(a surface switch, a viewer that re-joined) resets the encodings, and the
cap is re-applied after each negotiation and when a leg reaches `connected`.
The assertions read the parameters back from the sharer's real
RTCPeerConnection senders, through the page's `window.__probe` test handle
(AGENTS.md §6) — on the full Chromium channel this is a real read, not a
stub. The media rules still govern: pixel assertions are made on the
*viewer's* `<video>`, never on the sharer's preview.
"""
from __future__ import annotations
import time
import pytest
from playwright.sync_api import expect
from .conftest import frames_matching, start_sharing
pytestmark = [pytest.mark.e2e, pytest.mark.timeout(180)]
@pytest.fixture
def device(base_url, browser, request):
"""Open a page as its own device (isolated context, fresh peer id)."""
opened = []
def _open(path: str = "/", errors: list | None = None):
context = browser.new_context(viewport={"width": 1100, "height": 720})
opened.append(context)
request.addfinalizer(context.close)
page = context.new_page()
if errors is not None:
page.on("pageerror", lambda error: errors.append(f"pageerror: {error}"))
page.goto(f"{base_url}{path}", wait_until="domcontentloaded")
expect(page.locator("#net")).to_have_attribute("data-state", "online", timeout=10_000)
return page
return _open
# Reads the video sender's committed parameters back from the sharer's live
# legs. `state` is the leg's connectionState; `maxBitrate` is the cap the
# leg is actually encoding under (0 or undefined would mean "uncapped").
SENDER_PROBE = """() => {
const probe = window.__probe;
if (!probe) return null;
return [...probe.peers.values()].map((peer) => {
const sender = peer.pc.getSenders().find(
(s) => s.track && s.track.kind === "video"
);
if (!sender) return null;
const params = sender.getParameters();
const encodings = params.encodings || [];
return {
state: peer.pc.connectionState,
degradationPreference: params.degradationPreference,
maxBitrate: encodings.length ? encodings[0].maxBitrate : null,
};
});
}"""
def _wait_for(sharer, want: int, pred, timeout: float = 45.0) -> list:
"""Poll the sharer's legs until `want` of them satisfy `pred` (or give up)."""
legs: list = []
deadline = time.time() + timeout
while time.time() < deadline:
legs = sharer.evaluate(SENDER_PROBE) or []
if len(legs) == want and all(leg and pred(leg) for leg in legs):
return legs
time.sleep(0.5)
return legs
class TestSenderFidelity:
def test_two_live_legs_report_maintain_resolution_and_the_cap(self, device, base_url):
import httpx
cap = httpx.get(f"{base_url}/api/config", timeout=5).json()["maxBitrateBps"]
assert cap > 0
errors: list = []
sharer = device("/mirror", errors)
start_sharing(sharer)
viewers = [device("/watch", errors) for _ in range(2)]
for viewer in viewers:
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
legs = _wait_for(sharer, 2, lambda leg: leg["state"] == "connected")
assert len(legs) == 2, f"the sharer has {len(legs)} legs, wanted 2: {legs}"
for leg in legs:
assert leg["state"] == "connected", legs
assert leg["degradationPreference"] == "maintain-resolution", leg
assert leg["maxBitrate"] == cap, leg
# The parameters are not a facade: the pixels actually arrive, moving.
for viewer in viewers:
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"a viewer froze: {frames}"
expect(sharer.locator("#viewer-count")).to_have_text("2", timeout=10_000)
assert errors == [], f"uncaught browser errors: {errors}"
def test_the_quality_survives_a_renegotiation(self, device, base_url):
"""The bug the post-negotiation re-apply exists for.
A live leg is renegotiated in place — a second offer on the same
RTCPeerConnection, exactly what a surface switch or a viewer that
re-joined does. The re-offer resets the encodings; the parameters
must be back by the time the renegotiation completes, and the wall
must still be moving on the viewer.
"""
import httpx
cap = httpx.get(f"{base_url}/api/config", timeout=5).json()["maxBitrateBps"]
errors: list = []
sharer = device("/mirror", errors)
start_sharing(sharer)
viewer = device("/watch", errors)
expect(viewer.locator(".tile[data-state='live']")).to_have_count(1, timeout=25_000)
legs = _wait_for(sharer, 1, lambda leg: leg["state"] == "connected")
assert legs and legs[0]["state"] == "connected", legs
assert legs[0]["degradationPreference"] == "maintain-resolution", legs
assert legs[0]["maxBitrate"] == cap, legs
immediate = sharer.evaluate(
"""async () => {
const [id, peer] = [...window.__probe.peers.entries()][0];
await window.__probe.renegotiate(id);
const sender = peer.pc.getSenders().find(
(s) => s.track && s.track.kind === "video"
);
const params = sender.getParameters();
const encodings = params.encodings || [];
return {
state: peer.pc.connectionState,
degradationPreference: params.degradationPreference,
maxBitrate: encodings.length ? encodings[0].maxBitrate : null,
};
}"""
)
# renegotiate() awaits setLocalDescription *and* the re-apply before
# it resolves, so the parameters must already be back — whatever the
# leg's connection state is at that instant.
assert immediate["degradationPreference"] == "maintain-resolution", immediate
assert immediate["maxBitrate"] == cap, immediate
# ...and once the leg reports `connected` again, the connected-state
# re-apply confirms them and the picture is still moving.
legs = _wait_for(sharer, 1, lambda leg: leg["state"] == "connected")
assert legs and legs[0]["state"] == "connected", legs
assert legs[0]["degradationPreference"] == "maintain-resolution", legs
assert legs[0]["maxBitrate"] == cap, legs
frames = frames_matching(viewer, ".tile video")
assert frames["distinct"] >= 2, f"the leg froze across the renegotiation: {frames}"
assert errors == [], f"uncaught browser errors: {errors}"
+122 -6
View File
@@ -10,6 +10,28 @@ Skipped unless ``MIRROR_REALDISPLAY=1``, because it needs an X server binary and
a headed browser::
MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay
Measured on the reference Linux host (Xvfb 1280x800x24, headed Chromium,
phase 02, 2026-11-01) — requested vs delivered, per sharer window size:
=================== ============ ============ =====================
sharer window requested delivered viewer decodes
=================== ============ ============ =====================
1200x760 1200x760 1200x750 1200x750 (93.75% of desktop)
1024x700 1024x700 1024x640 1024x640 (80% -> fails the floor)
800x600 800x600 800x500 800x500 (62.5% -> fails the floor)
=================== ============ ============ =====================
* ``requested`` is ``screen x devicePixelRatio``; under Playwright ``screen``
tracks the browser window, so the request can never outgrow the window here.
* Chromium *still* clamps a monitor capture to the capturing window even with
an explicit ``ideal`` size named — which agrees with PLAN §5 ("Chromium
scales a monitor capture to the capturing window"). Removing the phase 02
size constraints (frameRate only) delivered the identical 1200x750 for a
1200x760 window, so on this host the floor discriminates by *window* size,
not by the constraints. On real hardware ``screen`` is the true display
resolution, so a small window on a large display is the case the 90% floor
and the share page's 75% toast are for.
"""
from __future__ import annotations
@@ -35,11 +57,18 @@ pytestmark = [
),
]
# Deliberately not 16:9: Chromium's fake device reports 1280x720 no matter what,
# so an aspect ratio of exactly 1280/800 is a fingerprint of the real screen.
# Deliberately not 16:9: an aspect ratio of exactly 1280/800 is a fingerprint
# of the real screen. (The fake device, where it is used, defaults to 1280x720
# and, once a size is requested, clamps to the capturing window — PLAN §5.)
XVFB_GEOMETRY = "1280x800x24"
XVFB_ASPECT = 1280 / 800
FAKE_DEVICE_SIZE = (1280, 720)
# The sharpness floor: 90% of the desktop width (1152 of 1280 px). An exact
# 100% match is environment-specific (compositor, fractional DPI, window
# chrome), but a window-clamped capture of a small share page lands at 62-93%
# of the desktop — that is where the fuzziness a person sees lives.
XVFB_WIDTH = 1280
SHARP_FLOOR_PX = int(XVFB_WIDTH * 0.9)
# Flags learned the hard way, and worth keeping written down:
#
@@ -240,8 +269,11 @@ class TestRealX11Capture:
f"got exactly {size}: that is Chromium's fake capture device, not the X11 screen"
)
assert settings["width"] >= 640, f"implausibly small capture: {settings}"
# Chromium scales a monitor capture to the capturing window, so compare
# the aspect ratio: 1280x800 in, 1200x750 out is the real screen.
# Measured after phase 02: the 1200x760 window requests 1200x760
# (Playwright emulates screen == window) and Chromium still clamps the
# monitor capture to the capturing window: 1280x800 desktop in, 1200x750
# out, aspect 1.6000 preserved. So compare the aspect ratio, not
# absolute pixels (PLAN §5).
assert abs(settings["width"] / settings["height"] - XVFB_ASPECT) < 0.06, (
f"{size} does not match the {XVFB_GEOMETRY} desktop aspect "
f"({XVFB_ASPECT:.3f}); this is not our Xvfb screen"
@@ -276,8 +308,10 @@ class TestRealX11Capture:
time.sleep(0.28)
result = watch_page.evaluate("() => window.__probe")
assert result["width"] >= 640 and result["height"] >= 400, (
f"the watcher decoded no picture: {result}"
assert result["width"] >= SHARP_FLOOR_PX, (
f"the watcher decoded a {result['width']}px-wide picture: the floor is "
f"{SHARP_FLOOR_PX}px (90% of the {XVFB_GEOMETRY} desktop); below it the "
f"wall shows a window-clamped capture, not the screen: {result}"
)
assert abs(result["width"] / result["height"] - XVFB_ASPECT) < 0.06, result
assert result["distinct"] >= 2, (
@@ -294,3 +328,85 @@ class TestRealX11Capture:
watch_page.close()
share_page.close()
def test_sharp_picture_reaches_the_wall(self, base_url, share_page, watch_page):
"""The size floor that makes \"sharper\" an assertion.
The viewer's decoded width must be at least 90% of the Xvfb desktop
(1152 of 1280 px), the picture must keep moving in the same probe (a
large-but-frozen picture must not pass), and the roster must not lie
about what is on the wire: the published ``/api/streams`` width/height
sit within one rounding step of both the sharer's
``track.getSettings()`` and the viewer's decoded size.
Measured on this host (phase 02, 2026-11-01): the 1200x760 share
window requests 1200x760 (Playwright emulates ``screen`` == viewport)
and Chromium clamps the monitor capture to the capturing window, so the
viewer decodes 1200x750 — 93.75% of the desktop, over the floor.
Removing the phase 02 size constraints delivered the identical 1200x750
here (the request cannot outgrow the window under Playwright), while a
1024x700 window delivered 1024x640 (80%) — under the floor. On real
hardware ``screen`` is the true display resolution, so a small window
on a large display is the case this floor and the share page's 75%
toast are for.
"""
errors: list[str] = []
share_page.on("pageerror", lambda error: errors.append(str(error)))
share_page.locator("#start").click()
expect(share_page.locator("body")).to_have_attribute("data-live", "on", timeout=40_000)
settings = share_page.evaluate(
"""() => {
const track = document.querySelector('#preview').srcObject.getVideoTracks()[0];
const s = track.getSettings();
return {width: s.width, height: s.height, surface: s.displaySurface};
}"""
)
assert settings["surface"] == "monitor", f"not a monitor capture: {settings}"
expect(watch_page.locator(".tile[data-state='live']")).to_have_count(1, timeout=60_000)
# Start measuring on the watcher, then paint: cycling the captured
# machine's background is what a real presenter's screen does constantly.
assert watch_page.evaluate(PROBE) == "started"
for colour in ("#c81e1e", "#0b0d10", "#1e6ec8", "#0b0d10", "#1ec85a"):
share_page.evaluate("(colour) => { document.body.style.background = colour; }", colour)
time.sleep(0.28)
result = watch_page.evaluate("() => window.__probe")
assert result["width"] >= SHARP_FLOOR_PX, (
f"the watcher decoded a {result['width']}px-wide picture: the floor is "
f"{SHARP_FLOOR_PX}px (90% of the {XVFB_GEOMETRY} desktop); below it the "
f"wall is a window-clamped capture, not the screen: {result}"
)
assert abs(result["width"] / result["height"] - XVFB_ASPECT) < 0.06, (
f"{result} does not match the {XVFB_GEOMETRY} desktop aspect "
f"({XVFB_ASPECT:.3f}); this is not our Xvfb screen"
)
assert result["distinct"] >= 2, (
f"the watcher received a frozen frame: {result} — a large-but-still "
f"picture must not pass a sharpness test"
)
# The roster must not lie about what is on the wire: the published
# size sits within one rounding step of the sharer's delivered
# settings *and* the viewer's decoded size.
time.sleep(0.6)
mirror = httpx.get(f"{base_url}/api/streams", timeout=5).json()["mirrors"][0]
for source, (w, h) in {
"the sharer's track.getSettings()": (settings["width"], settings["height"]),
"the viewer's decoded size": (result["width"], result["height"]),
}.items():
assert abs(mirror["width"] - w) <= 1, (
f"roster width {mirror['width']} vs {w} from {source}: the roster must "
f"not lie about what is on the wire"
)
assert abs(mirror["height"] - h) <= 1, (
f"roster height {mirror['height']} vs {h} from {source}: the roster must "
f"not lie about what is on the wire"
)
# And the sharer agrees that someone is watching its desktop.
expect(share_page.locator("#viewer-count")).to_have_text("1", timeout=20_000)
assert errors == [], f"uncaught browser errors: {errors}"
+61
View File
@@ -130,6 +130,67 @@ class TestClientScripts:
assert f'src="/static/{script}"' in html
assert 'type="module"' in html
def test_share_never_asks_for_an_exact_capture_size(self):
"""A hard size breaks pickers: `exact` fails or hides picker entries on
displays/DPRs the browser cannot honour. The size request must stay a
preference the browser can decline while still capturing."""
source = (STATIC / "share.js").read_text()
assert not re.search(r"\bexact\s*:", source), (
"share.js must not use an `exact` constraint key"
)
def test_server_and_client_agree_on_the_bitrate_default(self):
"""`/api/config` advertises the server's per-leg cap; a browser that cannot
reach it falls back to the hardcoded literal in `net.js`. If the two drift,
offline clients silently get a different picture quality and nothing fails.
One number, two places, one test that notices."""
server = int(
re.search(
r"DEFAULT_MAX_BITRATE_BPS\s*=\s*(\d[\d_]*)",
(STATIC.parent / "config.py").read_text(),
)
.group(1)
.replace("_", "")
)
client = int(re.search(r"maxBitrateBps:\s*(\d+)", (STATIC / "net.js").read_text()).group(1))
assert server == client, (
f"the server default ({server}) and the net.js fallback ({client}) "
"have drifted: a client that cannot reach /api/config would use "
"a different bitrate silently"
)
def test_sender_quality_is_reapplied_on_negotiation_and_connection(self):
"""`setParameters` is per-negotiation: a re-offer (a surface switch,
a viewer that re-joined) resets the encodings. The cap must therefore
be re-applied after `setLocalDescription` *and* when the leg becomes
`connected`. Both call sites are asserted so a future edit cannot drop
one and silently soften the wall."""
source = (STATIC / "share.js").read_text()
assert source.count('"maintain-resolution"') == 1, (
"the degradation preference must be a single, named decision"
)
assert "async function applySenderQuality" in source
def section(start: str, stop: str) -> str:
begin = source.index(start)
return source[begin : source.index(stop, begin)]
negotiate = section("async function negotiate(viewerId)", "async function onSignal")
assert "applySenderQuality" in negotiate, (
"the cap is not re-applied after setLocalDescription"
)
assert negotiate.index("setLocalDescription") < negotiate.index("applySenderQuality"), (
"the cap is applied before the encodings exist"
)
connected = section(
"pc.onconnectionstatechange = () => {",
"for (const track of state.stream.getTracks())",
)
assert re.search(
r'connectionState\s*===\s*"connected".*applySenderQuality', connected, re.S
), "the cap is not re-applied when the leg becomes connected"
def test_the_two_pages_share_no_element_ids_but_the_shared_chrome(self):
"""Both pages consume one stylesheet, so a duplicated id means a colliding rule.
+8 -1
View File
@@ -6,7 +6,13 @@ import pytest
from mirror import __main__ as entry
from mirror.access import ConfigError, parse_cidrs
from mirror.config import DEFAULT_PORT, Settings, lan_addresses, parse_ice_servers
from mirror.config import (
DEFAULT_MAX_BITRATE_BPS,
DEFAULT_PORT,
Settings,
lan_addresses,
parse_ice_servers,
)
from mirror.debug import maybe_enable_debugpy
@@ -39,6 +45,7 @@ class TestSettings:
assert settings.port == DEFAULT_PORT
assert settings.host == "0.0.0.0"
assert settings.ice_servers == []
assert settings.max_bitrate_bps == DEFAULT_MAX_BITRATE_BPS
assert settings.max_streams == 0
# Unrestricted until told otherwise, and only loopback may speak for a client.
assert settings.allow_cidrs == ()