diff options
Diffstat (limited to 'nixos/tests')
47 files changed, 1163 insertions, 291 deletions
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index cc8f5959f006d..909eea38b35e0 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -219,6 +219,7 @@ in { containers-physical_interfaces = handleTest ./containers-physical_interfaces.nix {}; containers-portforward = handleTest ./containers-portforward.nix {}; containers-reloadable = handleTest ./containers-reloadable.nix {}; + containers-require-bind-mounts = handleTest ./containers-require-bind-mounts.nix {}; containers-restart_networking = handleTest ./containers-restart_networking.nix {}; containers-tmpfs = handleTest ./containers-tmpfs.nix {}; containers-unified-hierarchy = handleTest ./containers-unified-hierarchy.nix {}; @@ -522,6 +523,8 @@ in { matrix-conduit = handleTest ./matrix/conduit.nix {}; matrix-synapse = handleTest ./matrix/synapse.nix {}; matrix-synapse-workers = handleTest ./matrix/synapse-workers.nix {}; + mautrix-meta-postgres = handleTest ./matrix/mautrix-meta-postgres.nix {}; + mautrix-meta-sqlite = handleTest ./matrix/mautrix-meta-sqlite.nix {}; mattermost = handleTest ./mattermost.nix {}; mealie = handleTest ./mealie.nix {}; mediamtx = handleTest ./mediamtx.nix {}; @@ -555,6 +558,7 @@ in { morty = handleTest ./morty.nix {}; mosquitto = handleTest ./mosquitto.nix {}; moosefs = handleTest ./moosefs.nix {}; + movim = discoverTests (import ./web-apps/movim { inherit handleTestOn; }); mpd = handleTest ./mpd.nix {}; mpv = handleTest ./mpv.nix {}; mtp = handleTest ./mtp.nix {}; @@ -649,6 +653,7 @@ in { nzbget = handleTest ./nzbget.nix {}; nzbhydra2 = handleTest ./nzbhydra2.nix {}; ocis = handleTest ./ocis.nix {}; + oddjobd = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./oddjobd.nix {}; oh-my-zsh = handleTest ./oh-my-zsh.nix {}; ollama = handleTest ./ollama.nix {}; ombi = handleTest ./ombi.nix {}; @@ -773,6 +778,7 @@ in { redis = handleTest ./redis.nix {}; redmine = handleTest ./redmine.nix {}; restartByActivationScript = handleTest ./restart-by-activation-script.nix {}; + restic-rest-server = handleTest ./restic-rest-server.nix {}; restic = handleTest ./restic.nix {}; retroarch = handleTest ./retroarch.nix {}; rkvm = handleTest ./rkvm {}; @@ -809,6 +815,7 @@ in { shattered-pixel-dungeon = handleTest ./shattered-pixel-dungeon.nix {}; shiori = handleTest ./shiori.nix {}; signal-desktop = handleTest ./signal-desktop.nix {}; + silverbullet = handleTest ./silverbullet.nix {}; simple = handleTest ./simple.nix {}; sing-box = handleTest ./sing-box.nix {}; slimserver = handleTest ./slimserver.nix {}; @@ -821,6 +828,7 @@ in { soapui = handleTest ./soapui.nix {}; soft-serve = handleTest ./soft-serve.nix {}; sogo = handleTest ./sogo.nix {}; + soju = handleTest ./soju.nix {}; solanum = handleTest ./solanum.nix {}; sonarr = handleTest ./sonarr.nix {}; sonic-server = handleTest ./sonic-server.nix {}; @@ -916,6 +924,7 @@ in { tang = handleTest ./tang.nix {}; taskserver = handleTest ./taskserver.nix {}; tayga = handleTest ./tayga.nix {}; + technitium-dns-server = handleTest ./technitium-dns-server.nix {}; teeworlds = handleTest ./teeworlds.nix {}; telegraf = handleTest ./telegraf.nix {}; teleport = handleTest ./teleport.nix {}; diff --git a/nixos/tests/ayatana-indicators.nix b/nixos/tests/ayatana-indicators.nix index a7de640f9e37c..5709ad2a1af69 100644 --- a/nixos/tests/ayatana-indicators.nix +++ b/nixos/tests/ayatana-indicators.nix @@ -21,8 +21,8 @@ in { services.xserver = { enable = true; desktopManager.mate.enable = true; - displayManager.defaultSession = lib.mkForce "mate"; }; + services.displayManager.defaultSession = lib.mkForce "mate"; services.ayatana-indicators = { enable = true; diff --git a/nixos/tests/budgie.nix b/nixos/tests/budgie.nix index 5228e869b056a..203e718c8c6d9 100644 --- a/nixos/tests/budgie.nix +++ b/nixos/tests/budgie.nix @@ -18,6 +18,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { }; }; + # We don't ship gnome-text-editor in Budgie module, we add this line mainly + # to catch eval issues related to this option. + environment.budgie.excludePackages = [ pkgs.gnome-text-editor ]; + services.xserver.desktopManager.budgie = { enable = true; extraPlugins = [ diff --git a/nixos/tests/cinnamon-wayland.nix b/nixos/tests/cinnamon-wayland.nix index 1629ead16f41f..19529d820d9c1 100644 --- a/nixos/tests/cinnamon-wayland.nix +++ b/nixos/tests/cinnamon-wayland.nix @@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; services.xserver.desktopManager.cinnamon.enable = true; - services.xserver.displayManager = { + services.displayManager = { autoLogin.enable = true; autoLogin.user = nodes.machine.users.users.alice.name; defaultSession = "cinnamon-wayland"; diff --git a/nixos/tests/cinnamon.nix b/nixos/tests/cinnamon.nix index eab907d0b712c..694308152149b 100644 --- a/nixos/tests/cinnamon.nix +++ b/nixos/tests/cinnamon.nix @@ -8,6 +8,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { services.xserver.enable = true; services.xserver.desktopManager.cinnamon.enable = true; + # We don't ship gnome-text-editor in Cinnamon module, we add this line mainly + # to catch eval issues related to this option. + environment.cinnamon.excludePackages = [ pkgs.gnome-text-editor ]; + # For the sessionPath subtest. services.xserver.desktopManager.cinnamon.sessionPath = [ pkgs.gnome.gpaste ]; }; diff --git a/nixos/tests/common/auto.nix b/nixos/tests/common/auto.nix index ac56bed4a88f1..a2e42e59c0442 100644 --- a/nixos/tests/common/auto.nix +++ b/nixos/tests/common/auto.nix @@ -30,12 +30,10 @@ in ###### implementation config = lib.mkIf cfg.enable { - services.xserver.displayManager = { - lightdm.enable = true; - autoLogin = { - enable = true; - user = cfg.user; - }; + services.xserver.displayManager.lightdm.enable = true; + services.displayManager.autoLogin = { + enable = true; + user = cfg.user; }; # lightdm by default doesn't allow auto login for root, which is diff --git a/nixos/tests/common/x11.nix b/nixos/tests/common/x11.nix index 0d76a0e972ff5..b79cedb864de4 100644 --- a/nixos/tests/common/x11.nix +++ b/nixos/tests/common/x11.nix @@ -12,6 +12,6 @@ # Use IceWM as the window manager. # Don't use a desktop manager. - services.xserver.displayManager.defaultSession = lib.mkDefault "none+icewm"; + services.displayManager.defaultSession = lib.mkDefault "none+icewm"; services.xserver.windowManager.icewm.enable = true; } diff --git a/nixos/tests/containers-require-bind-mounts.nix b/nixos/tests/containers-require-bind-mounts.nix new file mode 100644 index 0000000000000..5f986fd3e2803 --- /dev/null +++ b/nixos/tests/containers-require-bind-mounts.nix @@ -0,0 +1,35 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "containers-require-bind-mounts"; + meta.maintainers = with lib.maintainers; [ kira-bruneau ]; + + nodes.machine = { + containers.require-bind-mounts = { + bindMounts = { "/srv/data" = {}; }; + config = {}; + }; + + virtualisation.fileSystems = { + "/srv/data" = { + fsType = "tmpfs"; + options = [ "noauto" ]; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("default.target") + + assert "require-bind-mounts" in machine.succeed("nixos-container list") + assert "down" in machine.succeed("nixos-container status require-bind-mounts") + assert "inactive" in machine.fail("systemctl is-active srv-data.mount") + + with subtest("bind mount host paths must be mounted to run container"): + machine.succeed("nixos-container start require-bind-mounts") + assert "up" in machine.succeed("nixos-container status require-bind-mounts") + assert "active" in machine.succeed("systemctl status srv-data.mount") + + machine.succeed("systemctl stop srv-data.mount") + assert "down" in machine.succeed("nixos-container status require-bind-mounts") + assert "inactive" in machine.fail("systemctl is-active srv-data.mount") + ''; +}) diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index 7d91076600f97..c8a227eb2cf7b 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -178,6 +178,14 @@ in { "docker load --input='${examples.bashUncompressed}'", "docker rmi ${examples.bashUncompressed.imageName}", ) + docker.succeed( + "docker load --input='${examples.bashLayeredUncompressed}'", + "docker rmi ${examples.bashLayeredUncompressed.imageName}", + ) + docker.succeed( + "docker load --input='${examples.bashLayeredZstdCompressed}'", + "docker rmi ${examples.bashLayeredZstdCompressed.imageName}", + ) with subtest( "Check if the nix store is correctly initialized by listing " diff --git a/nixos/tests/forgejo.nix b/nixos/tests/forgejo.nix index 6acd6acb50fa9..b14df0a2c74f9 100644 --- a/nixos/tests/forgejo.nix +++ b/nixos/tests/forgejo.nix @@ -108,6 +108,12 @@ let assert "BEGIN PGP PUBLIC KEY BLOCK" in server.succeed("curl http://localhost:3000/api/v1/signing-key.gpg") + api_version = json.loads(server.succeed("curl http://localhost:3000/api/forgejo/v1/version")).get("version") + assert "development" != api_version and "-gitea-" in api_version, ( + "/api/forgejo/v1/version should not return 'development' " + + f"but should contain a gitea compatibility version string. Got '{api_version}' instead." + ) + server.succeed( "curl --fail http://localhost:3000/user/sign_up | grep 'Registration is disabled. " + "Please contact your site administrator.'" diff --git a/nixos/tests/gnome-flashback.nix b/nixos/tests/gnome-flashback.nix index f486dabc5c40b..e0a1d256c8c20 100644 --- a/nixos/tests/gnome-flashback.nix +++ b/nixos/tests/gnome-flashback.nix @@ -14,16 +14,17 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { services.xserver.displayManager = { gdm.enable = true; gdm.debug = true; - autoLogin = { - enable = true; - user = user.name; - }; + }; + + services.displayManager.autoLogin = { + enable = true; + user = user.name; }; services.xserver.desktopManager.gnome.enable = true; services.xserver.desktopManager.gnome.debug = true; services.xserver.desktopManager.gnome.flashback.enableMetacity = true; - services.xserver.displayManager.defaultSession = "gnome-flashback-metacity"; + services.displayManager.defaultSession = "gnome-flashback-metacity"; }; testScript = { nodes, ... }: let diff --git a/nixos/tests/gnome-xorg.nix b/nixos/tests/gnome-xorg.nix index 6ca700edcac38..c8ffb459edece 100644 --- a/nixos/tests/gnome-xorg.nix +++ b/nixos/tests/gnome-xorg.nix @@ -15,15 +15,16 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { services.xserver.displayManager = { gdm.enable = true; gdm.debug = true; - autoLogin = { - enable = true; - user = user.name; - }; + }; + + services.displayManager.autoLogin = { + enable = true; + user = user.name; }; services.xserver.desktopManager.gnome.enable = true; services.xserver.desktopManager.gnome.debug = true; - services.xserver.displayManager.defaultSession = "gnome-xorg"; + services.displayManager.defaultSession = "gnome-xorg"; systemd.user.services = { "org.gnome.Shell@x11" = { diff --git a/nixos/tests/gnome.nix b/nixos/tests/gnome.nix index 91182790cb248..98d61c7ea1723 100644 --- a/nixos/tests/gnome.nix +++ b/nixos/tests/gnome.nix @@ -12,10 +12,11 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { services.xserver.displayManager = { gdm.enable = true; gdm.debug = true; - autoLogin = { - enable = true; - user = "alice"; - }; + }; + + services.displayManager.autoLogin = { + enable = true; + user = "alice"; }; services.xserver.desktopManager.gnome.enable = true; diff --git a/nixos/tests/herbstluftwm.nix b/nixos/tests/herbstluftwm.nix index b6965914360e7..2a8b391947e74 100644 --- a/nixos/tests/herbstluftwm.nix +++ b/nixos/tests/herbstluftwm.nix @@ -8,7 +8,7 @@ import ./make-test-python.nix ({ lib, ...} : { nodes.machine = { pkgs, lib, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = lib.mkForce "none+herbstluftwm"; + services.displayManager.defaultSession = lib.mkForce "none+herbstluftwm"; services.xserver.windowManager.herbstluftwm.enable = true; environment.systemPackages = [ pkgs.dzen2 ]; # needed for upstream provided panel }; diff --git a/nixos/tests/hledger-web.nix b/nixos/tests/hledger-web.nix index f8919f7d4bd06..09941ca5c517c 100644 --- a/nixos/tests/hledger-web.nix +++ b/nixos/tests/hledger-web.nix @@ -19,7 +19,7 @@ rec { host = "127.0.0.1"; port = 5000; enable = true; - capabilities.manage = true; + allow = "edit"; }; networking.firewall.allowedTCPPorts = [ config.services.hledger-web.port ]; systemd.services.hledger-web.preStart = '' diff --git a/nixos/tests/i3wm.nix b/nixos/tests/i3wm.nix index b216650d8192b..c02ce86db8b20 100644 --- a/nixos/tests/i3wm.nix +++ b/nixos/tests/i3wm.nix @@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { nodes.machine = { lib, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = lib.mkForce "none+i3"; + services.displayManager.defaultSession = lib.mkForce "none+i3"; services.xserver.windowManager.i3.enable = true; }; diff --git a/nixos/tests/installer-systemd-stage-1.nix b/nixos/tests/installer-systemd-stage-1.nix index d10256d91d7fa..1dd55dada042a 100644 --- a/nixos/tests/installer-systemd-stage-1.nix +++ b/nixos/tests/installer-systemd-stage-1.nix @@ -38,6 +38,8 @@ clevisZfs clevisZfsFallback gptAutoRoot + clevisBcachefs + clevisBcachefsFallback ; } diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 1de886d6a0d19..7e835041eb39f 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -51,7 +51,7 @@ let boot.loader.systemd-boot.enable = true; ''} - boot.initrd.secrets."/etc/secret" = ./secret; + boot.initrd.secrets."/etc/secret" = "/etc/nixos/secret"; ${optionalString clevisTest '' boot.kernelParams = [ "console=tty0" "ip=192.168.1.1:::255.255.255.0::eth1:none" ]; @@ -80,39 +80,24 @@ let # a test script fragment `createPartitions', which must create # partitions and filesystems. testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi, grubIdentifier - , postInstallCommands, preBootCommands, postBootCommands, extraConfig + , postInstallCommands, postBootCommands, extraConfig , testSpecialisationConfig, testFlakeSwitch, clevisTest, clevisFallbackTest , disableFileSystems }: let - qemu-common = import ../lib/qemu-common.nix { inherit (pkgs) lib pkgs; }; - isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi); - qemu = qemu-common.qemuBinary pkgs.qemu_test; - in if !isEfi && !pkgs.stdenv.hostPlatform.isx86 then '' - machine.succeed("true") - '' else '' + startTarget = '' + ${optionalString clevisTest "tpm.start()"} + target.start() + ${postBootCommands} + target.wait_for_unit("multi-user.target") + ''; + in '' + ${optionalString clevisTest '' import os import subprocess tpm_folder = os.environ['NIX_BUILD_TOP'] - startcommand = "${qemu} -m 2048" - - ${optionalString clevisTest '' - startcommand += f" -chardev socket,id=chrtpm,path={tpm_folder}/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0" - startcommand += " -device virtio-net-pci,netdev=vlan1,mac=52:54:00:12:11:02 -netdev vde,id=vlan1,sock=\"$QEMU_VDE_SOCKET_1\"" - ''} - ${optionalString isEfi '' - startcommand +=" -drive if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware} -drive if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}" - ''} - - image_dir = machine.state_dir - disk_image = os.path.join(image_dir, "machine.qcow2") - startcommand += f" -drive file={disk_image},if=virtio,werror=report" - - def create_machine_named(name): - return create_machine(startcommand, name=name) - class Tpm: def __init__(self): self.start() @@ -143,30 +128,31 @@ let os.mkdir(f"{tpm_folder}/swtpm") tpm = Tpm() tpm.check() + ''} - start_all() + installer.start() ${optionalString clevisTest '' + tang.start() tang.wait_for_unit("sockets.target") tang.systemctl("start network-online.target") tang.wait_for_unit("network-online.target") - machine.systemctl("start network-online.target") - machine.wait_for_unit("network-online.target") + installer.systemctl("start network-online.target") + installer.wait_for_unit("network-online.target") ''} - machine.wait_for_unit("multi-user.target") - + installer.wait_for_unit("multi-user.target") with subtest("Assert readiness of login prompt"): - machine.succeed("echo hello") + installer.succeed("echo hello") with subtest("Wait for hard disks to appear in /dev"): - machine.succeed("udevadm settle") + installer.succeed("udevadm settle") ${createPartitions} with subtest("Create the NixOS configuration"): - machine.succeed("nixos-generate-config ${optionalString disableFileSystems "--no-filesystems"} --root /mnt") - machine.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2") - machine.copy_from_host( + installer.succeed("nixos-generate-config ${optionalString disableFileSystems "--no-filesystems"} --root /mnt") + installer.succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2") + installer.copy_from_host( "${ makeConfig { inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest; @@ -174,13 +160,13 @@ let }", "/mnt/etc/nixos/configuration.nix", ) - machine.copy_from_host("${pkgs.writeText "secret" "secret"}", "/mnt/etc/nixos/secret") + installer.copy_from_host("${pkgs.writeText "secret" "secret"}", "/mnt/etc/nixos/secret") ${optionalString clevisTest '' with subtest("Create the Clevis secret with Tang"): - machine.systemctl("start network-online.target") - machine.wait_for_unit("network-online.target") - machine.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''} + installer.systemctl("start network-online.target") + installer.wait_for_unit("network-online.target") + installer.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''} ${optionalString clevisFallbackTest '' with subtest("Shutdown Tang to check fallback to interactive prompt"): @@ -188,13 +174,13 @@ let ''} with subtest("Perform the installation"): - machine.succeed("nixos-install < /dev/null >&2") + installer.succeed("nixos-install < /dev/null >&2") with subtest("Do it again to make sure it's idempotent"): - machine.succeed("nixos-install < /dev/null >&2") + installer.succeed("nixos-install < /dev/null >&2") with subtest("Check that we can build things in nixos-enter"): - machine.succeed( + installer.succeed( """ nixos-enter -- nix-build --option substitute false -E 'derivation { name = "t"; @@ -209,48 +195,48 @@ let ${postInstallCommands} with subtest("Shutdown system after installation"): - machine.succeed("umount -R /mnt") - machine.succeed("sync") - machine.shutdown() + installer.succeed("umount -R /mnt") + installer.succeed("sync") + installer.shutdown() - # Now see if we can boot the installation. - machine = create_machine_named("boot-after-install") + # We're actually the same machine, just booting differently this time. + target.state_dir = installer.state_dir - # For example to enter LUKS passphrase. - ${preBootCommands} + # Now see if we can boot the installation. + ${startTarget} with subtest("Assert that /boot get mounted"): - machine.wait_for_unit("local-fs.target") + target.wait_for_unit("local-fs.target") ${if bootLoader == "grub" - then ''machine.succeed("test -e /boot/grub")'' - else ''machine.succeed("test -e /boot/loader/loader.conf")'' + then ''target.succeed("test -e /boot/grub")'' + else ''target.succeed("test -e /boot/loader/loader.conf")'' } with subtest("Check whether /root has correct permissions"): - assert "700" in machine.succeed("stat -c '%a' /root") + assert "700" in target.succeed("stat -c '%a' /root") with subtest("Assert swap device got activated"): # uncomment once https://bugs.freedesktop.org/show_bug.cgi?id=86930 is resolved - machine.wait_for_unit("swap.target") - machine.succeed("cat /proc/swaps | grep -q /dev") + target.wait_for_unit("swap.target") + target.succeed("cat /proc/swaps | grep -q /dev") with subtest("Check that the store is in good shape"): - machine.succeed("nix-store --verify --check-contents >&2") + target.succeed("nix-store --verify --check-contents >&2") with subtest("Check whether the channel works"): - machine.succeed("nix-env -iA nixos.procps >&2") - assert ".nix-profile" in machine.succeed("type -tP ps | tee /dev/stderr") + target.succeed("nix-env -iA nixos.procps >&2") + assert ".nix-profile" in target.succeed("type -tP ps | tee /dev/stderr") with subtest( "Check that the daemon works, and that non-root users can run builds " "(this will build a new profile generation through the daemon)" ): - machine.succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2") + target.succeed("su alice -l -c 'nix-env -iA nixos.procps' >&2") with subtest("Configure system with writable Nix store on next boot"): # we're not using copy_from_host here because the installer image # doesn't know about the host-guest sharing mechanism. - machine.copy_from_host_via_shell( + target.copy_from_host_via_shell( "${ makeConfig { inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest; @@ -261,25 +247,23 @@ let ) with subtest("Check whether nixos-rebuild works"): - machine.succeed("nixos-rebuild switch >&2") + target.succeed("nixos-rebuild switch >&2") # FIXME: Nix 2.4 broke nixos-option, someone has to fix it. # with subtest("Test nixos-option"): - # kernel_modules = machine.succeed("nixos-option boot.initrd.kernelModules") + # kernel_modules = target.succeed("nixos-option boot.initrd.kernelModules") # assert "virtio_console" in kernel_modules # assert "List of modules" in kernel_modules # assert "qemu-guest.nix" in kernel_modules - machine.shutdown() + target.shutdown() # Check whether a writable store build works - machine = create_machine_named("rebuild-switch") - ${preBootCommands} - machine.wait_for_unit("multi-user.target") + ${startTarget} # we're not using copy_from_host here because the installer image # doesn't know about the host-guest sharing mechanism. - machine.copy_from_host_via_shell( + target.copy_from_host_via_shell( "${ makeConfig { inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest; @@ -288,73 +272,62 @@ let }", "/etc/nixos/configuration.nix", ) - machine.succeed("nixos-rebuild boot >&2") - machine.shutdown() + target.succeed("nixos-rebuild boot >&2") + target.shutdown() - # And just to be sure, check that the machine still boots after - # "nixos-rebuild switch". - machine = create_machine_named("boot-after-rebuild-switch") - ${preBootCommands} - machine.wait_for_unit("network.target") + # And just to be sure, check that the target still boots after "nixos-rebuild switch". + ${startTarget} + target.wait_for_unit("network.target") # Sanity check, is it the configuration.nix we generated? - hostname = machine.succeed("hostname").strip() + hostname = target.succeed("hostname").strip() assert hostname == "thatworked" - ${postBootCommands} - machine.shutdown() + target.shutdown() # Tests for validating clone configuration entries in grub menu '' + optionalString testSpecialisationConfig '' - # Reboot Machine - machine = create_machine_named("clone-default-config") - ${preBootCommands} - machine.wait_for_unit("multi-user.target") + # Reboot target + ${startTarget} with subtest("Booted configuration name should be 'Home'"): # This is not the name that shows in the grub menu. # The default configuration is always shown as "Default" - machine.succeed("cat /run/booted-system/configuration-name >&2") - assert "Home" in machine.succeed("cat /run/booted-system/configuration-name") + target.succeed("cat /run/booted-system/configuration-name >&2") + assert "Home" in target.succeed("cat /run/booted-system/configuration-name") with subtest("We should **not** find a file named /etc/gitconfig"): - machine.fail("test -e /etc/gitconfig") + target.fail("test -e /etc/gitconfig") with subtest("Set grub to boot the second configuration"): - machine.succeed("grub-reboot 1") + target.succeed("grub-reboot 1") - ${postBootCommands} - machine.shutdown() + target.shutdown() - # Reboot Machine - machine = create_machine_named("clone-alternate-config") - ${preBootCommands} + # Reboot target + ${startTarget} - machine.wait_for_unit("multi-user.target") with subtest("Booted configuration name should be Work"): - machine.succeed("cat /run/booted-system/configuration-name >&2") - assert "Work" in machine.succeed("cat /run/booted-system/configuration-name") + target.succeed("cat /run/booted-system/configuration-name >&2") + assert "Work" in target.succeed("cat /run/booted-system/configuration-name") with subtest("We should find a file named /etc/gitconfig"): - machine.succeed("test -e /etc/gitconfig") + target.succeed("test -e /etc/gitconfig") - ${postBootCommands} - machine.shutdown() + target.shutdown() '' + optionalString testFlakeSwitch '' - ${preBootCommands} - machine.start() + ${startTarget} with subtest("Configure system with flake"): # TODO: evaluate as user? - machine.succeed(""" + target.succeed(""" mkdir /root/my-config mv /etc/nixos/hardware-configuration.nix /root/my-config/ - mv /etc/nixos/secret /root/my-config/ rm /etc/nixos/configuration.nix """) - machine.copy_from_host_via_shell( + target.copy_from_host_via_shell( "${makeConfig { inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest; forceGrubReinstallCount = 1; @@ -362,11 +335,11 @@ let }}", "/root/my-config/configuration.nix", ) - machine.copy_from_host_via_shell( + target.copy_from_host_via_shell( "${./installer/flake.nix}", "/root/my-config/flake.nix", ) - machine.succeed(""" + target.succeed(""" # for some reason the image does not have `pkgs.path`, so # we use readlink to find a Nixpkgs source. pkgs=$(readlink -f /nix/var/nix/profiles/per-user/root/channels)/nixos @@ -378,36 +351,32 @@ let """) with subtest("Switch to flake based config"): - machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz") - - ${postBootCommands} - machine.shutdown() + target.succeed("nixos-rebuild switch --flake /root/my-config#xyz") - ${preBootCommands} - machine.start() + target.shutdown() - machine.wait_for_unit("multi-user.target") + ${startTarget} with subtest("nix-channel command is not available anymore"): - machine.succeed("! which nix-channel") + target.succeed("! which nix-channel") # Note that the channel profile is still present on disk, but configured # not to be used. with subtest("builtins.nixPath is now empty"): - machine.succeed(""" + target.succeed(""" [[ "[ ]" == "$(nix-instantiate builtins.nixPath --eval --expr)" ]] """) with subtest("<nixpkgs> does not resolve"): - machine.succeed(""" + target.succeed(""" ! nix-instantiate '<nixpkgs>' --eval --expr """) with subtest("Evaluate flake config in fresh env without nix-channel"): - machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz") + target.succeed("nixos-rebuild switch --flake /root/my-config#xyz") with subtest("Evaluate flake config in fresh env without channel profiles"): - machine.succeed(""" + target.succeed(""" ( exec 1>&2 rm -v /root/.nix-channels @@ -415,16 +384,15 @@ let rm -vrf /nix/var/nix/profiles/per-user/root/channels* ) """) - machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz") + target.succeed("nixos-rebuild switch --flake /root/my-config#xyz") - ${postBootCommands} - machine.shutdown() + target.shutdown() ''; makeInstallerTest = name: { createPartitions - , postInstallCommands ? "", preBootCommands ? "", postBootCommands ? "" + , postInstallCommands ? "", postBootCommands ? "" , extraConfig ? "" , extraInstallerConfig ? {} , bootLoader ? "grub" # either "grub" or "systemd-boot" @@ -436,18 +404,39 @@ let , clevisFallbackTest ? false , disableFileSystems ? false }: - makeTest { + let + isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi); + in makeTest { inherit enableOCR; name = "installer-" + name; meta = { # put global maintainers here, individuals go into makeInstallerTest fkt call maintainers = (meta.maintainers or []); + # non-EFI tests can only run on x86 + platforms = if isEfi then platforms.linux else [ "x86_64-linux" "i686-linux" ]; }; - nodes = { + nodes = let + commonConfig = { + # builds stuff in the VM, needs more juice + virtualisation.diskSize = 8 * 1024; + virtualisation.cores = 8; + virtualisation.memorySize = 2048; + + # both installer and target need to use the same drive + virtualisation.diskImage = "./target.qcow2"; - # The configuration of the machine used to run "nixos-install". - machine = { pkgs, ... }: { + # and the same TPM options + virtualisation.qemu.options = mkIf (clevisTest) [ + "-chardev socket,id=chrtpm,path=$NIX_BUILD_TOP/swtpm-sock" + "-tpmdev emulator,id=tpm0,chardev=chrtpm" + "-device tpm-tis,tpmdev=tpm0" + ]; + }; + in { + # The configuration of the system used to run "nixos-install". + installer = { imports = [ + commonConfig ../modules/profiles/installation-device.nix ../modules/profiles/base.nix extraInstallerConfig @@ -458,11 +447,6 @@ let # root filesystem. virtualisation.fileSystems."/".autoFormat = systemdStage1; - # builds stuff in the VM, needs more juice - virtualisation.diskSize = 8 * 1024; - virtualisation.cores = 8; - virtualisation.memorySize = 2048; - boot.initrd.systemd.enable = systemdStage1; # Use a small /dev/vdb as the root disk for the @@ -470,17 +454,6 @@ let # the same during and after installation. virtualisation.emptyDiskImages = [ 512 ]; virtualisation.rootDevice = "/dev/vdb"; - virtualisation.bootLoaderDevice = "/dev/vda"; - virtualisation.qemu.diskInterface = "virtio"; - virtualisation.qemu.options = mkIf (clevisTest) [ - "-chardev socket,id=chrtpm,path=$NIX_BUILD_TOP/swtpm-sock" - "-tpmdev emulator,id=tpm0,chardev=chrtpm" - "-device tpm-tis,tpmdev=tpm0" - ]; - # We don't want to have any networking in the guest apart from the clevis tests. - virtualisation.vlans = mkIf (!clevisTest) []; - - boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true; hardware.enableAllFirmware = mkForce false; @@ -520,7 +493,13 @@ let in [ (pkgs.grub2.override { inherit zfsSupport; }) (pkgs.grub2_efi.override { inherit zfsSupport; }) - ]) ++ optionals clevisTest [ pkgs.klibc ]; + ]) + ++ optionals (bootLoader == "systemd-boot") [ + pkgs.zstd.bin + pkgs.mypy + pkgs.bootspec + ] + ++ optionals clevisTest [ pkgs.klibc ]; nix.settings = { substituters = mkForce []; @@ -529,6 +508,18 @@ let }; }; + target = { + imports = [ commonConfig ]; + virtualisation.useBootLoader = true; + virtualisation.useEFIBoot = isEfi; + virtualisation.useDefaultFilesystems = false; + virtualisation.efi.keepVariables = false; + + virtualisation.fileSystems."/" = { + device = "/dev/disk/by-label/this-is-not-real-and-will-never-be-used"; + fsType = "ext4"; + }; + }; } // optionalAttrs clevisTest { tang = { services.tang = { @@ -541,7 +532,7 @@ let }; testScript = testScriptFun { - inherit bootLoader createPartitions postInstallCommands preBootCommands postBootCommands + inherit bootLoader createPartitions postInstallCommands postBootCommands grubDevice grubIdentifier grubUseEfi extraConfig testSpecialisationConfig testFlakeSwitch clevisTest clevisFallbackTest disableFileSystems; @@ -550,7 +541,7 @@ let makeLuksRootTest = name: luksFormatOpts: makeInstallerTest name { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" @@ -572,10 +563,9 @@ let boot.kernelParams = lib.mkAfter [ "console=tty0" ]; ''; enableOCR = true; - preBootCommands = '' - machine.start() - machine.wait_for_text("[Pp]assphrase for") - machine.send_chars("supersecret\n") + postBootCommands = '' + target.wait_for_text("[Pp]assphrase for") + target.send_chars("supersecret\n") ''; }; @@ -583,7 +573,7 @@ let # one big filesystem partition. simple-test-config = { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary linux-swap 1M 1024M" + " mkpart primary ext2 1024M -1s", @@ -602,7 +592,7 @@ let simple-uefi-grub-config = { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel gpt" + " mkpart ESP fat32 1M 100MiB" # /boot + " set 1 boot on" @@ -656,7 +646,7 @@ let environment.systemPackages = with pkgs; [ keyutils clevis ]; }; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" + " mkpart primary linux-swap 100M 1024M" @@ -680,13 +670,9 @@ let # not know the UUID in advance. fileSystems."/" = lib.mkForce { device = "/dev/vda3"; fsType = "bcachefs"; }; ''; - preBootCommands = '' - tpm = Tpm() - tpm.check() - '' + optionalString fallback '' - machine.start() - machine.wait_for_text("enter passphrase for") - machine.send_chars("password\n") + postBootCommands = optionalString fallback '' + target.wait_for_text("enter passphrase for") + target.send_chars("password\n") ''; }; @@ -698,7 +684,7 @@ let environment.systemPackages = with pkgs; [ clevis ]; }; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" + " mkpart primary linux-swap 100M 1024M" @@ -719,17 +705,13 @@ let extraConfig = '' boot.initrd.clevis.devices."crypt-root".secretFile = "/etc/nixos/clevis-secret.jwe"; ''; - preBootCommands = '' - tpm = Tpm() - tpm.check() - '' + optionalString fallback '' - machine.start() + postBootCommands = optionalString fallback '' ${if systemdStage1 then '' - machine.wait_for_text("Please enter") + target.wait_for_text("Please enter") '' else '' - machine.wait_for_text("Passphrase for") + target.wait_for_text("Passphrase for") ''} - machine.send_chars("password\n") + target.send_chars("password\n") ''; }; @@ -742,7 +724,7 @@ let environment.systemPackages = with pkgs; [ clevis ]; }; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" + " mkpart primary linux-swap 100M 1024M" @@ -770,17 +752,13 @@ let boot.zfs.devNodes = "/dev/disk/by-uuid/"; networking.hostId = "00000000"; ''; - preBootCommands = '' - tpm = Tpm() - tpm.check() - '' + optionalString fallback '' - machine.start() + postBootCommands = optionalString fallback '' ${if systemdStage1 then '' - machine.wait_for_text("Enter key for rpool/root") + target.wait_for_text("Enter key for rpool/root") '' else '' - machine.wait_for_text("Key load error") + target.wait_for_text("Key load error") ''} - machine.send_chars("password\n") + target.send_chars("password\n") ''; }; @@ -801,7 +779,7 @@ in { # Simple GPT/UEFI configuration using systemd-boot with 3 partitions: ESP, swap & root filesystem simpleUefiSystemdBoot = makeInstallerTest "simpleUefiSystemdBoot" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel gpt" + " mkpart ESP fat32 1M 100MiB" # /boot + " set 1 boot on" @@ -828,7 +806,7 @@ in { # Same as the previous, but now with a separate /boot partition. separateBoot = makeInstallerTest "separateBoot" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100MB 1024M" @@ -848,7 +826,7 @@ in { # Same as the previous, but with fat32 /boot. separateBootFat = makeInstallerTest "separateBootFat" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100MB 1024M" @@ -880,7 +858,7 @@ in { ''; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 256MB" # /boot + " mkpart primary linux-swap 256MB 1280M" @@ -932,8 +910,8 @@ in { # umount & export bpool before shutdown # this is a fix for "cannot import 'bpool': pool was previously in use from another system." postInstallCommands = '' - machine.succeed("umount /mnt/boot") - machine.succeed("zpool export bpool") + installer.succeed("umount /mnt/boot") + installer.succeed("zpool export bpool") ''; }; @@ -954,7 +932,7 @@ in { ''; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" @@ -980,7 +958,7 @@ in { # that contains the logical swap and root partitions. lvm = makeInstallerTest "lvm" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary 1M 2048M" # PV1 + " set 1 lvm on" @@ -1013,7 +991,7 @@ in { # keyfile is configured encryptedFSWithKeyfile = makeInstallerTest "encryptedFSWithKeyfile" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" @@ -1052,7 +1030,7 @@ in { # LVM-on-LUKS and a keyfile in initrd.secrets to enter the passphrase once fullDiskEncryption = makeInstallerTest "fullDiskEncryption" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel gpt" + " mkpart ESP fat32 1M 100MiB" # /boot/efi + " set 1 boot on" @@ -1083,23 +1061,22 @@ in { boot.loader.grub.enableCryptodisk = true; boot.loader.efi.efiSysMountPoint = "/boot/efi"; - boot.initrd.secrets."/luks.key" = ./luks.key; + boot.initrd.secrets."/luks.key" = "/etc/nixos/luks.key"; boot.initrd.luks.devices.crypt = { device = "/dev/vda2"; keyFile = "/luks.key"; }; ''; enableOCR = true; - preBootCommands = '' - machine.start() - machine.wait_for_text("Enter passphrase for") - machine.send_chars("supersecret\n") + postBootCommands = '' + target.wait_for_text("Enter passphrase for") + target.send_chars("supersecret\n") ''; }; swraid = makeInstallerTest "swraid" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda --" + " mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot @@ -1128,15 +1105,14 @@ in { "udevadm settle", ) ''; - preBootCommands = '' - machine.start() - machine.fail("dmesg | grep 'immediate safe mode'") + postBootCommands = '' + target.fail("dmesg | grep 'immediate safe mode'") ''; }; bcache = makeInstallerTest "bcache" { createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda --" + " mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot @@ -1165,7 +1141,7 @@ in { }; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" # swap @@ -1197,18 +1173,17 @@ in { ''; enableOCR = true; - preBootCommands = '' - machine.start() + postBootCommands = '' # Enter it wrong once - machine.wait_for_text("enter passphrase for ") - machine.send_chars("wrong\n") + target.wait_for_text("enter passphrase for ") + target.send_chars("wrong\n") # Then enter it right. - machine.wait_for_text("enter passphrase for ") - machine.send_chars("password\n") + target.wait_for_text("enter passphrase for ") + target.send_chars("password\n") ''; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" # swap @@ -1235,7 +1210,7 @@ in { }; createPartitions = '' - machine.succeed( + installer.succeed( "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + " mkpart primary ext2 1M 100MB" # /boot + " mkpart primary linux-swap 100M 1024M" # swap @@ -1256,7 +1231,7 @@ in { # Test using labels to identify volumes in grub simpleLabels = makeInstallerTest "simpleLabels" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", "mkswap /dev/vda2 -L swap", @@ -1273,7 +1248,7 @@ in { simpleProvided = makeInstallerTest "simpleProvided" { createPartitions = '' uuid = "$(blkid -s UUID -o value /dev/vda2)" - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+100M -n 3:0:+1G -N 4 -t 1:ef02 -t 2:8300 " + "-t 3:8200 -t 4:8300 -c 2:boot -c 4:root /dev/vda", @@ -1282,9 +1257,9 @@ in { "mkfs.ext4 -L boot /dev/vda2", "mkfs.ext4 -L root /dev/vda4", ) - machine.execute(f"ln -s ../../vda2 /dev/disk/by-uuid/{uuid}") - machine.execute("ln -s ../../vda4 /dev/disk/by-label/root") - machine.succeed( + installer.execute(f"ln -s ../../vda2 /dev/disk/by-uuid/{uuid}") + installer.execute("ln -s ../../vda4 /dev/disk/by-label/root") + installer.succeed( "mount /dev/disk/by-label/root /mnt", "mkdir /mnt/boot", f"mount /dev/disk/by-uuid/{uuid} /mnt/boot", @@ -1296,7 +1271,7 @@ in { # Simple btrfs grub testing btrfsSimple = makeInstallerTest "btrfsSimple" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", "mkswap /dev/vda2 -L swap", @@ -1310,7 +1285,7 @@ in { # Test to see if we can detect /boot and /nix on subvolumes btrfsSubvols = makeInstallerTest "btrfsSubvols" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", "mkswap /dev/vda2 -L swap", @@ -1332,7 +1307,7 @@ in { # Test to see if we can detect default and aux subvolumes correctly btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", "mkswap /dev/vda2 -L swap", @@ -1358,7 +1333,7 @@ in { # Test to see if we can deal with subvols that need to be escaped in fstab btrfsSubvolEscape = makeInstallerTest "btrfsSubvolEscape" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk -Z /dev/vda", "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", "mkswap /dev/vda2 -L swap", @@ -1385,7 +1360,7 @@ in { } // optionalAttrs systemdStage1 { stratisRoot = makeInstallerTest "stratisRoot" { createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk --zap-all /dev/vda", "sgdisk --new=1:0:+100M --typecode=0:ef00 /dev/vda", # /boot "sgdisk --new=2:0:+1G --typecode=0:8200 /dev/vda", # swap @@ -1428,7 +1403,7 @@ in { in makeInstallerTest "gptAutoRoot" { disableFileSystems = true; createPartitions = '' - machine.succeed( + installer.succeed( "sgdisk --zap-all /dev/vda", "sgdisk --new=1:0:+100M --typecode=0:ef00 /dev/vda", # /boot "sgdisk --new=2:0:+1G --typecode=0:8200 /dev/vda", # swap diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix index 9714a94382ee0..5f0e7b3e37cd7 100644 --- a/nixos/tests/kernel-generic.nix +++ b/nixos/tests/kernel-generic.nix @@ -31,7 +31,6 @@ let linux_5_15_hardened linux_6_1_hardened linux_6_6_hardened - linux_6_7_hardened linux_rt_5_4 linux_rt_5_10 linux_rt_5_15 diff --git a/nixos/tests/lightdm.nix b/nixos/tests/lightdm.nix index 94cebd4a630ab..730983a804134 100644 --- a/nixos/tests/lightdm.nix +++ b/nixos/tests/lightdm.nix @@ -8,7 +8,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; services.xserver.displayManager.lightdm.enable = true; - services.xserver.displayManager.defaultSession = "none+icewm"; + services.displayManager.defaultSession = "none+icewm"; services.xserver.windowManager.icewm.enable = true; }; diff --git a/nixos/tests/maestral.nix b/nixos/tests/maestral.nix index 67a265926187d..52cc32cd0f4bb 100644 --- a/nixos/tests/maestral.nix +++ b/nixos/tests/maestral.nix @@ -29,11 +29,14 @@ import ./make-test-python.nix ({ pkgs, ... }: { gui = { ... }: common { services.xserver = { enable = true; - displayManager.sddm.enable = true; - displayManager.defaultSession = "plasma"; desktopManager.plasma5.enable = true; desktopManager.plasma5.runUsingSystemd = true; - displayManager.autoLogin = { + }; + + services.displayManager = { + sddm.enable = true; + defaultSession = "plasma"; + autoLogin = { enable = true; user = "alice"; }; diff --git a/nixos/tests/mate-wayland.nix b/nixos/tests/mate-wayland.nix index df39ead286e15..e5c96d2af7470 100644 --- a/nixos/tests/mate-wayland.nix +++ b/nixos/tests/mate-wayland.nix @@ -9,7 +9,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { ]; services.xserver.enable = true; - services.xserver.displayManager = { + services.displayManager = { sddm.enable = true; # https://github.com/canonical/lightdm/issues/63 sddm.wayland.enable = true; defaultSession = "MATE"; diff --git a/nixos/tests/matrix/mautrix-meta-postgres.nix b/nixos/tests/matrix/mautrix-meta-postgres.nix new file mode 100644 index 0000000000000..c9a45788afaf6 --- /dev/null +++ b/nixos/tests/matrix/mautrix-meta-postgres.nix @@ -0,0 +1,221 @@ +import ../make-test-python.nix ({ pkgs, ... }: + let + homeserverDomain = "server"; + homeserverUrl = "http://server:8008"; + userName = "alice"; + botUserName = "instagrambot"; + + asToken = "this-is-my-totally-randomly-generated-as-token"; + hsToken = "this-is-my-totally-randomly-generated-hs-token"; + in + { + name = "mautrix-meta-postgres"; + meta.maintainers = pkgs.mautrix-meta.meta.maintainers; + + nodes = { + server = { config, pkgs, ... }: { + services.postgresql = { + enable = true; + + ensureUsers = [ + { + name = "mautrix-meta-instagram"; + ensureDBOwnership = true; + } + ]; + + ensureDatabases = [ + "mautrix-meta-instagram" + ]; + }; + + systemd.services.mautrix-meta-instagram = { + wants = [ "postgres.service" ]; + after = [ "postgres.service" ]; + }; + + services.matrix-synapse = { + enable = true; + settings = { + database.name = "sqlite3"; + + enable_registration = true; + + # don't use this in production, always use some form of verification + enable_registration_without_verification = true; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" + ]; + port = 8008; + resources = [ { + "compress" = true; + "names" = [ "client" ]; + } { + "compress" = false; + "names" = [ "federation" ]; + } ]; + tls = false; + type = "http"; + } ]; + }; + }; + + services.mautrix-meta.instances.instagram = { + enable = true; + + environmentFile = pkgs.writeText ''my-secrets'' '' + AS_TOKEN=${asToken} + HS_TOKEN=${hsToken} + ''; + + settings = { + homeserver = { + address = homeserverUrl; + domain = homeserverDomain; + }; + + appservice = { + port = 8009; + + as_token = "$AS_TOKEN"; + hs_token = "$HS_TOKEN"; + + database = { + type = "postgres"; + uri = "postgres:///mautrix-meta-instagram?host=/var/run/postgresql"; + }; + + bot.username = botUserName; + }; + + bridge.permissions."@${userName}:server" = "user"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8008 8009 ]; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ + (pkgs.writers.writePython3Bin "do_test" + { + libraries = [ pkgs.python3Packages.matrix-nio ]; + flakeIgnore = [ + # We don't live in the dark ages anymore. + # Languages like Python that are whitespace heavy will overrun + # 79 characters.. + "E501" + ]; + } '' + import sys + import functools + import asyncio + + from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse + + + async def message_callback(matrix: AsyncClient, msg: str, _r, e): + print("Received matrix text message: ", e) + assert msg in e.body + exit(0) # Success! + + + async def run(homeserver: str): + matrix = AsyncClient(homeserver) + response = await matrix.register("${userName}", "foobar") + print("Matrix register response: ", response) + + # Open a DM with the bridge bot + response = await matrix.room_create() + print("Matrix create room response:", response) + assert isinstance(response, RoomCreateResponse) + room_id = response.room_id + + response = await matrix.room_invite(room_id, "@${botUserName}:${homeserverDomain}") + assert isinstance(response, RoomInviteResponse) + + callback = functools.partial( + message_callback, matrix, "Hello, I'm an Instagram bridge bot." + ) + matrix.add_event_callback(callback, RoomMessageNotice) + + print("Waiting for matrix message...") + await matrix.sync_forever(timeout=30000) + + + if __name__ == "__main__": + asyncio.run(run(sys.argv[1])) + '' + ) + ]; + }; + }; + + testScript = '' + def extract_token(data): + stdout = data[1] + stdout = stdout.strip() + line = stdout.split('\n')[-1] + return line.split(':')[-1].strip("\" '\n") + + def get_token_from(token, file): + data = server.execute(f"cat {file} | grep {token}") + return extract_token(data) + + def get_as_token_from(file): + return get_token_from("as_token", file) + + def get_hs_token_from(file): + return get_token_from("hs_token", file) + + config_yaml = "/var/lib/mautrix-meta-instagram/config.yaml" + registration_yaml = "/var/lib/mautrix-meta-instagram/meta-registration.yaml" + + expected_as_token = "${asToken}" + expected_hs_token = "${hsToken}" + + start_all() + + with subtest("start the server"): + # bridge + server.wait_for_unit("mautrix-meta-instagram.service") + + # homeserver + server.wait_for_unit("matrix-synapse.service") + + server.wait_for_open_port(8008) + # Bridge only opens the port after it contacts the homeserver + server.wait_for_open_port(8009) + + with subtest("ensure messages can be exchanged"): + client.succeed("do_test ${homeserverUrl} >&2") + + with subtest("ensure as_token, hs_token match from environment file"): + as_token = get_as_token_from(config_yaml) + hs_token = get_hs_token_from(config_yaml) + as_token_registration = get_as_token_from(registration_yaml) + hs_token_registration = get_hs_token_from(registration_yaml) + + assert as_token == expected_as_token, f"as_token in config should match the one specified (is: {as_token}, expected: {expected_as_token})" + assert hs_token == expected_hs_token, f"hs_token in config should match the one specified (is: {hs_token}, expected: {expected_hs_token})" + assert as_token_registration == expected_as_token, f"as_token in registration should match the one specified (is: {as_token_registration}, expected: {expected_as_token})" + assert hs_token_registration == expected_hs_token, f"hs_token in registration should match the one specified (is: {hs_token_registration}, expected: {expected_hs_token})" + + with subtest("ensure as_token and hs_token stays same after restart"): + server.systemctl("restart mautrix-meta-instagram") + server.wait_for_open_port(8009) + + as_token = get_as_token_from(config_yaml) + hs_token = get_hs_token_from(config_yaml) + as_token_registration = get_as_token_from(registration_yaml) + hs_token_registration = get_hs_token_from(registration_yaml) + + assert as_token == expected_as_token, f"as_token in config should match the one specified (is: {as_token}, expected: {expected_as_token})" + assert hs_token == expected_hs_token, f"hs_token in config should match the one specified (is: {hs_token}, expected: {expected_hs_token})" + assert as_token_registration == expected_as_token, f"as_token in registration should match the one specified (is: {as_token_registration}, expected: {expected_as_token})" + assert hs_token_registration == expected_hs_token, f"hs_token in registration should match the one specified (is: {hs_token_registration}, expected: {expected_hs_token})" + ''; + }) diff --git a/nixos/tests/matrix/mautrix-meta-sqlite.nix b/nixos/tests/matrix/mautrix-meta-sqlite.nix new file mode 100644 index 0000000000000..b5e580620049a --- /dev/null +++ b/nixos/tests/matrix/mautrix-meta-sqlite.nix @@ -0,0 +1,247 @@ +import ../make-test-python.nix ({ pkgs, ... }: + let + homeserverDomain = "server"; + homeserverUrl = "http://server:8008"; + username = "alice"; + instagramBotUsername = "instagrambot"; + facebookBotUsername = "facebookbot"; + in + { + name = "mautrix-meta-sqlite"; + meta.maintainers = pkgs.mautrix-meta.meta.maintainers; + + nodes = { + server = { config, pkgs, ... }: { + services.matrix-synapse = { + enable = true; + settings = { + database.name = "sqlite3"; + + enable_registration = true; + + # don't use this in production, always use some form of verification + enable_registration_without_verification = true; + + listeners = [ { + # The default but tls=false + bind_addresses = [ + "0.0.0.0" + ]; + port = 8008; + resources = [ { + "compress" = true; + "names" = [ "client" ]; + } { + "compress" = false; + "names" = [ "federation" ]; + } ]; + tls = false; + type = "http"; + } ]; + }; + }; + + services.mautrix-meta.instances.facebook = { + enable = true; + + settings = { + homeserver = { + address = homeserverUrl; + domain = homeserverDomain; + }; + + appservice = { + port = 8009; + + bot.username = facebookBotUsername; + }; + + bridge.permissions."@${username}:server" = "user"; + }; + }; + + services.mautrix-meta.instances.instagram = { + enable = true; + + settings = { + homeserver = { + address = homeserverUrl; + domain = homeserverDomain; + }; + + appservice = { + port = 8010; + + bot.username = instagramBotUsername; + }; + + bridge.permissions."@${username}:server" = "user"; + }; + }; + + networking.firewall.allowedTCPPorts = [ 8008 ]; + }; + + client = { pkgs, ... }: { + environment.systemPackages = [ + (pkgs.writers.writePython3Bin "register_user" + { + libraries = [ pkgs.python3Packages.matrix-nio ]; + flakeIgnore = [ + # We don't live in the dark ages anymore. + # Languages like Python that are whitespace heavy will overrun + # 79 characters.. + "E501" + ]; + } '' + import sys + import asyncio + + from nio import AsyncClient + + + async def run(username: str, homeserver: str): + matrix = AsyncClient(homeserver) + + response = await matrix.register(username, "foobar") + print("Matrix register response: ", response) + + + if __name__ == "__main__": + asyncio.run(run(sys.argv[1], sys.argv[2])) + '' + ) + (pkgs.writers.writePython3Bin "do_test" + { + libraries = [ pkgs.python3Packages.matrix-nio ]; + flakeIgnore = [ + # We don't live in the dark ages anymore. + # Languages like Python that are whitespace heavy will overrun + # 79 characters.. + "E501" + ]; + } '' + import sys + import functools + import asyncio + + from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse + + + async def message_callback(matrix: AsyncClient, msg: str, _r, e): + print("Received matrix text message: ", e) + assert msg in e.body + exit(0) # Success! + + + async def run(username: str, bot_username: str, homeserver: str): + matrix = AsyncClient(homeserver, f"@{username}:${homeserverDomain}") + + response = await matrix.login("foobar") + print("Matrix login response: ", response) + + # Open a DM with the bridge bot + response = await matrix.room_create() + print("Matrix create room response:", response) + assert isinstance(response, RoomCreateResponse) + room_id = response.room_id + + response = await matrix.room_invite(room_id, f"@{bot_username}:${homeserverDomain}") + assert isinstance(response, RoomInviteResponse) + + callback = functools.partial( + message_callback, matrix, "Hello, I'm an Instagram bridge bot." + ) + matrix.add_event_callback(callback, RoomMessageNotice) + + print("Waiting for matrix message...") + await matrix.sync_forever(timeout=30000) + + + if __name__ == "__main__": + asyncio.run(run(sys.argv[1], sys.argv[2], sys.argv[3])) + '' + ) + ]; + }; + }; + + testScript = '' + def extract_token(data): + stdout = data[1] + stdout = stdout.strip() + line = stdout.split('\n')[-1] + return line.split(':')[-1].strip("\" '\n") + + def get_token_from(token, file): + data = server.execute(f"cat {file} | grep {token}") + return extract_token(data) + + def get_as_token_from(file): + return get_token_from("as_token", file) + + def get_hs_token_from(file): + return get_token_from("hs_token", file) + + config_yaml = "/var/lib/mautrix-meta-facebook/config.yaml" + registration_yaml = "/var/lib/mautrix-meta-facebook/meta-registration.yaml" + + start_all() + + with subtest("wait for bridges and homeserver"): + # bridge + server.wait_for_unit("mautrix-meta-facebook.service") + server.wait_for_unit("mautrix-meta-instagram.service") + + # homeserver + server.wait_for_unit("matrix-synapse.service") + + server.wait_for_open_port(8008) + # Bridges only open the port after they contact the homeserver + server.wait_for_open_port(8009) + server.wait_for_open_port(8010) + + with subtest("register user"): + client.succeed("register_user ${username} ${homeserverUrl} >&2") + + with subtest("ensure messages can be exchanged"): + client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2") + client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2") + + with subtest("ensure as_token and hs_token stays same after restart"): + generated_as_token_facebook = get_as_token_from(config_yaml) + generated_hs_token_facebook = get_hs_token_from(config_yaml) + + generated_as_token_facebook_registration = get_as_token_from(registration_yaml) + generated_hs_token_facebook_registration = get_hs_token_from(registration_yaml) + + # Indirectly checks the as token is not set to something like empty string or "null" + assert len(generated_as_token_facebook) > 20, f"as_token ({generated_as_token_facebook}) is too short, something went wrong" + assert len(generated_hs_token_facebook) > 20, f"hs_token ({generated_hs_token_facebook}) is too short, something went wrong" + + assert generated_as_token_facebook == generated_as_token_facebook_registration, f"as_token should be the same in registration ({generated_as_token_facebook_registration}) and configuration ({generated_as_token_facebook}) files" + assert generated_hs_token_facebook == generated_hs_token_facebook_registration, f"hs_token should be the same in registration ({generated_hs_token_facebook_registration}) and configuration ({generated_hs_token_facebook}) files" + + server.systemctl("restart mautrix-meta-facebook") + server.systemctl("restart mautrix-meta-instagram") + + server.wait_for_open_port(8009) + server.wait_for_open_port(8010) + + new_as_token_facebook = get_as_token_from(config_yaml) + new_hs_token_facebook = get_hs_token_from(config_yaml) + + assert generated_as_token_facebook == new_as_token_facebook, f"as_token should stay the same after restart inside the configuration file (is: {new_as_token_facebook}, was: {generated_as_token_facebook})" + assert generated_hs_token_facebook == new_hs_token_facebook, f"hs_token should stay the same after restart inside the configuration file (is: {new_hs_token_facebook}, was: {generated_hs_token_facebook})" + + new_as_token_facebook = get_as_token_from(registration_yaml) + new_hs_token_facebook = get_hs_token_from(registration_yaml) + + assert generated_as_token_facebook == new_as_token_facebook, f"as_token should stay the same after restart inside the registration file (is: {new_as_token_facebook}, was: {generated_as_token_facebook})" + assert generated_hs_token_facebook == new_hs_token_facebook, f"hs_token should stay the same after restart inside the registration file (is: {new_hs_token_facebook}, was: {generated_hs_token_facebook})" + + with subtest("ensure messages can be exchanged after restart"): + client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2") + client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2") + ''; + }) diff --git a/nixos/tests/miriway.nix b/nixos/tests/miriway.nix index 24e6ec6367cdb..94373bb75a915 100644 --- a/nixos/tests/miriway.nix +++ b/nixos/tests/miriway.nix @@ -19,10 +19,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { user = "alice"; }; - services.xserver = { - enable = true; - displayManager.defaultSession = lib.mkForce "miriway"; - }; + services.xserver.enable = true; + services.displayManager.defaultSession = lib.mkForce "miriway"; programs.miriway = { enable = true; diff --git a/nixos/tests/nimdow.nix b/nixos/tests/nimdow.nix index cefe46edc5fb2..0656ef04be483 100644 --- a/nixos/tests/nimdow.nix +++ b/nixos/tests/nimdow.nix @@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { nodes.machine = { lib, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = lib.mkForce "none+nimdow"; + services.displayManager.defaultSession = lib.mkForce "none+nimdow"; services.xserver.windowManager.nimdow.enable = true; }; diff --git a/nixos/tests/oddjobd.nix b/nixos/tests/oddjobd.nix new file mode 100644 index 0000000000000..cc2d4079eebc9 --- /dev/null +++ b/nixos/tests/oddjobd.nix @@ -0,0 +1,23 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: { + name = "oddjobd"; + meta.maintainers = [ lib.maintainers.anthonyroussel ]; + + nodes.machine = { ... } : { + environment.systemPackages = [ + pkgs.oddjob + ]; + + programs.oddjobd.enable = true; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("oddjobd.service") + machine.wait_for_file("/run/oddjobd.pid") + + with subtest("send oddjob listall request"): + result = machine.succeed("oddjob_request -s com.redhat.oddjob -o /com/redhat/oddjob -i com.redhat.oddjob listall") + assert ('(service="com.redhat.oddjob",object="/com/redhat/oddjob",interface="com.redhat.oddjob",method="listall")' in result) + ''; +}) diff --git a/nixos/tests/pantheon.nix b/nixos/tests/pantheon.nix index 14f92fa3af4a2..d2a4a009af53d 100644 --- a/nixos/tests/pantheon.nix +++ b/nixos/tests/pantheon.nix @@ -13,6 +13,13 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : services.xserver.enable = true; services.xserver.desktopManager.pantheon.enable = true; + # We ship pantheon.appcenter by default when this is enabled. + services.flatpak.enable = true; + + # We don't ship gnome-text-editor in Pantheon module, we add this line mainly + # to catch eval issues related to this option. + environment.pantheon.excludePackages = [ pkgs.gnome-text-editor ]; + environment.systemPackages = [ pkgs.xdotool ]; }; @@ -50,7 +57,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.wait_until_succeeds(f"pgrep -f {i}") for i in ["gala", "io.elementary.wingpanel", "plank"]: machine.wait_for_window(i) - for i in ["io.elementary.gala.daemon@x11.service", "bamfdaemon.service", "io.elementary.files.xdg-desktop-portal.service"]: + for i in ["bamfdaemon.service", "io.elementary.files.xdg-desktop-portal.service"]: machine.wait_for_unit(i, "${user.name}") with subtest("Check if various environment variables are set"): diff --git a/nixos/tests/plasma-bigscreen.nix b/nixos/tests/plasma-bigscreen.nix index 2fe90fa9b539c..050937f33442d 100644 --- a/nixos/tests/plasma-bigscreen.nix +++ b/nixos/tests/plasma-bigscreen.nix @@ -11,10 +11,10 @@ import ./make-test-python.nix ({ pkgs, ...} : { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; - services.xserver.displayManager.sddm.enable = true; - services.xserver.displayManager.defaultSession = "plasma-bigscreen-x11"; + services.displayManager.sddm.enable = true; + services.displayManager.defaultSession = "plasma-bigscreen-x11"; services.xserver.desktopManager.plasma5.bigscreen.enable = true; - services.xserver.displayManager.autoLogin = { + services.displayManager.autoLogin = { enable = true; user = "alice"; }; diff --git a/nixos/tests/plasma5-systemd-start.nix b/nixos/tests/plasma5-systemd-start.nix index 31a313af308b4..891d4df2409f2 100644 --- a/nixos/tests/plasma5-systemd-start.nix +++ b/nixos/tests/plasma5-systemd-start.nix @@ -12,11 +12,14 @@ import ./make-test-python.nix ({ pkgs, ...} : imports = [ ./common/user-account.nix ]; services.xserver = { enable = true; - displayManager.sddm.enable = true; - displayManager.defaultSession = "plasma"; desktopManager.plasma5.enable = true; desktopManager.plasma5.runUsingSystemd = true; - displayManager.autoLogin = { + }; + + services.displayManager = { + sddm.enable = true; + defaultSession = "plasma"; + autoLogin = { enable = true; user = "alice"; }; diff --git a/nixos/tests/plasma5.nix b/nixos/tests/plasma5.nix index fb8a5b73832ea..1bff37981da3f 100644 --- a/nixos/tests/plasma5.nix +++ b/nixos/tests/plasma5.nix @@ -11,11 +11,11 @@ import ./make-test-python.nix ({ pkgs, ...} : { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; - services.xserver.displayManager.sddm.enable = true; - services.xserver.displayManager.defaultSession = "plasma"; + services.displayManager.sddm.enable = true; + services.displayManager.defaultSession = "plasma"; services.xserver.desktopManager.plasma5.enable = true; environment.plasma5.excludePackages = [ pkgs.plasma5Packages.elisa ]; - services.xserver.displayManager.autoLogin = { + services.displayManager.autoLogin = { enable = true; user = "alice"; }; diff --git a/nixos/tests/plasma6.nix b/nixos/tests/plasma6.nix index ec5b3f24ef749..7c8fba130e681 100644 --- a/nixos/tests/plasma6.nix +++ b/nixos/tests/plasma6.nix @@ -11,12 +11,12 @@ import ./make-test-python.nix ({ pkgs, ...} : { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; - services.xserver.displayManager.sddm.enable = true; + services.displayManager.sddm.enable = true; # FIXME: this should be testing Wayland - services.xserver.displayManager.defaultSession = "plasmax11"; - services.xserver.desktopManager.plasma6.enable = true; + services.displayManager.defaultSession = "plasmax11"; + services.desktopManager.plasma6.enable = true; environment.plasma6.excludePackages = [ pkgs.kdePackages.elisa ]; - services.xserver.displayManager.autoLogin = { + services.displayManager.autoLogin = { enable = true; user = "alice"; }; diff --git a/nixos/tests/ragnarwm.nix b/nixos/tests/ragnarwm.nix index f7c588b920081..6dc08a805ab12 100644 --- a/nixos/tests/ragnarwm.nix +++ b/nixos/tests/ragnarwm.nix @@ -8,7 +8,7 @@ import ./make-test-python.nix ({ lib, ...} : { nodes.machine = { pkgs, lib, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = lib.mkForce "ragnar"; + services.displayManager.defaultSession = lib.mkForce "ragnar"; services.xserver.windowManager.ragnarwm.enable = true; # Setup the default terminal of Ragnar diff --git a/nixos/tests/restic-rest-server.nix b/nixos/tests/restic-rest-server.nix new file mode 100644 index 0000000000000..1d38ddbe513c9 --- /dev/null +++ b/nixos/tests/restic-rest-server.nix @@ -0,0 +1,122 @@ +import ./make-test-python.nix ( + { pkgs, ... }: + + let + remoteRepository = "rest:http://restic_rest_server:8001/"; + + backupPrepareCommand = '' + touch /root/backupPrepareCommand + test ! -e /root/backupCleanupCommand + ''; + + backupCleanupCommand = '' + rm /root/backupPrepareCommand + touch /root/backupCleanupCommand + ''; + + testDir = pkgs.stdenvNoCC.mkDerivation { + name = "test-files-to-backup"; + unpackPhase = "true"; + installPhase = '' + mkdir $out + echo some_file > $out/some_file + echo some_other_file > $out/some_other_file + mkdir $out/a_dir + echo a_file > $out/a_dir/a_file + ''; + }; + + passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}"; + paths = [ "/opt" ]; + exclude = [ "/opt/excluded_file_*" ]; + pruneOpts = [ + "--keep-daily 2" + "--keep-weekly 1" + "--keep-monthly 1" + "--keep-yearly 99" + ]; + in + { + name = "restic-rest-server"; + + nodes = { + restic_rest_server = { + services.restic.server = { + enable = true; + extraFlags = [ "--no-auth" ]; + listenAddress = "8001"; + }; + networking.firewall.allowedTCPPorts = [ 8001 ]; + }; + server = { + services.restic.backups = { + remotebackup = { + inherit passwordFile paths exclude pruneOpts backupPrepareCommand backupCleanupCommand; + repository = remoteRepository; + initialize = true; + timerConfig = null; # has no effect here, just checking that it doesn't break the service + }; + remoteprune = { + inherit passwordFile; + repository = remoteRepository; + pruneOpts = [ "--keep-last 1" ]; + }; + }; + }; + }; + + testScript = '' + restic_rest_server.start() + server.start() + restic_rest_server.wait_for_unit("restic-rest-server.socket") + restic_rest_server.wait_for_open_port(8001) + server.wait_for_unit("dbus.socket") + server.fail( + "restic-remotebackup snapshots", + ) + server.succeed( + # set up + "cp -rT ${testDir} /opt", + "touch /opt/excluded_file_1 /opt/excluded_file_2", + + # test that remotebackup runs custom commands and produces a snapshot + "timedatectl set-time '2016-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + + # test that restoring that snapshot produces the same directory + "mkdir /tmp/restore-1", + "restic-remotebackup restore latest -t /tmp/restore-1", + "diff -ru ${testDir} /tmp/restore-1/opt", + + # test that we can create four snapshots in remotebackup and rclonebackup + "timedatectl set-time '2017-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + + "timedatectl set-time '2018-12-13 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + + "timedatectl set-time '2018-12-14 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + + "timedatectl set-time '2018-12-15 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + + "timedatectl set-time '2018-12-16 13:45'", + "systemctl start restic-backups-remotebackup.service", + "rm /root/backupCleanupCommand", + + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 4"', + + # test that remoteprune brings us back to 1 snapshot in remotebackup + "systemctl start restic-backups-remoteprune.service", + 'restic-remotebackup snapshots --json | ${pkgs.jq}/bin/jq "length | . == 1"', + ) + ''; + } +) diff --git a/nixos/tests/sddm.nix b/nixos/tests/sddm.nix index b6c05deac05e4..3ca105cf9713d 100644 --- a/nixos/tests/sddm.nix +++ b/nixos/tests/sddm.nix @@ -15,8 +15,8 @@ let nodes.machine = { ... }: { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; - services.xserver.displayManager.sddm.enable = true; - services.xserver.displayManager.defaultSession = "none+icewm"; + services.displayManager.sddm.enable = true; + services.displayManager.defaultSession = "none+icewm"; services.xserver.windowManager.icewm.enable = true; }; @@ -44,14 +44,14 @@ let nodes.machine = { ... }: { imports = [ ./common/user-account.nix ]; services.xserver.enable = true; - services.xserver.displayManager = { + services.displayManager = { sddm.enable = true; autoLogin = { enable = true; user = "alice"; }; }; - services.xserver.displayManager.defaultSession = "none+icewm"; + services.displayManager.defaultSession = "none+icewm"; services.xserver.windowManager.icewm.enable = true; }; diff --git a/nixos/tests/silverbullet.nix b/nixos/tests/silverbullet.nix new file mode 100644 index 0000000000000..e7e3cf5365583 --- /dev/null +++ b/nixos/tests/silverbullet.nix @@ -0,0 +1,47 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "silverbullet"; + meta.maintainers = with lib.maintainers; [ aorith ]; + + nodes.simple = { ... }: { + services.silverbullet.enable = true; + }; + + nodes.configured = { pkgs, ... }: { + users.users.test.isNormalUser = true; + users.groups.test = { }; + + services.silverbullet = { + enable = true; + package = pkgs.silverbullet; + listenPort = 3001; + listenAddress = "localhost"; + spaceDir = "/home/test/silverbullet"; + user = "test"; + group = "test"; + envFile = pkgs.writeText "silverbullet.env" '' + SB_USER=user:password + SB_AUTH_TOKEN=test + ''; + extraArgs = [ "--reindex" "--db /home/test/silverbullet/custom.db" ]; + }; + }; + + testScript = { nodes, ... }: '' + PORT = ${builtins.toString nodes.simple.services.silverbullet.listenPort} + ADDRESS = "${nodes.simple.services.silverbullet.listenAddress}" + SPACEDIR = "${nodes.simple.services.silverbullet.spaceDir}" + simple.wait_for_unit("silverbullet.service") + simple.wait_for_open_port(PORT) + simple.succeed(f"curl --max-time 5 -s -v -o /dev/null --fail http://{ADDRESS}:{PORT}/") + simple.succeed(f"test -d '{SPACEDIR}'") + + PORT = ${builtins.toString nodes.configured.services.silverbullet.listenPort} + ADDRESS = "${nodes.configured.services.silverbullet.listenAddress}" + SPACEDIR = "${nodes.configured.services.silverbullet.spaceDir}" + configured.wait_for_unit("silverbullet.service") + configured.wait_for_open_port(PORT) + assert int(configured.succeed(f"curl --max-time 5 -s -o /dev/null -w '%{{http_code}}' -XPUT -d 'test' --fail http://{ADDRESS}:{PORT}/test.md -H'Authorization: Bearer test'")) == 200 + assert int(configured.fail(f"curl --max-time 5 -s -o /dev/null -w '%{{http_code}}' -XPUT -d 'test' --fail http://{ADDRESS}:{PORT}/test.md -H'Authorization: Bearer wrong'")) == 401 + configured.succeed(f"test -d '{SPACEDIR}'") + ''; +}) diff --git a/nixos/tests/soju.nix b/nixos/tests/soju.nix new file mode 100644 index 0000000000000..23da36f7b3aba --- /dev/null +++ b/nixos/tests/soju.nix @@ -0,0 +1,31 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: +let + certs = import ./common/acme/server/snakeoil-certs.nix; + domain = certs.domain; + + user = "testuser"; + pass = "hunter2"; +in +{ + name = "soju"; + meta.maintainers = with lib.maintainers; [ Benjamin-L ]; + + nodes.machine = { ... }: { + services.soju = { + enable = true; + adminSocket.enable = true; + hostName = domain; + tlsCertificate = certs.${domain}.cert; + tlsCertificateKey = certs.${domain}.key; + }; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("soju") + machine.wait_for_file("/run/soju/admin") + + machine.succeed("sojuctl user create -username ${user} -password ${pass}") + ''; +}) diff --git a/nixos/tests/switch-test.nix b/nixos/tests/switch-test.nix index 5ffdf180d5e3f..a57d66f82eac9 100644 --- a/nixos/tests/switch-test.nix +++ b/nixos/tests/switch-test.nix @@ -691,9 +691,9 @@ in { with subtest("continuing from an aborted switch"): # An aborted switch will write into a file what it tried to start # and a second switch should continue from this - machine.succeed("echo dbus.service > /run/nixos/start-list") + machine.succeed("echo dbus-broker.service > /run/nixos/start-list") out = switch_to_specialisation("${machine}", "modifiedSystemConf") - assert_contains(out, "starting the following units: dbus.service\n") + assert_contains(out, "starting the following units: dbus-broker.service\n") with subtest("fstab mounts"): switch_to_specialisation("${machine}", "") @@ -732,7 +732,7 @@ in { out = switch_to_specialisation("${machine}", "") assert_contains(out, "stopping the following units: test.mount\n") assert_lacks(out, "NOT restarting the following changed units:") - assert_contains(out, "reloading the following units: dbus.service\n") + assert_contains(out, "reloading the following units: dbus-broker.service\n") assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_lacks(out, "the following new units were started:") @@ -740,7 +740,7 @@ in { out = switch_to_specialisation("${machine}", "storeMountModified") assert_lacks(out, "stopping the following units:") assert_contains(out, "NOT restarting the following changed units: -.mount") - assert_contains(out, "reloading the following units: dbus.service\n") + assert_contains(out, "reloading the following units: dbus-broker.service\n") assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_lacks(out, "the following new units were started:") @@ -751,7 +751,7 @@ in { out = switch_to_specialisation("${machine}", "swap") assert_lacks(out, "stopping the following units:") assert_lacks(out, "NOT restarting the following changed units:") - assert_contains(out, "reloading the following units: dbus.service\n") + assert_contains(out, "reloading the following units: dbus-broker.service\n") assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_contains(out, "the following new units were started: swapfile.swap") @@ -760,7 +760,7 @@ in { assert_contains(out, "stopping swap device: /swapfile") assert_lacks(out, "stopping the following units:") assert_lacks(out, "NOT restarting the following changed units:") - assert_contains(out, "reloading the following units: dbus.service\n") + assert_contains(out, "reloading the following units: dbus-broker.service\n") assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_lacks(out, "the following new units were started:") @@ -781,7 +781,7 @@ in { assert_lacks(out, "installing dummy bootloader") # test does not install a bootloader assert_lacks(out, "stopping the following units:") assert_lacks(out, "NOT restarting the following changed units:") - assert_contains(out, "reloading the following units: dbus.service\n") # huh + assert_contains(out, "reloading the following units: dbus-broker.service\n") # huh assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_contains(out, "the following new units were started: test.service\n") @@ -858,7 +858,7 @@ in { assert_lacks(out, "installing dummy bootloader") # test does not install a bootloader assert_lacks(out, "stopping the following units:") assert_lacks(out, "NOT restarting the following changed units:") - assert_contains(out, "reloading the following units: dbus.service\n") # huh + assert_contains(out, "reloading the following units: dbus-broker.service\n") # huh assert_lacks(out, "\nrestarting the following units:") assert_lacks(out, "\nstarting the following units:") assert_contains(out, "the following new units were started: test.service\n") diff --git a/nixos/tests/technitium-dns-server.nix b/nixos/tests/technitium-dns-server.nix new file mode 100644 index 0000000000000..016c9d4ecead5 --- /dev/null +++ b/nixos/tests/technitium-dns-server.nix @@ -0,0 +1,21 @@ +import ./make-test-python.nix ({pkgs, lib, ...}: +{ + name = "technitium-dns-server"; + + nodes = { + machine = {pkgs, ...}: { + services.technitium-dns-server = { + enable = true; + openFirewall = true; + }; + }; + }; + + testScript = '' + start_all() + machine.wait_for_unit("technitium-dns-server.service") + machine.wait_for_open_port(53) + ''; + + meta.maintainers = with lib.maintainers; [ fabianrig ]; +}) diff --git a/nixos/tests/unifi.nix b/nixos/tests/unifi.nix index d371bafd69652..789b11b55985c 100644 --- a/nixos/tests/unifi.nix +++ b/nixos/tests/unifi.nix @@ -31,8 +31,6 @@ let ''; }; in with pkgs; { - unifiLTS = makeAppTest unifiLTS; - unifi5 = makeAppTest unifi5; - unifi6 = makeAppTest unifi6; unifi7 = makeAppTest unifi7; + unifi8 = makeAppTest unifi8; } diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix index 9d2f0e6ab060e..28ff170e36107 100644 --- a/nixos/tests/vaultwarden.nix +++ b/nixos/tests/vaultwarden.nix @@ -106,7 +106,7 @@ let wait = WebDriverWait(driver, 10) - wait.until(EC.title_contains("Create account")) + wait.until(EC.title_contains("Vaultwarden Web")) driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_email').send_keys( '${userEmail}' diff --git a/nixos/tests/web-apps/movim/default.nix b/nixos/tests/web-apps/movim/default.nix new file mode 100644 index 0000000000000..5d6314e2b41be --- /dev/null +++ b/nixos/tests/web-apps/movim/default.nix @@ -0,0 +1,8 @@ +{ system ? builtins.currentSystem, handleTestOn }: + +let + supportedSystems = [ "x86_64-linux" "i686-linux" ]; +in +{ + standard = handleTestOn supportedSystems ./standard.nix { inherit system; }; +} diff --git a/nixos/tests/web-apps/movim/standard.nix b/nixos/tests/web-apps/movim/standard.nix new file mode 100644 index 0000000000000..470d81d8f7229 --- /dev/null +++ b/nixos/tests/web-apps/movim/standard.nix @@ -0,0 +1,102 @@ +import ../../make-test-python.nix ({ lib, pkgs, ... }: + +let + movim = { + domain = "movim.local"; + info = "No ToS in tests"; + description = "NixOS testing server"; + }; + xmpp = { + domain = "xmpp.local"; + admin = rec { + JID = "${username}@${xmpp.domain}"; + username = "romeo"; + password = "juliet"; + }; + }; +in +{ + name = "movim-standard"; + + meta = { + maintainers = with pkgs.lib.maintainers; [ toastal ]; + }; + + nodes = { + server = { pkgs, ... }: { + services.movim = { + inherit (movim) domain; + enable = true; + verbose = true; + podConfig = { + inherit (movim) description info; + xmppdomain = xmpp.domain; + }; + nginx = { }; + }; + + services.prosody = { + enable = true; + xmppComplianceSuite = false; + disco_items = [ + { url = "upload.${xmpp.domain}"; description = "File Uploads"; } + ]; + virtualHosts."${xmpp.domain}" = { + inherit (xmpp) domain; + enabled = true; + extraConfig = '' + Component "pubsub.${xmpp.domain}" "pubsub" + pubsub_max_items = 10000 + expose_publisher = true + + Component "upload.${xmpp.domain}" "http_file_share" + http_external_url = "http://upload.${xmpp.domain}" + http_file_share_expires_after = 300 * 24 * 60 * 60 + http_file_share_size_limit = 1024 * 1024 * 1024 + http_file_share_daily_quota = 4 * 1024 * 1024 * 1024 + ''; + }; + extraConfig = '' + pep_max_items = 10000 + + http_paths = { + file_share = "/"; + } + ''; + }; + + networking.extraHosts = '' + 127.0.0.1 ${movim.domain} + 127.0.0.1 ${xmpp.domain} + ''; + }; + }; + + testScript = /* python */ '' + server.wait_for_unit("phpfpm-movim.service") + server.wait_for_unit("nginx.service") + server.wait_for_open_port(80) + + server.wait_for_unit("prosody.service") + server.succeed('prosodyctl status | grep "Prosody is running"') + server.succeed("prosodyctl register ${xmpp.admin.username} ${xmpp.domain} ${xmpp.admin.password}") + + server.wait_for_unit("movim.service") + + # Test unauthenticated + server.fail("curl -L --fail-with-body --max-redirs 0 http://${movim.domain}/chat") + + # Test basic Websocket + server.succeed("echo \"\" | ${lib.getExe pkgs.websocat} 'ws://${movim.domain}/ws/?path=login&offset=0' --origin 'http://${movim.domain}'") + + # Test login + create cookiejar + login_html = server.succeed("curl --fail-with-body -c /tmp/cookies http://${movim.domain}/login") + assert "${movim.description}" in login_html + assert "${movim.info}" in login_html + + # Test authentication POST + server.succeed("curl --fail-with-body -b /tmp/cookies -X POST --data-urlencode 'username=${xmpp.admin.JID}' --data-urlencode 'password=${xmpp.admin.password}' http://${movim.domain}/login") + + server.succeed("curl -L --fail-with-body --max-redirs 1 -b /tmp/cookies http://${movim.domain}/chat") + ''; +}) diff --git a/nixos/tests/wmderland.nix b/nixos/tests/wmderland.nix index ebfd443763e1e..c60751c44e2cc 100644 --- a/nixos/tests/wmderland.nix +++ b/nixos/tests/wmderland.nix @@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { nodes.machine = { lib, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = lib.mkForce "none+wmderland"; + services.displayManager.defaultSession = lib.mkForce "none+wmderland"; services.xserver.windowManager.wmderland.enable = true; systemd.services.setupWmderlandConfig = { diff --git a/nixos/tests/xfce.nix b/nixos/tests/xfce.nix index 9620e9188cbf5..d97f07d752712 100644 --- a/nixos/tests/xfce.nix +++ b/nixos/tests/xfce.nix @@ -10,13 +10,11 @@ import ./make-test-python.nix ({ pkgs, ...} : { ]; services.xserver.enable = true; + services.xserver.displayManager.lightdm.enable = true; - services.xserver.displayManager = { - lightdm.enable = true; - autoLogin = { - enable = true; - user = "alice"; - }; + services.displayManager.autoLogin = { + enable = true; + user = "alice"; }; services.xserver.desktopManager.xfce.enable = true; diff --git a/nixos/tests/xmonad-xdg-autostart.nix b/nixos/tests/xmonad-xdg-autostart.nix index 2577a9ce2ea13..f1780072f9740 100644 --- a/nixos/tests/xmonad-xdg-autostart.nix +++ b/nixos/tests/xmonad-xdg-autostart.nix @@ -5,7 +5,7 @@ import ./make-test-python.nix ({ lib, ... }: { nodes.machine = { pkgs, config, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = "none+xmonad"; + services.displayManager.defaultSession = "none+xmonad"; services.xserver.windowManager.xmonad.enable = true; services.xserver.desktopManager.runXdgAutostartIfNone = true; diff --git a/nixos/tests/xmonad.nix b/nixos/tests/xmonad.nix index ec48c3e112750..c61e96886e2c5 100644 --- a/nixos/tests/xmonad.nix +++ b/nixos/tests/xmonad.nix @@ -61,7 +61,7 @@ in { nodes.machine = { pkgs, ... }: { imports = [ ./common/x11.nix ./common/user-account.nix ]; test-support.displayManager.auto.user = "alice"; - services.xserver.displayManager.defaultSession = "none+xmonad"; + services.displayManager.defaultSession = "none+xmonad"; services.xserver.windowManager.xmonad = { enable = true; enableConfiguredRecompile = true; |