diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 23:52:22 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 23:52:22 +0300 |
| commit | 563b23a33726289387193b85d90fb569631ee05f (patch) | |
| tree | ddf438338034b5ab2690b531684906999e56df44 /tests/helpers/run_reconnect.py | |
| parent | 76073fe5fad8799e5850805f2f090af2cb62c741 (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.py | 67 |
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() |
