test: xwayland_alt_delete waits for the reaped launcher, not a fixed poll

The 15s os.kill poll asked for trouble (fixed window on a foreign event
loop).  Replaced with kick's own SIGCHLD reap line ([child] pid N
exited, written unbuffered per reaped child) -- the same signal, event
anchored, 30s backstop only.

Two bugs found along the way, both in the test not the product:
- claim pid != reaped pid (sh -c forks; the claim is the grandchild,
  the reap is the direct-child launcher) -- wait on [launch] app=0's pid.
- [child] uses 'pid ' (space) vs [launch]/[claim] 'pid=' -- the first
  version of this wait matched nothing for 30s, deterministically.
  (Also: earlier validation runs silently deselected this marked test;
  always pass -m flaky when validating marked tests.)

Unmarked after 12/12 at -n15 + serial green.
This commit is contained in:
Andrew Hamilton 2026-09-09 21:59:56 +10:00
parent 5ffc051940
commit 52d12bdf2e

View file

@ -4182,7 +4182,6 @@ def test_xwayland_tab_renders_and_cycles(xwayland_session):
f"X11 tab rendered black at ({cx},{cy})"
@pytest.mark.flaky
def test_xwayland_alt_delete_closes_x11_tab(xwayland_session):
"""Alt+Delete on the active X11 tab sends WM_DELETE_WINDOW; xmessage
honors it, exits, and the escalation never needs to fire."""
@ -4194,18 +4193,18 @@ def test_xwayland_alt_delete_closes_x11_tab(xwayland_session):
s.wait_active(1)
got = s.cycle_ack(+1)
assert got == 0
d = dict((int(a), int(p)) for a, p in CLAIM_RE.findall(s.read_log()))
xpid = d[0]
s.chord_ack(ALT, DELETE)
since = time.monotonic()
while time.monotonic() - since < 15.0:
try:
os.kill(xpid, 0)
except ProcessLookupError:
break # xmessage exited from the graceful close
time.sleep(0.1)
else:
pytest.fail(f"xmessage (pid {xpid}) survived Alt+Delete")
# Event, not wall-clock: kick's SIGCHLD handler logs every reaped child
# unbuffered. Watch the LAUNCHER pid ([launch]), not the claim pid: the
# claim is the X client's pid, but sh -c forks so the reaped direct
# child (which exits once its client does) is a different pid. The 30s
# backstop bounds hangs only. (Whether xmessage exits gracefully via
# WM_DELETE or via the escalation SIGTERM, the launcher reaps the same;
# this test asserts teardown + survival either way.)
m = re.search(r"\[launch\] app=0 pid=(\d+)", s.read_log())
assert m, "xmessage launcher never logged"
# NOTE: [child] uses `pid ` (space), unlike [launch]/[claim] `pid=`.
s.wait_for(r"\[child\] pid %s exited" % m.group(1), timeout=30.0)
# The compositor stays up with the remaining Wayland tab.
assert s.proc.poll() is None, "compositor exited after closing X11 tab"
assert s.active() == 1