about summary refs log tree commit diff
path: root/nixpkgs/nixos/tests
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2023-08-08 16:04:42 +0000
committerAlyssa Ross <hi@alyssa.is>2023-08-13 06:35:37 +0000
commit12aaa58dac35800b5b7d77f81cf2a87c21ee55da (patch)
treebe0add9e5c22a85d20b5d78206aa74f956eb2a1b /nixpkgs/nixos/tests
parent45892a5591202f75a1c2f1ca7c62a92c7566e3c5 (diff)
parent5a8e9243812ba528000995b294292d3b5e120947 (diff)
downloadnixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar.gz
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar.bz2
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar.lz
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar.xz
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.tar.zst
nixlib-12aaa58dac35800b5b7d77f81cf2a87c21ee55da.zip
Merge branch 'nixos-unstable' of https://github.com/NixOS/nixpkgs
Conflicts:
	nixpkgs/pkgs/applications/window-managers/sway/default.nix
	nixpkgs/pkgs/build-support/go/module.nix
	nixpkgs/pkgs/build-support/rust/build-rust-package/default.nix
	nixpkgs/pkgs/development/libraries/mesa/default.nix
	nixpkgs/pkgs/servers/dict/dictd-db.nix

Link: https://gitlab.freedesktop.org/xkeyboard-config/xkeyboard-config/-/issues/391
Diffstat (limited to 'nixpkgs/nixos/tests')
-rw-r--r--nixpkgs/nixos/tests/adguardhome.nix69
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix36
-rw-r--r--nixpkgs/nixos/tests/anuko-time-tracker.nix17
-rw-r--r--nixpkgs/nixos/tests/apfs.nix8
-rw-r--r--nixpkgs/nixos/tests/appliance-repart-image.nix116
-rw-r--r--nixpkgs/nixos/tests/atuin.nix2
-rw-r--r--nixpkgs/nixos/tests/bcachefs.nix2
-rw-r--r--nixpkgs/nixos/tests/binary-cache.nix10
-rw-r--r--nixpkgs/nixos/tests/bpftune.nix20
-rw-r--r--nixpkgs/nixos/tests/budgie.nix10
-rw-r--r--nixpkgs/nixos/tests/buildkite-agents.nix6
-rw-r--r--nixpkgs/nixos/tests/caddy.nix9
-rw-r--r--nixpkgs/nixos/tests/cage.nix2
-rw-r--r--nixpkgs/nixos/tests/calibre-server.nix104
-rw-r--r--nixpkgs/nixos/tests/common/auto-format-root-device.nix29
-rw-r--r--nixpkgs/nixos/tests/common/gpg-keyring.nix21
-rw-r--r--nixpkgs/nixos/tests/common/resolver.nix2
-rw-r--r--nixpkgs/nixos/tests/coturn.nix1
-rw-r--r--nixpkgs/nixos/tests/cups-pdf.nix2
-rw-r--r--nixpkgs/nixos/tests/curl-impersonate.nix157
-rw-r--r--nixpkgs/nixos/tests/deepin.nix6
-rw-r--r--nixpkgs/nixos/tests/evcc.nix2
-rw-r--r--nixpkgs/nixos/tests/fail2ban.nix18
-rw-r--r--nixpkgs/nixos/tests/fakeroute.nix22
-rw-r--r--nixpkgs/nixos/tests/fontconfig-default-fonts.nix4
-rw-r--r--nixpkgs/nixos/tests/freshrss-http-auth.nix20
-rw-r--r--nixpkgs/nixos/tests/fsck.nix10
-rw-r--r--nixpkgs/nixos/tests/gitea.nix31
-rw-r--r--nixpkgs/nixos/tests/gnome-flashback.nix14
-rw-r--r--nixpkgs/nixos/tests/guacamole-server.nix21
-rw-r--r--nixpkgs/nixos/tests/hibernate.nix143
-rw-r--r--nixpkgs/nixos/tests/homepage-dashboard.nix14
-rw-r--r--nixpkgs/nixos/tests/initrd-luks-empty-passphrase.nix3
-rw-r--r--nixpkgs/nixos/tests/initrd-network-ssh/default.nix18
-rw-r--r--nixpkgs/nixos/tests/installed-tests/default.nix1
-rw-r--r--nixpkgs/nixos/tests/installed-tests/upower.nix9
-rw-r--r--nixpkgs/nixos/tests/installer-systemd-stage-1.nix2
-rw-r--r--nixpkgs/nixos/tests/installer.nix122
-rw-r--r--nixpkgs/nixos/tests/installer/flake.nix20
-rw-r--r--nixpkgs/nixos/tests/jenkins.nix4
-rw-r--r--nixpkgs/nixos/tests/k3s/single-node.nix14
-rw-r--r--nixpkgs/nixos/tests/kafka.nix2
-rw-r--r--nixpkgs/nixos/tests/kanidm.nix53
-rw-r--r--nixpkgs/nixos/tests/kernel-generic.nix8
-rw-r--r--nixpkgs/nixos/tests/keter.nix65
-rw-r--r--nixpkgs/nixos/tests/kexec.nix11
-rw-r--r--nixpkgs/nixos/tests/keyd.nix2
-rw-r--r--nixpkgs/nixos/tests/keymap.nix37
-rw-r--r--nixpkgs/nixos/tests/lemmy.nix12
-rw-r--r--nixpkgs/nixos/tests/luks.nix2
-rw-r--r--nixpkgs/nixos/tests/lxd-ui.nix35
-rw-r--r--nixpkgs/nixos/tests/maestral.nix5
-rw-r--r--nixpkgs/nixos/tests/matomo.nix4
-rw-r--r--nixpkgs/nixos/tests/miniflux.nix6
-rw-r--r--nixpkgs/nixos/tests/miriway.nix2
-rw-r--r--nixpkgs/nixos/tests/mumble.nix4
-rw-r--r--nixpkgs/nixos/tests/n8n.nix3
-rw-r--r--nixpkgs/nixos/tests/networking.nix78
-rw-r--r--nixpkgs/nixos/tests/nextcloud/basic.nix6
-rw-r--r--nixpkgs/nixos/tests/nextcloud/default.nix2
-rw-r--r--nixpkgs/nixos/tests/nextcloud/openssl-sse.nix2
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix40
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix2
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix5
-rw-r--r--nixpkgs/nixos/tests/nginx-proxyprotocol/default.nix4
-rw-r--r--nixpkgs/nixos/tests/nginx-status-page.nix72
-rw-r--r--nixpkgs/nixos/tests/nixos-test-driver/busybox.nix16
-rw-r--r--nixpkgs/nixos/tests/nixos-test-driver/lib-extend.nix31
-rw-r--r--nixpkgs/nixos/tests/non-default-filesystems.nix66
-rw-r--r--nixpkgs/nixos/tests/noto-fonts-cjk-qt-default-weight.nix2
-rw-r--r--nixpkgs/nixos/tests/noto-fonts.nix4
-rw-r--r--nixpkgs/nixos/tests/opentelemetry-collector.nix76
-rw-r--r--nixpkgs/nixos/tests/os-prober.nix4
-rw-r--r--nixpkgs/nixos/tests/osquery.nix52
-rw-r--r--nixpkgs/nixos/tests/paperless.nix14
-rw-r--r--nixpkgs/nixos/tests/pgbouncer.nix61
-rw-r--r--nixpkgs/nixos/tests/plasma-bigscreen.nix9
-rw-r--r--nixpkgs/nixos/tests/plasma5-systemd-start.nix8
-rw-r--r--nixpkgs/nixos/tests/plasma5.nix14
-rw-r--r--nixpkgs/nixos/tests/powerdns.nix8
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix59
-rw-r--r--nixpkgs/nixos/tests/public-inbox.nix3
-rw-r--r--nixpkgs/nixos/tests/qemu-vm-volatile-root.nix17
-rw-r--r--nixpkgs/nixos/tests/qownnotes.nix70
-rw-r--r--nixpkgs/nixos/tests/retroarch.nix4
-rw-r--r--nixpkgs/nixos/tests/samba-wsdd.nix6
-rw-r--r--nixpkgs/nixos/tests/scaphandre.nix18
-rw-r--r--nixpkgs/nixos/tests/sddm.nix14
-rw-r--r--nixpkgs/nixos/tests/sftpgo.nix10
-rw-r--r--nixpkgs/nixos/tests/sing-box.nix48
-rw-r--r--nixpkgs/nixos/tests/snapper.nix2
-rw-r--r--nixpkgs/nixos/tests/sway.nix75
-rw-r--r--nixpkgs/nixos/tests/switch-test.nix47
-rw-r--r--nixpkgs/nixos/tests/syncthing-init.nix7
-rw-r--r--nixpkgs/nixos/tests/syncthing-no-settings.nix18
-rw-r--r--nixpkgs/nixos/tests/systemd-boot.nix3
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-fido2.nix1
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix1
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-password.nix1
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix1
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-networkd-ssh.nix18
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-swraid.nix12
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-vconsole.nix17
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix57
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix6
-rw-r--r--nixpkgs/nixos/tests/systemd-nspawn-configfile.nix128
-rw-r--r--nixpkgs/nixos/tests/systemd-nspawn.nix22
-rw-r--r--nixpkgs/nixos/tests/systemd-shutdown.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-sysupdate.nix66
-rw-r--r--nixpkgs/nixos/tests/terminal-emulators.nix7
-rw-r--r--nixpkgs/nixos/tests/tmate-ssh-server.nix1
-rw-r--r--nixpkgs/nixos/tests/twingate.nix14
-rw-r--r--nixpkgs/nixos/tests/typesense.nix23
-rw-r--r--nixpkgs/nixos/tests/virtualbox.nix2
-rw-r--r--nixpkgs/nixos/tests/vscode-remote-ssh.nix124
-rw-r--r--nixpkgs/nixos/tests/vscodium.nix2
-rw-r--r--nixpkgs/nixos/tests/web-apps/gotosocial.nix28
-rw-r--r--nixpkgs/nixos/tests/web-apps/peering-manager.nix2
-rw-r--r--nixpkgs/nixos/tests/web-servers/static-web-server.nix32
-rw-r--r--nixpkgs/nixos/tests/wpa_supplicant.nix228
121 files changed, 2663 insertions, 483 deletions
diff --git a/nixpkgs/nixos/tests/adguardhome.nix b/nixpkgs/nixos/tests/adguardhome.nix
index ec1cc1e497b5..9f8ddc33f57e 100644
--- a/nixpkgs/nixos/tests/adguardhome.nix
+++ b/nixpkgs/nixos/tests/adguardhome.nix
@@ -40,6 +40,67 @@
         };
       };
     };
+
+    dhcpConf = { lib, ... }: {
+      virtualisation.vlans = [ 1 ];
+
+      networking = {
+        # Configure static IP for DHCP server
+        useDHCP = false;
+        interfaces."eth1" = lib.mkForce {
+          useDHCP = false;
+          ipv4 = {
+            addresses = [{
+              address = "10.0.10.1";
+              prefixLength = 24;
+            }];
+
+            routes = [{
+              address = "10.0.10.0";
+              prefixLength = 24;
+            }];
+          };
+        };
+
+        # Required for DHCP
+        firewall.allowedUDPPorts = [ 67 68 ];
+      };
+
+      services.adguardhome = {
+        enable = true;
+        allowDHCP = true;
+        mutableSettings = false;
+        settings = {
+          schema_version = 0;
+          dns = {
+            bind_host = "0.0.0.0";
+            bootstrap_dns = "127.0.0.1";
+          };
+          dhcp = {
+            # This implicitly enables CAP_NET_RAW
+            enabled = true;
+            interface_name = "eth1";
+            local_domain_name = "lan";
+            dhcpv4 = {
+              gateway_ip = "10.0.10.1";
+              range_start = "10.0.10.100";
+              range_end = "10.0.10.101";
+              subnet_mask = "255.255.255.0";
+            };
+          };
+        };
+      };
+    };
+
+    client = { lib, ... }: {
+      virtualisation.vlans = [ 1 ];
+      networking = {
+        interfaces.eth1 = {
+          useDHCP = true;
+          ipv4.addresses = lib.mkForce [ ];
+        };
+      };
+    };
   };
 
   testScript = ''
@@ -63,5 +124,13 @@
         mixedConf.systemctl("restart adguardhome.service")
         mixedConf.wait_for_unit("adguardhome.service")
         mixedConf.wait_for_open_port(3000)
+
+    with subtest("Testing successful DHCP start"):
+        dhcpConf.wait_for_unit("adguardhome.service")
+        client.wait_for_unit("network-online.target")
+        # Test IP assignment via DHCP
+        dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100")
+        # Test hostname resolution over DHCP-provided DNS
+        dhcpConf.wait_until_succeeds("ping -c 5 client.lan")
   '';
 }
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index e597a26f31bb..3b4a39f5ff96 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -87,7 +87,9 @@ in {
   # Testing the test driver
   nixos-test-driver = {
     extra-python-packages = handleTest ./nixos-test-driver/extra-python-packages.nix {};
+    lib-extend = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./nixos-test-driver/lib-extend.nix {};
     node-name = runTest ./nixos-test-driver/node-name.nix;
+    busybox = runTest ./nixos-test-driver/busybox.nix;
   };
 
   # NixOS vm tests and non-vm unit tests
@@ -107,8 +109,10 @@ in {
   allTerminfo = handleTest ./all-terminfo.nix {};
   alps = handleTest ./alps.nix {};
   amazon-init-shell = handleTest ./amazon-init-shell.nix {};
+  anuko-time-tracker = handleTest ./anuko-time-tracker.nix {};
   apcupsd = handleTest ./apcupsd.nix {};
-  apfs = handleTest ./apfs.nix {};
+  apfs = runTest ./apfs.nix;
+  appliance-repart-image = runTest ./appliance-repart-image.nix;
   apparmor = handleTest ./apparmor.nix {};
   atd = handleTest ./atd.nix {};
   atop = handleTest ./atop.nix {};
@@ -136,6 +140,7 @@ in {
   borgbackup = handleTest ./borgbackup.nix {};
   botamusique = handleTest ./botamusique.nix {};
   bpf = handleTestOn ["x86_64-linux" "aarch64-linux"] ./bpf.nix {};
+  bpftune = handleTest ./bpftune.nix {};
   breitbandmessung = handleTest ./breitbandmessung.nix {};
   brscan5 = handleTest ./brscan5.nix {};
   btrbk = handleTest ./btrbk.nix {};
@@ -150,6 +155,7 @@ in {
   cage = handleTest ./cage.nix {};
   cagebreak = handleTest ./cagebreak.nix {};
   calibre-web = handleTest ./calibre-web.nix {};
+  calibre-server = handleTest ./calibre-server.nix {};
   cassandra_3_0 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_0; };
   cassandra_3_11 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_11; };
   cassandra_4 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_4; };
@@ -199,6 +205,7 @@ in {
   couchdb = handleTest ./couchdb.nix {};
   cri-o = handleTestOn ["aarch64-linux" "x86_64-linux"] ./cri-o.nix {};
   cups-pdf = handleTest ./cups-pdf.nix {};
+  curl-impersonate = handleTest ./curl-impersonate.nix {};
   custom-ca = handleTest ./custom-ca.nix {};
   croc = handleTest ./croc.nix {};
   darling = handleTest ./darling.nix {};
@@ -253,6 +260,8 @@ in {
   etebase-server = handleTest ./etebase-server.nix {};
   etesync-dav = handleTest ./etesync-dav.nix {};
   evcc = handleTest ./evcc.nix {};
+  fail2ban = handleTest ./fail2ban.nix { };
+  fakeroute = handleTest ./fakeroute.nix {};
   fancontrol = handleTest ./fancontrol.nix {};
   fcitx5 = handleTest ./fcitx5 {};
   fenics = handleTest ./fenics.nix {};
@@ -262,6 +271,7 @@ in {
   firefox-devedition = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-devedition; };
   firefox-esr    = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr; }; # used in `tested` job
   firefox-esr-102 = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr-102; };
+  firefox-esr-115 = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr-115; };
   firejail = handleTest ./firejail.nix {};
   firewall = handleTest ./firewall.nix { nftables = false; };
   firewall-nftables = handleTest ./firewall.nix { nftables = true; };
@@ -306,12 +316,15 @@ in {
   gonic = handleTest ./gonic.nix {};
   google-oslogin = handleTest ./google-oslogin {};
   gotify-server = handleTest ./gotify-server.nix {};
+  gotosocial = runTest ./web-apps/gotosocial.nix;
   grafana = handleTest ./grafana {};
   grafana-agent = handleTest ./grafana-agent.nix {};
   graphite = handleTest ./graphite.nix {};
   graylog = handleTest ./graylog.nix {};
   grocy = handleTest ./grocy.nix {};
   grub = handleTest ./grub.nix {};
+  guacamole-client = handleTest ./guacamole-client.nix {};
+  guacamole-server = handleTest ./guacamole-server.nix {};
   gvisor = handleTest ./gvisor.nix {};
   hadoop = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop; };
   hadoop_3_2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_2; };
