From 61d6423fdd38e98ba230e73b5224d8290e7da7ee Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 31 Oct 2026 14:36:42 -0700 Subject: [PATCH 1/2] test(e2e): handover needs two tiled containers on the workspace, or says so Scenario precondition fix; the check "the unmanaged window is inside the work area and not on a tile of the layout" itself stays as strict as it was. The KDE VM suite vm-commands failed it on a calm host, on the original komorebi-for-kde tip (7d19fd40) and on the refactored stage alike, with the same numbers each time: work area (0,0,1920,1080), layout a single tile (10,10,1900,1060), win3 at (10,10,1896,1050) (within the 24 px tolerance of that tile), win1/win2/win5 parked on workspace 3. After the sweep win3 was the only window on its workspace. Unmanaging a lone window leaves it on the tile it was put on, and an emptied workspace has nothing to calculate, so it keeps its last layout; "not on a tile" could never hold. The scenario now checks first that the focused workspace has at least two tiled containers and, if not, fails with a message that says so (and the describe() dump) instead of the misleading unmanage failure. Windows runs handover as its own suite with its three tiled clients on workspace 0, so the precondition holds there. The same file lives in e2e/lib and in komorebi-for-kde/nix/tests/vm/lib; both are edited alike. A fake-platform test covers the precondition; the existing handover cases still fail where they should. Native pytest of the VM lib: 320 passed; ruff check and format clean. VM verification: not yet (vm-commands on baseline-with-fix and candidate, ~20 min each, after the KDE VM run). --- e2e/lib/komorebi_vm/core/scenarios/handover.py | 13 +++++++++++++ .../vm/lib/komorebi_vm/core/scenarios/handover.py | 13 +++++++++++++ .../nix/tests/vm/lib/tests/test_moved.py | 13 ++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/e2e/lib/komorebi_vm/core/scenarios/handover.py b/e2e/lib/komorebi_vm/core/scenarios/handover.py index 9f1a75bb..439ee301 100644 --- a/e2e/lib/komorebi_vm/core/scenarios/handover.py +++ b/e2e/lib/komorebi_vm/core/scenarios/handover.py @@ -22,7 +22,20 @@ def run(platform: Platform, checks: Checks, clients: list[Client]) -> None: They take a window out of the daemon's hands, so a sweep of commands does not run them. The window is tiled again at the end. + + There have to be two containers or more on the focused workspace. A window that is alone there + stays on the tile it was put on, and an emptied workspace keeps its last layout (the daemon has + nothing to calculate), so "not on a tile of the layout" could never hold: the scenario says so + and stops, rather than fail on a precondition that was never met. """ + tiled = len(platform.state().workspace().containers) + if not checks.check( + "the focused workspace has two tiled containers or more, for a window to be let go of" + f" (it has {tiled})", + tiled >= 2, + ): + print(describe(platform, clients)) + return title = platform.state().focused_title() target = Client(title) before = platform.state().managed() diff --git a/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/core/scenarios/handover.py b/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/core/scenarios/handover.py index 9f1a75bb..439ee301 100644 --- a/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/core/scenarios/handover.py +++ b/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/core/scenarios/handover.py @@ -22,7 +22,20 @@ def run(platform: Platform, checks: Checks, clients: list[Client]) -> None: They take a window out of the daemon's hands, so a sweep of commands does not run them. The window is tiled again at the end. + + There have to be two containers or more on the focused workspace. A window that is alone there + stays on the tile it was put on, and an emptied workspace keeps its last layout (the daemon has + nothing to calculate), so "not on a tile of the layout" could never hold: the scenario says so + and stops, rather than fail on a precondition that was never met. """ + tiled = len(platform.state().workspace().containers) + if not checks.check( + "the focused workspace has two tiled containers or more, for a window to be let go of" + f" (it has {tiled})", + tiled >= 2, + ): + print(describe(platform, clients)) + return title = platform.state().focused_title() target = Client(title) before = platform.state().managed() diff --git a/komorebi-for-kde/nix/tests/vm/lib/tests/test_moved.py b/komorebi-for-kde/nix/tests/vm/lib/tests/test_moved.py index 675bd9d6..8b484c55 100644 --- a/komorebi-for-kde/nix/tests/vm/lib/tests/test_moved.py +++ b/komorebi-for-kde/nix/tests/vm/lib/tests/test_moved.py @@ -60,7 +60,7 @@ def test_a_daemon_that_lets_go_and_takes_up_again_passes_handover() -> None: base = checks.passed handover.run(platform, checks, clients) assert checks.failed == 0, checks.failures - assert checks.passed - base == 5 + assert checks.passed - base == 6 def test_a_daemon_that_keeps_an_unmanaged_window_fails_handover() -> None: @@ -332,3 +332,14 @@ def test_a_crash_that_leaves_a_window_hidden_fails() -> None: clients = opened(platform, checks) lifecycle_hidden.crash(platform, checks, clients) assert any("none is left out of sight" in f for f in checks.failures), checks.failures + + +def test_a_window_that_is_alone_on_its_workspace_fails_handover_on_the_precondition() -> None: + platform = FakePlatform() + checks = Checks() + clients = opened(platform, checks) + platform.komorebic("send-to-workspace", "1") + platform.komorebic("send-to-workspace", "1") + handover.run(platform, checks, clients) + assert any("two tiled containers" in f for f in checks.failures) + assert not any("unmanage" in f for f in checks.failures) From b680dbd31d497d23afd711350b1a66c5171d3ffa Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sat, 31 Oct 2026 14:36:42 -0700 Subject: [PATCH 2/2] test(kde): vm-commands brings the swept windows back before handover Scenario precondition fix for the vm-commands failure "[shared] win3 is inside the work area and not on a tile of the layout" (see the previous revision for the log evidence). The shared sweep sends windows to other workspaces (send-to-last-workspace and the like), so by the time handover ran, win3 was alone on workspace 0 and win1/win2/win5 were parked on workspace 3. New KDE step bring_back, between replace_configuration and handover: while another workspace of the first monitor has windows, focus it and send-to-workspace 0, then focus workspace 0 and check that it has two containers or more and is the focused one. The handover check is untouched. Native pytest of the VM lib: 320 passed; ruff check and format clean. The step itself only runs in the VM. VM verification: not yet (vm-commands on baseline-with-fix and candidate, ~20 min each, after the KDE VM run). --- .../platforms/kde/extras/commands.py | 40 ++++++++++++++++++- .../nix/tests/vm/suites/commands/test.py | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/platforms/kde/extras/commands.py b/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/platforms/kde/extras/commands.py index 80c86b9c..ff58f36c 100644 --- a/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/platforms/kde/extras/commands.py +++ b/komorebi-for-kde/nix/tests/vm/lib/komorebi_vm/platforms/kde/extras/commands.py @@ -6,8 +6,8 @@ windows and that every command is understood and leaves the daemon healthy, as t sees it; what is here reads KWin (`kdotool`) and the daemon's log. The suite runs `setup`, `layouts_by_count`, the shared `layouts` and `sweep`, -`replace_configuration`, the shared `handover`, `title_rule`, `prints` and `queries`, and -`at_the_end`. +`replace_configuration`, `bring_back`, the shared `handover`, `title_rule`, `prints` and +`queries`, and `at_the_end`. The daemon runs on a session with two outputs, and `clients` are five windows on the first. """ @@ -143,6 +143,42 @@ def replace_configuration(platform: KdePlatform, checks: Checks, clients: list[C ) +def bring_back(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None: + """Puts the windows the sweep sent to other workspaces back on the first, a container each, and + focuses it, so that the scenarios after it start from the windows the sweep left, on one + workspace, as the shared `handover` needs (a window alone on its workspace has no layout to be + left out of). + """ + + def count() -> int: + return len(platform.state().workspace(0).windows()) + + for _ in clients: + elsewhere = [ + i + for i, ws in enumerate(platform.state().monitors[0].workspaces) + if i != 0 and ws.windows() + ] + if not elsewhere: + break + here = count() + platform.komorebic("focus-workspace", str(elsewhere[0])) + platform.komorebic("send-to-workspace", "0") + platform.wait_for(lambda h=here: count() > h, timeout=10) + platform.komorebic("focus-workspace", "0") + state = platform.state + checks.check( + "the windows are back on the first workspace, in view, in a container each", + platform.wait_for( + lambda: ( + len(state().workspace(0).containers) >= 2 + and state().monitors[0].focused_workspace == 0 + ), + timeout=10, + ), + ) + + def at_the_end(platform: KdePlatform, checks: Checks, clients: list[Client]) -> None: """The daemon has every window KWin has, each is where the daemon last asked for it, and a clean stop leaves the daemon not running.""" diff --git a/komorebi-for-kde/nix/tests/vm/suites/commands/test.py b/komorebi-for-kde/nix/tests/vm/suites/commands/test.py index 9b6bb901..9a019831 100644 --- a/komorebi-for-kde/nix/tests/vm/suites/commands/test.py +++ b/komorebi-for-kde/nix/tests/vm/suites/commands/test.py @@ -45,6 +45,7 @@ run_suite( platform_only("kde", kde.komorebic, "change-layout", "bsp"), shared(commands.sweep, *args, CONFIG), platform_only("kde", kde_commands.replace_configuration, *args), + platform_only("kde", kde_commands.bring_back, *args), shared(handover.run, *args), shared(title_rule.run, platform, checks), shared(commands.prints, platform, checks),