chore(repo): combine candidate 3b with the KDE handover scenario fix (candidate 3c)

Gate candidate 3c: wip-cand3b (cand3 + the bar e2e scenario) plus wip-u-kdefix (handover precondition in both copies of the shared e2e lib, KDE vm-commands bring_back step). The shared e2e/lib handover scenario is also what the Windows runner runs, so the Windows gate must include it.
This commit is contained in:
LGUG2Z committed 2026-11-05 15:03:26 -08:00
commit 4e2c50e526
5 files changed
+77 -3

No files matched your search

@@ -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()
@@ -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()
@@ -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."""
@@ -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)
@@ -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),