Files
feresaria/scripts/ci/run-native-checks.py
T
Samuel Onoja 7a7df0106c Start with defaults when configuration is invalid (#29)
Invalid configuration currently prevents login. Ferese now starts with built-in defaults and shows a notification when the shell is ready, leaving the file untouched. Loading and validation belong to the config module, while the theme module resolves appearance. Validation remains strict, and failed live reloads keep the active settings.

The native Morph regression checks the animated input region and idle frame scheduling while its backing surface stays allocated.

Validation: workspace and Python tests, formatting, Clippy, release build, and isolated Wayland startup/reload and panel-motion tests. Native CI includes the startup regression.

Related: #28.
2026-10-12 13:18:50 +01:00

93 lines
4.4 KiB
Python

"""Run native regressions on a private software-rendered Weston host."""
import argparse
import os
from pathlib import Path
import signal
import subprocess
import sys
import tempfile
import time
def stop(process):
if process.poll() is None:
os.killpg(process.pid, signal.SIGINT)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(process.pid, signal.SIGKILL)
process.wait(timeout=5)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--log-dir", type=Path, required=True)
parser.add_argument("--suite", choices=("panel-xwayland", "desktop"), default="panel-xwayland")
args = parser.parse_args()
logs = args.log_dir.resolve()
logs.mkdir(parents=True, exist_ok=True)
repo = Path(__file__).resolve().parents[2]
env = {key: value for key, value in os.environ.items()
if not key.startswith("FERESE_") or key.startswith("FERESE_TEST_")}
for key in ("DISPLAY", "WAYLAND_DISPLAY", "WAYLAND_SOCKET", "XAUTHORITY",
"DBUS_SESSION_BUS_ADDRESS", "DBUS_SESSION_BUS_PID", "EGL_PLATFORM"):
env.pop(key, None)
env.update(LIBGL_ALWAYS_SOFTWARE="1", FERESE_TEST_LOG_DIR=str(logs))
for key, value in {"FERESE_TEST_BINARY": "target/debug/ferese",
"FERESE_TEST_CTL": "target/debug/feresectl",
"FERESE_TEST_SHELL": "target/debug/ferese-shell"}.items():
env.setdefault(key, value)
with tempfile.TemporaryDirectory(prefix="ferese-native-host-") as temporary:
root = Path(temporary)
runtime = root / "runtime"
runtime.mkdir(mode=0o700)
env.update(XDG_RUNTIME_DIR=str(runtime), WAYLAND_DISPLAY="ferese-test-host",
XDG_CONFIG_HOME=str(root / "config"), XDG_STATE_HOME=str(root / "state"),
XDG_CACHE_HOME=str(root / "cache"))
with (logs / "weston.log").open("w") as log:
host = subprocess.Popen([
env.get("FERESE_TEST_WESTON", "weston"),
"--backend=headless-backend.so", "--renderer=pixman",
"--width=1600", "--height=1000", "--socket=ferese-test-host",
"--idle-time=0", "--no-config",
], env=env, stdout=log, stderr=log, start_new_session=True)
try:
deadline = time.monotonic() + 15
while not (runtime / env["WAYLAND_DISPLAY"]).is_socket():
if host.poll() is not None or time.monotonic() >= deadline:
raise RuntimeError((logs / "weston.log").read_text())
time.sleep(.05)
cases = [
("shell-flat", "shell_motion", {"FERESE_TEST_SHELL_MOTION": "1", "FERESE_TEST_BAR_LAYOUT": "flat"}),
("shell-floating", "shell_motion", {"FERESE_TEST_SHELL_MOTION": "1", "FERESE_TEST_BAR_LAYOUT": "floating"}),
("invalid-config", "startup_config", {"FERESE_TEST_STARTUP_CONFIG": "1"}),
]
if args.suite == "desktop":
cases.insert(0, ("lock", "lock", {"FERESE_TEST_LOCK": "1", "FERESE_TEST_BIN_DIR": "target/debug"}))
cases.extend([
("presentation", "presentation", {"FERESE_TEST_PRESENTATION": "1"}),
("resize", "resize_dependencies", {"FERESE_TEST_RESIZE": "1"}),
])
else:
cases.append(("xwayland", "xwayland", {"FERESE_TEST_XWAYLAND": "1"}))
for name, script, options in cases:
print(f"Running {name}", flush=True)
with (logs / f"{name}-test.log").open("w") as output:
test = subprocess.Popen([
sys.executable, f"scripts/tests/test_{script}_isolated.py", "-v",
], cwd=repo, env=dict(env, **options), stdout=output, stderr=output,
start_new_session=True)
try:
status = test.wait(timeout=180)
if status:
raise RuntimeError((logs / f"{name}-test.log").read_text())
finally:
stop(test)
print(f"Passed {name}", flush=True)
finally:
stop(host)
if __name__ == "__main__":
main()