Files
daynivo-kiosk-os/tests/test_browser.py
T
rothmanandClaude Opus 5.5 6733aacb6e
CI / test-bookworm (push) Successful in 29s
CI / test-latest (push) Successful in 33s
Rename the Python package to daynivo_kiosk
src/voxip_kiosk -> src/daynivo_kiosk, with every import, the launchers,
install.sh, the Makefile and the manager's gunicorn app path. An upgrade
replaces /usr/lib/voxip-kiosk/python as a whole, so the old package
disappears; tested by upgrading an installation of the previous commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 23:52:39 +01:00

103 lines
4.4 KiB
Python

import json
from pathlib import Path
from urllib.parse import parse_qs, urlsplit
from daynivo_kiosk import browser as b
from daynivo_kiosk.config import DEFAULTS
XRANDR = """Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 7680 x 7680
HDMI-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 531mm x 299mm
1920x1080 60.00*+ 50.00 59.94
1280x720 60.00 50.00 59.94
720x576 50.00
HDMI-2 disconnected (normal left inverted right x axis y axis)
"""
def test_build_args_never_weakens_tls_and_binds_devtools_locally(tmp_path):
args = b.build_args("/usr/bin/chromium", dict(DEFAULTS), tmp_path / "p", tmp_path / "c", "file:///start.html", (1920, 1080))
joined = " ".join(args)
for flag in b.FORBIDDEN_FLAGS:
assert flag not in joined
assert "--remote-debugging-address=127.0.0.1" in args
assert "--kiosk" in args and "--noerrdialogs" in args and "--disable-session-crashed-bubble" in args
assert "--window-size=1920,1080" in args
assert args[-1] == "file:///start.html"
assert not any(a.startswith("--force-device-scale-factor") for a in args)
def test_build_args_zoom(tmp_path):
args = b.build_args("/usr/bin/chromium", dict(DEFAULTS, zoom=1.5), tmp_path, tmp_path, "x")
assert "--force-device-scale-factor=1.5" in args
def test_parse_xrandr():
outputs = b.parse_xrandr(XRANDR)
assert len(outputs) == 1
out = outputs[0]
assert out["name"] == "HDMI-1"
assert out["modes"] == ["1920x1080", "1280x720", "720x576"]
assert out["current"] == "1920x1080@60.00"
assert out["preferred"] == "1920x1080"
assert out["size"] == (1920, 1080)
def test_xrandr_args_rotation_and_resolution():
out = b.parse_xrandr(XRANDR)[0]
assert b.xrandr_args(out, dict(DEFAULTS, rotation=90)) == ["xrandr", "--output", "HDMI-1", "--auto", "--rotate", "right"]
assert b.xrandr_args(out, dict(DEFAULTS, rotation=270, resolution="1280x720@50")) == [
"xrandr", "--output", "HDMI-1", "--mode", "1280x720", "--rate", "50", "--rotate", "left"]
# unsupported mode falls back to auto instead of failing
assert "--auto" in b.xrandr_args(out, dict(DEFAULTS, resolution="3840x2160"))
def test_xset_commands():
assert ["xset", "-dpms"] in b.xset_commands(dict(DEFAULTS))
cmds = b.xset_commands(dict(DEFAULTS, screen_always_on=False, screen_off_minutes=15))
assert ["xset", "+dpms"] in cmds and ["xset", "dpms", "0", "0", "900"] in cmds
def test_clean_profile_removes_locks_and_crash_flag(tmp_path):
profile = tmp_path / "profile"
(profile / "Default").mkdir(parents=True)
(profile / "SingletonLock").symlink_to("kiosk-1234")
(profile / "Default" / "Preferences").write_text(json.dumps({"profile": {"exit_type": "Crashed", "exited_cleanly": False}, "x": 1}))
b.clean_profile(profile)
assert not (profile / "SingletonLock").is_symlink()
prefs = json.loads((profile / "Default" / "Preferences").read_text())
assert prefs["profile"] == {"exit_type": "Normal", "exited_cleanly": True}
assert prefs["x"] == 1
def test_start_page_url_contains_target(paths):
url = b.start_page_url(paths, dict(DEFAULTS, url="https://e.org/x?token=abc", device_name="Hal 1"))
assert url.startswith(f"file://{paths.www_dir}/start.html?")
assert "next=https%3A%2F%2Fe.org%2Fx%3Ftoken%3Dabc" in url and "name=Hal+1" in url
def test_start_page_shows_only_the_masked_link(paths):
url = b.start_page_url(paths, dict(DEFAULTS, url="https://e.org/x?token=geheim123456"))
query = parse_qs(urlsplit(url).query)
assert query["url"] == ["https://e.org/x?token=…3456"]
assert query["admin"][0].endswith(".local:8080")
def test_local_pages_exist():
www = Path(__file__).resolve().parents[1] / "www"
for page in ("start.html", "offline.html", "setup.html", "kiosk.css", "kiosk.js"):
assert (www / page).exists()
def test_prepare_display_waits_for_a_screen_only_after_boot(paths, monkeypatch):
calls = []
monkeypatch.setattr(b, "_run", lambda args: calls.append(args) or None)
monkeypatch.setattr(b.time, "sleep", lambda s: None)
monkeypatch.setattr(b.sysinfo, "uptime_seconds", lambda: 3600.0)
assert b.prepare_display(paths, dict(DEFAULTS)) is None
assert sum(c == ["xrandr", "--query"] for c in calls) == 1
calls.clear()
monkeypatch.setattr(b.sysinfo, "uptime_seconds", lambda: 40.0)
b.prepare_display(paths, dict(DEFAULTS))
assert sum(c == ["xrandr", "--query"] for c in calls) == 15