mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-11-15 21:32:26 +01:00
feat(nix): known failures, with unknown_monitor the first
Checks.known_failure records a check that fails for a reason that is to be followed up on: the suite does not fail, the totals say how many known failures there are, and one that holds fails the suite so the marker goes. unknown_monitor takes the reason, and core-e2e runs it last, because the window it loses stays lost. BEHAVIOUR.md says so.
This commit is contained in:
1 parent
54d866f83a
commit
8fc7c961d0
6 files changed
+83
-8
No files matched your search
@@ -36,7 +36,7 @@ runs, and goes stale when the code changes.
|
||||
| `closing` | a closed window leaves the state, and the others take its room | pass | pass |
|
||||
| `resize` | dragging the edge two tiles share moves it by what the pointer moved | pass | **fails**, cause found |
|
||||
| `commands` | every layout, and about 216 commands, leave the daemon healthy | pass, none skipped | not run, see below |
|
||||
| `commands.unknown_monitor` | a window sent to a monitor that does not exist stays managed | **fails** | **fails** |
|
||||
| `commands.unknown_monitor` | a window sent to a monitor that does not exist stays managed | **known failure** | **known failure** |
|
||||
| `rules` | initial, permanent and ignore rules by title | see below | not run |
|
||||
| `hotplug` | an unplugged display takes its windows to the other, a plugged one is a monitor | pass | not run |
|
||||
|
||||
@@ -54,9 +54,11 @@ present, with the command exiting 0 and printing nothing. On kfde `core-e2e` fai
|
||||
check on a real KWin, and the windows after it. kfde's code shows how:
|
||||
`WindowManager::move_container_to_monitor` takes the focused container out of its workspace with
|
||||
`remove_focused_container()` and only then looks the monitor up, with an error for one that is not
|
||||
there, so the container is gone when the error is returned. This is not fixed, on either port. The
|
||||
scenario is `commands.unknown_monitor`, which a suite can call; it is not in `core-e2e` while it
|
||||
would fail there. The sweep of `commands` is not affected on kfde, which has two outputs, and on
|
||||
there, so the container is gone when the error is returned. This is not fixed, on either port, and is a
|
||||
**known failure to follow up on later**: `commands.unknown_monitor` takes a `known_failure`
|
||||
reason, with which its checks are recorded by `Checks.known_failure`. They do not fail the suite,
|
||||
the totals say `known failures: N`, and one that holds fails the suite to say the marker can go.
|
||||
`core-e2e` runs it last (section 12c), because the window is lost. The sweep of `commands` is not affected on kfde, which has two outputs, and on
|
||||
kfw the sweep now plugs in a second display first.
|
||||
|
||||
**`resize` on kfw.** Dragging the edge between two tiles by 30, 60 and 120 pixels moved it by 27,
|
||||
|
||||
@@ -16,6 +16,7 @@ class Checks:
|
||||
self.failed = 0
|
||||
self.failures: list[str] = []
|
||||
self.skipped: list[str] = []
|
||||
self.known: list[str] = []
|
||||
|
||||
def ok(self, description: str) -> None:
|
||||
"""Records a check that passed."""
|
||||
@@ -33,6 +34,19 @@ class Checks:
|
||||
self.skipped.append(f"{description} ({reason})")
|
||||
print(f" skip {description}: {reason}")
|
||||
|
||||
def known_failure(self, description: str, condition: bool, reason: str) -> bool:
|
||||
"""Records a check that is known to fail, with the reason, to follow up on later.
|
||||
|
||||
The suite does not fail while it does. When it holds, that is a failure, to say that
|
||||
the marker can go.
|
||||
"""
|
||||
if condition:
|
||||
self.bad(f"{description}: it holds now, so it is no longer a known failure")
|
||||
else:
|
||||
self.known.append(f"{description} ({reason})")
|
||||
print(f" known failure {description}: {reason}")
|
||||
return condition
|
||||
|
||||
def check(self, description: str, condition: bool | Callable[[], bool]) -> bool:
|
||||
"""Records `condition` (or what calling it returns) and returns it."""
|
||||
holds = condition() if callable(condition) else condition
|
||||
@@ -51,5 +65,7 @@ class Checks:
|
||||
print(f"passed: {self.passed} failed: {self.failed}")
|
||||
if self.skipped:
|
||||
print(f"skipped: {len(self.skipped)}")
|
||||
if self.known:
|
||||
print(f"known failures: {len(self.known)}")
|
||||
if self.failed:
|
||||
raise AssertionError(f"{self.failed} checks failed: {'; '.join(self.failures)}")
|
||||
@@ -359,18 +359,28 @@ def prints(platform: Platform, checks: Checks) -> None:
|
||||
checks.check(f"komorebic {line}", status == 0)
|
||||
|
||||
|
||||
def unknown_monitor(platform: Platform, checks: Checks, clients: list[Client]) -> None:
|
||||
def unknown_monitor(
|
||||
platform: Platform, checks: Checks, clients: list[Client], known_failure: str | None = None
|
||||
) -> None:
|
||||
"""Sends the focused window to a monitor that does not exist, and checks that no window is lost.
|
||||
|
||||
A port may refuse the command or ignore it, but a window that was managed has to stay managed:
|
||||
a daemon that stops managing it leaves it on the screen with nothing tiling it. The platform
|
||||
has fewer than seven displays.
|
||||
|
||||
With `known_failure`, the reason a port is known to lose the window, the checks are recorded as
|
||||
known failures: they do not fail the suite, and one that holds says the marker can go. The
|
||||
window is lost then, so the scenario belongs at the end of a suite.
|
||||
"""
|
||||
managed = platform.state().managed()
|
||||
for command in ("send-to-monitor", "move-to-monitor"):
|
||||
platform.komorebic_status(command, "7")
|
||||
platform.wait_for(lambda: unhealthy(platform, clients) is None, timeout=5)
|
||||
checks.check(
|
||||
f"after {command} 7, which no display has, the daemon still manages every window",
|
||||
platform.state().managed() == managed and unhealthy(platform, clients) is None,
|
||||
description = (
|
||||
f"after {command} 7, which no display has, the daemon still manages every window"
|
||||
)
|
||||
holds = platform.state().managed() == managed and unhealthy(platform, clients) is None
|
||||
if known_failure is None:
|
||||
checks.check(description, holds)
|
||||
else:
|
||||
checks.known_failure(description, holds, known_failure)
|
||||
@@ -31,3 +31,18 @@ def test_finish_raises_only_when_something_failed(capsys: pytest.CaptureFixture[
|
||||
with pytest.raises(AssertionError, match="^1 checks failed: broken$"):
|
||||
checks.finish()
|
||||
assert "passed: 1 failed: 1" in capsys.readouterr().out
|
||||
|
||||
|
||||
def test_a_known_failure_is_listed_and_does_not_fail(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
checks = Checks()
|
||||
assert checks.known_failure("x", False, "why") is False
|
||||
checks.finish()
|
||||
out = capsys.readouterr().out
|
||||
assert "passed: 0 failed: 0" in out and "known failures: 1" in out
|
||||
assert checks.known == ["x (why)"]
|
||||
|
||||
|
||||
def test_a_known_failure_that_holds_fails_so_the_marker_goes() -> None:
|
||||
checks = Checks()
|
||||
checks.known_failure("x", True, "why")
|
||||
assert checks.failed == 1 and "no longer a known failure" in checks.failures[0]
|
||||
@@ -258,3 +258,24 @@ def test_a_daemon_that_ignores_a_monitor_that_does_not_exist_passes() -> None:
|
||||
clients = opened(platform, checks)
|
||||
commands.unknown_monitor(platform, checks, clients)
|
||||
assert checks.failed == 0, checks.failures
|
||||
|
||||
|
||||
def test_a_known_failure_does_not_fail_the_suite_until_it_is_fixed() -> None:
|
||||
class Loses(FakePlatform):
|
||||
def komorebic_status(self, *args: str) -> tuple[int, str]:
|
||||
if args[:1] == ("send-to-monitor",):
|
||||
self.containers[self.focus].clear()
|
||||
return 0, ""
|
||||
return super().komorebic_status(*args)
|
||||
|
||||
reason = "the container goes first"
|
||||
broken, checks = Loses(), Checks()
|
||||
clients = opened(broken, checks)
|
||||
commands.unknown_monitor(broken, checks, clients, known_failure=reason)
|
||||
assert checks.failed == 0, checks.failures
|
||||
assert len(checks.known) >= 1
|
||||
|
||||
fixed, checks = FakePlatform(), Checks()
|
||||
clients = opened(fixed, checks)
|
||||
commands.unknown_monitor(fixed, checks, clients, known_failure=reason)
|
||||
assert checks.failed == 2 and checks.known == []
|
||||
@@ -16,6 +16,7 @@ from komorebi_vm import Checks, Kde, Rect, daemon
|
||||
from komorebi_vm.core.platform import Client
|
||||
from komorebi_vm.core.scenarios import (
|
||||
closing,
|
||||
commands,
|
||||
focus,
|
||||
lifecycle,
|
||||
monocle,
|
||||
@@ -467,6 +468,16 @@ platform.close(Client("after-the-restart"))
|
||||
platform.close(Client("beside"))
|
||||
checks.check("one window is left", kde.wait_for(lambda: kde.managed_all() == 1, timeout=20))
|
||||
|
||||
print("== 12c. a window sent to a monitor that does not exist")
|
||||
# KNOWN FAILURE, to follow up on: move_container_to_monitor takes the container out before it
|
||||
# looks the monitor up. See docs/dev/BEHAVIOUR.md. The window is lost, so this stays last.
|
||||
commands.unknown_monitor(
|
||||
platform,
|
||||
checks,
|
||||
[Client("afterwards")],
|
||||
known_failure="the container is removed before the monitor is looked up, on both ports",
|
||||
)
|
||||
|
||||
print("== 13. komorebic stop")
|
||||
kde.komorebic("stop")
|
||||
checks.check("the daemon exited", kde.wait_for(lambda: not kde.komorebi_running()))
|
||||
|
||||
Reference in new issue
Block a user