prole/tests/test_dashboard_systemd_unit.py
chrisfu 17cb827be5 test(dashboard): add unit tests for systemd unit and script validation
- Ensure dashboard service doesn't create an ordering cycle with `multi-user.target`.
- Verify service safely attaches to a virtual terminal (VT) and passes VT to Xorg.
- Ensure no `su` usage by default in the service.
- Validate script behavior for passing VT and `-keeptty` options to Xorg.

chore(dashboard): update systemd unit to avoid VT conflicts and improve logging

- Remove `After` and `Wants` directives for `multi-user.target` to prevent conflicts.
- Add `TTYPath`, `StandardInput`, and related options for VT attachment.
- Ensure `ExecStopPost` restores getty service for the dashboard VT.

fix(dashboard): improve Xorg resolution and clean up script logic

- Dynamically determine Xorg executable location in `dashboard.sh`.
- Pass VT, display, and `-keeptty` to Xorg to improve script reliability.

fix(mariadb): correct exFAT mount options for external storage

- Avoid `chown` failures by setting root ownership with group access for `mysql`.
- Update external mount options to `uid=0,gid=mysql,umask=0002`.

cleanup(mariadb): remove unnecessary owner/group permissions from migration marker task
2026-03-13 01:49:57 -07:00

55 lines
1.7 KiB
Python

from __future__ import annotations
from pathlib import Path
def _project_root() -> Path:
# This test file lives in `<root>/tests/`.
return Path(__file__).resolve().parents[1]
def _render_dashboard_service(*, vt: int = 1) -> str:
template_path = (
_project_root()
/ "infrastructure/roles/dashboard/templates/dashboard.service.j2"
)
template = template_path.read_text(encoding="utf-8")
# Keep this test dependency-free (no Jinja2 import required).
return (
template.replace("{{ dashboard_vt }}", str(vt))
.replace("{{ dashboard_script_dest }}", "/usr/local/bin/dashboard.sh")
.replace("{{ dashboard_user }}", "pi")
)
def test_dashboard_service_is_safe_for_multi_user_target() -> None:
rendered = _render_dashboard_service(vt=1)
# Avoid an ordering cycle with the target that wants the service.
assert "After=multi-user.target" not in rendered
assert "Wants=multi-user.target" not in rendered
assert "WantedBy=multi-user.target" in rendered
def test_dashboard_service_attaches_to_a_vt_and_passes_vt_to_script() -> None:
rendered = _render_dashboard_service(vt=1)
assert "TTYPath=/dev/tty1" in rendered
assert "StandardInput=tty" in rendered
assert "Environment=DASHBOARD_VT=1" in rendered
def test_dashboard_service_does_not_use_su_by_default() -> None:
rendered = _render_dashboard_service(vt=1)
assert "su -l" not in rendered
def test_dashboard_script_passes_vt_and_keeptty_to_xorg() -> None:
script_path = _project_root() / "tools/dashboard.sh"
script = script_path.read_text(encoding="utf-8")
assert "DASHBOARD_VT" in script
assert "vt${DASHBOARD_VT}" in script
assert "-keeptty" in script