From 49b3ea4d57fca68cb679da644ae0d7e02f1fa9da Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Sat, 26 Sep 2026 18:24:41 +0200 Subject: [PATCH] Give every xdist worker its own Xvfb (pytest-xvfb) The first -n auto Tests run segfaulted in Tk's focus_force(): keyboard focus is global to an X display, and four workers were sharing the one xvfb-run display, stealing each other's focus. Stressed locally (layout + keyboard tests x40, -n 8): 5 of 2760 failed on a shared display (focus-ring assertions), 0 of 4600 with pytest-xvfb's per-process display -- and faster. The geometry xvfb-run used moves into pyproject; the workflow keeps the Xvfb install guard and drops xvfb-run. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM --- .github/workflows/python-tests.yml | 8 +++++--- app/pubspec.yaml | 2 +- pyproject.toml | 8 ++++++++ requirements.txt | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 1f19d15..8272b8b 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -31,13 +31,15 @@ jobs: # The gate's keyboard and layout tests drive real Tk: widget heights and # the focus ring come from the font engine, and no mock can answer what # they ask. Without a display they do not skip -- they fail, which is how - # this job stayed red while the tests themselves were fine. + # this job stayed red while the tests themselves were fine. pytest-xvfb + # (requirements.txt, geometry in pyproject) starts one Xvfb per xdist + # worker: a shared display let workers steal each other's focus. # ubuntu-latest already ships xvfb, so the unconditional # `apt-get update && install` spent ~7 s to report "already the newest # version"; it now installs only on an image that lacks it. - name: Install a virtual X display run: | - command -v xvfb-run >/dev/null \ + command -v Xvfb >/dev/null \ || { sudo apt-get update && sudo apt-get install -y xvfb; } # -n auto spreads the suite over every runner core (pytest-xdist is in @@ -46,7 +48,7 @@ jobs: # printed all ~1050 test ids. - name: Run tests with coverage run: | - xvfb-run -a -s "-screen 0 1600x1200x24" python -m pytest \ + python -m pytest \ -n auto \ -p no:sugar \ -q diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 5e28b5b..e8f50c3 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -2,7 +2,7 @@ name: diet_guard_app description: "Companion phone app for diet_guard: log meals on the go." publish_to: 'none' -version: 1.0.93+1 +version: 1.0.94+1 environment: sdk: ^3.12.2 diff --git a/pyproject.toml b/pyproject.toml index f75a82c..8855e26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,6 +176,14 @@ filterwarnings = [ "ignore::DeprecationWarning", "default::pytest.PytestUnraisableExceptionWarning", ] +# pytest-xvfb gives every pytest process -- each xdist worker included -- its +# own Xvfb. Keyboard focus is global to an X display, so real-Tk tests from +# several workers sharing one xvfb-run display stole each other's focus +# (focus-ring assertions failed) and Tk segfaulted in focus_force(): 5 of 2760 +# stressed runs failed shared, 0 of 4600 with a display per worker. +xvfb_width = "1600" +xvfb_height = "1200" +xvfb_colordepth = "24" [tool.coverage.run] source = ["diet_guard"] diff --git a/requirements.txt b/requirements.txt index 39dfe65..10e34b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,5 +16,6 @@ pytest-cov==7.1.0 pytest-randomly==5.0.0 pytest-sugar==1.1.1 pytest-xdist==3.8.0 +pytest-xvfb==3.1.1 requests==2.34.2 ruff==0.16.9