diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 99ddff4a4813..21b03dfb31c1 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1250,7 +1250,7 @@ in qgis = handleTest ./qgis.nix { package = pkgs.qgis; }; qgis-ltr = handleTest ./qgis.nix { package = pkgs.qgis-ltr; }; qownnotes = runTest ./qownnotes.nix; - qtile = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./qtile.nix; + qtile = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./qtile/default.nix; qtile-extras = runTestOn [ "x86_64-linux" "aarch64-linux" ] ./qtile-extras/default.nix; quake3 = runTest ./quake3.nix; quicktun = runTest ./quicktun.nix; diff --git a/nixos/tests/qtile-extras/add-startup-hook.patch b/nixos/tests/qtile-extras/add-startup-hook.patch new file mode 100644 index 000000000000..ea10209e4b5c --- /dev/null +++ b/nixos/tests/qtile-extras/add-startup-hook.patch @@ -0,0 +1,22 @@ +--- a/config.py 2025-08-03 00:37:13.058374602 +0200 ++++ b/config.py 2025-08-03 00:45:51.869382363 +0200 +@@ -24,10 +24,18 @@ + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + # SOFTWARE. + +-from libqtile import bar, layout, qtile, widget ++from libqtile import bar, layout, qtile, widget, hook + from libqtile.config import Click, Drag, Group, Key, Match, Screen + from libqtile.lazy import lazy + from libqtile.utils import guess_terminal ++from libqtile.log_utils import logger ++ ++ ++@hook.subscribe.startup ++def print_ready(): ++ logger.warning("ready!") # warning to make it always visible ++ ++ + + mod = "mod4" + terminal = guess_terminal() diff --git a/nixos/tests/qtile-extras/config.nix b/nixos/tests/qtile-extras/config.nix index b3756b1fe449..177431fabd68 100644 --- a/nixos/tests/qtile-extras/config.nix +++ b/nixos/tests/qtile-extras/config.nix @@ -15,7 +15,10 @@ stdenvNoCC.mkDerivation { cp $src config.py ''; - patches = [ ./add-widget.patch ]; + patches = [ + ./add-widget.patch + ./add-startup-hook.patch + ]; dontUnpack = true; dontBuild = true; diff --git a/nixos/tests/qtile-extras/default.nix b/nixos/tests/qtile-extras/default.nix index de2a17db1fbf..759408a9b540 100644 --- a/nixos/tests/qtile-extras/default.nix +++ b/nixos/tests/qtile-extras/default.nix @@ -40,6 +40,8 @@ }; testScript = '' + from pathlib import Path + with subtest("ensure x starts"): machine.wait_for_x() machine.wait_for_file("/home/alice/.Xauthority") @@ -48,6 +50,13 @@ with subtest("ensure client is available"): machine.succeed("qtile --version") + with subtest("Qtile signals that it is ready"): + qtile_logfile = Path("/home/alice/.local/share/qtile/qtile.log") + + machine.succeed(f"mkdir -p {qtile_logfile.parent}") + machine.succeed(f"touch {qtile_logfile}") + machine.succeed(f"sh -c 'tail -f {qtile_logfile} | grep --line-buffered \'ready\' -m 1'") + with subtest("ensure we can open a new terminal"): machine.send_key("meta_l-ret") machine.wait_for_window(r"alice.*?machine") diff --git a/nixos/tests/qtile.nix b/nixos/tests/qtile.nix deleted file mode 100644 index 55c4a4769aa1..000000000000 --- a/nixos/tests/qtile.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ lib, ... }: -{ - name = "qtile"; - - meta = { - maintainers = with lib.maintainers; [ - sigmanificient - gurjaka - ]; - }; - - nodes.machine = - { - pkgs, - lib, - ... - }: - { - imports = [ - ./common/x11.nix - ./common/user-account.nix - ]; - test-support.displayManager.auto.user = "alice"; - - services.xserver.windowManager.qtile.enable = true; - - services.displayManager.defaultSession = lib.mkForce "qtile"; - - environment.systemPackages = [ pkgs.kitty ]; - }; - - testScript = '' - with subtest("ensure x starts"): - machine.wait_for_x() - machine.wait_for_file("/home/alice/.Xauthority") - machine.succeed("xauth merge ~alice/.Xauthority") - - with subtest("ensure client is available"): - machine.succeed("qtile --version") - - with subtest("ensure we can open a new terminal"): - machine.send_key("meta_l-ret") - machine.wait_for_window(r"alice.*?machine") - machine.screenshot("terminal") - ''; -} diff --git a/nixos/tests/qtile/add-startup-hook.patch b/nixos/tests/qtile/add-startup-hook.patch new file mode 100644 index 000000000000..ea10209e4b5c --- /dev/null +++ b/nixos/tests/qtile/add-startup-hook.patch @@ -0,0 +1,22 @@ +--- a/config.py 2025-08-03 00:37:13.058374602 +0200 ++++ b/config.py 2025-08-03 00:45:51.869382363 +0200 +@@ -24,10 +24,18 @@ + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + # SOFTWARE. + +-from libqtile import bar, layout, qtile, widget ++from libqtile import bar, layout, qtile, widget, hook + from libqtile.config import Click, Drag, Group, Key, Match, Screen + from libqtile.lazy import lazy + from libqtile.utils import guess_terminal ++from libqtile.log_utils import logger ++ ++ ++@hook.subscribe.startup ++def print_ready(): ++ logger.warning("ready!") # warning to make it always visible ++ ++ + + mod = "mod4" + terminal = guess_terminal() diff --git a/nixos/tests/qtile/config.nix b/nixos/tests/qtile/config.nix new file mode 100644 index 000000000000..c2d74b95f35a --- /dev/null +++ b/nixos/tests/qtile/config.nix @@ -0,0 +1,27 @@ +{ + stdenvNoCC, + fetchurl, +}: +stdenvNoCC.mkDerivation { + name = "qtile-extras-config"; + version = "0.0.1"; + + src = fetchurl { + url = "https://raw.githubusercontent.com/qtile/qtile/v0.28.1/libqtile/resources/default_config.py"; + hash = "sha256-Y5W277CWVNSi4BdgEW/f7Px/MMjnN9W9TDqdOncVwPc="; + }; + + prePatch = '' + cp $src config.py + ''; + + patches = [ ./add-startup-hook.patch ]; + + dontUnpack = true; + dontBuild = true; + + installPhase = '' + mkdir -p $out + cp config.py $out/config.py + ''; +} diff --git a/nixos/tests/qtile/default.nix b/nixos/tests/qtile/default.nix new file mode 100644 index 000000000000..cf0d932b9f16 --- /dev/null +++ b/nixos/tests/qtile/default.nix @@ -0,0 +1,68 @@ +{ lib, ... }: +{ + name = "qtile"; + + meta = { + maintainers = with lib.maintainers; [ + sigmanificient + gurjaka + ]; + }; + + nodes.machine = + { + pkgs, + lib, + ... + }: + let + # We create a custom Qtile configuration file that adds a + # startup hook to qtile. This ensure we can reproducibly check + # when Qtile is truly ready to receive our inputs + config-deriv = pkgs.callPackage ./config.nix { }; + in + { + imports = [ + ../common/x11.nix + ../common/user-account.nix + ]; + test-support.displayManager.auto.user = "alice"; + + services.xserver.windowManager.qtile = { + enable = true; + configFile = "${config-deriv}/config.py"; + extraPackages = ps: [ ps.qtile-extras ]; + }; + + services.displayManager.defaultSession = lib.mkForce "qtile"; + + environment.systemPackages = [ + pkgs.kitty + pkgs.xorg.xwininfo + ]; + }; + + testScript = '' + from pathlib import Path + + with subtest("ensure x starts"): + machine.wait_for_x() + machine.wait_for_file("/home/alice/.Xauthority") + machine.succeed("xauth merge ~alice/.Xauthority") + + with subtest("ensure client is available"): + machine.succeed("qtile --version") + + with subtest("Qtile signals that it is ready"): + qtile_logfile = Path("/home/alice/.local/share/qtile/qtile.log") + + machine.succeed(f"mkdir -p {qtile_logfile.parent}") + machine.succeed(f"touch {qtile_logfile}") + machine.succeed(f"sh -c 'tail -f {qtile_logfile} | grep --line-buffered \'ready\' -m 1'") + + with subtest("ensure we can open a new terminal"): + machine.send_key("meta_l-ret") + machine.wait_for_window(r"alice.*?machine") + machine.screenshot("terminal") + ''; +}