@@ -328,6 +341,7 @@ in {
   hbase3 = handleTest ./hbase.nix { package=pkgs.hbase3; };
   hedgedoc = handleTest ./hedgedoc.nix {};
   herbstluftwm = handleTest ./herbstluftwm.nix {};
+  homepage-dashboard = handleTest ./homepage-dashboard.nix {};
   installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
   invidious = handleTest ./invidious.nix {};
   oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {};
@@ -427,6 +441,7 @@ in {
   lxd = handleTest ./lxd.nix {};
   lxd-nftables = handleTest ./lxd-nftables.nix {};
   lxd-image-server = handleTest ./lxd-image-server.nix {};
+  lxd-ui = handleTest ./lxd-ui.nix {};
   #logstash = handleTest ./logstash.nix {};
   lorri = handleTest ./lorri/default.nix {};
   maddy = discoverTests (import ./maddy { inherit handleTest; });
@@ -520,11 +535,12 @@ in {
   nginx-http3 = handleTest ./nginx-http3.nix {};
   nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
   nginx-njs = handleTest ./nginx-njs.nix {};
+  nginx-proxyprotocol = handleTest ./nginx-proxyprotocol {};
   nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
   nginx-sandbox = handleTestOn ["x86_64-linux"] ./nginx-sandbox.nix {};
   nginx-sso = handleTest ./nginx-sso.nix {};
+  nginx-status-page = handleTest ./nginx-status-page.nix {};
   nginx-variants = handleTest ./nginx-variants.nix {};
-  nginx-proxyprotocol = handleTest ./nginx-proxyprotocol {};
   nifi = handleTestOn ["x86_64-linux"] ./web-apps/nifi.nix {};
   nitter = handleTest ./nitter.nix {};
   nix-ld = handleTest ./nix-ld.nix {};
@@ -558,12 +574,14 @@ in {
   openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
   openstack-image-userdata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).userdata or {};
   opentabletdriver = handleTest ./opentabletdriver.nix {};
+  opentelemetry-collector = handleTest ./opentelemetry-collector.nix {};
   owncast = handleTest ./owncast.nix {};
   outline = handleTest ./outline.nix {};
   image-contents = handleTest ./image-contents.nix {};
   openvscode-server = handleTest ./openvscode-server.nix {};
   orangefs = handleTest ./orangefs.nix {};
   os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
+  osquery = handleTestOn ["x86_64-linux"] ./osquery.nix {};
   osrm-backend = handleTest ./osrm-backend.nix {};
   overlayfs = handleTest ./overlayfs.nix {};
   pacemaker = handleTest ./pacemaker.nix {};
@@ -585,14 +603,15 @@ in {
   peertube = handleTestOn ["x86_64-linux"] ./web-apps/peertube.nix {};
   peroxide = handleTest ./peroxide.nix {};
   pgadmin4 = handleTest ./pgadmin4.nix {};
+  pgbouncer = handleTest ./pgbouncer.nix {};
   pgjwt = handleTest ./pgjwt.nix {};
   pgmanage = handleTest ./pgmanage.nix {};
   phosh = handleTest ./phosh.nix {};
   photoprism = handleTest ./photoprism.nix {};
   php = handleTest ./php {};
-  php80 = handleTest ./php { php = pkgs.php80; };
   php81 = handleTest ./php { php = pkgs.php81; };
   php82 = handleTest ./php { php = pkgs.php82; };
+  php83 = handleTest ./php { php = pkgs.php83; };
   phylactery = handleTest ./web-apps/phylactery.nix {};
   pict-rs = handleTest ./pict-rs.nix {};
   pinnwand = handleTest ./pinnwand.nix {};
@@ -640,8 +659,10 @@ in {
   pulseaudio = discoverTests (import ./pulseaudio.nix);
   qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {};
   qemu-vm-restrictnetwork = handleTest ./qemu-vm-restrictnetwork.nix {};
+  qemu-vm-volatile-root = runTest ./qemu-vm-volatile-root.nix;
   quorum = handleTest ./quorum.nix {};
   quake3 = handleTest ./quake3.nix {};
+  qownnotes = handleTest ./qownnotes.nix {};
   rabbitmq = handleTest ./rabbitmq.nix {};
   radarr = handleTest ./radarr.nix {};
   radicale = handleTest ./radicale.nix {};
@@ -665,6 +686,7 @@ in {
   samba = handleTest ./samba.nix {};
   samba-wsdd = handleTest ./samba-wsdd.nix {};
   sanoid = handleTest ./sanoid.nix {};
+  scaphandre = handleTest ./scaphandre.nix {};
   schleuder = handleTest ./schleuder.nix {};
   sddm = handleTest ./sddm.nix {};
   seafile = handleTest ./seafile.nix {};
@@ -679,6 +701,7 @@ in {
   shiori = handleTest ./shiori.nix {};
   signal-desktop = handleTest ./signal-desktop.nix {};
   simple = handleTest ./simple.nix {};
+  sing-box = handleTest ./sing-box.nix {};
   slurm = handleTest ./slurm.nix {};
   smokeping = handleTest ./smokeping.nix {};
   snapcast = handleTest ./snapcast.nix {};
@@ -697,6 +720,7 @@ in {
   sssd-ldap = handleTestOn ["x86_64-linux"] ./sssd-ldap.nix {};
   stargazer = runTest ./web-servers/stargazer.nix;
   starship = handleTest ./starship.nix {};
+  static-web-server = handleTest ./web-servers/static-web-server.nix {};
   step-ca = handleTestOn ["x86_64-linux"] ./step-ca.nix {};
   stratis = handleTest ./stratis {};
   strongswan-swanctl = handleTest ./strongswan-swanctl.nix {};
@@ -709,6 +733,7 @@ in {
   switchTest = handleTest ./switch-test.nix {};
   sympa = handleTest ./sympa.nix {};
   syncthing = handleTest ./syncthing.nix {};
+  syncthing-no-settings = handleTest ./syncthing-no-settings.nix {};
   syncthing-init = handleTest ./syncthing-init.nix {};
   syncthing-relay = handleTest ./syncthing-relay.nix {};
   systemd = handleTest ./systemd.nix {};
@@ -744,10 +769,12 @@ in {
   systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
   systemd-no-tainted = handleTest ./systemd-no-tainted.nix {};
   systemd-nspawn = handleTest ./systemd-nspawn.nix {};
+  systemd-nspawn-configfile = handleTest ./systemd-nspawn-configfile.nix {};
   systemd-oomd = handleTest ./systemd-oomd.nix {};
   systemd-portabled = handleTest ./systemd-portabled.nix {};
   systemd-repart = handleTest ./systemd-repart.nix {};
   systemd-shutdown = handleTest ./systemd-shutdown.nix {};
+  systemd-sysupdate = runTest ./systemd-sysupdate.nix;
   systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
   systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {};
   systemd-misc = handleTest ./systemd-misc.nix {};
@@ -785,6 +812,8 @@ in {
   tuptime = handleTest ./tuptime.nix {};
   turbovnc-headless-server = handleTest ./turbovnc-headless-server.nix {};
   tuxguitar = handleTest ./tuxguitar.nix {};
+  twingate = runTest ./twingate.nix;
+  typesense = handleTest ./typesense.nix {};
   ucarp = handleTest ./ucarp.nix {};
   udisks2 = handleTest ./udisks2.nix {};
   ulogd = handleTest ./ulogd.nix {};
@@ -812,6 +841,7 @@ in {
   victoriametrics = handleTest ./victoriametrics.nix {};
   vikunja = handleTest ./vikunja.nix {};
   virtualbox = handleTestOn ["x86_64-linux"] ./virtualbox.nix {};
+  vscode-remote-ssh = handleTestOn ["x86_64-linux"] ./vscode-remote-ssh.nix {};
   vscodium = discoverTests (import ./vscodium.nix);
   vsftpd = handleTest ./vsftpd.nix {};
   warzone2100 = handleTest ./warzone2100.nix {};
diff --git a/nixpkgs/nixos/tests/anuko-time-tracker.nix b/nixpkgs/nixos/tests/anuko-time-tracker.nix
new file mode 100644
index 000000000000..18c3bf5cf695
--- /dev/null
+++ b/nixpkgs/nixos/tests/anuko-time-tracker.nix
@@ -0,0 +1,17 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "anuko-time-tracker";
+  meta = {
+    maintainers = with pkgs.lib.maintainers; [ michaelshmitty ];
+  };
+  nodes = {
+    machine = {
+      services.anuko-time-tracker.enable = true;
+    };
+  };
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("phpfpm-anuko-time-tracker")
+    machine.wait_for_open_port(80);
+    machine.wait_until_succeeds("curl -s --fail -L http://localhost/time.php | grep 'Anuko Time Tracker'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/apfs.nix b/nixpkgs/nixos/tests/apfs.nix
index 9fe689951c78..15ed5aa7f573 100644
--- a/nixpkgs/nixos/tests/apfs.nix
+++ b/nixpkgs/nixos/tests/apfs.nix
@@ -1,8 +1,8 @@
-import ./make-test-python.nix ({ pkgs, ... }: {
+{ lib, ... }: {
   name = "apfs";
-  meta.maintainers = with pkgs.lib.maintainers; [ Luflosi ];
+  meta.maintainers = with lib.maintainers; [ Luflosi ];
 
-  nodes.machine = { pkgs, ... }: {
+  nodes.machine = {
     virtualisation.emptyDiskImages = [ 1024 ];
 
     boot.supportedFilesystems = [ "apfs" ];
@@ -62,4 +62,4 @@ import ./make-test-python.nix ({ pkgs, ... }: {
           "apfsck /dev/vdb",
       )
   '';
-})
+}
diff --git a/nixpkgs/nixos/tests/appliance-repart-image.nix b/nixpkgs/nixos/tests/appliance-repart-image.nix
new file mode 100644
index 000000000000..3f256db84621
--- /dev/null
+++ b/nixpkgs/nixos/tests/appliance-repart-image.nix
@@ -0,0 +1,116 @@
+# Tests building and running a GUID Partition Table (GPT) appliance image.
+# "Appliance" here means that the image does not contain the normal NixOS
+# infrastructure of a system profile and cannot be re-built via
+# `nixos-rebuild`.
+
+{ lib, ... }:
+
+let
+  rootPartitionLabel = "root";
+
+  bootLoaderConfigPath = "/loader/entries/nixos.conf";
+  kernelPath = "/EFI/nixos/kernel.efi";
+  initrdPath = "/EFI/nixos/initrd.efi";
+in
+{
+  name = "appliance-gpt-image";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = { config, lib, pkgs, ... }: {
+
+    imports = [ ../modules/image/repart.nix ];
+
+    virtualisation.directBoot.enable = false;
+    virtualisation.mountHostNixStore = false;
+    virtualisation.useEFIBoot = true;
+
+    # Disable boot loaders because we install one "manually".
+    # TODO(raitobezarius): revisit this when #244907 lands
+    boot.loader.grub.enable = false;
+
+    virtualisation.fileSystems = lib.mkForce {
+      "/" = {
+        device = "/dev/disk/by-partlabel/${rootPartitionLabel}";
+        fsType = "ext4";
+      };
+    };
+
+    image.repart = {
+      name = "appliance-gpt-image";
+      partitions = {
+        "esp" = {
+          contents =
+            let
+              efiArch = config.nixpkgs.hostPlatform.efiArch;
+            in
+            {
+              "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source =
+                "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
+
+              # TODO: create an abstraction for Boot Loader Specification (BLS) entries.
+              "${bootLoaderConfigPath}".source = pkgs.writeText "nixos.conf" ''
+                title NixOS
+                linux ${kernelPath}
+                initrd ${initrdPath}
+                options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
+              '';
+
+              "${kernelPath}".source =
+                "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}";
+
+              "${initrdPath}".source =
+                "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}";
+            };
+          repartConfig = {
+            Type = "esp";
+            Format = "vfat";
+            # Minimize = "guess" seems to not work very vell for vfat
+            # partitons. It's better to set a sensible default instead. The
+            # aarch64 kernel seems to generally be a little bigger than the
+            # x86_64 kernel. To stay on the safe side, leave some more slack
+            # for every platform other than x86_64.
+            SizeMinBytes = if config.nixpkgs.hostPlatform.isx86_64 then "64M" else "96M";
+          };
+        };
+        "root" = {
+          storePaths = [ config.system.build.toplevel ];
+          repartConfig = {
+            Type = "root";
+            Format = config.fileSystems."/".fsType;
+            Label = rootPartitionLabel;
+            Minimize = "guess";
+          };
+        };
+      };
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    import os
+    import subprocess
+    import tempfile
+
+    tmp_disk_image = tempfile.NamedTemporaryFile()
+
+    subprocess.run([
+      "${nodes.machine.virtualisation.qemu.package}/bin/qemu-img",
+      "create",
+      "-f",
+      "qcow2",
+      "-b",
+      "${nodes.machine.system.build.image}/image.raw",
+      "-F",
+      "raw",
+      tmp_disk_image.name,
+    ])
+
+    # Set NIX_DISK_IMAGE so that the qemu script finds the right disk image.
+    os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name
+
+    bootctl_status = machine.succeed("bootctl status")
+    assert "${bootLoaderConfigPath}" in bootctl_status
+    assert "${kernelPath}" in bootctl_status
+    assert "${initrdPath}" in bootctl_status
+  '';
+}
diff --git a/nixpkgs/nixos/tests/atuin.nix b/nixpkgs/nixos/tests/atuin.nix
index 9f23a3cf6713..3164c83c683d 100644
--- a/nixpkgs/nixos/tests/atuin.nix
+++ b/nixpkgs/nixos/tests/atuin.nix
@@ -14,6 +14,8 @@ in
     server =
       { ... }:
       {
+        services.postgresql.enable = true;
+
         services.atuin = {
           enable = true;
           port = testPort;
diff --git a/nixpkgs/nixos/tests/bcachefs.nix b/nixpkgs/nixos/tests/bcachefs.nix
index 68ac49d0a6a6..0385e098997f 100644
--- a/nixpkgs/nixos/tests/bcachefs.nix
+++ b/nixpkgs/nixos/tests/bcachefs.nix
@@ -23,7 +23,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
         "keyctl link @u @s",
         "echo password | bcachefs format --encrypted --metadata_replicas 2 --label vtest /dev/vdb1 /dev/vdb2",
         "echo password | bcachefs unlock /dev/vdb1",
-        "mount -t bcachefs /dev/vdb1:/dev/vdb2 /tmp/mnt",
+        "echo password | mount -t bcachefs /dev/vdb1:/dev/vdb2 /tmp/mnt",
         "udevadm settle",
         "bcachefs fs usage /tmp/mnt",
         "umount /tmp/mnt",
diff --git a/nixpkgs/nixos/tests/binary-cache.nix b/nixpkgs/nixos/tests/binary-cache.nix
index 0809e59e5a11..bc1c6fb9a267 100644
--- a/nixpkgs/nixos/tests/binary-cache.nix
+++ b/nixpkgs/nixos/tests/binary-cache.nix
@@ -1,16 +1,14 @@
-import ./make-test-python.nix ({ lib, ... }:
-
-with lib;
+import ./make-test-python.nix ({ lib, pkgs, ... }:
 
 {
   name = "binary-cache";
-  meta.maintainers = with maintainers; [ thomasjm ];
+  meta.maintainers = with lib.maintainers; [ thomasjm ];
 
   nodes.machine =
     { pkgs, ... }: {
       imports = [ ../modules/installer/cd-dvd/channel.nix ];
-      environment.systemPackages = with pkgs; [python3];
-      system.extraDependencies = with pkgs; [hello.inputDerivation];
+      environment.systemPackages = [ pkgs.python3 ];
+      system.extraDependencies = [ pkgs.hello.inputDerivation ];
       nix.extraOptions = ''
         experimental-features = nix-command
       '';
diff --git a/nixpkgs/nixos/tests/bpftune.nix b/nixpkgs/nixos/tests/bpftune.nix
new file mode 100644
index 000000000000..c17bbcd11092
--- /dev/null
+++ b/nixpkgs/nixos/tests/bpftune.nix
@@ -0,0 +1,20 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+
+  name = "bpftune";
+
+  meta = {
+    maintainers = with lib.maintainers; [ nickcao ];
+  };
+
+  nodes = {
+    machine = { pkgs, ... }: {
+      services.bpftune.enable = true;
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("bpftune.service")
+    machine.wait_for_console_text("bpftune works")
+  '';
+
+})
diff --git a/nixpkgs/nixos/tests/budgie.nix b/nixpkgs/nixos/tests/budgie.nix
index b1b0e618c884..34ee1e303de9 100644
--- a/nixpkgs/nixos/tests/budgie.nix
+++ b/nixpkgs/nixos/tests/budgie.nix
@@ -32,7 +32,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     in
     ''
       with subtest("Wait for login"):
-          machine.wait_for_x()
+          # wait_for_x() checks graphical-session.target, which is expected to be
+          # inactive on Budgie before #228946 (i.e. systemd managed gnome-session) is
+          # done on upstream.
+          # https://github.com/BuddiesOfBudgie/budgie-desktop/blob/v10.7.2/src/session/budgie-desktop.in#L16
+          #
+          # Previously this was unconditionally touched by xsessionWrapper but was
+          # changed in #233981 (we have Budgie:GNOME in XDG_CURRENT_DESKTOP).
+          # machine.wait_for_x()
+          machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"')
           machine.wait_for_file("${user.home}/.Xauthority")
           machine.succeed("xauth merge ${user.home}/.Xauthority")
 
diff --git a/nixpkgs/nixos/tests/buildkite-agents.nix b/nixpkgs/nixos/tests/buildkite-agents.nix
index 2c5593323e87..a5abfdb5e2e5 100644
--- a/nixpkgs/nixos/tests/buildkite-agents.nix
+++ b/nixpkgs/nixos/tests/buildkite-agents.nix
@@ -1,10 +1,8 @@
-import ./make-test-python.nix ({ pkgs, ... }:
+import ./make-test-python.nix ({ lib, pkgs, ... }:
 
 {
   name = "buildkite-agent";
-  meta = with pkgs.lib.maintainers; {
-    maintainers = [ flokli ];
-  };
+  meta.maintainers = with lib.maintainers; [ flokli ];
 
   nodes.machine = { pkgs, ... }: {
     services.buildkite-agents = {
diff --git a/nixpkgs/nixos/tests/caddy.nix b/nixpkgs/nixos/tests/caddy.nix
index c4abd33d0395..ed88f08739e8 100644
--- a/nixpkgs/nixos/tests/caddy.nix
+++ b/nixpkgs/nixos/tests/caddy.nix
@@ -20,6 +20,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
           }
         }
       '';
+      services.caddy.enableReload = true;
 
       specialisation.etag.configuration = {
         services.caddy.extraConfig = lib.mkForce ''
@@ -54,9 +55,9 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
   testScript = { nodes, ... }:
     let
-      etagSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/etag";
-      justReloadSystem = "${nodes.webserver.config.system.build.toplevel}/specialisation/config-reload";
-      multipleConfigs = "${nodes.webserver.config.system.build.toplevel}/specialisation/multiple-configs";
+      etagSystem = "${nodes.webserver.system.build.toplevel}/specialisation/etag";
+      justReloadSystem = "${nodes.webserver.system.build.toplevel}/specialisation/config-reload";
+      multipleConfigs = "${nodes.webserver.system.build.toplevel}/specialisation/multiple-configs";
     in
     ''
       url = "http://localhost/example.html"
@@ -96,6 +97,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
               "${justReloadSystem}/bin/switch-to-configuration test >&2"
           )
           webserver.wait_for_open_port(8080)
+          webserver.fail("journalctl -u caddy | grep -q -i stopped")
+          webserver.succeed("journalctl -u caddy | grep -q -i reloaded")
 
       with subtest("multiple configs are correctly merged"):
           webserver.succeed(
diff --git a/nixpkgs/nixos/tests/cage.nix b/nixpkgs/nixos/tests/cage.nix
index db1b7854673d..3b49185124f3 100644
--- a/nixpkgs/nixos/tests/cage.nix
+++ b/nixpkgs/nixos/tests/cage.nix
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
   {
     imports = [ ./common/user-account.nix ];
 
-    fonts.fonts = with pkgs; [ dejavu_fonts ];
+    fonts.packages = with pkgs; [ dejavu_fonts ];
 
     services.cage = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/calibre-server.nix b/nixpkgs/nixos/tests/calibre-server.nix
new file mode 100644
index 000000000000..4b1753aaa704
--- /dev/null
+++ b/nixpkgs/nixos/tests/calibre-server.nix
@@ -0,0 +1,104 @@
+{ system ? builtins.currentSystem
+, config ? { }
+, pkgs ? import ../.. { inherit system config; }
+}:
+
+let
+  inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
+  inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge
+    removeSuffix splitString;
+
+  tests = {
+    default = {
+      calibreConfig = {};
+      calibreScript = ''
+        wait_for_unit("calibre-server.service")
+      '';
+    };
+    customLibrary = {
+      calibreConfig = {
+        libraries = [ "/var/lib/calibre-data" ];
+      };
+      calibreScript = ''
+        succeed("ls -la /var/lib/calibre-data")
+        wait_for_unit("calibre-server.service")
+      '';
+    };
+    multipleLibraries = {
+      calibreConfig = {
+        libraries = [ "/var/lib/calibre-data" "/var/lib/calibre-server" ];
+      };
+      calibreScript = ''
+        succeed("ls -la /var/lib/calibre-data")
+        succeed("ls -la /var/lib/calibre-server")
+        wait_for_unit("calibre-server.service")
+      '';
+    };
+    hostAndPort = {
+      calibreConfig = {
+        host = "127.0.0.1";
+        port = 8888;
+      };
+      calibreScript = ''
+        wait_for_unit("calibre-server.service")
+        wait_for_open_port(8888)
+        succeed("curl --fail http://127.0.0.1:8888")
+      '';
+    };
+    basicAuth = {
+      calibreConfig = {
+        host = "127.0.0.1";
+        port = 8888;
+        auth = {
+          enable = true;
+          mode = "basic";
+        };
+      };
+      calibreScript = ''
+        wait_for_unit("calibre-server.service")
+        wait_for_open_port(8888)
+        fail("curl --fail http://127.0.0.1:8888")
+      '';
+    };
+  };
+in
+mapAttrs
+  (test: testConfig: (makeTest (
+    let
+      nodeName = testConfig.nodeName or test;
+      calibreConfig = {
+        enable = true;
+        libraries = [ "/var/lib/calibre-server" ];
+      } // testConfig.calibreConfig or {};
+      librariesInitScript = path: ''
+        ${nodeName}.execute("touch /tmp/test.epub")
+        ${nodeName}.execute("zip -r /tmp/test.zip /tmp/test.epub")
+        ${nodeName}.execute("mkdir -p ${path}")
+        ${nodeName}.execute("calibredb add -d --with-library ${path} /tmp/test.zip")
+      '';
+    in
+    {
+      name = "calibre-server-${test}";
+
+      nodes.${nodeName} = mkMerge [{
+        environment.systemPackages = [ pkgs.zip ];
+        services.calibre-server = calibreConfig;
+      } testConfig.calibreProvider or { }];
+
+      testScript = ''
+        ${nodeName}.start()
+        ${concatStringsSep "\n" (map librariesInitScript calibreConfig.libraries)}
+        ${concatStringsSep "\n" (map (line:
+          if (builtins.substring 0 1 line == " " || builtins.substring 0 1 line == ")")
+          then line
+          else "${nodeName}.${line}"
+        ) (splitString "\n" (removeSuffix "\n" testConfig.calibreScript)))}
+        ${nodeName}.shutdown()
+      '';
+
+      meta = with maintainers; {
+        maintainers = [ gaelreyrol ];
+      };
+    }
+  )))
+  tests
diff --git a/nixpkgs/nixos/tests/common/auto-format-root-device.nix b/nixpkgs/nixos/tests/common/auto-format-root-device.nix
new file mode 100644
index 000000000000..56eecef2f411
--- /dev/null
+++ b/nixpkgs/nixos/tests/common/auto-format-root-device.nix
@@ -0,0 +1,29 @@
+# This is a test utility that automatically formats
+# `config.virtualisation.rootDevice` in the initrd.
+# Note that when you are using
+# `boot.initrd.systemd.enable = true`, you can use
+# `virtualisation.fileSystems."/".autoFormat = true;`
+# instead.
+
+{ config, pkgs, ... }:
+
+let
+  rootDevice = config.virtualisation.rootDevice;
+in
+{
+
+  boot.initrd.extraUtilsCommands = ''
+    # We need mke2fs in the initrd.
+    copy_bin_and_libs ${pkgs.e2fsprogs}/bin/mke2fs
+  '';
+
+  boot.initrd.postDeviceCommands = ''
+    # If the disk image appears to be empty, run mke2fs to
+    # initialise.
+    FSTYPE=$(blkid -o value -s TYPE ${rootDevice} || true)
+    PARTTYPE=$(blkid -o value -s PTTYPE ${rootDevice} || true)
+    if test -z "$FSTYPE" -a -z "$PARTTYPE"; then
+        mke2fs -t ext4 ${rootDevice}
+    fi
+  '';
+}
diff --git a/nixpkgs/nixos/tests/common/gpg-keyring.nix b/nixpkgs/nixos/tests/common/gpg-keyring.nix
new file mode 100644
index 000000000000..fb8d07b1183e
--- /dev/null
+++ b/nixpkgs/nixos/tests/common/gpg-keyring.nix
@@ -0,0 +1,21 @@
+{ pkgs, ... }:
+
+pkgs.runCommand "gpg-keyring" { nativeBuildInputs = [ pkgs.gnupg ]; } ''
+  mkdir -p $out
+  export GNUPGHOME=$out
+  cat > foo <<EOF
+    %echo Generating a basic OpenPGP key
+    %no-protection
+    Key-Type: EdDSA
+    Key-Curve: ed25519
+    Name-Real: Bob Foobar
+    Name-Email: bob@foo.bar
+    Expire-Date: 0
+    # Do a commit here, so that we can later print "done"
+    %commit
+    %echo done
+  EOF
+  gpg --batch --generate-key foo
+  rm $out/S.gpg-agent $out/S.gpg-agent.*
+  gpg --export bob@foo.bar -a > $out/pubkey.gpg
+''
diff --git a/nixpkgs/nixos/tests/common/resolver.nix b/nixpkgs/nixos/tests/common/resolver.nix
index 3ddf730668c4..609058a7374a 100644
--- a/nixpkgs/nixos/tests/common/resolver.nix
+++ b/nixpkgs/nixos/tests/common/resolver.nix
@@ -63,7 +63,7 @@
             matched = builtins.match "[ \t]+(${reHost})(.*)" str;
             continue = lib.singleton (lib.head matched)
                     ++ matchAliases (lib.last matched);
-          in if matched == null then [] else continue;
+          in lib.optional (matched != null) continue;
 
           matchLine = str: let
             result = builtins.match "[ \t]*(${reIp})[ \t]+(${reHost})(.*)" str;
diff --git a/nixpkgs/nixos/tests/coturn.nix b/nixpkgs/nixos/tests/coturn.nix
index 301b34b0da70..b44bf8d06e39 100644
--- a/nixpkgs/nixos/tests/coturn.nix
+++ b/nixpkgs/nixos/tests/coturn.nix
@@ -24,6 +24,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
       with subtest("works with static-auth-secret-file"):
           secretsfile.wait_for_unit("coturn.service")
+          secretsfile.wait_for_open_port(3478)
           secretsfile.succeed("grep 'some-very-secret-string' /run/coturn/turnserver.cfg")
           # Forbidden IP, fails:
           secretsfile.fail("${pkgs.coturn}/bin/turnutils_uclient -W some-very-secret-string 127.0.0.1 -DgX -e 127.0.0.1 -n 1 -c -y")
diff --git a/nixpkgs/nixos/tests/cups-pdf.nix b/nixpkgs/nixos/tests/cups-pdf.nix
index 957b0296a755..5602193b0408 100644
--- a/nixpkgs/nixos/tests/cups-pdf.nix
+++ b/nixpkgs/nixos/tests/cups-pdf.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   nodes.machine = { pkgs, ... }: {
     imports = [ ./common/user-account.nix ];
     environment.systemPackages = [ pkgs.poppler_utils ];
-    fonts.fonts = [ pkgs.dejavu_fonts ];  # yields more OCR-able pdf
+    fonts.packages = [ pkgs.dejavu_fonts ];  # yields more OCR-able pdf
     services.printing.cups-pdf.enable = true;
     services.printing.cups-pdf.instances = {
       opt = {};
diff --git a/nixpkgs/nixos/tests/curl-impersonate.nix b/nixpkgs/nixos/tests/curl-impersonate.nix
new file mode 100644
index 000000000000..7954e9e5584c
--- /dev/null
+++ b/nixpkgs/nixos/tests/curl-impersonate.nix
@@ -0,0 +1,157 @@
+/*
+  Test suite for curl-impersonate
+
+  Abstract:
+    Uses the test suite from the curl-impersonate source repo which:
+
+    1. Performs requests with libcurl and captures the TLS client-hello
+       packets with tcpdump to compare against known-good signatures
+    2. Spins up an nghttpd2 server to test client HTTP/2 headers against
+       known-good headers
+
+    See https://github.com/lwthiker/curl-impersonate/tree/main/tests/signatures
+    for details.
+
+  Notes:
+    - We need to have our own web server running because the tests expect to be able
+      to hit domains like wikipedia.org and the sandbox has no internet
+    - We need to be able to do (verifying) TLS handshakes without internet access.
+      We do that by creating a trusted CA and issuing a cert that includes
+      all of the test domains as subject-alternative names and then spoofs the
+      hostnames in /etc/hosts.
+*/
+
+import ./make-test-python.nix ({ pkgs, lib, ... }: let
+  # Update with domains in TestImpersonate.TEST_URLS if needed from:
+  # https://github.com/lwthiker/curl-impersonate/blob/main/tests/test_impersonate.py
+  domains = [
+    "www.wikimedia.org"
+    "www.wikipedia.org"
+    "www.mozilla.org"
+    "www.apache.org"
+    "www.kernel.org"
+    "git-scm.com"
+  ];
+
+  tls-certs = let
+    # Configure CA with X.509 v3 extensions that would be trusted by curl
+    ca-cert-conf = pkgs.writeText "curl-impersonate-ca.cnf" ''
+      basicConstraints = critical, CA:TRUE
+      subjectKeyIdentifier = hash
+      authorityKeyIdentifier = keyid:always, issuer:always
+      keyUsage = critical, cRLSign, digitalSignature, keyCertSign
+    '';
+
+    # Configure leaf certificate with X.509 v3 extensions that would be trusted
+    # by curl and set subject-alternative names for test domains
+    tls-cert-conf = pkgs.writeText "curl-impersonate-tls.cnf" ''
+      basicConstraints = critical, CA:FALSE
+      subjectKeyIdentifier = hash
+      authorityKeyIdentifier = keyid:always, issuer:always
+      keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement
+      extendedKeyUsage = critical, serverAuth
+      subjectAltName = @alt_names
+
+      [alt_names]
+      ${lib.concatStringsSep "\n" (lib.imap0 (idx: domain: "DNS.${toString idx} = ${domain}") domains)}
+    '';
+  in pkgs.runCommand "curl-impersonate-test-certs" {
+    nativeBuildInputs = [ pkgs.openssl ];
+  } ''
+    # create CA certificate and key
+    openssl req -newkey rsa:4096 -keyout ca-key.pem -out ca-csr.pem -nodes -subj '/CN=curl-impersonate-ca.nixos.test'
+    openssl x509 -req -sha512 -in ca-csr.pem -key ca-key.pem -out ca.pem -extfile ${ca-cert-conf} -days 36500
+    openssl x509 -in ca.pem -text
+
+    # create server certificate and key
+    openssl req -newkey rsa:4096 -keyout key.pem -out csr.pem -nodes -subj '/CN=curl-impersonate.nixos.test'
+    openssl x509 -req -sha512 -in csr.pem -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile ${tls-cert-conf} -days 36500
+    openssl x509 -in cert.pem -text
+
+    # output CA cert and server cert and key
+    mkdir -p $out
+    cp key.pem cert.pem ca.pem $out
+  '';
+
+  # Test script
+  curl-impersonate-test = let
+    # Build miniature libcurl client used by test driver
+    minicurl = pkgs.runCommandCC "minicurl" {
+      buildInputs = [ pkgs.curl ];
+    } ''
+      mkdir -p $out/bin
+      $CC -Wall -Werror -o $out/bin/minicurl ${pkgs.curl-impersonate.src}/tests/minicurl.c `curl-config --libs`
+    '';
+  in pkgs.writeShellScript "curl-impersonate-test" ''
+    set -euxo pipefail
+
+    # Test driver requirements
+    export PATH="${with pkgs; lib.makeBinPath [
+      bash
+      coreutils
+      python3Packages.pytest
+      nghttp2
+      tcpdump
+    ]}"
+    export PYTHONPATH="${with pkgs.python3Packages; makePythonPath [
+      pyyaml
+      pytest-asyncio
+      dpkt
+    ]}"
+
+    # Prepare test root prefix
+    mkdir -p usr/{bin,lib}
+    cp -rs ${pkgs.curl-impersonate}/* ${minicurl}/* usr/
+
+    cp -r ${pkgs.curl-impersonate.src}/tests ./
+
+    # Run tests
+    cd tests
+    pytest . --install-dir ../usr --capture-interface eth1
+  '';
+in {
+  name = "curl-impersonate";
+
+  meta = with lib.maintainers; {
+    maintainers = [ lilyinstarlight ];
+  };
+
+  nodes = {
+    web = { nodes, pkgs, lib, config, ... }: {
+      networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+      services = {
+        nginx = {
+          enable = true;
+          virtualHosts."curl-impersonate.nixos.test" = {
+            default = true;
+            addSSL = true;
+            sslCertificate = "${tls-certs}/cert.pem";
+            sslCertificateKey = "${tls-certs}/key.pem";
+          };
+        };
+      };
+    };
+
+    curl = { nodes, pkgs, lib, config, ... }: {
+      networking.extraHosts = lib.concatStringsSep "\n" (map (domain: "${nodes.web.networking.primaryIPAddress}  ${domain}") domains);
+
+      security.pki.certificateFiles = [ "${tls-certs}/ca.pem" ];
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    start_all()
+
+    with subtest("Wait for network"):
+        web.wait_for_unit("network-online.target")
+        curl.wait_for_unit("network-online.target")
+
+    with subtest("Wait for web server"):
+        web.wait_for_unit("nginx.service")
+        web.wait_for_open_port(443)
+
+    with subtest("Run curl-impersonate tests"):
+        curl.succeed("${curl-impersonate-test}")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/deepin.nix b/nixpkgs/nixos/tests/deepin.nix
index 0fe93486b6cb..7b2e2430f31c 100644
--- a/nixpkgs/nixos/tests/deepin.nix
+++ b/nixpkgs/nixos/tests/deepin.nix
@@ -1,15 +1,15 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "deepin";
 
-  meta = with lib; {
-    maintainers = teams.deepin.members;
-  };
+  meta.maintainers = lib.teams.deepin.members;
 
   nodes.machine = { ... }: {
     imports = [
       ./common/user-account.nix
     ];
 
+    virtualisation.memorySize = 2048;
+
     services.xserver.enable = true;
 
     services.xserver.displayManager = {
diff --git a/nixpkgs/nixos/tests/evcc.nix b/nixpkgs/nixos/tests/evcc.nix
index b445735ede98..7ebdc6a6f5ab 100644
--- a/nixpkgs/nixos/tests/evcc.nix
+++ b/nixpkgs/nixos/tests/evcc.nix
@@ -46,7 +46,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
             type = "custom";
             status = {
               source = "script";
-              cmd = "/bin/sh -c 'echo charger status F'";
+              cmd = "/bin/sh -c 'echo charger status A'";
             };
             enabled = {
               source = "script";
diff --git a/nixpkgs/nixos/tests/fail2ban.nix b/nixpkgs/nixos/tests/fail2ban.nix
new file mode 100644
index 000000000000..c3708575b702
--- /dev/null
+++ b/nixpkgs/nixos/tests/fail2ban.nix
@@ -0,0 +1,18 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "fail2ban";
+
+  nodes.machine = _: {
+    services.fail2ban = {
+      enable = true;
+      bantime-increment.enable = true;
+    };
+
+    services.openssh.enable = true;
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+
+    machine.wait_for_unit("fail2ban")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/fakeroute.nix b/nixpkgs/nixos/tests/fakeroute.nix
new file mode 100644
index 000000000000..37b174524ab8
--- /dev/null
+++ b/nixpkgs/nixos/tests/fakeroute.nix
@@ -0,0 +1,22 @@
+import ./make-test-python.nix ({ lib, pkgs, ...} : {
+  name = "fakeroute";
+  meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+
+  nodes.machine = { ... }: {
+    imports = [ ../modules/profiles/minimal.nix ];
+    services.fakeroute.enable = true;
+    services.fakeroute.route =
+      [ "216.102.187.130" "4.0.1.122"
+        "198.116.142.34" "63.199.8.242"
+      ];
+    environment.systemPackages = [ pkgs.traceroute ];
+  };
+
+  testScript =
+    ''
+      start_all()
+      machine.wait_for_unit("fakeroute.service")
+      machine.succeed("traceroute 127.0.0.1 | grep -q 216.102.187.130")
+    '';
+})
+
diff --git a/nixpkgs/nixos/tests/fontconfig-default-fonts.nix b/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
index 664afc9bf44c..d8c6ea0f721b 100644
--- a/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
+++ b/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
@@ -7,8 +7,8 @@ import ./make-test-python.nix ({ lib, ... }:
   ];
 
   nodes.machine = { config, pkgs, ... }: {
-    fonts.enableDefaultFonts = true; # Background fonts
-    fonts.fonts = with pkgs; [
+    fonts.enableDefaultPackages = true; # Background fonts
+    fonts.packages = with pkgs; [
       noto-fonts-emoji
       cantarell-fonts
       twitter-color-emoji
diff --git a/nixpkgs/nixos/tests/freshrss-http-auth.nix b/nixpkgs/nixos/tests/freshrss-http-auth.nix
new file mode 100644
index 000000000000..d0ec3da31689
--- /dev/null
+++ b/nixpkgs/nixos/tests/freshrss-http-auth.nix
@@ -0,0 +1,20 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "freshrss";
+  meta.maintainers = with lib.maintainers; [ mattchrist ];
+
+  nodes.machine = { pkgs, ... }: {
+    services.freshrss = {
+      enable = true;
+      baseUrl = "http://localhost";
+      dataDir = "/srv/freshrss";
+      authType = "http_auth";
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_open_port(80)
+    response = machine.succeed("curl -vvv -s -H 'Host: freshrss' -H 'Remote-User: testuser' http://127.0.0.1:80/i/")
+    assert 'Account: testuser' in response, "http_auth method didn't work."
+  '';
+})
diff --git a/nixpkgs/nixos/tests/fsck.nix b/nixpkgs/nixos/tests/fsck.nix
index ec6bfa69ae84..31ed8bdf78c0 100644
--- a/nixpkgs/nixos/tests/fsck.nix
+++ b/nixpkgs/nixos/tests/fsck.nix
@@ -21,13 +21,17 @@ import ./make-test-python.nix {
     boot.initrd.systemd.enable = systemdStage1;
   };
 
-  testScript = ''
+  testScript =  { nodes, ...}:
+  let
+    rootDevice = nodes.machine.virtualisation.rootDevice;
+  in
+  ''
     machine.wait_for_unit("default.target")
 
     with subtest("root fs is fsckd"):
         machine.succeed("journalctl -b | grep '${if systemdStage1
-          then "fsck.*vda.*clean"
-          else "fsck.ext4.*/dev/vda"}'")
+          then "fsck.*${builtins.baseNameOf rootDevice}.*clean"
+          else "fsck.ext4.*${rootDevice}"}'")
 
     with subtest("mnt fs is fsckd"):
         machine.succeed("journalctl -b | grep 'fsck.*vdb.*clean'")
diff --git a/nixpkgs/nixos/tests/gitea.nix b/nixpkgs/nixos/tests/gitea.nix
index 2285bb5a4252..b747659de829 100644
--- a/nixpkgs/nixos/tests/gitea.nix
+++ b/nixpkgs/nixos/tests/gitea.nix
@@ -37,9 +37,25 @@ let
           package = giteaPackage;
           settings.service.DISABLE_REGISTRATION = true;
           settings."repository.signing".SIGNING_KEY = signingPrivateKeyId;
+          settings.actions.ENABLED = true;
         };
         environment.systemPackages = [ giteaPackage pkgs.gnupg pkgs.jq ];
         services.openssh.enable = true;
+
+        specialisation.runner = {
+          inheritParentConfig = true;
+
+          configuration.services.gitea-actions-runner.instances."test" = {
+            enable = true;
+            name = "ci";
+            url = "http://localhost:3000";
+            labels = [
+              # don't require docker/podman
+              "native:host"
+            ];
+            tokenFile = "/var/lib/gitea/runner_token";
+          };
+        };
       };
       client1 = { config, pkgs, ... }: {
         environment.systemPackages = [ pkgs.git ];
@@ -49,8 +65,9 @@ let
       };
     };
 
-    testScript = let
+    testScript = { nodes, ... }: let
       inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
+      serverSystem = nodes.server.system.build.toplevel;
     in ''
       GIT_SSH_COMMAND = "ssh -i $HOME/.ssh/privk -o StrictHostKeyChecking=no"
       REPO = "gitea@server:test/repo"
@@ -121,14 +138,18 @@ let
       client2.succeed(f"GIT_SSH_COMMAND='{GIT_SSH_COMMAND}' git clone {REPO}")
       client2.succeed('test "$(cat repo/testfile | xargs echo -n)" = "hello world"')
 
-      server.succeed(
+      server.wait_until_succeeds(
           'test "$(curl http://localhost:3000/api/v1/repos/test/repo/commits '
           + '-H "Accept: application/json" | jq length)" = "1"'
       )
 
-      client1.shutdown()
-      client2.shutdown()
-      server.shutdown()
+      with subtest("Testing runner registration"):
+          server.succeed(
+              "su -l gitea -c 'GITEA_WORK_DIR=/var/lib/gitea gitea actions generate-runner-token' | sed 's/^/TOKEN=/' | tee /var/lib/gitea/runner_token"
+          )
+          server.succeed("${serverSystem}/specialisation/runner/bin/switch-to-configuration test")
+          server.wait_for_unit("gitea-runner-test.service")
+          server.succeed("journalctl -o cat -u gitea-runner-test.service | grep -q 'Runner registered successfully'")
     '';
   });
 in
diff --git a/nixpkgs/nixos/tests/gnome-flashback.nix b/nixpkgs/nixos/tests/gnome-flashback.nix
index 70569db797ec..876d36477c1a 100644
--- a/nixpkgs/nixos/tests/gnome-flashback.nix
+++ b/nixpkgs/nixos/tests/gnome-flashback.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
 
   nodes.machine = { nodes, ... }:
     let
-      user = nodes.machine.config.users.users.alice;
+      user = nodes.machine.users.users.alice;
     in
 
     { imports = [ ./common/user-account.nix ];
@@ -27,12 +27,20 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     };
 
   testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.users.alice;
+    user = nodes.machine.users.users.alice;
     uid = toString user.uid;
     xauthority = "/run/user/${uid}/gdm/Xauthority";
   in ''
       with subtest("Login to GNOME Flashback with GDM"):
-          machine.wait_for_x()
+          # wait_for_x() checks graphical-session.target, which is expected to be
+          # inactive on gnome-flashback before #228946 (i.e. systemd managed
+          # gnome-session) is done.
+          # https://github.com/NixOS/nixpkgs/pull/208060
+          #
+          # Previously this was unconditionally touched by xsessionWrapper but was
+          # changed in #233981 (we have GNOME-Flashback:GNOME in XDG_CURRENT_DESKTOP).
+          # machine.wait_for_x()
+          machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"')
           # Wait for alice to be logged in"
           machine.wait_for_unit("default.target", "${user.name}")
           machine.wait_for_file("${xauthority}")
diff --git a/nixpkgs/nixos/tests/guacamole-server.nix b/nixpkgs/nixos/tests/guacamole-server.nix
new file mode 100644
index 000000000000..48194fddfb22
--- /dev/null
+++ b/nixpkgs/nixos/tests/guacamole-server.nix
@@ -0,0 +1,21 @@
+import ./make-test-python.nix ({pkgs, lib, ...}:
+{
+  name = "guacamole-server";
+
+  nodes = {
+    machine = {pkgs, ...}: {
+      services.guacamole-server = {
+        enable = true;
+        host = "0.0.0.0";
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("guacamole-server.service")
+    machine.wait_for_open_port(4822)
+  '';
+
+  meta.maintainers = [ lib.maintainers.drupol ];
+})
diff --git a/nixpkgs/nixos/tests/hibernate.nix b/nixpkgs/nixos/tests/hibernate.nix
index 24b4ed382c12..296aa9ba68b9 100644
--- a/nixpkgs/nixos/tests/hibernate.nix
+++ b/nixpkgs/nixos/tests/hibernate.nix
@@ -8,127 +8,48 @@
 
 with import ../lib/testing-python.nix { inherit system pkgs; };
 
-let
-  # System configuration of the installed system, which is used for the actual
-  # hibernate testing.
-  installedConfig = with pkgs.lib; {
-    imports = [
-      ../modules/testing/test-instrumentation.nix
-      ../modules/profiles/qemu-guest.nix
-      ../modules/profiles/minimal.nix
-    ];
-
-    hardware.enableAllFirmware = mkForce false;
-    documentation.nixos.enable = false;
-    boot.loader.grub.device = "/dev/vda";
-
-    systemd.services.backdoor.conflicts = [ "sleep.target" ];
-
-    powerManagement.resumeCommands = "systemctl --no-block restart backdoor.service";
-
-    fileSystems."/" = {
-      device = "/dev/vda2";
-      fsType = "ext3";
-    };
-    swapDevices = mkOverride 0 [ { device = "/dev/vda1"; } ];
-    boot.resumeDevice = mkIf systemdStage1 "/dev/vda1";
-    boot.initrd.systemd = mkIf systemdStage1 {
-      enable = true;
-      emergencyAccess = true;
-    };
-  };
-  installedSystem = (import ../lib/eval-config.nix {
-    inherit system;
-    modules = [ installedConfig ];
-  }).config.system.build.toplevel;
-in makeTest {
+makeTest {
   name = "hibernate";
 
   nodes = {
-    # System configuration used for installing the installedConfig from above.
     machine = { config, lib, pkgs, ... }: {
       imports = [
-        ../modules/profiles/installation-device.nix
-        ../modules/profiles/base.nix
+        ./common/auto-format-root-device.nix
       ];
 
-      nix.settings = {
-        substituters = lib.mkForce [];
-        hashed-mirrors = null;
-        connect-timeout = 1;
-      };
+      systemd.services.backdoor.conflicts = [ "sleep.target" ];
+      powerManagement.resumeCommands = "systemctl --no-block restart backdoor.service";
 
-      virtualisation.diskSize = 8 * 1024;
-      virtualisation.emptyDiskImages = [
-        # Small root disk for installer
-        512
-      ];
-      virtualisation.rootDevice = "/dev/vdb";
+      virtualisation.emptyDiskImages = [ (2 * config.virtualisation.memorySize) ];
+      virtualisation.useNixStoreImage = true;
+
+      swapDevices = lib.mkOverride 0 [ { device = "/dev/vdc"; options = [ "x-systemd.makefs" ]; } ];
+      boot.resumeDevice = "/dev/vdc";
+      boot.initrd.systemd.enable = systemdStage1;
     };
   };
 
-  # 9P doesn't support reconnection to virtio transport after a hibernation.
-  # Therefore, machine just hangs on any Nix store access.
-  # To avoid this, we install NixOS onto a temporary disk with everything we need
-  # included into the store.
-
-  testScript =
-    ''
-      def create_named_machine(name):
-          machine = create_machine(
-              {
-                  "qemuFlags": "-cpu max ${
-                    if system == "x86_64-linux" then "-m 1024"
-                    else "-m 768 -enable-kvm -machine virt,gic-version=host"}",
-                  "hdaInterface": "virtio",
-                  "hda": "vm-state-machine/machine.qcow2",
-                  "name": name,
-              }
-          )
-          driver.machines.append(machine)
-          return machine
-
-
-      # Install NixOS
-      machine.start()
-      machine.succeed(
-          # Partition /dev/vda
-          "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
-          + " mkpart primary linux-swap 1M 1024M"
-          + " mkpart primary ext2 1024M -1s",
-          "udevadm settle",
-          "mkfs.ext3 -L nixos /dev/vda2",
-          "mount LABEL=nixos /mnt",
-          "mkswap /dev/vda1 -L swap",
-          # Install onto /mnt
-          "nix-store --load-db < ${pkgs.closureInfo {rootPaths = [installedSystem];}}/registration",
-          "nixos-install --root /mnt --system ${installedSystem} --no-root-passwd --no-channel-copy >&2",
-      )
-      machine.shutdown()
-
-      # Start up
-      hibernate = create_named_machine("hibernate")
-
-      # Drop in file that checks if we un-hibernated properly (and not booted fresh)
-      hibernate.succeed(
-          "mkdir /run/test",
-          "mount -t ramfs -o size=1m ramfs /run/test",
-          "echo not persisted to disk > /run/test/suspended",
-      )
-
-      # Hibernate machine
-      hibernate.execute("systemctl hibernate >&2 &", check_return=False)
-      hibernate.wait_for_shutdown()
-
-      # Restore machine from hibernation, validate our ramfs file is there.
-      resume = create_named_machine("resume")
-      resume.start()
-      resume.succeed("grep 'not persisted to disk' /run/test/suspended")
-
-      # Ensure we don't restore from hibernation when booting again
-      resume.crash()
-      resume.wait_for_unit("default.target")
-      resume.fail("grep 'not persisted to disk' /run/test/suspended")
-    '';
+  testScript = ''
+    # Drop in file that checks if we un-hibernated properly (and not booted fresh)
+    machine.wait_for_unit("default.target")
+    machine.succeed(
+        "mkdir /run/test",
+        "mount -t ramfs -o size=1m ramfs /run/test",
+        "echo not persisted to disk > /run/test/suspended",
+    )
+
+    # Hibernate machine
+    machine.execute("systemctl hibernate >&2 &", check_return=False)
+    machine.wait_for_shutdown()
+
+    # Restore machine from hibernation, validate our ramfs file is there.
+    machine.start()
+    machine.succeed("grep 'not persisted to disk' /run/test/suspended")
+
+    # Ensure we don't restore from hibernation when booting again
+    machine.crash()
+    machine.wait_for_unit("default.target")
+    machine.fail("grep 'not persisted to disk' /run/test/suspended")
+  '';
 
 }
diff --git a/nixpkgs/nixos/tests/homepage-dashboard.nix b/nixpkgs/nixos/tests/homepage-dashboard.nix
new file mode 100644
index 000000000000..56e077f5ff6d
--- /dev/null
+++ b/nixpkgs/nixos/tests/homepage-dashboard.nix
@@ -0,0 +1,14 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "homepage-dashboard";
+  meta.maintainers = with lib.maintainers; [ jnsgruk ];
+
+  nodes.machine = { pkgs, ... }: {
+    services.homepage-dashboard.enable = true;
+  };
+
+  testScript = ''
+    machine.wait_for_unit("homepage-dashboard.service")
+    machine.wait_for_open_port(8082)
+    machine.succeed("curl --fail http://localhost:8082/")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/initrd-luks-empty-passphrase.nix b/nixpkgs/nixos/tests/initrd-luks-empty-passphrase.nix
index 521456e7e0b2..a846c120415d 100644
--- a/nixpkgs/nixos/tests/initrd-luks-empty-passphrase.nix
+++ b/nixpkgs/nixos/tests/initrd-luks-empty-passphrase.nix
@@ -14,6 +14,8 @@ in {
   name = "initrd-luks-empty-passphrase";
 
   nodes.machine = { pkgs, ... }: {
+    imports = lib.optionals (!systemdStage1) [ ./common/auto-format-root-device.nix ];
+
     virtualisation = {
       emptyDiskImages = [ 512 ];
       useBootLoader = true;
@@ -23,6 +25,7 @@ in {
       # the new root device is /dev/vdb
       # an empty 512MiB drive, containing no Nix store.
       mountHostNixStore = true;
+      fileSystems."/".autoFormat = lib.mkIf systemdStage1 true;
     };
 
     boot.loader.systemd-boot.enable = true;
diff --git a/nixpkgs/nixos/tests/initrd-network-ssh/default.nix b/nixpkgs/nixos/tests/initrd-network-ssh/default.nix
index 017de6882081..17b6c21ff1e9 100644
--- a/nixpkgs/nixos/tests/initrd-network-ssh/default.nix
+++ b/nixpkgs/nixos/tests/initrd-network-ssh/default.nix
@@ -1,12 +1,10 @@
-import ../make-test-python.nix ({ lib, ... }:
+import ../make-test-python.nix ({ lib, pkgs, ... }:
 
 {
   name = "initrd-network-ssh";
-  meta = with lib.maintainers; {
-    maintainers = [ willibutz emily ];
-  };
+  meta.maintainers = with lib.maintainers; [ willibutz emily ];
 
-  nodes = with lib; {
+  nodes = {
     server =
       { config, ... }:
       {
@@ -17,7 +15,7 @@ import ../make-test-python.nix ({ lib, ... }:
           enable = true;
           ssh = {
             enable = true;
-            authorizedKeys = [ (readFile ./id_ed25519.pub) ];
+            authorizedKeys = [ (lib.readFile ./id_ed25519.pub) ];
             port = 22;
             hostKeys = [ ./ssh_host_ed25519_key ];
           };
@@ -37,12 +35,12 @@ import ../make-test-python.nix ({ lib, ... }:
       {
         environment.etc = {
           knownHosts = {
-            text = concatStrings [
+            text = lib.concatStrings [
               "server,"
-              "${toString (head (splitString " " (
-                toString (elemAt (splitString "\n" config.networking.extraHosts) 2)
+              "${toString (lib.head (lib.splitString " " (
+                toString (lib.elemAt (lib.splitString "\n" config.networking.extraHosts) 2)
               )))} "
-              "${readFile ./ssh_host_ed25519_key.pub}"
+              "${lib.readFile ./ssh_host_ed25519_key.pub}"
             ];
           };
           sshKey = {
diff --git a/nixpkgs/nixos/tests/installed-tests/default.nix b/nixpkgs/nixos/tests/installed-tests/default.nix
index 78a6325a245e..e87edb2007e9 100644
--- a/nixpkgs/nixos/tests/installed-tests/default.nix
+++ b/nixpkgs/nixos/tests/installed-tests/default.nix
@@ -107,5 +107,6 @@ in
   malcontent = callInstalledTest ./malcontent.nix {};
   ostree = callInstalledTest ./ostree.nix {};
   pipewire = callInstalledTest ./pipewire.nix {};
+  upower = callInstalledTest ./upower.nix {};
   xdg-desktop-portal = callInstalledTest ./xdg-desktop-portal.nix {};
 }
diff --git a/nixpkgs/nixos/tests/installed-tests/upower.nix b/nixpkgs/nixos/tests/installed-tests/upower.nix
new file mode 100644
index 000000000000..a8e777a55527
--- /dev/null
+++ b/nixpkgs/nixos/tests/installed-tests/upower.nix
@@ -0,0 +1,9 @@
+{ pkgs, makeInstalledTest, ... }:
+
+makeInstalledTest {
+  tested = pkgs.upower;
+
+  testConfig = {
+    services.upower.enable = true;
+  };
+}
diff --git a/nixpkgs/nixos/tests/installer-systemd-stage-1.nix b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
index 05fb2b2ae89c..85155a6c682b 100644
--- a/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
+++ b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
@@ -28,7 +28,7 @@
     simpleUefiGrubSpecialisation
     simpleUefiSystemdBoot
     stratisRoot
-    # swraid
+    swraid
     zfsroot
     ;
 
diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix
index 1ac164f4b816..56ba85b76e6f 100644
--- a/nixpkgs/nixos/tests/installer.nix
+++ b/nixpkgs/nixos/tests/installer.nix
@@ -11,16 +11,20 @@ let
 
   # The configuration to install.
   makeConfig = { bootLoader, grubDevice, grubIdentifier, grubUseEfi
-               , extraConfig, forceGrubReinstallCount ? 0
+               , extraConfig, forceGrubReinstallCount ? 0, flake ? false
                }:
     pkgs.writeText "configuration.nix" ''
       { config, lib, pkgs, modulesPath, ... }:
 
       { imports =
           [ ./hardware-configuration.nix
-            <nixpkgs/nixos/modules/testing/test-instrumentation.nix>
+            ${if flake
+              then "" # Still included, but via installer/flake.nix
+              else "<nixpkgs/nixos/modules/testing/test-instrumentation.nix>"}
           ];
 
+        networking.hostName = "thatworked";
+
         documentation.enable = false;
 
         # To ensure that we can rebuild the grub configuration on the nixos-rebuild
@@ -67,7 +71,7 @@ let
   # partitions and filesystems.
   testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi
                   , grubIdentifier, preBootCommands, postBootCommands, extraConfig
-                  , testSpecialisationConfig
+                  , testSpecialisationConfig, testFlakeSwitch
                   }:
     let iface = "virtio";
         isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi);
@@ -86,9 +90,14 @@ let
 
       qemu_flags = {"qemuFlags": assemble_qemu_flags()}
 
+      import os
+
+      image_dir = machine.state_dir
+      disk_image = os.path.join(image_dir, "machine.qcow2")
+
       hd_flags = {
           "hdaInterface": "${iface}",
-          "hda": "vm-state-machine/machine.qcow2",
+          "hda": disk_image,
       }
       ${optionalString isEfi ''
         hd_flags.update(
@@ -232,6 +241,11 @@ let
       machine = create_machine_named("boot-after-rebuild-switch")
       ${preBootCommands}
       machine.wait_for_unit("network.target")
+
+      # Sanity check, is it the configuration.nix we generated?
+      hostname = machine.succeed("hostname").strip()
+      assert hostname == "thatworked"
+
       ${postBootCommands}
       machine.shutdown()
 
@@ -272,6 +286,84 @@ let
 
       ${postBootCommands}
       machine.shutdown()
+    ''
+    + optionalString testFlakeSwitch ''
+      ${preBootCommands}
+      machine.start()
+
+      with subtest("Configure system with flake"):
+        # TODO: evaluate as user?
+        machine.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(
+          "${makeConfig {
+               inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig;
+               forceGrubReinstallCount = 1;
+               flake = true;
+            }}",
+          "/root/my-config/configuration.nix",
+        )
+        machine.copy_from_host_via_shell(
+          "${./installer/flake.nix}",
+          "/root/my-config/flake.nix",
+        )
+        machine.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
+          if ! [[ -e $pkgs/pkgs/top-level/default.nix ]]; then
+            echo 1>&2 "$pkgs does not seem to be a nixpkgs source. Please fix the test so that pkgs points to a nixpkgs source.";
+            exit 1;
+          fi
+          sed -e s^@nixpkgs@^$pkgs^ -i /root/my-config/flake.nix
+        """)
+
+      with subtest("Switch to flake based config"):
+        machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
+
+      ${postBootCommands}
+      machine.shutdown()
+
+      ${preBootCommands}
+      machine.start()
+
+      machine.wait_for_unit("multi-user.target")
+
+      with subtest("nix-channel command is not available anymore"):
+        machine.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("""
+          [[ "[ ]" == "$(nix-instantiate builtins.nixPath --eval --expr)" ]]
+        """)
+
+      with subtest("<nixpkgs> does not resolve"):
+        machine.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")
+
+      with subtest("Evaluate flake config in fresh env without channel profiles"):
+        machine.succeed("""
+          (
+            exec 1>&2
+            rm -v /root/.nix-channels
+            rm -vrf ~/.nix-defexpr
+            rm -vrf /nix/var/nix/profiles/per-user/root/channels*
+          )
+        """)
+        machine.succeed("nixos-rebuild switch --flake /root/my-config#xyz")
+
+      ${postBootCommands}
+      machine.shutdown()
     '';
 
 
@@ -282,11 +374,12 @@ let
     , grubDevice ? "/dev/vda", grubIdentifier ? "uuid", grubUseEfi ? false
     , enableOCR ? false, meta ? {}
     , testSpecialisationConfig ? false
+    , testFlakeSwitch ? false
     }:
     makeTest {
       inherit enableOCR;
       name = "installer-" + name;
-      meta = with pkgs.lib.maintainers; {
+      meta = {
         # put global maintainers here, individuals go into makeInstallerTest fkt call
         maintainers = (meta.maintainers or []);
       };
@@ -298,8 +391,13 @@ let
             ../modules/profiles/installation-device.nix
             ../modules/profiles/base.nix
             extraInstallerConfig
+            ./common/auto-format-root-device.nix
           ];
 
+          # In systemdStage1, also automatically format the device backing the
+          # root filesystem.
+          virtualisation.fileSystems."/".autoFormat = systemdStage1;
+
           # builds stuff in the VM, needs more juice
           virtualisation.diskSize = 8 * 1024;
           virtualisation.cores = 8;
@@ -329,15 +427,13 @@ let
           # The test cannot access the network, so any packages we
           # need must be included in the VM.
           system.extraDependencies = with pkgs; [
+            bintools
             brotli
             brotli.dev
             brotli.lib
             desktop-file-utils
             docbook5
             docbook_xsl_ns
-            (docbook-xsl-ns.override {
-              withManOptDedupPatch = true;
-            })
             kbd.dev
             kmod.dev
             libarchive.dev
@@ -385,7 +481,7 @@ let
       testScript = testScriptFun {
         inherit bootLoader createPartitions preBootCommands postBootCommands
                 grubDevice grubIdentifier grubUseEfi extraConfig
-                testSpecialisationConfig;
+                testSpecialisationConfig testFlakeSwitch;
       };
     };
 
@@ -437,6 +533,10 @@ let
     '';
   };
 
+  simple-test-config-flake = simple-test-config // {
+    testFlakeSwitch = true;
+  };
+
   simple-uefi-grub-config = {
     createPartitions = ''
       machine.succeed(
@@ -491,6 +591,8 @@ in {
   # one big filesystem partition.
   simple = makeInstallerTest "simple" simple-test-config;
 
+  switchToFlake = makeInstallerTest "switch-to-flake" simple-test-config-flake;
+
   # Test cloned configurations with the simple grub configuration
   simpleSpecialised = makeInstallerTest "simpleSpecialised" (simple-test-config // specialisation-test-extraconfig);
 
@@ -832,7 +934,7 @@ in {
         "keyctl link @u @s",
         "echo password | mkfs.bcachefs -L root --encrypted /dev/vda3",
         "echo password | bcachefs unlock /dev/vda3",
-        "mount -t bcachefs /dev/vda3 /mnt",
+        "echo password | mount -t bcachefs /dev/vda3 /mnt",
         "mkfs.ext3 -L boot /dev/vda1",
         "mkdir -p /mnt/boot",
         "mount /dev/vda1 /mnt/boot",
diff --git a/nixpkgs/nixos/tests/installer/flake.nix b/nixpkgs/nixos/tests/installer/flake.nix
new file mode 100644
index 000000000000..4bbef44e34fc
--- /dev/null
+++ b/nixpkgs/nixos/tests/installer/flake.nix
@@ -0,0 +1,20 @@
+# This file gets copied into the installation
+
+{
+  # To keep things simple, we'll use an absolute path dependency here.
+  inputs.nixpkgs.url = "@nixpkgs@";
+
+  outputs = { nixpkgs, ... }: {
+
+    nixosConfigurations.xyz = nixpkgs.lib.nixosSystem {
+      modules = [
+        ./configuration.nix
+        ( nixpkgs + "/nixos/modules/testing/test-instrumentation.nix" )
+        {
+          # We don't need nix-channel anymore
+          nix.channel.enable = false;
+        }
+      ];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/tests/jenkins.nix b/nixpkgs/nixos/tests/jenkins.nix
index a1ede6dc917b..a8f621000654 100644
--- a/nixpkgs/nixos/tests/jenkins.nix
+++ b/nixpkgs/nixos/tests/jenkins.nix
@@ -73,8 +73,8 @@ import ./make-test-python.nix ({ pkgs, ...} : {
 
   testScript = { nodes, ... }:
     let
-      configWithoutJobs = "${nodes.master.config.system.build.toplevel}/specialisation/noJenkinsJobs";
-      jenkinsPort = nodes.master.config.services.jenkins.port;
+      configWithoutJobs = "${nodes.master.system.build.toplevel}/specialisation/noJenkinsJobs";
+      jenkinsPort = nodes.master.services.jenkins.port;
       jenkinsUrl = "http://localhost:${toString jenkinsPort}";
     in ''
     start_all()
diff --git a/nixpkgs/nixos/tests/k3s/single-node.nix b/nixpkgs/nixos/tests/k3s/single-node.nix
index d61595d889e2..e059603b9c9d 100644
--- a/nixpkgs/nixos/tests/k3s/single-node.nix
+++ b/nixpkgs/nixos/tests/k3s/single-node.nix
@@ -62,20 +62,20 @@ import ../make-test-python.nix ({ pkgs, lib, k3s, ... }:
       start_all()
 
       machine.wait_for_unit("k3s")
-      machine.succeed("k3s kubectl cluster-info")
-      machine.fail("sudo -u noprivs k3s kubectl cluster-info")
+      machine.succeed("kubectl cluster-info")
+      machine.fail("sudo -u noprivs kubectl cluster-info")
       '' # Fix-Me: Tests fail for 'aarch64-linux' as: "CONFIG_CGROUP_FREEZER: missing (fail)"
       + lib.optionalString (!pkgs.stdenv.isAarch64) ''machine.succeed("k3s check-config")'' + ''
 
       machine.succeed(
-          "${pauseImage} | k3s ctr image import -"
+          "${pauseImage} | ctr image import -"
       )
 
       # Also wait for our service account to show up; it takes a sec
-      machine.wait_until_succeeds("k3s kubectl get serviceaccount default")
-      machine.succeed("k3s kubectl apply -f ${testPodYaml}")
-      machine.succeed("k3s kubectl wait --for 'condition=Ready' pod/test")
-      machine.succeed("k3s kubectl delete -f ${testPodYaml}")
+      machine.wait_until_succeeds("kubectl get serviceaccount default")
+      machine.succeed("kubectl apply -f ${testPodYaml}")
+      machine.succeed("kubectl wait --for 'condition=Ready' pod/test")
+      machine.succeed("kubectl delete -f ${testPodYaml}")
 
       # regression test for #176445
       machine.fail("journalctl -o cat -u k3s.service | grep 'ipset utility not found'")
diff --git a/nixpkgs/nixos/tests/kafka.nix b/nixpkgs/nixos/tests/kafka.nix
index 79af02710c32..864253fd8c73 100644
--- a/nixpkgs/nixos/tests/kafka.nix
+++ b/nixpkgs/nixos/tests/kafka.nix
@@ -72,5 +72,7 @@ in with pkgs; {
   kafka_3_1  = makeKafkaTest "kafka_3_1"  apacheKafka_3_1;
   kafka_3_2  = makeKafkaTest "kafka_3_2"  apacheKafka_3_2;
   kafka_3_3  = makeKafkaTest "kafka_3_3"  apacheKafka_3_3;
+  kafka_3_4  = makeKafkaTest "kafka_3_4"  apacheKafka_3_4;
+  kafka_3_5  = makeKafkaTest "kafka_3_5"  apacheKafka_3_5;
   kafka  = makeKafkaTest "kafka"  apacheKafka;
 }
diff --git a/nixpkgs/nixos/tests/kanidm.nix b/nixpkgs/nixos/tests/kanidm.nix
index 7e174590cb5f..3f5bca397740 100644
--- a/nixpkgs/nixos/tests/kanidm.nix
+++ b/nixpkgs/nixos/tests/kanidm.nix
@@ -2,6 +2,10 @@ import ./make-test-python.nix ({ pkgs, ... }:
   let
     certs = import ./common/acme/server/snakeoil-certs.nix;
     serverDomain = certs.domain;
+
+    testCredentials = {
+      password = "Password1_cZPEwpCWvrReripJmAZdmVIZd8HHoHcl";
+    };
   in
   {
     name = "kanidm";
@@ -63,9 +67,10 @@ import ./make-test-python.nix ({ pkgs, ... }:
       ''
         start_all()
         server.wait_for_unit("kanidm.service")
+        client.wait_for_unit("network-online.target")
 
         with subtest("Test HTTP interface"):
-            server.wait_until_succeeds("curl -sf https://${serverDomain} | grep Kanidm")
+            server.wait_until_succeeds("curl -Lsf https://${serverDomain} | grep Kanidm")
 
         with subtest("Test LDAP interface"):
             server.succeed("ldapsearch -H ldaps://${serverDomain}:636 -b '${ldapBaseDN}' -x '(name=test)'")
@@ -73,17 +78,51 @@ import ./make-test-python.nix ({ pkgs, ... }:
         with subtest("Test CLI login"):
             client.succeed("kanidm login -D anonymous")
             client.succeed("kanidm self whoami | grep anonymous@${serverDomain}")
+            client.succeed("kanidm logout")
 
         with subtest("Recover idm_admin account"):
-            # Must stop the server for account recovery or else kanidmd fails with
-            # "unable to lock kanidm exclusive lock at /var/lib/kanidm/kanidm.db.klock".
-            server.succeed("systemctl stop kanidm")
-            server.succeed("su - kanidm -c 'kanidmd recover-account -c ${serverConfigFile} idm_admin 2>&1 | rg -o \'[A-Za-z0-9]{48}\' '")
-            server.succeed("systemctl start kanidm")
+            idm_admin_password = server.succeed("su - kanidm -c 'kanidmd recover-account -c ${serverConfigFile} idm_admin 2>&1 | rg -o \'[A-Za-z0-9]{48}\' '").strip().removeprefix("'").removesuffix("'")
 
         with subtest("Test unixd connection"):
             client.wait_for_unit("kanidm-unixd.service")
-            # TODO: client.wait_for_file("/run/kanidm-unixd/sock")
+            client.wait_for_file("/run/kanidm-unixd/sock")
             client.wait_until_succeeds("kanidm-unix status | grep working!")
+
+        with subtest("Test user creation"):
+            client.wait_for_unit("getty@tty1.service")
+            client.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
+            client.wait_until_tty_matches("1", "login: ")
+            client.send_chars("root\n")
+            client.send_chars("kanidm login -D idm_admin\n")
+            client.wait_until_tty_matches("1", "Enter password: ")
+            client.send_chars(f"{idm_admin_password}\n")
+            client.wait_until_tty_matches("1", "Login Success for idm_admin")
+            client.succeed("kanidm person create testuser TestUser")
+            client.succeed("kanidm person posix set --shell \"$SHELL\" testuser")
+            client.send_chars("kanidm person posix set-password testuser\n")
+            client.wait_until_tty_matches("1", "Enter new")
+            client.send_chars("${testCredentials.password}\n")
+            client.wait_until_tty_matches("1", "Retype")
+            client.send_chars("${testCredentials.password}\n")
+            output = client.succeed("getent passwd testuser")
+            assert "TestUser" in output
+            client.succeed("kanidm group create shell")
+            client.succeed("kanidm group posix set shell")
+            client.succeed("kanidm group add-members shell testuser")
+
+        with subtest("Test user login"):
+            client.send_key("alt-f2")
+            client.wait_until_succeeds("[ $(fgconsole) = 2 ]")
+            client.wait_for_unit("getty@tty2.service")
+            client.wait_until_succeeds("pgrep -f 'agetty.*tty2'")
+            client.wait_until_tty_matches("2", "login: ")
+            client.send_chars("testuser\n")
+            client.wait_until_tty_matches("2", "login: testuser")
+            client.wait_until_succeeds("pgrep login")
+            client.wait_until_tty_matches("2", "Password: ")
+            client.send_chars("${testCredentials.password}\n")
+            client.wait_until_succeeds("systemctl is-active user@$(id -u testuser).service")
+            client.send_chars("touch done\n")
+            client.wait_for_file("/home/testuser@${serverDomain}/done")
       '';
   })
diff --git a/nixpkgs/nixos/tests/kernel-generic.nix b/nixpkgs/nixos/tests/kernel-generic.nix
index 3e74554de339..e4a8e06df1ef 100644
--- a/nixpkgs/nixos/tests/kernel-generic.nix
+++ b/nixpkgs/nixos/tests/kernel-generic.nix
@@ -9,7 +9,7 @@ let
   testsForLinuxPackages = linuxPackages: (import ./make-test-python.nix ({ pkgs, ... }: {
     name = "kernel-${linuxPackages.kernel.version}";
     meta = with pkgs.lib.maintainers; {
-      maintainers = [ nequissimus atemu ];
+      maintainers = [ nequissimus atemu ma27 ];
     };
 
     nodes.machine = { ... }:
@@ -31,6 +31,12 @@ let
       linux_5_10_hardened
       linux_5_15_hardened
       linux_6_1_hardened
+      linux_6_4_hardened
+      linux_rt_5_4
+      linux_rt_5_10
+      linux_rt_5_15
+      linux_rt_6_1
+      linux_libre
 
       linux_testing;
   };
diff --git a/nixpkgs/nixos/tests/keter.nix b/nixpkgs/nixos/tests/keter.nix
index 0bfb96e1c324..1cc2ffbde0a0 100644
--- a/nixpkgs/nixos/tests/keter.nix
+++ b/nixpkgs/nixos/tests/keter.nix
@@ -1,42 +1,43 @@
 import ./make-test-python.nix ({ pkgs, ... }:
-let
-  port = 81;
-in
-{
-  name = "keter";
-  meta = with pkgs.lib.maintainers; {
-    maintainers = [ jappie ];
-  };
+  let
+    port = 81;
+  in
+  {
+    name = "keter";
+    meta = with pkgs.lib.maintainers; {
+      maintainers = [ jappie ];
+    };
 
 
-  nodes.machine = { config, pkgs, ... }: {
-    services.keter = {
-      enable = true;
+    nodes.machine = { config, pkgs, ... }: {
+      services.keter = {
+        enable = true;
 
-      globalKeterConfig = {
-        listeners = [{
-          host = "*4";
-          inherit port;
-        }];
-      };
-      bundle = {
-        appName = "test-bundle";
-        domain = "localhost";
-        executable = pkgs.writeShellScript "run" ''
-          ${pkgs.python3}/bin/python -m http.server $PORT
-        '';
+        globalKeterConfig = {
+          cli-port = 123; # just adding this to test the freeform
+          listeners = [{
+            host = "*4";
+            inherit port;
+          }];
+        };
+        bundle = {
+          appName = "test-bundle";
+          domain = "localhost";
+          executable = pkgs.writeShellScript "run" ''
+            ${pkgs.python3}/bin/python -m http.server $PORT
+          '';
+        };
       };
     };
-  };
 
-  testScript =
-    ''
-      machine.wait_for_unit("keter.service")
+    testScript =
+      ''
+        machine.wait_for_unit("keter.service")
 
-      machine.wait_for_open_port(${toString port})
-      machine.wait_for_console_text("Activating app test-bundle with hosts: localhost")
+        machine.wait_for_open_port(${toString port})
+        machine.wait_for_console_text("Activating app test-bundle with hosts: localhost")
 
 
-      machine.succeed("curl --fail http://localhost:${toString port}/")
-    '';
-})
+        machine.succeed("curl --fail http://localhost:${toString port}/")
+      '';
+  })
diff --git a/nixpkgs/nixos/tests/kexec.nix b/nixpkgs/nixos/tests/kexec.nix
index 3f5a6f521af0..4d1be497b8ba 100644
--- a/nixpkgs/nixos/tests/kexec.nix
+++ b/nixpkgs/nixos/tests/kexec.nix
@@ -8,10 +8,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     node1 = { ... }: {
       virtualisation.vlans = [ ];
       virtualisation.memorySize = 4 * 1024;
-      virtualisation.useBootLoader = true;
-      virtualisation.useEFIBoot = true;
-      boot.loader.systemd-boot.enable = true;
-      boot.loader.efi.canTouchEfiVariables = true;
     };
 
     node2 = { modulesPath, ... }: {
@@ -19,6 +15,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
       environment.systemPackages = [ pkgs.hello ];
       imports = [
         "${modulesPath}/installer/netboot/netboot-minimal.nix"
+        "${modulesPath}/testing/test-instrumentation.nix"
+        "${modulesPath}/profiles/qemu-guest.nix"
       ];
     };
   };
@@ -39,7 +37,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     # Kexec node1 to the toplevel of node2 via the kexec-boot script
     node1.succeed('touch /run/foo')
     node1.fail('hello')
-    node1.execute('${nodes.node2.config.system.build.kexecTree}/kexec-boot', check_return=False)
+    node1.execute('${nodes.node2.system.build.kexecTree}/kexec-boot', check_output=False)
+    node1.connected = False
+    node1.connect()
+    node1.wait_for_unit("multi-user.target")
     node1.succeed('! test -e /run/foo')
     node1.succeed('hello')
     node1.succeed('[ "$(hostname)" = "node2" ]')
diff --git a/nixpkgs/nixos/tests/keyd.nix b/nixpkgs/nixos/tests/keyd.nix
index d492cc194895..1ee08b4101f7 100644
--- a/nixpkgs/nixos/tests/keyd.nix
+++ b/nixpkgs/nixos/tests/keyd.nix
@@ -32,7 +32,7 @@ let
     nodes.machine = {
       services.keyd = {
         enable = true;
-        inherit settings;
+        keyboards.default = { inherit settings; };
       };
     };
 
diff --git a/nixpkgs/nixos/tests/keymap.nix b/nixpkgs/nixos/tests/keymap.nix
index 0bde21093b0a..cc45824667ed 100644
--- a/nixpkgs/nixos/tests/keymap.nix
+++ b/nixpkgs/nixos/tests/keymap.nix
@@ -29,10 +29,10 @@ let
   mkKeyboardTest = layout: { extraConfig ? {}, tests }: with pkgs.lib; makeTest {
     name = "keymap-${layout}";
 
-    machine.console.keyMap = mkOverride 900 layout;
-    machine.services.xserver.desktopManager.xterm.enable = false;
-    machine.services.xserver.layout = mkOverride 900 layout;
-    machine.imports = [ ./common/x11.nix extraConfig ];
+    nodes.machine.console.keyMap = mkOverride 900 layout;
+    nodes.machine.services.xserver.desktopManager.xterm.enable = false;
+    nodes.machine.services.xserver.layout = mkOverride 900 layout;
+    nodes.machine.imports = [ ./common/x11.nix extraConfig ];
 
     testScript = ''
       import json
@@ -201,4 +201,33 @@ in pkgs.lib.mapAttrs mkKeyboardTest {
     extraConfig.console.keyMap = "de";
     extraConfig.services.xserver.layout = "de";
   };
+
+  custom = {
+    tests = {
+      us.qwerty = [ "a" "b" "g" "d" "z" "shift-2" "shift-3" ];
+      us.expect = [ "a" "b" "g" "d" "z" "@" "#" ];
+      greek.qwerty = map (x: "alt_r-${x}")
+                     [ "a" "b" "g" "d" "z" ];
+      greek.expect = [ "α" "β" "γ" "δ" "ζ" ];
+    };
+
+    extraConfig.console.useXkbConfig = true;
+    extraConfig.services.xserver.layout = "us-greek";
+    extraConfig.services.xserver.extraLayouts.us-greek =
+      { description = "US layout with alt-gr greek";
+        languages   = [ "eng" ];
+        symbolsFile = pkgs.writeText "us-greek" ''
+          xkb_symbols "us-greek"
+          {
+            include "us(basic)"
+            include "level3(ralt_switch)"
+            key <LatA> { [ a, A, Greek_alpha ] };
+            key <LatB> { [ b, B, Greek_beta  ] };
+            key <LatG> { [ g, G, Greek_gamma ] };
+            key <LatD> { [ d, D, Greek_delta ] };
+            key <LatZ> { [ z, Z, Greek_zeta  ] };
+          };
+        '';
+      };
+  };
 }
diff --git a/nixpkgs/nixos/tests/lemmy.nix b/nixpkgs/nixos/tests/lemmy.nix
index fb64daa80e64..de2c4938fe23 100644
--- a/nixpkgs/nixos/tests/lemmy.nix
+++ b/nixpkgs/nixos/tests/lemmy.nix
@@ -22,14 +22,16 @@ in
           # Without setup, the /feeds/* and /nodeinfo/* API endpoints won't return 200
           setup = {
             admin_username = "mightyiam";
-            admin_password = "ThisIsWhatIUseEverywhereTryIt";
             site_name = "Lemmy FTW";
             admin_email = "mightyiam@example.com";
           };
         };
+        adminPasswordFile = /etc/lemmy-admin-password.txt;
         caddy.enable = true;
       };
 
+      environment.etc."lemmy-admin-password.txt".text = "ThisIsWhatIUseEverywhereTryIt";
+
       networking.firewall.allowedTCPPorts = [ 80 ];
 
       # pict-rs seems to need more than 1025114112 bytes
@@ -40,8 +42,14 @@ in
   testScript = ''
     server = ${lemmyNodeName}
 
-    with subtest("the backend starts and responds"):
+    with subtest("the merged config is secure"):
         server.wait_for_unit("lemmy.service")
+        config_permissions = server.succeed("stat --format %A /run/lemmy/config.hjson").rstrip()
+        assert config_permissions == "-rw-------", f"merged config permissions {config_permissions} are insecure"
+        directory_permissions = server.succeed("stat --format %A /run/lemmy").rstrip()
+        assert directory_permissions[5] == directory_permissions[8] == "-", "merged config can be replaced"
+
+    with subtest("the backend starts and responds"):
         server.wait_for_open_port(${toString backendPort})
         server.succeed("curl --fail localhost:${toString backendPort}/api/v3/site")
 
diff --git a/nixpkgs/nixos/tests/luks.nix b/nixpkgs/nixos/tests/luks.nix
index d5ac550a3c57..da1d0c63b95d 100644
--- a/nixpkgs/nixos/tests/luks.nix
+++ b/nixpkgs/nixos/tests/luks.nix
@@ -2,6 +2,8 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   name = "luks";
 
   nodes.machine = { pkgs, ... }: {
+    imports = [ ./common/auto-format-root-device.nix ];
+
     # Use systemd-boot
     virtualisation = {
       emptyDiskImages = [ 512 512 ];
diff --git a/nixpkgs/nixos/tests/lxd-ui.nix b/nixpkgs/nixos/tests/lxd-ui.nix
new file mode 100644
index 000000000000..19eaa226c0bf
--- /dev/null
+++ b/nixpkgs/nixos/tests/lxd-ui.nix
@@ -0,0 +1,35 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "lxd-ui";
+
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ jnsgruk ];
+  };
+
+  nodes.machine = { lib, ... }: {
+    virtualisation = {
+      lxd.enable = true;
+      lxd.ui.enable = true;
+    };
+
+    environment.systemPackages = [ pkgs.curl ];
+  };
+
+  testScript = ''
+    machine.wait_for_unit("sockets.target")
+    machine.wait_for_unit("lxd.service")
+    machine.wait_for_file("/var/lib/lxd/unix.socket")
+
+    # Wait for lxd to settle
+    machine.succeed("lxd waitready")
+
+    # Configure LXC listen address
+    machine.succeed("lxc config set core.https_address :8443")
+    machine.succeed("systemctl restart lxd")
+
+    # Check that the LXD_UI environment variable is populated in the systemd unit
+    machine.succeed("cat /etc/systemd/system/lxd.service | grep 'LXD_UI'")
+
+    # Ensure the endpoint returns an HTML page with 'LXD UI' in the title
+    machine.succeed("curl -kLs https://localhost:8443/ui | grep '<title>LXD UI</title>'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/maestral.nix b/nixpkgs/nixos/tests/maestral.nix
index ba2e0b2f3baa..67a265926187 100644
--- a/nixpkgs/nixos/tests/maestral.nix
+++ b/nixpkgs/nixos/tests/maestral.nix
@@ -52,7 +52,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
   testScript = { nodes, ... }:
     let
-      user = nodes.cli.config.users.users.alice;
+      user = nodes.cli.users.users.alice;
     in
     ''
       start_all()
@@ -65,7 +65,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
       with subtest("GUI"):
         gui.wait_for_x()
-        gui.succeed("xauth merge ${user.home}/.Xauthority")
+        gui.wait_for_file("/tmp/xauth_*")
+        gui.succeed("xauth merge /tmp/xauth_*")
         gui.wait_for_window("^Desktop ")
         gui.wait_for_unit("maestral.service", "${user.name}")
     '';
diff --git a/nixpkgs/nixos/tests/matomo.nix b/nixpkgs/nixos/tests/matomo.nix
index 0e09ad295f95..7dbef63136aa 100644
--- a/nixpkgs/nixos/tests/matomo.nix
+++ b/nixpkgs/nixos/tests/matomo.nix
@@ -41,10 +41,10 @@ let
 in {
   matomo = matomoTest pkgs.matomo // {
     name = "matomo";
-    meta.maintainers = with maintainers; [ florianjacob kiwi mmilata ];
+    meta.maintainers = with maintainers; [ florianjacob kiwi mmilata twey boozedog ];
   };
   matomo-beta = matomoTest pkgs.matomo-beta // {
     name = "matomo-beta";
-    meta.maintainers = with maintainers; [ florianjacob kiwi mmilata ];
+    meta.maintainers = with maintainers; [ florianjacob kiwi mmilata twey boozedog ];
   };
 }
diff --git a/nixpkgs/nixos/tests/miniflux.nix b/nixpkgs/nixos/tests/miniflux.nix
index be3e7abb6abd..a3af53db0e7a 100644
--- a/nixpkgs/nixos/tests/miniflux.nix
+++ b/nixpkgs/nixos/tests/miniflux.nix
@@ -25,6 +25,7 @@ in
     default =
       { ... }:
       {
+        security.apparmor.enable = true;
         services.miniflux = {
           enable = true;
           inherit adminCredentialsFile;
@@ -34,6 +35,7 @@ in
     withoutSudo =
       { ... }:
       {
+        security.apparmor.enable = true;
         services.miniflux = {
           enable = true;
           inherit adminCredentialsFile;
@@ -44,6 +46,7 @@ in
     customized =
       { ... }:
       {
+        security.apparmor.enable = true;
         services.miniflux = {
           enable = true;
           config = {
@@ -63,6 +66,7 @@ in
     default.succeed(
         "curl 'http://localhost:${toString defaultPort}/v1/me' -u '${defaultUsername}:${defaultPassword}' -H Content-Type:application/json | grep '\"is_admin\":true'"
     )
+    default.fail('journalctl -b --no-pager --grep "^audit: .*apparmor=\\"DENIED\\""')
 
     withoutSudo.wait_for_unit("miniflux.service")
     withoutSudo.wait_for_open_port(${toString defaultPort})
@@ -70,6 +74,7 @@ in
     withoutSudo.succeed(
         "curl 'http://localhost:${toString defaultPort}/v1/me' -u '${defaultUsername}:${defaultPassword}' -H Content-Type:application/json | grep '\"is_admin\":true'"
     )
+    withoutSudo.fail('journalctl -b --no-pager --grep "^audit: .*apparmor=\\"DENIED\\""')
 
     customized.wait_for_unit("miniflux.service")
     customized.wait_for_open_port(${toString port})
@@ -77,5 +82,6 @@ in
     customized.succeed(
         "curl 'http://localhost:${toString port}/v1/me' -u '${username}:${password}' -H Content-Type:application/json | grep '\"is_admin\":true'"
     )
+    customized.fail('journalctl -b --no-pager --grep "^audit: .*apparmor=\\"DENIED\\""')
   '';
 })
diff --git a/nixpkgs/nixos/tests/miriway.nix b/nixpkgs/nixos/tests/miriway.nix
index 9000e9278197..f12c4d5ecc41 100644
--- a/nixpkgs/nixos/tests/miriway.nix
+++ b/nixpkgs/nixos/tests/miriway.nix
@@ -83,7 +83,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
       };
     };
 
-    fonts.fonts = [ pkgs.inconsolata ];
+    fonts.packages = [ pkgs.inconsolata ];
   };
 
   enableOCR = true;
diff --git a/nixpkgs/nixos/tests/mumble.nix b/nixpkgs/nixos/tests/mumble.nix
index 2b5cc20163bc..8eee454721a1 100644
--- a/nixpkgs/nixos/tests/mumble.nix
+++ b/nixpkgs/nixos/tests/mumble.nix
@@ -20,6 +20,7 @@ in
 
   nodes = {
     server = { config, ... }: {
+      security.apparmor.enable = true;
       services.murmur.enable = true;
       services.murmur.registerName = "NixOS tests";
       services.murmur.password = "$MURMURD_PASSWORD";
@@ -81,5 +82,8 @@ in
     server.sleep(5)  # wait to get screenshot
     client1.screenshot("screen1")
     client2.screenshot("screen2")
+
+    # check if apparmor denied anything
+    server.fail('journalctl -b --no-pager --grep "^audit: .*apparmor=\\"DENIED\\""')
   '';
 })
diff --git a/nixpkgs/nixos/tests/n8n.nix b/nixpkgs/nixos/tests/n8n.nix
index 771296bf37a5..0a12192d5c71 100644
--- a/nixpkgs/nixos/tests/n8n.nix
+++ b/nixpkgs/nixos/tests/n8n.nix
@@ -1,6 +1,7 @@
 import ./make-test-python.nix ({ lib, ... }:
 let
   port = 5678;
+  webhookUrl = "http://example.com";
 in
 {
   name = "n8n";
@@ -11,6 +12,7 @@ in
     {
       services.n8n = {
         enable = true;
+        webhookUrl = webhookUrl;
       };
     };
 
@@ -18,5 +20,6 @@ in
     machine.wait_for_unit("n8n.service")
     machine.wait_for_console_text("Editor is now accessible via")
     machine.succeed("curl --fail -vvv http://localhost:${toString port}/")
+    machine.succeed("grep -qF ${webhookUrl} /etc/systemd/system/n8n.service")
   '';
 })
diff --git a/nixpkgs/nixos/tests/networking.nix b/nixpkgs/nixos/tests/networking.nix
index 05fed0f4b473..46fc715d0891 100644
--- a/nixpkgs/nixos/tests/networking.nix
+++ b/nixpkgs/nixos/tests/networking.nix
@@ -29,23 +29,49 @@ let
             ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ];
           })));
       };
-      services.dhcpd4 = {
-        enable = true;
-        interfaces = map (n: "eth${toString n}") vlanIfs;
-        extraConfig = flip concatMapStrings vlanIfs (n: ''
-          subnet 192.168.${toString n}.0 netmask 255.255.255.0 {
-            option routers 192.168.${toString n}.1;
-            range 192.168.${toString n}.3 192.168.${toString n}.254;
-          }
-        '')
-        ;
-        machines = flip map vlanIfs (vlan:
-          {
-            hostName = "client${toString vlan}";
-            ethernetAddress = qemu-common.qemuNicMac vlan 1;
-            ipAddress = "192.168.${toString vlan}.2";
-          }
-        );
+      services.kea = {
+        dhcp4 = {
+          enable = true;
+          settings = {
+            interfaces-config = {
+              interfaces = map (n: "eth${toString n}") vlanIfs;
+              dhcp-socket-type = "raw";
+              service-sockets-require-all = true;
+              service-sockets-max-retries = 5;
+              service-sockets-retry-wait-time = 2500;
+            };
+            subnet4 = map (n: {
+              id = n;
+              subnet = "192.168.${toString n}.0/24";
+              pools = [{ pool = "192.168.${toString n}.3 - 192.168.${toString n}.254"; }];
+              option-data = [{ name = "routers"; data = "192.168.${toString n}.1"; }];
+
+              reservations = [{
+                hw-address = qemu-common.qemuNicMac n 1;
+                hostname = "client${toString n}";
+                ip-address = "192.168.${toString n}.2";
+              }];
+            }) vlanIfs;
+          };
+        };
+        dhcp6 = {
+          enable = true;
+          settings = {
+            interfaces-config = {
+              interfaces = map (n: "eth${toString n}") vlanIfs;
+              service-sockets-require-all = true;
+              service-sockets-max-retries = 5;
+              service-sockets-retry-wait-time = 2500;
+            };
+
+            subnet6 = map (n: {
+              id = n;
+              subnet = "fd00:1234:5678:${toString n}::/64";
+              interface = "eth${toString n}";
+              pools = [{ pool = "fd00:1234:5678:${toString n}::2-fd00:1234:5678:${toString n}::2"; }];
+            }) vlanIfs;
+          };
+        };
       };
       services.radvd = {
         enable = true;
@@ -61,17 +87,6 @@ let
           };
         '');
       };
-      services.dhcpd6 = {
-        enable = true;
-        interfaces = map (n: "eth${toString n}") vlanIfs;
-        extraConfig = ''
-          authoritative;
-        '' + flip concatMapStrings vlanIfs (n: ''
-          subnet6 fd00:1234:5678:${toString n}::/64 {
-            range6 fd00:1234:5678:${toString n}::2 fd00:1234:5678:${toString n}::2;
-          }
-        '');
-      };
     };
 
   testCases = {
@@ -117,8 +132,9 @@ let
           client.wait_for_unit("network.target")
           router.wait_for_unit("network-online.target")
 
-          with subtest("Make sure dhcpcd is not started"):
-              client.fail("systemctl status dhcpcd.service")
+          with subtest("Make sure DHCP server is not started"):
+              client.fail("systemctl status kea-dhcp4-server.service")
+              client.fail("systemctl status kea-dhcp6-server.service")
 
           with subtest("Test vlan 1"):
               client.wait_until_succeeds("ping -c 1 192.168.1.1")
@@ -1035,7 +1051,7 @@ let
       testScript = ''
         machine.succeed("udevadm settle")
         print(machine.succeed("ip link show dev enCustom"))
-        machine.wait_until_succeeds("ip link show dev enCustom | grep -q '52:54:00:12:0b:01")
+        machine.wait_until_succeeds("ip link show dev enCustom | grep -q 52:54:00:12:0b:01")
       '';
     };
   };
diff --git a/nixpkgs/nixos/tests/nextcloud/basic.nix b/nixpkgs/nixos/tests/nextcloud/basic.nix
index e17f701c54b7..db5cee9f6584 100644
--- a/nixpkgs/nixos/tests/nextcloud/basic.nix
+++ b/nixpkgs/nixos/tests/nextcloud/basic.nix
@@ -14,12 +14,12 @@ in {
     client = { ... }: {
       services.davfs2.enable = true;
       system.activationScripts.davfs2-secrets = ''
-        echo "http://nextcloud/remote.php/webdav/ ${adminuser} ${adminpass}" > /tmp/davfs2-secrets
+        echo "http://nextcloud/remote.php/dav/files/${adminuser} ${adminuser} ${adminpass}" > /tmp/davfs2-secrets
         chmod 600 /tmp/davfs2-secrets
       '';
       virtualisation.fileSystems = {
         "/mnt/dav" = {
-          device = "http://nextcloud/remote.php/webdav/";
+          device = "http://nextcloud/remote.php/dav/files/${adminuser}";
           fsType = "davfs";
           options = let
             davfs2Conf = (pkgs.writeText "davfs2.conf" "secrets /tmp/davfs2-secrets");
@@ -70,7 +70,7 @@ in {
     withRcloneEnv = pkgs.writeScript "with-rclone-env" ''
       #!${pkgs.runtimeShell}
       export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
-      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
+      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/dav/files/${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
       export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
diff --git a/nixpkgs/nixos/tests/nextcloud/default.nix b/nixpkgs/nixos/tests/nextcloud/default.nix
index 78fe026b4a84..b9f35b398cfe 100644
--- a/nixpkgs/nixos/tests/nextcloud/default.nix
+++ b/nixpkgs/nixos/tests/nextcloud/default.nix
@@ -26,4 +26,4 @@ foldl
     };
   })
 { }
-  [ 25 26 ]
+  [ 25 26 27 ]
diff --git a/nixpkgs/nixos/tests/nextcloud/openssl-sse.nix b/nixpkgs/nixos/tests/nextcloud/openssl-sse.nix
index 659a4311cddd..92beb869eb03 100644
--- a/nixpkgs/nixos/tests/nextcloud/openssl-sse.nix
+++ b/nixpkgs/nixos/tests/nextcloud/openssl-sse.nix
@@ -33,7 +33,7 @@ in {
     withRcloneEnv = host: pkgs.writeScript "with-rclone-env" ''
       #!${pkgs.runtimeShell}
       export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
-      export RCLONE_CONFIG_NEXTCLOUD_URL="http://${host}/remote.php/webdav/"
+      export RCLONE_CONFIG_NEXTCLOUD_URL="http://${host}/remote.php/dav/files/${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
       export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
diff --git a/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
index ce0019e9da4a..e638f2e5b861 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
@@ -1,5 +1,6 @@
-import ../make-test-python.nix ({ pkgs, ...}: let
-  username = "custom_admin_username";
+args@{ nextcloudVersion ? 27, ... }:
+(import ../make-test-python.nix ({ pkgs, ...}: let
+  adminuser = "custom_admin_username";
   # This will be used both for redis and postgresql
   pass = "hunter2";
   # Don't do this at home, use a file outside of the nix store instead
@@ -9,7 +10,7 @@ import ../make-test-python.nix ({ pkgs, ...}: let
 in {
   name = "nextcloud-with-declarative-redis";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ eqyiel ];
+    maintainers = [ eqyiel ma27 ];
   };
 
   nodes = {
@@ -22,6 +23,7 @@ in {
       services.nextcloud = {
         enable = true;
         hostName = "nextcloud";
+        package = pkgs.${"nextcloud" + (toString nextcloudVersion)};
         caching = {
           apcu = false;
           redis = true;
@@ -32,28 +34,26 @@ in {
         config = {
           dbtype = "pgsql";
           dbname = "nextcloud";
-          dbuser = username;
+          dbuser = adminuser;
           dbpassFile = passFile;
-          adminuser = username;
+          adminuser = adminuser;
           adminpassFile = passFile;
         };
         secretFile = "/etc/nextcloud-secrets.json";
 
         extraOptions.redis = {
-          host = "/run/redis/redis.sock";
-          port = 0;
           dbindex = 0;
           timeout = 1.5;
           # password handled via secretfile below
         };
-        extraOptions.memcache = {
-          local = "\OC\Memcache\Redis";
-          locking = "\OC\Memcache\Redis";
-        };
+        configureRedis = true;
       };
 
-      services.redis.servers."nextcloud".enable = true;
-      services.redis.servers."nextcloud".port = 6379;
+      services.redis.servers."nextcloud" = {
+        enable = true;
+        port = 6379;
+        requirePass = "secret";
+      };
 
       systemd.services.nextcloud-setup= {
         requires = ["postgresql.service"];
@@ -66,15 +66,15 @@ in {
       systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
         password=$(cat ${passFile})
         ${config.services.postgresql.package}/bin/psql <<EOF
-          CREATE ROLE ${username} WITH LOGIN PASSWORD '$password' CREATEDB;
+          CREATE ROLE ${adminuser} WITH LOGIN PASSWORD '$password' CREATEDB;
           CREATE DATABASE nextcloud;
-          GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ${username};
+          GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ${adminuser};
         EOF
       '';
 
       # This file is meant to contain secret options which should
       # not go into the nix store. Here it is just used to set the
-      # databyse type to postgres.
+      # redis password.
       environment.etc."nextcloud-secrets.json".text = ''
         {
           "redis": {
@@ -89,9 +89,9 @@ in {
     withRcloneEnv = pkgs.writeScript "with-rclone-env" ''
       #!${pkgs.runtimeShell}
       export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
-      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
+      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/dav/files/${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
-      export RCLONE_CONFIG_NEXTCLOUD_USER="${username}"
+      export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${pass})"
       "''${@}"
     '';
@@ -117,6 +117,6 @@ in {
     )
 
     # redis cache should not be empty
-    nextcloud.fail("redis-cli KEYS * | grep -q 'empty array'")
+    nextcloud.fail('test "[]" = "$(redis-cli --json KEYS "*")"')
   '';
-})
+})) args
diff --git a/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix b/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
index e57aabfaf86b..035a7fdcb0c8 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
@@ -49,7 +49,7 @@ in {
     withRcloneEnv = pkgs.writeScript "with-rclone-env" ''
       #!${pkgs.runtimeShell}
       export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
-      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
+      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/dav/files/${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
       export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
diff --git a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
index 1cbb13104287..586bf50fd939 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-postgresql-and-redis.nix
@@ -60,7 +60,7 @@ in {
     withRcloneEnv = pkgs.writeScript "with-rclone-env" ''
       #!${pkgs.runtimeShell}
       export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
-      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
+      export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/dav/files/${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
       export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
       export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
@@ -89,5 +89,8 @@ in {
         "${withRcloneEnv} ${diffSharedFile}"
     )
     nextcloud.wait_until_succeeds("journalctl -u nextcloud-notify_push | grep -q \"Sending ping to ${adminuser}\"")
+
+    # redis cache should not be empty
+    nextcloud.fail('test "[]" = "$(redis-cli --json KEYS "*")"')
   '';
 })) args
diff --git a/nixpkgs/nixos/tests/nginx-proxyprotocol/default.nix b/nixpkgs/nixos/tests/nginx-proxyprotocol/default.nix
index 9ef5d01cd65b..2ff7debfcbe2 100644
--- a/nixpkgs/nixos/tests/nginx-proxyprotocol/default.nix
+++ b/nixpkgs/nixos/tests/nginx-proxyprotocol/default.nix
@@ -4,6 +4,10 @@ in
 import ../make-test-python.nix ({ pkgs, ... }: {
   name = "nginx-proxyprotocol";
 
+  meta = {
+    maintainers = with pkgs.lib.maintainers; [ raitobezarius ];
+  };
+
   nodes = {
     webserver = { pkgs, lib, ... }: {
       environment.systemPackages = [ pkgs.netcat ];
diff --git a/nixpkgs/nixos/tests/nginx-status-page.nix b/nixpkgs/nixos/tests/nginx-status-page.nix
new file mode 100644
index 000000000000..ff2c0940379c
--- /dev/null
+++ b/nixpkgs/nixos/tests/nginx-status-page.nix
@@ -0,0 +1,72 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "nginx-status-page";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ h7x4 ];
+  };
+
+  nodes = {
+    webserver = { ... }: {
+      virtualisation.vlans = [ 1 ];
+
+      networking = {
+        useNetworkd = true;
+        useDHCP = false;
+        firewall.enable = false;
+      };
+
+      systemd.network.networks."01-eth1" = {
+        name = "eth1";
+        networkConfig.Address = "10.0.0.1/24";
+      };
+
+      services.nginx = {
+        enable = true;
+        statusPage = true;
+        virtualHosts."localhost".locations."/index.html".return = "200 'hello world\n'";
+      };
+
+      environment.systemPackages = with pkgs; [ curl ];
+    };
+
+    client = { ... }: {
+      virtualisation.vlans = [ 1 ];
+
+      networking = {
+        useNetworkd = true;
+        useDHCP = false;
+        firewall.enable = false;
+      };
+
+      systemd.network.networks."01-eth1" = {
+        name = "eth1";
+        networkConfig.Address = "10.0.0.2/24";
+      };
+
+      environment.systemPackages = with pkgs; [ curl ];
+    };
+  };
+
+  testScript = { nodes, ... }: ''
+    start_all()
+
+    webserver.wait_for_unit("nginx")
+    webserver.wait_for_open_port(80)
+
+    def expect_http_code(node, code, url):
+        http_code = node.succeed(f"curl -w '%{{http_code}}' '{url}'")
+        assert http_code.split("\n")[-1].strip() == code, \
+          f"expected {code} but got following response:\n{http_code}"
+
+    with subtest("localhost can access status page"):
+        expect_http_code(webserver, "200", "http://localhost/nginx_status")
+
+    with subtest("localhost can access other page"):
+        expect_http_code(webserver, "200", "http://localhost/index.html")
+
+    with subtest("client can not access status page"):
+        expect_http_code(client, "403", "http://10.0.0.1/nginx_status")
+
+    with subtest("client can access other page"):
+        expect_http_code(client, "200", "http://10.0.0.1/index.html")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/nixos-test-driver/busybox.nix b/nixpkgs/nixos/tests/nixos-test-driver/busybox.nix
new file mode 100644
index 000000000000..426f4494436e
--- /dev/null
+++ b/nixpkgs/nixos/tests/nixos-test-driver/busybox.nix
@@ -0,0 +1,16 @@
+{
+  name = "Test that basic tests work when busybox is installed";
+
+  nodes = {
+    machine = ({ pkgs, ... }: {
+      environment.systemPackages = [
+        pkgs.busybox
+      ];
+    });
+  };
+
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("multi-user.target")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/nixos-test-driver/lib-extend.nix b/nixpkgs/nixos/tests/nixos-test-driver/lib-extend.nix
new file mode 100644
index 000000000000..4fb7cf494aed
--- /dev/null
+++ b/nixpkgs/nixos/tests/nixos-test-driver/lib-extend.nix
@@ -0,0 +1,31 @@
+{ pkgs, ... }:
+
+let
+  patchedPkgs = pkgs.extend (new: old: {
+    lib = old.lib.extend (self: super: {
+      sorry_dave = "sorry dave";
+    });
+  });
+
+  testBody = {
+    name = "demo lib overlay";
+
+    nodes = {
+      machine = { lib, ... }: {
+        environment.etc."got-lib-overlay".text = lib.sorry_dave;
+      };
+    };
+
+    # We don't need to run an actual test. Instead we build the `machine` configuration
+    # and call it a day, because that already proves that `lib` is wired up correctly.
+    # See the attrset returned at the bottom of this file.
+    testScript = "";
+  };
+
+  inherit (patchedPkgs.testers) nixosTest runNixOSTest;
+  evaluationNixosTest = nixosTest testBody;
+  evaluationRunNixOSTest = runNixOSTest testBody;
+in {
+  nixosTest = evaluationNixosTest.driver.nodes.machine.system.build.toplevel;
+  runNixOSTest = evaluationRunNixOSTest.driver.nodes.machine.system.build.toplevel;
+}
diff --git a/nixpkgs/nixos/tests/non-default-filesystems.nix b/nixpkgs/nixos/tests/non-default-filesystems.nix
index 03cc5bf709a4..08a17107dd2f 100644
--- a/nixpkgs/nixos/tests/non-default-filesystems.nix
+++ b/nixpkgs/nixos/tests/non-default-filesystems.nix
@@ -6,6 +6,31 @@
 with import ../lib/testing-python.nix { inherit system pkgs; };
 with pkgs.lib;
 {
+  bind = makeTest {
+    name = "non-default-filesystem-bind";
+
+    nodes.machine = { ... }: {
+      virtualisation.writableStore = false;
+
+      virtualisation.fileSystems."/test-bind-dir/bind" = {
+        device = "/";
+        neededForBoot = true;
+        options = [ "bind" ];
+      };
+
+      virtualisation.fileSystems."/test-bind-file/bind" = {
+        depends = [ "/nix/store" ];
+        device = builtins.toFile "empty" "";
+        neededForBoot = true;
+        options = [ "bind" ];
+      };
+    };
+
+    testScript = ''
+      machine.wait_for_unit("multi-user.target")
+    '';
+  };
+
   btrfs = makeTest
     {
       name = "non-default-filesystems-btrfs";
@@ -69,6 +94,8 @@ with pkgs.lib;
     makeTest {
       name = "non-default-filesystems-erofs";
 
+      meta.maintainers = with maintainers; [ nikstur ];
+
       nodes.machine = _: {
         virtualisation.qemu.drives = [{
           name = "non-default-filesystem";
@@ -103,4 +130,43 @@ with pkgs.lib;
         assert "erofs" in file_contents
       '';
     };
+
+  squashfs =
+    let
+      fsImage = "/tmp/non-default-filesystem.img";
+    in
+    makeTest {
+      name = "non-default-filesystems-squashfs";
+
+      meta.maintainers = with maintainers; [ nikstur ];
+
+      nodes.machine = {
+        virtualisation.qemu.drives = [{
+          name = "non-default-filesystem";
+          file = fsImage;
+          deviceExtraOpts.serial = "non-default";
+        }];
+
+        virtualisation.fileSystems."/non-default" = {
+          device = "/dev/disk/by-id/virtio-non-default";
+          fsType = "squashfs";
+          neededForBoot = true;
+        };
+      };
+
+      testScript = ''
+        import subprocess
+
+        with open("filesystem", "w") as f:
+          f.write("squashfs")
+
+        subprocess.run([
+          "${pkgs.squashfsTools}/bin/mksquashfs",
+          "filesystem",
+          "${fsImage}",
+        ])
+
+        assert "squashfs" in machine.succeed("cat /non-default/filesystem")
+      '';
+    };
 }
diff --git a/nixpkgs/nixos/tests/noto-fonts-cjk-qt-default-weight.nix b/nixpkgs/nixos/tests/noto-fonts-cjk-qt-default-weight.nix
index 678013cf3ab9..c2e0cb3adaeb 100644
--- a/nixpkgs/nixos/tests/noto-fonts-cjk-qt-default-weight.nix
+++ b/nixpkgs/nixos/tests/noto-fonts-cjk-qt-default-weight.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   nodes.machine = {
     imports = [ ./common/x11.nix ];
     fonts = {
-      enableDefaultFonts = false;
+      enableDefaultPackages = false;
       fonts = [ pkgs.noto-fonts-cjk-sans ];
     };
   };
diff --git a/nixpkgs/nixos/tests/noto-fonts.nix b/nixpkgs/nixos/tests/noto-fonts.nix
index 0515f16d101c..edbb0db4cb7a 100644
--- a/nixpkgs/nixos/tests/noto-fonts.nix
+++ b/nixpkgs/nixos/tests/noto-fonts.nix
@@ -4,9 +4,9 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
   nodes.machine = {
     imports = [ ./common/x11.nix ];
-    environment.systemPackages = [ pkgs.gnome.gedit ];
+    environment.systemPackages = [ pkgs.gedit ];
     fonts = {
-      enableDefaultFonts = false;
+      enableDefaultPackages = false;
       fonts = with pkgs;[
         noto-fonts
         noto-fonts-cjk-sans
diff --git a/nixpkgs/nixos/tests/opentelemetry-collector.nix b/nixpkgs/nixos/tests/opentelemetry-collector.nix
new file mode 100644
index 000000000000..9a56a22ca47e
--- /dev/null
+++ b/nixpkgs/nixos/tests/opentelemetry-collector.nix
@@ -0,0 +1,76 @@
+import ./make-test-python.nix ({ pkgs, ...} : let
+  port = 4318;
+in {
+  name = "opentelemetry-collector";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ tylerjl ];
+  };
+
+  nodes.machine = { ... }: {
+    networking.firewall.allowedTCPPorts = [ port ];
+    services.opentelemetry-collector = {
+      enable = true;
+      settings = {
+        exporters.logging.verbosity = "detailed";
+        receivers.otlp.protocols.http = {};
+        service = {
+          pipelines.logs = {
+            receivers = [ "otlp" ];
+            exporters = [ "logging" ];
+          };
+        };
+      };
+    };
+    virtualisation.forwardPorts = [{
+      host.port = port;
+      guest.port = port;
+    }];
+  };
+
+  extraPythonPackages = p: [
+    p.requests
+    p.types-requests
+  ];
+
+  # Send a log event through the OTLP pipeline and check for its
+  # presence in the collector logs.
+  testScript = /* python */ ''
+    import requests
+    import time
+
+    from uuid import uuid4
+
+    flag = str(uuid4())
+
+    machine.wait_for_unit("opentelemetry-collector.service")
+    machine.wait_for_open_port(${toString port})
+
+    event = {
+        "resourceLogs": [
+            {
+                "resource": {"attributes": []},
+                "scopeLogs": [
+                    {
+                        "logRecords": [
+                            {
+                                "timeUnixNano": str(time.time_ns()),
+                                "severityNumber": 9,
+                                "severityText": "Info",
+                                "name": "logTest",
+                                "body": {
+                                    "stringValue": flag
+                                },
+                                "attributes": []
+                            },
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
+
+    response = requests.post("http://localhost:${toString port}/v1/logs", json=event)
+    assert response.status_code == 200
+    assert flag in machine.execute("journalctl -u opentelemetry-collector")[-1]
+  '';
+})
diff --git a/nixpkgs/nixos/tests/os-prober.nix b/nixpkgs/nixos/tests/os-prober.nix
index 8f3e2494047c..22e720824c80 100644
--- a/nixpkgs/nixos/tests/os-prober.nix
+++ b/nixpkgs/nixos/tests/os-prober.nix
@@ -8,7 +8,7 @@ let
       ${parted}/bin/parted --script /dev/vda mklabel msdos
       ${parted}/sbin/parted --script /dev/vda -- mkpart primary ext2 1M -1s
       mkdir /mnt
-      ${e2fsprogs}/bin/mkfs.ext4 /dev/vda1
+      ${e2fsprogs}/bin/mkfs.ext4 -O '^metadata_csum_seed' /dev/vda1
       ${util-linux}/bin/mount -t ext4 /dev/vda1 /mnt
 
       if test -e /mnt/.debug; then
@@ -83,6 +83,8 @@ in {
           docbook5
           docbook_xsl_ns
           grub2
+          kbd
+          kbd.dev
           kmod.dev
           libarchive
           libarchive.dev
diff --git a/nixpkgs/nixos/tests/osquery.nix b/nixpkgs/nixos/tests/osquery.nix
new file mode 100644
index 000000000000..9aa9820e50c5
--- /dev/null
+++ b/nixpkgs/nixos/tests/osquery.nix
@@ -0,0 +1,52 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+
+let
+  config_refresh = "10";
+  nullvalue = "NULL";
+  utc = false;
+in
+{
+  name = "osquery";
+  meta.maintainers = with lib.maintainers; [ znewman01 lewo ];
+
+  nodes.machine = { config, pkgs, ... }: {
+    services.osquery = {
+      enable = true;
+
+      settings.options = { inherit nullvalue utc; };
+      flags = {
+        inherit config_refresh;
+        nullvalue = "IGNORED";
+      };
+    };
+  };
+
+  testScript = { nodes, ... }:
+    let
+      cfg = nodes.machine.services.osquery;
+    in
+    ''
+      machine.start()
+      machine.wait_for_unit("osqueryd.service")
+
+      # Stop the osqueryd service so that we can use osqueryi to check information stored in the database.
+      machine.wait_until_succeeds("systemctl stop osqueryd.service")
+
+      # osqueryd was able to query information about the host.
+      machine.succeed("echo 'SELECT address FROM etc_hosts LIMIT 1;' | osqueryi | tee /dev/console | grep -q '127.0.0.1'")
+
+      # osquery binaries respect configuration from the Nix config option.
+      machine.succeed("echo 'SELECT value FROM osquery_flags WHERE name = \"utc\";' | osqueryi | tee /dev/console | grep -q ${boolToString utc}")
+
+      # osquery binaries respect configuration from the Nix flags option.
+      machine.succeed("echo 'SELECT value FROM osquery_flags WHERE name = \"config_refresh\";' | osqueryi | tee /dev/console | grep -q ${config_refresh}")
+
+      # Demonstrate that osquery binaries prefer configuration plugin options over CLI flags.
+      # https://osquery.readthedocs.io/en/latest/deployment/configuration/#options.
+      machine.succeed("echo 'SELECT value FROM osquery_flags WHERE name = \"nullvalue\";' | osqueryi | tee /dev/console | grep -q ${nullvalue}")
+
+      # Module creates directories for default database_path and pidfile flag values.
+      machine.succeed("test -d $(dirname ${cfg.flags.database_path})")
+      machine.succeed("test -d $(dirname ${cfg.flags.pidfile})")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/paperless.nix b/nixpkgs/nixos/tests/paperless.nix
index 7f36de4c29b7..ce6a4d8128df 100644
--- a/nixpkgs/nixos/tests/paperless.nix
+++ b/nixpkgs/nixos/tests/paperless.nix
@@ -30,20 +30,27 @@ import ./make-test-python.nix ({ lib, ... }: {
     with subtest("Task-queue gets ready"):
         machine.wait_for_unit("paperless-task-queue.service")
 
-    with subtest("Add a document via the web interface"):
+    with subtest("Add a png document via the web interface"):
         machine.succeed(
             "convert -size 400x40 xc:white -font 'DejaVu-Sans' -pointsize 20 -fill black "
             "-annotate +5+20 'hello web 16-10-2005' /tmp/webdoc.png"
         )
         machine.wait_until_succeeds("curl -u admin:admin -F document=@/tmp/webdoc.png -fs localhost:28981/api/documents/post_document/")
 
+    with subtest("Add a txt document via the web interface"):
+        machine.succeed(
+            "echo 'hello web 16-10-2005' > /tmp/webdoc.txt"
+        )
+        machine.wait_until_succeeds("curl -u admin:admin -F document=@/tmp/webdoc.txt -fs localhost:28981/api/documents/post_document/")
+
     with subtest("Documents are consumed"):
         machine.wait_until_succeeds(
-            "(($(curl -u admin:admin -fs localhost:28981/api/documents/ | jq .count) == 2))"
+            "(($(curl -u admin:admin -fs localhost:28981/api/documents/ | jq .count) == 3))"
         )
         docs = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/"))['results']
         assert "2005-10-16" in docs[0]['created']
         assert "2005-10-16" in docs[1]['created']
+        assert "2005-10-16" in docs[2]['created']
 
     # Detects gunicorn issues, see PR #190888
     with subtest("Document metadata can be accessed"):
@@ -52,5 +59,8 @@ import ./make-test-python.nix ({ lib, ... }: {
 
         metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/2/metadata/"))
         assert "original_checksum" in metadata
+
+        metadata = json.loads(machine.succeed("curl -u admin:admin -fs localhost:28981/api/documents/3/metadata/"))
+        assert "original_checksum" in metadata
   '';
 })
diff --git a/nixpkgs/nixos/tests/pgbouncer.nix b/nixpkgs/nixos/tests/pgbouncer.nix
new file mode 100644
index 000000000000..1e72327d4200
--- /dev/null
+++ b/nixpkgs/nixos/tests/pgbouncer.nix
@@ -0,0 +1,61 @@
+import ./make-test-python.nix ({ pkgs, ... } :
+let
+  testAuthFile = pkgs.writeTextFile {
+    name = "authFile";
+    text = ''
+      "testuser" "testpass"
+    '';
+  };
+in
+{
+  name = "pgbouncer";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ _1000101 ];
+  };
+  nodes = {
+    one = { config, pkgs, ... }: {
+
+      systemd.services.postgresql = {
+        postStart = ''
+            ${pkgs.postgresql}/bin/psql -U postgres -c "ALTER ROLE testuser WITH LOGIN PASSWORD 'testpass'";
+        '';
+      };
+
+      services = {
+        postgresql = {
+          enable = true;
+          ensureDatabases = [ "testdb" ];
+          ensureUsers = [
+          {
+            name = "testuser";
+            ensurePermissions = {
+              "DATABASE testdb" = "ALL PRIVILEGES";
+            };
+          }];
+          authentication = ''
+            local testdb testuser scram-sha-256
+          '';
+        };
+
+        pgbouncer = {
+          enable = true;
+          listenAddress = "localhost";
+          databases = { testdb = "host=/run/postgresql/ port=5432 auth_user=testuser dbname=testdb"; };
+          authType = "scram-sha-256";
+          authFile = testAuthFile;
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    one.wait_for_unit("default.target")
+    one.require_unit_state("pgbouncer.service", "active")
+
+    # Test if we can make a query through PgBouncer
+    one.wait_until_succeeds(
+        "psql 'postgres://testuser:testpass@localhost:6432/testdb' -c 'SELECT 1;'"
+    )
+  '';
+})
diff --git a/nixpkgs/nixos/tests/plasma-bigscreen.nix b/nixpkgs/nixos/tests/plasma-bigscreen.nix
index 1c61cafcbff3..2fe90fa9b539 100644
--- a/nixpkgs/nixos/tests/plasma-bigscreen.nix
+++ b/nixpkgs/nixos/tests/plasma-bigscreen.nix
@@ -22,14 +22,11 @@ import ./make-test-python.nix ({ pkgs, ...} :
     users.users.alice.extraGroups = ["uinput"];
   };
 
-  testScript = { nodes, ... }: let
-    user = nodes.machine.users.users.alice;
-    xdo = "${pkgs.xdotool}/bin/xdotool";
-  in ''
+  testScript = { nodes, ... }: ''
     with subtest("Wait for login"):
         start_all()
-        machine.wait_for_file("${user.home}/.Xauthority")
-        machine.succeed("xauth merge ${user.home}/.Xauthority")
+        machine.wait_for_file("/tmp/xauth_*")
+        machine.succeed("xauth merge /tmp/xauth_*")
 
     with subtest("Check plasmashell started"):
         machine.wait_until_succeeds("pgrep plasmashell")
diff --git a/nixpkgs/nixos/tests/plasma5-systemd-start.nix b/nixpkgs/nixos/tests/plasma5-systemd-start.nix
index f584c1ec137a..31a313af308b 100644
--- a/nixpkgs/nixos/tests/plasma5-systemd-start.nix
+++ b/nixpkgs/nixos/tests/plasma5-systemd-start.nix
@@ -23,13 +23,11 @@ import ./make-test-python.nix ({ pkgs, ...} :
     };
   };
 
-  testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.users.alice;
-  in ''
+  testScript = { nodes, ... }: ''
     with subtest("Wait for login"):
         start_all()
-        machine.wait_for_file("${user.home}/.Xauthority")
-        machine.succeed("xauth merge ${user.home}/.Xauthority")
+        machine.wait_for_file("/tmp/xauth_*")
+        machine.succeed("xauth merge /tmp/xauth_*")
 
     with subtest("Check plasmashell started"):
         machine.wait_until_succeeds("pgrep plasmashell")
diff --git a/nixpkgs/nixos/tests/plasma5.nix b/nixpkgs/nixos/tests/plasma5.nix
index b3836cf641d4..fb8a5b73832e 100644
--- a/nixpkgs/nixos/tests/plasma5.nix
+++ b/nixpkgs/nixos/tests/plasma5.nix
@@ -13,10 +13,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     services.xserver.enable = true;
     services.xserver.displayManager.sddm.enable = true;
     services.xserver.displayManager.defaultSession = "plasma";
-    services.xserver.desktopManager.plasma5 = {
-      enable = true;
-      excludePackages = [ pkgs.plasma5Packages.elisa ];
-    };
+    services.xserver.desktopManager.plasma5.enable = true;
+    environment.plasma5.excludePackages = [ pkgs.plasma5Packages.elisa ];
     services.xserver.displayManager.autoLogin = {
       enable = true;
       user = "alice";
@@ -25,13 +23,13 @@ import ./make-test-python.nix ({ pkgs, ...} :
   };
 
   testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.users.alice;
+    user = nodes.machine.users.users.alice;
     xdo = "${pkgs.xdotool}/bin/xdotool";
   in ''
     with subtest("Wait for login"):
         start_all()
-        machine.wait_for_file("${user.home}/.Xauthority")
-        machine.succeed("xauth merge ${user.home}/.Xauthority")
+        machine.wait_for_file("/tmp/xauth_*")
+        machine.succeed("xauth merge /tmp/xauth_*")
 
     with subtest("Check plasmashell started"):
         machine.wait_until_succeeds("pgrep plasmashell")
@@ -46,6 +44,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     with subtest("Ensure Elisa is not installed"):
         machine.fail("which elisa")
 
+    machine.succeed("su - ${user.name} -c 'xauth merge /tmp/xauth_*'")
+
     with subtest("Run Dolphin"):
         machine.execute("su - ${user.name} -c 'DISPLAY=:0.0 dolphin >&2 &'")
         machine.wait_for_window(" Dolphin")
diff --git a/nixpkgs/nixos/tests/powerdns.nix b/nixpkgs/nixos/tests/powerdns.nix
index d3708d25f0fb..599d5ea67efe 100644
--- a/nixpkgs/nixos/tests/powerdns.nix
+++ b/nixpkgs/nixos/tests/powerdns.nix
@@ -28,8 +28,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   };
 
   testScript = ''
-    import re
-
     with subtest("PowerDNS database exists"):
         server.wait_for_unit("mysql")
         server.succeed("echo 'SHOW DATABASES;' | sudo -u pdns mysql -u pdns >&2")
@@ -46,11 +44,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
     with subtest("Adding an example zone works"):
         # Extract configuration file needed by pdnsutil
-        unit = server.succeed("systemctl cat pdns")
-        match = re.search("(--config-dir=[^ ]+)", unit)
-        assert(match is not None)
-        conf = match.group(1)
-        pdnsutil = "sudo -u pdns pdnsutil " + conf
+        pdnsutil = "sudo -u pdns pdnsutil "
         server.succeed(f"{pdnsutil} create-zone example.com ns1.example.com")
         server.succeed(f"{pdnsutil} add-record  example.com ns1 A 192.168.1.2")
 
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index a69f2347b54b..23740dd98e3d 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -6,7 +6,7 @@
 let
   inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest;
   inherit (pkgs.lib) concatStringsSep maintainers mapAttrs mkMerge
-    removeSuffix replaceStrings singleton splitString;
+    removeSuffix replaceStrings singleton splitString makeBinPath;
 
   /*
     * The attrset `exporterTests` contains one attribute
@@ -914,6 +914,47 @@ let
       '';
     };
 
+    php-fpm = {
+      nodeName = "php_fpm";
+      exporterConfig = {
+        enable = true;
+        environmentFile = pkgs.writeTextFile {
+          name = "/tmp/prometheus-php-fpm-exporter.env";
+          text = ''
+            PHP_FPM_SCRAPE_URI="tcp://127.0.0.1:9000/status"
+          '';
+        };
+      };
+      metricProvider = {
+        users.users."php-fpm-exporter" = {
+          isSystemUser = true;
+          group  = "php-fpm-exporter";
+        };
+        users.groups."php-fpm-exporter" = {};
+        services.phpfpm.pools."php-fpm-exporter" = {
+          user = "php-fpm-exporter";
+          group = "php-fpm-exporter";
+          settings = {
+            "pm" = "dynamic";
+            "pm.max_children" = 32;
+            "pm.max_requests" = 500;
+            "pm.start_servers" = 2;
+            "pm.min_spare_servers" = 2;
+            "pm.max_spare_servers" = 5;
+            "pm.status_path" = "/status";
+            "listen" = "127.0.0.1:9000";
+            "listen.allowed_clients" = "127.0.0.1";
+          };
+          phpEnv."PATH" = makeBinPath [ pkgs.php ];
+        };
+      };
+      exporterTest = ''
+        wait_for_unit("phpfpm-php-fpm-exporter.service")
+        wait_for_unit("prometheus-php-fpm-exporter.service")
+        succeed("curl -sSf http://localhost:9253/metrics | grep 'phpfpm_up{.*} 1'")
+      '';
+    };
+
     postfix = {
       exporterConfig = {
         enable = true;
@@ -1085,6 +1126,22 @@ let
       '';
     };
 
+    scaphandre = {
+      exporterConfig = {
+        enable = true;
+      };
+      metricProvider = {
+        boot.kernelModules = [ "intel_rapl_common" ];
+      };
+      exporterTest = ''
+        wait_for_unit("prometheus-scaphandre-exporter.service")
+        wait_for_open_port(8080)
+        wait_until_succeeds(
+            "curl -sSf 'localhost:8080/metrics'"
+        )
+      '';
+    };
+
     shelly = {
       exporterConfig = {
         enable = true;
diff --git a/nixpkgs/nixos/tests/public-inbox.nix b/nixpkgs/nixos/tests/public-inbox.nix
index 784ef9e3dc28..4d06d3e1738e 100644
--- a/nixpkgs/nixos/tests/public-inbox.nix
+++ b/nixpkgs/nixos/tests/public-inbox.nix
@@ -223,5 +223,8 @@ in
     # require to use --all
     machine.succeed("curl -L https://machine.${domain}/inbox/repo1/repo1@root-1/raw | sudo -u public-inbox public-inbox-learn rm --all")
     machine.fail("curl -L https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u | grep 'This is a testing mail.'")
+
+    # Compact the database
+    machine.succeed("sudo -u public-inbox public-inbox-compact --all")
   '';
 })
diff --git a/nixpkgs/nixos/tests/qemu-vm-volatile-root.nix b/nixpkgs/nixos/tests/qemu-vm-volatile-root.nix
new file mode 100644
index 000000000000..bc8fd853409d
--- /dev/null
+++ b/nixpkgs/nixos/tests/qemu-vm-volatile-root.nix
@@ -0,0 +1,17 @@
+# Test that the root filesystem is a volatile tmpfs.
+
+{ lib, ... }:
+
+{
+  name = "qemu-vm-volatile-root";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes.machine = _: {
+    virtualisation.diskImage = null;
+  };
+
+  testScript = ''
+    machine.succeed("findmnt --kernel --types tmpfs /")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/qownnotes.nix b/nixpkgs/nixos/tests/qownnotes.nix
new file mode 100644
index 000000000000..93801cb98702
--- /dev/null
+++ b/nixpkgs/nixos/tests/qownnotes.nix
@@ -0,0 +1,70 @@
+import ./make-test-python.nix ({ lib, pkgs, ...} :
+
+{
+  name = "qownnotes";
+  meta.maintainers = [ lib.maintainers.pbek ];
+
+  nodes.machine = { ... }:
+
+  {
+    imports = [
+      ./common/user-account.nix
+      ./common/x11.nix
+    ];
+
+    test-support.displayManager.auto.user = "alice";
+    environment.systemPackages = [
+      pkgs.qownnotes
+      pkgs.xdotool
+    ];
+  };
+
+  enableOCR = true;
+
+  testScript = { nodes, ... }: let
+    aliceDo = cmd: ''machine.succeed("su - alice -c '${cmd}' >&2 &");'';
+    in ''
+    with subtest("Ensure X starts"):
+        start_all()
+        machine.wait_for_x()
+
+    with subtest("Check QOwnNotes version on CLI"):
+        ${aliceDo "qownnotes --version"}
+
+        machine.wait_for_console_text("QOwnNotes ${pkgs.qownnotes.version}")
+
+    with subtest("Ensure QOwnNotes starts"):
+        # start QOwnNotes window
+        ${aliceDo "qownnotes"}
+
+        machine.wait_for_text("Welcome to QOwnNotes")
+        machine.screenshot("QOwnNotes-Welcome")
+
+    with subtest("Finish first-run wizard"):
+        # The wizard should show up now
+        machine.wait_for_text("Note folder")
+        machine.send_key("ret")
+        machine.wait_for_console_text("Note path '/home/alice/Notes' was now created.")
+        machine.wait_for_text("Panel layout")
+        machine.send_key("ret")
+        machine.wait_for_text("Nextcloud")
+        machine.send_key("ret")
+        machine.wait_for_text("App metric")
+        machine.send_key("ret")
+
+        # The main window should now show up
+        machine.wait_for_text("QOwnNotes - ${pkgs.qownnotes.version}")
+        machine.wait_for_open_port(22222)
+        machine.wait_for_console_text("QOwnNotes server listening on port 22222")
+
+        machine.screenshot("QOwnNotes-DemoNote")
+
+    with subtest("Create a new note"):
+        machine.send_key("ctrl-n")
+        machine.sleep(1)
+        machine.send_chars("This is a NixOS test!\n")
+        machine.wait_for_text("This is a NixOS test!")
+
+        machine.screenshot("QOwnNotes-NewNote")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/retroarch.nix b/nixpkgs/nixos/tests/retroarch.nix
index f4bf232ea725..0e5f60aa8be2 100644
--- a/nixpkgs/nixos/tests/retroarch.nix
+++ b/nixpkgs/nixos/tests/retroarch.nix
@@ -30,8 +30,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
       in ''
         with subtest("Wait for login"):
             start_all()
-            machine.wait_for_file("${user.home}/.Xauthority")
-            machine.succeed("xauth merge ${user.home}/.Xauthority")
+            machine.wait_for_file("/tmp/xauth_*")
+            machine.succeed("xauth merge /tmp/xauth_*")
 
         with subtest("Check RetroArch started"):
             machine.wait_until_succeeds("pgrep retroarch")
diff --git a/nixpkgs/nixos/tests/samba-wsdd.nix b/nixpkgs/nixos/tests/samba-wsdd.nix
index 0e3185b0c684..666a626d1b4a 100644
--- a/nixpkgs/nixos/tests/samba-wsdd.nix
+++ b/nixpkgs/nixos/tests/samba-wsdd.nix
@@ -8,25 +8,23 @@ import ./make-test-python.nix ({ pkgs, ... }:
     client_wsdd = { pkgs, ... }: {
       services.samba-wsdd = {
         enable = true;
+        openFirewall = true;
         interface = "eth1";
         workgroup = "WORKGROUP";
         hostname = "CLIENT-WSDD";
         discovery = true;
         extraOptions = [ "--no-host" ];
       };
-      networking.firewall.allowedTCPPorts = [ 5357 ];
-      networking.firewall.allowedUDPPorts = [ 3702 ];
     };
 
     server_wsdd = { ... }: {
       services.samba-wsdd = {
         enable = true;
+        openFirewall = true;
         interface = "eth1";
         workgroup = "WORKGROUP";
         hostname = "SERVER-WSDD";
       };
-      networking.firewall.allowedTCPPorts = [ 5357 ];
-      networking.firewall.allowedUDPPorts = [ 3702 ];
     };
   };
 
diff --git a/nixpkgs/nixos/tests/scaphandre.nix b/nixpkgs/nixos/tests/scaphandre.nix
new file mode 100644
index 000000000000..f0a411748503
--- /dev/null
+++ b/nixpkgs/nixos/tests/scaphandre.nix
@@ -0,0 +1,18 @@
+import ./make-test-python.nix {
+  name = "scaphandre";
+
+  nodes = {
+    scaphandre = { pkgs, ... } : {
+      boot.kernelModules = [ "intel_rapl_common" ];
+
+      environment.systemPackages = [ pkgs.scaphandre ];
+    };
+  };
+
+  testScript = { nodes, ... } : ''
+    scaphandre.start()
+    scaphandre.wait_until_succeeds(
+        "scaphandre stdout -t 4",
+    )
+  '';
+}
diff --git a/nixpkgs/nixos/tests/sddm.nix b/nixpkgs/nixos/tests/sddm.nix
index c76a9683e66d..b6c05deac05e 100644
--- a/nixpkgs/nixos/tests/sddm.nix
+++ b/nixpkgs/nixos/tests/sddm.nix
@@ -23,14 +23,14 @@ let
       enableOCR = true;
 
       testScript = { nodes, ... }: let
-        user = nodes.machine.config.users.users.alice;
+        user = nodes.machine.users.users.alice;
       in ''
         start_all()
         machine.wait_for_text("(?i)select your user")
         machine.screenshot("sddm")
         machine.send_chars("${user.password}\n")
-        machine.wait_for_file("${user.home}/.Xauthority")
-        machine.succeed("xauth merge ${user.home}/.Xauthority")
+        machine.wait_for_file("/tmp/xauth_*")
+        machine.succeed("xauth merge /tmp/xauth_*")
         machine.wait_for_window("^IceWM ")
       '';
     };
@@ -55,12 +55,10 @@ let
         services.xserver.windowManager.icewm.enable = true;
       };
 
-      testScript = { nodes, ... }: let
-        user = nodes.machine.config.users.users.alice;
-      in ''
+      testScript = { nodes, ... }: ''
         start_all()
-        machine.wait_for_file("${user.home}/.Xauthority")
-        machine.succeed("xauth merge ${user.home}/.Xauthority")
+        machine.wait_for_file("/tmp/xauth_*")
+        machine.succeed("xauth merge /tmp/xauth_*")
         machine.wait_for_window("^IceWM ")
       '';
     };
diff --git a/nixpkgs/nixos/tests/sftpgo.nix b/nixpkgs/nixos/tests/sftpgo.nix
index ca55b9c962a0..8cd5675c1d4d 100644
--- a/nixpkgs/nixos/tests/sftpgo.nix
+++ b/nixpkgs/nixos/tests/sftpgo.nix
@@ -12,8 +12,6 @@
 # would be a nice to have for the future.
 { pkgs, lib, ...  }:
 
-with lib;
-
 let
   inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
 
@@ -54,7 +52,7 @@ let
       # inside the dataprovider they will be automatically created.
       # You have to create the folder on the filesystem yourself
       virtual_folders =
-        optional (isMemberOf config sharedFolderName user) {
+        lib.optional (lib.isMemberOf config sharedFolderName user) {
           name = sharedFolderName;
           mapped_path = "${config.services.sftpgo.dataDir}/${sharedFolderName}";
           virtual_path = "/${sharedFolderName}";
@@ -62,10 +60,10 @@ let
 
       # Defines the ACL on the virtual filesystem
       permissions =
-        recursiveUpdate {
+        lib.recursiveUpdate {
           "/" = [ "list" ];     # read-only top level directory
           "/private" = [ "*" ]; # private subdirectory, not shared with others
-        } (optionalAttrs (isMemberOf config "shared" user) {
+        } (lib.optionalAttrs (lib.isMemberOf config "shared" user) {
           "/shared" = [ "*" ];
         });
 
@@ -91,7 +89,7 @@ let
   # of users and folders to import to SFTPGo.
   loadDataJson = config: pkgs.writeText "users-and-folders.json" (builtins.toJSON {
     users =
-      mapAttrsToList (name: user: generateUserAttrSet config user) (normalUsers config);
+      lib.mapAttrsToList (name: user: lib.generateUserAttrSet config user) (normalUsers config);
 
     folders = [
       {
diff --git a/nixpkgs/nixos/tests/sing-box.nix b/nixpkgs/nixos/tests/sing-box.nix
new file mode 100644
index 000000000000..582d594be3fd
--- /dev/null
+++ b/nixpkgs/nixos/tests/sing-box.nix
@@ -0,0 +1,48 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+
+  name = "sing-box";
+
+  meta = {
+    maintainers = with lib.maintainers; [ nickcao ];
+  };
+
+  nodes.machine = { pkgs, ... }: {
+    environment.systemPackages = [ pkgs.curl ];
+    services.nginx = {
+      enable = true;
+      statusPage = true;
+    };
+    services.sing-box = {
+      enable = true;
+      settings = {
+        inbounds = [{
+          type = "mixed";
+          tag = "inbound";
+          listen = "127.0.0.1";
+          listen_port = 1080;
+          users = [{
+            username = "user";
+            password = { _secret = pkgs.writeText "password" "supersecret"; };
+          }];
+        }];
+        outbounds = [{
+          type = "direct";
+          tag = "outbound";
+        }];
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("nginx.service")
+    machine.wait_for_unit("sing-box.service")
+
+    machine.wait_for_open_port(80)
+    machine.wait_for_open_port(1080)
+
+    machine.succeed("curl --fail --max-time 10 --proxy http://user:supersecret@localhost:1080 http://localhost")
+    machine.fail("curl --fail --max-time 10 --proxy http://user:supervillain@localhost:1080 http://localhost")
+    machine.succeed("curl --fail --max-time 10 --proxy socks5://user:supersecret@localhost:1080 http://localhost")
+  '';
+
+})
diff --git a/nixpkgs/nixos/tests/snapper.nix b/nixpkgs/nixos/tests/snapper.nix
index 651adc8934d3..674523584fda 100644
--- a/nixpkgs/nixos/tests/snapper.nix
+++ b/nixpkgs/nixos/tests/snapper.nix
@@ -15,7 +15,7 @@ import ./make-test-python.nix ({ ... }:
         fsType = "btrfs";
       };
     };
-    services.snapper.configs.home.subvolume = "/home";
+    services.snapper.configs.home.SUBVOLUME = "/home";
     services.snapper.filters = "/nix";
   };
 
diff --git a/nixpkgs/nixos/tests/sway.nix b/nixpkgs/nixos/tests/sway.nix
index 52e2c7c99ec4..695d4a770810 100644
--- a/nixpkgs/nixos/tests/sway.nix
+++ b/nixpkgs/nixos/tests/sway.nix
@@ -45,9 +45,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           regular2 = foreground;
         };
       };
+
+      etc."gpg-agent.conf".text = ''
+        pinentry-timeout 86400
+      '';
     };
 
-    fonts.fonts = [ pkgs.inconsolata ];
+    fonts.packages = [ pkgs.inconsolata ];
 
     # Automatically configure and start Sway when logging in on tty1:
     programs.bash.loginShellInit = ''
@@ -71,16 +75,53 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     virtualisation.qemu.options = [ "-vga none -device virtio-gpu-pci" ];
   };
 
-  enableOCR = true;
-
   testScript = { nodes, ... }: ''
     import shlex
+    import json
+
+    q = shlex.quote
+    NODE_GROUPS = ["nodes", "floating_nodes"]
+
+
+    def swaymsg(command: str = "", succeed=True, type="command"):
+        assert command != "" or type != "command", "Must specify command or type"
+        shell = q(f"swaymsg -t {q(type)} -- {q(command)}")
+        with machine.nested(
+            f"sending swaymsg {shell!r}" + " (allowed to fail)" * (not succeed)
+        ):
+            ret = (machine.succeed if succeed else machine.execute)(
+                f"su - alice -c {shell}"
+            )
+
+        # execute also returns a status code, but disregard.
+        if not succeed:
+            _, ret = ret
+
+        if not succeed and not ret:
+            return None
+
+        parsed = json.loads(ret)
+        return parsed
 
-    def swaymsg(command: str, succeed=True):
-        with machine.nested(f"sending swaymsg {command!r}" + " (allowed to fail)" * (not succeed)):
-          (machine.succeed if succeed else machine.execute)(
-            f"su - alice -c {shlex.quote('swaymsg -- ' + command)}"
-          )
+
+    def walk(tree):
+        yield tree
+        for group in NODE_GROUPS:
+            for node in tree.get(group, []):
+                yield from walk(node)
+
+
+    def wait_for_window(pattern):
+        def func(last_chance):
+            nodes = (node["name"] for node in walk(swaymsg(type="get_tree")))
+
+            if last_chance:
+                nodes = list(nodes)
+                machine.log(f"Last call! Current list of windows: {nodes}")
+
+            return any(pattern in name for name in nodes)
+
+        retry(func)
 
     start_all()
     machine.wait_for_unit("multi-user.target")
@@ -94,7 +135,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
     # Test XWayland (foot does not support X):
     swaymsg("exec WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty")
-    machine.wait_for_text("alice@machine")
+    wait_for_window("alice@machine")
     machine.send_chars("test-x11\n")
     machine.wait_for_file("/tmp/test-x11-exit-ok")
     print(machine.succeed("cat /tmp/test-x11.out"))
@@ -106,7 +147,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     machine.send_key("alt-3")
     machine.sleep(3)
     machine.send_key("alt-ret")
-    machine.wait_for_text("alice@machine")
+    wait_for_window("alice@machine")
     machine.send_chars("test-wayland\n")
     machine.wait_for_file("/tmp/test-wayland-exit-ok")
     print(machine.succeed("cat /tmp/test-wayland.out"))
@@ -117,16 +158,24 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
     # Test gpg-agent starting pinentry-gnome3 via D-Bus (tests if
     # $WAYLAND_DISPLAY is correctly imported into the D-Bus user env):
-    swaymsg("exec gpg --no-tty --yes --quick-generate-key test")
+    swaymsg("exec mkdir -p ~/.gnupg")
+    swaymsg("exec cp /etc/gpg-agent.conf ~/.gnupg")
+
+    swaymsg("exec DISPLAY=INVALID gpg --no-tty --yes --quick-generate-key test", succeed=False)
     machine.wait_until_succeeds("pgrep --exact gpg")
-    machine.wait_for_text("Passphrase")
+    wait_for_window("gpg")
+    machine.succeed("pgrep --exact gpg")
     machine.screenshot("gpg_pinentry")
     machine.send_key("alt-shift-q")
     machine.wait_until_fails("pgrep --exact gpg")
 
     # Test swaynag:
+    def get_height():
+        return [node['rect']['height'] for node in walk(swaymsg(type="get_tree")) if node['focused']][0]
+
+    before = get_height()
     machine.send_key("alt-shift-e")
-    machine.wait_for_text("You pressed the exit shortcut.")
+    retry(lambda _: get_height() < before)
     machine.screenshot("sway_exit")
 
     swaymsg("exec swaylock")
diff --git a/nixpkgs/nixos/tests/switch-test.nix b/nixpkgs/nixos/tests/switch-test.nix
index f891a2cb2f4c..f44dede7fef4 100644
--- a/nixpkgs/nixos/tests/switch-test.nix
+++ b/nixpkgs/nixos/tests/switch-test.nix
@@ -70,6 +70,19 @@ in {
           };
         };
 
+        simpleServiceSeparateActivationScript.configuration = {
+          system.activatable = false;
+          systemd.services.test = {
+            wantedBy = [ "multi-user.target" ];
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = true;
+              ExecStart = "${pkgs.coreutils}/bin/true";
+              ExecReload = "${pkgs.coreutils}/bin/true";
+            };
+          };
+        };
+
         simpleServiceDifferentDescription.configuration = {
           imports = [ simpleService.configuration ];
           systemd.services.test.description = "Test unit";
@@ -482,9 +495,9 @@ in {
   };
 
   testScript = { nodes, ... }: let
-    originalSystem = nodes.machine.config.system.build.toplevel;
-    otherSystem = nodes.other.config.system.build.toplevel;
-    machine = nodes.machine.config.system.build.toplevel;
+    originalSystem = nodes.machine.system.build.toplevel;
+    otherSystem = nodes.other.system.build.toplevel;
+    machine = nodes.machine.system.build.toplevel;
 
     # Ensures failures pass through using pipefail, otherwise failing to
     # switch-to-configuration is hidden by the success of `tee`.
@@ -497,11 +510,15 @@ in {
   in /* python */ ''
     def switch_to_specialisation(system, name, action="test", fail=False):
         if name == "":
-            stc = f"{system}/bin/switch-to-configuration"
+            switcher = f"{system}/bin/switch-to-configuration"
         else:
-            stc = f"{system}/specialisation/{name}/bin/switch-to-configuration"
-        out = machine.fail(f"{stc} {action} 2>&1") if fail \
-            else machine.succeed(f"{stc} {action} 2>&1")
+            switcher = f"{system}/specialisation/{name}/bin/switch-to-configuration"
+        return run_switch(switcher, action, fail)
+
+    # like above but stc = switcher
+    def run_switch(switcher, action="test", fail=False):
+        out = machine.fail(f"{switcher} {action} 2>&1") if fail \
+            else machine.succeed(f"{switcher} {action} 2>&1")
         assert_lacks(out, "switch-to-configuration line")  # Perl warnings
         return out
 
@@ -639,6 +656,22 @@ in {
         assert_lacks(out, "the following new units were started:")
         assert_contains(out, "would start the following units: test.service\n")
 
+        out = switch_to_specialisation("${machine}", "", action="test")
+
+        # Ensure the service can be started when the activation script isn't in toplevel
+        # This is a lot like "Start a simple service", except activation-only deps could be gc-ed
+        out = run_switch("${nodes.machine.specialisation.simpleServiceSeparateActivationScript.configuration.system.build.separateActivationScript}/bin/switch-to-configuration");
+        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_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")
+        machine.succeed("! test -e /run/current-system/activate")
+        machine.succeed("! test -e /run/current-system/dry-activate")
+        machine.succeed("! test -e /run/current-system/bin/switch-to-configuration")
+
         # Ensure \ works in unit names
         out = switch_to_specialisation("${machine}", "unitWithBackslash")
         assert_contains(out, "stopping the following units: test.service\n")
diff --git a/nixpkgs/nixos/tests/syncthing-init.nix b/nixpkgs/nixos/tests/syncthing-init.nix
index fcd90739e6a5..195c157ffb6e 100644
--- a/nixpkgs/nixos/tests/syncthing-init.nix
+++ b/nixpkgs/nixos/tests/syncthing-init.nix
@@ -1,6 +1,7 @@
 import ./make-test-python.nix ({ lib, pkgs, ... }: let
 
   testId = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
+  testName = "testDevice foo'bar";
 
 in {
   name = "syncthing-init";
@@ -9,14 +10,14 @@ in {
   nodes.machine = {
     services.syncthing = {
       enable = true;
-      devices.testDevice = {
+      settings.devices.testDevice = {
         id = testId;
       };
-      folders.testFolder = {
+      settings.folders.testFolder = {
         path = "/tmp/test";
         devices = [ "testDevice" ];
       };
-      extraOptions.gui.user = "guiUser";
+      settings.gui.user = "guiUser";
     };
   };
 
diff --git a/nixpkgs/nixos/tests/syncthing-no-settings.nix b/nixpkgs/nixos/tests/syncthing-no-settings.nix
new file mode 100644
index 000000000000..fee122b5e35c
--- /dev/null
+++ b/nixpkgs/nixos/tests/syncthing-no-settings.nix
@@ -0,0 +1,18 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "syncthing";
+  meta.maintainers = with pkgs.lib.maintainers; [ chkno ];
+
+  nodes = {
+    a = {
+      environment.systemPackages = with pkgs; [ curl libxml2 syncthing ];
+      services.syncthing = {
+        enable = true;
+      };
+    };
+  };
+  # Test that indeed a syncthing-init.service systemd service is not created.
+  #
+  testScript = /* python */ ''
+    a.succeed("systemctl list-unit-files | awk '$1 == \"syncthing-init.service\" {exit 1;}'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-boot.nix b/nixpkgs/nixos/tests/systemd-boot.nix
index 814cdc5f1443..84a4da5aa6ec 100644
--- a/nixpkgs/nixos/tests/systemd-boot.nix
+++ b/nixpkgs/nixos/tests/systemd-boot.nix
@@ -258,7 +258,8 @@ in
     '';
   };
 
-  # See: [Firmware file size bug] in systemd/default.nix
+  # Some UEFI firmwares fail on large reads. Now that systemd-boot loads initrd
+  # itself, systems with such firmware won't boot without this fix
   uefiLargeFileWorkaround = makeTest {
     name = "uefi-large-file-workaround";
 
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-fido2.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-fido2.nix
index 32c79b731d80..f9f75ab7f301 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-luks-fido2.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-fido2.nix
@@ -26,6 +26,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
         };
       };
       virtualisation.rootDevice = "/dev/mapper/cryptroot";
+      virtualisation.fileSystems."/".autoFormat = true;
     };
   };
 
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix
index 5ca0f48c333a..617c003484b9 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix
@@ -34,6 +34,7 @@ in {
         };
       };
       virtualisation.rootDevice = "/dev/mapper/cryptroot";
+      virtualisation.fileSystems."/".autoFormat = true;
       boot.initrd.secrets."/etc/cryptroot.key" = keyfile;
     };
   };
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix
index a90a59feed6f..66b5022d87fd 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix
@@ -25,6 +25,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
         cryptroot2.device = "/dev/vdc";
       };
       virtualisation.rootDevice = "/dev/mapper/cryptroot";
+      virtualisation.fileSystems."/".autoFormat = true;
       # test mounting device unlocked in initrd after switching root
       virtualisation.fileSystems."/cryptroot2".device = "/dev/mapper/cryptroot2";
     };
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
index 73aa190ad620..d9dd9118a3a2 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-tpm2.nix
@@ -28,6 +28,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
         };
       };
       virtualisation.rootDevice = "/dev/mapper/cryptroot";
+      virtualisation.fileSystems."/".autoFormat = true;
     };
   };
 
diff --git a/nixpkgs/nixos/tests/systemd-initrd-networkd-ssh.nix b/nixpkgs/nixos/tests/systemd-initrd-networkd-ssh.nix
index 46dbdf537393..6aaa6c828f7b 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-networkd-ssh.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-networkd-ssh.nix
@@ -2,21 +2,23 @@ import ./make-test-python.nix ({ lib, ... }: {
   name = "systemd-initrd-network-ssh";
   meta.maintainers = [ lib.maintainers.elvishjerricco ];
 
-  nodes = with lib; {
+  nodes = {
     server = { config, pkgs, ... }: {
-      environment.systemPackages = [pkgs.cryptsetup];
+      environment.systemPackages = [ pkgs.cryptsetup ];
       boot.loader.systemd-boot.enable = true;
       boot.loader.timeout = 0;
       virtualisation = {
         emptyDiskImages = [ 4096 ];
         useBootLoader = true;
-        # Booting off the encrypted disk requires an available init script from the Nix store
+        # Booting off the encrypted disk requires an available init script from
+        # the Nix store
         mountHostNixStore = true;
         useEFIBoot = true;
       };
 
       specialisation.encrypted-root.configuration = {
         virtualisation.rootDevice = "/dev/mapper/root";
+        virtualisation.fileSystems."/".autoFormat = true;
         boot.initrd.luks.devices = lib.mkVMOverride {
           root.device = "/dev/vdb";
         };
@@ -25,7 +27,7 @@ import ./make-test-python.nix ({ lib, ... }: {
           enable = true;
           ssh = {
             enable = true;
-            authorizedKeys = [ (readFile ./initrd-network-ssh/id_ed25519.pub) ];
+            authorizedKeys = [ (lib.readFile ./initrd-network-ssh/id_ed25519.pub) ];
             port = 22;
             # Terrible hack so it works with useBootLoader
             hostKeys = [ { outPath = "${./initrd-network-ssh/ssh_host_ed25519_key}"; } ];
@@ -37,13 +39,13 @@ import ./make-test-python.nix ({ lib, ... }: {
     client = { config, ... }: {
       environment.etc = {
         knownHosts = {
-          text = concatStrings [
+          text = lib.concatStrings [
             "server,"
             "${
-              toString (head (splitString " " (toString
-                (elemAt (splitString "\n" config.networking.extraHosts) 2))))
+              toString (lib.head (lib.splitString " " (toString
+                (lib.elemAt (lib.splitString "\n" config.networking.extraHosts) 2))))
             } "
-            "${readFile ./initrd-network-ssh/ssh_host_ed25519_key.pub}"
+            "${lib.readFile ./initrd-network-ssh/ssh_host_ed25519_key.pub}"
           ];
         };
         sshKey = {
diff --git a/nixpkgs/nixos/tests/systemd-initrd-swraid.nix b/nixpkgs/nixos/tests/systemd-initrd-swraid.nix
index 0d5a1c6354d0..d87170c92574 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-swraid.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-swraid.nix
@@ -14,17 +14,17 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
     boot.loader.efi.canTouchEfiVariables = true;
 
     environment.systemPackages = with pkgs; [ mdadm e2fsprogs ]; # for mdadm and mkfs.ext4
+    boot.swraid = {
+      enable = true;
+      mdadmConf = ''
+        ARRAY /dev/md0 devices=/dev/vdb,/dev/vdc
+      '';
+    };
     boot.initrd = {
       systemd = {
         enable = true;
         emergencyAccess = true;
       };
-      services.swraid = {
-        enable = true;
-        mdadmConf = ''
-          ARRAY /dev/md0 devices=/dev/vdb,/dev/vdc
-        '';
-      };
       kernelModules = [ "raid0" ];
     };
 
diff --git a/nixpkgs/nixos/tests/systemd-initrd-vconsole.nix b/nixpkgs/nixos/tests/systemd-initrd-vconsole.nix
index b74df410c422..d4c2a57680c1 100644
--- a/nixpkgs/nixos/tests/systemd-initrd-vconsole.nix
+++ b/nixpkgs/nixos/tests/systemd-initrd-vconsole.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   name = "systemd-initrd-vconsole";
 
   nodes.machine = { pkgs, ... }: {
-    boot.kernelParams = [ "rd.systemd.unit=rescue.target" ];
+    boot.kernelParams = lib.mkAfter [ "rd.systemd.unit=rescue.target" "loglevel=3" "udev.log_level=3" "systemd.log_level=warning" ];
 
     boot.initrd.systemd = {
       enable = true;
@@ -20,14 +20,23 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
     machine.start()
     machine.wait_for_console_text("Press Enter for maintenance")
     machine.send_console("\n")
-    machine.wait_for_console_text("Logging in with home")
+
+    # Wait for shell to become ready
+    for _ in range(300):
+      machine.send_console("printf '%s to receive commands:\\n' Ready\n")
+      try:
+        machine.wait_for_console_text("Ready to receive commands:", timeout=1)
+        break
+      except Exception:
+        continue
+    else:
+      raise RuntimeError("Rescue shell never became ready")
 
     # Check keymap
-    machine.send_console("(printf '%s to receive text: \\n' Ready && read text && echo \"$text\") </dev/tty1\n")
+    machine.send_console("(printf '%s to receive text:\\n' Ready && read text && echo \"$text\") </dev/tty1\n")
     machine.wait_for_console_text("Ready to receive text:")
     for key in "asdfjkl;\n":
       machine.send_key(key)
     machine.wait_for_console_text("arstneio")
-    machine.send_console("systemctl poweroff\n")
   '';
 })
diff --git a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix
index a8254a158016..f6d5411aa5ca 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver-static-leases.nix
@@ -3,7 +3,7 @@
 import ./make-test-python.nix ({ lib, ... }: {
   name = "systemd-networkd-dhcpserver-static-leases";
   meta = with lib.maintainers; {
-    maintainers = [ veehaitch tomfitzhenry ];
+    maintainers = [ veehaitch ];
   };
   nodes = {
     router = {
diff --git a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
index b52c1499718b..cf0ccb744211 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-dhcpserver.nix
@@ -1,10 +1,16 @@
 # This test predominantly tests systemd-networkd DHCP server, by
 # setting up a DHCP server and client, and ensuring they are mutually
 # reachable via the DHCP allocated address.
+# Two DHCP servers are set up on bridge VLANs, testing to make sure that
+# bridge VLAN settings are correctly applied.
+#
+# br0 ----untagged---v
+#                    +---PVID 1+VLAN 2---[bridge]---PVID 2---eth1
+# vlan2 ---VLAN 2----^
 import ./make-test-python.nix ({pkgs, ...}: {
   name = "systemd-networkd-dhcpserver";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ tomfitzhenry ];
+    maintainers = [ ];
   };
   nodes = {
     router = { config, pkgs, ... }: {
@@ -16,6 +22,28 @@ import ./make-test-python.nix ({pkgs, ...}: {
         firewall.enable = false;
       };
       systemd.network = {
+        netdevs = {
+          br0 = {
+            enable = true;
+            netdevConfig = {
+              Name = "br0";
+              Kind = "bridge";
+            };
+            extraConfig = ''
+              [Bridge]
+              VLANFiltering=yes
+              DefaultPVID=none
+            '';
+          };
+          vlan2 = {
+            enable = true;
+            netdevConfig = {
+              Name = "vlan2";
+              Kind = "vlan";
+            };
+            vlanConfig.Id = 2;
+          };
+        };
         networks = {
           # systemd-networkd will load the first network unit file
           # that matches, ordered lexiographically by filename.
@@ -24,9 +52,32 @@ import ./make-test-python.nix ({pkgs, ...}: {
           # however, hence why this network is named such.
           "01-eth1" = {
             name = "eth1";
+            networkConfig.Bridge = "br0";
+            bridgeVLANs = [
+              { bridgeVLANConfig = { PVID = 2; EgressUntagged = 2; }; }
+            ];
+          };
+          "02-br0" = {
+            name = "br0";
             networkConfig = {
               DHCPServer = true;
               Address = "10.0.0.1/24";
+              VLAN = ["vlan2"];
+            };
+            dhcpServerConfig = {
+              PoolOffset = 100;
+              PoolSize = 1;
+            };
+            bridgeVLANs = [
+              { bridgeVLANConfig = { PVID = 1; EgressUntagged = 1; }; }
+              { bridgeVLANConfig = { VLAN = 2; }; }
+            ];
+          };
+          "02-vlan2" = {
+            name = "vlan2";
+            networkConfig = {
+              DHCPServer = true;
+              Address = "10.0.2.1/24";
             };
             dhcpServerConfig = {
               PoolOffset = 100;
@@ -52,7 +103,7 @@ import ./make-test-python.nix ({pkgs, ...}: {
     start_all()
     router.wait_for_unit("systemd-networkd-wait-online.service")
     client.wait_for_unit("systemd-networkd-wait-online.service")
-    client.wait_until_succeeds("ping -c 5 10.0.0.1")
-    router.wait_until_succeeds("ping -c 5 10.0.0.100")
+    client.wait_until_succeeds("ping -c 5 10.0.2.1")
+    router.wait_until_succeeds("ping -c 5 10.0.2.100")
   '';
 })
diff --git a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
index e6bed6b9218f..54f371e6c070 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix
@@ -67,14 +67,14 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
             interfaces-config.interfaces = [ "eth1" ];
             subnet6 = [ {
               interface = "eth1";
-              subnet = "2001:DB8:F::/36";
+              subnet = "2001:DB8::/32";
               pd-pools = [ {
-                prefix = "2001:DB8:F::";
+                prefix = "2001:DB8:1000::";
                 prefix-len = 36;
                 delegated-len = 48;
               } ];
               pools = [ {
-                pool = "2001:DB8:0000:0000:FFFF::-2001:DB8:0000:0000:FFFF::FFFF";
+                pool = "2001:DB8:0000:0000::-2001:DB8:0FFF:FFFF::FFFF";
               } ];
             } ];
 
diff --git a/nixpkgs/nixos/tests/systemd-nspawn-configfile.nix b/nixpkgs/nixos/tests/systemd-nspawn-configfile.nix
new file mode 100644
index 000000000000..12ab21b7f9b5
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-nspawn-configfile.nix
@@ -0,0 +1,128 @@
+import ./make-test-python.nix ({ lib, ... }:
+let
+  execOptions = [
+    "Boot"
+    "ProcessTwo"
+    "Parameters"
+    "Environment"
+    "User"
+    "WorkingDirectory"
+    "PivotRoot"
+    "Capability"
+    "DropCapability"
+    "NoNewPrivileges"
+    "KillSignal"
+    "Personality"
+    "MachineID"
+    "PrivateUsers"
+    "NotifyReady"
+    "SystemCallFilter"
+    "LimitCPU"
+    "LimitFSIZE"
+    "LimitDATA"
+    "LimitSTACK"
+    "LimitCORE"
+    "LimitRSS"
+    "LimitNOFILE"
+    "LimitAS"
+    "LimitNPROC"
+    "LimitMEMLOCK"
+    "LimitLOCKS"
+    "LimitSIGPENDING"
+    "LimitMSGQUEUE"
+    "LimitNICE"
+    "LimitRTPRIO"
+    "LimitRTTIME"
+    "OOMScoreAdjust"
+    "CPUAffinity"
+    "Hostname"
+    "ResolvConf"
+    "Timezone"
+    "LinkJournal"
+    "Ephemeral"
+    "AmbientCapability"
+  ];
+
+  filesOptions = [
+    "ReadOnly"
+    "Volatile"
+    "Bind"
+    "BindReadOnly"
+    "TemporaryFileSystem"
+    "Overlay"
+    "OverlayReadOnly"
+    "PrivateUsersChown"
+    "BindUser"
+    "Inaccessible"
+    "PrivateUsersOwnership"
+  ];
+
+  networkOptions = [
+    "Private"
+    "VirtualEthernet"
+    "VirtualEthernetExtra"
+    "Interface"
+    "MACVLAN"
+    "IPVLAN"
+    "Bridge"
+    "Zone"
+    "Port"
+  ];
+
+  optionsToConfig = opts: builtins.listToAttrs (map (n: lib.nameValuePair n "testdata") opts);
+
+  grepForOptions = opts: ''node.succeed(
+    "for o in ${builtins.concatStringsSep " " opts} ; do grep --quiet $o ${configFile} || exit 1 ; done"
+  )'';
+
+  unitName = "options-test";
+  configFile = "/etc/systemd/nspawn/${unitName}.nspawn";
+
+in
+{
+  name = "systemd-nspawn-configfile";
+
+  nodes = {
+    node = { pkgs, ... }: {
+      systemd.nspawn."${unitName}" = {
+        enable = true;
+
+        execConfig = optionsToConfig execOptions // {
+          Boot = true;
+          ProcessTwo = true;
+          NotifyReady = true;
+        };
+
+        filesConfig = optionsToConfig filesOptions // {
+          ReadOnly = true;
+          Volatile = "state";
+          PrivateUsersChown = true;
+          PrivateUsersOwnership = "auto";
+        };
+
+        networkConfig = optionsToConfig networkOptions // {
+          Private = true;
+          VirtualEthernet = true;
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+
+    node.wait_for_file("${configFile}")
+
+    with subtest("Test for presence of all specified options in config file"):
+      ${grepForOptions execOptions}
+      ${grepForOptions filesOptions}
+      ${grepForOptions networkOptions}
+
+    with subtest("Test for absence of misspelled option 'MachineId' (instead of 'MachineID')"):
+      node.fail("grep --quiet MachineId ${configFile}")
+  '';
+
+  meta.maintainers = [
+    lib.maintainers.zi3m5f
+  ];
+})
diff --git a/nixpkgs/nixos/tests/systemd-nspawn.nix b/nixpkgs/nixos/tests/systemd-nspawn.nix
index bc77ee2a4d15..1a4251ef069e 100644
--- a/nixpkgs/nixos/tests/systemd-nspawn.nix
+++ b/nixpkgs/nixos/tests/systemd-nspawn.nix
@@ -1,26 +1,6 @@
 import ./make-test-python.nix ({pkgs, lib, ...}:
 let
-  gpgKeyring = (pkgs.runCommand "gpg-keyring" { buildInputs = [ pkgs.gnupg ]; } ''
-    mkdir -p $out
-    export GNUPGHOME=$out
-    cat > foo <<EOF
-      %echo Generating a basic OpenPGP key
-      %no-protection
-      Key-Type: DSA
-      Key-Length: 1024
-      Subkey-Type: ELG-E
-      Subkey-Length: 1024
-      Name-Real: Bob Foobar
-      Name-Email: bob@foo.bar
-      Expire-Date: 0
-      # Do a commit here, so that we can later print "done"
-      %commit
-      %echo done
-    EOF
-    gpg --batch --generate-key foo
-    rm $out/S.gpg-agent $out/S.gpg-agent.*
-    gpg --export bob@foo.bar -a > $out/pubkey.gpg
-  '');
+  gpgKeyring = import ./common/gpg-keyring.nix { inherit pkgs; };
 
   nspawnImages = (pkgs.runCommand "localhost" { buildInputs = [ pkgs.coreutils pkgs.gnupg ]; } ''
     mkdir -p $out
diff --git a/nixpkgs/nixos/tests/systemd-shutdown.nix b/nixpkgs/nixos/tests/systemd-shutdown.nix
index dad8167f198f..ca6754046f57 100644
--- a/nixpkgs/nixos/tests/systemd-shutdown.nix
+++ b/nixpkgs/nixos/tests/systemd-shutdown.nix
@@ -22,6 +22,6 @@ in {
     machine.wait_for_console_text("Unmounting '/oldroot'")
     machine.wait_for_console_text("${msg}")
     # Don't try to sync filesystems
-    machine.booted = False
+    machine.wait_for_shutdown()
   '';
 })
diff --git a/nixpkgs/nixos/tests/systemd-sysupdate.nix b/nixpkgs/nixos/tests/systemd-sysupdate.nix
new file mode 100644
index 000000000000..37811605dbb2
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-sysupdate.nix
@@ -0,0 +1,66 @@
+# Tests downloading a signed update aritfact from a server to a target machine.
+# This test does not rely on the `systemd.timer` units provided by the
+# `systemd-sysupdate` module but triggers the `systemd-sysupdate` service
+# manually to make the test more robust.
+
+{ lib, pkgs, ... }:
+
+let
+  gpgKeyring = import ./common/gpg-keyring.nix { inherit pkgs; };
+in
+{
+  name = "systemd-sysupdate";
+
+  meta.maintainers = with lib.maintainers; [ nikstur ];
+
+  nodes = {
+    server = { pkgs, ... }: {
+      networking.firewall.enable = false;
+      services.nginx = {
+        enable = true;
+        virtualHosts."server" = {
+          root = pkgs.runCommand "sysupdate-artifacts" { buildInputs = [ pkgs.gnupg ]; } ''
+            mkdir -p $out
+            cd $out
+
+            echo "nixos" > nixos_1.efi
+            sha256sum nixos_1.efi > SHA256SUMS
+
+            export GNUPGHOME="$(mktemp -d)"
+            cp -R ${gpgKeyring}/* $GNUPGHOME
+
+            gpg --batch --sign --detach-sign --output SHA256SUMS.gpg SHA256SUMS
+          '';
+        };
+      };
+    };
+
+    target = {
+      systemd.sysupdate = {
+        enable = true;
+        transfers = {
+          "uki" = {
+            Source = {
+              Type = "url-file";
+              Path = "http://server/";
+              MatchPattern = "nixos_@v.efi";
+            };
+            Target = {
+              Path = "/boot/EFI/Linux";
+              MatchPattern = "nixos_@v.efi";
+            };
+          };
+        };
+      };
+
+      environment.etc."systemd/import-pubring.gpg".source = "${gpgKeyring}/pubkey.gpg";
+    };
+  };
+
+  testScript = ''
+    server.wait_for_unit("nginx.service")
+
+    target.succeed("systemctl start systemd-sysupdate")
+    assert "nixos" in target.wait_until_succeeds("cat /boot/EFI/Linux/nixos_1.efi", timeout=5)
+  '';
+}
diff --git a/nixpkgs/nixos/tests/terminal-emulators.nix b/nixpkgs/nixos/tests/terminal-emulators.nix
index 4269d05056d8..6d76cc8e5741 100644
--- a/nixpkgs/nixos/tests/terminal-emulators.nix
+++ b/nixpkgs/nixos/tests/terminal-emulators.nix
@@ -35,6 +35,8 @@ let tests = {
 
       darktile.pkg = p: p.darktile;
 
+      deepin-terminal.pkg = p: p.deepin.deepin-terminal;
+
       eterm.pkg = p: p.eterm;
       eterm.executable = "Eterm";
       eterm.pinkValue = "#D40055";
@@ -72,6 +74,9 @@ let tests = {
       qterminal.pkg = p: p.lxqt.qterminal;
       qterminal.kill = true;
 
+      rio.pkg = p: p.rio;
+      rio.cmd = "rio -e $command";
+
       roxterm.pkg = p: p.roxterm;
       roxterm.cmd = "roxterm -e $command";
 
@@ -118,7 +123,7 @@ in mapAttrs (name: { pkg, executable ? name, cmd ? "SHELL=$command ${executable}
     maintainers = [ jjjollyjim ];
   };
 
-  machine = { pkgsInner, ... }:
+  nodes.machine = { pkgsInner, ... }:
 
   {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/tmate-ssh-server.nix b/nixpkgs/nixos/tests/tmate-ssh-server.nix
index e7f94db9bfcf..122434c505c1 100644
--- a/nixpkgs/nixos/tests/tmate-ssh-server.nix
+++ b/nixpkgs/nixos/tests/tmate-ssh-server.nix
@@ -24,6 +24,7 @@ in
         services.tmate-ssh-server = {
           enable = true;
           port = 2223;
+          openFirewall = true;
         };
       };
       client = { ... }: {
diff --git a/nixpkgs/nixos/tests/twingate.nix b/nixpkgs/nixos/tests/twingate.nix
new file mode 100644
index 000000000000..f8bede09d9f2
--- /dev/null
+++ b/nixpkgs/nixos/tests/twingate.nix
@@ -0,0 +1,14 @@
+{
+  name = "twingate";
+
+  nodes.machine.services.twingate.enable = true;
+
+  testScript = { nodes, ... }: ''
+    machine.wait_for_unit("twingate.service")
+    machine.succeed("twingate --version | grep '${nodes.machine.services.twingate.package.version}' >&2")
+    machine.succeed("twingate config log-level 'debug'")
+    machine.systemctl("restart twingate.service")
+    machine.succeed("grep 'debug' /etc/twingate/log_level.conf >&2")
+    machine.succeed("twingate config log-level | grep 'debug' >&2")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/typesense.nix b/nixpkgs/nixos/tests/typesense.nix
new file mode 100644
index 000000000000..4f07a2e194be
--- /dev/null
+++ b/nixpkgs/nixos/tests/typesense.nix
@@ -0,0 +1,23 @@
+import ./make-test-python.nix ({ pkgs, ... }: let
+  testPort = 8108;
+in {
+  name = "typesense";
+  meta.maintainers = with pkgs.lib.maintainers; [ oddlama ];
+
+  nodes.machine = { ... }: {
+    services.typesense = {
+      enable = true;
+      apiKeyFile = pkgs.writeText "typesense-api-key" "dummy";
+      settings.server = {
+        api-port = testPort;
+        api-address = "0.0.0.0";
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("typesense.service")
+    machine.wait_for_open_port(${toString testPort})
+    assert machine.succeed("curl --fail http://localhost:${toString testPort}/health") == '{"ok":true}'
+  '';
+})
diff --git a/nixpkgs/nixos/tests/virtualbox.nix b/nixpkgs/nixos/tests/virtualbox.nix
index 1ebd99f5d75d..062b125eb611 100644
--- a/nixpkgs/nixos/tests/virtualbox.nix
+++ b/nixpkgs/nixos/tests/virtualbox.nix
@@ -519,4 +519,4 @@ in mapAttrs (mkVBoxTest false vboxVMs) {
     destroy_vm_test1()
     destroy_vm_test2()
   '';
-} // (if enableUnfree then unfreeTests else {})
+} // (lib.optionalAttrs enableUnfree unfreeTests)
diff --git a/nixpkgs/nixos/tests/vscode-remote-ssh.nix b/nixpkgs/nixos/tests/vscode-remote-ssh.nix
new file mode 100644
index 000000000000..de7cc6badc9a
--- /dev/null
+++ b/nixpkgs/nixos/tests/vscode-remote-ssh.nix
@@ -0,0 +1,124 @@
+import ./make-test-python.nix ({ lib, ... }@args: let
+  pkgs = args.pkgs.extend (self: super: {
+    stdenv = super.stdenv.override {
+      config = super.config // {
+        allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
+          "vscode" "vscode-with-extensions" "vscode-extension-ms-vscode-remote-remote-ssh"
+        ];
+      };
+    };
+  });
+
+  inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
+
+  inherit (pkgs.vscode.passthru) rev vscodeServer;
+in {
+  name = "vscode-remote-ssh";
+  meta.maintainers = with lib.maintainers; [ Enzime ];
+
+  nodes = let
+    serverAddress = "192.168.0.2";
+    clientAddress = "192.168.0.1";
+  in {
+    server = { ... }: {
+      networking.interfaces.eth1.ipv4.addresses = [ { address = serverAddress; prefixLength = 24; } ];
+      services.openssh.enable = true;
+      users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
+      virtualisation.additionalPaths = with pkgs; [ patchelf bintools stdenv.cc.cc.lib ];
+    };
+    client = { ... }: {
+      imports = [ ./common/x11.nix ./common/user-account.nix ];
+      networking.interfaces.eth1.ipv4.addresses = [ { address = clientAddress; prefixLength = 24; } ];
+      networking.hosts.${serverAddress} = [ "server" ];
+      test-support.displayManager.auto.user = "alice";
+      environment.systemPackages = [
+        (pkgs.vscode-with-extensions.override {
+          vscodeExtensions = [
+            pkgs.vscode-extensions.ms-vscode-remote.remote-ssh
+          ];
+        })
+      ];
+    };
+  };
+
+  enableOCR = true;
+
+  testScript = let
+    jq = "${pkgs.jq}/bin/jq";
+
+    sshConfig = builtins.toFile "ssh.conf" ''
+      UserKnownHostsFile=/dev/null
+      StrictHostKeyChecking=no
+    '';
+
+    vscodeConfig = builtins.toFile "settings.json" ''
+      {
+        "window.zoomLevel": 1,
+        "security.workspace.trust.startupPrompt": "always"
+      }
+    '';
+  in ''
+    def connect_with_remote_ssh(screenshot, should_succeed):
+      print(f"connect_with_remote_ssh({screenshot=}, {should_succeed=})")
+
+      if server.execute("test -d ~/.vscode-server")[0] == 0:
+        server.succeed("rm -r ~/.vscode-server")
+
+      server.succeed("mkdir -p ~/.vscode-server/bin")
+      server.succeed("cp -r ${vscodeServer} ~/.vscode-server/bin/${rev}")
+
+      client.succeed("sudo -u alice code --remote=ssh-remote+root@server /root")
+      client.wait_for_window("Visual Studio Code")
+
+      client.wait_for_text("Do you trust the authors" if should_succeed else "Disconnected from SSH")
+      client.screenshot(screenshot)
+
+      if should_succeed:
+        # Press the Don't Trust button
+        client.send_key("tab")
+        client.send_key("tab")
+        client.send_key("tab")
+        client.send_key("\n")
+      else:
+        # Close the error dialog
+        client.send_key("esc")
+
+      # Don't send Ctrl-q too quickly otherwise it might not get sent to VS Code
+      client.sleep(1)
+      client.send_key("ctrl-q")
+      client.wait_until_fails("pidof code")
+
+
+    start_all()
+    server.wait_for_open_port(22)
+
+    VSCODE_COMMIT = server.execute("${jq} -r .commit ${pkgs.vscode}/lib/vscode/resources/app/product.json")[1].rstrip()
+    SERVER_COMMIT = server.execute("${jq} -r .commit ${vscodeServer}/product.json")[1].rstrip()
+
+    print(f"{VSCODE_COMMIT=} {SERVER_COMMIT=}")
+    assert VSCODE_COMMIT == SERVER_COMMIT, "VSCODE_COMMIT and SERVER_COMMIT do not match"
+
+    client.wait_until_succeeds("ping -c1 server")
+    client.succeed("sudo -u alice mkdir ~alice/.ssh")
+    client.succeed("sudo -u alice install -Dm 600 ${snakeOilPrivateKey} ~alice/.ssh/id_ecdsa")
+    client.succeed("sudo -u alice install ${sshConfig} ~alice/.ssh/config")
+    client.succeed("sudo -u alice install -Dm 644 ${vscodeConfig} ~alice/.config/Code/User/settings.json")
+
+    client.wait_for_x()
+    client.wait_for_file("~alice/.Xauthority")
+    client.succeed("xauth merge ~alice/.Xauthority")
+    # Move the mouse out of the way
+    client.succeed("${pkgs.xdotool}/bin/xdotool mousemove 0 0")
+
+    with subtest("fails to connect when nixpkgs isn't available"):
+      server.fail("nix-build '<nixpkgs>' -A hello")
+      connect_with_remote_ssh(screenshot="no_node_installed", should_succeed=False)
+      server.succeed("test -e ~/.vscode-server/bin/${rev}/node")
+      server.fail("~/.vscode-server/bin/${rev}/node -v")
+
+    with subtest("connects when server can patch Node"):
+      server.succeed("mkdir -p /nix/var/nix/profiles/per-user/root/channels")
+      server.succeed("ln -s ${pkgs.path} /nix/var/nix/profiles/per-user/root/channels/nixos")
+      connect_with_remote_ssh(screenshot="build_node_with_nix", should_succeed=True)
+  '';
+})
diff --git a/nixpkgs/nixos/tests/vscodium.nix b/nixpkgs/nixos/tests/vscodium.nix
index 3eda8b6cfb20..d817ce927ff8 100644
--- a/nixpkgs/nixos/tests/vscodium.nix
+++ b/nixpkgs/nixos/tests/vscodium.nix
@@ -8,7 +8,7 @@ let
       environment.variables.NIXOS_OZONE_WL = "1";
       environment.variables.DISPLAY = "do not use";
 
-      fonts.fonts = with pkgs; [ dejavu_fonts ];
+      fonts.packages = with pkgs; [ dejavu_fonts ];
     };
     xorg = { pkgs, ... }: {
       imports = [ ./common/user-account.nix ./common/x11.nix ];
diff --git a/nixpkgs/nixos/tests/web-apps/gotosocial.nix b/nixpkgs/nixos/tests/web-apps/gotosocial.nix
new file mode 100644
index 000000000000..6d279ab63a79
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/gotosocial.nix
@@ -0,0 +1,28 @@
+{ lib, ... }:
+{
+  name = "gotosocial";
+  meta.maintainers = with lib.maintainers; [ misuzu ];
+
+  nodes.machine = { pkgs, ... }: {
+    environment.systemPackages = [ pkgs.jq ];
+    services.gotosocial = {
+      enable = true;
+      setupPostgresqlDB = true;
+      settings = {
+        host = "localhost:8081";
+        port = 8081;
+      };
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("gotosocial.service")
+    machine.wait_for_unit("postgresql.service")
+    machine.wait_for_open_port(8081)
+
+    # check user registration via cli
+    machine.succeed("curl -sS -f http://localhost:8081/nodeinfo/2.0 | jq '.usage.users.total' | grep -q '^0$'")
+    machine.succeed("gotosocial-admin account create --username nickname --email email@example.com --password kurtz575VPeBgjVm")
+    machine.succeed("curl -sS -f http://localhost:8081/nodeinfo/2.0 | jq '.usage.users.total' | grep -q '^1$'")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/web-apps/peering-manager.nix b/nixpkgs/nixos/tests/web-apps/peering-manager.nix
index 56b7eebfadff..3f0acd560d13 100644
--- a/nixpkgs/nixos/tests/web-apps/peering-manager.nix
+++ b/nixpkgs/nixos/tests/web-apps/peering-manager.nix
@@ -34,7 +34,7 @@ import ../make-test-python.nix ({ lib, pkgs, ... }: {
             "sudo -u postgres psql -c 'ALTER USER \"peering-manager\" WITH SUPERUSER;'"
         )
         machine.succeed(
-            "cd ${nodes.machine.config.system.build.peeringManagerPkg}/opt/peering-manager ; peering-manager-manage test --no-input"
+            "cd ${nodes.machine.system.build.peeringManagerPkg}/opt/peering-manager ; peering-manager-manage test --no-input"
         )
   '';
 })
diff --git a/nixpkgs/nixos/tests/web-servers/static-web-server.nix b/nixpkgs/nixos/tests/web-servers/static-web-server.nix
new file mode 100644
index 000000000000..da1a9bdec5d2
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-servers/static-web-server.nix
@@ -0,0 +1,32 @@
+import ../make-test-python.nix ({ pkgs, lib, ... } : {
+  name = "static-web-server";
+  meta = {
+    maintainers = with lib.maintainers; [ mac-chaffee ];
+  };
+
+  nodes.machine = { pkgs, ... }: {
+    services.static-web-server = {
+      enable = true;
+      listen = "[::]:8080";
+      root = toString (pkgs.writeTextDir "nixos-test.html" ''
+        <h1>Hello NixOS!</h1>
+      '');
+      configuration = {
+        general = { directory-listing = true; };
+      };
+    };
+  };
+
+  testScript = ''
+    machine.start()
+    machine.wait_for_unit("static-web-server.socket")
+    machine.wait_for_open_port(8080)
+    # We don't use wait_until_succeeds() because we're testing socket
+    # activation which better work on the first request
+    response = machine.succeed("curl -fsS localhost:8080")
+    assert "nixos-test.html" in response, "The directory listing page did not include a link to our nixos-test.html file"
+    response = machine.succeed("curl -fsS localhost:8080/nixos-test.html")
+    assert "Hello NixOS!" in response
+    machine.wait_for_unit("static-web-server.service")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/wpa_supplicant.nix b/nixpkgs/nixos/tests/wpa_supplicant.nix
index a05a79e8367d..8c701ca7d5f7 100644
--- a/nixpkgs/nixos/tests/wpa_supplicant.nix
+++ b/nixpkgs/nixos/tests/wpa_supplicant.nix
@@ -2,63 +2,160 @@ import ./make-test-python.nix ({ pkgs, lib, ...}:
 {
   name = "wpa_supplicant";
   meta = with lib.maintainers; {
-    maintainers = [ rnhmjoj ];
+    maintainers = [ oddlama rnhmjoj ];
   };
 
-  nodes.machine = { ... }: {
-    imports = [ ../modules/profiles/minimal.nix ];
+  nodes = let
+    machineWithHostapd = extraConfigModule: { ... }: {
+      imports = [
+        ../modules/profiles/minimal.nix
+        extraConfigModule
+      ];
+
+      # add a virtual wlan interface
+      boot.kernelModules = [ "mac80211_hwsim" ];
+
+      # wireless access point
+      services.hostapd = {
+        enable = true;
+        radios.wlan0 = {
+          band = "2g";
+          countryCode = "US";
+          networks = {
+            wlan0 = {
+              ssid = "nixos-test-sae";
+              authentication = {
+                mode = "wpa3-sae";
+                saePasswords = [ { password = "reproducibility"; } ];
+              };
+              bssid = "02:00:00:00:00:00";
+            };
+            wlan0-1 = {
+              ssid = "nixos-test-mixed";
+              authentication = {
+                mode = "wpa3-sae-transition";
+                saeAddToMacAllow = true;
+                saePasswordsFile = pkgs.writeText "password" "reproducibility";
+                wpaPasswordFile = pkgs.writeText "password" "reproducibility";
+              };
+              bssid = "02:00:00:00:00:01";
+            };
+            wlan0-2 = {
+              ssid = "nixos-test-wpa2";
+              authentication = {
+                mode = "wpa2-sha256";
+                wpaPassword = "reproducibility";
+              };
+              bssid = "02:00:00:00:00:02";
+            };
+          };
+        };
+      };
 
-    # add a virtual wlan interface
-    boot.kernelModules = [ "mac80211_hwsim" ];
+      # wireless client
+      networking.wireless = {
+        # the override is needed because the wifi is
+        # disabled with mkVMOverride in qemu-vm.nix.
+        enable = lib.mkOverride 0 true;
+        userControlled.enable = true;
+        interfaces = [ "wlan1" ];
+        fallbackToWPA2 = lib.mkDefault true;
+
+        # networks will be added on-demand below for the specific
+        # network that should be tested
+
+        # secrets
+        environmentFile = pkgs.writeText "wpa-secrets" ''
+          PSK_NIXOS_TEST="reproducibility"
+        '';
+      };
+    };
+  in {
+    basic = { ... }: {
+      imports = [ ../modules/profiles/minimal.nix ];
+
+      # add a virtual wlan interface
+      boot.kernelModules = [ "mac80211_hwsim" ];
+
+      # wireless client
+      networking.wireless = {
+        # the override is needed because the wifi is
+        # disabled with mkVMOverride in qemu-vm.nix.
+        enable = lib.mkOverride 0 true;
+        userControlled.enable = true;
+        interfaces = [ "wlan1" ];
+        fallbackToWPA2 = true;
+
+        networks = {
+          # test WPA2 fallback
+          mixed-wpa = {
+            psk = "password";
+            authProtocols = [ "WPA-PSK" "SAE" ];
+          };
+          sae-only = {
+            psk = "password";
+            authProtocols = [ "SAE" ];
+          };
+
+          # secrets substitution test cases
+          test1.psk = "@PSK_VALID@";              # should be replaced
+          test2.psk = "@PSK_SPECIAL@";            # should be replaced
+          test3.psk = "@PSK_MISSING@";            # should not be replaced
+          test4.psk = "P@ssowrdWithSome@tSymbol"; # should not be replaced
+        };
 
-    # wireless access point
-    services.hostapd = {
-      enable = true;
-      wpa = true;
-      interface = "wlan0";
-      ssid = "nixos-test";
-      wpaPassphrase = "reproducibility";
+        # secrets
+        environmentFile = pkgs.writeText "wpa-secrets" ''
+          PSK_VALID="S0m3BadP4ssw0rd";
+          # taken from https://github.com/minimaxir/big-list-of-naughty-strings
+          PSK_SPECIAL=",./;'[]\-= <>?:\"{}|_+ !@#$%^\&*()`~";
+        '';
+      };
     };
 
-    # wireless client
-    networking.wireless = {
-      # the override is needed because the wifi is
-      # disabled with mkVMOverride in qemu-vm.nix.
-      enable = lib.mkOverride 0 true;
-      userControlled.enable = true;
-      interfaces = [ "wlan1" ];
-      fallbackToWPA2 = true;
-
-      networks = {
-        # test WPA2 fallback
-        mixed-wpa = {
-          psk = "password";
-          authProtocols = [ "WPA-PSK" "SAE" ];
-        };
-        sae-only = {
-          psk = "password";
+    # Test connecting to the SAE-only hotspot using SAE
+    machineSae = machineWithHostapd {
+      networking.wireless = {
+        fallbackToWPA2 = false;
+        networks.nixos-test-sae = {
+          psk = "@PSK_NIXOS_TEST@";
           authProtocols = [ "SAE" ];
         };
+      };
+    };
 
-        # test network
-        nixos-test.psk = "@PSK_NIXOS_TEST@";
-
-        # secrets substitution test cases
-        test1.psk = "@PSK_VALID@";              # should be replaced
-        test2.psk = "@PSK_SPECIAL@";            # should be replaced
-        test3.psk = "@PSK_MISSING@";            # should not be replaced
-        test4.psk = "P@ssowrdWithSome@tSymbol"; # should not be replaced
+    # Test connecting to the SAE and WPA2 mixed hotspot using SAE
+    machineMixedUsingSae = machineWithHostapd {
+      networking.wireless = {
+        fallbackToWPA2 = false;
+        networks.nixos-test-mixed = {
+          psk = "@PSK_NIXOS_TEST@";
+          authProtocols = [ "SAE" ];
+        };
       };
+    };
 
-      # secrets
-      environmentFile = pkgs.writeText "wpa-secrets" ''
-        PSK_NIXOS_TEST="reproducibility"
-        PSK_VALID="S0m3BadP4ssw0rd";
-        # taken from https://github.com/minimaxir/big-list-of-naughty-strings
-        PSK_SPECIAL=",./;'[]\-= <>?:\"{}|_+ !@#$%^\&*()`~";
-      '';
+    # Test connecting to the SAE and WPA2 mixed hotspot using WPA2
+    machineMixedUsingWpa2 = machineWithHostapd {
+      networking.wireless = {
+        fallbackToWPA2 = true;
+        networks.nixos-test-mixed = {
+          psk = "@PSK_NIXOS_TEST@";
+          authProtocols = [ "WPA-PSK-SHA256" ];
+        };
+      };
     };
 
+    # Test connecting to the WPA2 legacy hotspot using WPA2
+    machineWpa2 = machineWithHostapd {
+      networking.wireless = {
+        fallbackToWPA2 = true;
+        networks.nixos-test-wpa2 = {
+          psk = "@PSK_NIXOS_TEST@";
+          authProtocols = [ "WPA-PSK-SHA256" ];
+        };
+      };
+    };
   };
 
   testScript =
@@ -66,30 +163,47 @@ import ./make-test-python.nix ({ pkgs, lib, ...}:
       config_file = "/run/wpa_supplicant/wpa_supplicant.conf"
 
       with subtest("Configuration file is inaccessible to other users"):
-          machine.wait_for_file(config_file)
-          machine.fail(f"sudo -u nobody ls {config_file}")
+          basic.wait_for_file(config_file)
+          basic.fail(f"sudo -u nobody ls {config_file}")
 
       with subtest("Secrets variables have been substituted"):
-          machine.fail(f"grep -q @PSK_VALID@ {config_file}")
-          machine.fail(f"grep -q @PSK_SPECIAL@ {config_file}")
-          machine.succeed(f"grep -q @PSK_MISSING@ {config_file}")
-          machine.succeed(f"grep -q P@ssowrdWithSome@tSymbol {config_file}")
+          basic.fail(f"grep -q @PSK_VALID@ {config_file}")
+          basic.fail(f"grep -q @PSK_SPECIAL@ {config_file}")
+          basic.succeed(f"grep -q @PSK_MISSING@ {config_file}")
+          basic.succeed(f"grep -q P@ssowrdWithSome@tSymbol {config_file}")
 
       with subtest("WPA2 fallbacks have been generated"):
-          assert int(machine.succeed(f"grep -c sae-only {config_file}")) == 1
-          assert int(machine.succeed(f"grep -c mixed-wpa {config_file}")) == 2
+          assert int(basic.succeed(f"grep -c sae-only {config_file}")) == 1
+          assert int(basic.succeed(f"grep -c mixed-wpa {config_file}")) == 2
 
       # save file for manual inspection
-      machine.copy_from_vm(config_file)
+      basic.copy_from_vm(config_file)
 
       with subtest("Daemon is running and accepting connections"):
-          machine.wait_for_unit("wpa_supplicant-wlan1.service")
-          status = machine.succeed("wpa_cli -i wlan1 status")
+          basic.wait_for_unit("wpa_supplicant-wlan1.service")
+          status = basic.succeed("wpa_cli -i wlan1 status")
           assert "Failed to connect" not in status, \
                  "Failed to connect to the daemon"
 
-      with subtest("Daemon can connect to the access point"):
-          machine.wait_until_succeeds(
+      machineSae.wait_for_unit("hostapd.service")
+      machineSae.copy_from_vm("/run/hostapd/wlan0.hostapd.conf")
+      with subtest("Daemon can connect to the SAE access point using SAE"):
+          machineSae.wait_until_succeeds(
+            "wpa_cli -i wlan1 status | grep -q wpa_state=COMPLETED"
+          )
+
+      with subtest("Daemon can connect to the SAE and WPA2 mixed access point using SAE"):
+          machineMixedUsingSae.wait_until_succeeds(
+            "wpa_cli -i wlan1 status | grep -q wpa_state=COMPLETED"
+          )
+
+      with subtest("Daemon can connect to the SAE and WPA2 mixed access point using WPA2"):
+          machineMixedUsingWpa2.wait_until_succeeds(
+            "wpa_cli -i wlan1 status | grep -q wpa_state=COMPLETED"
+          )
+
+      with subtest("Daemon can connect to the WPA2 access point using WPA2"):
+          machineWpa2.wait_until_succeeds(
             "wpa_cli -i wlan1 status | grep -q wpa_state=COMPLETED"
           )
     '';