NixOS VM tests: Difference between revisions
imported>Roberth Link to docs and add nixosTest |
imported>Olafklingt add examples |
||
Line 1: | Line 1: | ||
The primary documentation for the [https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests NixOS VM testing framework] is in [https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests the NixOS manual]. | The primary documentation for the [https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests NixOS VM testing framework] is in [https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests the NixOS manual], and in [https://nixos.org/manual/nixpkgs/unstable/#tester-runNixOSTest the Nixpkgs manual]. A tutorial can be found at [https://nix.dev/tutorials/nixos/integration-testing-using-virtual-machines]. | ||
The test infrastructure entry point is nixos/lib/testing.nix. Alternatively, for out-of-tree tests you can invoke it via Nixpkgs as the nixosTest function, which reuses your already evaluated Nixpkgs to generate your node configurations. | The test infrastructure entry point is nixos/lib/testing.nix. Alternatively, for out-of-tree tests you can invoke it via Nixpkgs as the nixosTest function, which reuses your already evaluated Nixpkgs to generate your node configurations. | ||
Line 37: | Line 37: | ||
Keys: https://en.wikibooks.org/wiki/QEMU/Monitor#sendkey_keys | Keys: https://en.wikibooks.org/wiki/QEMU/Monitor#sendkey_keys | ||
== home-manager example == | |||
It is possible to use home-manager to manage packages per user. | |||
This example shows how to add home-manager to a single file configuration. | |||
The complete `hmtest.nix` file content looks like the following: | |||
let | |||
nixpkgs = builtins.fetchTarball "https://github.com/nixOS/nixpkgs/archive/22.05.tar.gz"; | |||
pkgs = import nixpkgs {}; | |||
home-manager = builtins.fetchTarball "https://github.com/nix-community/home-manager/archive/release-22.05.tar.gz"; | |||
in | |||
pkgs.nixosTest { | |||
nodes.machine = { config, pkgs, ... }: { | |||
imports = [ | |||
(import "${home-manager}/nixos") | |||
]; | |||
boot.loader.systemd-boot.enable = true; | |||
boot.loader.efi.canTouchEfiVariables = true; | |||
services.xserver.enable = true; | |||
services.xserver.displayManager.gdm.enable = true; | |||
services.xserver.desktopManager.gnome.enable = true; | |||
users.users.alice = { | |||
isNormalUser = true; | |||
extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. | |||
}; | |||
home-manager.users.alice = { | |||
home.packages = [ | |||
pkgs.firefox | |||
pkgs.thunderbird | |||
]; | |||
}; | |||
system.stateVersion = "22.05"; | |||
}; | |||
testScript = {nodes, ...}: '' | |||
machine.wait_for_unit("default.target") | |||
machine.succeed("su -- alice -c 'which firefox'") | |||
machine.fail("su -- root -c 'which firefox'") | |||
''; | |||
} | |||
== wayland application example == | |||
The configuration we are using is starting the gnome desktop manager using wayland. | |||
To test if a wayland application is working is more complicated because we need to automate the login into gnome and automated startup of the application. Additionally we need to enable access to gnome dbus interface. To do this we need to modify the configuration the automated start of the application including automated login to gnome/wayland | |||
In the machine configuration we need to enable autologin for the user alice. | |||
services.xserver.displayManager.autoLogin.enable = true; | |||
services.xserver.displayManager.autoLogin.user = "alice"; | |||
To simplify our script we pin the uid of the user to 1000. | |||
uid = 1000; | |||
We specify a service that auto start firefox after login, which is easier than doing this in the test script. | |||
environment.systemPackages = [ | |||
(pkgs.makeAutostartItem { | |||
name = "firefox"; | |||
package = pkgs.firefox; | |||
}) | |||
]; | |||
Because gnome doesn't allow the evaluation of javascript to get information about open windows we need to override the gnome-shell startup service to start gnome-shell in unsafe mode: | |||
systemd.user.services = { | |||
"org.gnome.Shell@wayland" = { | |||
serviceConfig = { | |||
ExecStart = [ | |||
# Clear the list before overriding it. | |||
"" | |||
# Eval API is now internal so Shell needs to run in unsafe mode. | |||
"${pkgs.gnome.gnome-shell}/bin/gnome-shell --unsafe-mode" | |||
]; | |||
}; | |||
}; | |||
The test script utilizes the gnome dbus interface to get a list of open wayland windows. we wait until firefox appear to be started and make a screenshot that will be found in the result folder. | |||
testScript = {nodes, ...}: let | |||
user = nodes.machine.config.users.users.alice; | |||
bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus"; | |||
gdbus = "${bus} gdbus"; | |||
su = command: "su - ${user.name} -c '${command}'"; | |||
gseval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; | |||
wmClass = su "${gdbus} ${gseval} global.display.focus_window.wm_class"; | |||
in '' | |||
machine.wait_until_succeeds("${wmClass} | grep -q 'firefox'") | |||
machine.sleep(20) | |||
machine.screenshot("screen") | |||
''; | |||
The complete `firefoxtest.nix` file looks like the following: | |||
let | |||
nixpkgs = builtins.fetchTarball "https://github.com/nixOS/nixpkgs/archive/22.05.tar.gz"; | |||
pkgs = import nixpkgs {}; | |||
home-manager = builtins.fetchTarball "https://github.com/nix-community/home-manager/archive/release-22.05.tar.gz"; | |||
in | |||
pkgs.nixosTest { | |||
nodes.machine = {...}: { | |||
imports = [ | |||
(import "${home-manager}/nixos") | |||
]; | |||
boot.loader.systemd-boot.enable = true; | |||
boot.loader.efi.canTouchEfiVariables = true; | |||
services.xserver.enable = true; | |||
services.xserver.displayManager.gdm.enable = true; | |||
services.xserver.desktopManager.gnome.enable = true; | |||
services.xserver.displayManager.autoLogin.enable = true; | |||
services.xserver.displayManager.autoLogin.user = "alice"; | |||
users.users.alice = { | |||
isNormalUser = true; | |||
extraGroups = ["wheel"]; # Enable ‘sudo’ for the user. | |||
uid = 1000; | |||
}; | |||
home-manager.users.alice = { | |||
home.packages = [ | |||
pkgs.firefox | |||
pkgs.thunderbird | |||
]; | |||
}; | |||
system.stateVersion = "22.05"; | |||
environment.systemPackages = [ | |||
(pkgs.makeAutostartItem { | |||
name = "firefox"; | |||
package = pkgs.firefox; | |||
}) | |||
]; | |||
systemd.user.services = { | |||
"org.gnome.Shell@wayland" = { | |||
serviceConfig = { | |||
ExecStart = [ | |||
# Clear the list before overriding it. | |||
"" | |||
# Eval API is now internal so Shell needs to run in unsafe mode. | |||
"${pkgs.gnome.gnome-shell}/bin/gnome-shell --unsafe-mode" | |||
]; | |||
}; | |||
}; | |||
}; | |||
}; | |||
testScript = {nodes, ...}: let | |||
user = nodes.machine.config.users.users.alice; | |||
#uid = toString user.uid; | |||
bus = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus"; | |||
gdbus = "${bus} gdbus"; | |||
su = command: "su - ${user.name} -c '${command}'"; | |||
gseval = "call --session -d org.gnome.Shell -o /org/gnome/Shell -m org.gnome.Shell.Eval"; | |||
wmClass = su "${gdbus} ${gseval} global.display.focus_window.wm_class"; | |||
in '' | |||
machine.wait_until_succeeds("${wmClass} | grep -q 'firefox'") | |||
machine.sleep(20) | |||
machine.screenshot("screen") | |||
''; | |||
} |