#!/usr/bin/env python3 """Exercise actual i3 IPC on a private Xvfb display; never touch the live WM.""" import os from pathlib import Path import subprocess import sys import tempfile sys.dont_write_bytecode = True from native_test_session import run_private_session from native_x11 import wait_for ROOT = Path(__file__).resolve().parents[1] def inside(): env = dict(os.environ, GOCACHE="/tmp/cthulhu-go-cache", GOPROXY="off") subprocess.run(["go", "test", "./internal/i3ipc", "-run", "^TestNativeI3Unavailable$", "-count=1", "-v"], cwd=ROOT, env=dict(env, CTHULHU_NATIVE_I3_UNAVAILABLE="1"), check=True, timeout=60) with tempfile.TemporaryDirectory(prefix="cthulhu-i3-") as directory: config = Path(directory) / "config" config.write_text('font pango:monospace 8\nfocus_follows_mouse no\n' 'mode "personal" {\n bindsym Escape mode "default"\n}\n' 'mode "ratpoison" {\n bindsym Escape mode "default"\n}\n' 'mode "panel" {\n bindsym Escape mode "default"\n}\n' 'mode --pango_markup "marked & mode" {\n bindsym Escape mode "default"\n}\n') with (Path(directory) / "i3.log").open("w+") as log: wm = subprocess.Popen(["i3", "-c", str(config)], env=env, stdout=log, stderr=log) try: def ready(): if wm.poll() is not None: log.seek(0) raise RuntimeError(log.read()) result = subprocess.run(["i3", "--get-socketpath"], env=env, capture_output=True, text=True) return result.returncode == 0 and Path(result.stdout.strip()).is_socket() wait_for(ready, "private i3 did not start") subprocess.run(["go", "test", "./internal/i3ipc", "-run", "^TestNativeI3(Events|EmptyWorkspaceFocus)$", "-count=1", "-v", "-timeout=30s"], cwd=ROOT, env=dict(env, CTHULHU_NATIVE_I3="1"), check=True, timeout=60) finally: wm.terminate() wm.wait(timeout=5) def main(): if "--inside" in sys.argv: inside() return read_fd, write_fd = os.pipe() server = subprocess.Popen(["Xvfb", "-displayfd", str(write_fd), "-screen", "0", "1024x768x24", "-nolisten", "tcp"], pass_fds=(write_fd,), stderr=subprocess.DEVNULL) os.close(write_fd) try: with os.fdopen(read_fd) as reader: display = reader.readline().strip() assert display, "Xvfb failed" env = dict(os.environ, DISPLAY=":" + display) for key in ("DBUS_SESSION_BUS_ADDRESS", "AT_SPI_BUS_ADDRESS", "WAYLAND_DISPLAY", "I3SOCK"): env.pop(key, None) run_private_session(["dbus-run-session", "--", sys.executable, str(Path(__file__).resolve()), "--inside"], env=env, check=True, timeout=150) finally: server.terminate() server.wait(timeout=5) if __name__ == "__main__": main()