Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions nixos/tests/sway.nix
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
regular2 = foreground;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this now, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the entire foot config I think (unless we want to return to ORC? Not sure how common font rendering issues are vs. how finicky ORC is (doesn't work reliably in interactive mode, etc.))

};
};

etc."gpg-agent.conf".text = ''
pinentry-timeout 86400
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be great if we could document this change (either here via a comment or via the commit message) - otherwise it might not be clear / obvious enough in the future.

I also checked the man page but the timeout seems to come from pinentry-gnome3:

--pinentry-timeout n
This option asks the Pinentry to timeout after n seconds with no user input. The default value of 0 does not ask the pinentry to timeout, however a Pinentry may use its own default timeout
value in this case. A Pinentry may or may not honor this request.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah I tried that but it didn't work with 0 (which was with the first value I tried), but I didn't retry with a large positive value... I'll investigate

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I tried this again and it just doesn't come up. Seems like the config file is really needed.

'';
};

fonts.fonts = [ pkgs.inconsolata ];
Expand All @@ -71,16 +75,53 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
virtualisation.qemu.options = [ "-vga none -device virtio-gpu-pci" ];
};

enableOCR = true;

testScript = { nodes, ... }: ''
import shlex
import json

q = shlex.quote
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, not sure about this but I can live with it.
from shlex import quote (or from shlex import quote as q) would probably be nicer.

NODE_GROUPS = ["nodes", "floating_nodes"]


def swaymsg(command: str = "", succeed=True, type="command"):
Copy link
Member

@primeos primeos Jun 21, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: A docstring would be nice (but the function is well readable so it's not required).
For the other two functions it'd be a bit more useful.

assert command != "" or type != "command", "Must specify command or type"
shell = q(f"swaymsg -t {q(type)} -- {q(command)}")
with machine.nested(
f"sending swaymsg {shell!r}" + " (allowed to fail)" * (not succeed)
):
ret = (machine.succeed if succeed else machine.execute)(
f"su - alice -c {shell}"
)

# execute also returns a status code, but disregard.
if not succeed:
_, ret = ret

if not succeed and not ret:
return None

parsed = json.loads(ret)
return parsed

def swaymsg(command: str, succeed=True):
with machine.nested(f"sending swaymsg {command!r}" + " (allowed to fail)" * (not succeed)):
(machine.succeed if succeed else machine.execute)(
f"su - alice -c {shlex.quote('swaymsg -- ' + command)}"
)

def walk(tree):
yield tree
for group in NODE_GROUPS:
for node in tree.get(group, []):
yield from walk(node)


def wait_for_window(pattern):
def func(last_chance):
nodes = (node["name"] for node in walk(swaymsg(type="get_tree")))

if last_chance:
nodes = list(nodes)
machine.log(f"Last call! Current list of windows: {nodes}")

return any(pattern in name for name in nodes)

retry(func)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how safe it is to rely on retry being available but it should be fine given that other tests also already rely on it.


start_all()
machine.wait_for_unit("multi-user.target")
Expand All @@ -94,7 +135,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {

# Test XWayland (foot does not support X):
swaymsg("exec WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty")
machine.wait_for_text("alice@machine")
wait_for_window("alice@machine")
machine.send_chars("test-x11\n")
machine.wait_for_file("/tmp/test-x11-exit-ok")
print(machine.succeed("cat /tmp/test-x11.out"))
Expand All @@ -106,7 +147,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
machine.send_key("alt-3")
machine.sleep(3)
machine.send_key("alt-ret")
machine.wait_for_text("alice@machine")
wait_for_window("alice@machine")
machine.send_chars("test-wayland\n")
machine.wait_for_file("/tmp/test-wayland-exit-ok")
print(machine.succeed("cat /tmp/test-wayland.out"))
Expand All @@ -117,16 +158,24 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {

# Test gpg-agent starting pinentry-gnome3 via D-Bus (tests if
# $WAYLAND_DISPLAY is correctly imported into the D-Bus user env):
swaymsg("exec gpg --no-tty --yes --quick-generate-key test")
swaymsg("exec mkdir -p ~/.gnupg")
swaymsg("exec cp /etc/gpg-agent.conf ~/.gnupg")
Comment on lines +161 to +162
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit unfortunate but the package seems to use sysconfdir=${gnupg}/etc/gnupg so it's fine for now.


swaymsg("exec DISPLAY=INVALID gpg --no-tty --yes --quick-generate-key test", succeed=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need the succeed=False here and do you know why it returns an unsuccessful exit code?

machine.wait_until_succeeds("pgrep --exact gpg")
machine.wait_for_text("Passphrase")
wait_for_window("gpg")
machine.succeed("pgrep --exact gpg")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, it's fine but is this really useful again after waiting for the window (since we already ensured that the process is there before waiting for the window)?

machine.screenshot("gpg_pinentry")
machine.send_key("alt-shift-q")
machine.wait_until_fails("pgrep --exact gpg")

# Test swaynag:
def get_height():
return [node['rect']['height'] for node in walk(swaymsg(type="get_tree")) if node['focused']][0]

before = get_height()
machine.send_key("alt-shift-e")
machine.wait_for_text("You pressed the exit shortcut.")
retry(lambda _: get_height() < before)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine but a bit of a weird test. Would seem better if we could use wait_for_window but I haven't tested if and how it gets listed there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't show up in the window list, this was the best thing I could think of.

machine.screenshot("sway_exit")

swaymsg("exec swaylock")
Expand Down