summaryrefslogtreecommitdiff
path: root/tests/helpers/run_reconnect.py
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 23:52:22 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 23:52:22 +0300
commit563b23a33726289387193b85d90fb569631ee05f (patch)
treeddf438338034b5ab2690b531684906999e56df44 /tests/helpers/run_reconnect.py
parent76073fe5fad8799e5850805f2f090af2cb62c741 (diff)
Reconnect to a restarted Wayland compositor
Windows now outlive the compositor. On connection loss YASL sends DISPLAY_LOST instead of closing every window, retries the connection on a loop timer, rebuilds each toplevel with its title, size, state and GL context, and sends DISPLAY_RESTORED. CPU windows keep their pixels; GPU renderers drop Vulkan surfaces and GL objects on loss and rebuild them on restore. - Free the dead connection's objects on the next wait, after the application has released GPU objects built on them. - Report a lost connection as an event rather than a failed wait. - Refuse window and Vulkan surface creation while offline with the new YASL_ERROR_DISCONNECTED. - Close popups, cancel drags and fail pending clipboard requests on loss. - Print only protocol errors, not ordinary disconnects. - Examples survive a restart; game.c rebinds its GL context. - Add an end-to-end test that kills Weston under CPU, GL and Vulkan windows and requires them to recover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tests/helpers/run_reconnect.py')
-rw-r--r--tests/helpers/run_reconnect.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/tests/helpers/run_reconnect.py b/tests/helpers/run_reconnect.py
new file mode 100644
index 0000000..e86e994
--- /dev/null
+++ b/tests/helpers/run_reconnect.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+"""Kill Weston under a running client, start a new one on the same socket, and
+require the client to reconnect: run_reconnect.py <weston> <client>."""
+import os
+from pathlib import Path
+import signal
+import subprocess
+import sys
+import tempfile
+import time
+
+
+def start_weston(weston, root, env, log):
+ process = subprocess.Popen([weston, '--backend=headless', '--renderer=gl', '--socket=yasl-test',
+ '--idle-time=0', '--no-config', '--width=1024', '--height=768'],
+ env=env, stdout=log, stderr=log)
+ deadline = time.monotonic() + 12
+ while not (root/'yasl-test').is_socket():
+ if process.poll() is not None or time.monotonic() > deadline:
+ raise RuntimeError('Weston did not start')
+ time.sleep(0.02)
+ return process
+
+
+def expect(client, word):
+ line = client.stdout.readline().strip()
+ if line != word:
+ raise RuntimeError(f'client printed {line!r}, expected {word!r}')
+
+
+def main():
+ weston, binary = sys.argv[1:]
+ signal.alarm(50)
+ with tempfile.TemporaryDirectory(prefix='yasl-reconnect-') as directory:
+ root = Path(directory)
+ env = os.environ.copy()
+ env.pop('WAYLAND_SOCKET', None)
+ env.update(XDG_RUNTIME_DIR=directory, WAYLAND_DISPLAY='yasl-test', LIBGL_ALWAYS_SOFTWARE='1')
+ lavapipe = next(Path('/usr/share/vulkan/icd.d').glob('*lvp*.json'), None)
+ if lavapipe:
+ env['VK_DRIVER_FILES'] = str(lavapipe)
+ with (root/'weston.log').open('w+') as log:
+ servers = [start_weston(weston, root, env, log)]
+ client = subprocess.Popen([binary], env=env, stdout=subprocess.PIPE, text=True)
+ try:
+ expect(client, 'ready')
+ servers[0].send_signal(signal.SIGKILL)
+ servers[0].wait()
+ expect(client, 'lost')
+ time.sleep(0.5)
+ servers.append(start_weston(weston, root, env, log))
+ expect(client, 'restored')
+ if client.wait(timeout=15) != 0:
+ raise RuntimeError(f'client exited with {client.returncode}')
+ except BaseException:
+ client.kill()
+ log.flush(); log.seek(0); print(log.read(), file=sys.stderr)
+ raise
+ finally:
+ for server in servers:
+ if server.poll() is None:
+ server.terminate()
+ server.wait(timeout=5)
+
+
+if __name__ == '__main__':
+ main()