VoxIP Kiosk OS 1.0.0: Raspberry Pi kiosk with web management
Chromium kiosk without a desktop for the Raspberry Pi 3, a Flask web interface on port 8080 (kiosk, system and network management), a restricted root helper, network changes with automatic rollback, a healthcheck timer, install/update/uninstall scripts and a pi-gen image build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
a33c4822bf
96 files changed
+7535
No files matched your search
@@ -0,0 +1,80 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from voxip_kiosk import browser as b
|
||||
from voxip_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_local_pages_exist():
|
||||
www = Path(__file__).resolve().parents[1] / "www"
|
||||
for page in ("start.html", "offline.html", "setup.html", "kiosk.css", "logo.svg"):
|
||||
assert (www / page).exists()
|
||||
Reference in new issue
Block a user