about summary refs log tree commit diff
path: root/nixos/tests
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/tests')
-rw-r--r--nixos/tests/all-tests.nix9
-rw-r--r--nixos/tests/ayatana-indicators.nix2
-rw-r--r--nixos/tests/budgie.nix4
-rw-r--r--nixos/tests/cinnamon-wayland.nix2
-rw-r--r--nixos/tests/cinnamon.nix4
-rw-r--r--nixos/tests/common/auto.nix10
-rw-r--r--nixos/tests/common/x11.nix2
-rw-r--r--nixos/tests/containers-require-bind-mounts.nix35
-rw-r--r--nixos/tests/docker-tools.nix8
-rw-r--r--nixos/tests/forgejo.nix6
-rw-r--r--nixos/tests/gnome-flashback.nix11
-rw-r--r--nixos/tests/gnome-xorg.nix11
-rw-r--r--nixos/tests/gnome.nix9
-rw-r--r--nixos/tests/herbstluftwm.nix2
-rw-r--r--nixos/tests/hledger-web.nix2
-rw-r--r--nixos/tests/i3wm.nix2
-rw-r--r--nixos/tests/installer-systemd-stage-1.nix2
-rw-r--r--nixos/tests/installer.nix403
-rw-r--r--nixos/tests/kernel-generic.nix1
-rw-r--r--nixos/tests/lightdm.nix2
-rw-r--r--nixos/tests/maestral.nix9
-rw-r--r--nixos/tests/mate-wayland.nix2
-rw-r--r--nixos/tests/matrix/mautrix-meta-postgres.nix221
-rw-r--r--nixos/tests/matrix/mautrix-meta-sqlite.nix247
-rw-r--r--nixos/tests/miriway.nix6
-rw-r--r--nixos/tests/nimdow.nix2
-rw-r--r--nixos/tests/oddjobd.nix23
-rw-r--r--nixos/tests/pantheon.nix9
-rw-r--r--nixos/tests/plasma-bigscreen.nix6
-rw-r--r--nixos/tests/plasma5-systemd-start.nix9
-rw-r--r--nixos/tests/plasma5.nix6
-rw-r--r--nixos/tests/plasma6.nix8
-rw-r--r--nixos/tests/ragnarwm.nix2
-rw-r--r--nixos/tests/restic-rest-server.nix122
-rw-r--r--nixos/tests/sddm.nix8
-rw-r--r--nixos/tests/silverbullet.nix47
-rw-r--r--nixos/tests/soju.nix31
-rw-r--r--nixos/tests/switch-test.nix16
-rw-r--r--nixos/tests/technitium-dns-server.nix21
-rw-r--r--nixos/tests/unifi.nix4
-rw-r--r--nixos/tests/vaultwarden.nix2
-rw-r--r--nixos/tests/web-apps/movim/default.nix8
-rw-r--r--nixos/tests/web-apps/movim/standard.nix102
-rw-r--r--nixos/tests/wmderland.nix2
-rw-r--r--nixos/tests/xfce.nix10
-rw-r--r--nixos/tests/xmonad-xdg-autostart.nix2
-rw-r--r--nixos/tests/xmonad.nix2
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;