about summary refs log tree commit diff
path: root/nixpkgs/nixos/tests
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2022-12-06 19:57:55 +0000
committerAlyssa Ross <hi@alyssa.is>2023-02-08 13:48:30 +0000
commitbf3aadfdd39aa197e18bade671fab6726349ffa4 (patch)
tree698567af766ed441d757b57a7b21e68d4a342a2b /nixpkgs/nixos/tests
parentf4afc5a01d9539ce09e47494e679c51f80723d07 (diff)
parent99665eb45f58d959d2cb9e49ddb960c79d596f33 (diff)
downloadnixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar.gz
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar.bz2
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar.lz
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar.xz
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.tar.zst
nixlib-bf3aadfdd39aa197e18bade671fab6726349ffa4.zip
Merge commit '99665eb45f58d959d2cb9e49ddb960c79d596f33'
Diffstat (limited to 'nixpkgs/nixos/tests')
-rw-r--r--nixpkgs/nixos/tests/3proxy.nix6
-rw-r--r--nixpkgs/nixos/tests/acme.nix2
-rw-r--r--nixpkgs/nixos/tests/aesmd.nix2
-rw-r--r--nixpkgs/nixos/tests/agda.nix2
-rw-r--r--nixpkgs/nixos/tests/airsonic.nix5
-rw-r--r--nixpkgs/nixos/tests/all-terminfo.nix31
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix77
-rw-r--r--nixpkgs/nixos/tests/amazon-init-shell.nix2
-rw-r--r--nixpkgs/nixos/tests/apfs.nix2
-rw-r--r--nixpkgs/nixos/tests/apparmor.nix2
-rw-r--r--nixpkgs/nixos/tests/atd.nix2
-rw-r--r--nixpkgs/nixos/tests/atop.nix20
-rw-r--r--nixpkgs/nixos/tests/auth-mysql.nix177
-rw-r--r--nixpkgs/nixos/tests/bazarr.nix2
-rw-r--r--nixpkgs/nixos/tests/bcachefs.nix4
-rw-r--r--nixpkgs/nixos/tests/beanstalkd.nix2
-rw-r--r--nixpkgs/nixos/tests/bees.nix2
-rw-r--r--nixpkgs/nixos/tests/bind.nix2
-rw-r--r--nixpkgs/nixos/tests/bitcoind.nix6
-rw-r--r--nixpkgs/nixos/tests/blockbook-frontend.nix2
-rw-r--r--nixpkgs/nixos/tests/boot-stage1.nix2
-rw-r--r--nixpkgs/nixos/tests/botamusique.nix4
-rw-r--r--nixpkgs/nixos/tests/bpf.nix2
-rw-r--r--nixpkgs/nixos/tests/breitbandmessung.nix2
-rw-r--r--nixpkgs/nixos/tests/brscan5.nix2
-rw-r--r--nixpkgs/nixos/tests/btrbk-no-timer.nix37
-rw-r--r--nixpkgs/nixos/tests/buildkite-agents.nix2
-rw-r--r--nixpkgs/nixos/tests/caddy.nix8
-rw-r--r--nixpkgs/nixos/tests/cage.nix2
-rw-r--r--nixpkgs/nixos/tests/cagebreak.nix2
-rw-r--r--nixpkgs/nixos/tests/cfssl.nix2
-rw-r--r--nixpkgs/nixos/tests/chromium.nix14
-rw-r--r--nixpkgs/nixos/tests/clickhouse.nix2
-rw-r--r--nixpkgs/nixos/tests/cloud-init.nix2
-rw-r--r--nixpkgs/nixos/tests/cntr.nix2
-rw-r--r--nixpkgs/nixos/tests/collectd.nix9
-rw-r--r--nixpkgs/nixos/tests/common/lxd/config.yaml24
-rw-r--r--nixpkgs/nixos/tests/containers-bridge.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-custom-pkgs.nix4
-rw-r--r--nixpkgs/nixos/tests/containers-ephemeral.nix8
-rw-r--r--nixpkgs/nixos/tests/containers-extra_veth.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-hosts.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-imperative.nix17
-rw-r--r--nixpkgs/nixos/tests/containers-ip.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-names.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-nested.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-portforward.nix2
-rw-r--r--nixpkgs/nixos/tests/containers-tmpfs.nix12
-rw-r--r--nixpkgs/nixos/tests/convos.nix4
-rw-r--r--nixpkgs/nixos/tests/couchdb.nix2
-rw-r--r--nixpkgs/nixos/tests/cryptpad.nix18
-rw-r--r--nixpkgs/nixos/tests/custom-ca.nix196
-rw-r--r--nixpkgs/nixos/tests/deluge.nix2
-rw-r--r--nixpkgs/nixos/tests/disable-installer-tools.nix2
-rw-r--r--nixpkgs/nixos/tests/discourse.nix1
-rw-r--r--nixpkgs/nixos/tests/dnsdist.nix2
-rw-r--r--nixpkgs/nixos/tests/doas.nix2
-rw-r--r--nixpkgs/nixos/tests/docker-edge.nix49
-rw-r--r--nixpkgs/nixos/tests/docker-registry.nix2
-rw-r--r--nixpkgs/nixos/tests/docker-tools-cross.nix10
-rw-r--r--nixpkgs/nixos/tests/docker-tools.nix11
-rw-r--r--nixpkgs/nixos/tests/documize.nix8
-rw-r--r--nixpkgs/nixos/tests/domination.nix2
-rw-r--r--nixpkgs/nixos/tests/dovecot.nix2
-rw-r--r--nixpkgs/nixos/tests/ecryptfs.nix12
-rw-r--r--nixpkgs/nixos/tests/emacs-daemon.nix4
-rw-r--r--nixpkgs/nixos/tests/enlightenment.nix2
-rw-r--r--nixpkgs/nixos/tests/env.nix2
-rw-r--r--nixpkgs/nixos/tests/envoy.nix33
-rw-r--r--nixpkgs/nixos/tests/etebase-server.nix2
-rw-r--r--nixpkgs/nixos/tests/etesync-dav.nix2
-rw-r--r--nixpkgs/nixos/tests/extra-python-packages.nix13
-rw-r--r--nixpkgs/nixos/tests/fancontrol.nix2
-rw-r--r--nixpkgs/nixos/tests/fcitx/default.nix3
-rw-r--r--nixpkgs/nixos/tests/fenics.nix2
-rw-r--r--nixpkgs/nixos/tests/firefox.nix27
-rw-r--r--nixpkgs/nixos/tests/fish.nix2
-rw-r--r--nixpkgs/nixos/tests/fluentd.nix2
-rw-r--r--nixpkgs/nixos/tests/fontconfig-default-fonts.nix2
-rw-r--r--nixpkgs/nixos/tests/freeswitch.nix2
-rw-r--r--nixpkgs/nixos/tests/fsck.nix2
-rw-r--r--nixpkgs/nixos/tests/ft2-clone.nix2
-rw-r--r--nixpkgs/nixos/tests/geth.nix2
-rw-r--r--nixpkgs/nixos/tests/gitlab.nix323
-rw-r--r--nixpkgs/nixos/tests/gitolite.nix2
-rw-r--r--nixpkgs/nixos/tests/gnome-xorg.nix2
-rw-r--r--nixpkgs/nixos/tests/gnome.nix2
-rw-r--r--nixpkgs/nixos/tests/gocd-agent.nix2
-rw-r--r--nixpkgs/nixos/tests/gotify-server.nix2
-rw-r--r--nixpkgs/nixos/tests/grafana-agent.nix32
-rw-r--r--nixpkgs/nixos/tests/graphite.nix12
-rw-r--r--nixpkgs/nixos/tests/graylog.nix2
-rw-r--r--nixpkgs/nixos/tests/grocy.nix2
-rw-r--r--nixpkgs/nixos/tests/grub.nix2
-rw-r--r--nixpkgs/nixos/tests/hadoop/default.nix1
-rw-r--r--nixpkgs/nixos/tests/hadoop/hbase.nix84
-rw-r--r--nixpkgs/nixos/tests/hadoop/yarn.nix2
-rw-r--r--nixpkgs/nixos/tests/hardened.nix11
-rw-r--r--nixpkgs/nixos/tests/haste-server.nix23
-rw-r--r--nixpkgs/nixos/tests/hbase.nix30
-rw-r--r--nixpkgs/nixos/tests/hedgedoc.nix4
-rw-r--r--nixpkgs/nixos/tests/herbstluftwm.nix2
-rw-r--r--nixpkgs/nixos/tests/hibernate.nix11
-rw-r--r--nixpkgs/nixos/tests/hitch/default.nix2
-rw-r--r--nixpkgs/nixos/tests/hocker-fetchdocker/default.nix2
-rw-r--r--nixpkgs/nixos/tests/hockeypuck.nix2
-rw-r--r--nixpkgs/nixos/tests/home-assistant.nix56
-rw-r--r--nixpkgs/nixos/tests/hostname.nix2
-rw-r--r--nixpkgs/nixos/tests/hound.nix2
-rw-r--r--nixpkgs/nixos/tests/hydra/default.nix4
-rw-r--r--nixpkgs/nixos/tests/i3wm.nix2
-rw-r--r--nixpkgs/nixos/tests/ihatemoney/default.nix11
-rw-r--r--nixpkgs/nixos/tests/incron.nix2
-rw-r--r--nixpkgs/nixos/tests/initrd-network.nix2
-rw-r--r--nixpkgs/nixos/tests/initrd-secrets.nix2
-rw-r--r--nixpkgs/nixos/tests/input-remapper.nix2
-rw-r--r--nixpkgs/nixos/tests/installed-tests/default.nix4
-rw-r--r--nixpkgs/nixos/tests/installed-tests/flatpak-builder.nix1
-rw-r--r--nixpkgs/nixos/tests/installed-tests/geocode-glib.nix13
-rw-r--r--nixpkgs/nixos/tests/installed-tests/power-profiles-daemon.nix9
-rw-r--r--nixpkgs/nixos/tests/installer-systemd-stage-1.nix33
-rw-r--r--nixpkgs/nixos/tests/installer.nix95
-rw-r--r--nixpkgs/nixos/tests/invidious.nix2
-rw-r--r--nixpkgs/nixos/tests/ipfs.nix17
-rw-r--r--nixpkgs/nixos/tests/isso.nix4
-rw-r--r--nixpkgs/nixos/tests/jellyfin.nix26
-rw-r--r--nixpkgs/nixos/tests/jenkins.nix23
-rw-r--r--nixpkgs/nixos/tests/jibri.nix2
-rw-r--r--nixpkgs/nixos/tests/jitsi-meet.nix3
-rw-r--r--nixpkgs/nixos/tests/k3s-single-node-docker.nix84
-rw-r--r--nixpkgs/nixos/tests/k3s/default.nix9
-rw-r--r--nixpkgs/nixos/tests/k3s/multi-node.nix137
-rw-r--r--nixpkgs/nixos/tests/k3s/single-node.nix (renamed from nixpkgs/nixos/tests/k3s-single-node.nix)18
-rw-r--r--nixpkgs/nixos/tests/kanidm.nix75
-rw-r--r--nixpkgs/nixos/tests/kbd-setfont-decompress.nix2
-rw-r--r--nixpkgs/nixos/tests/kbd-update-search-paths-patch.nix2
-rw-r--r--nixpkgs/nixos/tests/kea.nix2
-rw-r--r--nixpkgs/nixos/tests/keepassxc.nix6
-rw-r--r--nixpkgs/nixos/tests/kerberos/heimdal.nix2
-rw-r--r--nixpkgs/nixos/tests/kerberos/mit.nix2
-rw-r--r--nixpkgs/nixos/tests/kernel-generic.nix3
-rw-r--r--nixpkgs/nixos/tests/kernel-latest-ath-user-regd.nix2
-rw-r--r--nixpkgs/nixos/tests/keter.nix42
-rw-r--r--nixpkgs/nixos/tests/kexec.nix59
-rw-r--r--nixpkgs/nixos/tests/keycloak.nix26
-rw-r--r--nixpkgs/nixos/tests/komga.nix22
-rw-r--r--nixpkgs/nixos/tests/krb5/deprecated-config.nix2
-rw-r--r--nixpkgs/nixos/tests/krb5/example-config.nix2
-rw-r--r--nixpkgs/nixos/tests/ksm.nix2
-rw-r--r--nixpkgs/nixos/tests/kubernetes/dns.nix12
-rw-r--r--nixpkgs/nixos/tests/kubernetes/rbac.nix6
-rw-r--r--nixpkgs/nixos/tests/libinput.nix2
-rw-r--r--nixpkgs/nixos/tests/libreddit.nix14
-rw-r--r--nixpkgs/nixos/tests/libresprite.nix2
-rw-r--r--nixpkgs/nixos/tests/libuiohook.nix21
-rw-r--r--nixpkgs/nixos/tests/lidarr.nix2
-rw-r--r--nixpkgs/nixos/tests/lightdm.nix2
-rw-r--r--nixpkgs/nixos/tests/lighttpd.nix21
-rw-r--r--nixpkgs/nixos/tests/limesurvey.nix2
-rw-r--r--nixpkgs/nixos/tests/litestream.nix2
-rw-r--r--nixpkgs/nixos/tests/login.nix8
-rw-r--r--nixpkgs/nixos/tests/logrotate.nix135
-rw-r--r--nixpkgs/nixos/tests/loki.nix2
-rw-r--r--nixpkgs/nixos/tests/lorri/default.nix2
-rw-r--r--nixpkgs/nixos/tests/lvm2/default.nix45
-rw-r--r--nixpkgs/nixos/tests/lvm2/systemd-stage-1.nix104
-rw-r--r--nixpkgs/nixos/tests/lvm2/thinpool.nix32
-rw-r--r--nixpkgs/nixos/tests/lvm2/vdo.nix27
-rw-r--r--nixpkgs/nixos/tests/lxd-image-server.nix65
-rw-r--r--nixpkgs/nixos/tests/lxd-image.nix89
-rw-r--r--nixpkgs/nixos/tests/lxd-nftables.nix2
-rw-r--r--nixpkgs/nixos/tests/lxd.nix105
-rw-r--r--nixpkgs/nixos/tests/maddy.nix2
-rw-r--r--nixpkgs/nixos/tests/maestral.nix72
-rw-r--r--nixpkgs/nixos/tests/magnetico.nix2
-rw-r--r--nixpkgs/nixos/tests/mailcatcher.nix13
-rw-r--r--nixpkgs/nixos/tests/mailhog.nix6
-rw-r--r--nixpkgs/nixos/tests/matomo.nix2
-rw-r--r--nixpkgs/nixos/tests/matrix/appservice-irc.nix (renamed from nixpkgs/nixos/tests/matrix-appservice-irc.nix)8
-rw-r--r--nixpkgs/nixos/tests/matrix/conduit.nix (renamed from nixpkgs/nixos/tests/matrix-conduit.nix)2
-rw-r--r--nixpkgs/nixos/tests/matrix/dendrite.nix (renamed from nixpkgs/nixos/tests/dendrite.nix)6
-rw-r--r--nixpkgs/nixos/tests/matrix/mjolnir.nix1
-rw-r--r--nixpkgs/nixos/tests/matrix/pantalaimon.nix2
-rw-r--r--nixpkgs/nixos/tests/matrix/synapse.nix (renamed from nixpkgs/nixos/tests/matrix-synapse.nix)4
-rw-r--r--nixpkgs/nixos/tests/mediawiki.nix2
-rw-r--r--nixpkgs/nixos/tests/meilisearch.nix15
-rw-r--r--nixpkgs/nixos/tests/memcached.nix2
-rw-r--r--nixpkgs/nixos/tests/mimir.nix50
-rw-r--r--nixpkgs/nixos/tests/minecraft-server.nix1
-rw-r--r--nixpkgs/nixos/tests/minidlna.nix2
-rw-r--r--nixpkgs/nixos/tests/misc.nix2
-rw-r--r--nixpkgs/nixos/tests/mod_perl.nix2
-rw-r--r--nixpkgs/nixos/tests/mongodb.nix4
-rw-r--r--nixpkgs/nixos/tests/moodle.nix2
-rw-r--r--nixpkgs/nixos/tests/mosquitto.nix28
-rw-r--r--nixpkgs/nixos/tests/mtp.nix109
-rw-r--r--nixpkgs/nixos/tests/musescore.nix2
-rw-r--r--nixpkgs/nixos/tests/mysql/mysql-autobackup.nix2
-rw-r--r--nixpkgs/nixos/tests/mysql/mysql-backup.nix1
-rw-r--r--nixpkgs/nixos/tests/n8n.nix4
-rw-r--r--nixpkgs/nixos/tests/nagios.nix2
-rw-r--r--nixpkgs/nixos/tests/nar-serve.nix2
-rw-r--r--nixpkgs/nixos/tests/navidrome.nix4
-rw-r--r--nixpkgs/nixos/tests/nbd.nix16
-rw-r--r--nixpkgs/nixos/tests/ncdns.nix19
-rw-r--r--nixpkgs/nixos/tests/neo4j.nix14
-rw-r--r--nixpkgs/nixos/tests/networking.nix102
-rw-r--r--nixpkgs/nixos/tests/nextcloud/default.nix6
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix118
-rw-r--r--nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix23
-rw-r--r--nixpkgs/nixos/tests/nghttpx.nix4
-rw-r--r--nixpkgs/nixos/tests/nginx-auth.nix8
-rw-r--r--nixpkgs/nixos/tests/nginx-etag.nix4
-rw-r--r--nixpkgs/nixos/tests/nginx-http3.nix93
-rw-r--r--nixpkgs/nixos/tests/nginx-modsecurity.nix2
-rw-r--r--nixpkgs/nixos/tests/nginx-pubhtml.nix2
-rw-r--r--nixpkgs/nixos/tests/nginx-sandbox.nix2
-rw-r--r--nixpkgs/nixos/tests/nginx-sso.nix2
-rw-r--r--nixpkgs/nixos/tests/nginx-variants.nix2
-rw-r--r--nixpkgs/nixos/tests/nitter.nix2
-rw-r--r--nixpkgs/nixos/tests/nix-ld.nix2
-rw-r--r--nixpkgs/nixos/tests/nix-serve.nix2
-rw-r--r--nixpkgs/nixos/tests/nixops/default.nix2
-rw-r--r--nixpkgs/nixos/tests/nixos-generate-config.nix2
-rw-r--r--nixpkgs/nixos/tests/node-red.nix2
-rw-r--r--nixpkgs/nixos/tests/non-default-filesystems.nix54
-rw-r--r--nixpkgs/nixos/tests/noto-fonts.nix2
-rw-r--r--nixpkgs/nixos/tests/novacomd.nix2
-rw-r--r--nixpkgs/nixos/tests/oh-my-zsh.nix2
-rw-r--r--nixpkgs/nixos/tests/ombi.nix2
-rw-r--r--nixpkgs/nixos/tests/openldap.nix232
-rw-r--r--nixpkgs/nixos/tests/openssh.nix18
-rw-r--r--nixpkgs/nixos/tests/opentabletdriver.nix2
-rw-r--r--nixpkgs/nixos/tests/os-prober.nix25
-rw-r--r--nixpkgs/nixos/tests/osrm-backend.nix2
-rw-r--r--nixpkgs/nixos/tests/overlayfs.nix2
-rw-r--r--nixpkgs/nixos/tests/packagekit.nix2
-rw-r--r--nixpkgs/nixos/tests/pam/pam-oath-login.nix26
-rw-r--r--nixpkgs/nixos/tests/pam/pam-u2f.nix5
-rw-r--r--nixpkgs/nixos/tests/pam/pam-ussh.nix70
-rw-r--r--nixpkgs/nixos/tests/pantheon.nix2
-rw-r--r--nixpkgs/nixos/tests/paperless.nix (renamed from nixpkgs/nixos/tests/paperless-ng.nix)25
-rw-r--r--nixpkgs/nixos/tests/pass-secret-service.nix69
-rw-r--r--nixpkgs/nixos/tests/patroni.nix204
-rw-r--r--nixpkgs/nixos/tests/pdns-recursor.nix7
-rw-r--r--nixpkgs/nixos/tests/pgadmin4.nix98
-rw-r--r--nixpkgs/nixos/tests/php/fpm.nix2
-rw-r--r--nixpkgs/nixos/tests/php/httpd.nix2
-rw-r--r--nixpkgs/nixos/tests/php/pcre.nix2
-rw-r--r--nixpkgs/nixos/tests/pict-rs.nix4
-rw-r--r--nixpkgs/nixos/tests/plasma5-systemd-start.nix2
-rw-r--r--nixpkgs/nixos/tests/plasma5.nix10
-rw-r--r--nixpkgs/nixos/tests/plausible.nix2
-rw-r--r--nixpkgs/nixos/tests/pleroma.nix4
-rw-r--r--nixpkgs/nixos/tests/plikd.nix4
-rw-r--r--nixpkgs/nixos/tests/plotinus.nix2
-rw-r--r--nixpkgs/nixos/tests/podgrab.nix4
-rw-r--r--nixpkgs/nixos/tests/polaris.nix31
-rw-r--r--nixpkgs/nixos/tests/postfix-raise-smtpd-tls-security-level.nix2
-rw-r--r--nixpkgs/nixos/tests/postfix.nix2
-rw-r--r--nixpkgs/nixos/tests/postgresql-wal-receiver.nix2
-rw-r--r--nixpkgs/nixos/tests/postgresql.nix2
-rw-r--r--nixpkgs/nixos/tests/power-profiles-daemon.nix2
-rw-r--r--nixpkgs/nixos/tests/powerdns.nix4
-rw-r--r--nixpkgs/nixos/tests/predictable-interface-names.nix2
-rw-r--r--nixpkgs/nixos/tests/privacyidea.nix4
-rw-r--r--nixpkgs/nixos/tests/privoxy.nix10
-rw-r--r--nixpkgs/nixos/tests/prometheus-exporters.nix22
-rw-r--r--nixpkgs/nixos/tests/prowlarr.nix2
-rw-r--r--nixpkgs/nixos/tests/pt2-clone.nix2
-rw-r--r--nixpkgs/nixos/tests/public-inbox.nix227
-rw-r--r--nixpkgs/nixos/tests/pulseaudio.nix2
-rw-r--r--nixpkgs/nixos/tests/pykms.nix14
-rw-r--r--nixpkgs/nixos/tests/qboot.nix2
-rw-r--r--nixpkgs/nixos/tests/rabbitmq.nix4
-rw-r--r--nixpkgs/nixos/tests/radarr.nix2
-rw-r--r--nixpkgs/nixos/tests/radicale.nix2
-rw-r--r--nixpkgs/nixos/tests/rasdaemon.nix2
-rw-r--r--nixpkgs/nixos/tests/redis.nix2
-rw-r--r--nixpkgs/nixos/tests/redmine.nix2
-rw-r--r--nixpkgs/nixos/tests/restart-by-activation-script.nix2
-rw-r--r--nixpkgs/nixos/tests/restic.nix200
-rw-r--r--nixpkgs/nixos/tests/retroarch.nix2
-rw-r--r--nixpkgs/nixos/tests/riak.nix18
-rw-r--r--nixpkgs/nixos/tests/rspamd.nix10
-rw-r--r--nixpkgs/nixos/tests/rsyslogd.nix4
-rw-r--r--nixpkgs/nixos/tests/sabnzbd.nix2
-rw-r--r--nixpkgs/nixos/tests/sanoid.nix6
-rw-r--r--nixpkgs/nixos/tests/schleuder.nix128
-rw-r--r--nixpkgs/nixos/tests/sddm.nix4
-rw-r--r--nixpkgs/nixos/tests/shadow.nix24
-rw-r--r--nixpkgs/nixos/tests/shattered-pixel-dungeon.nix2
-rw-r--r--nixpkgs/nixos/tests/shiori.nix2
-rw-r--r--nixpkgs/nixos/tests/signal-desktop.nix4
-rw-r--r--nixpkgs/nixos/tests/simple.nix2
-rw-r--r--nixpkgs/nixos/tests/snapcast.nix1
-rw-r--r--nixpkgs/nixos/tests/snapper.nix2
-rw-r--r--nixpkgs/nixos/tests/soapui.nix2
-rw-r--r--nixpkgs/nixos/tests/solr.nix2
-rw-r--r--nixpkgs/nixos/tests/sonarr.nix2
-rw-r--r--nixpkgs/nixos/tests/sourcehut.nix44
-rw-r--r--nixpkgs/nixos/tests/sssd-ldap.nix8
-rw-r--r--nixpkgs/nixos/tests/sssd.nix2
-rw-r--r--nixpkgs/nixos/tests/starship.nix2
-rw-r--r--nixpkgs/nixos/tests/step-ca.nix1
-rw-r--r--nixpkgs/nixos/tests/stunnel.nix174
-rw-r--r--nixpkgs/nixos/tests/swap-partition.nix48
-rw-r--r--nixpkgs/nixos/tests/sway.nix8
-rw-r--r--nixpkgs/nixos/tests/sympa.nix4
-rw-r--r--nixpkgs/nixos/tests/syncthing-init.nix2
-rw-r--r--nixpkgs/nixos/tests/syncthing-relay.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-analyze.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-binfmt.nix6
-rw-r--r--nixpkgs/nixos/tests/systemd-boot.nix18
-rw-r--r--nixpkgs/nixos/tests/systemd-confinement.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-coredump.nix44
-rw-r--r--nixpkgs/nixos/tests/systemd-cryptenroll.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-escaping.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-btrfs-raid.nix45
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix53
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-luks-password.nix48
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-simple.nix44
-rw-r--r--nixpkgs/nixos/tests/systemd-initrd-swraid.nix50
-rw-r--r--nixpkgs/nixos/tests/systemd-journal.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-machinectl.nix26
-rw-r--r--nixpkgs/nixos/tests/systemd-misc.nix2
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd-vrf.nix65
-rw-r--r--nixpkgs/nixos/tests/systemd-networkd.nix10
-rw-r--r--nixpkgs/nixos/tests/systemd-nspawn.nix19
-rw-r--r--nixpkgs/nixos/tests/systemd-shutdown.nix26
-rw-r--r--nixpkgs/nixos/tests/systemd.nix6
-rw-r--r--nixpkgs/nixos/tests/taskserver.nix1
-rw-r--r--nixpkgs/nixos/tests/telegraf.nix2
-rw-r--r--nixpkgs/nixos/tests/teleport.nix12
-rw-r--r--nixpkgs/nixos/tests/terminal-emulators.nix1
-rw-r--r--nixpkgs/nixos/tests/tinywl.nix2
-rw-r--r--nixpkgs/nixos/tests/tomcat.nix2
-rw-r--r--nixpkgs/nixos/tests/traefik.nix22
-rw-r--r--nixpkgs/nixos/tests/transmission.nix2
-rw-r--r--nixpkgs/nixos/tests/tsm-client-gui.nix2
-rw-r--r--nixpkgs/nixos/tests/tuptime.nix2
-rw-r--r--nixpkgs/nixos/tests/turbovnc-headless-server.nix2
-rw-r--r--nixpkgs/nixos/tests/tuxguitar.nix2
-rw-r--r--nixpkgs/nixos/tests/udisks2.nix2
-rw-r--r--nixpkgs/nixos/tests/uptermd.nix65
-rw-r--r--nixpkgs/nixos/tests/usbguard.nix2
-rw-r--r--nixpkgs/nixos/tests/user-activation-scripts.nix6
-rw-r--r--nixpkgs/nixos/tests/user-home-mode.nix27
-rw-r--r--nixpkgs/nixos/tests/uwsgi.nix2
-rw-r--r--nixpkgs/nixos/tests/v2ray.nix2
-rw-r--r--nixpkgs/nixos/tests/vault-dev.nix35
-rw-r--r--nixpkgs/nixos/tests/vault-postgresql.nix2
-rw-r--r--nixpkgs/nixos/tests/vault.nix2
-rw-r--r--nixpkgs/nixos/tests/vaultwarden.nix32
-rw-r--r--nixpkgs/nixos/tests/vector.nix2
-rw-r--r--nixpkgs/nixos/tests/vengi-tools.nix4
-rw-r--r--nixpkgs/nixos/tests/vikunja.nix4
-rw-r--r--nixpkgs/nixos/tests/virtualbox.nix33
-rw-r--r--nixpkgs/nixos/tests/vscodium.nix8
-rw-r--r--nixpkgs/nixos/tests/vsftpd.nix2
-rw-r--r--nixpkgs/nixos/tests/web-apps/healthchecks.nix42
-rw-r--r--nixpkgs/nixos/tests/web-apps/netbox.nix30
-rw-r--r--nixpkgs/nixos/tests/web-apps/nifi.nix30
-rw-r--r--nixpkgs/nixos/tests/web-apps/peertube.nix10
-rw-r--r--nixpkgs/nixos/tests/web-apps/phylactery.nix20
-rw-r--r--nixpkgs/nixos/tests/web-servers/unit-php.nix19
-rw-r--r--nixpkgs/nixos/tests/wiki-js.nix2
-rw-r--r--nixpkgs/nixos/tests/wine.nix2
-rw-r--r--nixpkgs/nixos/tests/wireguard/wg-quick.nix5
-rw-r--r--nixpkgs/nixos/tests/wmderland.nix2
-rw-r--r--nixpkgs/nixos/tests/wpa_supplicant.nix2
-rw-r--r--nixpkgs/nixos/tests/xfce.nix2
-rw-r--r--nixpkgs/nixos/tests/xmonad-xdg-autostart.nix35
-rw-r--r--nixpkgs/nixos/tests/xmonad.nix17
-rw-r--r--nixpkgs/nixos/tests/xmpp/xmpp-sendmessage.nix7
-rw-r--r--nixpkgs/nixos/tests/xrdp.nix2
-rw-r--r--nixpkgs/nixos/tests/xterm.nix2
-rw-r--r--nixpkgs/nixos/tests/yabar.nix2
-rw-r--r--nixpkgs/nixos/tests/yggdrasil.nix4
-rw-r--r--nixpkgs/nixos/tests/zeronet-conservancy.nix25
-rw-r--r--nixpkgs/nixos/tests/zfs.nix52
-rw-r--r--nixpkgs/nixos/tests/zigbee2mqtt.nix2
-rw-r--r--nixpkgs/nixos/tests/zoneminder.nix2
-rw-r--r--nixpkgs/nixos/tests/zrepl.nix66
-rw-r--r--nixpkgs/nixos/tests/zsh-history.nix6
385 files changed, 5425 insertions, 1480 deletions
diff --git a/nixpkgs/nixos/tests/3proxy.nix b/nixpkgs/nixos/tests/3proxy.nix
index dfc4b35a772d..8127438fabd9 100644
--- a/nixpkgs/nixos/tests/3proxy.nix
+++ b/nixpkgs/nixos/tests/3proxy.nix
@@ -139,7 +139,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     peer0.wait_for_unit("network-online.target")
 
     peer1.wait_for_unit("3proxy.service")
-    peer1.wait_for_open_port("9999")
+    peer1.wait_for_open_port(9999)
 
     # test none auth
     peer0.succeed(
@@ -153,7 +153,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     )
 
     peer2.wait_for_unit("3proxy.service")
-    peer2.wait_for_open_port("9999")
+    peer2.wait_for_open_port(9999)
 
     # test iponly auth
     peer0.succeed(
@@ -167,7 +167,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     )
 
     peer3.wait_for_unit("3proxy.service")
-    peer3.wait_for_open_port("9999")
+    peer3.wait_for_open_port(9999)
 
     # test strong auth
     peer0.succeed(
diff --git a/nixpkgs/nixos/tests/acme.nix b/nixpkgs/nixos/tests/acme.nix
index 2dd06a50f40b..c07f99c5db3a 100644
--- a/nixpkgs/nixos/tests/acme.nix
+++ b/nixpkgs/nixos/tests/acme.nix
@@ -578,7 +578,7 @@ in {
               webserver.wait_for_unit(f"acme-finished-{test_domain}.target")
               wait_for_server()
               check_connection(client, test_domain)
-              rc, _ = client.execute(
+              rc, _s = client.execute(
                   f"openssl s_client -CAfile /tmp/ca.crt -connect {test_alias}:443"
                   " </dev/null 2>/dev/null | openssl x509 -noout -text"
                   f" | grep DNS: | grep {test_alias}"
diff --git a/nixpkgs/nixos/tests/aesmd.nix b/nixpkgs/nixos/tests/aesmd.nix
index 59c04fe7e96a..9f07426be8d8 100644
--- a/nixpkgs/nixos/tests/aesmd.nix
+++ b/nixpkgs/nixos/tests/aesmd.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ veehaitch ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     services.aesmd = {
       enable = true;
       settings = {
diff --git a/nixpkgs/nixos/tests/agda.nix b/nixpkgs/nixos/tests/agda.nix
index ec61af2afe75..6f51300111ac 100644
--- a/nixpkgs/nixos/tests/agda.nix
+++ b/nixpkgs/nixos/tests/agda.nix
@@ -15,7 +15,7 @@ in
     maintainers = [ alexarice turion ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [
       (pkgs.agda.withPackages {
         pkgs = p: [ p.standard-library ];
diff --git a/nixpkgs/nixos/tests/airsonic.nix b/nixpkgs/nixos/tests/airsonic.nix
index d8df092c2ecf..69f979726bce 100644
--- a/nixpkgs/nixos/tests/airsonic.nix
+++ b/nixpkgs/nixos/tests/airsonic.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ sumnerevans ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     {
       services.airsonic = {
@@ -15,7 +15,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
   testScript = ''
     def airsonic_is_up(_) -> bool:
-        return machine.succeed("curl --fail http://localhost:4040/login")
+        status, _ = machine.execute("curl --fail http://localhost:4040/login")
+        return status == 0
 
 
     machine.start()
diff --git a/nixpkgs/nixos/tests/all-terminfo.nix b/nixpkgs/nixos/tests/all-terminfo.nix
new file mode 100644
index 000000000000..dd47c66ee1c1
--- /dev/null
+++ b/nixpkgs/nixos/tests/all-terminfo.nix
@@ -0,0 +1,31 @@
+import ./make-test-python.nix ({ pkgs, ... }: rec {
+  name = "all-terminfo";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ jkarlson ];
+  };
+
+  nodes.machine = { pkgs, config, lib, ... }:
+    let
+      infoFilter = name: drv:
+        let
+          o = builtins.tryEval drv;
+        in
+        o.success && lib.isDerivation o.value && o.value ? outputs && builtins.elem "terminfo" o.value.outputs;
+      terminfos = lib.filterAttrs infoFilter pkgs;
+      excludedTerminfos = lib.filterAttrs (_: drv: !(builtins.elem drv.terminfo config.environment.systemPackages)) terminfos;
+      includedOuts = lib.filterAttrs (_: drv: builtins.elem drv.out config.environment.systemPackages) terminfos;
+    in
+    {
+      environment = {
+        enableAllTerminfo = true;
+        etc."terminfo-missing".text = builtins.concatStringsSep "\n" (builtins.attrNames excludedTerminfos);
+        etc."terminfo-extra-outs".text = builtins.concatStringsSep "\n" (builtins.attrNames includedOuts);
+      };
+    };
+
+  testScript =
+    ''
+      machine.fail("grep . /etc/terminfo-missing >&2")
+      machine.fail("grep . /etc/terminfo-extra-outs >&2")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index ab6906cd24e2..c718c292b257 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -26,8 +26,8 @@ let
     featureFlags.minimalModules = {};
   };
   evalMinimalConfig = module: nixosLib.evalModules { modules = [ module ]; };
-in
-{
+
+in {
   _3proxy = handleTest ./3proxy.nix {};
   acme = handleTest ./acme.nix {};
   adguardhome = handleTest ./adguardhome.nix {};
@@ -35,11 +35,13 @@ in
   agate = handleTest ./web-servers/agate.nix {};
   agda = handleTest ./agda.nix {};
   airsonic = handleTest ./airsonic.nix {};
+  allTerminfo = handleTest ./all-terminfo.nix {};
   amazon-init-shell = handleTest ./amazon-init-shell.nix {};
   apfs = handleTest ./apfs.nix {};
   apparmor = handleTest ./apparmor.nix {};
   atd = handleTest ./atd.nix {};
   atop = handleTest ./atop.nix {};
+  auth-mysql = handleTest ./auth-mysql.nix {};
   avahi = handleTest ./avahi.nix {};
   avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };
   babeld = handleTest ./babeld.nix {};
@@ -61,6 +63,7 @@ in
   breitbandmessung = handleTest ./breitbandmessung.nix {};
   brscan5 = handleTest ./brscan5.nix {};
   btrbk = handleTest ./btrbk.nix {};
+  btrbk-no-timer = handleTest ./btrbk-no-timer.nix {};
   buildbot = handleTest ./buildbot.nix {};
   buildkite-agents = handleTest ./buildkite-agents.nix {};
   caddy = handleTest ./caddy.nix {};
@@ -108,9 +111,8 @@ in
   cri-o = handleTestOn ["x86_64-linux"] ./cri-o.nix {};
   custom-ca = handleTest ./custom-ca.nix {};
   croc = handleTest ./croc.nix {};
-  cryptpad = handleTest ./cryptpad.nix {};
   deluge = handleTest ./deluge.nix {};
-  dendrite = handleTest ./dendrite.nix {};
+  dendrite = handleTest ./matrix/dendrite.nix {};
   dex-oidc = handleTest ./dex-oidc.nix {};
   dhparams = handleTest ./dhparams.nix {};
   disable-installer-tools = handleTest ./disable-installer-tools.nix {};
@@ -121,12 +123,12 @@ in
   doas = handleTest ./doas.nix {};
   docker = handleTestOn ["x86_64-linux"] ./docker.nix {};
   docker-rootless = handleTestOn ["x86_64-linux"] ./docker-rootless.nix {};
-  docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
   docker-registry = handleTest ./docker-registry.nix {};
   docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
   docker-tools-cross = handleTestOn ["x86_64-linux" "aarch64-linux"] ./docker-tools-cross.nix {};
   docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
   documize = handleTest ./documize.nix {};
+  documentation = pkgs.callPackage ../modules/misc/documentation/test.nix { inherit nixosLib; };
   doh-proxy-rust = handleTest ./doh-proxy-rust.nix {};
   dokuwiki = handleTest ./dokuwiki.nix {};
   domination = handleTest ./domination.nix {};
@@ -142,6 +144,7 @@ in
   engelsystem = handleTest ./engelsystem.nix {};
   enlightenment = handleTest ./enlightenment.nix {};
   env = handleTest ./env.nix {};
+  envoy = handleTest ./envoy.nix {};
   ergo = handleTest ./ergo.nix {};
   ergochat = handleTest ./ergochat.nix {};
   etc = pkgs.callPackage ../modules/system/etc/test.nix { inherit evalMinimalConfig; };
@@ -149,6 +152,7 @@ in
   etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {};
   etebase-server = handleTest ./etebase-server.nix {};
   etesync-dav = handleTest ./etesync-dav.nix {};
+  extra-python-packages = handleTest ./extra-python-packages.nix {};
   fancontrol = handleTest ./fancontrol.nix {};
   fcitx = handleTest ./fcitx {};
   fenics = handleTest ./fenics.nix {};
@@ -156,6 +160,7 @@ in
   firefox = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox; };
   firefox-esr    = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr; }; # used in `tested` job
   firefox-esr-91 = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr-91; };
+  firefox-esr-102 = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-esr-102; };
   firejail = handleTest ./firejail.nix {};
   firewall = handleTest ./firewall.nix {};
   fish = handleTest ./fish.nix {};
@@ -167,6 +172,7 @@ in
   frr = handleTest ./frr.nix {};
   fsck = handleTest ./fsck.nix {};
   ft2-clone = handleTest ./ft2-clone.nix {};
+  mimir = handleTest ./mimir.nix {};
   gerrit = handleTest ./gerrit.nix {};
   geth = handleTest ./geth.nix {};
   ghostunnel = handleTest ./ghostunnel.nix {};
@@ -185,6 +191,7 @@ in
   google-oslogin = handleTest ./google-oslogin {};
   gotify-server = handleTest ./gotify-server.nix {};
   grafana = handleTest ./grafana.nix {};
+  grafana-agent = handleTest ./grafana-agent.nix {};
   graphite = handleTest ./graphite.nix {};
   graylog = handleTest ./graylog.nix {};
   grocy = handleTest ./grocy.nix {};
@@ -194,8 +201,13 @@ in
   hadoop_3_2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_2; };
   hadoop2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop2; };
   haka = handleTest ./haka.nix {};
+  haste-server = handleTest ./haste-server.nix {};
   haproxy = handleTest ./haproxy.nix {};
   hardened = handleTest ./hardened.nix {};
+  healthchecks = handleTest ./web-apps/healthchecks.nix {};
+  hbase1 = handleTest ./hbase.nix { package=pkgs.hbase1; };
+  hbase2 = handleTest ./hbase.nix { package=pkgs.hbase2; };
+  hbase3 = handleTest ./hbase.nix { package=pkgs.hbase3; };
   hedgedoc = handleTest ./hedgedoc.nix {};
   herbstluftwm = handleTest ./herbstluftwm.nix {};
   installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
@@ -206,6 +218,7 @@ in
   # hibernation. This test happens to work on x86_64-linux but
   # not on other platforms.
   hibernate = handleTestOn ["x86_64-linux"] ./hibernate.nix {};
+  hibernate-systemd-stage-1 = handleTestOn ["x86_64-linux"] ./hibernate.nix { systemdStage1 = true; };
   hitch = handleTest ./hitch {};
   hledger-web = handleTest ./hledger-web.nix {};
   hocker-fetchdocker = handleTest ./hocker-fetchdocker {};
@@ -228,6 +241,7 @@ in
   input-remapper = handleTest ./input-remapper.nix {};
   inspircd = handleTest ./inspircd.nix {};
   installer = handleTest ./installer.nix {};
+  installer-systemd-stage-1 = handleTest ./installer-systemd-stage-1.nix {};
   invoiceplane = handleTest ./invoiceplane.nix {};
   iodine = handleTest ./iodine.nix {};
   ipfs = handleTest ./ipfs.nix {};
@@ -242,9 +256,9 @@ in
   jibri = handleTest ./jibri.nix {};
   jirafeau = handleTest ./jirafeau.nix {};
   jitsi-meet = handleTest ./jitsi-meet.nix {};
-  k3s-single-node = handleTest ./k3s-single-node.nix {};
-  k3s-single-node-docker = handleTest ./k3s-single-node-docker.nix {};
+  k3s = handleTest ./k3s {};
   kafka = handleTest ./kafka.nix {};
+  kanidm = handleTest ./kanidm.nix {};
   kbd-setfont-decompress = handleTest ./kbd-setfont-decompress.nix {};
   kbd-update-search-paths-patch = handleTest ./kbd-update-search-paths-patch.nix {};
   kea = handleTest ./kea.nix {};
@@ -253,10 +267,12 @@ in
   kerberos = handleTest ./kerberos/default.nix {};
   kernel-generic = handleTest ./kernel-generic.nix {};
   kernel-latest-ath-user-regd = handleTest ./kernel-latest-ath-user-regd.nix {};
+  keter = handleTest ./keter.nix {};
   kexec = handleTest ./kexec.nix {};
   keycloak = discoverTests (import ./keycloak.nix);
   keymap = handleTest ./keymap.nix {};
   knot = handleTest ./knot.nix {};
+  komga = handleTest ./komga.nix {};
   krb5 = discoverTests (import ./krb5 {});
   ksm = handleTest ./ksm.nix {};
   kubernetes = handleTestOn ["x86_64-linux"] ./kubernetes {};
@@ -266,21 +282,25 @@ in
   libreddit = handleTest ./libreddit.nix {};
   libresprite = handleTest ./libresprite.nix {};
   libreswan = handleTest ./libreswan.nix {};
+  librewolf = handleTest ./firefox.nix { firefoxPackage = pkgs.librewolf; };
+  libuiohook = handleTest ./libuiohook.nix {};
   lidarr = handleTest ./lidarr.nix {};
   lightdm = handleTest ./lightdm.nix {};
+  lighttpd = handleTest ./lighttpd.nix {};
   limesurvey = handleTest ./limesurvey.nix {};
   litestream = handleTest ./litestream.nix {};
   locate = handleTest ./locate.nix {};
   login = handleTest ./login.nix {};
   logrotate = handleTest ./logrotate.nix {};
   loki = handleTest ./loki.nix {};
+  lvm2 = handleTest ./lvm2 {};
   lxd = handleTest ./lxd.nix {};
-  lxd-image = handleTest ./lxd-image.nix {};
   lxd-nftables = handleTest ./lxd-nftables.nix {};
   lxd-image-server = handleTest ./lxd-image-server.nix {};
   #logstash = handleTest ./logstash.nix {};
   lorri = handleTest ./lorri/default.nix {};
   maddy = handleTest ./maddy.nix {};
+  maestral = handleTest ./maestral.nix {};
   magic-wormhole-mailbox-server = handleTest ./magic-wormhole-mailbox-server.nix {};
   magnetico = handleTest ./magnetico.nix {};
   mailcatcher = handleTest ./mailcatcher.nix {};
@@ -289,9 +309,9 @@ in
   mariadb-galera = handleTest ./mysql/mariadb-galera.nix {};
   mastodon = handleTestOn ["x86_64-linux" "i686-linux" "aarch64-linux"] ./web-apps/mastodon.nix {};
   matomo = handleTest ./matomo.nix {};
-  matrix-appservice-irc = handleTest ./matrix-appservice-irc.nix {};
-  matrix-conduit = handleTest ./matrix-conduit.nix {};
-  matrix-synapse = handleTest ./matrix-synapse.nix {};
+  matrix-appservice-irc = handleTest ./matrix/appservice-irc.nix {};
+  matrix-conduit = handleTest ./matrix/conduit.nix {};
+  matrix-synapse = handleTest ./matrix/synapse.nix {};
   mattermost = handleTest ./mattermost.nix {};
   mediatomb = handleTest ./mediatomb.nix {};
   mediawiki = handleTest ./mediawiki.nix {};
@@ -315,6 +335,7 @@ in
   moosefs = handleTest ./moosefs.nix {};
   mpd = handleTest ./mpd.nix {};
   mpv = handleTest ./mpv.nix {};
+  mtp = handleTest ./mtp.nix {};
   mumble = handleTest ./mumble.nix {};
   musescore = handleTest ./musescore.nix {};
   munin = handleTest ./munin.nix {};
@@ -341,6 +362,7 @@ in
   networking.networkd = handleTest ./networking.nix { networkd = true; };
   networking.scripted = handleTest ./networking.nix { networkd = false; };
   specialisation = handleTest ./specialisation.nix {};
+  netbox = handleTest ./web-apps/netbox.nix {};
   # TODO: put in networking.nix after the test becomes more complete
   networkingProxy = handleTest ./networking-proxy.nix {};
   nextcloud = handleTest ./nextcloud {};
@@ -352,13 +374,15 @@ in
   nginx = handleTest ./nginx.nix {};
   nginx-auth = handleTest ./nginx-auth.nix {};
   nginx-etag = handleTest ./nginx-etag.nix {};
+  nginx-http3 = handleTest ./nginx-http3.nix {};
   nginx-modsecurity = handleTest ./nginx-modsecurity.nix {};
   nginx-pubhtml = handleTest ./nginx-pubhtml.nix {};
   nginx-sandbox = handleTestOn ["x86_64-linux"] ./nginx-sandbox.nix {};
   nginx-sso = handleTest ./nginx-sso.nix {};
   nginx-variants = handleTest ./nginx-variants.nix {};
+  nifi = handleTestOn ["x86_64-linux"] ./web-apps/nifi.nix {};
   nitter = handleTest ./nitter.nix {};
-  nix-ld = handleTest ./nix-ld {};
+  nix-ld = handleTest ./nix-ld.nix {};
   nix-serve = handleTest ./nix-serve.nix {};
   nix-serve-ssh = handleTest ./nix-serve-ssh.nix {};
   nixops = handleTest ./nixops/default.nix {};
@@ -366,6 +390,7 @@ in
   nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; };
   node-red = handleTest ./node-red.nix {};
   nomad = handleTest ./nomad.nix {};
+  non-default-filesystems = handleTest ./non-default-filesystems.nix {};
   noto-fonts = handleTest ./noto-fonts.nix {};
   novacomd = handleTestOn ["x86_64-linux"] ./novacomd.nix {};
   nsd = handleTest ./nsd.nix {};
@@ -393,9 +418,12 @@ in
   pam-file-contents = handleTest ./pam/pam-file-contents.nix {};
   pam-oath-login = handleTest ./pam/pam-oath-login.nix {};
   pam-u2f = handleTest ./pam/pam-u2f.nix {};
+  pam-ussh = handleTest ./pam/pam-ussh.nix {};
+  pass-secret-service = handleTest ./pass-secret-service.nix {};
+  patroni = handleTest ./patroni.nix {};
   pantalaimon = handleTest ./matrix/pantalaimon.nix {};
   pantheon = handleTest ./pantheon.nix {};
-  paperless-ng = handleTest ./paperless-ng.nix {};
+  paperless = handleTest ./paperless.nix {};
   parsedmarc = handleTest ./parsedmarc {};
   pdns-recursor = handleTest ./pdns-recursor.nix {};
   peerflix = handleTest ./peerflix.nix {};
@@ -405,9 +433,9 @@ in
   pgjwt = handleTest ./pgjwt.nix {};
   pgmanage = handleTest ./pgmanage.nix {};
   php = handleTest ./php {};
-  php74 = handleTest ./php { php = pkgs.php74; };
   php80 = handleTest ./php { php = pkgs.php80; };
   php81 = handleTest ./php { php = pkgs.php81; };
+  phylactery = handleTest ./web-apps/phylactery.nix {};
   pict-rs = handleTest ./pict-rs.nix {};
   pinnwand = handleTest ./pinnwand.nix {};
   plasma5 = handleTest ./plasma5.nix {};
@@ -420,6 +448,7 @@ in
   podman = handleTestOn ["x86_64-linux"] ./podman/default.nix {};
   podman-dnsname = handleTestOn ["x86_64-linux"] ./podman/dnsname.nix {};
   podman-tls-ghostunnel = handleTestOn ["x86_64-linux"] ./podman/tls-ghostunnel.nix {};
+  polaris = handleTest ./polaris.nix {};
   pomerium = handleTestOn ["x86_64-linux"] ./pomerium.nix {};
   postfix = handleTest ./postfix.nix {};
   postfix-raise-smtpd-tls-security-level = handleTest ./postfix-raise-smtpd-tls-security-level.nix {};
@@ -442,6 +471,8 @@ in
   proxy = handleTest ./proxy.nix {};
   prowlarr = handleTest ./prowlarr.nix {};
   pt2-clone = handleTest ./pt2-clone.nix {};
+  pykms = handleTest ./pykms.nix {};
+  public-inbox = handleTest ./public-inbox.nix {};
   pulseaudio = discoverTests (import ./pulseaudio.nix);
   qboot = handleTestOn ["x86_64-linux" "i686-linux"] ./qboot.nix {};
   quorum = handleTest ./quorum.nix {};
@@ -455,7 +486,6 @@ in
   restartByActivationScript = handleTest ./restart-by-activation-script.nix {};
   restic = handleTest ./restic.nix {};
   retroarch = handleTest ./retroarch.nix {};
-  riak = handleTest ./riak.nix {};
   robustirc-bridge = handleTest ./robustirc-bridge.nix {};
   roundcube = handleTest ./roundcube.nix {};
   rspamd = handleTest ./rspamd.nix {};
@@ -468,6 +498,7 @@ in
   samba = handleTest ./samba.nix {};
   samba-wsdd = handleTest ./samba-wsdd.nix {};
   sanoid = handleTest ./sanoid.nix {};
+  schleuder = handleTest ./schleuder.nix {};
   sddm = handleTest ./sddm.nix {};
   seafile = handleTest ./seafile.nix {};
   searx = handleTest ./searx.nix {};
@@ -497,7 +528,9 @@ in
   starship = handleTest ./starship.nix {};
   step-ca = handleTestOn ["x86_64-linux"] ./step-ca.nix {};
   strongswan-swanctl = handleTest ./strongswan-swanctl.nix {};
+  stunnel = handleTest ./stunnel.nix {};
   sudo = handleTest ./sudo.nix {};
+  swap-partition = handleTest ./swap-partition.nix {};
   sway = handleTest ./sway.nix {};
   switchTest = handleTest ./switch-test.nix {};
   sympa = handleTest ./sympa.nix {};
@@ -509,8 +542,15 @@ in
   systemd-binfmt = handleTestOn ["x86_64-linux"] ./systemd-binfmt.nix {};
   systemd-boot = handleTest ./systemd-boot.nix {};
   systemd-confinement = handleTest ./systemd-confinement.nix {};
+  systemd-coredump = handleTest ./systemd-coredump.nix {};
   systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {};
   systemd-escaping = handleTest ./systemd-escaping.nix {};
+  systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {};
+  systemd-initrd-luks-keyfile = handleTest ./systemd-initrd-luks-keyfile.nix {};
+  systemd-initrd-luks-password = handleTest ./systemd-initrd-luks-password.nix {};
+  systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; };
+  systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {};
+  systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {};
   systemd-journal = handleTest ./systemd-journal.nix {};
   systemd-machinectl = handleTest ./systemd-machinectl.nix {};
   systemd-networkd = handleTest ./systemd-networkd.nix {};
@@ -519,6 +559,7 @@ in
   systemd-networkd-ipv6-prefix-delegation = handleTest ./systemd-networkd-ipv6-prefix-delegation.nix {};
   systemd-networkd-vrf = handleTest ./systemd-networkd-vrf.nix {};
   systemd-nspawn = handleTest ./systemd-nspawn.nix {};
+  systemd-shutdown = handleTest ./systemd-shutdown.nix {};
   systemd-timesyncd = handleTest ./systemd-timesyncd.nix {};
   systemd-misc = handleTest ./systemd-misc.nix {};
   taskserver = handleTest ./taskserver.nix {};
@@ -553,11 +594,14 @@ in
   unifi = handleTest ./unifi.nix {};
   unit-php = handleTest ./web-servers/unit-php.nix {};
   upnp = handleTest ./upnp.nix {};
+  uptermd = handleTest ./uptermd.nix {};
   usbguard = handleTest ./usbguard.nix {};
   user-activation-scripts = handleTest ./user-activation-scripts.nix {};
+  user-home-mode = handleTest ./user-home-mode.nix {};
   uwsgi = handleTest ./uwsgi.nix {};
   v2ray = handleTest ./v2ray.nix {};
   vault = handleTest ./vault.nix {};
+  vault-dev = handleTest ./vault-dev.nix {};
   vault-postgresql = handleTest ./vault-postgresql.nix {};
   vaultwarden = handleTest ./vaultwarden.nix {};
   vector = handleTest ./vector.nix {};
@@ -579,6 +623,7 @@ in
   xautolock = handleTest ./xautolock.nix {};
   xfce = handleTest ./xfce.nix {};
   xmonad = handleTest ./xmonad.nix {};
+  xmonad-xdg-autostart = handleTest ./xmonad-xdg-autostart.nix {};
   xrdp = handleTest ./xrdp.nix {};
   xss-lock = handleTest ./xss-lock.nix {};
   xterm = handleTest ./xterm.nix {};
@@ -586,9 +631,11 @@ in
   yabar = handleTest ./yabar.nix {};
   yggdrasil = handleTest ./yggdrasil.nix {};
   zammad = handleTest ./zammad.nix {};
+  zeronet-conservancy = handleTest ./zeronet-conservancy.nix {};
   zfs = handleTest ./zfs.nix {};
   zigbee2mqtt = handleTest ./zigbee2mqtt.nix {};
   zoneminder = handleTest ./zoneminder.nix {};
   zookeeper = handleTest ./zookeeper.nix {};
+  zrepl = handleTest ./zrepl.nix {};
   zsh-history = handleTest ./zsh-history.nix {};
 }
diff --git a/nixpkgs/nixos/tests/amazon-init-shell.nix b/nixpkgs/nixos/tests/amazon-init-shell.nix
index f9268b2f3a00..3c040841b6d2 100644
--- a/nixpkgs/nixos/tests/amazon-init-shell.nix
+++ b/nixpkgs/nixos/tests/amazon-init-shell.nix
@@ -18,7 +18,7 @@ makeTest {
   meta = with maintainers; {
     maintainers = [ urbas ];
   };
-  machine = { ... }:
+  nodes.machine = { ... }:
   {
     imports = [ ../modules/profiles/headless.nix ../modules/virtualisation/amazon-init.nix ];
     services.openssh.enable = true;
diff --git a/nixpkgs/nixos/tests/apfs.nix b/nixpkgs/nixos/tests/apfs.nix
index a82886cbe731..a8841fe93046 100644
--- a/nixpkgs/nixos/tests/apfs.nix
+++ b/nixpkgs/nixos/tests/apfs.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "apfs";
   meta.maintainers = with pkgs.lib.maintainers; [ Luflosi ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.emptyDiskImages = [ 1024 ];
 
     boot.supportedFilesystems = [ "apfs" ];
diff --git a/nixpkgs/nixos/tests/apparmor.nix b/nixpkgs/nixos/tests/apparmor.nix
index c6daa8e67de3..f85bff0295e7 100644
--- a/nixpkgs/nixos/tests/apparmor.nix
+++ b/nixpkgs/nixos/tests/apparmor.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... } : {
     maintainers = [ julm ];
   };
 
-  machine =
+  nodes.machine =
     { lib, pkgs, config, ... }:
     with lib;
     {
diff --git a/nixpkgs/nixos/tests/atd.nix b/nixpkgs/nixos/tests/atd.nix
index ad4d60067cf1..4342e9d7dc18 100644
--- a/nixpkgs/nixos/tests/atd.nix
+++ b/nixpkgs/nixos/tests/atd.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     maintainers = [ bjornfor ];
   };
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.atd.enable = true;
       users.users.alice = { isNormalUser = true; };
diff --git a/nixpkgs/nixos/tests/atop.nix b/nixpkgs/nixos/tests/atop.nix
index f7a90346f3d7..ec10369a24fd 100644
--- a/nixpkgs/nixos/tests/atop.nix
+++ b/nixpkgs/nixos/tests/atop.nix
@@ -107,7 +107,7 @@ in
 {
   justThePackage = makeTest {
     name = "atop-justThePackage";
-    machine = {
+    nodes.machine = {
       environment.systemPackages = [ pkgs.atop ];
     };
     testScript = with assertions; builtins.concatStringsSep "\n" [
@@ -123,7 +123,7 @@ in
   };
   defaults = makeTest {
     name = "atop-defaults";
-    machine = {
+    nodes.machine = {
       programs.atop = {
         enable = true;
       };
@@ -141,7 +141,7 @@ in
   };
   minimal = makeTest {
     name = "atop-minimal";
-    machine = {
+    nodes.machine = {
       programs.atop = {
         enable = true;
         atopService.enable = false;
@@ -162,7 +162,7 @@ in
   };
   netatop = makeTest {
     name = "atop-netatop";
-    machine = {
+    nodes.machine = {
       programs.atop = {
         enable = true;
         netatop.enable = true;
@@ -181,11 +181,7 @@ in
   };
   atopgpu = makeTest {
     name = "atop-atopgpu";
-    machine = {
-      nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (getName pkg) [
-        "cudatoolkit"
-      ];
-
+    nodes.machine = {
       programs.atop = {
         enable = true;
         atopgpu.enable = true;
@@ -204,11 +200,7 @@ in
   };
   everything = makeTest {
     name = "atop-everthing";
-    machine = {
-      nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (getName pkg) [
-        "cudatoolkit"
-      ];
-
+    nodes.machine = {
       programs.atop = {
         enable = true;
         settings = {
diff --git a/nixpkgs/nixos/tests/auth-mysql.nix b/nixpkgs/nixos/tests/auth-mysql.nix
new file mode 100644
index 000000000000..0ed4b050a69a
--- /dev/null
+++ b/nixpkgs/nixos/tests/auth-mysql.nix
@@ -0,0 +1,177 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+
+let
+  dbUser = "nixos_auth";
+  dbPassword = "topsecret123";
+  dbName = "auth";
+
+  mysqlUsername = "mysqltest";
+  mysqlPassword = "topsecretmysqluserpassword123";
+  mysqlGroup = "mysqlusers";
+
+  localUsername = "localtest";
+  localPassword = "topsecretlocaluserpassword123";
+
+  mysqlInit = pkgs.writeText "mysqlInit" ''
+      CREATE USER '${dbUser}'@'localhost' IDENTIFIED BY '${dbPassword}';
+      CREATE DATABASE ${dbName};
+      GRANT ALL PRIVILEGES ON ${dbName}.* TO '${dbUser}'@'localhost';
+      FLUSH PRIVILEGES;
+
+      USE ${dbName};
+      CREATE TABLE `groups` (
+        rowid int(11) NOT NULL auto_increment,
+        gid int(11) NOT NULL,
+        name char(255) NOT NULL,
+        PRIMARY KEY (rowid)
+      );
+
+      CREATE TABLE `users` (
+        name varchar(255) NOT NULL,
+        uid int(11) NOT NULL auto_increment,
+        gid int(11) NOT NULL,
+        password varchar(255) NOT NULL,
+        PRIMARY KEY (uid),
+        UNIQUE (name)
+      ) AUTO_INCREMENT=5000;
+
+      INSERT INTO `users` (name, uid, gid, password) VALUES
+      ('${mysqlUsername}', 5000, 5000, SHA2('${mysqlPassword}', 256));
+      INSERT INTO `groups` (name, gid) VALUES ('${mysqlGroup}', 5000);
+    '';
+in
+{
+  name = "auth-mysql";
+  meta.maintainers = with lib.maintainers; [ netali ];
+
+  nodes.machine =
+    { ... }:
+    {
+      services.mysql = {
+        enable = true;
+        package = pkgs.mariadb;
+        settings.mysqld.bind-address = "127.0.0.1";
+        initialScript = mysqlInit;
+      };
+
+      users.users.${localUsername} = {
+        isNormalUser = true;
+        password = localPassword;
+      };
+
+      security.pam.services.login.makeHomeDir = true;
+
+      users.mysql = {
+        enable = true;
+        host = "127.0.0.1";
+        user = dbUser;
+        database = dbName;
+        passwordFile = "${builtins.toFile "dbPassword" dbPassword}";
+        pam = {
+          table = "users";
+          userColumn = "name";
+          passwordColumn = "password";
+          passwordCrypt = "sha256";
+          disconnectEveryOperation = true;
+        };
+        nss = {
+          getpwnam = ''
+            SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
+            FROM users \
+            WHERE name='%1$s' \
+            LIMIT 1
+          '';
+          getpwuid = ''
+            SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
+            FROM users \
+            WHERE id=%1$u \
+            LIMIT 1
+          '';
+          getspnam = ''
+            SELECT name, password, 1, 0, 99999, 7, 0, -1, 0 \
+            FROM users \
+            WHERE name='%1$s' \
+            LIMIT 1
+          '';
+          getpwent = ''
+            SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
+            FROM users
+          '';
+          getspent = ''
+            SELECT name, password, 1, 0, 99999, 7, 0, -1, 0 \
+            FROM users
+          '';
+          getgrnam = ''
+            SELECT name, 'x', gid FROM groups WHERE name='%1$s' LIMIT 1
+          '';
+          getgrgid = ''
+            SELECT name, 'x', gid FROM groups WHERE gid='%1$u' LIMIT 1
+          '';
+          getgrent = ''
+            SELECT name, 'x', gid FROM groups
+          '';
+          memsbygid = ''
+            SELECT name FROM users WHERE gid=%1$u
+          '';
+          gidsbymem = ''
+            SELECT gid FROM users WHERE name='%1$s'
+          '';
+        };
+      };
+    };
+
+  testScript = ''
+    def switch_to_tty(tty_number):
+        machine.fail(f"pgrep -f 'agetty.*tty{tty_number}'")
+        machine.send_key(f"alt-f{tty_number}")
+        machine.wait_until_succeeds(f"[ $(fgconsole) = {tty_number} ]")
+        machine.wait_for_unit(f"getty@tty{tty_number}.service")
+        machine.wait_until_succeeds(f"pgrep -f 'agetty.*tty{tty_number}'")
+
+
+    def try_login(tty_number, username, password):
+        machine.wait_until_tty_matches(tty_number, "login: ")
+        machine.send_chars(f"{username}\n")
+        machine.wait_until_tty_matches(tty_number, f"login: {username}")
+        machine.wait_until_succeeds("pgrep login")
+        machine.wait_until_tty_matches(tty_number, "Password: ")
+        machine.send_chars(f"{password}\n")
+
+
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("mysql.service")
+    machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
+
+    with subtest("Local login"):
+        switch_to_tty("2")
+        try_login("2", "${localUsername}", "${localPassword}")
+
+        machine.wait_until_succeeds("pgrep -u ${localUsername} bash")
+        machine.send_chars("id > local_id.txt\n")
+        machine.wait_for_file("/home/${localUsername}/local_id.txt")
+        machine.succeed("cat /home/${localUsername}/local_id.txt | grep 'uid=1000(${localUsername}) gid=100(users) groups=100(users)'")
+
+    with subtest("Local incorrect login"):
+        switch_to_tty("3")
+        try_login("3", "${localUsername}", "wrongpassword")
+
+        machine.wait_until_tty_matches("3", "Login incorrect")
+        machine.wait_until_tty_matches("3", "login:")
+
+    with subtest("MySQL login"):
+        switch_to_tty("4")
+        try_login("4", "${mysqlUsername}", "${mysqlPassword}")
+
+        machine.wait_until_succeeds("pgrep -u ${mysqlUsername} bash")
+        machine.send_chars("id > mysql_id.txt\n")
+        machine.wait_for_file("/home/${mysqlUsername}/mysql_id.txt")
+        machine.succeed("cat /home/${mysqlUsername}/mysql_id.txt | grep 'uid=5000(${mysqlUsername}) gid=5000(${mysqlGroup}) groups=5000(${mysqlGroup})'")
+
+    with subtest("MySQL incorrect login"):
+        switch_to_tty("5")
+        try_login("5", "${mysqlUsername}", "wrongpassword")
+
+        machine.wait_until_tty_matches("5", "Login incorrect")
+        machine.wait_until_tty_matches("5", "login:")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/bazarr.nix b/nixpkgs/nixos/tests/bazarr.nix
index c3337611aa29..efcd9de01080 100644
--- a/nixpkgs/nixos/tests/bazarr.nix
+++ b/nixpkgs/nixos/tests/bazarr.nix
@@ -20,7 +20,7 @@ in
 
   testScript = ''
     machine.wait_for_unit("bazarr.service")
-    machine.wait_for_open_port("${toString port}")
+    machine.wait_for_open_port(port)
     machine.succeed("curl --fail http://localhost:${toString port}/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/bcachefs.nix b/nixpkgs/nixos/tests/bcachefs.nix
index 44997a746879..68ac49d0a6a6 100644
--- a/nixpkgs/nixos/tests/bcachefs.nix
+++ b/nixpkgs/nixos/tests/bcachefs.nix
@@ -1,8 +1,8 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "bcachefs";
-  meta.maintainers = with pkgs.lib.maintainers; [ chiiruno ];
+  meta.maintainers = with pkgs.lib.maintainers; [ Madouura ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.emptyDiskImages = [ 4096 ];
     networking.hostId = "deadbeef";
     boot.supportedFilesystems = [ "bcachefs" ];
diff --git a/nixpkgs/nixos/tests/beanstalkd.nix b/nixpkgs/nixos/tests/beanstalkd.nix
index 4f4a454fb47f..518f018408ad 100644
--- a/nixpkgs/nixos/tests/beanstalkd.nix
+++ b/nixpkgs/nixos/tests/beanstalkd.nix
@@ -28,7 +28,7 @@ in
   name = "beanstalkd";
   meta.maintainers = [ lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.beanstalkd.enable = true;
     };
diff --git a/nixpkgs/nixos/tests/bees.nix b/nixpkgs/nixos/tests/bees.nix
index 58a9c2951356..3ab9f38ada8f 100644
--- a/nixpkgs/nixos/tests/bees.nix
+++ b/nixpkgs/nixos/tests/bees.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
 {
   name = "bees";
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     boot.initrd.postDeviceCommands = ''
       ${pkgs.btrfs-progs}/bin/mkfs.btrfs -f -L aux1 /dev/vdb
       ${pkgs.btrfs-progs}/bin/mkfs.btrfs -f -L aux2 /dev/vdc
diff --git a/nixpkgs/nixos/tests/bind.nix b/nixpkgs/nixos/tests/bind.nix
index 7234f56a1c3a..15accbd49db4 100644
--- a/nixpkgs/nixos/tests/bind.nix
+++ b/nixpkgs/nixos/tests/bind.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "bind";
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     services.bind.enable = true;
     services.bind.extraOptions = "empty-zones-enable no;";
     services.bind.zones = lib.singleton {
diff --git a/nixpkgs/nixos/tests/bitcoind.nix b/nixpkgs/nixos/tests/bitcoind.nix
index 3e9e085287ac..7726a23d853e 100644
--- a/nixpkgs/nixos/tests/bitcoind.nix
+++ b/nixpkgs/nixos/tests/bitcoind.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = with maintainers; [ _1000101 ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.bitcoind."mainnet" = {
       enable = true;
       rpc = {
@@ -13,9 +13,11 @@ import ./make-test-python.nix ({ pkgs, ... }: {
         users.rpc2.passwordHMAC = "1495e4a3ad108187576c68f7f9b5ddc5$accce0881c74aa01bb8960ff3bdbd39f607fd33178147679e055a4ac35f53225";
       };
     };
+
+    environment.etc."test.blank".text = "";
     services.bitcoind."testnet" = {
       enable = true;
-      configFile = "/test.blank";
+      configFile = "/etc/test.blank";
       testnet = true;
       rpc = {
         port = 18332;
diff --git a/nixpkgs/nixos/tests/blockbook-frontend.nix b/nixpkgs/nixos/tests/blockbook-frontend.nix
index e17a2d057797..dca4f2f53cc1 100644
--- a/nixpkgs/nixos/tests/blockbook-frontend.nix
+++ b/nixpkgs/nixos/tests/blockbook-frontend.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = with maintainers; [ _1000101 ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.blockbook-frontend."test" = {
       enable = true;
     };
diff --git a/nixpkgs/nixos/tests/boot-stage1.nix b/nixpkgs/nixos/tests/boot-stage1.nix
index 756decd2039d..fbe82d61afae 100644
--- a/nixpkgs/nixos/tests/boot-stage1.nix
+++ b/nixpkgs/nixos/tests/boot-stage1.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "boot-stage1";
 
-  machine = { config, pkgs, lib, ... }: {
+  nodes.machine = { config, pkgs, lib, ... }: {
     boot.extraModulePackages = let
       compileKernelModule = name: source: pkgs.runCommandCC name rec {
         inherit source;
diff --git a/nixpkgs/nixos/tests/botamusique.nix b/nixpkgs/nixos/tests/botamusique.nix
index ccb105dc142f..ecb79cb69867 100644
--- a/nixpkgs/nixos/tests/botamusique.nix
+++ b/nixpkgs/nixos/tests/botamusique.nix
@@ -6,6 +6,10 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
 
   nodes = {
     machine = { config, ... }: {
+      networking.extraHosts = ''
+        127.0.0.1 all.api.radio-browser.info
+      '';
+
       services.murmur = {
         enable = true;
         registerName = "NixOS tests";
diff --git a/nixpkgs/nixos/tests/bpf.nix b/nixpkgs/nixos/tests/bpf.nix
index e479cd057921..5868e3bfcb4c 100644
--- a/nixpkgs/nixos/tests/bpf.nix
+++ b/nixpkgs/nixos/tests/bpf.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "bpf";
   meta.maintainers = with pkgs.lib.maintainers; [ martinetd ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     programs.bcc.enable = true;
     environment.systemPackages = with pkgs; [ bpftrace ];
   };
diff --git a/nixpkgs/nixos/tests/breitbandmessung.nix b/nixpkgs/nixos/tests/breitbandmessung.nix
index 12b1a094839b..78df0d5017eb 100644
--- a/nixpkgs/nixos/tests/breitbandmessung.nix
+++ b/nixpkgs/nixos/tests/breitbandmessung.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, ... }: {
   name = "breitbandmessung";
   meta.maintainers = with lib.maintainers; [ b4dm4n ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [
       ./common/user-account.nix
       ./common/x11.nix
diff --git a/nixpkgs/nixos/tests/brscan5.nix b/nixpkgs/nixos/tests/brscan5.nix
index 9aed742f6de7..9156a4cccfcf 100644
--- a/nixpkgs/nixos/tests/brscan5.nix
+++ b/nixpkgs/nixos/tests/brscan5.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ mattchrist ];
   };
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
     {
       nixpkgs.config.allowUnfree = true;
       hardware.sane = {
diff --git a/nixpkgs/nixos/tests/btrbk-no-timer.nix b/nixpkgs/nixos/tests/btrbk-no-timer.nix
new file mode 100644
index 000000000000..4fcab8839c89
--- /dev/null
+++ b/nixpkgs/nixos/tests/btrbk-no-timer.nix
@@ -0,0 +1,37 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+  {
+    name = "btrbk-no-timer";
+    meta.maintainers = with lib.maintainers; [ oxalica ];
+
+    nodes.machine = { ... }: {
+      environment.systemPackages = with pkgs; [ btrfs-progs ];
+      services.btrbk.instances.local = {
+        onCalendar = null;
+        settings.volume."/mnt" = {
+          snapshot_dir = "btrbk/local";
+          subvolume = "to_backup";
+        };
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      # Create btrfs partition at /mnt
+      machine.succeed("truncate --size=128M /data_fs")
+      machine.succeed("mkfs.btrfs /data_fs")
+      machine.succeed("mkdir /mnt")
+      machine.succeed("mount /data_fs /mnt")
+      machine.succeed("btrfs subvolume create /mnt/to_backup")
+      machine.succeed("mkdir -p /mnt/btrbk/local")
+
+      # The service should not have any triggering timer.
+      unit = machine.get_unit_info('btrbk-local.service')
+      assert "TriggeredBy" not in unit
+
+      # Manually starting the service should still work.
+      machine.succeed("echo foo > /mnt/to_backup/bar")
+      machine.start_job("btrbk-local.service")
+      machine.wait_until_succeeds("cat /mnt/btrbk/local/*/bar | grep foo")
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/buildkite-agents.nix b/nixpkgs/nixos/tests/buildkite-agents.nix
index 6674a0e884ed..2c5593323e87 100644
--- a/nixpkgs/nixos/tests/buildkite-agents.nix
+++ b/nixpkgs/nixos/tests/buildkite-agents.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     maintainers = [ flokli ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.buildkite-agents = {
       one = {
         privateSshKeyPath = (import ./ssh-keys.nix pkgs).snakeOilPrivateKey;
diff --git a/nixpkgs/nixos/tests/caddy.nix b/nixpkgs/nixos/tests/caddy.nix
index 16436ab52800..c4abd33d0395 100644
--- a/nixpkgs/nixos/tests/caddy.nix
+++ b/nixpkgs/nixos/tests/caddy.nix
@@ -61,7 +61,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     ''
       url = "http://localhost/example.html"
       webserver.wait_for_unit("caddy")
-      webserver.wait_for_open_port("80")
+      webserver.wait_for_open_port(80)
 
 
       def check_etag(url):
@@ -95,13 +95,13 @@ import ./make-test-python.nix ({ pkgs, ... }: {
           webserver.succeed(
               "${justReloadSystem}/bin/switch-to-configuration test >&2"
           )
-          webserver.wait_for_open_port("8080")
+          webserver.wait_for_open_port(8080)
 
       with subtest("multiple configs are correctly merged"):
           webserver.succeed(
               "${multipleConfigs}/bin/switch-to-configuration test >&2"
           )
-          webserver.wait_for_open_port("8080")
-          webserver.wait_for_open_port("8081")
+          webserver.wait_for_open_port(8080)
+          webserver.wait_for_open_port(8081)
     '';
 })
diff --git a/nixpkgs/nixos/tests/cage.nix b/nixpkgs/nixos/tests/cage.nix
index 83bae3deeeab..39c8d0441b6d 100644
--- a/nixpkgs/nixos/tests/cage.nix
+++ b/nixpkgs/nixos/tests/cage.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ matthewbauer ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/cagebreak.nix b/nixpkgs/nixos/tests/cagebreak.nix
index c6c2c632b61a..1dcc910f9744 100644
--- a/nixpkgs/nixos/tests/cagebreak.nix
+++ b/nixpkgs/nixos/tests/cagebreak.nix
@@ -13,7 +13,7 @@ in
     maintainers = [ berbiche ];
   };
 
-  machine = { config, ... }:
+  nodes.machine = { config, ... }:
   let
     alice = config.users.users.alice;
   in {
diff --git a/nixpkgs/nixos/tests/cfssl.nix b/nixpkgs/nixos/tests/cfssl.nix
index 170f09d9b76c..e673df3131f8 100644
--- a/nixpkgs/nixos/tests/cfssl.nix
+++ b/nixpkgs/nixos/tests/cfssl.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ...} : {
   name = "cfssl";
 
-  machine = { config, lib, pkgs, ... }:
+  nodes.machine = { config, lib, pkgs, ... }:
   {
     networking.firewall.allowedTCPPorts = [ config.services.cfssl.port ];
 
diff --git a/nixpkgs/nixos/tests/chromium.nix b/nixpkgs/nixos/tests/chromium.nix
index 3815dca76220..6b296fe8a61a 100644
--- a/nixpkgs/nixos/tests/chromium.nix
+++ b/nixpkgs/nixos/tests/chromium.nix
@@ -45,12 +45,14 @@ mapAttrs (channel: chromiumPkg: makeTest {
 
   enableOCR = true;
 
-  machine.imports = [ ./common/user-account.nix ./common/x11.nix ];
-  machine.virtualisation.memorySize = 2047;
-  machine.test-support.displayManager.auto.user = user;
-  machine.environment = {
-    systemPackages = [ chromiumPkg ];
-    variables."XAUTHORITY" = "/home/alice/.Xauthority";
+  nodes.machine = { ... }: {
+    imports = [ ./common/user-account.nix ./common/x11.nix ];
+    virtualisation.memorySize = 2047;
+    test-support.displayManager.auto.user = user;
+    environment = {
+      systemPackages = [ chromiumPkg ];
+      variables."XAUTHORITY" = "/home/alice/.Xauthority";
+    };
   };
 
   testScript = let
diff --git a/nixpkgs/nixos/tests/clickhouse.nix b/nixpkgs/nixos/tests/clickhouse.nix
index 017f2ee35dab..043263ec05dd 100644
--- a/nixpkgs/nixos/tests/clickhouse.nix
+++ b/nixpkgs/nixos/tests/clickhouse.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "clickhouse";
   meta.maintainers = with pkgs.lib.maintainers; [ ma27 ];
 
-  machine = {
+  nodes.machine = {
     services.clickhouse.enable = true;
     virtualisation.memorySize = 4096;
   };
diff --git a/nixpkgs/nixos/tests/cloud-init.nix b/nixpkgs/nixos/tests/cloud-init.nix
index 3f191ff5616e..9feb8d5c1526 100644
--- a/nixpkgs/nixos/tests/cloud-init.nix
+++ b/nixpkgs/nixos/tests/cloud-init.nix
@@ -61,7 +61,7 @@ in makeTest {
   meta = with pkgs.lib.maintainers; {
     maintainers = [ lewo ];
   };
-  machine = { ... }:
+  nodes.machine = { ... }:
   {
     virtualisation.qemu.options = [ "-cdrom" "${metadataDrive}/metadata.iso" ];
     services.cloud-init = {
diff --git a/nixpkgs/nixos/tests/cntr.nix b/nixpkgs/nixos/tests/cntr.nix
index e4e13545b876..598143beb6c0 100644
--- a/nixpkgs/nixos/tests/cntr.nix
+++ b/nixpkgs/nixos/tests/cntr.nix
@@ -46,7 +46,7 @@ let
 
     meta = with pkgs.lib.maintainers; { maintainers = [ sorki mic92 ]; };
 
-    machine = { lib, ... }: {
+    nodes.machine = { lib, ... }: {
       environment.systemPackages = [ pkgs.cntr ];
       containers.test = {
         autoStart = true;
diff --git a/nixpkgs/nixos/tests/collectd.nix b/nixpkgs/nixos/tests/collectd.nix
index cb196224a231..2480bdb5f917 100644
--- a/nixpkgs/nixos/tests/collectd.nix
+++ b/nixpkgs/nixos/tests/collectd.nix
@@ -2,12 +2,15 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "collectd";
   meta = { };
 
-  machine =
-    { pkgs, ... }:
+  nodes.machine =
+    { pkgs, lib, ... }:
 
     {
       services.collectd = {
         enable = true;
+        extraConfig = lib.mkBefore ''
+          Interval 30
+        '';
         plugins = {
           rrdtool = ''
             DataDir "/var/lib/collectd/rrd"
@@ -26,6 +29,8 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     machine.succeed(f"rrdinfo {file} | logger")
     # check that this file contains a shortterm metric
     machine.succeed(f"rrdinfo {file} | grep -F 'ds[shortterm].min = '")
+    # check that interval was set before the plugins
+    machine.succeed(f"rrdinfo {file} | grep -F 'step = 30'")
     # check that there are frequent updates
     machine.succeed(f"cp {file} before")
     machine.wait_until_fails(f"cmp before {file}")
diff --git a/nixpkgs/nixos/tests/common/lxd/config.yaml b/nixpkgs/nixos/tests/common/lxd/config.yaml
new file mode 100644
index 000000000000..3bb667ed43f7
--- /dev/null
+++ b/nixpkgs/nixos/tests/common/lxd/config.yaml
@@ -0,0 +1,24 @@
+storage_pools:
+  - name: default
+    driver: dir
+    config:
+      source: /var/lxd-pool
+
+networks:
+  - name: lxdbr0
+    type: bridge
+    config:
+      ipv4.address: auto
+      ipv6.address: none
+
+profiles:
+  - name: default
+    devices:
+      eth0:
+        name: eth0
+        network: lxdbr0
+        type: nic
+      root:
+        path: /
+        pool: default
+        type: disk
diff --git a/nixpkgs/nixos/tests/containers-bridge.nix b/nixpkgs/nixos/tests/containers-bridge.nix
index b8661fd7997c..d2e16299edaa 100644
--- a/nixpkgs/nixos/tests/containers-bridge.nix
+++ b/nixpkgs/nixos/tests/containers-bridge.nix
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ aristid aszlig eelco kampfschlaefer ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation.writableStore = true;
diff --git a/nixpkgs/nixos/tests/containers-custom-pkgs.nix b/nixpkgs/nixos/tests/containers-custom-pkgs.nix
index 1627a2c70c3c..e8740ac63134 100644
--- a/nixpkgs/nixos/tests/containers-custom-pkgs.nix
+++ b/nixpkgs/nixos/tests/containers-custom-pkgs.nix
@@ -9,10 +9,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: let
 in {
   name = "containers-custom-pkgs";
   meta = {
-    maintainers = with lib.maintainers; [ adisbladis earvstedt ];
+    maintainers = with lib.maintainers; [ adisbladis erikarvstedt ];
   };
 
-  machine = { config, ... }: {
+  nodes.machine = { config, ... }: {
     assertions = let
       helloName = (builtins.head config.containers.test.config.system.extraDependencies).name;
     in [ {
diff --git a/nixpkgs/nixos/tests/containers-ephemeral.nix b/nixpkgs/nixos/tests/containers-ephemeral.nix
index db1631cf5b5d..cb4b7d4eba0f 100644
--- a/nixpkgs/nixos/tests/containers-ephemeral.nix
+++ b/nixpkgs/nixos/tests/containers-ephemeral.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ patryk27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.writableStore = true;
 
     containers.webserver = {
@@ -33,10 +33,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     machine.succeed("nixos-container start webserver")
 
     with subtest("Container got its own root folder"):
-        machine.succeed("ls /run/containers/webserver")
+        machine.succeed("ls /run/nixos-containers/webserver")
 
     with subtest("Container persistent directory is not created"):
-        machine.fail("ls /var/lib/containers/webserver")
+        machine.fail("ls /var/lib/nixos-containers/webserver")
 
     # Since "start" returns after the container has reached
     # multi-user.target, we should now be able to access it.
@@ -49,6 +49,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
         machine.fail(f"curl --fail --connect-timeout 2 http://{ip}/ > /dev/null")
 
     with subtest("Container's root folder was removed"):
-        machine.fail("ls /run/containers/webserver")
+        machine.fail("ls /run/nixos-containers/webserver")
   '';
 })
diff --git a/nixpkgs/nixos/tests/containers-extra_veth.nix b/nixpkgs/nixos/tests/containers-extra_veth.nix
index b8f3d9844064..f3e62265f6c4 100644
--- a/nixpkgs/nixos/tests/containers-extra_veth.nix
+++ b/nixpkgs/nixos/tests/containers-extra_veth.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ kampfschlaefer ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation.writableStore = true;
diff --git a/nixpkgs/nixos/tests/containers-hosts.nix b/nixpkgs/nixos/tests/containers-hosts.nix
index 3c6a15710027..7bce7c997efe 100644
--- a/nixpkgs/nixos/tests/containers-hosts.nix
+++ b/nixpkgs/nixos/tests/containers-hosts.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ montag451 ];
   };
 
-  machine =
+  nodes.machine =
     { lib, ... }:
     {
       virtualisation.vlans = [];
diff --git a/nixpkgs/nixos/tests/containers-imperative.nix b/nixpkgs/nixos/tests/containers-imperative.nix
index 14001657bee0..3007efaf8871 100644
--- a/nixpkgs/nixos/tests/containers-imperative.nix
+++ b/nixpkgs/nixos/tests/containers-imperative.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ aristid aszlig eelco kampfschlaefer ];
   };
 
-  machine =
+  nodes.machine =
     { config, pkgs, lib, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
 
@@ -18,8 +18,9 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
       # container available within the VM, because we don't have network access.
       virtualisation.additionalPaths = let
         emptyContainer = import ../lib/eval-config.nix {
-          inherit (config.nixpkgs.localSystem) system;
           modules = lib.singleton {
+            nixpkgs = { inherit (config.nixpkgs) localSystem; };
+
             containers.foo.config = {
               system.stateVersion = "18.03";
             };
@@ -69,8 +70,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
 
       with subtest(f"Put the root of {id2} into a bind mount"):
           machine.succeed(
-              f"mv /var/lib/containers/{id2} /id2-bindmount",
-              f"mount --bind /id2-bindmount /var/lib/containers/{id1}",
+              f"mv /var/lib/nixos-containers/{id2} /id2-bindmount",
+              f"mount --bind /id2-bindmount /var/lib/nixos-containers/{id1}",
           )
 
           ip1 = machine.succeed(f"nixos-container show-ip {id1}").rstrip()
@@ -88,7 +89,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           "Create a directory with a dummy file and bind-mount it into both containers."
       ):
           for id in id1, id2:
-              important_path = f"/var/lib/containers/{id}/very/important/data"
+              important_path = f"/var/lib/nixos-containers/{id}/very/important/data"
               machine.succeed(
                   f"mkdir -p {important_path}",
                   f"mount --bind /nested-bindmount {important_path}",
@@ -154,13 +155,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           machine.succeed("grep -qF 'important data' /nested-bindmount/dummy")
 
       with subtest("Ensure that the container path is gone"):
-          print(machine.succeed("ls -lsa /var/lib/containers"))
-          machine.succeed(f"test ! -e /var/lib/containers/{id1}")
+          print(machine.succeed("ls -lsa /var/lib/nixos-containers"))
+          machine.succeed(f"test ! -e /var/lib/nixos-containers/{id1}")
 
       with subtest("Ensure that a failed container creation doesn'leave any state"):
           machine.fail(
               "nixos-container create b0rk --config-file ${brokenCfg}"
           )
-          machine.succeed("test ! -e /var/lib/containers/b0rk")
+          machine.succeed("test ! -e /var/lib/nixos-containers/b0rk")
     '';
 })
diff --git a/nixpkgs/nixos/tests/containers-ip.nix b/nixpkgs/nixos/tests/containers-ip.nix
index 91fdda0392a9..ecead5c22f75 100644
--- a/nixpkgs/nixos/tests/containers-ip.nix
+++ b/nixpkgs/nixos/tests/containers-ip.nix
@@ -17,7 +17,7 @@ in import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ aristid aszlig eelco kampfschlaefer ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }: {
       imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation = {
diff --git a/nixpkgs/nixos/tests/containers-names.nix b/nixpkgs/nixos/tests/containers-names.nix
index 9ad2bfb748a8..721f64990724 100644
--- a/nixpkgs/nixos/tests/containers-names.nix
+++ b/nixpkgs/nixos/tests/containers-names.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ patryk27 ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     # We're using the newest kernel, so that we can test containers with long names.
     # Please see https://github.com/NixOS/nixpkgs/issues/38509 for details.
     boot.kernelPackages = pkgs.linuxPackages_latest;
diff --git a/nixpkgs/nixos/tests/containers-nested.nix b/nixpkgs/nixos/tests/containers-nested.nix
index a653361494f9..4a9fb8f01e24 100644
--- a/nixpkgs/nixos/tests/containers-nested.nix
+++ b/nixpkgs/nixos/tests/containers-nested.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
   meta = with pkgs.lib.maintainers; { maintainers = [ sorki ]; };
 
-  machine = { lib, ... }:
+  nodes.machine = { lib, ... }:
     let
       makeNested = subConf: {
         containers.nested = {
diff --git a/nixpkgs/nixos/tests/containers-portforward.nix b/nixpkgs/nixos/tests/containers-portforward.nix
index 6cecd72f1bda..b8c7aabc5a50 100644
--- a/nixpkgs/nixos/tests/containers-portforward.nix
+++ b/nixpkgs/nixos/tests/containers-portforward.nix
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ aristid aszlig eelco kampfschlaefer ianwookim ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation.writableStore = true;
diff --git a/nixpkgs/nixos/tests/containers-tmpfs.nix b/nixpkgs/nixos/tests/containers-tmpfs.nix
index d95178d1ff58..cf5b81656afe 100644
--- a/nixpkgs/nixos/tests/containers-tmpfs.nix
+++ b/nixpkgs/nixos/tests/containers-tmpfs.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ patryk27 ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation.writableStore = true;
@@ -62,7 +62,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           machine.succeed(
               tmpfs_cmd("touch /root/test.file"),
               tmpfs_cmd("ls -l  /root | grep -q test.file"),
-              "test -e /var/lib/containers/tmpfs/root/test.file",
+              "test -e /var/lib/nixos-containers/tmpfs/root/test.file",
           )
 
       with subtest(
@@ -73,7 +73,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
               tmpfs_cmd("touch /some/random/path/test.file"),
               tmpfs_cmd("test -e /some/random/path/test.file"),
           )
-          machine.fail("test -e /var/lib/containers/tmpfs/some/random/path/test.file")
+          machine.fail("test -e /var/lib/nixos-containers/tmpfs/some/random/path/test.file")
 
       with subtest(
           "files created in the hosts container dir in a path where a tmpfs "
@@ -81,9 +81,9 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
           + "the do not exist in the tmpfs"
       ):
           machine.succeed(
-              "touch /var/lib/containers/tmpfs/var/test.file",
-              "test -e /var/lib/containers/tmpfs/var/test.file",
-              "ls -l /var/lib/containers/tmpfs/var/ | grep -q test.file 2>/dev/null",
+              "touch /var/lib/nixos-containers/tmpfs/var/test.file",
+              "test -e /var/lib/nixos-containers/tmpfs/var/test.file",
+              "ls -l /var/lib/nixos-containers/tmpfs/var/ | grep -q test.file 2>/dev/null",
           )
           machine.fail(tmpfs_cmd("ls -l /var | grep -q test.file"))
     '';
diff --git a/nixpkgs/nixos/tests/convos.nix b/nixpkgs/nixos/tests/convos.nix
index a13870d17084..a5dafed8f6f0 100644
--- a/nixpkgs/nixos/tests/convos.nix
+++ b/nixpkgs/nixos/tests/convos.nix
@@ -23,8 +23,8 @@ in
 
   testScript = ''
     machine.wait_for_unit("convos")
-    machine.wait_for_open_port("${toString port}")
-    machine.succeed("journalctl -u convos | grep -q 'Listening at.*${toString port}'")
+    machine.wait_for_open_port(${toString port})
+    machine.succeed("journalctl -u convos | grep -q 'application available at.*${toString port}'")
     machine.succeed("curl -f http://localhost:${toString port}/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/couchdb.nix b/nixpkgs/nixos/tests/couchdb.nix
index 453f5dcd66e8..b57072d6be2d 100644
--- a/nixpkgs/nixos/tests/couchdb.nix
+++ b/nixpkgs/nixos/tests/couchdb.nix
@@ -20,7 +20,7 @@ with lib;
 {
   name = "couchdb";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ fpletz ];
+    maintainers = [ ];
   };
 
   nodes = {
diff --git a/nixpkgs/nixos/tests/cryptpad.nix b/nixpkgs/nixos/tests/cryptpad.nix
deleted file mode 100644
index 895f291abaca..000000000000
--- a/nixpkgs/nixos/tests/cryptpad.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-import ./make-test-python.nix ({ lib, ... }:
-
-with lib;
-
-{
-  name = "cryptpad";
-  meta.maintainers = with maintainers; [ davhau ];
-
-  nodes.machine =
-    { pkgs, ... }:
-    { services.cryptpad.enable = true; };
-
-  testScript = ''
-    machine.wait_for_unit("cryptpad.service")
-    machine.wait_for_open_port("3000")
-    machine.succeed("curl -L --fail http://localhost:3000/sheet")
-  '';
-})
diff --git a/nixpkgs/nixos/tests/custom-ca.nix b/nixpkgs/nixos/tests/custom-ca.nix
index a55449a397a7..73e47c3c9d0d 100644
--- a/nixpkgs/nixos/tests/custom-ca.nix
+++ b/nixpkgs/nixos/tests/custom-ca.nix
@@ -1,11 +1,18 @@
 # Checks that `security.pki` options are working in curl and the main browser
-# engines: Gecko (via Firefox), Chromium, QtWebEngine (Falkon) and WebKitGTK
-# (via Midori). The test checks that certificates issued by a custom trusted
-# CA are accepted but those from an unknown CA are rejected.
+# engines: Gecko (via Firefox), Chromium, QtWebEngine (via qutebrowser) and
+# WebKitGTK (via Midori). The test checks that certificates issued by a custom
+# trusted CA are accepted but those from an unknown CA are rejected.
 
-import ./make-test-python.nix ({ pkgs, lib, ... }:
+{ system ? builtins.currentSystem,
+  config ? {},
+  pkgs ? import ../.. { inherit system config; }
+}:
+
+with import ../lib/testing-python.nix { inherit system pkgs; };
 
 let
+  inherit (pkgs) lib;
+
   makeCert = { caName, domain }: pkgs.runCommand "example-cert"
   { buildInputs = [ pkgs.gnutls ]; }
   ''
@@ -68,24 +75,8 @@ let
       domain = "bad.example.com";
     };
 
-in
-
-{
-  name = "custom-ca";
-  meta.maintainers = with lib.maintainers; [ rnhmjoj ];
-
-  enableOCR = true;
-
-  machine = { pkgs, ... }:
-    { imports = [ ./common/user-account.nix ./common/x11.nix ];
-
-      # chromium-based browsers refuse to run as root
-      test-support.displayManager.auto.user = "alice";
-
-      # browsers may hang with the default memory
-      virtualisation.memorySize = 600;
-
-      networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ];
+  webserverConfig =
+    { networking.hosts."127.0.0.1" = [ "good.example.com" "bad.example.com" ];
       security.pki.certificateFiles = [ "${example-good-cert}/ca.crt" ];
 
       services.nginx.enable = true;
@@ -107,73 +98,98 @@ in
             return 200 'It does not work!';
           '';
         };
-
-      environment.systemPackages = with pkgs; [
-        xdotool
-        firefox
-        chromium
-        qutebrowser
-        midori
-      ];
     };
 
-  testScript = ''
-    from typing import Tuple
-    def execute_as(user: str, cmd: str) -> Tuple[int, str]:
-        """
-        Run a shell command as a specific user.
-        """
-        return machine.execute(f"sudo -u {user} {cmd}")
-
-
-    def wait_for_window_as(user: str, cls: str) -> None:
-        """
-        Wait until a X11 window of a given user appears.
-        """
-
-        def window_is_visible(last_try: bool) -> bool:
-            ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}")
-            if last_try:
-                machine.log(f"Last chance to match {cls} on the window list")
-            return ret == 0
-
-        with machine.nested("Waiting for a window to appear"):
-            retry(window_is_visible)
-
-
-    machine.start()
-
-    with subtest("Good certificate is trusted in curl"):
-        machine.wait_for_unit("nginx")
-        machine.wait_for_open_port(443)
-        machine.succeed("curl -fv https://good.example.com")
-
-    with subtest("Unknown CA is untrusted in curl"):
-        machine.fail("curl -fv https://bad.example.com")
-
-    browsers = {
-      "firefox": "Security Risk",
-      "chromium": "not private",
-      "qutebrowser -T": "Certificate error",
-      "midori": "Security"
-    }
-
-    machine.wait_for_x()
-    for command, error in browsers.items():
-        browser = command.split()[0]
-        with subtest("Good certificate is trusted in " + browser):
-            execute_as(
-                "alice", f"{command} https://good.example.com >&2 &"
-            )
-            wait_for_window_as("alice", browser)
-            machine.wait_for_text("It works!")
-            machine.screenshot("good" + browser)
-            execute_as("alice", "xdotool key ctrl+w")  # close tab
-
-        with subtest("Unknown CA is untrusted in " + browser):
-            execute_as("alice", f"{command} https://bad.example.com >&2 &")
-            machine.wait_for_text(error)
-            machine.screenshot("bad" + browser)
-            machine.succeed("pkill -f " + browser)
-  '';
-})
+  curlTest = makeTest {
+    name = "custom-ca-curl";
+    meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+    nodes.machine = { ... }: webserverConfig;
+    testScript = ''
+        with subtest("Good certificate is trusted in curl"):
+            machine.wait_for_unit("nginx")
+            machine.wait_for_open_port(443)
+            machine.succeed("curl -fv https://good.example.com")
+
+        with subtest("Unknown CA is untrusted in curl"):
+            machine.fail("curl -fv https://bad.example.com")
+    '';
+  };
+
+  mkBrowserTest = browser: testParams: makeTest {
+    name = "custom-ca-${browser}";
+    meta.maintainers = with lib.maintainers; [ rnhmjoj ];
+
+    enableOCR = true;
+
+    nodes.machine = { pkgs, ... }:
+      { imports =
+          [ ./common/user-account.nix
+            ./common/x11.nix
+            webserverConfig
+          ];
+
+        # chromium-based browsers refuse to run as root
+        test-support.displayManager.auto.user = "alice";
+
+        # browsers may hang with the default memory
+        virtualisation.memorySize = 600;
+
+        environment.systemPackages = [ pkgs.xdotool pkgs.${browser} ];
+      };
+
+    testScript = ''
+      from typing import Tuple
+      def execute_as(user: str, cmd: str) -> Tuple[int, str]:
+          """
+          Run a shell command as a specific user.
+          """
+          return machine.execute(f"sudo -u {user} {cmd}")
+
+
+      def wait_for_window_as(user: str, cls: str) -> None:
+          """
+          Wait until a X11 window of a given user appears.
+          """
+
+          def window_is_visible(last_try: bool) -> bool:
+              ret, stdout = execute_as(user, f"xdotool search --onlyvisible --class {cls}")
+              if last_try:
+                  machine.log(f"Last chance to match {cls} on the window list")
+              return ret == 0
+
+          with machine.nested("Waiting for a window to appear"):
+              retry(window_is_visible)
+
+
+      machine.start()
+      machine.wait_for_x()
+
+      command = "${browser} ${testParams.args or ""}"
+      with subtest("Good certificate is trusted in ${browser}"):
+          execute_as(
+              "alice", f"{command} https://good.example.com >&2 &"
+          )
+          wait_for_window_as("alice", "${browser}")
+          machine.sleep(4)
+          execute_as("alice", "xdotool key ctrl+r")  # reload to be safe
+          machine.wait_for_text("It works!")
+          machine.screenshot("good${browser}")
+          execute_as("alice", "xdotool key ctrl+w")  # close tab
+
+      with subtest("Unknown CA is untrusted in ${browser}"):
+          execute_as("alice", f"{command} https://bad.example.com >&2 &")
+          machine.wait_for_text("${testParams.error}")
+          machine.screenshot("bad${browser}")
+    '';
+  };
+
+in
+
+{
+  curl = curlTest;
+} // pkgs.lib.mapAttrs mkBrowserTest {
+  firefox = { error = "Security Risk"; };
+  chromium = { error = "not private"; };
+  qutebrowser = { args = "-T"; error = "Certificate error"; };
+  midori = { error = "Security"; };
+}
diff --git a/nixpkgs/nixos/tests/deluge.nix b/nixpkgs/nixos/tests/deluge.nix
index 33c57ce7c36c..0cd1d21870ad 100644
--- a/nixpkgs/nixos/tests/deluge.nix
+++ b/nixpkgs/nixos/tests/deluge.nix
@@ -47,7 +47,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
 
     simple.wait_for_unit("deluged")
     simple.wait_for_unit("delugeweb")
-    simple.wait_for_open_port("8112")
+    simple.wait_for_open_port(8112)
     declarative.wait_for_unit("network.target")
     declarative.wait_until_succeeds("curl --fail http://simple:8112")
 
diff --git a/nixpkgs/nixos/tests/disable-installer-tools.nix b/nixpkgs/nixos/tests/disable-installer-tools.nix
index 23c15faa8d33..69f99122753a 100644
--- a/nixpkgs/nixos/tests/disable-installer-tools.nix
+++ b/nixpkgs/nixos/tests/disable-installer-tools.nix
@@ -3,7 +3,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }:
 {
   name = "disable-installer-tools";
 
-  machine =
+  nodes.machine =
     { pkgs, lib, ... }:
     {
         system.disableInstallerTools = true;
diff --git a/nixpkgs/nixos/tests/discourse.nix b/nixpkgs/nixos/tests/discourse.nix
index cfac5f84a62f..35ca083c6c4e 100644
--- a/nixpkgs/nixos/tests/discourse.nix
+++ b/nixpkgs/nixos/tests/discourse.nix
@@ -30,6 +30,7 @@ import ./make-test-python.nix (
         virtualisation.memorySize = 2048;
         virtualisation.cores = 4;
         virtualisation.useNixStoreImage = true;
+        virtualisation.writableStore = false;
 
         imports = [ common/user-account.nix ];
 
diff --git a/nixpkgs/nixos/tests/dnsdist.nix b/nixpkgs/nixos/tests/dnsdist.nix
index cfc41c13864e..e72fa05ff282 100644
--- a/nixpkgs/nixos/tests/dnsdist.nix
+++ b/nixpkgs/nixos/tests/dnsdist.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix (
       maintainers = with maintainers; [ jojosch ];
     };
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       services.bind = {
         enable = true;
         extraOptions = "empty-zones-enable no;";
diff --git a/nixpkgs/nixos/tests/doas.nix b/nixpkgs/nixos/tests/doas.nix
index 7f038b2bee29..3713c728195c 100644
--- a/nixpkgs/nixos/tests/doas.nix
+++ b/nixpkgs/nixos/tests/doas.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix (
       maintainers = [ cole-h ];
     };
 
-    machine =
+    nodes.machine =
       { ... }:
         {
           users.groups = { foobar = {}; barfoo = {}; baz = { gid = 1337; }; };
diff --git a/nixpkgs/nixos/tests/docker-edge.nix b/nixpkgs/nixos/tests/docker-edge.nix
deleted file mode 100644
index c6a1a0830189..000000000000
--- a/nixpkgs/nixos/tests/docker-edge.nix
+++ /dev/null
@@ -1,49 +0,0 @@
-# This test runs docker and checks if simple container starts
-
-import ./make-test-python.nix ({ pkgs, ...} : {
-  name = "docker";
-  meta = with pkgs.lib.maintainers; {
-    maintainers = [ nequissimus offline ];
-  };
-
-  nodes = {
-    docker =
-      { pkgs, ... }:
-        {
-          virtualisation.docker.enable = true;
-          virtualisation.docker.package = pkgs.docker-edge;
-
-          users.users = {
-            noprivs = {
-              isNormalUser = true;
-              description = "Can't access the docker daemon";
-              password = "foobar";
-            };
-
-            hasprivs = {
-              isNormalUser = true;
-              description = "Can access the docker daemon";
-              password = "foobar";
-              extraGroups = [ "docker" ];
-            };
-          };
-        };
-    };
-
-  testScript = ''
-    start_all()
-
-    docker.wait_for_unit("sockets.target")
-    docker.succeed("tar cv --files-from /dev/null | docker import - scratchimg")
-    docker.succeed(
-        "docker run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
-    )
-    docker.succeed("docker ps | grep sleeping")
-    docker.succeed("sudo -u hasprivs docker ps")
-    docker.fail("sudo -u noprivs docker ps")
-    docker.succeed("docker stop sleeping")
-
-    # Must match version 4 times to ensure client and server git commits and versions are correct
-    docker.succeed('[ $(docker version | grep ${pkgs.docker-edge.version} | wc -l) = "4" ]')
-  '';
-})
diff --git a/nixpkgs/nixos/tests/docker-registry.nix b/nixpkgs/nixos/tests/docker-registry.nix
index 1d449db45191..316b7c9b9727 100644
--- a/nixpkgs/nixos/tests/docker-registry.nix
+++ b/nixpkgs/nixos/tests/docker-registry.nix
@@ -35,7 +35,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
 
     registry.start()
     registry.wait_for_unit("docker-registry.service")
-    registry.wait_for_open_port("8080")
+    registry.wait_for_open_port(8080)
     client1.succeed("docker push registry:8080/scratch")
 
     client2.start()
diff --git a/nixpkgs/nixos/tests/docker-tools-cross.nix b/nixpkgs/nixos/tests/docker-tools-cross.nix
index a7a6a31475d6..14cb14ceeaea 100644
--- a/nixpkgs/nixos/tests/docker-tools-cross.nix
+++ b/nixpkgs/nixos/tests/docker-tools-cross.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
 let
 
   remoteSystem =
-    if pkgs.system == "aarch64-linux"
+    if pkgs.stdenv.hostPlatform.system == "aarch64-linux"
     then "x86_64-linux"
     else "aarch64-linux";
 
@@ -18,13 +18,17 @@ let
 
     # NOTE: Since this file can't control where the test will be _run_ we don't
     #       cross-compile _to_ a different system but _from_ a different system
-    crossSystem = pkgs.system;
+    crossSystem = pkgs.stdenv.hostPlatform.system;
   };
 
   hello1 = remoteCrossPkgs.dockerTools.buildImage {
     name = "hello1";
     tag = "latest";
-    contents = remoteCrossPkgs.hello;
+    copyToRoot = remoteCrossPkgs.buildEnv {
+      name = "image-root";
+      pathsToLink = [ "/bin" ];
+      paths = [ remoteCrossPkgs.hello ];
+    };
   };
 
   hello2 = remoteCrossPkgs.dockerTools.buildLayeredImage {
diff --git a/nixpkgs/nixos/tests/docker-tools.nix b/nixpkgs/nixos/tests/docker-tools.nix
index 8a240ddb17f2..d76f70b791ce 100644
--- a/nixpkgs/nixos/tests/docker-tools.nix
+++ b/nixpkgs/nixos/tests/docker-tools.nix
@@ -315,7 +315,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
                 "docker inspect ${pkgs.dockerTools.examples.cross.imageName} "
                 + "| ${pkgs.jq}/bin/jq -r .[].Architecture"
             ).strip()
-            == "${if pkgs.system == "aarch64-linux" then "amd64" else "arm64"}"
+            == "${if pkgs.stdenv.hostPlatform.system == "aarch64-linux" then "amd64" else "arm64"}"
         )
 
     with subtest("buildLayeredImage doesn't dereference /nix/store symlink layers"):
@@ -346,7 +346,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
             "docker load --input='${examples.layeredImageWithFakeRootCommands}'"
         )
         docker.succeed(
-            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/jane | grep -E ^1000$'"
+            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/alice | grep -E ^1000$'"
         )
 
     with subtest("Ensure docker load on merged images loads all of the constituent images"):
@@ -389,7 +389,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
             "docker load --input='${examples.mergedBashFakeRoot}'"
         )
         docker.succeed(
-            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/jane | grep -E ^1000$'"
+            "docker run --rm ${examples.layeredImageWithFakeRootCommands.imageName} sh -c 'stat -c '%u' /home/alice | grep -E ^1000$'"
         )
 
     with subtest("The image contains store paths referenced by the fakeRootCommands output"):
@@ -419,5 +419,10 @@ import ./make-test-python.nix ({ pkgs, ... }: {
             "docker rmi layered-image-with-path",
         )
 
+    with subtest("etc"):
+        docker.succeed("${examples.etc} | docker load")
+        docker.succeed("docker run --rm etc | grep localhost")
+        docker.succeed("docker image rm etc:latest")
+
   '';
 })
diff --git a/nixpkgs/nixos/tests/documize.nix b/nixpkgs/nixos/tests/documize.nix
index d5a77ffcd4f2..fda79b1a0931 100644
--- a/nixpkgs/nixos/tests/documize.nix
+++ b/nixpkgs/nixos/tests/documize.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     maintainers = [ ma27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.jq ];
 
     services.documize = {
@@ -47,9 +47,9 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
             " --data 'dbhash={}'"
             " --data 'title=NixOS'"
             " --data 'message=Docs'"
-            " --data 'firstname=John'"
-            " --data 'lastname=Doe'"
-            " --data 'email=john.doe@nixos.org'"
+            " --data 'firstname=Bob'"
+            " --data 'lastname=Foobar'"
+            " --data 'email=bob.foobar@nixos.org'"
             " --data 'password=verysafe'"
             " -f localhost:3000/api/setup"
         ).format(dbhash)
diff --git a/nixpkgs/nixos/tests/domination.nix b/nixpkgs/nixos/tests/domination.nix
index c76d4ed8c61b..09027740ab8d 100644
--- a/nixpkgs/nixos/tests/domination.nix
+++ b/nixpkgs/nixos/tests/domination.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/dovecot.nix b/nixpkgs/nixos/tests/dovecot.nix
index 8913c2a6a7e8..5439387807fd 100644
--- a/nixpkgs/nixos/tests/dovecot.nix
+++ b/nixpkgs/nixos/tests/dovecot.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "dovecot";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ common/user-account.nix ];
     services.postfix.enable = true;
     services.dovecot2 = {
diff --git a/nixpkgs/nixos/tests/ecryptfs.nix b/nixpkgs/nixos/tests/ecryptfs.nix
index ef7bd13eb92c..1c67d307a00e 100644
--- a/nixpkgs/nixos/tests/ecryptfs.nix
+++ b/nixpkgs/nixos/tests/ecryptfs.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ ... }:
 {
   name = "ecryptfs";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ./common/user-account.nix ];
     boot.kernelModules = [ "ecryptfs" ];
     security.pam.enableEcryptfs = true;
@@ -11,16 +11,16 @@ import ./make-test-python.nix ({ ... }:
 
   testScript = ''
     def login_as_alice():
-        machine.wait_until_tty_matches(1, "login: ")
+        machine.wait_until_tty_matches("1", "login: ")
         machine.send_chars("alice\n")
-        machine.wait_until_tty_matches(1, "Password: ")
+        machine.wait_until_tty_matches("1", "Password: ")
         machine.send_chars("foobar\n")
-        machine.wait_until_tty_matches(1, "alice\@machine")
+        machine.wait_until_tty_matches("1", "alice\@machine")
 
 
     def logout():
         machine.send_chars("logout\n")
-        machine.wait_until_tty_matches(1, "login: ")
+        machine.wait_until_tty_matches("1", "login: ")
 
 
     machine.wait_for_unit("default.target")
@@ -36,7 +36,7 @@ import ./make-test-python.nix ({ ... }:
     with subtest("Log alice in (ecryptfs passwhrase is wrapped during first login)"):
         login_as_alice()
         machine.send_chars("logout\n")
-        machine.wait_until_tty_matches(1, "login: ")
+        machine.wait_until_tty_matches("1", "login: ")
 
     # Why do I need to do this??
     machine.succeed("su alice -c ecryptfs-umount-private || true")
diff --git a/nixpkgs/nixos/tests/emacs-daemon.nix b/nixpkgs/nixos/tests/emacs-daemon.nix
index e12da56021da..310e93e19b0b 100644
--- a/nixpkgs/nixos/tests/emacs-daemon.nix
+++ b/nixpkgs/nixos/tests/emacs-daemon.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
 
   enableOCR = true;
 
-  machine =
+  nodes.machine =
     { ... }:
 
     { imports = [ ./common/x11.nix ];
@@ -33,7 +33,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
       )
 
       # connects to the daemon
-      machine.succeed("emacsclient --create-frame $EDITOR >&2 &")
+      machine.succeed("emacsclient --no-wait --frame-parameters='((display . \"'\"$DISPLAY\"'\"))' --create-frame $EDITOR >&2")
 
       # checks that Emacs shows the edited filename
       machine.wait_for_text("emacseditor")
diff --git a/nixpkgs/nixos/tests/enlightenment.nix b/nixpkgs/nixos/tests/enlightenment.nix
index 8506c348246d..2e06eedd9915 100644
--- a/nixpkgs/nixos/tests/enlightenment.nix
+++ b/nixpkgs/nixos/tests/enlightenment.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ romildo ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
   {
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
diff --git a/nixpkgs/nixos/tests/env.nix b/nixpkgs/nixos/tests/env.nix
index fc96ace6b2d2..dec17b6b565a 100644
--- a/nixpkgs/nixos/tests/env.nix
+++ b/nixpkgs/nixos/tests/env.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ nequissimus ];
   };
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
     {
       boot.kernelPackages = pkgs.linuxPackages;
       environment.etc.plainFile.text = ''
diff --git a/nixpkgs/nixos/tests/envoy.nix b/nixpkgs/nixos/tests/envoy.nix
new file mode 100644
index 000000000000..9d2c32ce102f
--- /dev/null
+++ b/nixpkgs/nixos/tests/envoy.nix
@@ -0,0 +1,33 @@
+import ./make-test-python.nix ({ pkgs, lib, ...} : {
+  name = "envoy";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ cameronnemo ];
+  };
+
+  nodes.machine = { pkgs, ... }: {
+    services.envoy.enable = true;
+    services.envoy.settings = {
+      admin = {
+        access_log_path = "/dev/null";
+        address = {
+          socket_address = {
+            protocol = "TCP";
+            address = "127.0.0.1";
+            port_value = 9901;
+          };
+        };
+      };
+      static_resources = {
+        listeners = [];
+        clusters = [];
+      };
+    };
+  };
+
+  testScript = ''
+    machine.start()
+    machine.wait_for_unit("envoy.service")
+    machine.wait_for_open_port(9901)
+    machine.wait_until_succeeds("curl -fsS localhost:9901/ready")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/etebase-server.nix b/nixpkgs/nixos/tests/etebase-server.nix
index 4fc3c1f6392f..49bfccf359e2 100644
--- a/nixpkgs/nixos/tests/etebase-server.nix
+++ b/nixpkgs/nixos/tests/etebase-server.nix
@@ -9,7 +9,7 @@ in {
       maintainers = [ felschr ];
     };
 
-    machine = { pkgs, ... }:
+    nodes.machine = { pkgs, ... }:
       {
         services.etebase-server = {
           inherit dataDir;
diff --git a/nixpkgs/nixos/tests/etesync-dav.nix b/nixpkgs/nixos/tests/etesync-dav.nix
index 6a747e23f76f..f49152c60991 100644
--- a/nixpkgs/nixos/tests/etesync-dav.nix
+++ b/nixpkgs/nixos/tests/etesync-dav.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ _3699n ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
       environment.systemPackages = [ pkgs.curl pkgs.etesync-dav ];
   };
 
diff --git a/nixpkgs/nixos/tests/extra-python-packages.nix b/nixpkgs/nixos/tests/extra-python-packages.nix
new file mode 100644
index 000000000000..7a48077cf98b
--- /dev/null
+++ b/nixpkgs/nixos/tests/extra-python-packages.nix
@@ -0,0 +1,13 @@
+import ./make-test-python.nix ({ ... }:
+  {
+    name = "extra-python-packages";
+
+    extraPythonPackages = p: [ p.numpy ];
+
+    nodes = { };
+
+    testScript = ''
+      import numpy as np
+      assert str(np.zeros(4) == "array([0., 0., 0., 0.])")
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/fancontrol.nix b/nixpkgs/nixos/tests/fancontrol.nix
index 296c68026415..ecb936097446 100644
--- a/nixpkgs/nixos/tests/fancontrol.nix
+++ b/nixpkgs/nixos/tests/fancontrol.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... } : {
     maintainers = [ evils ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
     hardware.fancontrol.enable = true;
     hardware.fancontrol.config = ''
diff --git a/nixpkgs/nixos/tests/fcitx/default.nix b/nixpkgs/nixos/tests/fcitx/default.nix
index a243be8dc19b..c132249fcb24 100644
--- a/nixpkgs/nixos/tests/fcitx/default.nix
+++ b/nixpkgs/nixos/tests/fcitx/default.nix
@@ -5,7 +5,8 @@ import ../make-test-python.nix (
     # copy_from_host works only for store paths
     rec {
         name = "fcitx";
-        machine =
+        meta.broken = true; # takes hours to time out since October 2021
+        nodes.machine =
         {
           pkgs,
           ...
diff --git a/nixpkgs/nixos/tests/fenics.nix b/nixpkgs/nixos/tests/fenics.nix
index f0a8c32c7cd8..1d182cfc4499 100644
--- a/nixpkgs/nixos/tests/fenics.nix
+++ b/nixpkgs/nixos/tests/fenics.nix
@@ -44,6 +44,6 @@ in
     { nodes, ... }:
     ''
       start_all()
-      node1.succeed("${fenicsScript}")
+      fenicsnode.succeed("${fenicsScript}")
     '';
 })
diff --git a/nixpkgs/nixos/tests/firefox.nix b/nixpkgs/nixos/tests/firefox.nix
index 6101fc973564..3f9cea6662fb 100644
--- a/nixpkgs/nixos/tests/firefox.nix
+++ b/nixpkgs/nixos/tests/firefox.nix
@@ -1,15 +1,24 @@
-import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }: {
-  name = "firefox";
+import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }:
+let firefoxPackage' = firefoxPackage.override (args: {
+      extraPrefsFiles = (args.extraPrefsFiles or []) ++ [
+        # make sure that autoplay is enabled by default for the audio test
+        (builtins.toString (builtins.toFile "autoplay-pref.js" ''defaultPref("media.autoplay.default",0);''))
+      ];
+  });
+
+in
+{
+  name = firefoxPackage'.unwrapped.pname;
   meta = with pkgs.lib.maintainers; {
     maintainers = [ eelco shlevy ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
 
     { imports = [ ./common/x11.nix ];
       environment.systemPackages = [
-        firefoxPackage
+        firefoxPackage'
         pkgs.xdotool
       ];
 
@@ -54,7 +63,7 @@ import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }: {
 
 
       @contextmanager
-      def audio_recording(machine: Machine) -> None:
+      def record_audio(machine: Machine):
           """
           Perform actions while recording the
           machine audio output.
@@ -64,7 +73,7 @@ import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }: {
           machine.systemctl("stop audio-recorder")
 
 
-      def wait_for_sound(machine: Machine) -> None:
+      def wait_for_sound(machine: Machine):
           """
           Wait until any sound has been emitted.
           """
@@ -88,15 +97,15 @@ import ./make-test-python.nix ({ pkgs, firefoxPackage, ... }: {
 
       with subtest("Wait until Firefox has finished loading the Valgrind docs page"):
           machine.execute(
-              "xterm -e 'firefox file://${pkgs.valgrind.doc}/share/doc/valgrind/html/index.html' >&2 &"
+              "xterm -e '${firefoxPackage'.unwrapped.binaryName} file://${pkgs.valgrind.doc}/share/doc/valgrind/html/index.html' >&2 &"
           )
           machine.wait_for_window("Valgrind")
           machine.sleep(40)
 
       with subtest("Check whether Firefox can play sound"):
-          with audio_recording(machine):
+          with record_audio(machine):
               machine.succeed(
-                  "firefox file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga >&2 &"
+                  "${firefoxPackage'.unwrapped.binaryName} file://${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/phone-incoming-call.oga >&2 &"
               )
               wait_for_sound(machine)
           machine.copy_from_vm("/tmp/record.wav")
diff --git a/nixpkgs/nixos/tests/fish.nix b/nixpkgs/nixos/tests/fish.nix
index 68fba428439b..3d9b13c6af70 100644
--- a/nixpkgs/nixos/tests/fish.nix
+++ b/nixpkgs/nixos/tests/fish.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "fish";
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
 
     {
diff --git a/nixpkgs/nixos/tests/fluentd.nix b/nixpkgs/nixos/tests/fluentd.nix
index 918f2f87db17..150638f246f2 100644
--- a/nixpkgs/nixos/tests/fluentd.nix
+++ b/nixpkgs/nixos/tests/fluentd.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "fluentd";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.fluentd = {
       enable = true;
       config = ''
diff --git a/nixpkgs/nixos/tests/fontconfig-default-fonts.nix b/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
index 58d0f6227cc7..664afc9bf44c 100644
--- a/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
+++ b/nixpkgs/nixos/tests/fontconfig-default-fonts.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ lib, ... }:
     jtojnar
   ];
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     fonts.enableDefaultFonts = true; # Background fonts
     fonts.fonts = with pkgs; [
       noto-fonts-emoji
diff --git a/nixpkgs/nixos/tests/freeswitch.nix b/nixpkgs/nixos/tests/freeswitch.nix
index bcc6a9cb3586..bfb7339ec3c0 100644
--- a/nixpkgs/nixos/tests/freeswitch.nix
+++ b/nixpkgs/nixos/tests/freeswitch.nix
@@ -24,6 +24,6 @@ import ./make-test-python.nix ({ pkgs, ...} : {
   testScript = ''
     node0.wait_for_unit("freeswitch.service")
     # Wait for SIP port to be open
-    node0.wait_for_open_port("5060")
+    node0.wait_for_open_port(5060)
   '';
 })
diff --git a/nixpkgs/nixos/tests/fsck.nix b/nixpkgs/nixos/tests/fsck.nix
index 5453f3bc48b5..5b8b09f433a2 100644
--- a/nixpkgs/nixos/tests/fsck.nix
+++ b/nixpkgs/nixos/tests/fsck.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "fsck";
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     virtualisation.emptyDiskImages = [ 1 ];
 
     virtualisation.fileSystems = {
diff --git a/nixpkgs/nixos/tests/ft2-clone.nix b/nixpkgs/nixos/tests/ft2-clone.nix
index 71eda43e2b24..3c90b3d3fa20 100644
--- a/nixpkgs/nixos/tests/ft2-clone.nix
+++ b/nixpkgs/nixos/tests/ft2-clone.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/geth.nix b/nixpkgs/nixos/tests/geth.nix
index af8230553bbb..11ad1ed2ea66 100644
--- a/nixpkgs/nixos/tests/geth.nix
+++ b/nixpkgs/nixos/tests/geth.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = with maintainers; [bachp ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.geth."mainnet" = {
       enable = true;
       http = {
diff --git a/nixpkgs/nixos/tests/gitlab.nix b/nixpkgs/nixos/tests/gitlab.nix
index dc3b889c8e8e..d9d75d1cbd89 100644
--- a/nixpkgs/nixos/tests/gitlab.nix
+++ b/nixpkgs/nixos/tests/gitlab.nix
@@ -1,12 +1,34 @@
-# This test runs gitlab and checks if it works
+# This test runs gitlab and performs the following tests:
+# - Creating users
+# - Pushing commits
+#   - over the API
+#   - over SSH
+# - Creating Merge Requests and merging them
+# - Opening and closing issues.
+# - Downloading repository archives as tar.gz and tar.bz2
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+
+with lib;
 
 let
+  inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
   initialRootPassword = "notproduction";
-in
-import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
+  rootProjectId = "2";
+
+  aliceUsername = "alice";
+  aliceUserId = "2";
+  alicePassword = "alicepassword";
+  aliceProjectId = "2";
+  aliceProjectName = "test-alice";
+
+  bobUsername = "bob";
+  bobUserId = "3";
+  bobPassword = "bobpassword";
+  bobProjectId = "3";
+in {
   name = "gitlab";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ globin ];
+    maintainers = [ globin yayayayaka ];
   };
 
   nodes = {
@@ -16,6 +38,8 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
       virtualisation.memorySize = if pkgs.stdenv.is64bit then 4096 else 2047;
       virtualisation.cores = 4;
       virtualisation.useNixStoreImage = true;
+      virtualisation.writableStore = false;
+
       systemd.services.gitlab.serviceConfig.Restart = mkForce "no";
       systemd.services.gitlab-workhorse.serviceConfig.Restart = mkForce "no";
       systemd.services.gitaly.serviceConfig.Restart = mkForce "no";
@@ -31,6 +55,8 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
         };
       };
 
+      services.openssh.enable = true;
+
       services.dovecot2 = {
         enable = true;
         enableImap = true;
@@ -77,8 +103,43 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
         password = initialRootPassword;
       });
 
-      createProject = pkgs.writeText "create-project.json" (builtins.toJSON {
-        name = "test";
+      createUserAlice = pkgs.writeText "create-user-alice.json" (builtins.toJSON rec {
+        username = aliceUsername;
+        name = username;
+        email = "alice@localhost";
+        password = alicePassword;
+        skip_confirmation = true;
+      });
+
+      createUserBob = pkgs.writeText "create-user-bob.json" (builtins.toJSON rec {
+        username = bobUsername;
+        name = username;
+        email = "bob@localhost";
+        password = bobPassword;
+        skip_confirmation = true;
+      });
+
+      aliceAuth = pkgs.writeText "alice-auth.json" (builtins.toJSON {
+        grant_type = "password";
+        username = aliceUsername;
+        password = alicePassword;
+      });
+
+      bobAuth = pkgs.writeText "bob-auth.json" (builtins.toJSON {
+        grant_type = "password";
+        username = bobUsername;
+        password = bobPassword;
+      });
+
+      aliceAddSSHKey = pkgs.writeText "alice-add-ssh-key.json" (builtins.toJSON {
+        id = aliceUserId;
+        title = "snakeoil@nixos";
+        key = snakeOilPublicKey;
+      });
+
+      createProjectAlice = pkgs.writeText "create-project-alice.json" (builtins.toJSON {
+        name = aliceProjectName;
+        visibility = "public";
       });
 
       putFile = pkgs.writeText "put-file.json" (builtins.toJSON {
@@ -89,6 +150,23 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
         commit_message = "create a new file";
       });
 
+      mergeRequest = pkgs.writeText "merge-request.json" (builtins.toJSON {
+        id = bobProjectId;
+        target_project_id = aliceProjectId;
+        source_branch = "master";
+        target_branch = "master";
+        title = "Add some other file";
+      });
+
+      newIssue = pkgs.writeText "new-issue.json" (builtins.toJSON {
+        title = "useful issue title";
+      });
+
+      closeIssue = pkgs.writeText "close-issue.json" (builtins.toJSON {
+        issue_iid = 1;
+        state_event = "close";
+      });
+
       # Wait for all GitLab services to be fully started.
       waitForServices = ''
         gitlab.wait_for_unit("gitaly.service")
@@ -105,6 +183,8 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
       # The actual test of GitLab. Only push data to GitLab if
       # `doSetup` is is true.
       test = doSetup: ''
+        GIT_SSH_COMMAND = "ssh -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/dev/null"
+
         gitlab.succeed(
             "curl -isSf http://gitlab | grep -i location | grep http://gitlab/users/sign_in"
         )
@@ -112,24 +192,225 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with lib; {
             "${pkgs.sudo}/bin/sudo -u gitlab -H gitlab-rake gitlab:check 1>&2"
         )
         gitlab.succeed(
-            "echo \"Authorization: Bearer \$(curl -X POST -H 'Content-Type: application/json' -d @${auth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers"
+            "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${auth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers"
         )
       '' + optionalString doSetup ''
-        gitlab.succeed(
-            "curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createProject} http://gitlab/api/v4/projects"
-        )
-        gitlab.succeed(
-            "curl -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${putFile} http://gitlab/api/v4/projects/1/repository/files/some-file.txt"
-        )
+        with subtest("Create user Alice"):
+            gitlab.succeed(
+                """[ "$(curl -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createUserAlice} http://gitlab/api/v4/users)" = "201" ]"""
+            )
+            gitlab.succeed(
+                "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${aliceAuth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers-alice"
+            )
+
+        with subtest("Create user Bob"):
+            gitlab.succeed(
+                """ [ "$(curl -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -H @/tmp/headers -d @${createUserBob} http://gitlab/api/v4/users)" = "201" ]"""
+            )
+            gitlab.succeed(
+                "echo \"Authorization: Bearer $(curl -X POST -H 'Content-Type: application/json' -d @${bobAuth} http://gitlab/oauth/token | ${pkgs.jq}/bin/jq -r '.access_token')\" >/tmp/headers-bob"
+            )
+
+        with subtest("Setup Git and SSH for Alice"):
+            gitlab.succeed("git config --global user.name Alice")
+            gitlab.succeed("git config --global user.email alice@nixos.invalid")
+            gitlab.succeed("mkdir -m 700 /root/.ssh")
+            gitlab.succeed("cat ${snakeOilPrivateKey} > /root/.ssh/id_ecdsa")
+            gitlab.succeed("chmod 600 /root/.ssh/id_ecdsa")
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-alice -d @${aliceAddSSHKey} \
+                    http://gitlab/api/v4/user/keys)" = "201" ]
+                """
+            )
+
+        with subtest("Create a new repository"):
+            # Alice creates a new repository
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-alice \
+                    -d @${createProjectAlice} \
+                    http://gitlab/api/v4/projects)" = "201" ]
+                """
+            )
+
+            # Alice commits an initial commit
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-alice \
+                    -d @${putFile} \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/repository/files/some-file.txt)" = "201" ]"""
+            )
+
+        with subtest("git clone over HTTP"):
+            gitlab.succeed(
+                """git clone http://gitlab/alice/${aliceProjectName}.git clone-via-http""",
+                timeout=15
+            )
+
+        with subtest("Push a commit via SSH"):
+            gitlab.succeed(
+                f"""GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git clone gitlab@gitlab:alice/${aliceProjectName}.git""",
+                timeout=15
+            )
+            gitlab.succeed(
+                """echo "a commit sent over ssh" > ${aliceProjectName}/ssh.txt"""
+            )
+            gitlab.succeed(
+                """
+                cd ${aliceProjectName} || exit 1
+                git add .
+                """
+            )
+            gitlab.succeed(
+                """
+                cd ${aliceProjectName} || exit 1
+                git commit -m "Add a commit to be sent over ssh"
+                """
+            )
+            gitlab.succeed(
+                f"""
+                cd ${aliceProjectName} || exit 1
+                GIT_SSH_COMMAND="{GIT_SSH_COMMAND}" git push --set-upstream origin master
+                """,
+                timeout=15
+            )
+
+        with subtest("Fork a project"):
+            # Bob forks Alice's project
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-bob \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/fork)" = "201" ]
+                """
+            )
+
+            # Bob creates a commit
+            gitlab.wait_until_succeeds(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-bob \
+                    -d @${putFile} \
+                    http://gitlab/api/v4/projects/${bobProjectId}/repository/files/some-other-file.txt)" = "201" ]
+                """
+            )
+
+        with subtest("Create a Merge Request"):
+            # Bob opens a merge request against Alice's repository
+            gitlab.wait_until_succeeds(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-bob \
+                    -d @${mergeRequest} \
+                    http://gitlab/api/v4/projects/${bobProjectId}/merge_requests)" = "201" ]
+                """
+            )
+
+            # Alice merges the MR
+            gitlab.wait_until_succeeds(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X PUT \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-alice \
+                    -d @${mergeRequest} \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/merge_requests/1/merge)" = "200" ]
+                """
+            )
+
+        with subtest("Create an Issue"):
+            # Bob opens an issue on Alice's repository
+            gitlab.succeed(
+                """[ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X POST \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-bob \
+                    -d @${newIssue} \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/issues)" = "201" ]
+                """
+            )
+
+            # Alice closes the issue
+            gitlab.wait_until_succeeds(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -X PUT \
+                    -H 'Content-Type: application/json' \
+                    -H @/tmp/headers-alice -d @${closeIssue} http://gitlab/api/v4/projects/${aliceProjectId}/issues/1)" = "200" ]
+                """
+            )
       '' + ''
-        gitlab.succeed(
-            "curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.gz > /tmp/archive.tar.gz"
-        )
-        gitlab.succeed(
-            "curl -H @/tmp/headers http://gitlab/api/v4/projects/1/repository/archive.tar.bz2 > /tmp/archive.tar.bz2"
-        )
-        gitlab.succeed("test -s /tmp/archive.tar.gz")
-        gitlab.succeed("test -s /tmp/archive.tar.bz2")
+        with subtest("Download archive.tar.gz"):
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -H @/tmp/headers-alice \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz)" = "200" ]
+                """
+            )
+            gitlab.succeed(
+                """
+                curl \
+                    -H @/tmp/headers-alice \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.gz > /tmp/archive.tar.gz
+                """
+            )
+            gitlab.succeed("test -s /tmp/archive.tar.gz")
+
+        with subtest("Download archive.tar.bz2"):
+            gitlab.succeed(
+                """
+                [ "$(curl \
+                    -o /dev/null \
+                    -w '%{http_code}' \
+                    -H @/tmp/headers-alice \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2)" = "200" ]
+                """
+            )
+            gitlab.succeed(
+                """
+                curl \
+                    -H @/tmp/headers-alice \
+                    http://gitlab/api/v4/projects/${aliceProjectId}/repository/archive.tar.bz2 > /tmp/archive.tar.bz2
+                """
+            )
+            gitlab.succeed("test -s /tmp/archive.tar.bz2")
       '';
 
   in ''
diff --git a/nixpkgs/nixos/tests/gitolite.nix b/nixpkgs/nixos/tests/gitolite.nix
index 128677cebde3..9b3af59e4fbd 100644
--- a/nixpkgs/nixos/tests/gitolite.nix
+++ b/nixpkgs/nixos/tests/gitolite.nix
@@ -107,7 +107,7 @@ in
     with subtest("gitolite server starts"):
         server.wait_for_unit("gitolite-init.service")
         server.wait_for_unit("sshd.service")
-        client.succeed("ssh gitolite@server info")
+        client.succeed("ssh -n gitolite@server info")
 
     with subtest("admin can clone and configure gitolite-admin.git"):
         client.succeed(
diff --git a/nixpkgs/nixos/tests/gnome-xorg.nix b/nixpkgs/nixos/tests/gnome-xorg.nix
index d7be531e364e..618458b1f6b5 100644
--- a/nixpkgs/nixos/tests/gnome-xorg.nix
+++ b/nixpkgs/nixos/tests/gnome-xorg.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     maintainers = teams.gnome.members;
   };
 
-  machine = { nodes, ... }: let
+  nodes.machine = { nodes, ... }: let
     user = nodes.machine.config.users.users.alice;
   in
 
diff --git a/nixpkgs/nixos/tests/gnome.nix b/nixpkgs/nixos/tests/gnome.nix
index ca49183fe442..05619cbd7d82 100644
--- a/nixpkgs/nixos/tests/gnome.nix
+++ b/nixpkgs/nixos/tests/gnome.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     maintainers = teams.gnome.members;
   };
 
-  machine =
+  nodes.machine =
     { ... }:
 
     { imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/gocd-agent.nix b/nixpkgs/nixos/tests/gocd-agent.nix
index 686d0b971d30..9301a88ec05d 100644
--- a/nixpkgs/nixos/tests/gocd-agent.nix
+++ b/nixpkgs/nixos/tests/gocd-agent.nix
@@ -36,7 +36,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
   testScript = ''
     start_all()
     agent.wait_for_unit("gocd-server")
-    agent.wait_for_open_port("8153")
+    agent.wait_for_open_port(8153)
     agent.wait_for_unit("gocd-agent")
     agent.wait_until_succeeds(
         "curl ${serverUrl} -H '${header}' | ${pkgs.jq}/bin/jq -e ._embedded.agents[0].uuid"
diff --git a/nixpkgs/nixos/tests/gotify-server.nix b/nixpkgs/nixos/tests/gotify-server.nix
index 051666fbe72e..e7942b76d8e5 100644
--- a/nixpkgs/nixos/tests/gotify-server.nix
+++ b/nixpkgs/nixos/tests/gotify-server.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     maintainers = [ ma27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.jq ];
 
     services.gotify = {
diff --git a/nixpkgs/nixos/tests/grafana-agent.nix b/nixpkgs/nixos/tests/grafana-agent.nix
new file mode 100644
index 000000000000..a9f34d8cea31
--- /dev/null
+++ b/nixpkgs/nixos/tests/grafana-agent.nix
@@ -0,0 +1,32 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+
+  let
+    nodes = {
+      machine = {
+        services.grafana-agent = {
+          enable = true;
+        };
+      };
+    };
+  in
+  {
+    name = "grafana-agent";
+
+    meta = with lib.maintainers; {
+      maintainers = [ zimbatm ];
+    };
+
+    inherit nodes;
+
+    testScript = ''
+      start_all()
+
+      with subtest("Grafana-agent is running"):
+          machine.wait_for_unit("grafana-agent.service")
+          machine.wait_for_open_port(12345)
+          machine.succeed(
+              "curl -sSfN http://127.0.0.1:12345/-/healthy"
+          )
+          machine.shutdown()
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/graphite.nix b/nixpkgs/nixos/tests/graphite.nix
index 496f16846ea6..c534d45428e1 100644
--- a/nixpkgs/nixos/tests/graphite.nix
+++ b/nixpkgs/nixos/tests/graphite.nix
@@ -12,14 +12,8 @@ import ./make-test-python.nix ({ pkgs, ... } :
               SECRET_KEY = "abcd";
             '';
           };
-          api = {
-            enable = true;
-            port = 8082;
-            finders = [ ];
-          };
           carbon.enableCache = true;
           seyren.enable = false;  # Implicitely requires openssl-1.0.2u which is marked insecure
-          beacon.enable = true;
         };
       };
   };
@@ -28,21 +22,15 @@ import ./make-test-python.nix ({ pkgs, ... } :
     start_all()
     one.wait_for_unit("default.target")
     one.wait_for_unit("graphiteWeb.service")
-    one.wait_for_unit("graphiteApi.service")
-    one.wait_for_unit("graphite-beacon.service")
     one.wait_for_unit("carbonCache.service")
     # The services above are of type "simple". systemd considers them active immediately
     # even if they're still in preStart (which takes quite long for graphiteWeb).
     # Wait for ports to open so we're sure the services are up and listening.
     one.wait_for_open_port(8080)
-    one.wait_for_open_port(8082)
     one.wait_for_open_port(2003)
     one.succeed('echo "foo 1 `date +%s`" | nc -N localhost 2003')
     one.wait_until_succeeds(
         "curl 'http://localhost:8080/metrics/find/?query=foo&format=treejson' --silent | grep foo >&2"
     )
-    one.wait_until_succeeds(
-        "curl 'http://localhost:8082/metrics/find/?query=foo&format=treejson' --silent | grep foo >&2"
-    )
   '';
 })
diff --git a/nixpkgs/nixos/tests/graylog.nix b/nixpkgs/nixos/tests/graylog.nix
index 572904f60d57..23f426fc7af9 100644
--- a/nixpkgs/nixos/tests/graylog.nix
+++ b/nixpkgs/nixos/tests/graylog.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "graylog";
   meta.maintainers = with lib.maintainers; [ ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.memorySize = 4096;
     virtualisation.diskSize = 4096;
 
diff --git a/nixpkgs/nixos/tests/grocy.nix b/nixpkgs/nixos/tests/grocy.nix
index 2be5c24ecb55..fe0ddd341486 100644
--- a/nixpkgs/nixos/tests/grocy.nix
+++ b/nixpkgs/nixos/tests/grocy.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ ma27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.grocy = {
       enable = true;
       hostName = "localhost";
diff --git a/nixpkgs/nixos/tests/grub.nix b/nixpkgs/nixos/tests/grub.nix
index 84bfc90955b5..e0875e70f6a5 100644
--- a/nixpkgs/nixos/tests/grub.nix
+++ b/nixpkgs/nixos/tests/grub.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ lib, ... }: {
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     virtualisation.useBootLoader = true;
 
     boot.loader.timeout = null;
diff --git a/nixpkgs/nixos/tests/hadoop/default.nix b/nixpkgs/nixos/tests/hadoop/default.nix
index d2a97cbeffb8..479690adc064 100644
--- a/nixpkgs/nixos/tests/hadoop/default.nix
+++ b/nixpkgs/nixos/tests/hadoop/default.nix
@@ -4,4 +4,5 @@
   all = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./hadoop.nix { inherit package; };
   hdfs = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./hdfs.nix { inherit package; };
   yarn = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./yarn.nix { inherit package; };
+  hbase = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./hbase.nix { inherit package; };
 }
diff --git a/nixpkgs/nixos/tests/hadoop/hbase.nix b/nixpkgs/nixos/tests/hadoop/hbase.nix
new file mode 100644
index 000000000000..d9d2dac0f658
--- /dev/null
+++ b/nixpkgs/nixos/tests/hadoop/hbase.nix
@@ -0,0 +1,84 @@
+# Test a minimal hbase cluster
+{ pkgs, ... }:
+import ../make-test-python.nix ({ hadoop ? pkgs.hadoop, hbase ? pkgs.hbase, ... }:
+with pkgs.lib;
+{
+  name = "hadoop-hbase";
+
+  nodes = let
+    coreSite = {
+      "fs.defaultFS" = "hdfs://namenode:8020";
+    };
+    defOpts = {
+      enable = true;
+      openFirewall = true;
+    };
+    zookeeperQuorum = "zookeeper";
+  in {
+    zookeeper = { ... }: {
+      services.zookeeper.enable = true;
+      networking.firewall.allowedTCPPorts = [ 2181 ];
+    };
+    namenode = { ... }: {
+      services.hadoop = {
+        hdfs = {
+          namenode = defOpts // { formatOnInit = true; };
+        };
+        inherit coreSite;
+      };
+    };
+    datanode = { ... }: {
+      virtualisation.diskSize = 8192;
+      services.hadoop = {
+        hdfs.datanode = defOpts;
+        inherit coreSite;
+      };
+    };
+
+    master = { ... }:{
+      services.hadoop = {
+        inherit coreSite;
+        hbase = {
+          inherit zookeeperQuorum;
+          master = defOpts // { initHDFS = true; };
+        };
+      };
+    };
+    regionserver = { ... }:{
+      services.hadoop = {
+        inherit coreSite;
+        hbase = {
+          inherit zookeeperQuorum;
+          regionServer = defOpts;
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+
+    # wait for HDFS cluster
+    namenode.wait_for_unit("hdfs-namenode")
+    namenode.wait_for_unit("network.target")
+    namenode.wait_for_open_port(8020)
+    namenode.wait_for_open_port(9870)
+    datanode.wait_for_unit("hdfs-datanode")
+    datanode.wait_for_unit("network.target")
+    datanode.wait_for_open_port(9864)
+    datanode.wait_for_open_port(9866)
+    datanode.wait_for_open_port(9867)
+
+    # wait for ZK
+    zookeeper.wait_for_unit("zookeeper")
+    zookeeper.wait_for_open_port(2181)
+
+    # wait for HBase to start up
+    master.wait_for_unit("hbase-master")
+    regionserver.wait_for_unit("hbase-regionserver")
+
+    assert "1 active master, 0 backup masters, 1 servers" in master.succeed("echo status | HADOOP_USER_NAME=hbase hbase shell -n")
+    regionserver.wait_until_succeeds("echo \"create 't1','f1'\" | HADOOP_USER_NAME=hbase hbase shell -n")
+    assert "NAME => 'f1'" in regionserver.succeed("echo \"describe 't1'\" | HADOOP_USER_NAME=hbase hbase shell -n")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/hadoop/yarn.nix b/nixpkgs/nixos/tests/hadoop/yarn.nix
index 1bf8e3831f67..08c8ff857d8c 100644
--- a/nixpkgs/nixos/tests/hadoop/yarn.nix
+++ b/nixpkgs/nixos/tests/hadoop/yarn.nix
@@ -19,7 +19,7 @@ import ../make-test-python.nix ({ package, ... }: {
           enable = true;
           openFirewall = true;
         };
-        yarnSite = options.services.hadoop.yarnSite.default // {
+        yarnSite = {
           "yarn.resourcemanager.hostname" = "resourcemanager";
           "yarn.nodemanager.log-dirs" = "/tmp/userlogs";
         };
diff --git a/nixpkgs/nixos/tests/hardened.nix b/nixpkgs/nixos/tests/hardened.nix
index dc455f971f5c..ccb858168547 100644
--- a/nixpkgs/nixos/tests/hardened.nix
+++ b/nixpkgs/nixos/tests/hardened.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... } : {
     maintainers = [ joachifm ];
   };
 
-  machine =
+  nodes.machine =
     { lib, pkgs, config, ... }:
     with lib;
     { users.users.alice = { isNormalUser = true; extraGroups = [ "proc" ]; };
@@ -12,6 +12,11 @@ import ./make-test-python.nix ({ pkgs, ... } : {
       imports = [ ../modules/profiles/hardened.nix ];
       environment.memoryAllocator.provider = "graphene-hardened";
       nix.settings.sandbox = false;
+      nixpkgs.overlays = [
+        (final: super: {
+          dhcpcd = super.dhcpcd.override { enablePrivSep = false; };
+        })
+      ];
       virtualisation.emptyDiskImages = [ 4096 ];
       boot.initrd.postDeviceCommands = ''
         ${pkgs.dosfstools}/bin/mkfs.vfat -n EFISYS /dev/vdb
@@ -85,8 +90,8 @@ import ./make-test-python.nix ({ pkgs, ... } : {
 
       # Test Nix dæmon usage
       with subtest("nix-daemon cannot be used by all users"):
-          machine.fail("su -l nobody -s /bin/sh -c 'nix ping-store'")
-          machine.succeed("su -l alice -c 'nix ping-store'")
+          machine.fail("su -l nobody -s /bin/sh -c 'nix --extra-experimental-features nix-command ping-store'")
+          machine.succeed("su -l alice -c 'nix --extra-experimental-features nix-command ping-store'")
 
 
       # Test kernel image protection
diff --git a/nixpkgs/nixos/tests/haste-server.nix b/nixpkgs/nixos/tests/haste-server.nix
new file mode 100644
index 000000000000..9097c992c548
--- /dev/null
+++ b/nixpkgs/nixos/tests/haste-server.nix
@@ -0,0 +1,23 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+  {
+    name = "haste-server";
+    meta.maintainers = with lib.maintainers; [ mkg20001 ];
+
+    nodes.machine = { pkgs, ... }: {
+      environment.systemPackages = with pkgs; [
+        curl
+        jq
+      ];
+
+      services.haste-server = {
+        enable = true;
+      };
+    };
+
+    testScript = ''
+      machine.wait_for_unit("haste-server")
+      machine.wait_until_succeeds("curl -s localhost:7777")
+      machine.succeed('curl -s -X POST http://localhost:7777/documents -d "Hello World!" > bla')
+      machine.succeed('curl http://localhost:7777/raw/$(cat bla | jq -r .key) | grep "Hello World"')
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/hbase.nix b/nixpkgs/nixos/tests/hbase.nix
new file mode 100644
index 000000000000..7d8e32f81603
--- /dev/null
+++ b/nixpkgs/nixos/tests/hbase.nix
@@ -0,0 +1,30 @@
+import ./make-test-python.nix ({ pkgs, lib, package ? pkgs.hbase, ... }:
+{
+  name = "hbase-standalone";
+
+  meta = with lib.maintainers; {
+    maintainers = [ illustris ];
+  };
+
+  nodes = {
+    hbase = { pkgs, ... }: {
+      services.hbase-standalone = {
+        enable = true;
+        inherit package;
+        # Needed for standalone mode in hbase 2+
+        # This setting and standalone mode are not suitable for production
+        settings."hbase.unsafe.stream.capability.enforce" = "false";
+      };
+      environment.systemPackages = with pkgs; [
+        package
+      ];
+    };
+  };
+
+  testScript = ''
+    start_all()
+    hbase.wait_for_unit("hbase.service")
+    hbase.wait_until_succeeds("echo \"create 't1','f1'\" | sudo -u hbase hbase shell -n")
+    assert "NAME => 'f1'" in hbase.succeed("echo \"describe 't1'\" | sudo -u hbase hbase shell -n")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/hedgedoc.nix b/nixpkgs/nixos/tests/hedgedoc.nix
index 657d49c555e9..410350d83627 100644
--- a/nixpkgs/nixos/tests/hedgedoc.nix
+++ b/nixpkgs/nixos/tests/hedgedoc.nix
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       services = {
         hedgedoc = {
           enable = true;
-          configuration.dbURL = "sqlite:///var/lib/hedgedoc/hedgedoc.db";
+          settings.dbURL = "sqlite:///var/lib/hedgedoc/hedgedoc.db";
         };
       };
     };
@@ -21,7 +21,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       services = {
         hedgedoc = {
           enable = true;
-          configuration.dbURL = "postgres://hedgedoc:\${DB_PASSWORD}@localhost:5432/hedgedocdb";
+          settings.dbURL = "postgres://hedgedoc:\${DB_PASSWORD}@localhost:5432/hedgedocdb";
 
           /*
            * Do not use pkgs.writeText for secrets as
diff --git a/nixpkgs/nixos/tests/herbstluftwm.nix b/nixpkgs/nixos/tests/herbstluftwm.nix
index 7d079f4bfb69..b6965914360e 100644
--- a/nixpkgs/nixos/tests/herbstluftwm.nix
+++ b/nixpkgs/nixos/tests/herbstluftwm.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ lib, ...} : {
     maintainers = with lib.maintainers; [ thibautmarty ];
   };
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     test-support.displayManager.auto.user = "alice";
     services.xserver.displayManager.defaultSession = lib.mkForce "none+herbstluftwm";
diff --git a/nixpkgs/nixos/tests/hibernate.nix b/nixpkgs/nixos/tests/hibernate.nix
index 3880f1649bd3..7a4b331169a3 100644
--- a/nixpkgs/nixos/tests/hibernate.nix
+++ b/nixpkgs/nixos/tests/hibernate.nix
@@ -3,6 +3,7 @@
 { system ? builtins.currentSystem
 , config ? {}
 , pkgs ? import ../.. { inherit system config; }
+, systemdStage1 ? false
 }:
 
 with import ../lib/testing-python.nix { inherit system pkgs; };
@@ -29,6 +30,11 @@ let
       "/".device = "/dev/vda2";
     };
     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;
@@ -117,6 +123,11 @@ in makeTest {
       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")
     '';
 
 }
diff --git a/nixpkgs/nixos/tests/hitch/default.nix b/nixpkgs/nixos/tests/hitch/default.nix
index a1d8e6162606..4283b9f7dffb 100644
--- a/nixpkgs/nixos/tests/hitch/default.nix
+++ b/nixpkgs/nixos/tests/hitch/default.nix
@@ -4,7 +4,7 @@ import ../make-test-python.nix ({ pkgs, ... }:
   meta = with pkgs.lib.maintainers; {
     maintainers = [ jflanglois ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.curl ];
     services.hitch = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/hocker-fetchdocker/default.nix b/nixpkgs/nixos/tests/hocker-fetchdocker/default.nix
index e3979db3c60b..b5c06126c2e8 100644
--- a/nixpkgs/nixos/tests/hocker-fetchdocker/default.nix
+++ b/nixpkgs/nixos/tests/hocker-fetchdocker/default.nix
@@ -5,7 +5,7 @@ import ../make-test-python.nix ({ pkgs, ...} : {
     broken = true; # tries to download from registry-1.docker.io - how did this ever work?
   };
 
-  machine = import ./machine.nix;
+  nodes.machine = import ./machine.nix;
 
   testScript = ''
     start_all()
diff --git a/nixpkgs/nixos/tests/hockeypuck.nix b/nixpkgs/nixos/tests/hockeypuck.nix
index 19df9dee3d31..d1ef4cbf588a 100644
--- a/nixpkgs/nixos/tests/hockeypuck.nix
+++ b/nixpkgs/nixos/tests/hockeypuck.nix
@@ -24,7 +24,7 @@ in {
   name = "hockeypuck";
   meta.maintainers = with lib.maintainers; [ etu ];
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     # Used for test
     environment.systemPackages = [ pkgs.gnupg ];
 
diff --git a/nixpkgs/nixos/tests/home-assistant.nix b/nixpkgs/nixos/tests/home-assistant.nix
index 10f9cb05c9cb..0bbeffd18cf0 100644
--- a/nixpkgs/nixos/tests/home-assistant.nix
+++ b/nixpkgs/nixos/tests/home-assistant.nix
@@ -7,8 +7,6 @@ in {
   meta.maintainers = lib.teams.home-assistant.members;
 
   nodes.hass = { pkgs, ... }: {
-    environment.systemPackages = with pkgs; [ mosquitto ];
-
     services.postgresql = {
       enable = true;
       ensureDatabases = [ "hass" ];
@@ -98,10 +96,26 @@ in {
       };
       lovelaceConfigWritable = true;
     };
+
+    # Cause a configuration change inside `configuration.yml` and verify that the process is being reloaded.
+    specialisation.differentName = {
+      inheritParentConfig = true;
+      configuration.services.home-assistant.config.homeassistant.name = lib.mkForce "Test Home";
+    };
+
+    # Cause a configuration change that requires a service restart as we added a new runtime dependency
+    specialisation.newFeature = {
+      inheritParentConfig = true;
+      configuration.services.home-assistant.config.esphome = {};
+    };
   };
 
-  testScript = ''
+  testScript = { nodes, ... }: let
+    system = nodes.hass.config.system.build.toplevel;
+  in
+  ''
     import re
+    import json
 
     start_all()
 
@@ -111,9 +125,22 @@ in {
     pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass")
     response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1]
     match = pattern.search(response)
+    assert match
     package = match.group('path')
 
+
+    def get_journal_cursor(host) -> str:
+        exit, out = host.execute("journalctl -u home-assistant.service -n1 -o json-pretty --output-fields=__CURSOR")
+        assert exit == 0
+        return json.loads(out)["__CURSOR"]
+
+
+    def wait_for_homeassistant(host, cursor):
+        host.wait_until_succeeds(f"journalctl --after-cursor='{cursor}' -u home-assistant.service | grep -q 'Home Assistant initialized in'")
+
+
     hass.wait_for_unit("home-assistant.service")
+    cursor = get_journal_cursor(hass)
 
     with subtest("Check that YAML configuration file is in place"):
         hass.succeed("test -L ${configDir}/configuration.yaml")
@@ -130,7 +157,7 @@ in {
         hass.succeed(f"grep -q 'wake_on_lan' {package}/extra_components")
 
     with subtest("Check that Home Assistant's web interface and API can be reached"):
-        hass.wait_until_succeeds("journalctl -u home-assistant.service | grep -q 'Home Assistant initialized in'")
+        wait_for_homeassistant(hass, cursor)
         hass.wait_for_open_port(8123)
         hass.succeed("curl --fail http://localhost:8123/lovelace")
 
@@ -141,12 +168,25 @@ in {
     with subtest("Check extra components are considered in systemd unit hardening"):
         hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB")
 
-    with subtest("Print log to ease debugging"):
-        output_log = hass.succeed("cat ${configDir}/home-assistant.log")
-        print("\n### home-assistant.log ###\n")
-        print(output_log + "\n")
+    with subtest("Check service reloads when configuration changes"):
+      # store the old pid of the process
+      pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
+      cursor = get_journal_cursor(hass)
+      hass.succeed("${system}/specialisation/differentName/bin/switch-to-configuration test")
+      new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
+      assert pid == new_pid, "The PID of the process should not change between process reloads"
+      wait_for_homeassistant(hass, cursor)
+
+    with subtest("check service restarts when package changes"):
+      pid = new_pid
+      cursor = get_journal_cursor(hass)
+      hass.succeed("${system}/specialisation/newFeature/bin/switch-to-configuration test")
+      new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
+      assert pid != new_pid, "The PID of the process shoudl change when the HA binary changes"
+      wait_for_homeassistant(hass, cursor)
 
     with subtest("Check that no errors were logged"):
+        output_log = hass.succeed("cat ${configDir}/home-assistant.log")
         assert "ERROR" not in output_log
 
     with subtest("Check systemd unit hardening"):
diff --git a/nixpkgs/nixos/tests/hostname.nix b/nixpkgs/nixos/tests/hostname.nix
index 2e92b4259a6a..1de8f19267af 100644
--- a/nixpkgs/nixos/tests/hostname.nix
+++ b/nixpkgs/nixos/tests/hostname.nix
@@ -20,7 +20,7 @@ let
           maintainers = [ primeos blitz ];
         };
 
-        machine = { lib, ... }: {
+        nodes.machine = { lib, ... }: {
           networking.hostName = hostName;
           networking.domain = domain;
 
diff --git a/nixpkgs/nixos/tests/hound.nix b/nixpkgs/nixos/tests/hound.nix
index 4f51db1de9de..a9b036deb0dd 100644
--- a/nixpkgs/nixos/tests/hound.nix
+++ b/nixpkgs/nixos/tests/hound.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... } : {
   meta = with pkgs.lib.maintainers; {
     maintainers = [ grahamc ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.hound = {
       enable = true;
       config = ''
diff --git a/nixpkgs/nixos/tests/hydra/default.nix b/nixpkgs/nixos/tests/hydra/default.nix
index ef5e677953dc..baf18afbc569 100644
--- a/nixpkgs/nixos/tests/hydra/default.nix
+++ b/nixpkgs/nixos/tests/hydra/default.nix
@@ -11,7 +11,7 @@ let
   inherit (import ./common.nix { inherit system; }) baseConfig;
 
   hydraPkgs = {
-    inherit (pkgs) hydra-unstable;
+    inherit (pkgs) hydra_unstable;
   };
 
   makeHydraTest = with pkgs.lib; name: package: makeTest {
@@ -20,7 +20,7 @@ let
       maintainers = [ lewo ma27 ];
     };
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ baseConfig ];
       services.hydra = { inherit package; };
     };
diff --git a/nixpkgs/nixos/tests/i3wm.nix b/nixpkgs/nixos/tests/i3wm.nix
index 59b4ffe3986e..b216650d8192 100644
--- a/nixpkgs/nixos/tests/i3wm.nix
+++ b/nixpkgs/nixos/tests/i3wm.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ aszlig ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     test-support.displayManager.auto.user = "alice";
     services.xserver.displayManager.defaultSession = lib.mkForce "none+i3";
diff --git a/nixpkgs/nixos/tests/ihatemoney/default.nix b/nixpkgs/nixos/tests/ihatemoney/default.nix
index 78278d2e8699..894a97d43d35 100644
--- a/nixpkgs/nixos/tests/ihatemoney/default.nix
+++ b/nixpkgs/nixos/tests/ihatemoney/default.nix
@@ -7,7 +7,7 @@ let
   inherit (import ../../lib/testing-python.nix { inherit system pkgs; }) makeTest;
   f = backend: makeTest {
     name = "ihatemoney-${backend}";
-    machine = { nodes, lib, ... }: {
+    nodes.machine = { nodes, lib, ... }: {
       services.ihatemoney = {
         enable = true;
         enablePublicProjectCreation = true;
@@ -32,14 +32,7 @@ let
         };
       };
       # ihatemoney needs a local smtp server otherwise project creation just crashes
-      services.opensmtpd = {
-        enable = true;
-        serverConfiguration = ''
-          listen on lo
-          action foo relay
-          match from any for any action foo
-        '';
-      };
+      services.postfix.enable = true;
     };
     testScript = ''
       machine.wait_for_open_port(8000)
diff --git a/nixpkgs/nixos/tests/incron.nix b/nixpkgs/nixos/tests/incron.nix
index b22ee4c9a037..c978ff27dfad 100644
--- a/nixpkgs/nixos/tests/incron.nix
+++ b/nixpkgs/nixos/tests/incron.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
   name = "incron";
   meta.maintainers = [ lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.incron.enable = true;
       services.incron.extraPackages = [ pkgs.coreutils ];
diff --git a/nixpkgs/nixos/tests/initrd-network.nix b/nixpkgs/nixos/tests/initrd-network.nix
index 14e7e7d40bc5..f2483b7393de 100644
--- a/nixpkgs/nixos/tests/initrd-network.nix
+++ b/nixpkgs/nixos/tests/initrd-network.nix
@@ -3,7 +3,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
 
   meta.maintainers = [ pkgs.lib.maintainers.eelco ];
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
     boot.initrd.network.enable = true;
     boot.initrd.network.postCommands =
diff --git a/nixpkgs/nixos/tests/initrd-secrets.nix b/nixpkgs/nixos/tests/initrd-secrets.nix
index 113a9cebf788..0f3f83b0904e 100644
--- a/nixpkgs/nixos/tests/initrd-secrets.nix
+++ b/nixpkgs/nixos/tests/initrd-secrets.nix
@@ -11,7 +11,7 @@ let
 
     meta.maintainers = [ lib.maintainers.lheckemann ];
 
-    machine = { ... }: {
+    nodes.machine = { ... }: {
       virtualisation.useBootLoader = true;
       boot.initrd.secrets = {
         "/test" = secretInStore;
diff --git a/nixpkgs/nixos/tests/input-remapper.nix b/nixpkgs/nixos/tests/input-remapper.nix
index f692564caa57..1b0350063f7f 100644
--- a/nixpkgs/nixos/tests/input-remapper.nix
+++ b/nixpkgs/nixos/tests/input-remapper.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
       maintainers = with pkgs.lib.maintainers; [ LunNova ];
     };
 
-    machine = { config, ... }:
+    nodes.machine = { config, ... }:
       let user = config.users.users.sybil; in
       {
         imports = [
diff --git a/nixpkgs/nixos/tests/installed-tests/default.nix b/nixpkgs/nixos/tests/installed-tests/default.nix
index 079fd54e71e5..b81384aa8c0b 100644
--- a/nixpkgs/nixos/tests/installed-tests/default.nix
+++ b/nixpkgs/nixos/tests/installed-tests/default.nix
@@ -43,7 +43,7 @@ let
             maintainers = tested.meta.maintainers;
           };
 
-          machine = { ... }: {
+          nodes.machine = { ... }: {
             imports = [
               testConfig
             ] ++ optional withX11 ../common/x11.nix;
@@ -92,6 +92,7 @@ in
   fwupd = callInstalledTest ./fwupd.nix {};
   gcab = callInstalledTest ./gcab.nix {};
   gdk-pixbuf = callInstalledTest ./gdk-pixbuf.nix {};
+  geocode-glib = callInstalledTest ./geocode-glib.nix {};
   gjs = callInstalledTest ./gjs.nix {};
   glib-networking = callInstalledTest ./glib-networking.nix {};
   gnome-photos = callInstalledTest ./gnome-photos.nix {};
@@ -106,6 +107,5 @@ in
   malcontent = callInstalledTest ./malcontent.nix {};
   ostree = callInstalledTest ./ostree.nix {};
   pipewire = callInstalledTest ./pipewire.nix {};
-  power-profiles-daemon = callInstalledTest ./power-profiles-daemon.nix {};
   xdg-desktop-portal = callInstalledTest ./xdg-desktop-portal.nix {};
 }
diff --git a/nixpkgs/nixos/tests/installed-tests/flatpak-builder.nix b/nixpkgs/nixos/tests/installed-tests/flatpak-builder.nix
index 31b9f2b258fd..41f4060fb69e 100644
--- a/nixpkgs/nixos/tests/installed-tests/flatpak-builder.nix
+++ b/nixpkgs/nixos/tests/installed-tests/flatpak-builder.nix
@@ -6,6 +6,7 @@ makeInstalledTest {
   testConfig = {
     services.flatpak.enable = true;
     xdg.portal.enable = true;
+    xdg.portal.extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
     environment.systemPackages = with pkgs; [ flatpak-builder ] ++ flatpak-builder.installedTestsDependencies;
     virtualisation.diskSize = 2048;
   };
diff --git a/nixpkgs/nixos/tests/installed-tests/geocode-glib.nix b/nixpkgs/nixos/tests/installed-tests/geocode-glib.nix
new file mode 100644
index 000000000000..fcb38c96ab0f
--- /dev/null
+++ b/nixpkgs/nixos/tests/installed-tests/geocode-glib.nix
@@ -0,0 +1,13 @@
+{ pkgs, makeInstalledTest, ... }:
+
+makeInstalledTest {
+  testConfig = {
+    i18n.supportedLocales = [
+      "en_US.UTF-8/UTF-8"
+      # The tests require this locale available.
+      "en_GB.UTF-8/UTF-8"
+    ];
+  };
+
+  tested = pkgs.geocode-glib;
+}
diff --git a/nixpkgs/nixos/tests/installed-tests/power-profiles-daemon.nix b/nixpkgs/nixos/tests/installed-tests/power-profiles-daemon.nix
deleted file mode 100644
index 43629a0155d2..000000000000
--- a/nixpkgs/nixos/tests/installed-tests/power-profiles-daemon.nix
+++ /dev/null
@@ -1,9 +0,0 @@
-{ pkgs, lib, makeInstalledTest, ... }:
-
-makeInstalledTest {
-  tested = pkgs.power-profiles-daemon;
-
-  testConfig = {
-    services.power-profiles-daemon.enable = true;
-  };
-}
diff --git a/nixpkgs/nixos/tests/installer-systemd-stage-1.nix b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
new file mode 100644
index 000000000000..d02387ee80e0
--- /dev/null
+++ b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
@@ -0,0 +1,33 @@
+{ system ? builtins.currentSystem
+, config ? {}
+, pkgs ? import ../.. { inherit system config; }
+}:
+
+{
+  # Some of these tests don't work with systemd stage 1 yet. Uncomment
+  # them when fixed.
+  inherit (import ./installer.nix { inherit system config pkgs; systemdStage1 = true; })
+    # bcache
+    # btrfsSimple
+    # btrfsSubvolDefault
+    # btrfsSubvols
+    # encryptedFSWithKeyfile
+    # grub1
+    # luksroot
+    # luksroot-format1
+    # luksroot-format2
+    # lvm
+    separateBoot
+    separateBootFat
+    simple
+    simpleLabels
+    simpleProvided
+    simpleSpecialised
+    simpleUefiGrub
+    simpleUefiGrubSpecialisation
+    simpleUefiSystemdBoot
+    # swraid
+    zfsroot
+    ;
+
+}
diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix
index 2cfadf85c935..8bef4fad3dd2 100644
--- a/nixpkgs/nixos/tests/installer.nix
+++ b/nixpkgs/nixos/tests/installer.nix
@@ -1,6 +1,7 @@
 { system ? builtins.currentSystem,
   config ? {},
-  pkgs ? import ../.. { inherit system config; }
+  pkgs ? import ../.. { inherit system config; },
+  systemdStage1 ? false
 }:
 
 with import ../lib/testing-python.nix { inherit system pkgs; };
@@ -23,6 +24,8 @@ let
         # To ensure that we can rebuild the grub configuration on the nixos-rebuild
         system.extraDependencies = with pkgs; [ stdenvNoCC ];
 
+        ${optionalString systemdStage1 "boot.initrd.systemd.enable = true;"}
+
         ${optionalString (bootLoader == "grub") ''
           boot.loader.grub.version = ${toString grubVersion};
           ${optionalString (grubVersion == 1) ''
@@ -290,6 +293,8 @@ let
           virtualisation.cores = 8;
           virtualisation.memorySize = 1536;
 
+          boot.initrd.systemd.enable = systemdStage1;
+
           # Use a small /dev/vdb as the root disk for the
           # installer. This ensures the target disk (/dev/vda) is
           # the same during and after installation.
@@ -299,6 +304,13 @@ let
           virtualisation.qemu.diskInterface =
             if grubVersion == 1 then "scsi" else "virtio";
 
+          # We don't want to have any networking in the guest whatsoever.
+          # Also, if any vlans are enabled, the guest will reboot
+          # (with a different configuration for legacy reasons),
+          # and spend 5 minutes waiting for the vlan interface to show up
+          # (which will never happen).
+          virtualisation.vlans = [];
+
           boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true;
 
           hardware.enableAllFirmware = mkForce false;
@@ -312,6 +324,8 @@ let
             desktop-file-utils
             docbook5
             docbook_xsl_ns
+            kmod.dev
+            libarchive.dev
             libxml2.bin
             libxslt.bin
             nixos-artwork.wallpapers.simple-dark-gray-bottom
@@ -687,6 +701,85 @@ in {
     '';
   };
 
+  bcachefsSimple = makeInstallerTest "bcachefs-simple" {
+    extraInstallerConfig = {
+      boot.supportedFilesystems = [ "bcachefs" ];
+    };
+
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"          # /boot
+        + " mkpart primary linux-swap 100M 1024M"  # swap
+        + " mkpart primary 1024M -1s",             # /
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "mkfs.bcachefs -L root /dev/vda3",
+        "mount -t bcachefs /dev/vda3 /mnt",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount /dev/vda1 /mnt/boot",
+      )
+    '';
+  };
+
+  bcachefsEncrypted = makeInstallerTest "bcachefs-encrypted" {
+    extraInstallerConfig = {
+      boot.supportedFilesystems = [ "bcachefs" ];
+      environment.systemPackages = with pkgs; [ keyutils ];
+    };
+
+    # We don't want to use the normal way of unlocking bcachefs defined in tasks/filesystems/bcachefs.nix.
+    # So, override initrd.postDeviceCommands completely and simply unlock with the predefined password.
+    extraConfig = ''
+      boot.initrd.postDeviceCommands = lib.mkForce "echo password | bcachefs unlock /dev/vda3";
+    '';
+
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"          # /boot
+        + " mkpart primary linux-swap 100M 1024M"  # swap
+        + " mkpart primary 1024M -1s",             # /
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "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",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount /dev/vda1 /mnt/boot",
+      )
+    '';
+  };
+
+  bcachefsMulti = makeInstallerTest "bcachefs-multi" {
+    extraInstallerConfig = {
+      boot.supportedFilesystems = [ "bcachefs" ];
+    };
+
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"          # /boot
+        + " mkpart primary linux-swap 100M 1024M"  # swap
+        + " mkpart primary 1024M 4096M"            # /
+        + " mkpart primary 4096M -1s",             # /
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "mkfs.bcachefs -L root --metadata_replicas 2 --foreground_target ssd --promote_target ssd --background_target hdd --label ssd /dev/vda3 --label hdd /dev/vda4",
+        "mount -t bcachefs /dev/vda3:/dev/vda4 /mnt",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount /dev/vda1 /mnt/boot",
+      )
+    '';
+  };
+
   # Test a basic install using GRUB 1.
   grub1 = makeInstallerTest "grub1" rec {
     createPartitions = ''
diff --git a/nixpkgs/nixos/tests/invidious.nix b/nixpkgs/nixos/tests/invidious.nix
index 8b831715a441..582d1550fff1 100644
--- a/nixpkgs/nixos/tests/invidious.nix
+++ b/nixpkgs/nixos/tests/invidious.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ sbruder ];
   };
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     services.invidious = {
       enable = true;
     };
diff --git a/nixpkgs/nixos/tests/ipfs.nix b/nixpkgs/nixos/tests/ipfs.nix
index 5e7c967028e4..024822745ada 100644
--- a/nixpkgs/nixos/tests/ipfs.nix
+++ b/nixpkgs/nixos/tests/ipfs.nix
@@ -14,6 +14,14 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     };
   };
 
+  nodes.fuse = { ... }: {
+    services.ipfs = {
+      enable = true;
+      apiAddress = "/ip4/127.0.0.1/tcp/2324";
+      autoMount = true;
+    };
+  };
+
   testScript = ''
     start_all()
 
@@ -40,5 +48,14 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     # Test if setting dataDir works properly with the hardened systemd unit
     machine.succeed("test -e /mnt/ipfs/config")
     machine.succeed("test ! -e /var/lib/ipfs/")
+
+    # Test FUSE mountpoint
+    ipfs_hash = fuse.succeed(
+        "echo fnord3 | ipfs --api /ip4/127.0.0.1/tcp/2324 add --quieter"
+    )
+
+    # The FUSE mount functionality is broken as of v0.13.0.
+    # See https://github.com/ipfs/kubo/issues/9044.
+    # fuse.succeed(f"cat /ipfs/{ipfs_hash.strip()} | grep fnord3")
   '';
 })
diff --git a/nixpkgs/nixos/tests/isso.nix b/nixpkgs/nixos/tests/isso.nix
index 99dc8009ae06..575e1c52eccf 100644
--- a/nixpkgs/nixos/tests/isso.nix
+++ b/nixpkgs/nixos/tests/isso.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ asbachb ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     services.isso = {
       enable = true;
       settings = {
@@ -22,7 +22,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   ''
     machine.wait_for_unit("isso.service")
 
-    machine.wait_for_open_port("${toString port}")
+    machine.wait_for_open_port(${toString port})
 
     machine.succeed("curl --fail http://localhost:${toString port}/?uri")
     machine.succeed("curl --fail http://localhost:${toString port}/js/embed.min.js")
diff --git a/nixpkgs/nixos/tests/jellyfin.nix b/nixpkgs/nixos/tests/jellyfin.nix
index cae31a719258..7d3097b58629 100644
--- a/nixpkgs/nixos/tests/jellyfin.nix
+++ b/nixpkgs/nixos/tests/jellyfin.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
     name = "jellyfin";
     meta.maintainers = with lib.maintainers; [ minijackson ];
 
-    machine =
+    nodes.machine =
       { ... }:
       {
         services.jellyfin.enable = true;
@@ -52,18 +52,18 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
             machine.succeed(api_post("/Startup/Complete"))
 
         with machine.nested("Can login"):
-            auth_result = machine.succeed(
+            auth_result_str = machine.succeed(
                 api_post(
                     "/Users/AuthenticateByName",
                     "${payloads.auth}",
                 )
             )
-            auth_result = json.loads(auth_result)
+            auth_result = json.loads(auth_result_str)
             auth_token = auth_result["AccessToken"]
             auth_header += f", Token={auth_token}"
 
-            sessions_result = machine.succeed(api_get("/Sessions"))
-            sessions_result = json.loads(sessions_result)
+            sessions_result_str = machine.succeed(api_get("/Sessions"))
+            sessions_result = json.loads(sessions_result_str)
 
             this_session = [
                 session for session in sessions_result if session["DeviceId"] == "1337"
@@ -71,8 +71,8 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
             if len(this_session) != 1:
                 raise Exception("Session not created")
 
-            me = machine.succeed(api_get("/Users/Me"))
-            me = json.loads(me)["Id"]
+            me_str = machine.succeed(api_get("/Users/Me"))
+            me = json.loads(me_str)["Id"]
 
         with machine.nested("Can add library"):
             tempdir = machine.succeed("mktemp -d -p /var/lib/jellyfin").strip()
@@ -100,8 +100,8 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
 
 
         def is_refreshed(_):
-            folders = machine.succeed(api_get("/Library/VirtualFolders"))
-            folders = json.loads(folders)
+            folders_str = machine.succeed(api_get("/Library/VirtualFolders"))
+            folders = json.loads(folders_str)
             print(folders)
             return all(folder["RefreshStatus"] == "Idle" for folder in folders)
 
@@ -116,10 +116,10 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
             def has_movie(_):
                 global items
 
-                items = machine.succeed(
+                items_str = machine.succeed(
                     api_get(f"/Users/{me}/Items?IncludeItemTypes=Movie&Recursive=true")
                 )
-                items = json.loads(items)["Items"]
+                items = json.loads(items_str)["Items"]
 
                 return len(items) == 1
 
@@ -127,8 +127,8 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
 
             video = items[0]["Id"]
 
-            item_info = machine.succeed(api_get(f"/Users/{me}/Items/{video}"))
-            item_info = json.loads(item_info)
+            item_info_str = machine.succeed(api_get(f"/Users/{me}/Items/{video}"))
+            item_info = json.loads(item_info_str)
 
             if item_info["Name"] != "Big Buck Bunny":
                 raise Exception("Jellyfin failed to properly identify file")
diff --git a/nixpkgs/nixos/tests/jenkins.nix b/nixpkgs/nixos/tests/jenkins.nix
index cb4207c6e773..3f111426db38 100644
--- a/nixpkgs/nixos/tests/jenkins.nix
+++ b/nixpkgs/nixos/tests/jenkins.nix
@@ -18,6 +18,8 @@ import ./make-test-python.nix ({ pkgs, ...} : {
           enable = true;
           jobBuilder = {
             enable = true;
+            accessUser = "admin";
+            accessTokenFile = "/var/lib/jenkins/secrets/initialAdminPassword";
             nixJobs = [
               { job = {
                   name = "job-1";
@@ -79,7 +81,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     in ''
     start_all()
 
-    master.wait_for_unit("jenkins")
+    master.wait_for_unit("default.target")
 
     assert "Authentication required" in master.succeed("curl http://localhost:8080")
 
@@ -90,20 +92,16 @@ import ./make-test-python.nix ({ pkgs, ...} : {
 
     slave.fail("systemctl is-enabled jenkins.service")
 
+    slave.succeed("java -fullversion")
+
     with subtest("jobs are declarative"):
         # Check that jobs are created on disk.
-        master.wait_for_unit("jenkins-job-builder")
-        master.wait_until_fails("systemctl is-active jenkins-job-builder")
         master.wait_until_succeeds("test -f /var/lib/jenkins/jobs/job-1/config.xml")
         master.wait_until_succeeds("test -f /var/lib/jenkins/jobs/folder-1/config.xml")
         master.wait_until_succeeds("test -f /var/lib/jenkins/jobs/folder-1/jobs/job-2/config.xml")
 
-        # Wait until jenkins is ready, reload configuration and verify it also
-        # sees the jobs.
-        master.succeed("curl --fail ${jenkinsUrl}/cli")
-        master.succeed("curl ${jenkinsUrl}/jnlpJars/jenkins-cli.jar -O")
-        master.succeed("${pkgs.jre}/bin/java -jar jenkins-cli.jar -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) reload-configuration")
-        out = master.succeed("${pkgs.jre}/bin/java -jar jenkins-cli.jar -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) list-jobs")
+        # Verify that jenkins also sees the jobs.
+        out = master.succeed("${pkgs.jenkins}/bin/jenkins-cli -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) list-jobs")
         jobs = [x.strip() for x in out.splitlines()]
         # Seeing jobs inside folders requires the Folders plugin
         # (https://plugins.jenkins.io/cloudbees-folder/), which we don't have
@@ -115,15 +113,12 @@ import ./make-test-python.nix ({ pkgs, ...} : {
         )
 
         # Check that jobs are removed from disk.
-        master.wait_for_unit("jenkins-job-builder")
-        master.wait_until_fails("systemctl is-active jenkins-job-builder")
         master.wait_until_fails("test -f /var/lib/jenkins/jobs/job-1/config.xml")
         master.wait_until_fails("test -f /var/lib/jenkins/jobs/folder-1/config.xml")
         master.wait_until_fails("test -f /var/lib/jenkins/jobs/folder-1/jobs/job-2/config.xml")
 
-        # Reload jenkins' configuration and verify it also sees the jobs as removed.
-        master.succeed("${pkgs.jre}/bin/java -jar jenkins-cli.jar -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) reload-configuration")
-        out = master.succeed("${pkgs.jre}/bin/java -jar jenkins-cli.jar -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) list-jobs")
+        # Verify that jenkins also sees the jobs as removed.
+        out = master.succeed("${pkgs.jenkins}/bin/jenkins-cli -s ${jenkinsUrl} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) list-jobs")
         jobs = [x.strip() for x in out.splitlines()]
         assert jobs == [], f"jobs != []: {jobs}"
   '';
diff --git a/nixpkgs/nixos/tests/jibri.nix b/nixpkgs/nixos/tests/jibri.nix
index af20e639d30e..223120cdb229 100644
--- a/nixpkgs/nixos/tests/jibri.nix
+++ b/nixpkgs/nixos/tests/jibri.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = teams.jitsi.members;
   };
 
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       virtualisation.memorySize = 5120;
 
       services.jitsi-meet = {
diff --git a/nixpkgs/nixos/tests/jitsi-meet.nix b/nixpkgs/nixos/tests/jitsi-meet.nix
index 41d53bc73800..c39cd19e1f0a 100644
--- a/nixpkgs/nixos/tests/jitsi-meet.nix
+++ b/nixpkgs/nixos/tests/jitsi-meet.nix
@@ -34,9 +34,6 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     server.wait_for_unit("prosody.service")
 
     server.wait_until_succeeds(
-        "journalctl -b -u jitsi-videobridge2 -o cat | grep -q 'Performed a successful health check'"
-    )
-    server.wait_until_succeeds(
         "journalctl -b -u prosody -o cat | grep -q 'Authenticated as focus@auth.server'"
     )
     server.wait_until_succeeds(
diff --git a/nixpkgs/nixos/tests/k3s-single-node-docker.nix b/nixpkgs/nixos/tests/k3s-single-node-docker.nix
deleted file mode 100644
index 7f3d15788b04..000000000000
--- a/nixpkgs/nixos/tests/k3s-single-node-docker.nix
+++ /dev/null
@@ -1,84 +0,0 @@
-import ./make-test-python.nix ({ pkgs, ... }:
-
-  let
-    imageEnv = pkgs.buildEnv {
-      name = "k3s-pause-image-env";
-      paths = with pkgs; [ tini (hiPrio coreutils) busybox ];
-    };
-    pauseImage = pkgs.dockerTools.streamLayeredImage {
-      name = "test.local/pause";
-      tag = "local";
-      contents = imageEnv;
-      config.Entrypoint = [ "/bin/tini" "--" "/bin/sleep" "inf" ];
-    };
-    # Don't use the default service account because there's a race where it may
-    # not be created yet; make our own instead.
-    testPodYaml = pkgs.writeText "test.yml" ''
-      apiVersion: v1
-      kind: ServiceAccount
-      metadata:
-        name: test
-      ---
-      apiVersion: v1
-      kind: Pod
-      metadata:
-        name: test
-      spec:
-        serviceAccountName: test
-        containers:
-        - name: test
-          image: test.local/pause:local
-          imagePullPolicy: Never
-          command: ["sh", "-c", "sleep inf"]
-    '';
-  in
-  {
-    name = "k3s";
-    meta = with pkgs.lib.maintainers; {
-      maintainers = [ euank ];
-    };
-
-    machine = { pkgs, ... }: {
-      environment.systemPackages = with pkgs; [ k3s gzip ];
-
-      # k3s uses enough resources the default vm fails.
-      virtualisation.memorySize = 1536;
-      virtualisation.diskSize = 4096;
-
-      services.k3s = {
-        enable = true;
-        role = "server";
-        docker = true;
-        # Slightly reduce resource usage
-        extraFlags = "--no-deploy coredns,servicelb,traefik,local-storage,metrics-server --pause-image test.local/pause:local";
-      };
-
-      users.users = {
-        noprivs = {
-          isNormalUser = true;
-          description = "Can't access k3s by default";
-          password = "*";
-        };
-      };
-    };
-
-    testScript = ''
-      start_all()
-
-      machine.wait_for_unit("k3s")
-      machine.succeed("k3s kubectl cluster-info")
-      machine.fail("sudo -u noprivs k3s kubectl cluster-info")
-      # FIXME: this fails with the current nixos kernel config; once it passes, we should uncomment it
-      # machine.succeed("k3s check-config")
-
-      machine.succeed(
-          "${pauseImage} | docker load"
-      )
-
-      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.shutdown()
-    '';
-  })
diff --git a/nixpkgs/nixos/tests/k3s/default.nix b/nixpkgs/nixos/tests/k3s/default.nix
new file mode 100644
index 000000000000..07d93c41c7a6
--- /dev/null
+++ b/nixpkgs/nixos/tests/k3s/default.nix
@@ -0,0 +1,9 @@
+{ system ? builtins.currentSystem
+, pkgs ? import ../../.. { inherit system; }
+}:
+{
+  # Run a single node k3s cluster and verify a pod can run
+  single-node = import ./single-node.nix { inherit system pkgs; };
+  # Run a multi-node k3s cluster and verify pod networking works across nodes
+  multi-node = import ./multi-node.nix { inherit system pkgs; };
+}
diff --git a/nixpkgs/nixos/tests/k3s/multi-node.nix b/nixpkgs/nixos/tests/k3s/multi-node.nix
new file mode 100644
index 000000000000..afb8c78f2339
--- /dev/null
+++ b/nixpkgs/nixos/tests/k3s/multi-node.nix
@@ -0,0 +1,137 @@
+import ../make-test-python.nix ({ pkgs, ... }:
+  let
+    imageEnv = pkgs.buildEnv {
+      name = "k3s-pause-image-env";
+      paths = with pkgs; [ tini bashInteractive coreutils socat ];
+    };
+    pauseImage = pkgs.dockerTools.streamLayeredImage {
+      name = "test.local/pause";
+      tag = "local";
+      contents = imageEnv;
+      config.Entrypoint = [ "/bin/tini" "--" "/bin/sleep" "inf" ];
+    };
+    # A daemonset that responds 'server' on port 8000
+    networkTestDaemonset = pkgs.writeText "test.yml" ''
+      apiVersion: apps/v1
+      kind: DaemonSet
+      metadata:
+        name: test
+        labels:
+          name: test
+      spec:
+        selector:
+          matchLabels:
+            name: test
+        template:
+          metadata:
+            labels:
+              name: test
+          spec:
+            containers:
+            - name: test
+              image: test.local/pause:local
+              imagePullPolicy: Never
+              resources:
+                limits:
+                  memory: 20Mi
+              command: ["socat", "TCP4-LISTEN:8000,fork", "EXEC:echo server"]
+    '';
+    tokenFile = pkgs.writeText "token" "p@s$w0rd";
+  in
+  {
+    name = "k3s-multi-node";
+
+    nodes = {
+      server = { pkgs, ... }: {
+        environment.systemPackages = with pkgs; [ gzip jq ];
+        # k3s uses enough resources the default vm fails.
+        virtualisation.memorySize = 1536;
+        virtualisation.diskSize = 4096;
+
+        services.k3s = {
+          inherit tokenFile;
+          enable = true;
+          role = "server";
+          package = pkgs.k3s;
+          extraFlags = "--no-deploy coredns,servicelb,traefik,local-storage,metrics-server --pause-image test.local/pause:local --node-ip 192.168.1.1";
+        };
+        networking.firewall.allowedTCPPorts = [ 6443 ];
+        networking.firewall.allowedUDPPorts = [ 8472 ];
+        networking.firewall.trustedInterfaces = [ "flannel.1" ];
+        networking.useDHCP = false;
+        networking.defaultGateway = "192.168.1.1";
+        networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
+          { address = "192.168.1.1"; prefixLength = 24; }
+        ];
+      };
+
+      agent = { pkgs, ... }: {
+        virtualisation.memorySize = 1024;
+        virtualisation.diskSize = 2048;
+        services.k3s = {
+          inherit tokenFile;
+          enable = true;
+          role = "agent";
+          serverAddr = "https://192.168.1.1:6443";
+          extraFlags = "--pause-image test.local/pause:local --node-ip 192.168.1.2";
+        };
+        networking.firewall.allowedTCPPorts = [ 6443 ];
+        networking.firewall.allowedUDPPorts = [ 8472 ];
+        networking.firewall.trustedInterfaces = [ "flannel.1" ];
+        networking.useDHCP = false;
+        networking.defaultGateway = "192.168.1.2";
+        networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkForce [
+          { address = "192.168.1.2"; prefixLength = 24; }
+        ];
+      };
+    };
+
+    meta = with pkgs.lib.maintainers; {
+      maintainers = [ euank ];
+    };
+
+    testScript = ''
+      start_all()
+      machines = [server, agent]
+      for m in machines:
+          m.wait_for_unit("k3s")
+
+      # wait for the agent to show up
+      server.wait_until_succeeds("k3s kubectl get node agent")
+
+      for m in machines:
+          m.succeed("k3s check-config")
+          m.succeed(
+              "${pauseImage} | k3s ctr image import -"
+          )
+
+      server.succeed("k3s kubectl cluster-info")
+      # Also wait for our service account to show up; it takes a sec
+      server.wait_until_succeeds("k3s kubectl get serviceaccount default")
+
+      # Now create a pod on each node via a daemonset and verify they can talk to each other.
+      server.succeed("k3s kubectl apply -f ${networkTestDaemonset}")
+      server.wait_until_succeeds(f'[ "$(k3s kubectl get ds test -o json | jq .status.numberReady)" -eq {len(machines)} ]')
+
+      # Get pod IPs
+      pods = server.succeed("k3s kubectl get po -o json | jq '.items[].metadata.name' -r").splitlines()
+      pod_ips = [server.succeed(f"k3s kubectl get po {name} -o json | jq '.status.podIP' -cr").strip() for name in pods]
+
+      # Verify each server can ping each pod ip
+      for pod_ip in pod_ips:
+          server.succeed(f"ping -c 1 {pod_ip}")
+          agent.succeed(f"ping -c 1 {pod_ip}")
+
+      # Verify the pods can talk to each other
+      resp = server.wait_until_succeeds(f"k3s kubectl exec {pods[0]} -- socat TCP:{pod_ips[1]}:8000 -")
+      assert resp.strip() == "server"
+      resp = server.wait_until_succeeds(f"k3s kubectl exec {pods[1]} -- socat TCP:{pod_ips[0]}:8000 -")
+      assert resp.strip() == "server"
+
+      # Cleanup
+      server.succeed("k3s kubectl delete -f ${networkTestDaemonset}")
+
+      for m in machines:
+          m.shutdown()
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/k3s-single-node.nix b/nixpkgs/nixos/tests/k3s/single-node.nix
index d98f20d468cb..27e1e455e641 100644
--- a/nixpkgs/nixos/tests/k3s-single-node.nix
+++ b/nixpkgs/nixos/tests/k3s/single-node.nix
@@ -1,5 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... }:
-
+import ../make-test-python.nix ({ pkgs, ... }:
   let
     imageEnv = pkgs.buildEnv {
       name = "k3s-pause-image-env";
@@ -11,20 +10,12 @@ import ./make-test-python.nix ({ pkgs, ... }:
       contents = imageEnv;
       config.Entrypoint = [ "/bin/tini" "--" "/bin/sleep" "inf" ];
     };
-    # Don't use the default service account because there's a race where it may
-    # not be created yet; make our own instead.
     testPodYaml = pkgs.writeText "test.yml" ''
       apiVersion: v1
-      kind: ServiceAccount
-      metadata:
-        name: test
-      ---
-      apiVersion: v1
       kind: Pod
       metadata:
         name: test
       spec:
-        serviceAccountName: test
         containers:
         - name: test
           image: test.local/pause:local
@@ -38,7 +29,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
       maintainers = [ euank ];
     };
 
-    machine = { pkgs, ... }: {
+    nodes.machine = { pkgs, ... }: {
       environment.systemPackages = with pkgs; [ k3s gzip ];
 
       # k3s uses enough resources the default vm fails.
@@ -66,13 +57,14 @@ import ./make-test-python.nix ({ pkgs, ... }:
       machine.wait_for_unit("k3s")
       machine.succeed("k3s kubectl cluster-info")
       machine.fail("sudo -u noprivs k3s kubectl cluster-info")
-      # FIXME: this fails with the current nixos kernel config; once it passes, we should uncomment it
-      # machine.succeed("k3s check-config")
+      machine.succeed("k3s check-config")
 
       machine.succeed(
           "${pauseImage} | k3s 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}")
diff --git a/nixpkgs/nixos/tests/kanidm.nix b/nixpkgs/nixos/tests/kanidm.nix
new file mode 100644
index 000000000000..d34f680f5224
--- /dev/null
+++ b/nixpkgs/nixos/tests/kanidm.nix
@@ -0,0 +1,75 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+  let
+    certs = import ./common/acme/server/snakeoil-certs.nix;
+    serverDomain = certs.domain;
+  in
+  {
+    name = "kanidm";
+    meta.maintainers = with pkgs.lib.maintainers; [ erictapen Flakebi ];
+
+    nodes.server = { config, pkgs, lib, ... }: {
+      services.kanidm = {
+        enableServer = true;
+        serverSettings = {
+          origin = "https://${serverDomain}";
+          domain = serverDomain;
+          bindaddress = "[::1]:8443";
+          ldapbindaddress = "[::1]:636";
+        };
+      };
+
+      services.nginx = {
+        enable = true;
+        recommendedProxySettings = true;
+        virtualHosts."${serverDomain}" = {
+          forceSSL = true;
+          sslCertificate = certs."${serverDomain}".cert;
+          sslCertificateKey = certs."${serverDomain}".key;
+          locations."/".proxyPass = "http://[::1]:8443";
+        };
+      };
+
+      security.pki.certificateFiles = [ certs.ca.cert ];
+
+      networking.hosts."::1" = [ serverDomain ];
+      networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+      users.users.kanidm.shell = pkgs.bashInteractive;
+
+      environment.systemPackages = with pkgs; [ kanidm openldap ripgrep ];
+    };
+
+    nodes.client = { pkgs, nodes, ... }: {
+      services.kanidm = {
+        enableClient = true;
+        clientSettings = {
+          uri = "https://${serverDomain}";
+        };
+      };
+
+      networking.hosts."${nodes.server.config.networking.primaryIPAddress}" = [ serverDomain ];
+
+      security.pki.certificateFiles = [ certs.ca.cert ];
+    };
+
+    testScript = { nodes, ... }:
+      let
+        ldapBaseDN = builtins.concatStringsSep "," (map (s: "dc=" + s) (pkgs.lib.splitString "." serverDomain));
+
+        # We need access to the config file in the test script.
+        filteredConfig = pkgs.lib.converge
+          (pkgs.lib.filterAttrsRecursive (_: v: v != null))
+          nodes.server.config.services.kanidm.serverSettings;
+        serverConfigFile = (pkgs.formats.toml { }).generate "server.toml" filteredConfig;
+
+      in
+      ''
+        start_all()
+        server.wait_for_unit("kanidm.service")
+        server.wait_until_succeeds("curl -sf https://${serverDomain} | grep Kanidm")
+        server.wait_until_succeeds("ldapsearch -H ldap://[::1]:636 -b '${ldapBaseDN}' -x '(name=test)'")
+        client.wait_until_succeeds("kanidm login -D anonymous && kanidm self whoami | grep anonymous@${serverDomain}")
+        (rv, result) = server.execute("kanidmd recover_account -d quiet -c ${serverConfigFile} -n admin 2>&1 | rg -o '[A-Za-z0-9]{48}'")
+        assert rv == 0
+      '';
+  })
diff --git a/nixpkgs/nixos/tests/kbd-setfont-decompress.nix b/nixpkgs/nixos/tests/kbd-setfont-decompress.nix
index c3a495afac84..810ef39cc11a 100644
--- a/nixpkgs/nixos/tests/kbd-setfont-decompress.nix
+++ b/nixpkgs/nixos/tests/kbd-setfont-decompress.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
 
   meta.maintainers = with lib.maintainers; [ oxalica ];
 
-  machine = { ... }: {};
+  nodes.machine = { ... }: {};
 
   testScript = ''
     machine.succeed("gzip -cd ${pkgs.terminus_font}/share/consolefonts/ter-v16b.psf.gz >font.psf")
diff --git a/nixpkgs/nixos/tests/kbd-update-search-paths-patch.nix b/nixpkgs/nixos/tests/kbd-update-search-paths-patch.nix
index 2cdb12340b1b..746a809c4cdf 100644
--- a/nixpkgs/nixos/tests/kbd-update-search-paths-patch.nix
+++ b/nixpkgs/nixos/tests/kbd-update-search-paths-patch.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "kbd-update-search-paths-patch";
 
-  machine = { pkgs, options, ... }: {
+  nodes.machine = { pkgs, options, ... }: {
     console = {
       packages = options.console.packages.default ++ [ pkgs.terminus_font ];
     };
diff --git a/nixpkgs/nixos/tests/kea.nix b/nixpkgs/nixos/tests/kea.nix
index 6b345893108f..b1d5894cc7cd 100644
--- a/nixpkgs/nixos/tests/kea.nix
+++ b/nixpkgs/nixos/tests/kea.nix
@@ -1,6 +1,8 @@
 import ./make-test-python.nix ({ pkgs, lib, ...}: {
   meta.maintainers = with lib.maintainers; [ hexa ];
 
+  name = "kea";
+
   nodes = {
     router = { config, pkgs, ... }: {
       virtualisation.vlans = [ 1 ];
diff --git a/nixpkgs/nixos/tests/keepassxc.nix b/nixpkgs/nixos/tests/keepassxc.nix
index 924c137a9032..303be1330405 100644
--- a/nixpkgs/nixos/tests/keepassxc.nix
+++ b/nixpkgs/nixos/tests/keepassxc.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ turion ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [
@@ -62,7 +62,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
         machine.send_key("tab")
         machine.send_chars("/home/alice/foo.keyfile")
         machine.send_key("ret")
-        # Passwords folder is displayed
-        machine.wait_for_text("Passwords")
+        # Database is unlocked (doesn't have "[Locked]" in the title anymore)
+        machine.wait_for_text("foo.kdbx - KeePassXC")
   '';
 })
diff --git a/nixpkgs/nixos/tests/kerberos/heimdal.nix b/nixpkgs/nixos/tests/kerberos/heimdal.nix
index 391a61cc9a90..47f9d0285aef 100644
--- a/nixpkgs/nixos/tests/kerberos/heimdal.nix
+++ b/nixpkgs/nixos/tests/kerberos/heimdal.nix
@@ -1,6 +1,6 @@
 import ../make-test-python.nix ({pkgs, ...}: {
   name = "kerberos_server-heimdal";
-  machine = { config, libs, pkgs, ...}:
+  nodes.machine = { config, libs, pkgs, ...}:
   { services.kerberos_server =
     { enable = true;
       realms = {
diff --git a/nixpkgs/nixos/tests/kerberos/mit.nix b/nixpkgs/nixos/tests/kerberos/mit.nix
index 93b4020d4994..b475b7e4c92b 100644
--- a/nixpkgs/nixos/tests/kerberos/mit.nix
+++ b/nixpkgs/nixos/tests/kerberos/mit.nix
@@ -1,6 +1,6 @@
 import ../make-test-python.nix ({pkgs, ...}: {
   name = "kerberos_server-mit";
-  machine = { config, libs, pkgs, ...}:
+  nodes.machine = { config, libs, pkgs, ...}:
   { services.kerberos_server =
     { enable = true;
       realms = {
diff --git a/nixpkgs/nixos/tests/kernel-generic.nix b/nixpkgs/nixos/tests/kernel-generic.nix
index 45c5c1963a0d..04d52cf82e42 100644
--- a/nixpkgs/nixos/tests/kernel-generic.nix
+++ b/nixpkgs/nixos/tests/kernel-generic.nix
@@ -12,7 +12,7 @@ let
       maintainers = [ nequissimus atemu ];
     };
 
-    machine = { ... }:
+    nodes.machine = { ... }:
       {
         boot.kernelPackages = linuxPackages;
       };
@@ -30,6 +30,7 @@ let
       linux_5_4_hardened
       linux_5_10_hardened
       linux_5_15_hardened
+      linux_5_18_hardened
 
       linux_testing;
   };
diff --git a/nixpkgs/nixos/tests/kernel-latest-ath-user-regd.nix b/nixpkgs/nixos/tests/kernel-latest-ath-user-regd.nix
index 11a3959e692e..09e1da9d2aff 100644
--- a/nixpkgs/nixos/tests/kernel-latest-ath-user-regd.nix
+++ b/nixpkgs/nixos/tests/kernel-latest-ath-user-regd.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ veehaitch ];
   };
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
     {
       boot.kernelPackages = pkgs.linuxPackages_latest;
       networking.wireless.athUserRegulatoryDomain = true;
diff --git a/nixpkgs/nixos/tests/keter.nix b/nixpkgs/nixos/tests/keter.nix
new file mode 100644
index 000000000000..0bfb96e1c324
--- /dev/null
+++ b/nixpkgs/nixos/tests/keter.nix
@@ -0,0 +1,42 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+let
+  port = 81;
+in
+{
+  name = "keter";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ jappie ];
+  };
+
+
+  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
+        '';
+      };
+    };
+  };
+
+  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.succeed("curl --fail http://localhost:${toString port}/")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/kexec.nix b/nixpkgs/nixos/tests/kexec.nix
index 010f3da49846..3f5a6f521af0 100644
--- a/nixpkgs/nixos/tests/kexec.nix
+++ b/nixpkgs/nixos/tests/kexec.nix
@@ -1,22 +1,49 @@
-# Test whether fast reboots via kexec work.
-
-import ./make-test-python.nix ({ pkgs, lib, ...} : {
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "kexec";
   meta = with lib.maintainers; {
-    maintainers = [ eelco ];
+    maintainers = [ flokli lassulus ];
+  };
+
+  nodes = {
+    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, ... }: {
+      virtualisation.vlans = [ ];
+      environment.systemPackages = [ pkgs.hello ];
+      imports = [
+        "${modulesPath}/installer/netboot/netboot-minimal.nix"
+      ];
+    };
   };
 
-  machine = { ... }:
-    { virtualisation.vlans = [ ]; };
+  testScript = { nodes, ... }: ''
+    # Test whether reboot via kexec works.
+    node1.wait_for_unit("multi-user.target")
+    node1.succeed('kexec --load /run/current-system/kernel --initrd /run/current-system/initrd --command-line "$(</proc/cmdline)"')
+    node1.execute("systemctl kexec >&2 &", check_return=False)
+    node1.connected = False
+    node1.connect()
+    node1.wait_for_unit("multi-user.target")
+
+    # Check if the machine with netboot-minimal.nix profile boots up
+    node2.wait_for_unit("multi-user.target")
+    node2.shutdown()
+
+    # 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.succeed('! test -e /run/foo')
+    node1.succeed('hello')
+    node1.succeed('[ "$(hostname)" = "node2" ]')
 
-  testScript =
-    ''
-      machine.wait_for_unit("multi-user.target")
-      machine.succeed('kexec --load /run/current-system/kernel --initrd /run/current-system/initrd --command-line "$(</proc/cmdline)"')
-      machine.execute("systemctl kexec >&2 &", check_return=False)
-      machine.connected = False
-      machine.connect()
-      machine.wait_for_unit("multi-user.target")
-      machine.shutdown()
-    '';
+    node1.shutdown()
+  '';
 })
diff --git a/nixpkgs/nixos/tests/keycloak.nix b/nixpkgs/nixos/tests/keycloak.nix
index fce8df2b7e3a..6ce136330d43 100644
--- a/nixpkgs/nixos/tests/keycloak.nix
+++ b/nixpkgs/nixos/tests/keycloak.nix
@@ -4,7 +4,7 @@
 
 let
   certs = import ./common/acme/server/snakeoil-certs.nix;
-  frontendUrl = "https://${certs.domain}/auth";
+  frontendUrl = "https://${certs.domain}";
   initialAdminPassword = "h4IhoJFnt2iQIR9";
 
   keycloakTest = import ./make-test-python.nix (
@@ -27,20 +27,23 @@ let
 
           services.keycloak = {
             enable = true;
-            inherit frontendUrl initialAdminPassword;
-            sslCertificate = certs.${certs.domain}.cert;
-            sslCertificateKey = certs.${certs.domain}.key;
+            settings = {
+              hostname = certs.domain;
+            };
+            inherit initialAdminPassword;
+            sslCertificate = "${certs.${certs.domain}.cert}";
+            sslCertificateKey = "${certs.${certs.domain}.key}";
             database = {
               type = databaseType;
               username = "bogus";
-              passwordFile = pkgs.writeText "dbPassword" "wzf6vOCbPp6cqTH";
+              name = "also bogus";
+              passwordFile = "${pkgs.writeText "dbPassword" "wzf6vOCbPp6cqTH"}";
             };
             plugins = with config.services.keycloak.package.plugins; [
               keycloak-discord
               keycloak-metrics-spi
             ];
           };
-
           environment.systemPackages = with pkgs; [
             xmlstarlet
             html-tidy
@@ -99,9 +102,9 @@ let
         in ''
           keycloak.start()
           keycloak.wait_for_unit("keycloak.service")
+          keycloak.wait_for_open_port(443)
           keycloak.wait_until_succeeds("curl -sSf ${frontendUrl}")
 
-
           ### Realm Setup ###
 
           # Get an admin interface access token
@@ -117,8 +120,8 @@ let
           # Register the metrics SPI
           keycloak.succeed(
               "${pkgs.jre}/bin/keytool -import -alias snakeoil -file ${certs.ca.cert} -storepass aaaaaa -keystore cacert.jks -noprompt",
-              "KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' ${pkgs.keycloak}/bin/kcadm.sh config credentials --server '${frontendUrl}' --realm master --user admin --password '${initialAdminPassword}'",
-              "KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' ${pkgs.keycloak}/bin/kcadm.sh update events/config -s 'eventsEnabled=true' -s 'adminEventsEnabled=true' -s 'eventsListeners+=metrics-listener'",
+              "KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh config credentials --server '${frontendUrl}' --realm master --user admin --password '${initialAdminPassword}'",
+              "KC_OPTS='-Djavax.net.ssl.trustStore=cacert.jks -Djavax.net.ssl.trustStorePassword=aaaaaa' kcadm.sh update events/config -s 'eventsEnabled=true' -s 'adminEventsEnabled=true' -s 'eventsListeners+=metrics-listener'",
               "curl -sSf '${frontendUrl}/realms/master/metrics' | grep '^keycloak_admin_event_UPDATE'"
           )
 
@@ -143,7 +146,7 @@ let
           # post url.
           keycloak.succeed(
               "curl -sSf -c cookie '${frontendUrl}/realms/${realm.realm}/protocol/openid-connect/auth?client_id=${client.name}&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=openid+email&response_type=code&response_mode=query&nonce=qw4o89g3qqm' >login_form",
-              "tidy -q -m login_form || true",
+              "tidy -asxml -q -m login_form || true",
               "xml sel -T -t -m \"_:html/_:body/_:div/_:div/_:div/_:div/_:div/_:div/_:form[@id='kc-form-login']\" -v @action login_form >form_post_url",
           )
 
@@ -151,7 +154,7 @@ let
           # the HTML, then extract the authorization code.
           keycloak.succeed(
               "curl -sSf -L -b cookie -d 'username=${user.username}' -d 'password=${password}' -d 'credentialId=' \"$(<form_post_url)\" >auth_code_html",
-              "tidy -q -m auth_code_html || true",
+              "tidy -asxml -q -m auth_code_html || true",
               "xml sel -T -t -m \"_:html/_:body/_:div/_:div/_:div/_:div/_:div/_:input[@id='code']\" -v @value auth_code_html >auth_code",
           )
 
@@ -172,5 +175,6 @@ let
 in
 {
   postgres = keycloakTest { databaseType = "postgresql"; };
+  mariadb = keycloakTest { databaseType = "mariadb"; };
   mysql = keycloakTest { databaseType = "mysql"; };
 }
diff --git a/nixpkgs/nixos/tests/komga.nix b/nixpkgs/nixos/tests/komga.nix
new file mode 100644
index 000000000000..02db50ef25f7
--- /dev/null
+++ b/nixpkgs/nixos/tests/komga.nix
@@ -0,0 +1,22 @@
+import ./make-test-python.nix ({ lib, ... }:
+
+with lib;
+
+{
+  name = "komga";
+  meta.maintainers = with maintainers; [ govanify ];
+
+  nodes.machine =
+    { pkgs, ... }:
+    { services.komga = {
+        enable = true;
+        port = 1234;
+      };
+    };
+
+  testScript = ''
+    machine.wait_for_unit("komga.service")
+    machine.wait_for_open_port(1234)
+    machine.succeed("curl --fail http://localhost:1234/")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/krb5/deprecated-config.nix b/nixpkgs/nixos/tests/krb5/deprecated-config.nix
index 9a9cafd4b13e..aca29ae6ca2b 100644
--- a/nixpkgs/nixos/tests/krb5/deprecated-config.nix
+++ b/nixpkgs/nixos/tests/krb5/deprecated-config.nix
@@ -7,7 +7,7 @@ import ../make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ eqyiel ];
   };
 
-  machine =
+  nodes.machine =
     { ... }: {
       krb5 = {
         enable = true;
diff --git a/nixpkgs/nixos/tests/krb5/example-config.nix b/nixpkgs/nixos/tests/krb5/example-config.nix
index 0932c71dd970..1125b02f01ca 100644
--- a/nixpkgs/nixos/tests/krb5/example-config.nix
+++ b/nixpkgs/nixos/tests/krb5/example-config.nix
@@ -7,7 +7,7 @@ import ../make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ eqyiel ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }: {
       krb5 = {
         enable = true;
diff --git a/nixpkgs/nixos/tests/ksm.nix b/nixpkgs/nixos/tests/ksm.nix
index 8f84b32020ab..026d2ee85a24 100644
--- a/nixpkgs/nixos/tests/ksm.nix
+++ b/nixpkgs/nixos/tests/ksm.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ lib, ...} :
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     hardware.ksm.enable = true;
diff --git a/nixpkgs/nixos/tests/kubernetes/dns.nix b/nixpkgs/nixos/tests/kubernetes/dns.nix
index 3fd1dd31f746..6299b7ff988a 100644
--- a/nixpkgs/nixos/tests/kubernetes/dns.nix
+++ b/nixpkgs/nixos/tests/kubernetes/dns.nix
@@ -33,7 +33,11 @@ let
   redisImage = pkgs.dockerTools.buildImage {
     name = "redis";
     tag = "latest";
-    contents = [ pkgs.redis pkgs.bind.host ];
+    copyToRoot = pkgs.buildEnv {
+      name = "image-root";
+      pathsToLink = [ "/bin" ];
+      paths = [ pkgs.redis pkgs.bind.host ];
+    };
     config.Entrypoint = ["/bin/redis-server"];
   };
 
@@ -54,7 +58,11 @@ let
   probeImage = pkgs.dockerTools.buildImage {
     name = "probe";
     tag = "latest";
-    contents = [ pkgs.bind.host pkgs.busybox ];
+    copyToRoot = pkgs.buildEnv {
+      name = "image-root";
+      pathsToLink = [ "/bin" ];
+      paths = [ pkgs.bind.host pkgs.busybox ];
+    };
     config.Entrypoint = ["/bin/tail"];
   };
 
diff --git a/nixpkgs/nixos/tests/kubernetes/rbac.nix b/nixpkgs/nixos/tests/kubernetes/rbac.nix
index 9e73fbbd32a8..779eafbb1d24 100644
--- a/nixpkgs/nixos/tests/kubernetes/rbac.nix
+++ b/nixpkgs/nixos/tests/kubernetes/rbac.nix
@@ -84,7 +84,11 @@ let
   kubectlImage = pkgs.dockerTools.buildImage {
     name = "kubectl";
     tag = "latest";
-    contents = [ copyKubectl pkgs.busybox kubectlPod2 ];
+    copyToRoot = pkgs.buildEnv {
+      name = "image-root";
+      pathsToLink = [ "/bin" ];
+      paths = [ copyKubectl pkgs.busybox kubectlPod2 ];
+    };
     config.Entrypoint = ["/bin/sh"];
   };
 
diff --git a/nixpkgs/nixos/tests/libinput.nix b/nixpkgs/nixos/tests/libinput.nix
index 2f84aaadcd0b..9b6fa159b999 100644
--- a/nixpkgs/nixos/tests/libinput.nix
+++ b/nixpkgs/nixos/tests/libinput.nix
@@ -3,7 +3,7 @@ import ./make-test-python.nix ({ ... }:
 {
   name = "libinput";
 
-  machine = { ... }:
+  nodes.machine = { ... }:
     {
       imports = [
         ./common/x11.nix
diff --git a/nixpkgs/nixos/tests/libreddit.nix b/nixpkgs/nixos/tests/libreddit.nix
index f7ef701d0865..82a44cb4e9cb 100644
--- a/nixpkgs/nixos/tests/libreddit.nix
+++ b/nixpkgs/nixos/tests/libreddit.nix
@@ -6,14 +6,16 @@ with lib;
   name = "libreddit";
   meta.maintainers = with maintainers; [ fab ];
 
-  nodes.machine =
-    { pkgs, ... }:
-    { services.libreddit.enable = true; };
+  nodes.machine = {
+    services.libreddit.enable = true;
+    # Test CAP_NET_BIND_SERVICE
+    services.libreddit.port = 80;
+  };
 
   testScript = ''
     machine.wait_for_unit("libreddit.service")
-    machine.wait_for_open_port("8080")
-    # The service wants to get data from https://www.reddit.com
-    machine.succeed("curl http://localhost:8080/")
+    machine.wait_for_open_port(80)
+    # Query a page that does not require Internet access
+    machine.succeed("curl --fail http://localhost:80/settings")
   '';
 })
diff --git a/nixpkgs/nixos/tests/libresprite.nix b/nixpkgs/nixos/tests/libresprite.nix
index 1a6210e3671a..16d272acfa0f 100644
--- a/nixpkgs/nixos/tests/libresprite.nix
+++ b/nixpkgs/nixos/tests/libresprite.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/libuiohook.nix b/nixpkgs/nixos/tests/libuiohook.nix
new file mode 100644
index 000000000000..66c5033d9688
--- /dev/null
+++ b/nixpkgs/nixos/tests/libuiohook.nix
@@ -0,0 +1,21 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "libuiohook";
+  meta = with lib.maintainers; { maintainers = [ anoa ]; };
+
+  nodes.client = { nodes, ... }:
+      let user = nodes.client.config.users.users.alice;
+      in {
+        imports = [ ./common/user-account.nix ./common/x11.nix ];
+
+        environment.systemPackages = [ pkgs.libuiohook.test ];
+
+        test-support.displayManager.auto.user = user.name;
+      };
+
+  testScript = { nodes, ... }:
+    let user = nodes.client.config.users.users.alice;
+    in ''
+      client.wait_for_x()
+      client.succeed("su - alice -c ${pkgs.libuiohook.test}/share/uiohook_tests >&2 &")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/lidarr.nix b/nixpkgs/nixos/tests/lidarr.nix
index d3f83e5d9145..7fbaea62f80e 100644
--- a/nixpkgs/nixos/tests/lidarr.nix
+++ b/nixpkgs/nixos/tests/lidarr.nix
@@ -14,7 +14,7 @@ with lib;
     start_all()
 
     machine.wait_for_unit("lidarr.service")
-    machine.wait_for_open_port("8686")
+    machine.wait_for_open_port(8686)
     machine.succeed("curl --fail http://localhost:8686/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/lightdm.nix b/nixpkgs/nixos/tests/lightdm.nix
index e98230ecb179..94cebd4a630a 100644
--- a/nixpkgs/nixos/tests/lightdm.nix
+++ b/nixpkgs/nixos/tests/lightdm.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ aszlig ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.displayManager.lightdm.enable = true;
diff --git a/nixpkgs/nixos/tests/lighttpd.nix b/nixpkgs/nixos/tests/lighttpd.nix
new file mode 100644
index 000000000000..36e2745c55c1
--- /dev/null
+++ b/nixpkgs/nixos/tests/lighttpd.nix
@@ -0,0 +1,21 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "lighttpd";
+  meta.maintainers = with lib.maintainers; [ bjornfor ];
+
+  nodes = {
+    server = {
+      services.lighttpd.enable = true;
+      services.lighttpd.document-root = pkgs.runCommand "document-root" {} ''
+        mkdir -p "$out"
+        echo "hello nixos test" > "$out/file.txt"
+      '';
+    };
+  };
+
+  testScript = ''
+    start_all()
+    server.wait_for_unit("lighttpd.service")
+    res = server.succeed("curl --fail http://localhost/file.txt")
+    assert "hello nixos test" in res, f"bad server response: '{res}'"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/limesurvey.nix b/nixpkgs/nixos/tests/limesurvey.nix
index b60e80be2444..9a3193991f35 100644
--- a/nixpkgs/nixos/tests/limesurvey.nix
+++ b/nixpkgs/nixos/tests/limesurvey.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "limesurvey";
   meta.maintainers = [ pkgs.lib.maintainers.aanderse ];
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.limesurvey = {
       enable = true;
       virtualHost = {
diff --git a/nixpkgs/nixos/tests/litestream.nix b/nixpkgs/nixos/tests/litestream.nix
index 886fbfef9cf5..f9d71c526e9e 100644
--- a/nixpkgs/nixos/tests/litestream.nix
+++ b/nixpkgs/nixos/tests/litestream.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ jwygoda ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     { services.litestream = {
         enable = true;
diff --git a/nixpkgs/nixos/tests/login.nix b/nixpkgs/nixos/tests/login.nix
index 4d1dcc8cc32d..2cff38d20059 100644
--- a/nixpkgs/nixos/tests/login.nix
+++ b/nixpkgs/nixos/tests/login.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }:
     maintainers = [ eelco ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, lib, ... }:
     { boot.kernelPackages = lib.mkIf latestKernel pkgs.linuxPackages_latest;
       sound.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
@@ -29,11 +29,11 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }:
           machine.wait_until_succeeds("pgrep -f 'agetty.*tty2'")
 
       with subtest("Log in as alice on a virtual console"):
-          machine.wait_until_tty_matches(2, "login: ")
+          machine.wait_until_tty_matches("2", "login: ")
           machine.send_chars("alice\n")
-          machine.wait_until_tty_matches(2, "login: alice")
+          machine.wait_until_tty_matches("2", "login: alice")
           machine.wait_until_succeeds("pgrep login")
-          machine.wait_until_tty_matches(2, "Password: ")
+          machine.wait_until_tty_matches("2", "Password: ")
           machine.send_chars("foobar\n")
           machine.wait_until_succeeds("pgrep -u alice bash")
           machine.send_chars("touch done\n")
diff --git a/nixpkgs/nixos/tests/logrotate.nix b/nixpkgs/nixos/tests/logrotate.nix
index 38da8d535275..b0685f3af9ff 100644
--- a/nixpkgs/nixos/tests/logrotate.nix
+++ b/nixpkgs/nixos/tests/logrotate.nix
@@ -1,26 +1,105 @@
 # Test logrotate service works and is enabled by default
 
-import ./make-test-python.nix ({ pkgs, ...} : rec {
+let
+  importTest = { ... }: {
+    services.logrotate.settings.import = {
+      olddir = false;
+    };
+  };
+
+in
+
+import ./make-test-python.nix ({ pkgs, ... }: rec {
   name = "logrotate";
   meta = with pkgs.lib.maintainers; {
     maintainers = [ martinetd ];
   };
 
-  # default machine
-  machine = { ... }: {
+  nodes = {
+    defaultMachine = { ... }: { };
+    failingMachine = { ... }: {
+      services.logrotate.configFile = pkgs.writeText "logrotate.conf" ''
+        # self-written config file
+        su notarealuser notagroupeither
+      '';
+    };
+    machine = { config, ... }: {
+      imports = [ importTest ];
+
+      services.logrotate.settings = {
+        # remove default frequency header and add another
+        header = {
+          frequency = null;
+          delaycompress = true;
+        };
+        # extra global setting... affecting nothing
+        last_line = {
+          global = true;
+          priority = 2000;
+          shred = true;
+        };
+        # using mail somewhere should add --mail to logrotate invokation
+        sendmail = {
+          mail = "user@domain.tld";
+        };
+        # postrotate should be suffixed by 'endscript'
+        postrotate = {
+          postrotate = "touch /dev/null";
+        };
+        # check checkConfig works as expected: there is nothing to check here
+        # except that the file build passes
+        checkConf = {
+          su = "root utmp";
+          createolddir = "0750 root utmp";
+          create = "root utmp";
+          "create " = "0750 root utmp";
+        };
+        # multiple paths should be aggregated
+        multipath = {
+          files = [ "file1" "file2" ];
+        };
+        # overriding imported path should keep existing attributes
+        # (e.g. olddir is still set)
+        import = {
+          notifempty = true;
+        };
+      };
+      # extraConfig compatibility - should be added to top level, early.
+      services.logrotate.extraConfig = ''
+        nomail
+      '';
+      # paths compatibility
+      services.logrotate.paths = {
+        compat_path = {
+          path = "compat_test_path";
+        };
+        # user/group should be grouped as 'su user group'
+        compat_user = {
+          user = config.users.users.root.name;
+          group = "root";
+        };
+        # extraConfig in path should be added to block
+        compat_extraConfig = {
+          extraConfig = "dateext";
+        };
+        # keep -> rotate
+        compat_keep = {
+          keep = 1;
+        };
+      };
+    };
   };
 
   testScript =
     ''
       with subtest("whether logrotate works"):
-          machine.succeed(
-              # we must rotate once first to create logrotate stamp
-              "systemctl start logrotate.service")
+          # we must rotate once first to create logrotate stamp
+          defaultMachine.succeed("systemctl start logrotate.service")
           # we need to wait for console text once here to
           # clear console buffer up to this point for next wait
-          machine.wait_for_console_text('logrotate.service: Deactivated successfully')
+          defaultMachine.wait_for_console_text('logrotate.service: Deactivated successfully')
 
-          machine.succeed(
+          defaultMachine.succeed(
               # wtmp is present in default config.
               "rm -f /var/log/wtmp*",
               # we need to give it at least 1MB
@@ -28,10 +107,46 @@ import ./make-test-python.nix ({ pkgs, ...} : rec {
 
               # move into the future and check rotation.
               "date -s 'now + 1 month + 1 day'")
-          machine.wait_for_console_text('logrotate.service: Deactivated successfully')
-          machine.succeed(
+          defaultMachine.wait_for_console_text('logrotate.service: Deactivated successfully')
+          defaultMachine.succeed(
               # check rotate worked
               "[ -e /var/log/wtmp.1 ]",
           )
+      with subtest("default config does not have mail"):
+          defaultMachine.fail("systemctl cat logrotate.service | grep -- --mail")
+      with subtest("using mails adds mail option"):
+          machine.succeed("systemctl cat logrotate.service | grep -- --mail")
+      with subtest("check generated config matches expectation"):
+          machine.succeed(
+              # copy conf to /tmp/logrotate.conf for easy grep
+              "conf=$(systemctl cat logrotate | grep -oE '/nix/store[^ ]*logrotate.conf'); cp $conf /tmp/logrotate.conf",
+              "! grep weekly /tmp/logrotate.conf",
+              "grep -E '^delaycompress' /tmp/logrotate.conf",
+              "tail -n 1 /tmp/logrotate.conf | grep shred",
+              "sed -ne '/\"sendmail\" {/,/}/p' /tmp/logrotate.conf | grep 'mail user@domain.tld'",
+              "sed -ne '/\"postrotate\" {/,/}/p' /tmp/logrotate.conf | grep endscript",
+              "grep '\"file1\"\n\"file2\" {' /tmp/logrotate.conf",
+              "sed -ne '/\"import\" {/,/}/p' /tmp/logrotate.conf | grep noolddir",
+              "sed -ne '1,/^\"/p' /tmp/logrotate.conf | grep nomail",
+              "grep '\"compat_test_path\" {' /tmp/logrotate.conf",
+              "sed -ne '/\"compat_user\" {/,/}/p' /tmp/logrotate.conf | grep 'su root root'",
+              "sed -ne '/\"compat_extraConfig\" {/,/}/p' /tmp/logrotate.conf | grep dateext",
+              "[[ $(sed -ne '/\"compat_keep\" {/,/}/p' /tmp/logrotate.conf | grep -w rotate) = \"  rotate 1\" ]]",
+              "! sed -ne '/\"compat_keep\" {/,/}/p' /tmp/logrotate.conf | grep -w keep",
+          )
+          # also check configFile option
+          failingMachine.succeed(
+              "conf=$(systemctl cat logrotate | grep -oE '/nix/store[^ ]*logrotate.conf'); cp $conf /tmp/logrotate.conf",
+              "grep 'self-written config' /tmp/logrotate.conf",
+          )
+      with subtest("Check logrotate-checkconf service"):
+          machine.wait_for_unit("logrotate-checkconf.service")
+          # wait_for_unit also asserts for success, so wait for
+          # parent target instead and check manually.
+          failingMachine.wait_for_unit("multi-user.target")
+          info = failingMachine.get_unit_info("logrotate-checkconf.service")
+          if info["ActiveState"] != "failed":
+              raise Exception('logrotate-checkconf.service was not failed')
+
     '';
 })
diff --git a/nixpkgs/nixos/tests/loki.nix b/nixpkgs/nixos/tests/loki.nix
index 0c6dff3fdf13..470f80e9db63 100644
--- a/nixpkgs/nixos/tests/loki.nix
+++ b/nixpkgs/nixos/tests/loki.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }:
     maintainers = [ willibutz ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.loki = {
       enable = true;
       configFile = "${pkgs.grafana-loki.src}/cmd/loki/loki-local-config.yaml";
diff --git a/nixpkgs/nixos/tests/lorri/default.nix b/nixpkgs/nixos/tests/lorri/default.nix
index c33c7503993d..209b87f9f26a 100644
--- a/nixpkgs/nixos/tests/lorri/default.nix
+++ b/nixpkgs/nixos/tests/lorri/default.nix
@@ -1,5 +1,5 @@
 import ../make-test-python.nix {
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ../../modules/profiles/minimal.nix ];
     environment.systemPackages = [ pkgs.lorri ];
   };
diff --git a/nixpkgs/nixos/tests/lvm2/default.nix b/nixpkgs/nixos/tests/lvm2/default.nix
new file mode 100644
index 000000000000..1eb9f572a4d6
--- /dev/null
+++ b/nixpkgs/nixos/tests/lvm2/default.nix
@@ -0,0 +1,45 @@
+{ system ? builtins.currentSystem
+, config ? { }
+, pkgs ? import ../../.. { inherit system config; }
+, lib ? pkgs.lib
+, kernelVersionsToTest ? [ "4.19" "5.4" "5.10" "5.15" "latest" ]
+}:
+
+# For quickly running a test, the nixosTests.lvm2.lvm-thinpool-linux-latest attribute is recommended
+let
+  tests = let callTest = p: lib.flip (import p) { inherit system pkgs; }; in {
+    thinpool = { test = callTest ./thinpool.nix; kernelFilter = lib.id; };
+    # we would like to test all versions, but the kernel module currently does not compile against the other versions
+    vdo = { test = callTest ./vdo.nix; kernelFilter = lib.filter (v: v == "5.15"); };
+
+
+    # systemd in stage 1
+    raid-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.id;
+      flavour = "raid";
+    };
+    thinpool-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.id;
+      flavour = "thinpool";
+    };
+    vdo-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.filter (v: v == "5.15");
+      flavour = "vdo";
+    };
+  };
+in
+lib.listToAttrs (
+  lib.filter (x: x.value != {}) (
+    lib.flip lib.concatMap kernelVersionsToTest (version:
+      let
+        v' = lib.replaceStrings [ "." ] [ "_" ] version;
+      in
+      lib.flip lib.mapAttrsToList tests (name: t:
+        lib.nameValuePair "lvm-${name}-linux-${v'}" (lib.optionalAttrs (builtins.elem version (t.kernelFilter kernelVersionsToTest)) (t.test ({ kernelPackages = pkgs."linuxPackages_${v'}"; } // builtins.removeAttrs t [ "test" "kernelFilter" ])))
+      )
+    )
+  )
+)
diff --git a/nixpkgs/nixos/tests/lvm2/systemd-stage-1.nix b/nixpkgs/nixos/tests/lvm2/systemd-stage-1.nix
new file mode 100644
index 000000000000..617ba77b1796
--- /dev/null
+++ b/nixpkgs/nixos/tests/lvm2/systemd-stage-1.nix
@@ -0,0 +1,104 @@
+{ kernelPackages ? null, flavour }: let
+  preparationCode = {
+    raid = ''
+      machine.succeed("vgcreate test_vg /dev/vdc /dev/vdd")
+      machine.succeed("lvcreate -L 512M --type raid0 test_vg -n test_lv")
+    '';
+
+    thinpool = ''
+      machine.succeed("vgcreate test_vg /dev/vdc")
+      machine.succeed("lvcreate -L 512M -T test_vg/test_thin_pool")
+      machine.succeed("lvcreate -n test_lv -V 16G --thinpool test_thin_pool test_vg")
+    '';
+
+    vdo = ''
+      machine.succeed("vgcreate test_vg /dev/vdc")
+      machine.succeed("lvcreate --type vdo -n test_lv -L 6G -V 12G test_vg/vdo_pool_lv")
+    '';
+  }.${flavour};
+
+  extraConfig = {
+    raid = {
+      boot.initrd.kernelModules = [
+        "dm-raid"
+        "raid0"
+      ];
+    };
+
+    thinpool = {
+      services.lvm = {
+        boot.thin.enable = true;
+        dmeventd.enable = true;
+      };
+    };
+
+    vdo = {
+      services.lvm = {
+        boot.vdo.enable = true;
+        dmeventd.enable = true;
+      };
+    };
+  }.${flavour};
+
+  extraCheck = {
+    raid = ''
+      "test_lv" in machine.succeed("lvs --select segtype=raid0")
+    '';
+
+    thinpool = ''
+      "test_lv" in machine.succeed("lvs --select segtype=thin-pool")
+    '';
+
+    vdo = ''
+      "test_lv" in machine.succeed("lvs --select segtype=vdo")
+    '';
+  }.${flavour};
+
+in import ../make-test-python.nix ({ pkgs, ... }: {
+  name = "lvm2-${flavour}-systemd-stage-1";
+  meta.maintainers = with pkgs.lib.maintainers; [ das_j ];
+
+  nodes.machine = { pkgs, lib, ... }: {
+    imports = [ extraConfig ];
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 8192 8192 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+    boot.loader.efi.canTouchEfiVariables = true;
+
+    environment.systemPackages = with pkgs; [ e2fsprogs ]; # for mkfs.ext4
+    boot = {
+      initrd.systemd = {
+        enable = true;
+        emergencyAccess = true;
+      };
+      initrd.services.lvm.enable = true;
+      kernelPackages = lib.mkIf (kernelPackages != null) kernelPackages;
+    };
+
+    specialisation.boot-lvm.configuration.virtualisation.bootDevice = "/dev/test_vg/test_lv";
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    # Create a VG for the root
+    ${preparationCode}
+    machine.succeed("mkfs.ext4 /dev/test_vg/test_lv")
+    machine.succeed("mkdir -p /mnt && mount /dev/test_vg/test_lv /mnt && echo hello > /mnt/test && umount /mnt")
+
+    # Boot from LVM
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-lvm.conf")
+    machine.succeed("sync")
+    machine.crash()
+    machine.wait_for_unit("multi-user.target")
+
+    # Ensure we have successfully booted from LVM
+    assert "(initrd)" in machine.succeed("systemd-analyze")  # booted with systemd in stage 1
+    assert "/dev/mapper/test_vg-test_lv on / type ext4" in machine.succeed("mount")
+    assert "hello" in machine.succeed("cat /test")
+    ${extraCheck}
+  '';
+})
diff --git a/nixpkgs/nixos/tests/lvm2/thinpool.nix b/nixpkgs/nixos/tests/lvm2/thinpool.nix
new file mode 100644
index 000000000000..82c6460a890a
--- /dev/null
+++ b/nixpkgs/nixos/tests/lvm2/thinpool.nix
@@ -0,0 +1,32 @@
+{ kernelPackages ? null }:
+import ../make-test-python.nix ({ pkgs, ... }: {
+  name = "lvm2-thinpool";
+  meta.maintainers = with pkgs.lib.maintainers; [ ajs124 ];
+
+  nodes.machine = { pkgs, lib, ... }: {
+    virtualisation.emptyDiskImages = [ 4096 ];
+    services.lvm = {
+      boot.thin.enable = true;
+      dmeventd.enable = true;
+    };
+    environment.systemPackages = with pkgs; [ xfsprogs ];
+    environment.etc."lvm/lvm.conf".text = ''
+      activation/thin_pool_autoextend_percent = 10
+      activation/thin_pool_autoextend_threshold = 80
+    '';
+    boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
+  };
+
+  testScript = ''
+    machine.succeed("vgcreate test_vg /dev/vdb")
+    machine.succeed("lvcreate -L 512M -T test_vg/test_thin_pool")
+    machine.succeed("lvcreate -n test_lv -V 16G --thinpool test_thin_pool test_vg")
+    machine.succeed("mkfs.xfs /dev/test_vg/test_lv")
+    machine.succeed("mkdir /mnt; mount /dev/test_vg/test_lv /mnt")
+    assert "/dev/mapper/test_vg-test_lv" == machine.succeed("findmnt -no SOURCE /mnt").strip()
+    machine.succeed("dd if=/dev/zero of=/mnt/empty.file bs=1M count=1024")
+    machine.succeed("journalctl -u dm-event.service | grep \"successfully resized\"")
+    machine.succeed("umount /mnt")
+    machine.succeed("vgchange -a n")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/lvm2/vdo.nix b/nixpkgs/nixos/tests/lvm2/vdo.nix
new file mode 100644
index 000000000000..5b014c2f7222
--- /dev/null
+++ b/nixpkgs/nixos/tests/lvm2/vdo.nix
@@ -0,0 +1,27 @@
+{ kernelPackages ? null }:
+import ../make-test-python.nix ({ pkgs, ... }: {
+  name = "lvm2-vdo";
+  meta.maintainers = with pkgs.lib.maintainers; [ ajs124 ];
+
+  nodes.machine = { pkgs, lib, ... }: {
+    # Minimum required size for VDO volume: 5063921664 bytes
+    virtualisation.emptyDiskImages = [ 8192 ];
+    services.lvm = {
+      boot.vdo.enable = true;
+      dmeventd.enable = true;
+    };
+    environment.systemPackages = with pkgs; [ xfsprogs ];
+    boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
+  };
+
+  testScript = ''
+    machine.succeed("vgcreate test_vg /dev/vdb")
+    machine.succeed("lvcreate --type vdo -n vdo_lv -L 6G -V 12G test_vg/vdo_pool_lv")
+    machine.succeed("mkfs.xfs -K /dev/test_vg/vdo_lv")
+    machine.succeed("mkdir /mnt; mount /dev/test_vg/vdo_lv /mnt")
+    assert "/dev/mapper/test_vg-vdo_lv" == machine.succeed("findmnt -no SOURCE /mnt").strip()
+    machine.succeed("umount /mnt")
+    machine.succeed("vdostats")
+    machine.succeed("vgchange -a n")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/lxd-image-server.nix b/nixpkgs/nixos/tests/lxd-image-server.nix
index 9f060fed38d8..072f4570c2c9 100644
--- a/nixpkgs/nixos/tests/lxd-image-server.nix
+++ b/nixpkgs/nixos/tests/lxd-image-server.nix
@@ -1,57 +1,24 @@
-import ./make-test-python.nix ({ pkgs, ...} :
+import ./make-test-python.nix ({ pkgs, lib, ... } :
 
 let
-  # Since we don't have access to the internet during the tests, we have to
-  # pre-fetch lxd containers beforehand.
-  #
-  # I've chosen to import Alpine Linux, because its image is turbo-tiny and,
-  # generally, sufficient for our tests.
-  alpine-meta = pkgs.fetchurl {
-    url = "https://tarballs.nixos.org/alpine/3.12/lxd.tar.xz";
-    hash = "sha256-1tcKaO9lOkvqfmG/7FMbfAEToAuFy2YMewS8ysBKuLA=";
-  };
-
-  alpine-rootfs = pkgs.fetchurl {
-    url = "https://tarballs.nixos.org/alpine/3.12/rootfs.tar.xz";
-    hash = "sha256-Tba9sSoaiMtQLY45u7p5DMqXTSDgs/763L/SQp0bkCA=";
+  lxd-image = import ../release.nix {
+    configuration = {
+      # Building documentation makes the test unnecessarily take a longer time:
+      documentation.enable = lib.mkForce false;
+    };
   };
 
-  lxd-config = pkgs.writeText "config.yaml" ''
-    storage_pools:
-      - name: default
-        driver: dir
-        config:
-          source: /var/lxd-pool
-
-    networks:
-      - name: lxdbr0
-        type: bridge
-        config:
-          ipv4.address: auto
-          ipv6.address: none
-
-    profiles:
-      - name: default
-        devices:
-          eth0:
-            name: eth0
-            network: lxdbr0
-            type: nic
-          root:
-            path: /
-            pool: default
-            type: disk
-  '';
-
+  lxd-image-metadata = lxd-image.lxdMeta.${pkgs.system};
+  lxd-image-rootfs = lxd-image.lxdImage.${pkgs.system};
 
 in {
   name = "lxd-image-server";
 
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ mkg20001 ];
+    maintainers = [ mkg20001 patryk27 ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     virtualisation = {
       cores = 2;
 
@@ -100,20 +67,20 @@ in {
     # lxd expects the pool's directory to already exist
     machine.succeed("mkdir /var/lxd-pool")
 
-
     machine.succeed(
-        "cat ${lxd-config} | lxd init --preseed"
+        "cat ${./common/lxd/config.yaml} | lxd init --preseed"
     )
 
     machine.succeed(
-        "lxc image import ${alpine-meta} ${alpine-rootfs} --alias alpine"
+        "lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs}/*/*.tar.xz --alias nixos"
     )
 
-    loc = "/var/www/simplestreams/images/iats/alpine/amd64/default/v1"
+    loc = "/var/www/simplestreams/images/iats/nixos/amd64/default/v1"
 
     with subtest("push image to server"):
-        machine.succeed("lxc launch alpine test")
-        machine.succeed("lxc stop test")
+        machine.succeed("lxc launch nixos test")
+        machine.sleep(5)
+        machine.succeed("lxc stop -f test")
         machine.succeed("lxc publish --public test --alias=testimg")
         machine.succeed("lxc image export testimg")
         machine.succeed("ls >&2")
diff --git a/nixpkgs/nixos/tests/lxd-image.nix b/nixpkgs/nixos/tests/lxd-image.nix
deleted file mode 100644
index 096b9d9aba90..000000000000
--- a/nixpkgs/nixos/tests/lxd-image.nix
+++ /dev/null
@@ -1,89 +0,0 @@
-# This test ensures that the nixOS lxd images builds and functions properly
-# It has been extracted from `lxd.nix` to seperate failures of just the image and the lxd software
-
-import ./make-test-python.nix ({ pkgs, ...} : let
-  release = import ../release.nix {
-    /* configuration = {
-      environment.systemPackages = with pkgs; [ stdenv ]; # inject stdenv so rebuild test works
-    }; */
-  };
-
-  metadata = release.lxdMeta.${pkgs.system};
-  image = release.lxdImage.${pkgs.system};
-
-  lxd-config = pkgs.writeText "config.yaml" ''
-    storage_pools:
-      - name: default
-        driver: dir
-        config:
-          source: /var/lxd-pool
-
-    networks:
-      - name: lxdbr0
-        type: bridge
-        config:
-          ipv4.address: auto
-          ipv6.address: none
-
-    profiles:
-      - name: default
-        devices:
-          eth0:
-            name: eth0
-            network: lxdbr0
-            type: nic
-          root:
-            path: /
-            pool: default
-            type: disk
-  '';
-in {
-  name = "lxd-image";
-
-  meta = with pkgs.lib.maintainers; {
-    maintainers = [ mkg20001 ];
-  };
-
-  machine = { lib, ... }: {
-    virtualisation = {
-      # disk full otherwise
-      diskSize = 2048;
-
-      lxc.lxcfs.enable = true;
-      lxd.enable = true;
-    };
-  };
-
-  testScript = ''
-    machine.wait_for_unit("sockets.target")
-    machine.wait_for_unit("lxd.service")
-    machine.wait_for_file("/var/lib/lxd/unix.socket")
-
-    # It takes additional second for lxd to settle
-    machine.sleep(1)
-
-    # lxd expects the pool's directory to already exist
-    machine.succeed("mkdir /var/lxd-pool")
-
-    machine.succeed(
-        "cat ${lxd-config} | lxd init --preseed"
-    )
-
-    # TODO: test custom built container aswell
-
-    with subtest("importing container works"):
-        machine.succeed("lxc image import ${metadata}/*/*.tar.xz ${image}/*/*.tar.xz --alias nixos")
-
-    with subtest("launching container works"):
-        machine.succeed("lxc launch nixos machine -c security.nesting=true")
-        # make sure machine boots up properly
-        machine.sleep(5)
-
-    with subtest("container shell works"):
-        machine.succeed("echo true | lxc exec machine /run/current-system/sw/bin/bash -")
-        machine.succeed("lxc exec machine /run/current-system/sw/bin/true")
-
-    # with subtest("rebuilding works"):
-    #     machine.succeed("lxc exec machine /run/current-system/sw/bin/nixos-rebuild switch")
-  '';
-})
diff --git a/nixpkgs/nixos/tests/lxd-nftables.nix b/nixpkgs/nixos/tests/lxd-nftables.nix
index a62d5a3064df..293065001567 100644
--- a/nixpkgs/nixos/tests/lxd-nftables.nix
+++ b/nixpkgs/nixos/tests/lxd-nftables.nix
@@ -12,7 +12,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ patryk27 ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     virtualisation = {
       lxd.enable = true;
     };
diff --git a/nixpkgs/nixos/tests/lxd.nix b/nixpkgs/nixos/tests/lxd.nix
index 1a3b84a85cf6..15d16564d641 100644
--- a/nixpkgs/nixos/tests/lxd.nix
+++ b/nixpkgs/nixos/tests/lxd.nix
@@ -1,48 +1,18 @@
-import ./make-test-python.nix ({ pkgs, ...} :
+import ./make-test-python.nix ({ pkgs, lib, ... } :
 
 let
-  # Since we don't have access to the internet during the tests, we have to
-  # pre-fetch lxd containers beforehand.
-  #
-  # I've chosen to import Alpine Linux, because its image is turbo-tiny and,
-  # generally, sufficient for our tests.
-  alpine-meta = pkgs.fetchurl {
-    url = "https://tarballs.nixos.org/alpine/3.12/lxd.tar.xz";
-    hash = "sha256-1tcKaO9lOkvqfmG/7FMbfAEToAuFy2YMewS8ysBKuLA=";
-  };
+  lxd-image = import ../release.nix {
+    configuration = {
+      # Building documentation makes the test unnecessarily take a longer time:
+      documentation.enable = lib.mkForce false;
 
-  alpine-rootfs = pkgs.fetchurl {
-    url = "https://tarballs.nixos.org/alpine/3.12/rootfs.tar.xz";
-    hash = "sha256-Tba9sSoaiMtQLY45u7p5DMqXTSDgs/763L/SQp0bkCA=";
+      # Our tests require `grep` & friends:
+      environment.systemPackages = with pkgs; [ busybox ];
+    };
   };
 
-  lxd-config = pkgs.writeText "config.yaml" ''
-    storage_pools:
-      - name: default
-        driver: dir
-        config:
-          source: /var/lxd-pool
-
-    networks:
-      - name: lxdbr0
-        type: bridge
-        config:
-          ipv4.address: auto
-          ipv6.address: none
-
-    profiles:
-      - name: default
-        devices:
-          eth0:
-            name: eth0
-            network: lxdbr0
-            type: nic
-          root:
-            path: /
-            pool: default
-            type: disk
-  '';
-
+  lxd-image-metadata = lxd-image.lxdMeta.${pkgs.system};
+  lxd-image-rootfs = lxd-image.lxdImage.${pkgs.system};
 
 in {
   name = "lxd";
@@ -51,8 +21,10 @@ in {
     maintainers = [ patryk27 ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     virtualisation = {
+      diskSize = 2048;
+
       # Since we're testing `limits.cpu`, we've gotta have a known number of
       # cores to lean on
       cores = 2;
@@ -77,61 +49,66 @@ in {
     machine.succeed("mkdir /var/lxd-pool")
 
     machine.succeed(
-        "cat ${lxd-config} | lxd init --preseed"
+        "cat ${./common/lxd/config.yaml} | lxd init --preseed"
     )
 
     machine.succeed(
-        "lxc image import ${alpine-meta} ${alpine-rootfs} --alias alpine"
+        "lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs}/*/*.tar.xz --alias nixos"
     )
 
-    with subtest("Containers can be launched and destroyed"):
-        machine.succeed("lxc launch alpine test")
-        machine.succeed("lxc exec test true")
-        machine.succeed("lxc delete -f test")
+    with subtest("Container can be managed"):
+        machine.succeed("lxc launch nixos container")
+        machine.sleep(5)
+        machine.succeed("echo true | lxc exec container /run/current-system/sw/bin/bash -")
+        machine.succeed("lxc exec container true")
+        machine.succeed("lxc delete -f container")
 
-    with subtest("Containers are being mounted with lxcfs inside"):
-        machine.succeed("lxc launch alpine test")
+    with subtest("Container is mounted with lxcfs inside"):
+        machine.succeed("lxc launch nixos container")
+        machine.sleep(5)
 
         ## ---------- ##
         ## limits.cpu ##
 
-        machine.succeed("lxc config set test limits.cpu 1")
-        machine.succeed("lxc restart test")
+        machine.succeed("lxc config set container limits.cpu 1")
+        machine.succeed("lxc restart container")
+        machine.sleep(5)
 
-        # Since Alpine doesn't have `nproc` pre-installed, we've gotta resort
-        # to the primal methods
         assert (
             "1"
-            == machine.succeed("lxc exec test grep -- -c ^processor /proc/cpuinfo").strip()
+            == machine.succeed("lxc exec container grep -- -c ^processor /proc/cpuinfo").strip()
         )
 
-        machine.succeed("lxc config set test limits.cpu 2")
-        machine.succeed("lxc restart test")
+        machine.succeed("lxc config set container limits.cpu 2")
+        machine.succeed("lxc restart container")
+        machine.sleep(5)
 
         assert (
             "2"
-            == machine.succeed("lxc exec test grep -- -c ^processor /proc/cpuinfo").strip()
+            == machine.succeed("lxc exec container grep -- -c ^processor /proc/cpuinfo").strip()
         )
 
         ## ------------- ##
         ## limits.memory ##
 
-        machine.succeed("lxc config set test limits.memory 64MB")
-        machine.succeed("lxc restart test")
+        machine.succeed("lxc config set container limits.memory 64MB")
+        machine.succeed("lxc restart container")
+        machine.sleep(5)
 
         assert (
             "MemTotal:          62500 kB"
-            == machine.succeed("lxc exec test grep -- MemTotal /proc/meminfo").strip()
+            == machine.succeed("lxc exec container grep -- MemTotal /proc/meminfo").strip()
         )
 
-        machine.succeed("lxc config set test limits.memory 128MB")
-        machine.succeed("lxc restart test")
+        machine.succeed("lxc config set container limits.memory 128MB")
+        machine.succeed("lxc restart container")
+        machine.sleep(5)
 
         assert (
             "MemTotal:         125000 kB"
-            == machine.succeed("lxc exec test grep -- MemTotal /proc/meminfo").strip()
+            == machine.succeed("lxc exec container grep -- MemTotal /proc/meminfo").strip()
         )
 
-        machine.succeed("lxc delete -f test")
+        machine.succeed("lxc delete -f container")
   '';
 })
diff --git a/nixpkgs/nixos/tests/maddy.nix b/nixpkgs/nixos/tests/maddy.nix
index 581748c1fa59..b9d0416482da 100644
--- a/nixpkgs/nixos/tests/maddy.nix
+++ b/nixpkgs/nixos/tests/maddy.nix
@@ -49,7 +49,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     server.wait_for_open_port(143)
     server.wait_for_open_port(587)
 
-    server.succeed("echo test | maddyctl creds create postmaster@server")
+    server.succeed("maddyctl creds create --password test postmaster@server")
     server.succeed("maddyctl imap-acct create postmaster@server")
 
     client.succeed("send-testmail")
diff --git a/nixpkgs/nixos/tests/maestral.nix b/nixpkgs/nixos/tests/maestral.nix
new file mode 100644
index 000000000000..ba2e0b2f3baa
--- /dev/null
+++ b/nixpkgs/nixos/tests/maestral.nix
@@ -0,0 +1,72 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "maestral";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ peterhoeg ];
+  };
+
+  nodes =
+    let
+      common = attrs:
+        pkgs.lib.recursiveUpdate
+          {
+            imports = [ ./common/user-account.nix ];
+            systemd.user.services.maestral = {
+              description = "Maestral Dropbox Client";
+              serviceConfig.Type = "exec";
+            };
+          }
+          attrs;
+
+    in
+    {
+      cli = { ... }: common {
+        systemd.user.services.maestral = {
+          wantedBy = [ "default.target" ];
+          serviceConfig.ExecStart = "${pkgs.maestral}/bin/maestral start --foreground";
+        };
+      };
+
+      gui = { ... }: common {
+        services.xserver = {
+          enable = true;
+          displayManager.sddm.enable = true;
+          displayManager.defaultSession = "plasma";
+          desktopManager.plasma5.enable = true;
+          desktopManager.plasma5.runUsingSystemd = true;
+          displayManager.autoLogin = {
+            enable = true;
+            user = "alice";
+          };
+        };
+
+        systemd.user.services = {
+          maestral = {
+            wantedBy = [ "graphical-session.target" ];
+            serviceConfig.ExecStart = "${pkgs.maestral-gui}/bin/maestral_qt";
+          };
+          # PowerDevil doesn't like our VM
+          plasma-powerdevil.enable = false;
+        };
+      };
+    };
+
+  testScript = { nodes, ... }:
+    let
+      user = nodes.cli.config.users.users.alice;
+    in
+    ''
+      start_all()
+
+      with subtest("CLI"):
+        # we need SOME way to give the user an active login session
+        cli.execute("loginctl enable-linger ${user.name}")
+        cli.systemctl("start user@${toString user.uid}")
+        cli.wait_for_unit("maestral.service", "${user.name}")
+
+      with subtest("GUI"):
+        gui.wait_for_x()
+        gui.succeed("xauth merge ${user.home}/.Xauthority")
+        gui.wait_for_window("^Desktop ")
+        gui.wait_for_unit("maestral.service", "${user.name}")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/magnetico.nix b/nixpkgs/nixos/tests/magnetico.nix
index 8433a974f453..ee84aacaf7a7 100644
--- a/nixpkgs/nixos/tests/magnetico.nix
+++ b/nixpkgs/nixos/tests/magnetico.nix
@@ -9,7 +9,7 @@ in
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     networking.firewall.allowedTCPPorts = [ 9000 ];
diff --git a/nixpkgs/nixos/tests/mailcatcher.nix b/nixpkgs/nixos/tests/mailcatcher.nix
index a55fba8a9950..627ef56617e9 100644
--- a/nixpkgs/nixos/tests/mailcatcher.nix
+++ b/nixpkgs/nixos/tests/mailcatcher.nix
@@ -4,13 +4,18 @@ import ./make-test-python.nix ({ lib, ... }:
   name = "mailcatcher";
   meta.maintainers = [ lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
     {
       services.mailcatcher.enable = true;
 
-      services.ssmtp.enable = true;
-      services.ssmtp.hostName = "localhost:1025";
+      programs.msmtp = {
+        enable = true;
+        accounts.default = {
+          host = "localhost";
+          port = 1025;
+        };
+      };
 
       environment.systemPackages = [ pkgs.mailutils ];
     };
@@ -19,7 +24,7 @@ import ./make-test-python.nix ({ lib, ... }:
     start_all()
 
     machine.wait_for_unit("mailcatcher.service")
-    machine.wait_for_open_port("1025")
+    machine.wait_for_open_port(1025)
     machine.succeed(
         'echo "this is the body of the email" | mail -s "subject" root@example.org'
     )
diff --git a/nixpkgs/nixos/tests/mailhog.nix b/nixpkgs/nixos/tests/mailhog.nix
index aece57178dd1..e3c2da37a3c8 100644
--- a/nixpkgs/nixos/tests/mailhog.nix
+++ b/nixpkgs/nixos/tests/mailhog.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, ... }: {
   name = "mailhog";
   meta.maintainers = with lib.maintainers; [ jojosch ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.mailhog.enable = true;
 
     environment.systemPackages = with pkgs; [ swaks ];
@@ -12,8 +12,8 @@ import ./make-test-python.nix ({ lib, ... }: {
     start_all()
 
     machine.wait_for_unit("mailhog.service")
-    machine.wait_for_open_port("1025")
-    machine.wait_for_open_port("8025")
+    machine.wait_for_open_port(1025)
+    machine.wait_for_open_port(8025)
     machine.succeed(
         'echo "this is the body of the email" | swaks --to root@example.org --body - --server localhost:1025'
     )
diff --git a/nixpkgs/nixos/tests/matomo.nix b/nixpkgs/nixos/tests/matomo.nix
index f6b0845749cd..526a24fc4db7 100644
--- a/nixpkgs/nixos/tests/matomo.nix
+++ b/nixpkgs/nixos/tests/matomo.nix
@@ -7,7 +7,7 @@ with pkgs.lib;
 let
   matomoTest = package:
   makeTest {
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       services.matomo = {
         package = package;
         enable = true;
diff --git a/nixpkgs/nixos/tests/matrix-appservice-irc.nix b/nixpkgs/nixos/tests/matrix/appservice-irc.nix
index d1c561f95dbf..78c53024ca6c 100644
--- a/nixpkgs/nixos/tests/matrix-appservice-irc.nix
+++ b/nixpkgs/nixos/tests/matrix/appservice-irc.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... }:
+import ../make-test-python.nix ({ pkgs, ... }:
   let
     homeserverUrl = "http://homeserver:8008";
   in
@@ -20,6 +20,9 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
               enable_registration = true;
 
+              # don't use this in production, always use some form of verification
+              enable_registration_without_verification = true;
+
               listeners = [ {
                 # The default but tls=false
                 bind_addresses = [
@@ -190,6 +193,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
     testScript = ''
       import pathlib
+      import os
 
       start_all()
 
@@ -203,7 +207,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
       with subtest("copy the registration file"):
           appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
           homeserver.copy_from_host(
-              pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml", "/"
+              str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
           )
           homeserver.succeed("chmod 444 /registration.yml")
 
diff --git a/nixpkgs/nixos/tests/matrix-conduit.nix b/nixpkgs/nixos/tests/matrix/conduit.nix
index d159fbaa4800..780837f962fa 100644
--- a/nixpkgs/nixos/tests/matrix-conduit.nix
+++ b/nixpkgs/nixos/tests/matrix/conduit.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... }:
+import ../make-test-python.nix ({ pkgs, ... }:
   let
     name = "conduit";
   in
diff --git a/nixpkgs/nixos/tests/dendrite.nix b/nixpkgs/nixos/tests/matrix/dendrite.nix
index a444c9b20018..82e71d912130 100644
--- a/nixpkgs/nixos/tests/dendrite.nix
+++ b/nixpkgs/nixos/tests/matrix/dendrite.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix (
+import ../make-test-python.nix (
   { pkgs, ... }:
     let
       homeserverUrl = "http://homeserver:8008";
@@ -17,9 +17,11 @@ import ./make-test-python.nix (
           homeserver = { pkgs, ... }: {
             services.dendrite = {
               enable = true;
+              loadCredential = [ "test_private_key:${private_key}" ];
+              openRegistration = true;
               settings = {
                 global.server_name = "test-dendrite-server.com";
-                global.private_key = private_key;
+                global.private_key = "$CREDENTIALS_DIRECTORY/test_private_key";
                 client_api.registration_disabled = false;
               };
             };
diff --git a/nixpkgs/nixos/tests/matrix/mjolnir.nix b/nixpkgs/nixos/tests/matrix/mjolnir.nix
index 54094ab9d611..cb843e2e9e3e 100644
--- a/nixpkgs/nixos/tests/matrix/mjolnir.nix
+++ b/nixpkgs/nixos/tests/matrix/mjolnir.nix
@@ -43,6 +43,7 @@ import ../make-test-python.nix (
             tls_certificate_path = "${cert}";
             tls_private_key_path = "${key}";
             enable_registration = true;
+            enable_registration_without_verification = true;
             registration_shared_secret = "supersecret-registration";
 
             listeners = [ {
diff --git a/nixpkgs/nixos/tests/matrix/pantalaimon.nix b/nixpkgs/nixos/tests/matrix/pantalaimon.nix
index 1a9894dd2159..b5d649e6517a 100644
--- a/nixpkgs/nixos/tests/matrix/pantalaimon.nix
+++ b/nixpkgs/nixos/tests/matrix/pantalaimon.nix
@@ -36,7 +36,7 @@ import ../make-test-python.nix (
       maintainers = teams.matrix.members;
     };
 
-    machine = { pkgs, ... }: {
+    nodes.machine = { pkgs, ... }: {
       services.pantalaimon-headless.instances.${pantalaimonInstanceName} = {
         homeserver = "https://localhost:8448";
         listenAddress = "0.0.0.0";
diff --git a/nixpkgs/nixos/tests/matrix-synapse.nix b/nixpkgs/nixos/tests/matrix/synapse.nix
index 1ff1e47b2840..756a8d5de49a 100644
--- a/nixpkgs/nixos/tests/matrix-synapse.nix
+++ b/nixpkgs/nixos/tests/matrix/synapse.nix
@@ -1,4 +1,4 @@
-import ./make-test-python.nix ({ pkgs, ... } : let
+import ../make-test-python.nix ({ pkgs, ... } : let
 
 
   runWithOpenSSL = file: cmd: pkgs.runCommand file {
@@ -27,7 +27,7 @@ import ./make-test-python.nix ({ pkgs, ... } : let
   '';
 
 
-  mailerCerts = import ./common/acme/server/snakeoil-certs.nix;
+  mailerCerts = import ../common/acme/server/snakeoil-certs.nix;
   mailerDomain = mailerCerts.domain;
   registrationSharedSecret = "unsecure123";
   testUser = "alice";
diff --git a/nixpkgs/nixos/tests/mediawiki.nix b/nixpkgs/nixos/tests/mediawiki.nix
index 702fefefa161..7f31d6aadfa2 100644
--- a/nixpkgs/nixos/tests/mediawiki.nix
+++ b/nixpkgs/nixos/tests/mediawiki.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "mediawiki";
   meta.maintainers = [ lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.mediawiki.enable = true;
       services.mediawiki.virtualHost.hostName = "localhost";
diff --git a/nixpkgs/nixos/tests/meilisearch.nix b/nixpkgs/nixos/tests/meilisearch.nix
index c379bda74c59..6d7514a1cc0a 100644
--- a/nixpkgs/nixos/tests/meilisearch.nix
+++ b/nixpkgs/nixos/tests/meilisearch.nix
@@ -5,14 +5,15 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
     apiUrl = "http://${listenAddress}:${toString listenPort}";
     uid = "movies";
     indexJSON = pkgs.writeText "index.json" (builtins.toJSON { inherit uid; });
-    moviesJSON = pkgs.runCommand "movies.json" {} ''
-      sed -n '1,5p;$p' ${pkgs.meilisearch.src}/datasets/movies/movies.json > $out
-    '';
+    moviesJSON = pkgs.fetchurl {
+      url = "https://github.com/meilisearch/meilisearch/raw/v0.23.1/datasets/movies/movies.json";
+      sha256 = "1r3srld63dpmg9yrmysm6xl175661j5cspi93mk5q2wf8xwn50c5";
+    };
   in {
     name = "meilisearch";
     meta.maintainers = with lib.maintainers; [ Br1ght0ne ];
 
-    machine = { ... }: {
+    nodes.machine = { ... }: {
       environment.systemPackages = with pkgs; [ curl jq ];
       services.meilisearch = {
         enable = true;
@@ -26,7 +27,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       start_all()
 
       machine.wait_for_unit("meilisearch")
-      machine.wait_for_open_port("7700")
+      machine.wait_for_open_port(7700)
 
       with subtest("check version"):
           version = json.loads(machine.succeed("curl ${apiUrl}/version"))
@@ -34,7 +35,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
 
       with subtest("create index"):
           machine.succeed(
-              "curl -XPOST ${apiUrl}/indexes --data @${indexJSON}"
+              "curl -XPOST --header 'Content-Type: application/json' ${apiUrl}/indexes --data @${indexJSON}"
           )
           indexes = json.loads(machine.succeed("curl ${apiUrl}/indexes"))
           assert len(indexes) == 1, "index wasn't created"
@@ -42,7 +43,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       with subtest("add documents"):
           response = json.loads(
               machine.succeed(
-                  "curl -XPOST ${apiUrl}/indexes/${uid}/documents --data @${moviesJSON}"
+                  "curl -XPOST --header 'Content-Type: application/json' ${apiUrl}/indexes/${uid}/documents --data @${moviesJSON}"
               )
           )
           update_id = response["updateId"]
diff --git a/nixpkgs/nixos/tests/memcached.nix b/nixpkgs/nixos/tests/memcached.nix
index 31f5627d25ce..6549995110d7 100644
--- a/nixpkgs/nixos/tests/memcached.nix
+++ b/nixpkgs/nixos/tests/memcached.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "memcached";
 
-  machine = {
+  nodes.machine = {
     imports = [ ../modules/profiles/minimal.nix ];
     services.memcached.enable = true;
   };
diff --git a/nixpkgs/nixos/tests/mimir.nix b/nixpkgs/nixos/tests/mimir.nix
new file mode 100644
index 000000000000..f1b30d261472
--- /dev/null
+++ b/nixpkgs/nixos/tests/mimir.nix
@@ -0,0 +1,50 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "mimir";
+  nodes = {
+    server = { ... }: {
+      environment.systemPackages = [ pkgs.jq ];
+      services.mimir.enable = true;
+      services.mimir.configuration = {
+        ingester.ring.replication_factor = 1;
+      };
+
+      services.telegraf.enable = true;
+      services.telegraf.extraConfig = {
+        agent.interval = "1s";
+        agent.flush_interval = "1s";
+        inputs.exec = {
+          commands = [
+            "${pkgs.coreutils}/bin/echo 'foo i=42i'"
+          ];
+          data_format = "influx";
+        };
+        outputs = {
+          http = {
+            # test remote write
+            url = "http://localhost:8080/api/v1/push";
+
+            # Data format to output.
+            data_format = "prometheusremotewrite";
+
+            headers = {
+              Content-Type = "application/x-protobuf";
+              Content-Encoding = "snappy";
+              X-Scope-OrgID = "nixos";
+              X-Prometheus-Remote-Write-Version = "0.1.0";
+            };
+          };
+        };
+      };
+    };
+  };
+
+  testScript = ''
+    start_all()
+    server.wait_for_unit("mimir.service")
+    server.wait_for_unit("telegraf.service")
+    server.wait_for_open_port(8080)
+    server.wait_until_succeeds(
+        "curl -H 'X-Scope-OrgID: nixos' http://127.0.0.1:8080/prometheus/api/v1/label/host/values | jq -r '.data[0]' | grep server"
+    )
+  '';
+})
diff --git a/nixpkgs/nixos/tests/minecraft-server.nix b/nixpkgs/nixos/tests/minecraft-server.nix
index dbe2cd6d56fe..a51b36ff5308 100644
--- a/nixpkgs/nixos/tests/minecraft-server.nix
+++ b/nixpkgs/nixos/tests/minecraft-server.nix
@@ -33,5 +33,6 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
     assert "${seed}" in server.succeed(
         "mcrcon -H localhost -P ${toString rcon-port} -p '${rcon-pass}' -c 'seed'"
     )
+    server.succeed("systemctl stop minecraft-server")
   '';
 })
diff --git a/nixpkgs/nixos/tests/minidlna.nix b/nixpkgs/nixos/tests/minidlna.nix
index 104b79078fd5..76039b0bb42c 100644
--- a/nixpkgs/nixos/tests/minidlna.nix
+++ b/nixpkgs/nixos/tests/minidlna.nix
@@ -32,7 +32,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     start_all()
     server.succeed("mkdir -p /tmp/stuff && chown minidlna: /tmp/stuff")
     server.wait_for_unit("minidlna")
-    server.wait_for_open_port("8200")
+    server.wait_for_open_port(8200)
     # requests must be made *by IP* to avoid triggering minidlna's
     # DNS-rebinding protection
     server.succeed("curl --fail http://$(getent ahostsv4 localhost | head -n1 | cut -f 1 -d ' '):8200/")
diff --git a/nixpkgs/nixos/tests/misc.nix b/nixpkgs/nixos/tests/misc.nix
index 02513c4726c1..0d5f0fe2f044 100644
--- a/nixpkgs/nixos/tests/misc.nix
+++ b/nixpkgs/nixos/tests/misc.nix
@@ -8,7 +8,7 @@ in {
     maintainers = [ eelco ];
   };
 
-  machine =
+  nodes.machine =
     { lib, ... }:
     with lib;
     { swapDevices = mkOverride 0
diff --git a/nixpkgs/nixos/tests/mod_perl.nix b/nixpkgs/nixos/tests/mod_perl.nix
index 29a1eb6503fd..f29d79ea6206 100644
--- a/nixpkgs/nixos/tests/mod_perl.nix
+++ b/nixpkgs/nixos/tests/mod_perl.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = [ sgo ];
   };
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     services.httpd = {
       enable = true;
       adminAddr = "admin@localhost";
diff --git a/nixpkgs/nixos/tests/mongodb.nix b/nixpkgs/nixos/tests/mongodb.nix
index 9c6fdfb1ca76..edd074f5163c 100644
--- a/nixpkgs/nixos/tests/mongodb.nix
+++ b/nixpkgs/nixos/tests/mongodb.nix
@@ -37,6 +37,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
           mongodb-3_6
           mongodb-4_0
           mongodb-4_2
+          mongodb-4_4
+          mongodb-5_0
         ];
       };
     };
@@ -48,6 +50,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
       + runMongoDBTest pkgs.mongodb-3_6
       + runMongoDBTest pkgs.mongodb-4_0
       + runMongoDBTest pkgs.mongodb-4_2
+      + runMongoDBTest pkgs.mongodb-4_4
+      + runMongoDBTest pkgs.mongodb-5_0
       + ''
         node.shutdown()
       '';
diff --git a/nixpkgs/nixos/tests/moodle.nix b/nixpkgs/nixos/tests/moodle.nix
index 56aa62596c07..4570e8963882 100644
--- a/nixpkgs/nixos/tests/moodle.nix
+++ b/nixpkgs/nixos/tests/moodle.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "moodle";
   meta.maintainers = [ lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.moodle.enable = true;
       services.moodle.virtualHost.hostName = "localhost";
diff --git a/nixpkgs/nixos/tests/mosquitto.nix b/nixpkgs/nixos/tests/mosquitto.nix
index 36cc8e3e3d9b..d516d3373d9f 100644
--- a/nixpkgs/nixos/tests/mosquitto.nix
+++ b/nixpkgs/nixos/tests/mosquitto.nix
@@ -4,6 +4,7 @@ let
   port = 1888;
   tlsPort = 1889;
   anonPort = 1890;
+  bindTestPort = 1891;
   password = "VERY_secret";
   hashedPassword = "$7$101$/WJc4Mp+I+uYE9sR$o7z9rD1EYXHPwEP5GqQj6A7k4W1yVbePlb8TqNcuOLV9WNCiDgwHOB0JHC1WCtdkssqTBduBNUnUGd6kmZvDSw==";
   topic = "test/foo";
@@ -125,6 +126,10 @@ in {
               };
             };
           }
+          {
+            settings.bind_interface = "eth0";
+            port = bindTestPort;
+          }
         ];
       };
     };
@@ -134,6 +139,8 @@ in {
   };
 
   testScript = ''
+    import json
+
     def mosquitto_cmd(binary, user, topic, port):
         return (
             "mosquitto_{} "
@@ -162,6 +169,27 @@ in {
     start_all()
     server.wait_for_unit("mosquitto.service")
 
+    with subtest("bind_interface"):
+        addrs = dict()
+        for iface in json.loads(server.succeed("ip -json address show")):
+            for addr in iface['addr_info']:
+                # don't want to deal with multihoming here
+                assert addr['local'] not in addrs
+                addrs[addr['local']] = (iface['ifname'], addr['family'])
+
+        # mosquitto grabs *one* random address per type for bind_interface
+        (has4, has6) = (False, False)
+        for line in server.succeed("ss -HlptnO sport = ${toString bindTestPort}").splitlines():
+            items = line.split()
+            if "mosquitto" not in items[5]: continue
+            listener = items[3].rsplit(':', maxsplit=1)[0].strip('[]')
+            assert listener in addrs
+            assert addrs[listener][0] == "eth0"
+            has4 |= addrs[listener][1] == 'inet'
+            has6 |= addrs[listener][1] == 'inet6'
+        assert has4
+        assert has6
+
     with subtest("check passwords"):
         client1.succeed(publish("-m test", "password_store"))
         client1.succeed(publish("-m test", "password_file"))
diff --git a/nixpkgs/nixos/tests/mtp.nix b/nixpkgs/nixos/tests/mtp.nix
new file mode 100644
index 000000000000..8f0835d75d3f
--- /dev/null
+++ b/nixpkgs/nixos/tests/mtp.nix
@@ -0,0 +1,109 @@
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "mtp";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ matthewcroughan nixinator ];
+  };
+
+  nodes =
+  {
+    client = { config, pkgs, ... }: {
+      # DBUS runs only once a user session is created, which means a user has to
+      # login. Here, we log in as root. Once logged in, the gvfs-daemon service runs
+      # as UID 0 in User-0.service
+      services.getty.autologinUser = "root";
+
+      # XDG_RUNTIME_DIR is needed for running systemd-user services such as
+      # gvfs-daemon as root.
+      environment.variables.XDG_RUNTIME_DIR = "/run/user/0";
+
+      environment.systemPackages = with pkgs; [ usbutils glib jmtpfs tree ];
+      services.gvfs.enable = true;
+
+      # Creates a usb-mtp device inside the VM, which is mapped to the host's
+      # /tmp folder, it is able to write files to this location, but only has
+      # permissions to read its own creations.
+      virtualisation.qemu.options = [
+        "-usb"
+        "-device usb-mtp,rootdir=/tmp,readonly=false"
+      ];
+    };
+  };
+
+
+  testScript = { nodes, ... }:
+    let
+      # Creates a list of QEMU MTP devices matching USB ID (46f4:0004). This
+      # value can be sourced in a shell script. This is so we can loop over the
+      # devices we find, as this test may want to use more than one MTP device
+      # in future.
+      mtpDevices = pkgs.writeScript "mtpDevices.sh" ''
+        export mtpDevices=$(lsusb -d 46f4:0004 | awk {'print $2","$4'} | sed 's/[:-]/ /g')
+      '';
+      # Qemu is only capable of creating an MTP device with Picture Transfer
+      # Protocol. This means that gvfs must use gphoto2:// rather than mtp://
+      # when mounting.
+      # https://github.com/qemu/qemu/blob/970bc16f60937bcfd334f14c614bd4407c247961/hw/usb/dev-mtp.c#L278
+      gvfs = rec {
+        mountAllMtpDevices = pkgs.writeScript "mountAllMtpDevices.sh" ''
+          set -e
+          source ${mtpDevices}
+          for i in $mtpDevices
+          do
+            gio mount "gphoto2://[usb:$i]/"
+          done
+        '';
+        unmountAllMtpDevices = pkgs.writeScript "unmountAllMtpDevices.sh" ''
+          set -e
+          source ${mtpDevices}
+          for i in $mtpDevices
+          do
+            gio mount -u "gphoto2://[usb:$i]/"
+          done
+        '';
+        # gvfsTest:
+        # 1. Creates a 10M test file
+        # 2. Copies it to the device using GIO tools
+        # 3. Checks for corruption with `diff`
+        # 4. Removes the file, then unmounts the disks.
+        gvfsTest = pkgs.writeScript "gvfsTest.sh" ''
+          set -e
+          source ${mtpDevices}
+          ${mountAllMtpDevices}
+          dd if=/dev/urandom of=testFile10M bs=1M count=10
+          for i in $mtpDevices
+          do
+            gio copy ./testFile10M gphoto2://[usb:$i]/
+            ls -lah /run/user/0/gvfs/*/testFile10M
+            gio remove gphoto2://[usb:$i]/testFile10M
+          done
+          ${unmountAllMtpDevices}
+        '';
+      };
+      jmtpfs = {
+        # jmtpfsTest:
+        # 1. Mounts the device on a dir named `phone` using jmtpfs
+        # 2. Puts the current Nixpkgs libmtp version into a file
+        # 3. Checks for corruption with `diff`
+        # 4. Prints the directory tree
+        jmtpfsTest = pkgs.writeScript "jmtpfsTest.sh" ''
+          set -e
+          mkdir phone
+          jmtpfs phone
+          echo "${pkgs.libmtp.version}" > phone/tmp/testFile
+          echo "${pkgs.libmtp.version}" > testFile
+          diff phone/tmp/testFile testFile
+          tree phone
+        '';
+      };
+    in
+    # Using >&2 allows the results of the scripts to be printed to the terminal
+    # when building this test with Nix. Scripts would otherwise complete
+    # silently.
+    ''
+    start_all()
+    client.wait_for_unit("multi-user.target")
+    client.wait_for_unit("dbus.service")
+    client.succeed("${gvfs.gvfsTest} >&2")
+    client.succeed("${jmtpfs.jmtpfsTest} >&2")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/musescore.nix b/nixpkgs/nixos/tests/musescore.nix
index 7fd80d70df12..18de0a550239 100644
--- a/nixpkgs/nixos/tests/musescore.nix
+++ b/nixpkgs/nixos/tests/musescore.nix
@@ -17,7 +17,7 @@ in
     maintainers = [ turion ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [
diff --git a/nixpkgs/nixos/tests/mysql/mysql-autobackup.nix b/nixpkgs/nixos/tests/mysql/mysql-autobackup.nix
index 101122f7bdef..b49466db0a9c 100644
--- a/nixpkgs/nixos/tests/mysql/mysql-autobackup.nix
+++ b/nixpkgs/nixos/tests/mysql/mysql-autobackup.nix
@@ -17,7 +17,7 @@ let
     name = "${name}-automysqlbackup";
     meta.maintainers = [ lib.maintainers.aanderse ];
 
-    machine = {
+    nodes.machine = {
       services.mysql = {
         inherit package;
         enable = true;
diff --git a/nixpkgs/nixos/tests/mysql/mysql-backup.nix b/nixpkgs/nixos/tests/mysql/mysql-backup.nix
index 9335b233327a..968f56dd3c9b 100644
--- a/nixpkgs/nixos/tests/mysql/mysql-backup.nix
+++ b/nixpkgs/nixos/tests/mysql/mysql-backup.nix
@@ -51,7 +51,6 @@ let
 
       # Do a backup and wait for it to start
       master.start_job("mysql-backup.service")
-      master.wait_for_unit("mysql-backup.service")
 
       # wait for backup to fail, because of database 'doesnotexist'
       master.wait_until_fails("systemctl is-active -q mysql-backup.service")
diff --git a/nixpkgs/nixos/tests/n8n.nix b/nixpkgs/nixos/tests/n8n.nix
index ed93639f2a42..c1753a418f67 100644
--- a/nixpkgs/nixos/tests/n8n.nix
+++ b/nixpkgs/nixos/tests/n8n.nix
@@ -7,7 +7,7 @@ let
 in
 {
   name = "n8n";
-  meta.maintainers = with maintainers; [ freezeboy ];
+  meta.maintainers = with maintainers; [ freezeboy k900 ];
 
   nodes.machine =
     { pkgs, ... }:
@@ -19,7 +19,7 @@ in
 
   testScript = ''
     machine.wait_for_unit("n8n.service")
-    machine.wait_for_open_port("${toString port}")
+    machine.wait_for_open_port(${toString port})
     machine.succeed("curl --fail http://localhost:${toString port}/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/nagios.nix b/nixpkgs/nixos/tests/nagios.nix
index e4d8dabedf72..b6e45fc103af 100644
--- a/nixpkgs/nixos/tests/nagios.nix
+++ b/nixpkgs/nixos/tests/nagios.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix (
       maintainers = [ symphorien ];
     };
 
-    machine = { lib, ... }: let
+    nodes.machine = { lib, ... }: let
       writer = pkgs.writeShellScript "write" ''
         set -x
         echo "$@"  >> /tmp/notifications
diff --git a/nixpkgs/nixos/tests/nar-serve.nix b/nixpkgs/nixos/tests/nar-serve.nix
index 9ee738ffb170..bb95ccb36911 100644
--- a/nixpkgs/nixos/tests/nar-serve.nix
+++ b/nixpkgs/nixos/tests/nar-serve.nix
@@ -31,7 +31,7 @@ import ./make-test-python.nix (
 
       # Create a fake cache with Nginx service the static files
       server.succeed(
-          "nix copy --to file:///var/www ${pkgs.hello}"
+          "nix --experimental-features nix-command copy --to file:///var/www ${pkgs.hello}"
       )
       server.wait_for_unit("nginx.service")
       server.wait_for_open_port(80)
diff --git a/nixpkgs/nixos/tests/navidrome.nix b/nixpkgs/nixos/tests/navidrome.nix
index 42e14720b2ed..7315aef62401 100644
--- a/nixpkgs/nixos/tests/navidrome.nix
+++ b/nixpkgs/nixos/tests/navidrome.nix
@@ -1,12 +1,12 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "navidrome";
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.navidrome.enable = true;
   };
 
   testScript = ''
     machine.wait_for_unit("navidrome")
-    machine.wait_for_open_port("4533")
+    machine.wait_for_open_port(4533)
   '';
 })
diff --git a/nixpkgs/nixos/tests/nbd.nix b/nixpkgs/nixos/tests/nbd.nix
index 16255e68e8a1..b4aaf29ee4e5 100644
--- a/nixpkgs/nixos/tests/nbd.nix
+++ b/nixpkgs/nixos/tests/nbd.nix
@@ -28,6 +28,11 @@ import ./make-test-python.nix ({ pkgs, ... }:
         ## It's also a loopback device to test exporting /dev/...
         systemd.services.create-priv-file =
           mkCreateSmallFileService { path = "/vault-priv.disk"; loop = true; };
+        ## `aaa.disk` is just here because "[aaa]" sorts before
+        ## "[generic]" lexicographically, and nbd-server breaks if
+        ## "[generic]" isn't the first section.
+        systemd.services.create-aaa-file =
+          mkCreateSmallFileService { path = "/aaa.disk"; };
 
         # Needed only for nbd-client used in the tests.
         environment.systemPackages = [ pkgs.nbd ];
@@ -39,6 +44,9 @@ import ./make-test-python.nix ({ pkgs, ... }:
         services.nbd.server = {
           enable = true;
           exports = {
+            aaa = {
+              path = "/aaa.disk";
+            };
             vault-pub = {
               path = "/vault-pub.disk";
             };
@@ -83,5 +91,13 @@ import ./make-test-python.nix ({ pkgs, ... }:
       if foundString != testString:
          raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'")
       server.succeed("nbd-client -d /dev/nbd0")
+
+      # Server: Successfully connect to the aaa disk
+      server.succeed("nbd-client localhost ${toString listenPort} /dev/nbd0 -name aaa -persist")
+      server.succeed(f"echo '{testString}' | dd of=/dev/nbd0 conv=notrunc")
+      foundString = server.succeed(f"dd status=none if=/aaa.disk count={len(testString)}")[:len(testString)]
+      if foundString != testString:
+         raise Exception(f"Read the wrong string from nbd disk. Expected: '{testString}'. Found: '{foundString}'")
+      server.succeed("nbd-client -d /dev/nbd0")
     '';
   })
diff --git a/nixpkgs/nixos/tests/ncdns.nix b/nixpkgs/nixos/tests/ncdns.nix
index 50193676f34f..3ce39ed3cb55 100644
--- a/nixpkgs/nixos/tests/ncdns.nix
+++ b/nixpkgs/nixos/tests/ncdns.nix
@@ -29,10 +29,10 @@ in
   };
 
   nodes.server = { ... }: {
-    networking.nameservers = [ "127.0.0.1" ];
+    networking.nameservers = [ "::1" ];
 
     services.namecoind.rpc = {
-      address = "127.0.0.1";
+      address = "::1";
       user = "namecoin";
       password = "secret";
       port = 8332;
@@ -45,7 +45,7 @@ in
       script = ''
         while true; do
           echo -e "HTTP/1.1 200 OK\n\n $(<${fakeReply})\n" \
-            | ${pkgs.netcat}/bin/nc -N -l 127.0.0.1 8332
+            | ${pkgs.netcat}/bin/nc -N -l ::1 8332
         done
       '';
     };
@@ -58,14 +58,10 @@ in
       identity.address    = "1.0.0.1";
     };
 
-    services.pdns-recursor = {
-      enable = true;
-      dns.allowFrom = [ "127.0.0.0/8" ];
-      resolveNamecoin = true;
-    };
+    services.pdns-recursor.enable = true;
+    services.pdns-recursor.resolveNamecoin = true;
 
     environment.systemPackages = [ pkgs.dnsutils ];
-
   };
 
   testScript =
@@ -77,20 +73,21 @@ in
 
       with subtest("DNSKEY bit record is present"):
           server.wait_for_unit("pdns-recursor")
-          server.wait_for_open_port("53")
+          server.wait_for_open_port(53)
           server.succeed("host -t DNSKEY bit")
     '') +
     ''
       with subtest("can resolve a .bit name"):
           server.wait_for_unit("namecoind")
           server.wait_for_unit("ncdns")
-          server.wait_for_open_port("8332")
+          server.wait_for_open_port(8332)
           assert "1.2.3.4" in server.succeed("dig @localhost -p 5333 test.bit")
 
       with subtest("SOA record has identity information"):
           assert "example.com" in server.succeed("dig SOA @localhost -p 5333 bit")
 
       with subtest("bit. zone forwarding works"):
+          server.wait_for_unit("pdns-recursor")
           assert "1.2.3.4" in server.succeed("host test.bit")
     '';
 })
diff --git a/nixpkgs/nixos/tests/neo4j.nix b/nixpkgs/nixos/tests/neo4j.nix
index 8329e5630d7a..0b57f5b2e038 100644
--- a/nixpkgs/nixos/tests/neo4j.nix
+++ b/nixpkgs/nixos/tests/neo4j.nix
@@ -2,19 +2,25 @@ import ./make-test-python.nix {
   name = "neo4j";
 
   nodes = {
-    master =
+    server =
       { ... }:
 
       {
+        virtualisation.memorySize = 4096;
+        virtualisation.diskSize = 1024;
+
         services.neo4j.enable = true;
+        # require tls certs to be available
+        services.neo4j.https.enable = false;
+        services.neo4j.bolt.enable = false;
       };
   };
 
   testScript = ''
     start_all()
 
-    master.wait_for_unit("neo4j")
-    master.wait_for_open_port(7474)
-    master.succeed("curl -f http://localhost:7474/")
+    server.wait_for_unit("neo4j.service")
+    server.wait_for_open_port(7474)
+    server.succeed("curl -f http://localhost:7474/")
   '';
 }
diff --git a/nixpkgs/nixos/tests/networking.nix b/nixpkgs/nixos/tests/networking.nix
index dc7938a436aa..71b82b871270 100644
--- a/nixpkgs/nixos/tests/networking.nix
+++ b/nixpkgs/nixos/tests/networking.nix
@@ -77,12 +77,14 @@ let
   testCases = {
     loopback = {
       name = "Loopback";
-      machine.networking.useDHCP = false;
-      machine.networking.useNetworkd = networkd;
+      nodes.client = { pkgs, ... }: with pkgs.lib; {
+        networking.useDHCP = false;
+        networking.useNetworkd = networkd;
+      };
       testScript = ''
         start_all()
-        machine.wait_for_unit("network.target")
-        loopback_addresses = machine.succeed("ip addr show lo")
+        client.wait_for_unit("network.target")
+        loopback_addresses = client.succeed("ip addr show lo")
         assert "inet 127.0.0.1/8" in loopback_addresses
         assert "inet6 ::1/128" in loopback_addresses
       '';
@@ -96,6 +98,7 @@ let
           useNetworkd = networkd;
           useDHCP = false;
           defaultGateway = "192.168.1.1";
+          defaultGateway6 = "fd00:1234:5678:1::1";
           interfaces.eth1.ipv4.addresses = mkOverride 0 [
             { address = "192.168.1.2"; prefixLength = 24; }
             { address = "192.168.1.3"; prefixLength = 32; }
@@ -137,8 +140,49 @@ let
           with subtest("Test default gateway"):
               router.wait_until_succeeds("ping -c 1 192.168.3.1")
               client.wait_until_succeeds("ping -c 1 192.168.3.1")
+              router.wait_until_succeeds("ping -c 1 fd00:1234:5678:3::1")
+              client.wait_until_succeeds("ping -c 1 fd00:1234:5678:3::1")
         '';
     };
+    routeType = {
+      name = "RouteType";
+      nodes.client = { pkgs, ... }: with pkgs.lib; {
+        networking = {
+          useDHCP = false;
+          useNetworkd = networkd;
+          interfaces.eth1.ipv4.routes = [{
+            address = "192.168.1.127";
+            prefixLength = 32;
+            type = "local";
+          }];
+        };
+      };
+      testScript = ''
+        start_all()
+        client.wait_for_unit("network.target")
+        client.succeed("ip -4 route list table local | grep 'local 192.168.1.127'")
+      '';
+    };
+    dhcpDefault = {
+      name = "useDHCP-by-default";
+      nodes.router = router;
+      nodes.client = { lib, ... }: {
+        # Disable test driver default config
+        networking.interfaces = lib.mkForce {};
+        networking.useNetworkd = networkd;
+        virtualisation.vlans = [ 1 ];
+      };
+      testScript = ''
+        start_all()
+        client.wait_for_unit("multi-user.target")
+        client.wait_until_succeeds("ip addr show dev eth1 | grep '192.168.1'")
+        client.shell_interact()
+        client.succeed("ping -c 1 192.168.1.1")
+        router.succeed("ping -c 1 192.168.1.1")
+        router.succeed("ping -c 1 192.168.1.2")
+        client.succeed("ping -c 1 192.168.1.2")
+      '';
+    };
     dhcpSimple = {
       name = "SimpleDHCP";
       nodes.router = router;
@@ -638,9 +682,49 @@ let
               client2.succeed("ip addr show dev vlan >&2")
         '';
     };
+    vlan-ping = let
+        baseIP = number: "10.10.10.${number}";
+        vlanIP = number: "10.1.1.${number}";
+        baseInterface = "eth1";
+        vlanInterface = "vlan42";
+        node = number: {pkgs, ... }: with pkgs.lib; {
+          virtualisation.vlans = [ 1 ];
+          networking = {
+            #useNetworkd = networkd;
+            useDHCP = false;
+            vlans.${vlanInterface} = { id = 42; interface = baseInterface; };
+            interfaces.${baseInterface}.ipv4.addresses = mkOverride 0 [{ address = baseIP number; prefixLength = 24; }];
+            interfaces.${vlanInterface}.ipv4.addresses = mkOverride 0 [{ address = vlanIP number; prefixLength = 24; }];
+          };
+        };
+
+        serverNodeNum = "1";
+        clientNodeNum = "2";
+
+    in {
+      name = "vlan-ping";
+      nodes.server = node serverNodeNum;
+      nodes.client = node clientNodeNum;
+      testScript = { ... }:
+        ''
+          start_all()
+
+          with subtest("Wait for networking to be configured"):
+              server.wait_for_unit("network.target")
+              client.wait_for_unit("network.target")
+
+          with subtest("Test ping on base interface in setup"):
+              client.succeed("ping -I ${baseInterface} -c 1 ${baseIP serverNodeNum}")
+              server.succeed("ping -I ${baseInterface} -c 1 ${baseIP clientNodeNum}")
+
+          with subtest("Test ping on vlan subinterface in setup"):
+              client.succeed("ping -I ${vlanInterface} -c 1 ${vlanIP serverNodeNum}")
+              server.succeed("ping -I ${vlanInterface} -c 1 ${vlanIP clientNodeNum}")
+        '';
+    };
     virtual = {
       name = "Virtual";
-      machine = {
+      nodes.machine = {
         networking.useNetworkd = networkd;
         networking.useDHCP = false;
         networking.interfaces.tap0 = {
@@ -784,7 +868,7 @@ let
     };
     routes = {
       name = "routes";
-      machine = {
+      nodes.machine = {
         networking.useNetworkd = networkd;
         networking.useDHCP = false;
         networking.interfaces.eth0 = {
@@ -865,7 +949,7 @@ let
     };
     rename = {
       name = "RenameInterface";
-      machine = { pkgs, ... }: {
+      nodes.machine = { pkgs, ... }: {
         virtualisation.vlans = [ 1 ];
         networking = {
           useNetworkd = networkd;
@@ -878,7 +962,7 @@ let
                 linkConfig.Name = "custom_name";
               };
             }
-       else { services.udev.initrdRules = ''
+       else { boot.initrd.services.udev.rules = ''
                SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:12:01:01", KERNEL=="eth*", NAME="custom_name"
               '';
             });
@@ -916,7 +1000,7 @@ let
       testMac = "06:00:00:00:02:00";
     in {
       name = "WlanInterface";
-      machine = { pkgs, ... }: {
+      nodes.machine = { pkgs, ... }: {
         boot.kernelModules = [ "mac80211_hwsim" ];
         networking.wlanInterfaces = {
           wlan0 = { device = "wlan0"; };
diff --git a/nixpkgs/nixos/tests/nextcloud/default.nix b/nixpkgs/nixos/tests/nextcloud/default.nix
index b7b1c5c66002..9e378fe6a52d 100644
--- a/nixpkgs/nixos/tests/nextcloud/default.nix
+++ b/nixpkgs/nixos/tests/nextcloud/default.nix
@@ -16,6 +16,10 @@ foldl
       inherit system pkgs;
       nextcloudVersion = ver;
     };
+    "with-declarative-redis-and-secrets${toString ver}" = import ./with-declarative-redis-and-secrets.nix {
+      inherit system pkgs;
+      nextcloudVersion = ver;
+    };
   })
 { }
-  [ 22 23 ]
+  [ 23 24 ]
diff --git a/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
new file mode 100644
index 000000000000..fda05bacb4fe
--- /dev/null
+++ b/nixpkgs/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix
@@ -0,0 +1,118 @@
+import ../make-test-python.nix ({ pkgs, ...}: let
+  adminpass = "hunter2";
+  adminuser = "custom-admin-username";
+in {
+  name = "nextcloud-with-declarative-redis";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ eqyiel ];
+  };
+
+  nodes = {
+    # The only thing the client needs to do is download a file.
+    client = { ... }: {};
+
+    nextcloud = { config, pkgs, ... }: {
+      networking.firewall.allowedTCPPorts = [ 80 ];
+
+      services.nextcloud = {
+        enable = true;
+        hostName = "nextcloud";
+        caching = {
+          apcu = false;
+          redis = true;
+          memcached = false;
+        };
+        config = {
+          dbtype = "pgsql";
+          dbname = "nextcloud";
+          dbuser = "nextcloud";
+          dbhost = "/run/postgresql";
+          inherit adminuser;
+          adminpassFile = toString (pkgs.writeText "admin-pass-file" ''
+            ${adminpass}
+          '');
+        };
+        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";
+        };
+      };
+
+      services.redis = {
+        enable = true;
+      };
+
+      systemd.services.nextcloud-setup= {
+        requires = ["postgresql.service"];
+        after = [
+          "postgresql.service"
+        ];
+      };
+
+      services.postgresql = {
+        enable = true;
+        ensureDatabases = [ "nextcloud" ];
+        ensureUsers = [
+          { name = "nextcloud";
+            ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
+          }
+        ];
+      };
+
+      # 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.
+      environment.etc."nextcloud-secrets.json".text = ''
+        {
+          "redis": {
+            "password": "secret"
+          }
+        }
+      '';
+    };
+  };
+
+  testScript = let
+    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_VENDOR="nextcloud"
+      export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
+      export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
+      "''${@}"
+    '';
+    copySharedFile = pkgs.writeScript "copy-shared-file" ''
+      #!${pkgs.runtimeShell}
+      echo 'hi' | ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file
+    '';
+
+    diffSharedFile = pkgs.writeScript "diff-shared-file" ''
+      #!${pkgs.runtimeShell}
+      diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file)
+    '';
+  in ''
+    start_all()
+    nextcloud.wait_for_unit("multi-user.target")
+    nextcloud.succeed("curl -sSf http://nextcloud/login")
+    nextcloud.succeed(
+        "${withRcloneEnv} ${copySharedFile}"
+    )
+    client.wait_for_unit("multi-user.target")
+    client.succeed(
+        "${withRcloneEnv} ${diffSharedFile}"
+    )
+
+    # redis cache should not be empty
+    nextcloud.fail("redis-cli KEYS * | grep -q 'empty array'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix b/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
index 891001e30b23..63e0e2c59639 100644
--- a/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
+++ b/nixpkgs/nixos/tests/nextcloud/with-mysql-and-memcached.nix
@@ -26,6 +26,7 @@ in {
           redis = false;
           memcached = true;
         };
+        database.createLocally = true;
         config = {
           dbtype = "mysql";
           dbname = "nextcloud";
@@ -38,28 +39,6 @@ in {
         };
       };
 
-      services.mysql = {
-        enable = true;
-        settings.mysqld = {
-          bind-address = "127.0.0.1";
-
-          # FIXME(@Ma27) Nextcloud isn't compatible with mariadb 10.6,
-          # this is a workaround.
-          # See https://help.nextcloud.com/t/update-to-next-cloud-21-0-2-has-get-an-error/117028/22
-          innodb_read_only_compressed = 0;
-        };
-        package = pkgs.mariadb;
-
-        initialScript = pkgs.writeText "mysql-init" ''
-          CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'hunter2';
-          CREATE DATABASE IF NOT EXISTS nextcloud;
-          GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
-            CREATE TEMPORARY TABLES ON nextcloud.* TO 'nextcloud'@'localhost'
-            IDENTIFIED BY 'hunter2';
-          FLUSH privileges;
-        '';
-      };
-
       systemd.services.nextcloud-setup= {
         requires = ["mysql.service"];
         after = ["mysql.service"];
diff --git a/nixpkgs/nixos/tests/nghttpx.nix b/nixpkgs/nixos/tests/nghttpx.nix
index d83c1c4cae63..11cac332827d 100644
--- a/nixpkgs/nixos/tests/nghttpx.nix
+++ b/nixpkgs/nixos/tests/nghttpx.nix
@@ -54,8 +54,8 @@ in
     testScript = ''
       start_all()
 
-      webserver.wait_for_open_port("80")
-      proxy.wait_for_open_port("80")
+      webserver.wait_for_open_port(80)
+      proxy.wait_for_open_port(80)
       client.wait_until_succeeds("curl -s --fail http://proxy/hello-world.txt")
     '';
   })
diff --git a/nixpkgs/nixos/tests/nginx-auth.nix b/nixpkgs/nixos/tests/nginx-auth.nix
index c0d24a20ddbc..a85426dda871 100644
--- a/nixpkgs/nixos/tests/nginx-auth.nix
+++ b/nixpkgs/nixos/tests/nginx-auth.nix
@@ -13,14 +13,14 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
         virtualHosts.lockedroot = {
           inherit root;
-          basicAuth.alice = "jane";
+          basicAuth.alice = "pwofa";
         };
 
         virtualHosts.lockedsubdir = {
           inherit root;
           locations."/sublocation/" = {
             alias = "${root}/";
-            basicAuth.bob = "john";
+            basicAuth.bob = "pwofb";
           };
         };
       };
@@ -33,7 +33,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
     webserver.fail("curl --fail --resolve lockedroot:80:127.0.0.1 http://lockedroot")
     webserver.succeed(
-        "curl --fail --resolve lockedroot:80:127.0.0.1 http://alice:jane@lockedroot"
+        "curl --fail --resolve lockedroot:80:127.0.0.1 http://alice:pwofa@lockedroot"
     )
 
     webserver.succeed("curl --fail --resolve lockedsubdir:80:127.0.0.1 http://lockedsubdir")
@@ -41,7 +41,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
         "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://lockedsubdir/sublocation/index.html"
     )
     webserver.succeed(
-        "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://bob:john@lockedsubdir/sublocation/index.html"
+        "curl --fail --resolve lockedsubdir:80:127.0.0.1 http://bob:pwofb@lockedsubdir/sublocation/index.html"
     )
   '';
 })
diff --git a/nixpkgs/nixos/tests/nginx-etag.nix b/nixpkgs/nixos/tests/nginx-etag.nix
index b69511d081d4..6f45eacf8b41 100644
--- a/nixpkgs/nixos/tests/nginx-etag.nix
+++ b/nixpkgs/nixos/tests/nginx-etag.nix
@@ -53,14 +53,14 @@ import ./make-test-python.nix {
 
           driver.implicitly_wait(20)
           driver.get('http://server/')
-          driver.find_element_by_xpath('//div[@foo="bar"]')
+          driver.find_element('xpath', '//div[@foo="bar"]')
           open('/tmp/passed_stage1', 'w')
 
           while not os.path.exists('/tmp/proceed'):
               time.sleep(0.5)
 
           driver.get('http://server/')
-          driver.find_element_by_xpath('//div[@foo="yay"]')
+          driver.find_element('xpath', '//div[@foo="yay"]')
           open('/tmp/passed', 'w')
         '';
       in [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
diff --git a/nixpkgs/nixos/tests/nginx-http3.nix b/nixpkgs/nixos/tests/nginx-http3.nix
new file mode 100644
index 000000000000..319f6aac184a
--- /dev/null
+++ b/nixpkgs/nixos/tests/nginx-http3.nix
@@ -0,0 +1,93 @@
+import ./make-test-python.nix ({lib, pkgs, ...}:
+let
+  hosts = ''
+    192.168.2.101 acme.test
+  '';
+
+in
+{
+  name = "nginx-http3";
+  meta.maintainers = with pkgs.lib.maintainers; [ izorkin ];
+
+  nodes = {
+    server = { pkgs, ... }: {
+      networking = {
+        interfaces.eth1 = {
+          ipv4.addresses = [
+            { address = "192.168.2.101"; prefixLength = 24; }
+          ];
+        };
+        extraHosts = hosts;
+        firewall.allowedTCPPorts = [ 443 ];
+        firewall.allowedUDPPorts = [ 443 ];
+      };
+
+      security.pki.certificates = [
+        (builtins.readFile ./common/acme/server/ca.cert.pem)
+      ];
+
+      services.nginx = {
+        enable = true;
+        package = pkgs.nginxQuic;
+
+        virtualHosts."acme.test" = {
+          onlySSL = true;
+          sslCertificate = ./common/acme/server/acme.test.cert.pem;
+          sslCertificateKey = ./common/acme/server/acme.test.key.pem;
+          http2 = true;
+          http3 = true;
+          reuseport = true;
+          root = lib.mkForce (pkgs.runCommandLocal "testdir2" {} ''
+            mkdir "$out"
+            cat > "$out/index.html" <<EOF
+            <html><body>Hello World!</body></html>
+            EOF
+            cat > "$out/example.txt" <<EOF
+            Check http3 protocol.
+            EOF
+          '');
+        };
+      };
+    };
+
+    client = { pkgs, ... }: {
+      environment.systemPackages = [ pkgs.curlHTTP3 ];
+      networking = {
+        interfaces.eth1 = {
+          ipv4.addresses = [
+            { address = "192.168.2.201"; prefixLength = 24; }
+          ];
+        };
+        extraHosts = hosts;
+      };
+
+      security.pki.certificates = [
+        (builtins.readFile ./common/acme/server/ca.cert.pem)
+      ];
+    };
+  };
+
+  testScript = ''
+    start_all()
+
+    server.wait_for_unit("nginx")
+    server.wait_for_open_port(443)
+
+    # Check http connections
+    client.succeed("curl --verbose --http3 https://acme.test | grep 'Hello World!'")
+
+    # Check downloadings
+    client.succeed("curl --verbose --http3 https://acme.test/example.txt --output /tmp/example.txt")
+    client.succeed("cat /tmp/example.txt | grep 'Check http3 protocol.'")
+
+    # Check header reading
+    client.succeed("curl --verbose --http3 --head https://acme.test | grep 'content-type'")
+
+    # Check change User-Agent
+    client.succeed("curl --verbose --http3 --user-agent 'Curl test 3.0' https://acme.test")
+    server.succeed("cat /var/log/nginx/access.log | grep 'Curl test 3.0'")
+
+    server.shutdown()
+    client.shutdown()
+  '';
+})
diff --git a/nixpkgs/nixos/tests/nginx-modsecurity.nix b/nixpkgs/nixos/tests/nginx-modsecurity.nix
index 8c53c0196d4c..5ceee3787297 100644
--- a/nixpkgs/nixos/tests/nginx-modsecurity.nix
+++ b/nixpkgs/nixos/tests/nginx-modsecurity.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "nginx-modsecurity";
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     services.nginx = {
       enable = true;
       additionalModules = [ pkgs.nginxModules.modsecurity-nginx ];
diff --git a/nixpkgs/nixos/tests/nginx-pubhtml.nix b/nixpkgs/nixos/tests/nginx-pubhtml.nix
index 6e1e605628e9..bff24c99d41a 100644
--- a/nixpkgs/nixos/tests/nginx-pubhtml.nix
+++ b/nixpkgs/nixos/tests/nginx-pubhtml.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "nginx-pubhtml";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     systemd.services.nginx.serviceConfig.ProtectHome = "read-only";
     services.nginx.enable = true;
     services.nginx.virtualHosts.localhost = {
diff --git a/nixpkgs/nixos/tests/nginx-sandbox.nix b/nixpkgs/nixos/tests/nginx-sandbox.nix
index 2d512725f265..92ba30a09cf9 100644
--- a/nixpkgs/nixos/tests/nginx-sandbox.nix
+++ b/nixpkgs/nixos/tests/nginx-sandbox.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
 
   # This test checks the creation and reading of a file in sandbox mode. Used simple lua script.
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     nixpkgs.overlays = [
       (self: super: {
         nginx-lua = super.nginx.override {
diff --git a/nixpkgs/nixos/tests/nginx-sso.nix b/nixpkgs/nixos/tests/nginx-sso.nix
index aeb89859c73f..221c5f4ed905 100644
--- a/nixpkgs/nixos/tests/nginx-sso.nix
+++ b/nixpkgs/nixos/tests/nginx-sso.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = with pkgs.lib.maintainers; [ delroth ];
   };
 
-  machine = {
+  nodes.machine = {
     services.nginx.sso = {
       enable = true;
       configuration = {
diff --git a/nixpkgs/nixos/tests/nginx-variants.nix b/nixpkgs/nixos/tests/nginx-variants.nix
index 96a9a2c3b8c1..0faa0127669d 100644
--- a/nixpkgs/nixos/tests/nginx-variants.nix
+++ b/nixpkgs/nixos/tests/nginx-variants.nix
@@ -13,7 +13,7 @@ builtins.listToAttrs (
         value = makeTest {
           name = "nginx-variant-${nginxName}";
 
-          machine = { pkgs, ... }: {
+          nodes.machine = { pkgs, ... }: {
             services.nginx = {
               enable = true;
               virtualHosts.localhost.locations."/".return = "200 'foo'";
diff --git a/nixpkgs/nixos/tests/nitter.nix b/nixpkgs/nixos/tests/nitter.nix
index 0e1a6d150f38..8bc55ba8c69f 100644
--- a/nixpkgs/nixos/tests/nitter.nix
+++ b/nixpkgs/nixos/tests/nitter.nix
@@ -12,7 +12,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
   testScript = ''
     machine.wait_for_unit("nitter.service")
-    machine.wait_for_open_port("80")
+    machine.wait_for_open_port(80)
     machine.succeed("curl --fail http://localhost:80/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/nix-ld.nix b/nixpkgs/nixos/tests/nix-ld.nix
index 5c886182d969..ae5297ab87ea 100644
--- a/nixpkgs/nixos/tests/nix-ld.nix
+++ b/nixpkgs/nixos/tests/nix-ld.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ lib, pkgs, ...} :
     environment.systemPackages = [
       (pkgs.runCommand "patched-hello" {} ''
         install -D -m755 ${pkgs.hello}/bin/hello $out/bin/hello
-        patchelf $out/bin/hello --set-interpreter ${pkgs.nix-ld.ldPath}
+        patchelf $out/bin/hello --set-interpreter $(cat ${pkgs.nix-ld}/nix-support/ldpath)
       '')
     ];
   };
diff --git a/nixpkgs/nixos/tests/nix-serve.nix b/nixpkgs/nixos/tests/nix-serve.nix
index ab82f4be43e6..3aa913f81107 100644
--- a/nixpkgs/nixos/tests/nix-serve.nix
+++ b/nixpkgs/nixos/tests/nix-serve.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }:
 {
   name = "nix-serve";
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.nix-serve.enable = true;
     environment.systemPackages = [
       pkgs.hello
diff --git a/nixpkgs/nixos/tests/nixops/default.nix b/nixpkgs/nixos/tests/nixops/default.nix
index f0834c51f0b4..227b38815073 100644
--- a/nixpkgs/nixos/tests/nixops/default.nix
+++ b/nixpkgs/nixos/tests/nixops/default.nix
@@ -97,7 +97,7 @@ let
     derivations and all build dependency outputs, all the way down.
   */
   allDrvOutputs = pkg:
-    let name = lib.strings.sanitizeDerivationName "allDrvOutputs-${pkg.pname or pkg.name or "unknown"}";
+    let name = "allDrvOutputs-${pkg.pname or pkg.name or "unknown"}";
     in
     pkgs.runCommand name { refs = pkgs.writeReferencesToFile pkg.drvPath; } ''
       touch $out
diff --git a/nixpkgs/nixos/tests/nixos-generate-config.nix b/nixpkgs/nixos/tests/nixos-generate-config.nix
index 1dadf4992ed0..e1c2f29e0673 100644
--- a/nixpkgs/nixos/tests/nixos-generate-config.nix
+++ b/nixpkgs/nixos/tests/nixos-generate-config.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ lib, ... } : {
   name = "nixos-generate-config";
   meta.maintainers = with lib.maintainers; [ basvandijk ];
-  machine = {
+  nodes.machine = {
     system.nixos-generate-config.configuration = ''
       # OVERRIDDEN
       { config, pkgs, ... }: {
diff --git a/nixpkgs/nixos/tests/node-red.nix b/nixpkgs/nixos/tests/node-red.nix
index 7660bc32f4c9..5f5960d68295 100644
--- a/nixpkgs/nixos/tests/node-red.nix
+++ b/nixpkgs/nixos/tests/node-red.nix
@@ -19,7 +19,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   testScript = ''
     start_all()
     nodered.wait_for_unit("node-red.service")
-    nodered.wait_for_open_port("1880")
+    nodered.wait_for_open_port(1880)
 
     client.wait_for_unit("multi-user.target")
 
diff --git a/nixpkgs/nixos/tests/non-default-filesystems.nix b/nixpkgs/nixos/tests/non-default-filesystems.nix
new file mode 100644
index 000000000000..7fa75aaad724
--- /dev/null
+++ b/nixpkgs/nixos/tests/non-default-filesystems.nix
@@ -0,0 +1,54 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+{
+  name = "non-default-filesystems";
+
+  nodes.machine =
+    { config, pkgs, lib, ... }:
+    let
+      disk = config.virtualisation.bootDevice;
+    in
+    {
+      virtualisation.useDefaultFilesystems = false;
+
+      boot.initrd.availableKernelModules = [ "btrfs" ];
+      boot.supportedFilesystems = [ "btrfs" ];
+
+      boot.initrd.postDeviceCommands = ''
+        FSTYPE=$(blkid -o value -s TYPE ${disk} || true)
+        if test -z "$FSTYPE"; then
+          modprobe btrfs
+          ${pkgs.btrfs-progs}/bin/mkfs.btrfs ${disk}
+
+          mkdir /nixos
+          mount -t btrfs ${disk} /nixos
+
+          ${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/root
+          ${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/home
+
+          umount /nixos
+        fi
+      '';
+
+      virtualisation.fileSystems = {
+        "/" = {
+          device = disk;
+          fsType = "btrfs";
+          options = [ "subvol=/root" ];
+        };
+
+        "/home" = {
+          device = disk;
+          fsType = "btrfs";
+          options = [ "subvol=/home" ];
+        };
+      };
+    };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+
+    with subtest("BTRFS filesystems are mounted correctly"):
+      machine.succeed("grep -E '/dev/vda / btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/root 0 0' /proc/mounts")
+      machine.succeed("grep -E '/dev/vda /home btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/home 0 0' /proc/mounts")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/noto-fonts.nix b/nixpkgs/nixos/tests/noto-fonts.nix
index 049dc766bd3b..e4c33fe26a9e 100644
--- a/nixpkgs/nixos/tests/noto-fonts.nix
+++ b/nixpkgs/nixos/tests/noto-fonts.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ nickcao midchildan ];
   };
 
-  machine = {
+  nodes.machine = {
     imports = [ ./common/x11.nix ];
     environment.systemPackages = [ pkgs.gnome.gedit ];
     fonts = {
diff --git a/nixpkgs/nixos/tests/novacomd.nix b/nixpkgs/nixos/tests/novacomd.nix
index b470c117e1e1..d47d212fb2ec 100644
--- a/nixpkgs/nixos/tests/novacomd.nix
+++ b/nixpkgs/nixos/tests/novacomd.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ dtzWill ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.novacomd.enable = true;
   };
 
diff --git a/nixpkgs/nixos/tests/oh-my-zsh.nix b/nixpkgs/nixos/tests/oh-my-zsh.nix
index 57a073b086e8..1d5227e36236 100644
--- a/nixpkgs/nixos/tests/oh-my-zsh.nix
+++ b/nixpkgs/nixos/tests/oh-my-zsh.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "oh-my-zsh";
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
 
     {
       programs.zsh = {
diff --git a/nixpkgs/nixos/tests/ombi.nix b/nixpkgs/nixos/tests/ombi.nix
index bfca86af8175..ce3064ce6ac6 100644
--- a/nixpkgs/nixos/tests/ombi.nix
+++ b/nixpkgs/nixos/tests/ombi.nix
@@ -12,7 +12,7 @@ with lib;
 
   testScript = ''
     machine.wait_for_unit("ombi.service")
-    machine.wait_for_open_port("5000")
+    machine.wait_for_open_port(5000)
     machine.succeed("curl --fail http://localhost:5000/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/openldap.nix b/nixpkgs/nixos/tests/openldap.nix
index f1a39ad7dde2..075bb5d1f640 100644
--- a/nixpkgs/nixos/tests/openldap.nix
+++ b/nixpkgs/nixos/tests/openldap.nix
@@ -1,9 +1,4 @@
-{ pkgs ? (import ../.. { inherit system; config = { }; })
-, system ? builtins.currentSystem
-, ...
-}:
-
-let
+import ./make-test-python.nix ({ pkgs, ... }: let
   dbContents = ''
     dn: dc=example
     objectClass: domain
@@ -13,118 +8,149 @@ let
     objectClass: organizationalUnit
     ou: users
   '';
-  testScript = ''
-    machine.wait_for_unit("openldap.service")
-    machine.succeed(
-        'ldapsearch -LLL -D "cn=root,dc=example" -w notapassword -b "dc=example"',
-    )
+
+  ldifConfig = ''
+    dn: cn=config
+    cn: config
+    objectClass: olcGlobal
+    olcLogLevel: stats
+
+    dn: cn=schema,cn=config
+    cn: schema
+    objectClass: olcSchemaConfig
+
+    include: file://${pkgs.openldap}/etc/schema/core.ldif
+    include: file://${pkgs.openldap}/etc/schema/cosine.ldif
+    include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
+
+    dn: olcDatabase={0}config,cn=config
+    olcDatabase: {0}config
+    objectClass: olcDatabaseConfig
+    olcRootDN: cn=root,cn=config
+    olcRootPW: configpassword
+
+    dn: olcDatabase={1}mdb,cn=config
+    objectClass: olcDatabaseConfig
+    objectClass: olcMdbConfig
+    olcDatabase: {1}mdb
+    olcDbDirectory: /var/db/openldap
+    olcDbIndex: objectClass eq
+    olcSuffix: dc=example
+    olcRootDN: cn=root,dc=example
+    olcRootPW: notapassword
   '';
+
+  ldapClientConfig = {
+    enable = true;
+    loginPam = false;
+    nsswitch = false;
+    server = "ldap://";
+    base = "dc=example";
+  };
+
 in {
-  # New-style configuration
-  current = import ./make-test-python.nix ({ pkgs, ... }: {
-    inherit testScript;
-    name = "openldap";
+  name = "openldap";
+
+  nodes.machine = { pkgs, ... }: {
+    environment.etc."openldap/root_password".text = "notapassword";
 
-    machine = { pkgs, ... }: {
-      environment.etc."openldap/root_password".text = "notapassword";
-      services.openldap = {
-        enable = true;
-        settings = {
-          children = {
-            "cn=schema".includes = [
-              "${pkgs.openldap}/etc/schema/core.ldif"
-              "${pkgs.openldap}/etc/schema/cosine.ldif"
-              "${pkgs.openldap}/etc/schema/inetorgperson.ldif"
-              "${pkgs.openldap}/etc/schema/nis.ldif"
-            ];
-            "olcDatabase={1}mdb" = {
-              # This tests string, base64 and path values, as well as lists of string values
-              attrs = {
-                objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
-                olcDatabase = "{1}mdb";
-                olcDbDirectory = "/var/db/openldap";
-                olcSuffix = "dc=example";
-                olcRootDN = {
-                  # cn=root,dc=example
-                  base64 = "Y249cm9vdCxkYz1leGFtcGxl";
-                };
-                olcRootPW = {
-                  path = "/etc/openldap/root_password";
-                };
+    users.ldap = ldapClientConfig;
+
+    services.openldap = {
+      enable = true;
+      urlList = [ "ldapi:///" "ldap://" ];
+      settings = {
+        children = {
+          "cn=schema".includes = [
+            "${pkgs.openldap}/etc/schema/core.ldif"
+            "${pkgs.openldap}/etc/schema/cosine.ldif"
+            "${pkgs.openldap}/etc/schema/inetorgperson.ldif"
+            "${pkgs.openldap}/etc/schema/nis.ldif"
+          ];
+          "olcDatabase={0}config" = {
+            attrs = {
+              objectClass = [ "olcDatabaseConfig" ];
+              olcDatabase = "{0}config";
+              olcRootDN = "cn=root,cn=config";
+              olcRootPW = "configpassword";
+            };
+          };
+          "olcDatabase={1}mdb" = {
+            # This tests string, base64 and path values, as well as lists of string values
+            attrs = {
+              objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
+              olcDatabase = "{1}mdb";
+              olcDbDirectory = "/var/lib/openldap/db";
+              olcSuffix = "dc=example";
+              olcRootDN = {
+                # cn=root,dc=example
+                base64 = "Y249cm9vdCxkYz1leGFtcGxl";
+              };
+              olcRootPW = {
+                path = "/etc/openldap/root_password";
               };
             };
           };
         };
-        declarativeContents."dc=example" = dbContents;
       };
     };
-  }) { inherit pkgs system; };
-
-  # Old-style configuration
-  oldOptions = import ./make-test-python.nix ({ pkgs, ... }: {
-    inherit testScript;
-    name = "openldap";
 
-    machine = { pkgs, ... }: {
-      services.openldap = {
-        enable = true;
-        logLevel = "stats acl";
-        defaultSchemas = true;
-        database = "mdb";
-        suffix = "dc=example";
-        rootdn = "cn=root,dc=example";
-        rootpw = "notapassword";
-        declarativeContents."dc=example" = dbContents;
+    specialisation = {
+      declarativeContents.configuration = { ... }: {
+        services.openldap.declarativeContents."dc=example" = dbContents;
       };
-    };
-  }) { inherit system pkgs; };
-
-  # Manually managed configDir, for example if dynamic config is essential
-  manualConfigDir = import ./make-test-python.nix ({ pkgs, ... }: {
-    name = "openldap";
-
-    machine = { pkgs, ... }: {
-      services.openldap = {
-        enable = true;
-        configDir = "/var/db/slapd.d";
+      mutableConfig.configuration = { ... }: {
+        services.openldap = {
+          declarativeContents."dc=example" = dbContents;
+          mutableConfig = true;
+        };
+      };
+      manualConfigDir = {
+        inheritParentConfig = false;
+        configuration = { ... }: {
+          users.ldap = ldapClientConfig;
+          services.openldap = {
+            enable = true;
+            configDir = "/var/db/slapd.d";
+          };
+        };
       };
     };
+  };
+  testScript = { nodes, ... }: let
+    specializations = "${nodes.machine.config.system.build.toplevel}/specialisation";
+    changeRootPw = ''
+      dn: olcDatabase={1}mdb,cn=config
+      changetype: modify
+      replace: olcRootPW
+      olcRootPW: foobar
+    '';
+  in ''
+    # Test startup with empty DB
+    machine.wait_for_unit("openldap.service")
 
-    testScript = let
-      contents = pkgs.writeText "data.ldif" dbContents;
-      config = pkgs.writeText "config.ldif" ''
-        dn: cn=config
-        cn: config
-        objectClass: olcGlobal
-        olcLogLevel: stats
-        olcPidFile: /run/slapd/slapd.pid
-
-        dn: cn=schema,cn=config
-        cn: schema
-        objectClass: olcSchemaConfig
+    with subtest("declarative contents"):
+      machine.succeed('${specializations}/declarativeContents/bin/switch-to-configuration test')
+      machine.wait_for_unit("openldap.service")
+      machine.succeed('ldapsearch -LLL -D "cn=root,dc=example" -w notapassword')
+      machine.fail('ldapmodify -D cn=root,cn=config -w configpassword -f ${pkgs.writeText "rootpw.ldif" changeRootPw}')
 
-        include: file://${pkgs.openldap}/etc/schema/core.ldif
-        include: file://${pkgs.openldap}/etc/schema/cosine.ldif
-        include: file://${pkgs.openldap}/etc/schema/inetorgperson.ldif
+    with subtest("mutable config"):
+      machine.succeed('${specializations}/mutableConfig/bin/switch-to-configuration test')
+      machine.succeed('ldapsearch -LLL -D "cn=root,dc=example" -w notapassword')
+      machine.succeed('ldapmodify -D cn=root,cn=config -w configpassword -f ${pkgs.writeText "rootpw.ldif" changeRootPw}')
+      machine.succeed('ldapsearch -LLL -D "cn=root,dc=example" -w foobar')
 
-        dn: olcDatabase={1}mdb,cn=config
-        objectClass: olcDatabaseConfig
-        objectClass: olcMdbConfig
-        olcDatabase: {1}mdb
-        olcDbDirectory: /var/db/openldap
-        olcDbIndex: objectClass eq
-        olcSuffix: dc=example
-        olcRootDN: cn=root,dc=example
-        olcRootPW: notapassword
-      '';
-    in ''
+    with subtest("manual config dir"):
       machine.succeed(
-          "mkdir -p /var/db/slapd.d /var/db/openldap",
-          "slapadd -F /var/db/slapd.d -n0 -l ${config}",
-          "slapadd -F /var/db/slapd.d -n1 -l ${contents}",
-          "chown -R openldap:openldap /var/db/slapd.d /var/db/openldap",
-          "systemctl restart openldap",
+        'mkdir /var/db/slapd.d /var/db/openldap',
+        'slapadd -F /var/db/slapd.d -n0 -l ${pkgs.writeText "config.ldif" ldifConfig}',
+        'slapadd -F /var/db/slapd.d -n1 -l ${pkgs.writeText "contents.ldif" dbContents}',
+        'chown -R openldap:openldap /var/db/slapd.d /var/db/openldap',
+        '${specializations}/manualConfigDir/bin/switch-to-configuration test',
       )
-    '' + testScript;
-  }) { inherit system pkgs; };
-}
+      machine.succeed('ldapsearch -LLL -D "cn=root,dc=example" -w notapassword')
+      machine.succeed('ldapmodify -D cn=root,cn=config -w configpassword -f ${pkgs.writeText "rootpw.ldif" changeRootPw}')
+      machine.succeed('ldapsearch -LLL -D "cn=root,dc=example" -w foobar')
+  '';
+})
diff --git a/nixpkgs/nixos/tests/openssh.nix b/nixpkgs/nixos/tests/openssh.nix
index 003813379e69..4083f5906d79 100644
--- a/nixpkgs/nixos/tests/openssh.nix
+++ b/nixpkgs/nixos/tests/openssh.nix
@@ -80,17 +80,21 @@ in {
 
         client.wait_for_unit("network.target")
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'echo hello world' >&2",
+            timeout=30
         )
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server 'ulimit -l' | grep 1024",
+            timeout=30
         )
 
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'echo hello world' >&2"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'echo hello world' >&2",
+            timeout=30
         )
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'ulimit -l' | grep 1024"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no server_lazy 'ulimit -l' | grep 1024",
+            timeout=30
         )
 
     with subtest("configured-authkey"):
@@ -99,10 +103,12 @@ in {
         )
         client.succeed("chmod 600 privkey.snakeoil")
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server true",
+            timeout=30
         )
         client.succeed(
-            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server_lazy true"
+            "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil server_lazy true",
+            timeout=30
         )
 
     with subtest("localhost-only"):
diff --git a/nixpkgs/nixos/tests/opentabletdriver.nix b/nixpkgs/nixos/tests/opentabletdriver.nix
index fe345a7bec73..b7583f6dd264 100644
--- a/nixpkgs/nixos/tests/opentabletdriver.nix
+++ b/nixpkgs/nixos/tests/opentabletdriver.nix
@@ -6,7 +6,7 @@ in {
     maintainers = with pkgs.lib.maintainers; [ thiagokokada ];
   };
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
     {
       imports = [
         ./common/user-account.nix
diff --git a/nixpkgs/nixos/tests/os-prober.nix b/nixpkgs/nixos/tests/os-prober.nix
index 90375450fe1b..1c89cf8c1c67 100644
--- a/nixpkgs/nixos/tests/os-prober.nix
+++ b/nixpkgs/nixos/tests/os-prober.nix
@@ -65,7 +65,7 @@ let
 in {
   name = "os-prober";
 
-  machine = { config, pkgs, ... }: (simpleConfig // {
+  nodes.machine = { config, pkgs, ... }: (simpleConfig // {
       imports = [ ../modules/profiles/installation-device.nix
                   ../modules/profiles/base.nix ];
       virtualisation.memorySize = 1300;
@@ -75,21 +75,30 @@ in {
       # The test cannot access the network, so any packages
       # nixos-rebuild needs must be included in the VM.
       system.extraDependencies = with pkgs;
-        [ sudo
-          libxml2.bin
-          libxslt.bin
+        [
+          brotli
+          brotli.dev
+          brotli.lib
           desktop-file-utils
           docbook5
           docbook_xsl_ns
-          unionfs-fuse
-          ntp
+          grub2
+          kmod.dev
+          libarchive
+          libarchive.dev
+          libxml2.bin
+          libxslt.bin
           nixos-artwork.wallpapers.simple-dark-gray-bottom
-          perlPackages.XMLLibXML
+          ntp
           perlPackages.ListCompare
+          perlPackages.XMLLibXML
+          python3Minimal
           shared-mime-info
+          stdenv
+          sudo
           texinfo
+          unionfs-fuse
           xorg.lndir
-          grub2
 
           # add curl so that rather than seeing the test attempt to download
           # curl's tarball, we see what it's trying to download
diff --git a/nixpkgs/nixos/tests/osrm-backend.nix b/nixpkgs/nixos/tests/osrm-backend.nix
index 4067d5b1a239..b0e65a2ae1c1 100644
--- a/nixpkgs/nixos/tests/osrm-backend.nix
+++ b/nixpkgs/nixos/tests/osrm-backend.nix
@@ -5,7 +5,7 @@ in {
   name = "osrm-backend";
   meta.maintainers = [ lib.maintainers.erictapen ];
 
-  machine = { config, pkgs, ... }:{
+  nodes.machine = { config, pkgs, ... }:{
 
     services.osrm = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/overlayfs.nix b/nixpkgs/nixos/tests/overlayfs.nix
index 1768f1fea1ed..6dab6760c5b9 100644
--- a/nixpkgs/nixos/tests/overlayfs.nix
+++ b/nixpkgs/nixos/tests/overlayfs.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "overlayfs";
   meta.maintainers = with pkgs.lib.maintainers; [ bachp ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.emptyDiskImages = [ 512 ];
     networking.hostId = "deadbeef";
     environment.systemPackages = with pkgs; [ parted ];
diff --git a/nixpkgs/nixos/tests/packagekit.nix b/nixpkgs/nixos/tests/packagekit.nix
index 020a4e65e6d8..5769c6c9a8d4 100644
--- a/nixpkgs/nixos/tests/packagekit.nix
+++ b/nixpkgs/nixos/tests/packagekit.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ peterhoeg ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     environment.systemPackages = with pkgs; [ dbus ];
     services.packagekit = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/pam/pam-oath-login.nix b/nixpkgs/nixos/tests/pam/pam-oath-login.nix
index 597596b211b1..dd6ef4a0abcb 100644
--- a/nixpkgs/nixos/tests/pam/pam-oath-login.nix
+++ b/nixpkgs/nixos/tests/pam/pam-oath-login.nix
@@ -7,7 +7,7 @@ let
   # how many passwords have been made. In this env, we'll always be on
   # the 0th counter, so the password is static.
   #
-  # Generated in nix-shell -p oathToolkit
+  # Generated in nix-shell -p oath-toolkit
   # via: oathtool -v -d6 -w10 cdd4083ef8ff1fa9178c6d46bfb1a3
   # and picking a the first 4:
   oathSnakeOilPassword1 = "143349";
@@ -21,7 +21,7 @@ in
 {
   name = "pam-oath-login";
 
-  machine =
+  nodes.machine =
     { ... }:
     {
       security.pam.oath = {
@@ -77,28 +77,28 @@ in
     machine.screenshot("postboot")
 
     with subtest("Invalid password"):
-        switch_to_tty(2)
-        enter_user_alice(2)
+        switch_to_tty("2")
+        enter_user_alice("2")
 
         machine.send_chars("${oathSnakeOilPassword1}\n")
-        machine.wait_until_tty_matches(2, "Password: ")
+        machine.wait_until_tty_matches("2", "Password: ")
         machine.send_chars("blorg\n")
-        machine.wait_until_tty_matches(2, "Login incorrect")
+        machine.wait_until_tty_matches("2", "Login incorrect")
 
     with subtest("Invalid oath token"):
-        switch_to_tty(3)
-        enter_user_alice(3)
+        switch_to_tty("3")
+        enter_user_alice("3")
 
         machine.send_chars("000000\n")
-        machine.wait_until_tty_matches(3, "Login incorrect")
-        machine.wait_until_tty_matches(3, "login:")
+        machine.wait_until_tty_matches("3", "Login incorrect")
+        machine.wait_until_tty_matches("3", "login:")
 
     with subtest("Happy path: Both passwords are mandatory to get us in"):
-        switch_to_tty(4)
-        enter_user_alice(4)
+        switch_to_tty("4")
+        enter_user_alice("4")
 
         machine.send_chars("${oathSnakeOilPassword2}\n")
-        machine.wait_until_tty_matches(4, "Password: ")
+        machine.wait_until_tty_matches("4", "Password: ")
         machine.send_chars("${alicePassword}\n")
 
         machine.wait_until_succeeds("pgrep -u alice bash")
diff --git a/nixpkgs/nixos/tests/pam/pam-u2f.nix b/nixpkgs/nixos/tests/pam/pam-u2f.nix
index 0ac6ac17be82..07408dea797e 100644
--- a/nixpkgs/nixos/tests/pam/pam-u2f.nix
+++ b/nixpkgs/nixos/tests/pam/pam-u2f.nix
@@ -3,7 +3,7 @@ import ../make-test-python.nix ({ ... }:
 {
   name = "pam-u2f";
 
-  machine =
+  nodes.machine =
     { ... }:
     {
       security.pam.u2f = {
@@ -12,6 +12,7 @@ import ../make-test-python.nix ({ ... }:
         debug = true;
         enable = true;
         interactive = true;
+        origin = "nixos-test";
       };
     };
 
@@ -19,7 +20,7 @@ import ../make-test-python.nix ({ ... }:
     ''
       machine.wait_for_unit("multi-user.target")
       machine.succeed(
-          'egrep "auth required .*/lib/security/pam_u2f.so.*debug.*interactive.*cue" /etc/pam.d/ -R'
+          'egrep "auth required .*/lib/security/pam_u2f.so.*debug.*interactive.*cue.*origin=nixos-test" /etc/pam.d/ -R'
       )
     '';
 })
diff --git a/nixpkgs/nixos/tests/pam/pam-ussh.nix b/nixpkgs/nixos/tests/pam/pam-ussh.nix
new file mode 100644
index 000000000000..ba0570dbf97d
--- /dev/null
+++ b/nixpkgs/nixos/tests/pam/pam-ussh.nix
@@ -0,0 +1,70 @@
+import ../make-test-python.nix ({ pkgs, lib, ... }:
+
+let
+  testOnlySSHCredentials = pkgs.runCommand "pam-ussh-test-ca" {
+    nativeBuildInputs = [ pkgs.openssh ];
+  } ''
+    mkdir $out
+    ssh-keygen -t ed25519 -N "" -f $out/ca
+
+    ssh-keygen -t ed25519 -N "" -f $out/alice
+    ssh-keygen -s $out/ca -I "alice user key" -n "alice,root" -V 19700101:forever $out/alice.pub
+
+    ssh-keygen -t ed25519 -N "" -f $out/bob
+    ssh-keygen -s $out/ca -I "bob user key" -n "bob" -V 19700101:forever $out/bob.pub
+  '';
+  makeTestScript = user: pkgs.writeShellScript "pam-ussh-${user}-test-script" ''
+    set -euo pipefail
+
+    eval $(${pkgs.openssh}/bin/ssh-agent)
+
+    mkdir -p $HOME/.ssh
+    chmod 700 $HOME/.ssh
+    cp ${testOnlySSHCredentials}/${user}{,.pub,-cert.pub} $HOME/.ssh
+    chmod 600 $HOME/.ssh/${user}
+    chmod 644 $HOME/.ssh/${user}{,-cert}.pub
+
+    set -x
+
+    ${pkgs.openssh}/bin/ssh-add $HOME/.ssh/${user}
+    ${pkgs.openssh}/bin/ssh-add -l &>2
+
+    exec sudo id -u -n
+  '';
+in {
+  name = "pam-ussh";
+  meta.maintainers = with lib.maintainers; [ lukegb ];
+
+  machine =
+    { ... }:
+    {
+      users.users.alice = { isNormalUser = true; extraGroups = [ "wheel" ]; };
+      users.users.bob = { isNormalUser = true; extraGroups = [ "wheel" ]; };
+
+      security.pam.ussh = {
+        enable = true;
+        authorizedPrincipals = "root";
+        caFile = "${testOnlySSHCredentials}/ca.pub";
+      };
+
+      security.sudo = {
+        enable = true;
+        extraConfig = ''
+          Defaults lecture="never"
+        '';
+      };
+    };
+
+  testScript =
+    ''
+      with subtest("alice should be allowed to escalate to root"):
+        machine.succeed(
+            'su -c "${makeTestScript "alice"}" -l alice | grep root'
+        )
+
+      with subtest("bob should not be allowed to escalate to root"):
+        machine.fail(
+            'su -c "${makeTestScript "bob"}" -l bob | grep root'
+        )
+    '';
+})
diff --git a/nixpkgs/nixos/tests/pantheon.nix b/nixpkgs/nixos/tests/pantheon.nix
index 989d29a966df..52f85f5c07da 100644
--- a/nixpkgs/nixos/tests/pantheon.nix
+++ b/nixpkgs/nixos/tests/pantheon.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} :
     maintainers = teams.pantheon.members;
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/paperless-ng.nix b/nixpkgs/nixos/tests/paperless.nix
index 618eeec6b125..12883cd62c60 100644
--- a/nixpkgs/nixos/tests/paperless-ng.nix
+++ b/nixpkgs/nixos/tests/paperless.nix
@@ -1,30 +1,32 @@
 import ./make-test-python.nix ({ lib, ... }: {
-  name = "paperless-ng";
-  meta.maintainers = with lib.maintainers; [ earvstedt Flakebi ];
+  name = "paperless";
+  meta.maintainers = with lib.maintainers; [ erikarvstedt Flakebi ];
 
   nodes.machine = { pkgs, ... }: {
     environment.systemPackages = with pkgs; [ imagemagick jq ];
-    services.paperless-ng = {
+    services.paperless = {
       enable = true;
       passwordFile = builtins.toFile "password" "admin";
     };
   };
 
   testScript = ''
-    machine.wait_for_unit("paperless-ng-consumer.service")
+    import json
 
-    with subtest("Create test doc"):
+    machine.wait_for_unit("paperless-consumer.service")
+
+    with subtest("Add a document via the file system"):
         machine.succeed(
             "convert -size 400x40 xc:white -font 'DejaVu-Sans' -pointsize 20 -fill black "
             "-annotate +5+20 'hello world 16-10-2005' /var/lib/paperless/consume/doc.png"
         )
 
     with subtest("Web interface gets ready"):
-        machine.wait_for_unit("paperless-ng-web.service")
+        machine.wait_for_unit("paperless-web.service")
         # Wait until server accepts connections
         machine.wait_until_succeeds("curl -fs localhost:28981")
 
-    with subtest("Create web test doc"):
+    with subtest("Add a 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"
@@ -35,11 +37,8 @@ import ./make-test-python.nix ({ lib, ... }: {
         machine.wait_until_succeeds(
             "(($(curl -u admin:admin -fs localhost:28981/api/documents/ | jq .count) == 2))"
         )
-        assert "2005-10-16" in machine.succeed(
-            "curl -u admin:admin -fs localhost:28981/api/documents/ | jq '.results | .[0] | .created'"
-        )
-        assert "2005-10-16" in machine.succeed(
-            "curl -u admin:admin -fs localhost:28981/api/documents/ | jq '.results | .[1] | .created'"
-        )
+        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']
   '';
 })
diff --git a/nixpkgs/nixos/tests/pass-secret-service.nix b/nixpkgs/nixos/tests/pass-secret-service.nix
new file mode 100644
index 000000000000..a85a508bfe16
--- /dev/null
+++ b/nixpkgs/nixos/tests/pass-secret-service.nix
@@ -0,0 +1,69 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "pass-secret-service";
+  meta.maintainers = with lib; [ aidalgol ];
+
+  nodes.machine = { nodes, pkgs, ... }:
+    {
+      imports = [ ./common/user-account.nix ];
+
+      services.passSecretService.enable = true;
+
+      environment.systemPackages = [
+        # Create a script that tries to make a request to the D-Bus secrets API.
+        (pkgs.writers.writePython3Bin "secrets-dbus-init"
+          {
+            libraries = [ pkgs.python3Packages.secretstorage ];
+          } ''
+          import secretstorage
+          print("Initializing dbus connection...")
+          connection = secretstorage.dbus_init()
+          print("Requesting default collection...")
+          collection = secretstorage.get_default_collection(connection)
+          print("Done!  dbus-org.freedesktop.secrets should now be active.")
+        '')
+        pkgs.pass
+      ];
+
+      programs.gnupg = {
+        agent.enable = true;
+        agent.pinentryFlavor = "tty";
+        dirmngr.enable = true;
+      };
+    };
+
+  # Some of the commands are run via a virtual console because they need to be
+  # run under a real login session, with D-Bus running in the environment.
+  testScript = { nodes, ... }:
+    let
+      user = nodes.machine.config.users.users.alice;
+      gpg-uid = "alice@example.net";
+      gpg-pw = "foobar9000";
+      ready-file = "/tmp/secrets-dbus-init.done";
+    in
+    ''
+      # Initialise the pass(1) storage.
+      machine.succeed("""
+        sudo -u alice gpg --pinentry-mode loopback --batch --passphrase ${gpg-pw} \
+        --quick-gen-key ${gpg-uid} \
+      """)
+      machine.succeed("sudo -u alice pass init ${gpg-uid}")
+
+      with subtest("Service is not running on login"):
+          machine.wait_until_tty_matches("1", "login: ")
+          machine.send_chars("alice\n")
+          machine.wait_until_tty_matches("1", "login: alice")
+          machine.wait_until_succeeds("pgrep login")
+          machine.wait_until_tty_matches("1", "Password: ")
+          machine.send_chars("${user.password}\n")
+          machine.wait_until_succeeds("pgrep -u alice bash")
+
+          _, output = machine.systemctl("status dbus-org.freedesktop.secrets --no-pager", "alice")
+          assert "Active: inactive (dead)" in output
+
+      with subtest("Service starts after a client tries to talk to the D-Bus API"):
+          machine.send_chars("secrets-dbus-init; touch ${ready-file}\n")
+          machine.wait_for_file("${ready-file}")
+          _, output = machine.systemctl("status dbus-org.freedesktop.secrets --no-pager", "alice")
+          assert "Active: active (running)" in output
+    '';
+})
diff --git a/nixpkgs/nixos/tests/patroni.nix b/nixpkgs/nixos/tests/patroni.nix
new file mode 100644
index 000000000000..f512fddcdbdd
--- /dev/null
+++ b/nixpkgs/nixos/tests/patroni.nix
@@ -0,0 +1,204 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+
+  let
+    nodesIps = [
+      "192.168.1.1"
+      "192.168.1.2"
+      "192.168.1.3"
+    ];
+
+    createNode = index: { pkgs, ... }:
+      let
+        ip = builtins.elemAt nodesIps index; # since we already use IPs to identify servers
+      in
+      {
+        networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = ip; prefixLength = 16; }
+        ];
+
+        networking.firewall.allowedTCPPorts = [ 5432 8008 5010 ];
+
+        environment.systemPackages = [ pkgs.jq ];
+
+        services.patroni = {
+
+          enable = true;
+
+          postgresqlPackage = pkgs.postgresql_14.withPackages (p: [ p.pg_safeupdate ]);
+
+          scope = "cluster1";
+          name = "node${toString(index + 1)}";
+          nodeIp = ip;
+          otherNodesIps = builtins.filter (h: h != ip) nodesIps;
+          softwareWatchdog = true;
+
+          settings = {
+            bootstrap = {
+              dcs = {
+                ttl = 30;
+                loop_wait = 10;
+                retry_timeout = 10;
+                maximum_lag_on_failover = 1048576;
+              };
+              initdb = [
+                { encoding = "UTF8"; }
+                "data-checksums"
+              ];
+            };
+
+            postgresql = {
+              use_pg_rewind = true;
+              use_slots = true;
+              authentication = {
+                replication = {
+                  username = "replicator";
+                };
+                superuser = {
+                  username = "postgres";
+                };
+                rewind = {
+                  username = "rewind";
+                };
+              };
+              parameters = {
+                listen_addresses = "${ip}";
+                wal_level = "replica";
+                hot_standby_feedback = "on";
+                unix_socket_directories = "/tmp";
+              };
+              pg_hba = [
+                "host replication replicator 192.168.1.0/24 md5"
+                # Unsafe, do not use for anything other than tests
+                "host all all 0.0.0.0/0 trust"
+              ];
+            };
+
+            etcd3 = {
+              host = "192.168.1.4:2379";
+            };
+          };
+
+          environmentFiles = {
+            PATRONI_REPLICATION_PASSWORD = pkgs.writeText "replication-password" "postgres";
+            PATRONI_SUPERUSER_PASSWORD = pkgs.writeText "superuser-password" "postgres";
+            PATRONI_REWIND_PASSWORD = pkgs.writeText "rewind-password" "postgres";
+          };
+        };
+
+        # We always want to restart so the tests never hang
+        systemd.services.patroni.serviceConfig.StartLimitIntervalSec = 0;
+      };
+  in
+  {
+    name = "patroni";
+
+    nodes = {
+      node1 = createNode 0;
+      node2 = createNode 1;
+      node3 = createNode 2;
+
+      etcd = { pkgs, ... }: {
+
+        networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = "192.168.1.4"; prefixLength = 16; }
+        ];
+
+        services.etcd = {
+          enable = true;
+          listenClientUrls = [ "http://192.168.1.4:2379" ];
+        };
+
+        networking.firewall.allowedTCPPorts = [ 2379 ];
+      };
+
+      client = { pkgs, ... }: {
+        environment.systemPackages = [ pkgs.postgresql_14 ];
+
+        networking.interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = "192.168.2.1"; prefixLength = 16; }
+        ];
+
+        services.haproxy = {
+          enable = true;
+          config = ''
+            global
+                maxconn 100
+
+            defaults
+                log global
+                mode tcp
+                retries 2
+                timeout client 30m
+                timeout connect 4s
+                timeout server 30m
+                timeout check 5s
+
+            listen cluster1
+                bind 127.0.0.1:5432
+                option httpchk
+                http-check expect status 200
+                default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
+                ${builtins.concatStringsSep "\n" (map (ip: "server postgresql_${ip}_5432 ${ip}:5432 maxconn 100 check port 8008") nodesIps)}
+          '';
+        };
+      };
+    };
+
+
+
+    testScript = ''
+      nodes = [node1, node2, node3]
+
+      def wait_for_all_nodes_ready(expected_replicas=2):
+          booted_nodes = filter(lambda node: node.booted, nodes)
+          for node in booted_nodes:
+              print(node.succeed("patronictl list cluster1"))
+              node.wait_until_succeeds(f"[ $(patronictl list -f json cluster1 | jq 'length') == {expected_replicas + 1} ]")
+              node.wait_until_succeeds("[ $(patronictl list -f json cluster1 | jq 'map(select(.Role | test(\"^Leader$\"))) | map(select(.State | test(\"^running$\"))) | length') == 1 ]")
+              node.wait_until_succeeds(f"[ $(patronictl list -f json cluster1 | jq 'map(select(.Role | test(\"^Replica$\"))) | map(select(.State | test(\"^running$\"))) | length') == {expected_replicas} ]")
+              print(node.succeed("patronictl list cluster1"))
+          client.wait_until_succeeds("psql -h 127.0.0.1 -U postgres --command='select 1;'")
+
+      def run_dummy_queries():
+          client.succeed("psql -h 127.0.0.1 -U postgres --pset='pager=off' --tuples-only --command='insert into dummy(val) values (101);'")
+          client.succeed("test $(psql -h 127.0.0.1 -U postgres --pset='pager=off' --tuples-only --command='select val from dummy where val = 101;') -eq 101")
+          client.succeed("psql -h 127.0.0.1 -U postgres --pset='pager=off' --tuples-only --command='delete from dummy where val = 101;'")
+
+      start_all()
+
+      with subtest("should bootstrap a new patroni cluster"):
+          wait_for_all_nodes_ready()
+
+      with subtest("should be able to insert and select"):
+          client.succeed("psql -h 127.0.0.1 -U postgres --command='create table dummy as select * from generate_series(1, 100) as val;'")
+          client.succeed("test $(psql -h 127.0.0.1 -U postgres --pset='pager=off' --tuples-only --command='select count(distinct val) from dummy;') -eq 100")
+
+      with subtest("should restart after all nodes are crashed"):
+          for node in nodes:
+              node.crash()
+          for node in nodes:
+              node.start()
+          wait_for_all_nodes_ready()
+
+      with subtest("should be able to run queries while any one node is crashed"):
+          masterNodeName = node1.succeed("patronictl list -f json cluster1 | jq '.[] | select(.Role | test(\"^Leader$\")) | .Member' -r").strip()
+          masterNodeIndex = int(masterNodeName[len(masterNodeName)-1]) - 1
+
+          # Move master node at the end of the list to avoid multiple failovers (makes the test faster and more consistent)
+          nodes.append(nodes.pop(masterNodeIndex))
+
+          for node in nodes:
+              node.crash()
+              wait_for_all_nodes_ready(1)
+
+              # Execute some queries while a node is down.
+              run_dummy_queries()
+
+              # Restart crashed node.
+              node.start()
+              wait_for_all_nodes_ready()
+
+              # Execute some queries with the node back up.
+              run_dummy_queries()
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/pdns-recursor.nix b/nixpkgs/nixos/tests/pdns-recursor.nix
index de1b60e0b1c7..14f1b7ea8a35 100644
--- a/nixpkgs/nixos/tests/pdns-recursor.nix
+++ b/nixpkgs/nixos/tests/pdns-recursor.nix
@@ -1,12 +1,15 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
-  name = "powerdns";
+  name = "powerdns-recursor";
 
   nodes.server = { ... }: {
     services.pdns-recursor.enable = true;
+    services.pdns-recursor.exportHosts= true;
+    networking.hosts."192.0.2.1" = [ "example.com" ];
   };
 
   testScript = ''
     server.wait_for_unit("pdns-recursor")
-    server.wait_for_open_port("53")
+    server.wait_for_open_port(53)
+    assert "192.0.2.1" in server.succeed("host example.com localhost")
   '';
 })
diff --git a/nixpkgs/nixos/tests/pgadmin4.nix b/nixpkgs/nixos/tests/pgadmin4.nix
index 658315d3ac0c..9f5ac3d8d922 100644
--- a/nixpkgs/nixos/tests/pgadmin4.nix
+++ b/nixpkgs/nixos/tests/pgadmin4.nix
@@ -1,52 +1,27 @@
-import ./make-test-python.nix ({ pkgs, lib, ... }:
+import ./make-test-python.nix ({ pkgs, lib, buildDeps ? [ ], pythonEnv ? [ ], ... }:
+
+  /*
+  This test suite replaces the typical pytestCheckHook function in python
+  packages. Pgadmin4 test suite needs a running and configured postgresql
+  server. This is why this test exists.
+
+  To not repeat all the python dependencies needed, this test is called directly
+  from the pgadmin4 derivation, which also passes the currently
+  used propagatedBuildInputs and any python overrides.
+
+  Unfortunately, there doesn't seem to be an easy way to otherwise include
+  the needed packages here.
+
+  Due the the needed parameters a direct call to "nixosTests.pgadmin4" fails
+  and needs to be called as "pgadmin4.tests"
+
+  */
 
   let
     pgadmin4SrcDir = "/pgadmin";
     pgadmin4Dir = "/var/lib/pgadmin";
     pgadmin4LogDir = "/var/log/pgadmin";
 
-    python-with-needed-packages = pkgs.python3.withPackages (ps: with ps; [
-      selenium
-      testtools
-      testscenarios
-      flask
-      flask-babelex
-      flask-babel
-      flask-gravatar
-      flask_login
-      flask_mail
-      flask_migrate
-      flask_sqlalchemy
-      flask_wtf
-      flask-compress
-      passlib
-      pytz
-      simplejson
-      six
-      sqlparse
-      wtforms
-      flask-paranoid
-      psutil
-      psycopg2
-      python-dateutil
-      sqlalchemy
-      itsdangerous
-      flask-security-too
-      bcrypt
-      cryptography
-      sshtunnel
-      ldap3
-      gssapi
-      flask-socketio
-      eventlet
-      httpagentparser
-      user-agents
-      wheel
-      authlib
-      qrcode
-      pillow
-      pyotp
-    ]);
   in
   {
     name = "pgadmin4";
@@ -54,12 +29,27 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
 
     nodes.machine = { pkgs, ... }: {
       imports = [ ./common/x11.nix ];
+      # needed because pgadmin 6.8 will fail, if those dependencies get updated
+      nixpkgs.overlays = [
+        (self: super: {
+          pythonPackages = pythonEnv;
+        })
+      ];
+
       environment.systemPackages = with pkgs; [
         pgadmin4
         postgresql
-        python-with-needed-packages
         chromedriver
         chromium
+        # include the same packages as in pgadmin minus speaklater3
+        (python3.withPackages
+          (ps: buildDeps ++
+            [
+              # test suite package requirements
+              pythonPackages.testscenarios
+              pythonPackages.selenium
+            ])
+        )
       ];
       services.postgresql = {
         enable = true;
@@ -117,11 +107,14 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       )
 
       # don't bother to test LDAP authentification
+      # exclude resql test due to recent postgres 14.4 update
+      # see bugreport here https://redmine.postgresql.org/issues/7527
       with subtest("run browser test"):
           machine.succeed(
                'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \
-               && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg browser --exclude \
-               browser.tests.test_ldap_login.LDAPLoginTestCase,browser.tests.test_ldap_login'
+               && python regression/runtests.py \
+               --pkg browser \
+               --exclude browser.tests.test_ldap_login.LDAPLoginTestCase,browser.tests.test_ldap_login,resql'
           )
 
       # fontconfig is necessary for chromium to run
@@ -130,13 +123,14 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
           machine.succeed(
               'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \
                && export FONTCONFIG_FILE=${pkgs.makeFontsConf { fontDirectories = [];}} \
-               && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg feature_tests'
+               && python regression/runtests.py --pkg feature_tests'
           )
 
-      with subtest("run resql test"):
-          machine.succeed(
-               'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \
-               && ${python-with-needed-packages.interpreter} regression/runtests.py --pkg resql'
-          )
+      # reactivate this test again, when the postgres 14.4 test has been fixed
+      # with subtest("run resql test"):
+      #    machine.succeed(
+      #         'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \
+      #         && python regression/runtests.py --pkg resql'
+      #    )
     '';
   })
diff --git a/nixpkgs/nixos/tests/php/fpm.nix b/nixpkgs/nixos/tests/php/fpm.nix
index 718a635a6c7c..64b61a377e28 100644
--- a/nixpkgs/nixos/tests/php/fpm.nix
+++ b/nixpkgs/nixos/tests/php/fpm.nix
@@ -2,7 +2,7 @@ import ../make-test-python.nix ({ pkgs, lib, php, ... }: {
   name = "php-${php.version}-fpm-nginx-test";
   meta.maintainers = lib.teams.php.members;
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     environment.systemPackages = [ php ];
 
     services.nginx = {
diff --git a/nixpkgs/nixos/tests/php/httpd.nix b/nixpkgs/nixos/tests/php/httpd.nix
index 36d90e72d7d1..b6dfbeeaed52 100644
--- a/nixpkgs/nixos/tests/php/httpd.nix
+++ b/nixpkgs/nixos/tests/php/httpd.nix
@@ -2,7 +2,7 @@ import ../make-test-python.nix ({ pkgs, lib, php, ... }: {
   name = "php-${php.version}-httpd-test";
   meta.maintainers = lib.teams.php.members;
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     services.httpd = {
       enable = true;
       adminAddr = "admin@phpfpm";
diff --git a/nixpkgs/nixos/tests/php/pcre.nix b/nixpkgs/nixos/tests/php/pcre.nix
index 917184b975ec..57407477f4b8 100644
--- a/nixpkgs/nixos/tests/php/pcre.nix
+++ b/nixpkgs/nixos/tests/php/pcre.nix
@@ -5,7 +5,7 @@ import ../make-test-python.nix ({ lib, php, ... }: {
   name = "php-${php.version}-httpd-pcre-jit-test";
   meta.maintainers = lib.teams.php.members;
 
-  machine = { lib, pkgs, ... }: {
+  nodes.machine = { lib, pkgs, ... }: {
     time.timeZone = "UTC";
     services.httpd = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/pict-rs.nix b/nixpkgs/nixos/tests/pict-rs.nix
index 432fd6a50ccd..4315e9fb6e90 100644
--- a/nixpkgs/nixos/tests/pict-rs.nix
+++ b/nixpkgs/nixos/tests/pict-rs.nix
@@ -3,7 +3,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
     name = "pict-rs";
     meta.maintainers = with lib.maintainers; [ happysalada ];
 
-    machine = { ... }: {
+    nodes.machine = { ... }: {
       environment.systemPackages = with pkgs; [ curl jq ];
       services.pict-rs.enable = true;
     };
@@ -12,6 +12,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       start_all()
 
       machine.wait_for_unit("pict-rs")
-      machine.wait_for_open_port("8080")
+      machine.wait_for_open_port(8080)
     '';
   })
diff --git a/nixpkgs/nixos/tests/plasma5-systemd-start.nix b/nixpkgs/nixos/tests/plasma5-systemd-start.nix
index 72de19af70ce..f584c1ec137a 100644
--- a/nixpkgs/nixos/tests/plasma5-systemd-start.nix
+++ b/nixpkgs/nixos/tests/plasma5-systemd-start.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ oxalica ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/plasma5.nix b/nixpkgs/nixos/tests/plasma5.nix
index 5c7ea602f79e..b3836cf641d4 100644
--- a/nixpkgs/nixos/tests/plasma5.nix
+++ b/nixpkgs/nixos/tests/plasma5.nix
@@ -6,14 +6,17 @@ import ./make-test-python.nix ({ pkgs, ...} :
     maintainers = [ ttuegel ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.displayManager.sddm.enable = true;
     services.xserver.displayManager.defaultSession = "plasma";
-    services.xserver.desktopManager.plasma5.enable = true;
+    services.xserver.desktopManager.plasma5 = {
+      enable = true;
+      excludePackages = [ pkgs.plasma5Packages.elisa ];
+    };
     services.xserver.displayManager.autoLogin = {
       enable = true;
       user = "alice";
@@ -40,6 +43,9 @@ import ./make-test-python.nix ({ pkgs, ...} :
     with subtest("Check that logging in has given the user ownership of devices"):
         machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")
 
+    with subtest("Ensure Elisa is not installed"):
+        machine.fail("which elisa")
+
     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/plausible.nix b/nixpkgs/nixos/tests/plausible.nix
index 58c1dd5cf4a8..ab91e08beb34 100644
--- a/nixpkgs/nixos/tests/plausible.nix
+++ b/nixpkgs/nixos/tests/plausible.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = [ ma27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.memorySize = 4096;
     services.plausible = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/pleroma.nix b/nixpkgs/nixos/tests/pleroma.nix
index 90a9a2511044..8998716243a2 100644
--- a/nixpkgs/nixos/tests/pleroma.nix
+++ b/nixpkgs/nixos/tests/pleroma.nix
@@ -158,7 +158,9 @@ import ./make-test-python.nix ({ pkgs, ... }:
 
     # Waiting for pleroma to be up.
     timeout 5m bash -c 'while [[ "$(curl -s -o /dev/null -w '%{http_code}' https://pleroma.nixos.test/api/v1/instance)" != "200" ]]; do sleep 2; done'
-    pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y
+    # Toremove the RELEASE_COOKIE bit when https://github.com/NixOS/nixpkgs/issues/166229 gets fixed.
+    RELEASE_COOKIE="/var/lib/pleroma/.cookie" \
+      pleroma_ctl user new jamy jamy@nixos.test --password 'jamy-password' --moderator --admin -y
   '';
 
   tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
diff --git a/nixpkgs/nixos/tests/plikd.nix b/nixpkgs/nixos/tests/plikd.nix
index 8fec93c01f6b..97c254a5f7b0 100644
--- a/nixpkgs/nixos/tests/plikd.nix
+++ b/nixpkgs/nixos/tests/plikd.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ lib, ... }: {
     maintainers = [ freezeboy ];
   };
 
-  machine = { pkgs, ... }: let
+  nodes.machine = { pkgs, ... }: let
   in {
     services.plikd.enable = true;
     environment.systemPackages = [ pkgs.plik ];
@@ -15,7 +15,7 @@ import ./make-test-python.nix ({ lib, ... }: {
     machine.wait_for_unit("plikd")
 
     # Network test
-    machine.wait_for_open_port("8080")
+    machine.wait_for_open_port(8080)
     machine.succeed("curl --fail -v http://localhost:8080")
 
     # Application test
diff --git a/nixpkgs/nixos/tests/plotinus.nix b/nixpkgs/nixos/tests/plotinus.nix
index af38b41813b7..b6ebab9b0198 100644
--- a/nixpkgs/nixos/tests/plotinus.nix
+++ b/nixpkgs/nixos/tests/plotinus.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = pkgs.plotinus.meta.maintainers;
   };
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
 
     { imports = [ ./common/x11.nix ];
diff --git a/nixpkgs/nixos/tests/podgrab.nix b/nixpkgs/nixos/tests/podgrab.nix
index e927e25fea56..dc9dfebaf49b 100644
--- a/nixpkgs/nixos/tests/podgrab.nix
+++ b/nixpkgs/nixos/tests/podgrab.nix
@@ -22,11 +22,11 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     start_all()
 
     default.wait_for_unit("podgrab")
-    default.wait_for_open_port("${toString defaultPort}")
+    default.wait_for_open_port(${toString defaultPort})
     default.succeed("curl --fail http://localhost:${toString defaultPort}")
 
     customized.wait_for_unit("podgrab")
-    customized.wait_for_open_port("${toString customPort}")
+    customized.wait_for_open_port(${toString customPort})
     customized.succeed("curl --fail http://localhost:${toString customPort}")
   '';
 
diff --git a/nixpkgs/nixos/tests/polaris.nix b/nixpkgs/nixos/tests/polaris.nix
new file mode 100644
index 000000000000..fb2e67f075aa
--- /dev/null
+++ b/nixpkgs/nixos/tests/polaris.nix
@@ -0,0 +1,31 @@
+import ./make-test-python.nix ({ lib, ... }:
+
+with lib;
+
+{
+  name = "polaris";
+  meta.maintainers = with maintainers; [ pbsds ];
+
+  nodes.machine =
+    { pkgs, ... }: {
+      environment.systemPackages = [ pkgs.jq ];
+      services.polaris = {
+        enable = true;
+        port = 5050;
+        settings.users = [
+          {
+            name = "test_user";
+            password = "very_secret_password";
+            admin = true;
+          }
+        ];
+      };
+    };
+
+  testScript = ''
+    machine.wait_for_unit("polaris.service")
+    machine.wait_for_open_port(5050)
+    machine.succeed("curl http://localhost:5050/api/version")
+    machine.succeed("curl -X GET http://localhost:5050/api/initial_setup -H  'accept: application/json' | jq -e '.has_any_users == true'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/postfix-raise-smtpd-tls-security-level.nix b/nixpkgs/nixos/tests/postfix-raise-smtpd-tls-security-level.nix
index 5fad1fed75b2..2a6c85a3a920 100644
--- a/nixpkgs/nixos/tests/postfix-raise-smtpd-tls-security-level.nix
+++ b/nixpkgs/nixos/tests/postfix-raise-smtpd-tls-security-level.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "postfix";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ common/user-account.nix ];
     services.postfix = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/postfix.nix b/nixpkgs/nixos/tests/postfix.nix
index 6d22b4edba0a..1dbe6a4c5193 100644
--- a/nixpkgs/nixos/tests/postfix.nix
+++ b/nixpkgs/nixos/tests/postfix.nix
@@ -5,7 +5,7 @@ in
 import ./make-test-python.nix {
   name = "postfix";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ common/user-account.nix ];
     services.postfix = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/postgresql-wal-receiver.nix b/nixpkgs/nixos/tests/postgresql-wal-receiver.nix
index 0e8b3bfd6c34..ae2708546f5d 100644
--- a/nixpkgs/nixos/tests/postgresql-wal-receiver.nix
+++ b/nixpkgs/nixos/tests/postgresql-wal-receiver.nix
@@ -31,7 +31,7 @@ let
         name = "postgresql-wal-receiver-${postgresqlPackage}";
         meta.maintainers = with lib.maintainers; [ pacien ];
 
-        machine = { ... }: {
+        nodes.machine = { ... }: {
           services.postgresql = {
             package = pkg;
             enable = true;
diff --git a/nixpkgs/nixos/tests/postgresql.nix b/nixpkgs/nixos/tests/postgresql.nix
index 2b487c20a625..7864f5d6ff32 100644
--- a/nixpkgs/nixos/tests/postgresql.nix
+++ b/nixpkgs/nixos/tests/postgresql.nix
@@ -27,7 +27,7 @@ let
       maintainers = [ zagy ];
     };
 
-    machine = {...}:
+    nodes.machine = {...}:
       {
         services.postgresql = {
           enable = true;
diff --git a/nixpkgs/nixos/tests/power-profiles-daemon.nix b/nixpkgs/nixos/tests/power-profiles-daemon.nix
index e073677bee9d..278e94711830 100644
--- a/nixpkgs/nixos/tests/power-profiles-daemon.nix
+++ b/nixpkgs/nixos/tests/power-profiles-daemon.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
   meta = with pkgs.lib.maintainers; {
     maintainers = [ mvnetbiz ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.power-profiles-daemon.enable = true;
     environment.systemPackages = [ pkgs.glib ];
   };
diff --git a/nixpkgs/nixos/tests/powerdns.nix b/nixpkgs/nixos/tests/powerdns.nix
index 70060bad87b6..d3708d25f0fb 100644
--- a/nixpkgs/nixos/tests/powerdns.nix
+++ b/nixpkgs/nixos/tests/powerdns.nix
@@ -47,7 +47,9 @@ 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")
-        conf = re.search("(--config-dir=[^ ]+)", unit).group(1)
+        match = re.search("(--config-dir=[^ ]+)", unit)
+        assert(match is not None)
+        conf = match.group(1)
         pdnsutil = "sudo -u pdns pdnsutil " + conf
         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/predictable-interface-names.nix b/nixpkgs/nixos/tests/predictable-interface-names.nix
index c0b472638a14..08773120bc12 100644
--- a/nixpkgs/nixos/tests/predictable-interface-names.nix
+++ b/nixpkgs/nixos/tests/predictable-interface-names.nix
@@ -16,7 +16,7 @@ in pkgs.lib.listToAttrs (builtins.map ({ predictable, withNetworkd }: {
     name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}";
     meta = {};
 
-    machine = { lib, ... }: {
+    nodes.machine = { lib, ... }: {
       networking.usePredictableInterfaceNames = lib.mkForce predictable;
       networking.useNetworkd = withNetworkd;
       networking.dhcpcd.enable = !withNetworkd;
diff --git a/nixpkgs/nixos/tests/privacyidea.nix b/nixpkgs/nixos/tests/privacyidea.nix
index c1141465ec24..401ad72c37b7 100644
--- a/nixpkgs/nixos/tests/privacyidea.nix
+++ b/nixpkgs/nixos/tests/privacyidea.nix
@@ -3,10 +3,10 @@
 import ./make-test-python.nix ({ pkgs, ...} : rec {
   name = "privacyidea";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ fpletz ];
+    maintainers = [ ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     virtualisation.cores = 2;
 
     services.privacyidea = {
diff --git a/nixpkgs/nixos/tests/privoxy.nix b/nixpkgs/nixos/tests/privoxy.nix
index d16cc498691f..2d95c4522a01 100644
--- a/nixpkgs/nixos/tests/privoxy.nix
+++ b/nixpkgs/nixos/tests/privoxy.nix
@@ -33,7 +33,7 @@ in
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.nginx.enable = true;
     services.nginx.virtualHosts."example.com" = {
       addSSL = true;
@@ -81,23 +81,23 @@ in
     ''
       with subtest("Privoxy is running"):
           machine.wait_for_unit("privoxy")
-          machine.wait_for_open_port("8118")
+          machine.wait_for_open_port(8118)
           machine.succeed("curl -f http://config.privoxy.org")
 
       with subtest("Privoxy can filter http requests"):
-          machine.wait_for_open_port("80")
+          machine.wait_for_open_port(80)
           assert "great day" in machine.succeed(
               "curl -sfL http://example.com/how-are-you? | tee /dev/stderr"
           )
 
       with subtest("Privoxy can filter https requests"):
-          machine.wait_for_open_port("443")
+          machine.wait_for_open_port(443)
           assert "great day" in machine.succeed(
               "curl -sfL https://example.com/how-are-you? | tee /dev/stderr"
           )
 
       with subtest("Blocks are working"):
-          machine.wait_for_open_port("443")
+          machine.wait_for_open_port(443)
           machine.fail("curl -f https://example.com/ads 1>&2")
           machine.succeed("curl -f https://example.com/PRIVOXY-FORCE/ads 1>&2")
 
diff --git a/nixpkgs/nixos/tests/prometheus-exporters.nix b/nixpkgs/nixos/tests/prometheus-exporters.nix
index ce3b3fbf3bf3..4fdff7dbdab8 100644
--- a/nixpkgs/nixos/tests/prometheus-exporters.nix
+++ b/nixpkgs/nixos/tests/prometheus-exporters.nix
@@ -35,7 +35,7 @@ let
     *      };
     *      exporterTest = ''
     *        wait_for_unit("prometheus-<exporterName>-exporter.service")
-    *        wait_for_open_port("1234")
+    *        wait_for_open_port(1234)
     *        succeed("curl -sSf 'localhost:1234/metrics'")
     *      '';
     *    };
@@ -52,7 +52,7 @@ let
     *    testScript = ''
     *      <exporterName>.start()
     *      <exporterName>.wait_for_unit("prometheus-<exporterName>-exporter.service")
-    *      <exporterName>.wait_for_open_port("1234")
+    *      <exporterName>.wait_for_open_port(1234)
     *      <exporterName>.succeed("curl -sSf 'localhost:1234/metrics'")
     *      <exporterName>.shutdown()
     *    '';
@@ -557,10 +557,12 @@ let
         systemd.services.prometheus-mail-exporter = {
           after = [ "postfix.service" ];
           requires = [ "postfix.service" ];
-          preStart = ''
-            mkdir -p -m 0700 mail-exporter/new
-          '';
           serviceConfig = {
+            ExecStartPre = [
+              "${pkgs.writeShellScript "create-maildir" ''
+                mkdir -p -m 0700 mail-exporter/new
+              ''}"
+            ];
             ProtectHome = true;
             ReadOnlyPaths = "/";
             ReadWritePaths = "/var/spool/mail";
@@ -1061,7 +1063,7 @@ let
       };
       exporterTest = ''
         wait_for_unit("prometheus-smartctl-exporter.service")
-        wait_for_open_port("9633")
+        wait_for_open_port(9633)
         wait_until_succeeds(
           "curl -sSf 'localhost:9633/metrics'"
         )
@@ -1179,21 +1181,21 @@ let
         enable = true;
 
         extraFlags = [
-          "--collector.enable-restart-count"
+          "--systemd.collector.enable-restart-count"
         ];
       };
       metricProvider = { };
       exporterTest = ''
         wait_for_unit("prometheus-systemd-exporter.service")
         wait_for_open_port(9558)
-        succeed(
+        wait_until_succeeds(
             "curl -sSf localhost:9558/metrics | grep '{}'".format(
                 'systemd_unit_state{name="basic.target",state="active",type="target"} 1'
             )
         )
         succeed(
             "curl -sSf localhost:9558/metrics | grep '{}'".format(
-                'systemd_service_restart_total{state="prometheus-systemd-exporter.service"} 0'
+                'systemd_service_restart_total{name="prometheus-systemd-exporter.service"} 0'
             )
         )
       '';
@@ -1335,7 +1337,7 @@ mapAttrs
       '';
 
       meta = with maintainers; {
-        maintainers = [ willibutz elseym ];
+        maintainers = [ willibutz ];
       };
     }
   )))
diff --git a/nixpkgs/nixos/tests/prowlarr.nix b/nixpkgs/nixos/tests/prowlarr.nix
index 4cbca107568f..144cbd5fc95d 100644
--- a/nixpkgs/nixos/tests/prowlarr.nix
+++ b/nixpkgs/nixos/tests/prowlarr.nix
@@ -12,7 +12,7 @@ with lib;
 
   testScript = ''
     machine.wait_for_unit("prowlarr.service")
-    machine.wait_for_open_port("9696")
+    machine.wait_for_open_port(9696)
     machine.succeed("curl --fail http://localhost:9696/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/pt2-clone.nix b/nixpkgs/nixos/tests/pt2-clone.nix
index 364920c39871..ea4329c4a980 100644
--- a/nixpkgs/nixos/tests/pt2-clone.nix
+++ b/nixpkgs/nixos/tests/pt2-clone.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/public-inbox.nix b/nixpkgs/nixos/tests/public-inbox.nix
new file mode 100644
index 000000000000..7de40400fcbf
--- /dev/null
+++ b/nixpkgs/nixos/tests/public-inbox.nix
@@ -0,0 +1,227 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+let
+  orga = "example";
+  domain = "${orga}.localdomain";
+
+  tls-cert = pkgs.runCommand "selfSignedCert" { buildInputs = [ pkgs.openssl ]; } ''
+    openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -days 36500 \
+      -subj '/CN=machine.${domain}'
+    install -D -t $out key.pem cert.pem
+  '';
+in
+{
+  name = "public-inbox";
+
+  meta.maintainers = with pkgs.lib.maintainers; [ julm ];
+
+  machine = { config, pkgs, nodes, ... }: let
+    inherit (config.services) gitolite public-inbox;
+    # Git repositories paths in Gitolite.
+    # Only their baseNameOf is used for configuring public-inbox.
+    repositories = [
+      "user/repo1"
+      "user/repo2"
+    ];
+  in
+  {
+    virtualisation.diskSize = 1 * 1024;
+    virtualisation.memorySize = 1 * 1024;
+    networking.domain = domain;
+
+    security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ];
+    # If using security.acme:
+    #security.acme.certs."${domain}".postRun = ''
+    #  systemctl try-restart public-inbox-nntpd public-inbox-imapd
+    #'';
+
+    services.public-inbox = {
+      enable = true;
+      postfix.enable = true;
+      openFirewall = true;
+      settings.publicinbox = {
+        css = [ "href=https://machine.${domain}/style/light.css" ];
+        nntpserver = [ "nntps://machine.${domain}" ];
+        wwwlisting = "match=domain";
+      };
+      mda = {
+        enable = true;
+        args = [ "--no-precheck" ]; # Allow Bcc:
+      };
+      http = {
+        enable = true;
+        port = "/run/public-inbox-http.sock";
+        #port = 8080;
+        args = ["-W0"];
+        mounts = [
+          "https://machine.${domain}/inbox"
+        ];
+      };
+      nntp = {
+        enable = true;
+        #port = 563;
+        args = ["-W0"];
+        cert = "${tls-cert}/cert.pem";
+        key = "${tls-cert}/key.pem";
+      };
+      imap = {
+        enable = true;
+        #port = 993;
+        args = ["-W0"];
+        cert = "${tls-cert}/cert.pem";
+        key = "${tls-cert}/key.pem";
+      };
+      inboxes = lib.recursiveUpdate (lib.genAttrs (map baseNameOf repositories) (repo: {
+        address = [
+          # Routed to the "public-inbox:" transport in services.postfix.transport
+          "${repo}@${domain}"
+        ];
+        description = ''
+          ${repo}@${domain} :
+          discussions about ${repo}.
+        '';
+        url = "https://machine.${domain}/inbox/${repo}";
+        newsgroup = "inbox.comp.${orga}.${repo}";
+        coderepo = [ repo ];
+      }))
+      {
+        repo2 = {
+          hide = [
+            "imap" # FIXME: doesn't work for IMAP as of public-inbox 1.6.1
+            "manifest"
+            "www"
+          ];
+        };
+      };
+      settings.coderepo = lib.listToAttrs (map (path: lib.nameValuePair (baseNameOf path) {
+        dir = "/var/lib/gitolite/repositories/${path}.git";
+        cgitUrl = "https://git.${domain}/${path}.git";
+      }) repositories);
+    };
+
+    # Use gitolite to store Git repositories listed in coderepo entries
+    services.gitolite = {
+      enable = true;
+      adminPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmoTOQnGqX+//us5oye8UuE+tQBx9QEM7PN13jrwgqY root@localhost";
+    };
+    systemd.services.public-inbox-httpd = {
+      serviceConfig.SupplementaryGroups = [ gitolite.group ];
+    };
+
+    # Use nginx as a reverse proxy for public-inbox-httpd
+    services.nginx = {
+      enable = true;
+      recommendedGzipSettings = true;
+      recommendedOptimisation = true;
+      recommendedTlsSettings = true;
+      recommendedProxySettings = true;
+      virtualHosts."machine.${domain}" = {
+        forceSSL = true;
+        sslCertificate = "${tls-cert}/cert.pem";
+        sslCertificateKey = "${tls-cert}/key.pem";
+        locations."/".return = "302 /inbox";
+        locations."= /inbox".return = "302 /inbox/";
+        locations."/inbox".proxyPass = "http://unix:${public-inbox.http.port}:/inbox";
+        # If using TCP instead of a Unix socket:
+        #locations."/inbox".proxyPass = "http://127.0.0.1:${toString public-inbox.http.port}/inbox";
+        # Referred to by settings.publicinbox.css
+        # See http://public-inbox.org/meta/_/text/color/
+        locations."= /style/light.css".alias = pkgs.writeText "light.css" ''
+          * { background:#fff; color:#000 }
+
+          a { color:#00f; text-decoration:none }
+          a:visited { color:#808 }
+
+          *.q { color:#008 }
+
+          *.add { color:#060 }
+          *.del {color:#900 }
+          *.head { color:#000 }
+          *.hunk { color:#960 }
+
+          .hl.num { color:#f30 } /* number */
+          .hl.esc { color:#f0f } /* escape character */
+          .hl.str { color:#f30 } /* string */
+          .hl.ppc { color:#c3c } /* preprocessor */
+          .hl.pps { color:#f30 } /* preprocessor string */
+          .hl.slc { color:#099 } /* single-line comment */
+          .hl.com { color:#099 } /* multi-line comment */
+          /* .hl.opt { color:#ccc } */ /* operator */
+          /* .hl.ipl { color:#ccc } */ /* interpolation */
+
+          /* keyword groups kw[a-z] */
+          .hl.kwa { color:#f90 }
+          .hl.kwb { color:#060 }
+          .hl.kwc { color:#f90 }
+          /* .hl.kwd { color:#ccc } */
+        '';
+      };
+    };
+
+    services.postfix = {
+      enable = true;
+      setSendmail = true;
+      #sslCert = "${tls-cert}/cert.pem";
+      #sslKey = "${tls-cert}/key.pem";
+      recipientDelimiter = "+";
+    };
+
+    environment.systemPackages = [
+      pkgs.mailutils
+      pkgs.openssl
+    ];
+
+  };
+
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("public-inbox-init.service")
+
+    # Very basic check that Gitolite can work;
+    # Gitolite is not needed for the rest of this testScript
+    machine.wait_for_unit("gitolite-init.service")
+
+    # List inboxes through public-inbox-httpd
+    machine.wait_for_unit("nginx.service")
+    machine.succeed("curl -L https://machine.${domain} | grep repo1@${domain}")
+    # The repo2 inbox is hidden
+    machine.fail("curl -L https://machine.${domain} | grep repo2@${domain}")
+    machine.wait_for_unit("public-inbox-httpd.service")
+
+    # Send a mail and read it through public-inbox-httpd
+    # Must work too when using a recipientDelimiter.
+    machine.wait_for_unit("postfix.service")
+    machine.succeed("mail -t <${pkgs.writeText "mail" ''
+      Subject: Testing mail
+      From: root@localhost
+      To: repo1+extension@${domain}
+      Message-ID: <repo1@root-1>
+      Content-Type: text/plain; charset=utf-8
+      Content-Disposition: inline
+
+      This is a testing mail.
+    ''}")
+    machine.sleep(5)
+    machine.succeed("curl -L 'https://machine.${domain}/inbox/repo1/repo1@root-1/T/#u' | grep 'This is a testing mail.'")
+
+    # Read a mail through public-inbox-imapd
+    machine.wait_for_open_port(993)
+    machine.wait_for_unit("public-inbox-imapd.service")
+    machine.succeed("openssl s_client -ign_eof -crlf -connect machine.${domain}:993 <${pkgs.writeText "imap-commands" ''
+      tag login anonymous@${domain} anonymous
+      tag SELECT INBOX.comp.${orga}.repo1.0
+      tag FETCH 1 (BODY[HEADER])
+      tag LOGOUT
+    ''} | grep '^Message-ID: <repo1@root-1>'")
+
+    # TODO: Read a mail through public-inbox-nntpd
+    #machine.wait_for_open_port(563)
+    #machine.wait_for_unit("public-inbox-nntpd.service")
+
+    # Delete a mail.
+    # Note that the use of an extension not listed in the addresses
+    # require to use --all
+    machine.succeed("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/raw | sudo -u public-inbox public-inbox-learn rm --all")
+    machine.fail("curl -L https://machine.example.localdomain/inbox/repo1/repo1@root-1/T/#u | grep 'This is a testing mail.'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/pulseaudio.nix b/nixpkgs/nixos/tests/pulseaudio.nix
index 4e2ce679acd7..cfdc61bc6c2b 100644
--- a/nixpkgs/nixos/tests/pulseaudio.nix
+++ b/nixpkgs/nixos/tests/pulseaudio.nix
@@ -27,7 +27,7 @@ let
           maintainers = [ synthetica ] ++ pkgs.pulseaudio.meta.maintainers;
         };
 
-        machine = { ... }:
+        nodes.machine = { ... }:
 
           {
             imports = [ ./common/wayland-cage.nix ];
diff --git a/nixpkgs/nixos/tests/pykms.nix b/nixpkgs/nixos/tests/pykms.nix
new file mode 100644
index 000000000000..14d776a2f113
--- /dev/null
+++ b/nixpkgs/nixos/tests/pykms.nix
@@ -0,0 +1,14 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+  {
+    name = "pykms-test";
+    meta.maintainers = with pkgs.lib.maintainers; [ zopieux ];
+
+    nodes.machine = { config, lib, pkgs, ... }: {
+      services.pykms.enable = true;
+    };
+
+    testScript = ''
+      machine.wait_for_unit("pykms.service")
+      machine.succeed("${pkgs.pykms}/bin/client")
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/qboot.nix b/nixpkgs/nixos/tests/qboot.nix
index 12aef6decfae..29d999be58e5 100644
--- a/nixpkgs/nixos/tests/qboot.nix
+++ b/nixpkgs/nixos/tests/qboot.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ...} : {
   name = "qboot";
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     virtualisation.bios = pkgs.qboot;
   };
 
diff --git a/nixpkgs/nixos/tests/rabbitmq.nix b/nixpkgs/nixos/tests/rabbitmq.nix
index 03f1fa46d29e..f8e8e61c47d2 100644
--- a/nixpkgs/nixos/tests/rabbitmq.nix
+++ b/nixpkgs/nixos/tests/rabbitmq.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ eelco offline ];
   };
 
-  machine = {
+  nodes.machine = {
     services.rabbitmq = {
       enable = true;
       managementPlugin.enable = true;
@@ -22,6 +22,6 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     machine.wait_until_succeeds(
         'su -s ${pkgs.runtimeShell} rabbitmq -c "rabbitmqctl status"'
     )
-    machine.wait_for_open_port("15672")
+    machine.wait_for_open_port(15672)
   '';
 })
diff --git a/nixpkgs/nixos/tests/radarr.nix b/nixpkgs/nixos/tests/radarr.nix
index ed90025ac420..85fd6572f061 100644
--- a/nixpkgs/nixos/tests/radarr.nix
+++ b/nixpkgs/nixos/tests/radarr.nix
@@ -12,7 +12,7 @@ with lib;
 
   testScript = ''
     machine.wait_for_unit("radarr.service")
-    machine.wait_for_open_port("7878")
+    machine.wait_for_open_port(7878)
     machine.succeed("curl --fail http://localhost:7878/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/radicale.nix b/nixpkgs/nixos/tests/radicale.nix
index 5101628a682c..66650dce4a00 100644
--- a/nixpkgs/nixos/tests/radicale.nix
+++ b/nixpkgs/nixos/tests/radicale.nix
@@ -11,7 +11,7 @@ in {
   name = "radicale3";
   meta.maintainers = with lib.maintainers; [ dotlambda ];
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.radicale = {
       enable = true;
       settings = {
diff --git a/nixpkgs/nixos/tests/rasdaemon.nix b/nixpkgs/nixos/tests/rasdaemon.nix
index e4bd8d96a8d5..7f30a3b81ab5 100644
--- a/nixpkgs/nixos/tests/rasdaemon.nix
+++ b/nixpkgs/nixos/tests/rasdaemon.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... } : {
     maintainers = [ evils ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
     hardware.rasdaemon = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/redis.nix b/nixpkgs/nixos/tests/redis.nix
index 7b70c239ad6e..abea1657f3ea 100644
--- a/nixpkgs/nixos/tests/redis.nix
+++ b/nixpkgs/nixos/tests/redis.nix
@@ -30,7 +30,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     machine.wait_for_unit("redis-test")
 
     # The unnamed Redis server still opens a port for backward-compatibility
-    machine.wait_for_open_port("6379")
+    machine.wait_for_open_port(6379)
 
     machine.wait_for_file("${redis.servers."".unixSocket}")
     machine.wait_for_file("${redis.servers."test".unixSocket}")
diff --git a/nixpkgs/nixos/tests/redmine.nix b/nixpkgs/nixos/tests/redmine.nix
index 3866a1f528c0..621b3e6a36ee 100644
--- a/nixpkgs/nixos/tests/redmine.nix
+++ b/nixpkgs/nixos/tests/redmine.nix
@@ -9,7 +9,7 @@ with pkgs.lib;
 let
   redmineTest = { name, type }: makeTest {
     name = "redmine-${name}";
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       services.redmine = {
         enable = true;
         package = pkgs.redmine;
diff --git a/nixpkgs/nixos/tests/restart-by-activation-script.nix b/nixpkgs/nixos/tests/restart-by-activation-script.nix
index 0eec292ea9e2..0ac079e0101e 100644
--- a/nixpkgs/nixos/tests/restart-by-activation-script.nix
+++ b/nixpkgs/nixos/tests/restart-by-activation-script.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ das_j ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     systemd.services.restart-me = {
diff --git a/nixpkgs/nixos/tests/restic.nix b/nixpkgs/nixos/tests/restic.nix
index 16979eab8217..75fffe9d9a84 100644
--- a/nixpkgs/nixos/tests/restic.nix
+++ b/nixpkgs/nixos/tests/restic.nix
@@ -1,96 +1,128 @@
 import ./make-test-python.nix (
   { pkgs, ... }:
 
-    let
-      password = "some_password";
-      repository = "/tmp/restic-backup";
-      rcloneRepository = "rclone:local:/tmp/restic-rclone-backup";
+  let
+    password = "some_password";
+    repository = "/tmp/restic-backup";
+    repositoryFile = "${pkgs.writeText "repositoryFile" "/tmp/restic-backup-from-file"}";
+    rcloneRepository = "rclone:local:/tmp/restic-rclone-backup";
 
-      passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}";
-      initialize = true;
-      paths = [ "/opt" ];
-      pruneOpts = [
-        "--keep-daily 2"
-        "--keep-weekly 1"
-        "--keep-monthly 1"
-        "--keep-yearly 99"
-      ];
-    in
-      {
-        name = "restic";
+    backupPrepareCommand = ''
+      touch /opt/backupPrepareCommand
+      test ! -e /opt/backupCleanupCommand
+    '';
 
-        meta = with pkgs.lib.maintainers; {
-          maintainers = [ bbigras i077 ];
-        };
+    backupCleanupCommand = ''
+      rm /opt/backupPrepareCommand
+      touch /opt/backupCleanupCommand
+    '';
 
-        nodes = {
-          server =
-            { pkgs, ... }:
-              {
-                services.restic.backups = {
-                  remotebackup = {
-                    inherit repository passwordFile initialize paths pruneOpts;
-                  };
-                  rclonebackup = {
-                    repository = rcloneRepository;
-                    rcloneConfig = {
-                      type = "local";
-                      one_file_system = true;
-                    };
+    passwordFile = "${pkgs.writeText "password" "correcthorsebatterystaple"}";
+    initialize = true;
+    paths = [ "/opt" ];
+    pruneOpts = [
+      "--keep-daily 2"
+      "--keep-weekly 1"
+      "--keep-monthly 1"
+      "--keep-yearly 99"
+    ];
+  in
+  {
+    name = "restic";
 
-                    # This gets overridden by rcloneConfig.type
-                    rcloneConfigFile = pkgs.writeText "rclone.conf" ''
-                      [local]
-                      type=ftp
-                    '';
-                    inherit passwordFile initialize paths pruneOpts;
-                  };
-                  remoteprune = {
-                    inherit repository passwordFile;
-                    pruneOpts = [ "--keep-last 1" ];
-                  };
-                };
+    meta = with pkgs.lib.maintainers; {
+      maintainers = [ bbigras i077 ];
+    };
 
-                environment.sessionVariables.RCLONE_CONFIG_LOCAL_TYPE = "local";
+    nodes = {
+      server =
+        { pkgs, ... }:
+        {
+          services.restic.backups = {
+            remotebackup = {
+              inherit repository passwordFile initialize paths pruneOpts backupPrepareCommand backupCleanupCommand;
+            };
+            remotebackup-from-file = {
+              inherit repositoryFile passwordFile initialize paths pruneOpts;
+            };
+            rclonebackup = {
+              repository = rcloneRepository;
+              rcloneConfig = {
+                type = "local";
+                one_file_system = true;
               };
+
+              # This gets overridden by rcloneConfig.type
+              rcloneConfigFile = pkgs.writeText "rclone.conf" ''
+                [local]
+                type=ftp
+              '';
+              inherit passwordFile initialize paths pruneOpts;
+            };
+            remoteprune = {
+              inherit repository passwordFile;
+              pruneOpts = [ "--keep-last 1" ];
+            };
+            custompackage = {
+              inherit repository passwordFile paths;
+              package = pkgs.writeShellScriptBin "restic" ''
+                echo "$@" >> /tmp/fake-restic.log;
+              '';
+            };
+          };
+
+          environment.sessionVariables.RCLONE_CONFIG_LOCAL_TYPE = "local";
         };
+    };
 
-        testScript = ''
-          server.start()
-          server.wait_for_unit("dbus.socket")
-          server.fail(
-              "${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots",
-              "${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots",
-          )
-          server.succeed(
-              "mkdir -p /opt",
-              "touch /opt/some_file",
-              "mkdir -p /tmp/restic-rclone-backup",
-              "timedatectl set-time '2016-12-13 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
-              '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
-              "timedatectl set-time '2017-12-13 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              "timedatectl set-time '2018-12-13 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              "timedatectl set-time '2018-12-14 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              "timedatectl set-time '2018-12-15 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              "timedatectl set-time '2018-12-16 13:45'",
-              "systemctl start restic-backups-remotebackup.service",
-              "systemctl start restic-backups-rclonebackup.service",
-              '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"',
-              '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"',
-              "systemctl start restic-backups-remoteprune.service",
-              '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
-          )
-        '';
-      }
+    testScript = ''
+      server.start()
+      server.wait_for_unit("dbus.socket")
+      server.fail(
+          "${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots",
+          '${pkgs.restic}/bin/restic --repository-file ${repositoryFile} -p ${passwordFile} snapshots"',
+          "${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots",
+          "grep 'backup .* /opt' /tmp/fake-restic.log",
+      )
+      server.succeed(
+          "mkdir -p /opt",
+          "touch /opt/some_file",
+          "mkdir -p /tmp/restic-rclone-backup",
+          "timedatectl set-time '2016-12-13 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-remotebackup-from-file.service",
+          "systemctl start restic-backups-rclonebackup.service",
+          '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
+          '${pkgs.restic}/bin/restic --repository-file ${repositoryFile} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
+          '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
+          "systemctl start restic-backups-custompackage.service",
+          "grep 'backup .* /opt' /tmp/fake-restic.log",
+          "timedatectl set-time '2017-12-13 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-rclonebackup.service",
+          "timedatectl set-time '2018-12-13 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-rclonebackup.service",
+          "timedatectl set-time '2018-12-14 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-rclonebackup.service",
+          "timedatectl set-time '2018-12-15 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-rclonebackup.service",
+          "timedatectl set-time '2018-12-16 13:45'",
+          "systemctl start restic-backups-remotebackup.service",
+          "rm /opt/backupCleanupCommand",
+          "systemctl start restic-backups-rclonebackup.service",
+          '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"',
+          '${pkgs.restic}/bin/restic -r ${rcloneRepository} -p ${passwordFile} snapshots -c | grep -e "^4 snapshot"',
+          "systemctl start restic-backups-remoteprune.service",
+          '${pkgs.restic}/bin/restic -r ${repository} -p ${passwordFile} snapshots -c | grep -e "^1 snapshot"',
+      )
+    '';
+  }
 )
diff --git a/nixpkgs/nixos/tests/retroarch.nix b/nixpkgs/nixos/tests/retroarch.nix
index 4c96f9eabc82..c506ed02da89 100644
--- a/nixpkgs/nixos/tests/retroarch.nix
+++ b/nixpkgs/nixos/tests/retroarch.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     name = "retroarch";
     meta = with pkgs.lib.maintainers; { maintainers = [ j0hax ]; };
 
-    machine = { ... }:
+    nodes.machine = { ... }:
 
       {
         imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/riak.nix b/nixpkgs/nixos/tests/riak.nix
deleted file mode 100644
index 3dd4e333d669..000000000000
--- a/nixpkgs/nixos/tests/riak.nix
+++ /dev/null
@@ -1,18 +0,0 @@
-import ./make-test-python.nix ({ lib, pkgs, ... }: {
-  name = "riak";
-  meta = with lib.maintainers; {
-    maintainers = [ Br1ght0ne ];
-  };
-
-  machine = {
-    services.riak.enable = true;
-    services.riak.package = pkgs.riak;
-  };
-
-  testScript = ''
-    machine.start()
-
-    machine.wait_for_unit("riak")
-    machine.wait_until_succeeds("riak ping 2>&1")
-  '';
-})
diff --git a/nixpkgs/nixos/tests/rspamd.nix b/nixpkgs/nixos/tests/rspamd.nix
index f0ccfe7ea0e6..26895fbad3f3 100644
--- a/nixpkgs/nixos/tests/rspamd.nix
+++ b/nixpkgs/nixos/tests/rspamd.nix
@@ -22,7 +22,7 @@ let
   '';
   simple = name: enableIPv6: makeTest {
     name = "rspamd-${name}";
-    machine = {
+    nodes.machine = {
       services.rspamd.enable = true;
       networking.enableIPv6 = enableIPv6;
     };
@@ -52,7 +52,7 @@ in
   ipv4only = simple "ipv4only" false;
   deprecated = makeTest {
     name = "rspamd-deprecated";
-    machine = {
+    nodes.machine = {
       services.rspamd = {
         enable = true;
         workers.normal.bindSockets = [{
@@ -91,7 +91,7 @@ in
 
   bindports = makeTest {
     name = "rspamd-bindports";
-    machine = {
+    nodes.machine = {
       services.rspamd = {
         enable = true;
         workers.normal.bindSockets = [{
@@ -152,7 +152,7 @@ in
   };
   customLuaRules = makeTest {
     name = "rspamd-custom-lua-rules";
-    machine = {
+    nodes.machine = {
       environment.etc."tests/no-muh.eml".text = ''
         From: Sheep1<bah@example.com>
         To: Sheep2<mah@example.com>
@@ -256,7 +256,7 @@ in
   };
   postfixIntegration = makeTest {
     name = "rspamd-postfix-integration";
-    machine = {
+    nodes.machine = {
       environment.systemPackages = with pkgs; [ msmtp ];
       environment.etc."tests/gtube.eml".text = ''
         From: Sheep1<bah@example.com>
diff --git a/nixpkgs/nixos/tests/rsyslogd.nix b/nixpkgs/nixos/tests/rsyslogd.nix
index f35db3bd44b8..049acdcd4393 100644
--- a/nixpkgs/nixos/tests/rsyslogd.nix
+++ b/nixpkgs/nixos/tests/rsyslogd.nix
@@ -11,7 +11,7 @@ with pkgs.lib;
     name = "rsyslogd-test1";
     meta.maintainers = [ pkgs.lib.maintainers.aanderse ];
 
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       services.rsyslogd.enable = true;
       services.journald.forwardToSyslog = false;
     };
@@ -27,7 +27,7 @@ with pkgs.lib;
     name = "rsyslogd-test2";
     meta.maintainers = [ pkgs.lib.maintainers.aanderse ];
 
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       services.rsyslogd.enable = true;
     };
 
diff --git a/nixpkgs/nixos/tests/sabnzbd.nix b/nixpkgs/nixos/tests/sabnzbd.nix
index fb35b212b493..075bd0b1fe09 100644
--- a/nixpkgs/nixos/tests/sabnzbd.nix
+++ b/nixpkgs/nixos/tests/sabnzbd.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with maintainers; [ jojosch ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.sabnzbd = {
       enable = true;
     };
diff --git a/nixpkgs/nixos/tests/sanoid.nix b/nixpkgs/nixos/tests/sanoid.nix
index 3bdbe0a8d8db..97833c37e6ef 100644
--- a/nixpkgs/nixos/tests/sanoid.nix
+++ b/nixpkgs/nixos/tests/sanoid.nix
@@ -48,6 +48,9 @@ in {
           };
           # Take snapshot and sync
           "pool/syncoid".target = "root@target:pool/syncoid";
+
+          # Test pool without parent (regression test for https://github.com/NixOS/nixpkgs/pull/180111)
+          "pool".target = "root@target:pool/full-pool";
         };
       };
     };
@@ -105,6 +108,9 @@ in {
     source.systemctl("start --wait syncoid-pool-syncoid.service")
     target.succeed("cat /mnt/pool/syncoid/test.txt")
 
+    source.systemctl("start --wait syncoid-pool.service")
+    target.succeed("[[ -d /mnt/pool/full-pool/syncoid ]]")
+
     assert len(source.succeed("zfs allow pool")) == 0, "Pool shouldn't have delegated permissions set after syncing snapshots"
     assert len(source.succeed("zfs allow pool/sanoid")) == 0, "Sanoid dataset shouldn't have delegated permissions set after syncing snapshots"
     assert len(source.succeed("zfs allow pool/syncoid")) == 0, "Syncoid dataset shouldn't have delegated permissions set after syncing snapshots"
diff --git a/nixpkgs/nixos/tests/schleuder.nix b/nixpkgs/nixos/tests/schleuder.nix
new file mode 100644
index 000000000000..a9e4cc325bc7
--- /dev/null
+++ b/nixpkgs/nixos/tests/schleuder.nix
@@ -0,0 +1,128 @@
+let
+  certs = import ./common/acme/server/snakeoil-certs.nix;
+  domain = certs.domain;
+in
+import ./make-test-python.nix {
+  name = "schleuder";
+  nodes.machine = { pkgs, ... }: {
+    imports = [ ./common/user-account.nix ];
+    services.postfix = {
+      enable = true;
+      enableSubmission = true;
+      tlsTrustedAuthorities = "${certs.ca.cert}";
+      sslCert = "${certs.${domain}.cert}";
+      sslKey = "${certs.${domain}.key}";
+      inherit domain;
+      destination = [ domain ];
+      localRecipients = [ "root" "alice" "bob" ];
+    };
+    services.schleuder = {
+      enable = true;
+      # Don't do it like this in production! The point of this setting
+      # is to allow loading secrets from _outside_ the world-readable
+      # Nix store.
+      extraSettingsFile = pkgs.writeText "schleuder-api-keys.yml" ''
+        api:
+          valid_api_keys:
+            - fnord
+      '';
+      lists = [ "security@${domain}" ];
+      settings.api = {
+        tls_cert_file = "${certs.${domain}.cert}";
+        tls_key_file = "${certs.${domain}.key}";
+      };
+    };
+
+    environment.systemPackages = [
+      pkgs.gnupg
+      pkgs.msmtp
+      (pkgs.writeScriptBin "do-test" ''
+        #!${pkgs.runtimeShell}
+        set -exuo pipefail
+
+        # Generate a GPG key with no passphrase and export it
+        sudo -u alice gpg --passphrase-fd 0 --batch --yes --quick-generate-key 'alice@${domain}' rsa4096 sign,encr < <(echo)
+        sudo -u alice gpg --armor --export alice@${domain} > alice.asc
+        # Create a new mailing list with alice as the owner, and alice's key
+        schleuder-cli list new security@${domain} alice@${domain} alice.asc
+
+        # Send an email from a non-member of the list. Use --auto-from so we don't have to specify who it's from twice.
+        msmtp --auto-from security@${domain} --host=${domain} --port=25 --tls --tls-starttls <<EOF
+          Subject: really big security issue!!
+          From: root@${domain}
+
+          I found a big security problem!
+        EOF
+
+        # Wait for delivery
+        (set +o pipefail; journalctl -f -n 1000 -u postfix | grep -m 1 'delivered to maildir')
+
+        # There should be exactly one email
+        mail=(/var/spool/mail/alice/new/*)
+        [[ "''${#mail[@]}" = 1 ]]
+
+        # Find the fingerprint of the mailing list key
+        read list_key_fp address < <(schleuder-cli keys list security@${domain} | grep security@)
+        schleuder-cli keys export security@${domain} $list_key_fp > list.asc
+
+        # Import the key into alice's keyring, so we can verify it as well as decrypting
+        sudo -u alice gpg --import <list.asc
+        # And perform the decryption.
+        sudo -u alice gpg -d $mail >decrypted
+        # And check that the text matches.
+        grep "big security problem" decrypted
+      '')
+
+      # For debugging:
+      # pkgs.vim pkgs.openssl pkgs.sqliteinteractive
+    ];
+
+    security.pki.certificateFiles = [ certs.ca.cert ];
+
+    # Since we don't have internet here, use dnsmasq to provide MX records from /etc/hosts
+    services.dnsmasq = {
+      enable = true;
+      extraConfig = ''
+        selfmx
+      '';
+    };
+
+    networking.extraHosts = ''
+      127.0.0.1 ${domain}
+    '';
+
+    # schleuder-cli's config is not quite optimal in several ways:
+    # - A fingerprint _must_ be pinned, it doesn't even have an option
+    #   to trust the PKI
+    # - It compares certificate fingerprints rather than key
+    #   fingerprints, so renewals break the pin (though that's not
+    #   relevant for this test)
+    # - It compares them as strings, which means we need to match the
+    #   expected format exactly. This means removing the :s and
+    #   lowercasing it.
+    # Refs:
+    # https://0xacab.org/schleuder/schleuder-cli/-/issues/16
+    # https://0xacab.org/schleuder/schleuder-cli/-/blob/f8895b9f47083d8c7b99a2797c93f170f3c6a3c0/lib/schleuder-cli/helper.rb#L230-238
+    systemd.tmpfiles.rules = let cliconfig = pkgs.runCommand "schleuder-cli.yml"
+      {
+        nativeBuildInputs = [ pkgs.jq pkgs.openssl ];
+      } ''
+      fp=$(openssl x509 -in ${certs.${domain}.cert} -noout -fingerprint -sha256 | cut -d = -f 2 | tr -d : | tr 'A-Z' 'a-z')
+      cat > $out <<EOF
+      host: localhost
+      port: 4443
+      tls_fingerprint: "$fp"
+      api_key: fnord
+      EOF
+    ''; in
+      [
+        "L+ /root/.schleuder-cli/schleuder-cli.yml - - - - ${cliconfig}"
+      ];
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_until_succeeds("nc -z localhost 4443")
+    machine.succeed("do-test")
+  '';
+}
diff --git a/nixpkgs/nixos/tests/sddm.nix b/nixpkgs/nixos/tests/sddm.nix
index d7c65fa33d67..c76a9683e66d 100644
--- a/nixpkgs/nixos/tests/sddm.nix
+++ b/nixpkgs/nixos/tests/sddm.nix
@@ -12,7 +12,7 @@ let
     default = {
       name = "sddm";
 
-      machine = { ... }: {
+      nodes.machine = { ... }: {
         imports = [ ./common/user-account.nix ];
         services.xserver.enable = true;
         services.xserver.displayManager.sddm.enable = true;
@@ -41,7 +41,7 @@ let
         maintainers = [ ttuegel ];
       };
 
-      machine = { ... }: {
+      nodes.machine = { ... }: {
         imports = [ ./common/user-account.nix ];
         services.xserver.enable = true;
         services.xserver.displayManager = {
diff --git a/nixpkgs/nixos/tests/shadow.nix b/nixpkgs/nixos/tests/shadow.nix
index dd2a575b1935..50a9f7124646 100644
--- a/nixpkgs/nixos/tests/shadow.nix
+++ b/nixpkgs/nixos/tests/shadow.nix
@@ -39,9 +39,9 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
         shadow.wait_until_succeeds("[ $(fgconsole) = 2 ]")
         shadow.wait_for_unit("getty@tty2.service")
         shadow.wait_until_succeeds("pgrep -f 'agetty.*tty2'")
-        shadow.wait_until_tty_matches(2, "login: ")
+        shadow.wait_until_tty_matches("2", "login: ")
         shadow.send_chars("emma\n")
-        shadow.wait_until_tty_matches(2, "login: emma")
+        shadow.wait_until_tty_matches("2", "login: emma")
         shadow.wait_until_succeeds("pgrep login")
         shadow.sleep(2)
         shadow.send_chars("${password1}\n")
@@ -63,9 +63,9 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
         shadow.wait_until_succeeds("[ $(fgconsole) = 3 ]")
         shadow.wait_for_unit("getty@tty3.service")
         shadow.wait_until_succeeds("pgrep -f 'agetty.*tty3'")
-        shadow.wait_until_tty_matches(3, "login: ")
+        shadow.wait_until_tty_matches("3", "login: ")
         shadow.send_chars("emma\n")
-        shadow.wait_until_tty_matches(3, "login: emma")
+        shadow.wait_until_tty_matches("3", "login: emma")
         shadow.wait_until_succeeds("pgrep login")
         shadow.sleep(2)
         shadow.send_chars("${password1}\n")
@@ -81,16 +81,16 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
         shadow.wait_until_succeeds("[ $(fgconsole) = 4 ]")
         shadow.wait_for_unit("getty@tty4.service")
         shadow.wait_until_succeeds("pgrep -f 'agetty.*tty4'")
-        shadow.wait_until_tty_matches(4, "login: ")
+        shadow.wait_until_tty_matches("4", "login: ")
         shadow.send_chars("emma\n")
-        shadow.wait_until_tty_matches(4, "login: emma")
+        shadow.wait_until_tty_matches("4", "login: emma")
         shadow.wait_until_succeeds("pgrep login")
         shadow.sleep(2)
         shadow.send_chars("${password1}\n")
-        shadow.wait_until_tty_matches(4, "Login incorrect")
-        shadow.wait_until_tty_matches(4, "login:")
+        shadow.wait_until_tty_matches("4", "Login incorrect")
+        shadow.wait_until_tty_matches("4", "login:")
         shadow.send_chars("emma\n")
-        shadow.wait_until_tty_matches(4, "login: emma")
+        shadow.wait_until_tty_matches("4", "login: emma")
         shadow.wait_until_succeeds("pgrep login")
         shadow.sleep(2)
         shadow.send_chars("${password3}\n")
@@ -109,11 +109,11 @@ in import ./make-test-python.nix ({ pkgs, ... }: {
         shadow.wait_until_succeeds("[ $(fgconsole) = 5 ]")
         shadow.wait_for_unit("getty@tty5.service")
         shadow.wait_until_succeeds("pgrep -f 'agetty.*tty5'")
-        shadow.wait_until_tty_matches(5, "login: ")
+        shadow.wait_until_tty_matches("5", "login: ")
         shadow.send_chars("layla\n")
-        shadow.wait_until_tty_matches(5, "login: layla")
+        shadow.wait_until_tty_matches("5", "login: layla")
         shadow.wait_until_succeeds("pgrep login")
         shadow.send_chars("${password2}\n")
-        shadow.wait_until_tty_matches(5, "login:")
+        shadow.wait_until_tty_matches("5", "login:")
   '';
 })
diff --git a/nixpkgs/nixos/tests/shattered-pixel-dungeon.nix b/nixpkgs/nixos/tests/shattered-pixel-dungeon.nix
index d4e5de22ab9d..a256bbdfd735 100644
--- a/nixpkgs/nixos/tests/shattered-pixel-dungeon.nix
+++ b/nixpkgs/nixos/tests/shattered-pixel-dungeon.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/shiori.nix b/nixpkgs/nixos/tests/shiori.nix
index 6c59c394009e..d0f68b903f8c 100644
--- a/nixpkgs/nixos/tests/shiori.nix
+++ b/nixpkgs/nixos/tests/shiori.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...}:
   name = "shiori";
   meta.maintainers = with lib.maintainers; [ minijackson ];
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.shiori.enable = true; };
 
diff --git a/nixpkgs/nixos/tests/signal-desktop.nix b/nixpkgs/nixos/tests/signal-desktop.nix
index 8c7230629923..5e2b648c7cf5 100644
--- a/nixpkgs/nixos/tests/signal-desktop.nix
+++ b/nixpkgs/nixos/tests/signal-desktop.nix
@@ -16,7 +16,7 @@ in {
     maintainers = [ flokli primeos ];
   };
 
-  machine = { ... }:
+  nodes.machine = { ... }:
 
   {
     imports = [
@@ -60,7 +60,7 @@ in {
     )
     # Only SQLCipher should be able to read the encrypted DB:
     machine.fail(
-        "su - alice -c 'sqlite3 ~/.config/Signal/sql/db.sqlite .databases'"
+        "su - alice -c 'sqlite3 ~/.config/Signal/sql/db.sqlite .tables'"
     )
     print(machine.succeed(
         "su - alice -c 'sqlcipher ~/.config/Signal/sql/db.sqlite'"
diff --git a/nixpkgs/nixos/tests/simple.nix b/nixpkgs/nixos/tests/simple.nix
index b4d90f750ecf..c36287b4e843 100644
--- a/nixpkgs/nixos/tests/simple.nix
+++ b/nixpkgs/nixos/tests/simple.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ eelco ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
   };
 
diff --git a/nixpkgs/nixos/tests/snapcast.nix b/nixpkgs/nixos/tests/snapcast.nix
index 30b8343e2ffe..9b62e4724e75 100644
--- a/nixpkgs/nixos/tests/snapcast.nix
+++ b/nixpkgs/nixos/tests/snapcast.nix
@@ -19,6 +19,7 @@ in {
         port = port;
         tcp.port = tcpPort;
         http.port = httpPort;
+        openFirewall = true;
         buffer = bufferSize;
         streams = {
           mpd = {
diff --git a/nixpkgs/nixos/tests/snapper.nix b/nixpkgs/nixos/tests/snapper.nix
index 098d8d9d72f5..651adc8934d3 100644
--- a/nixpkgs/nixos/tests/snapper.nix
+++ b/nixpkgs/nixos/tests/snapper.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ ... }:
 {
   name = "snapper";
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     boot.initrd.postDeviceCommands = ''
       ${pkgs.btrfs-progs}/bin/mkfs.btrfs -f -L aux /dev/vdb
     '';
diff --git a/nixpkgs/nixos/tests/soapui.nix b/nixpkgs/nixos/tests/soapui.nix
index 76a87ed5efa1..e4ce3888fd43 100644
--- a/nixpkgs/nixos/tests/soapui.nix
+++ b/nixpkgs/nixos/tests/soapui.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ asbachb ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/solr.nix b/nixpkgs/nixos/tests/solr.nix
index 86efe87c7078..33afe9d788f7 100644
--- a/nixpkgs/nixos/tests/solr.nix
+++ b/nixpkgs/nixos/tests/solr.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
   name = "solr";
   meta.maintainers = [ pkgs.lib.maintainers.aanderse ];
 
-  machine =
+  nodes.machine =
     { config, pkgs, ... }:
     {
       # Ensure the virtual machine has enough memory for Solr to avoid the following error:
diff --git a/nixpkgs/nixos/tests/sonarr.nix b/nixpkgs/nixos/tests/sonarr.nix
index 764a4d05b381..bdfc8916cb7f 100644
--- a/nixpkgs/nixos/tests/sonarr.nix
+++ b/nixpkgs/nixos/tests/sonarr.nix
@@ -12,7 +12,7 @@ with lib;
 
   testScript = ''
     machine.wait_for_unit("sonarr.service")
-    machine.wait_for_open_port("8989")
+    machine.wait_for_open_port(8989)
     machine.succeed("curl --fail http://localhost:8989/")
   '';
 })
diff --git a/nixpkgs/nixos/tests/sourcehut.nix b/nixpkgs/nixos/tests/sourcehut.nix
index 55757e35f9b4..d52fbddd20f3 100644
--- a/nixpkgs/nixos/tests/sourcehut.nix
+++ b/nixpkgs/nixos/tests/sourcehut.nix
@@ -119,7 +119,7 @@ in
 
   meta.maintainers = [ pkgs.lib.maintainers.tomberek ];
 
-  machine = { config, pkgs, nodes, ... }: {
+  nodes.machine = { config, pkgs, nodes, ... }: {
     # buildsrht needs space
     virtualisation.diskSize = 4 * 1024;
     virtualisation.memorySize = 2 * 1024;
@@ -169,6 +169,45 @@ in
         oauth-client-id = "d07cb713d920702e";
       };
       settings.webhooks.private-key = pkgs.writeText "webhook-key" "Ra3IjxgFiwG9jxgp4WALQIZw/BMYt30xWiOsqD0J7EA=";
+      settings.mail = {
+        smtp-from = "root+hut@${domain}";
+        # WARNING: take care to keep pgp-privkey outside the Nix store in production,
+        # or use LoadCredentialEncrypted=
+        pgp-privkey = toString (pkgs.writeText "sourcehut.pgp-privkey" ''
+          -----BEGIN PGP PRIVATE KEY BLOCK-----
+
+          lFgEYqDRORYJKwYBBAHaRw8BAQdAehGoy36FUx2OesYm07be2rtLyvR5Pb/ltstd
+          Gk7hYQoAAP9X4oPmxxrHN8LewBpWITdBomNqlHoiP7mI0nz/BOPJHxEktDZuaXhv
+          cy90ZXN0cy9zb3VyY2VodXQgPHJvb3QraHV0QHNvdXJjZWh1dC5sb2NhbGRvbWFp
+          bj6IlwQTFgoAPxYhBPqjgjnL8RHN4JnADNicgXaYm0jJBQJioNE5AhsDBQkDwmcA
+          BgsJCAcDCgUVCgkICwUWAwIBAAIeBQIXgAAKCRDYnIF2mJtIySVCAP9e2nHsVHSi
+          2B1YGZpVG7Xf36vxljmMkbroQy+0gBPwRwEAq+jaiQqlbGhQ7R/HMFcAxBIVsq8h
+          Aw1rngsUd0o3dAicXQRioNE5EgorBgEEAZdVAQUBAQdAXZV2Sd5ZNBVTBbTGavMv
+          D6ORrUh8z7TI/3CsxCE7+yADAQgHAAD/c1RU9xH+V/uI1fE7HIn/zL0LUPpsuce2
+          cH++g4u3kBgTOYh+BBgWCgAmFiEE+qOCOcvxEc3gmcAM2JyBdpibSMkFAmKg0TkC
+          GwwFCQPCZwAACgkQ2JyBdpibSMlKagD/cTre6p1m8QuJ7kwmCFRSz5tBzIuYMMgN
+          xtT7dmS91csA/35fWsOykSiFRojQ7ccCSUTHL7ApF2EbL968tP/D2hIG
+          =Hjoc
+          -----END PGP PRIVATE KEY BLOCK-----
+        '');
+        pgp-pubkey = pkgs.writeText "sourcehut.pgp-pubkey" ''
+          -----BEGIN PGP PUBLIC KEY BLOCK-----
+
+          mDMEYqDRORYJKwYBBAHaRw8BAQdAehGoy36FUx2OesYm07be2rtLyvR5Pb/ltstd
+          Gk7hYQq0Nm5peG9zL3Rlc3RzL3NvdXJjZWh1dCA8cm9vdCtodXRAc291cmNlaHV0
+          LmxvY2FsZG9tYWluPoiXBBMWCgA/FiEE+qOCOcvxEc3gmcAM2JyBdpibSMkFAmKg
+          0TkCGwMFCQPCZwAGCwkIBwMKBRUKCQgLBRYDAgEAAh4FAheAAAoJENicgXaYm0jJ
+          JUIA/17acexUdKLYHVgZmlUbtd/fq/GWOYyRuuhDL7SAE/BHAQCr6NqJCqVsaFDt
+          H8cwVwDEEhWyryEDDWueCxR3Sjd0CLg4BGKg0TkSCisGAQQBl1UBBQEBB0BdlXZJ
+          3lk0FVMFtMZq8y8Po5GtSHzPtMj/cKzEITv7IAMBCAeIfgQYFgoAJhYhBPqjgjnL
+          8RHN4JnADNicgXaYm0jJBQJioNE5AhsMBQkDwmcAAAoJENicgXaYm0jJSmoA/3E6
+          3uqdZvELie5MJghUUs+bQcyLmDDIDcbU+3ZkvdXLAP9+X1rDspEohUaI0O3HAklE
+          xy+wKRdhGy/evLT/w9oSBg==
+          =pJD7
+          -----END PGP PUBLIC KEY BLOCK-----
+        '';
+        pgp-key-id = "0xFAA38239CBF111CDE099C00CD89C8176989B48C9";
+      };
     };
 
     networking.firewall.allowedTCPPorts = [ 443 ];
@@ -195,6 +234,7 @@ in
     # Testing metasrht
     machine.wait_for_unit("metasrht-api.service")
     machine.wait_for_unit("metasrht.service")
+    machine.wait_for_unit("metasrht-webhooks.service")
     machine.wait_for_open_port(5000)
     machine.succeed("curl -sL http://localhost:5000 | grep meta.${domain}")
     machine.succeed("curl -sL http://meta.${domain} | grep meta.${domain}")
@@ -206,7 +246,9 @@ in
     #machine.wait_for_unit("buildsrht-worker.service")
 
     # Testing gitsrht
+    machine.wait_for_unit("gitsrht-api.service")
     machine.wait_for_unit("gitsrht.service")
+    machine.wait_for_unit("gitsrht-webhooks.service")
     machine.succeed("curl -sL http://git.${domain} | grep git.${domain}")
   '';
 })
diff --git a/nixpkgs/nixos/tests/sssd-ldap.nix b/nixpkgs/nixos/tests/sssd-ldap.nix
index 5c58eaef7146..27dce6ceb98c 100644
--- a/nixpkgs/nixos/tests/sssd-ldap.nix
+++ b/nixpkgs/nixos/tests/sssd-ldap.nix
@@ -13,7 +13,7 @@ in import ./make-test-python.nix ({pkgs, ...}: {
     maintainers = [ bbigras ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.openldap = {
       enable = true;
       settings = {
@@ -28,7 +28,7 @@ in import ./make-test-python.nix ({pkgs, ...}: {
             attrs = {
               objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ];
               olcDatabase = "{1}mdb";
-              olcDbDirectory = "/var/db/openldap";
+              olcDbDirectory = "/var/lib/openldap/db";
               olcSuffix = dbSuffix;
               olcRootDN = "cn=${ldapRootUser},${dbSuffix}";
               olcRootPW = ldapRootPassword;
@@ -67,6 +67,8 @@ in import ./make-test-python.nix ({pkgs, ...}: {
 
     services.sssd = {
       enable = true;
+      # just for testing purposes, don't put this into the Nix store in production!
+      environmentFile = "${pkgs.writeText "ldap-root" "LDAP_BIND_PW=${ldapRootPassword}"}";
       config = ''
         [sssd]
         config_file_version = 2
@@ -80,7 +82,7 @@ in import ./make-test-python.nix ({pkgs, ...}: {
         ldap_search_base = ${dbSuffix}
         ldap_default_bind_dn = cn=${ldapRootUser},${dbSuffix}
         ldap_default_authtok_type = password
-        ldap_default_authtok = ${ldapRootPassword}
+        ldap_default_authtok = $LDAP_BIND_PW
       '';
     };
   };
diff --git a/nixpkgs/nixos/tests/sssd.nix b/nixpkgs/nixos/tests/sssd.nix
index 5c1abdca6aef..25527cb59a59 100644
--- a/nixpkgs/nixos/tests/sssd.nix
+++ b/nixpkgs/nixos/tests/sssd.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
   meta = with pkgs.lib.maintainers; {
     maintainers = [ bbigras ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.sssd.enable = true;
   };
 
diff --git a/nixpkgs/nixos/tests/starship.nix b/nixpkgs/nixos/tests/starship.nix
index 33e9a72f7000..48a4be6caf17 100644
--- a/nixpkgs/nixos/tests/starship.nix
+++ b/nixpkgs/nixos/tests/starship.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   name = "starship";
   meta.maintainers = pkgs.starship.meta.maintainers;
 
-  machine = {
+  nodes.machine = {
     programs = {
       fish.enable = true;
       zsh.enable = true;
diff --git a/nixpkgs/nixos/tests/step-ca.nix b/nixpkgs/nixos/tests/step-ca.nix
index f21bd5366266..a855b590232d 100644
--- a/nixpkgs/nixos/tests/step-ca.nix
+++ b/nixpkgs/nixos/tests/step-ca.nix
@@ -9,6 +9,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     '';
   in
   {
+    name = "step-ca";
     nodes =
       {
         caserver =
diff --git a/nixpkgs/nixos/tests/stunnel.nix b/nixpkgs/nixos/tests/stunnel.nix
new file mode 100644
index 000000000000..22c087290fc7
--- /dev/null
+++ b/nixpkgs/nixos/tests/stunnel.nix
@@ -0,0 +1,174 @@
+{ system ? builtins.currentSystem, config ? { }
+, pkgs ? import ../.. { inherit system config; } }:
+
+with import ../lib/testing-python.nix { inherit system pkgs; };
+with pkgs.lib;
+
+let
+  stunnelCommon = {
+    services.stunnel = {
+      enable = true;
+      user = "stunnel";
+    };
+    users.groups.stunnel = { };
+    users.users.stunnel = {
+      isSystemUser = true;
+      group = "stunnel";
+    };
+  };
+  makeCert = { config, pkgs, ... }: {
+    system.activationScripts.create-test-cert = stringAfter [ "users" ] ''
+      ${pkgs.openssl}/bin/openssl req -batch -x509 -newkey rsa -nodes -out /test-cert.pem -keyout /test-key.pem -subj /CN=${config.networking.hostName}
+      ( umask 077; cat /test-key.pem /test-cert.pem > /test-key-and-cert.pem )
+      chown stunnel /test-key.pem /test-key-and-cert.pem
+    '';
+  };
+  serverCommon = { pkgs, ... }: {
+    networking.firewall.allowedTCPPorts = [ 443 ];
+    services.stunnel.servers.https = {
+      accept = "443";
+      connect = 80;
+      cert = "/test-key-and-cert.pem";
+    };
+    systemd.services.simple-webserver = {
+      wantedBy = [ "multi-user.target" ];
+      script = ''
+        cd /etc/webroot
+        ${pkgs.python3}/bin/python -m http.server 80
+      '';
+    };
+  };
+  copyCert = src: dest: filename: ''
+    from shlex import quote
+    ${src}.wait_for_file("/test-key-and-cert.pem")
+    server_cert = ${src}.succeed("cat /test-cert.pem")
+    ${dest}.succeed("echo %s > ${filename}" % quote(server_cert))
+  '';
+
+in {
+  basicServer = makeTest {
+    name = "basicServer";
+
+    nodes = {
+      client = { };
+      server = {
+        imports = [ makeCert serverCommon stunnelCommon ];
+        environment.etc."webroot/index.html".text = "well met";
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      ${copyCert "server" "client" "/authorized-server-cert.crt"}
+
+      server.wait_for_unit("simple-webserver")
+      server.wait_for_unit("stunnel")
+
+      client.succeed("curl --fail --cacert /authorized-server-cert.crt https://server/ > out")
+      client.succeed('[[ "$(< out)" == "well met" ]]')
+    '';
+  };
+
+  serverAndClient = makeTest {
+    name = "serverAndClient";
+
+    nodes = {
+      client = {
+        imports = [ stunnelCommon ];
+        services.stunnel.clients = {
+          httpsClient = {
+            accept = "80";
+            connect = "server:443";
+            CAFile = "/authorized-server-cert.crt";
+          };
+          httpsClientWithHostVerify = {
+            accept = "81";
+            connect = "server:443";
+            CAFile = "/authorized-server-cert.crt";
+            verifyHostname = "server";
+          };
+          httpsClientWithHostVerifyFail = {
+            accept = "82";
+            connect = "server:443";
+            CAFile = "/authorized-server-cert.crt";
+            verifyHostname = "wronghostname";
+          };
+        };
+      };
+      server = {
+        imports = [ makeCert serverCommon stunnelCommon ];
+        environment.etc."webroot/index.html".text = "hello there";
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      ${copyCert "server" "client" "/authorized-server-cert.crt"}
+
+      server.wait_for_unit("simple-webserver")
+      server.wait_for_unit("stunnel")
+
+      # In case stunnel came up before we got the server's cert copied over
+      client.succeed("systemctl reload-or-restart stunnel")
+
+      client.succeed("curl --fail http://localhost/ > out")
+      client.succeed('[[ "$(< out)" == "hello there" ]]')
+
+      client.succeed("curl --fail http://localhost:81/ > out")
+      client.succeed('[[ "$(< out)" == "hello there" ]]')
+
+      client.fail("curl --fail http://localhost:82/ > out")
+      client.succeed('[[ "$(< out)" == "" ]]')
+    '';
+  };
+
+  mutualAuth = makeTest {
+    name = "mutualAuth";
+
+    nodes = rec {
+      client = {
+        imports = [ makeCert stunnelCommon ];
+        services.stunnel.clients.authenticated-https = {
+          accept = "80";
+          connect = "server:443";
+          verifyPeer = true;
+          CAFile = "/authorized-server-cert.crt";
+          cert = "/test-cert.pem";
+          key = "/test-key.pem";
+        };
+      };
+      wrongclient = client;
+      server = {
+        imports = [ makeCert serverCommon stunnelCommon ];
+        services.stunnel.servers.https = {
+          CAFile = "/authorized-client-certs.crt";
+          verifyPeer = true;
+        };
+        environment.etc."webroot/index.html".text = "secret handshake";
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      ${copyCert "server" "client" "/authorized-server-cert.crt"}
+      ${copyCert "client" "server" "/authorized-client-certs.crt"}
+      ${copyCert "server" "wrongclient" "/authorized-server-cert.crt"}
+
+      # In case stunnel came up before we got the cross-certs in place
+      client.succeed("systemctl reload-or-restart stunnel")
+      server.succeed("systemctl reload-or-restart stunnel")
+      wrongclient.succeed("systemctl reload-or-restart stunnel")
+
+      server.wait_for_unit("simple-webserver")
+      client.fail("curl --fail --insecure https://server/ > out")
+      client.succeed('[[ "$(< out)" == "" ]]')
+      client.succeed("curl --fail http://localhost/ > out")
+      client.succeed('[[ "$(< out)" == "secret handshake" ]]')
+      wrongclient.fail("curl --fail http://localhost/ > out")
+      wrongclient.succeed('[[ "$(< out)" == "" ]]')
+    '';
+  };
+}
diff --git a/nixpkgs/nixos/tests/swap-partition.nix b/nixpkgs/nixos/tests/swap-partition.nix
new file mode 100644
index 000000000000..2279630b57b8
--- /dev/null
+++ b/nixpkgs/nixos/tests/swap-partition.nix
@@ -0,0 +1,48 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }:
+{
+  name = "swap-partition";
+
+  nodes.machine =
+    { config, pkgs, lib, ... }:
+    {
+      virtualisation.useDefaultFilesystems = false;
+
+      virtualisation.bootDevice = "/dev/vda1";
+
+      boot.initrd.postDeviceCommands = ''
+        if ! test -b /dev/vda1; then
+          ${pkgs.parted}/bin/parted --script /dev/vda -- mklabel msdos
+          ${pkgs.parted}/bin/parted --script /dev/vda -- mkpart primary 1MiB -250MiB
+          ${pkgs.parted}/bin/parted --script /dev/vda -- mkpart primary -250MiB 100%
+          sync
+        fi
+
+        FSTYPE=$(blkid -o value -s TYPE /dev/vda1 || true)
+        if test -z "$FSTYPE"; then
+          ${pkgs.e2fsprogs}/bin/mke2fs -t ext4 -L root /dev/vda1
+          ${pkgs.util-linux}/bin/mkswap --label swap /dev/vda2
+        fi
+      '';
+
+      virtualisation.fileSystems = {
+        "/" = {
+          device = "/dev/disk/by-label/root";
+          fsType = "ext4";
+        };
+      };
+
+      swapDevices = [
+        {
+          device = "/dev/disk/by-label/swap";
+        }
+      ];
+    };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+
+    with subtest("Swap is active"):
+      # Doesn't matter if the numbers reported by `free` are slightly off due to unit conversions.
+      machine.succeed("free -h | grep -E 'Swap:\s+2[45][0-9]Mi'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/sway.nix b/nixpkgs/nixos/tests/sway.nix
index 1e9e146c4b6c..52e2c7c99ec4 100644
--- a/nixpkgs/nixos/tests/sway.nix
+++ b/nixpkgs/nixos/tests/sway.nix
@@ -4,7 +4,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ primeos synthetica ];
   };
 
-  machine = { config, ... }: {
+  # testScriptWithTypes:49: error: Cannot call function of unknown type
+  #           (machine.succeed if succeed else machine.execute)(
+  #           ^
+  # Found 1 error in 1 file (checked 1 source file)
+  skipTypeCheck = true;
+
+  nodes.machine = { config, ... }: {
     # Automatically login on tty1 as a normal user:
     imports = [ ./common/user-account.nix ];
     services.getty.autologinUser = "alice";
diff --git a/nixpkgs/nixos/tests/sympa.nix b/nixpkgs/nixos/tests/sympa.nix
index aad7c95b6c99..80daa4134f75 100644
--- a/nixpkgs/nixos/tests/sympa.nix
+++ b/nixpkgs/nixos/tests/sympa.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "sympa";
   meta.maintainers = with lib.maintainers; [ mmilata ];
 
-  machine =
+  nodes.machine =
     { ... }:
     {
 
@@ -13,7 +13,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
             webHost = "localhost";
           };
         };
-        listMasters = [ "joe@example.org" ];
+        listMasters = [ "bob@example.org" ];
         web.enable = true;
         web.https = false;
         database = {
diff --git a/nixpkgs/nixos/tests/syncthing-init.nix b/nixpkgs/nixos/tests/syncthing-init.nix
index 8b60ad7faf09..fcd90739e6a5 100644
--- a/nixpkgs/nixos/tests/syncthing-init.nix
+++ b/nixpkgs/nixos/tests/syncthing-init.nix
@@ -6,7 +6,7 @@ in {
   name = "syncthing-init";
   meta.maintainers = with pkgs.lib.maintainers; [ lassulus ];
 
-  machine = {
+  nodes.machine = {
     services.syncthing = {
       enable = true;
       devices.testDevice = {
diff --git a/nixpkgs/nixos/tests/syncthing-relay.nix b/nixpkgs/nixos/tests/syncthing-relay.nix
index a0233c969ec0..3d70b1eda7b2 100644
--- a/nixpkgs/nixos/tests/syncthing-relay.nix
+++ b/nixpkgs/nixos/tests/syncthing-relay.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
   name = "syncthing-relay";
   meta.maintainers = with pkgs.lib.maintainers; [ delroth ];
 
-  machine = {
+  nodes.machine = {
     environment.systemPackages = [ pkgs.jq ];
     services.syncthing.relay = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/systemd-analyze.nix b/nixpkgs/nixos/tests/systemd-analyze.nix
index 186f5aee7b85..31588e2b41aa 100644
--- a/nixpkgs/nixos/tests/systemd-analyze.nix
+++ b/nixpkgs/nixos/tests/systemd-analyze.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... }:
     maintainers = [ raskin ];
   };
 
-  machine =
+  nodes.machine =
     { pkgs, lib, ... }:
     { boot.kernelPackages = lib.mkIf latestKernel pkgs.linuxPackages_latest;
       sound.enable = true; # needed for the factl test, /dev/snd/* exists without them but udev doesn't care then
diff --git a/nixpkgs/nixos/tests/systemd-binfmt.nix b/nixpkgs/nixos/tests/systemd-binfmt.nix
index a3a6efac3e4d..b16fda0ddb1a 100644
--- a/nixpkgs/nixos/tests/systemd-binfmt.nix
+++ b/nixpkgs/nixos/tests/systemd-binfmt.nix
@@ -31,7 +31,7 @@ let
 in {
   basic = makeTest {
     name = "systemd-binfmt";
-    machine = {
+    nodes.machine = {
       boot.binfmt.emulatedSystems = [
         "armv7l-linux"
         "aarch64-linux"
@@ -56,7 +56,7 @@ in {
 
   preserveArgvZero = makeTest {
     name = "systemd-binfmt-preserve-argv0";
-    machine = {
+    nodes.machine = {
       boot.binfmt.emulatedSystems = [
         "aarch64-linux"
       ];
@@ -71,7 +71,7 @@ in {
 
   ldPreload = makeTest {
     name = "systemd-binfmt-ld-preload";
-    machine = {
+    nodes.machine = {
       boot.binfmt.emulatedSystems = [
         "aarch64-linux"
       ];
diff --git a/nixpkgs/nixos/tests/systemd-boot.nix b/nixpkgs/nixos/tests/systemd-boot.nix
index 51cfd82e6c4b..039e6bdd9d5a 100644
--- a/nixpkgs/nixos/tests/systemd-boot.nix
+++ b/nixpkgs/nixos/tests/systemd-boot.nix
@@ -20,7 +20,7 @@ in
     name = "systemd-boot";
     meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ];
 
-    machine = common;
+    nodes.machine = common;
 
     testScript = ''
       machine.start()
@@ -44,7 +44,7 @@ in
     name = "systemd-boot-specialisation";
     meta.maintainers = with pkgs.lib.maintainers; [ lukegb ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       specialisation.something.configuration = {};
     };
@@ -67,7 +67,7 @@ in
     name = "systemd-boot-fallback";
     meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.efi.canTouchEfiVariables = mkForce false;
     };
@@ -93,7 +93,7 @@ in
     name = "systemd-boot-update";
     meta.maintainers = with pkgs.lib.maintainers; [ danielfullmer ];
 
-    machine = common;
+    nodes.machine = common;
 
     testScript = ''
       machine.succeed("mount -o remount,rw /boot")
@@ -115,7 +115,7 @@ in
     name = "systemd-boot-memtest86";
     meta.maintainers = with pkgs.lib.maintainers; [ Enzime ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.systemd-boot.memtest86.enable = true;
       nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
@@ -133,7 +133,7 @@ in
     name = "systemd-boot-netbootxyz";
     meta.maintainers = with pkgs.lib.maintainers; [ Enzime ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.systemd-boot.netbootxyz.enable = true;
     };
@@ -148,7 +148,7 @@ in
     name = "systemd-boot-entry-filename";
     meta.maintainers = with pkgs.lib.maintainers; [ Enzime ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.systemd-boot.memtest86.enable = true;
       boot.loader.systemd-boot.memtest86.entryFilename = "apple.conf";
@@ -168,7 +168,7 @@ in
     name = "systemd-boot-extra-entries";
     meta.maintainers = with pkgs.lib.maintainers; [ Enzime ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.systemd-boot.extraEntries = {
         "banana.conf" = ''
@@ -187,7 +187,7 @@ in
     name = "systemd-boot-extra-files";
     meta.maintainers = with pkgs.lib.maintainers; [ Enzime ];
 
-    machine = { pkgs, lib, ... }: {
+    nodes.machine = { pkgs, lib, ... }: {
       imports = [ common ];
       boot.loader.systemd-boot.extraFiles = {
         "efi/fruits/tomato.efi" = pkgs.netbootxyz-efi;
diff --git a/nixpkgs/nixos/tests/systemd-confinement.nix b/nixpkgs/nixos/tests/systemd-confinement.nix
index 3181af309a6e..bde5b770ea50 100644
--- a/nixpkgs/nixos/tests/systemd-confinement.nix
+++ b/nixpkgs/nixos/tests/systemd-confinement.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix {
   name = "systemd-confinement";
 
-  machine = { pkgs, lib, ... }: let
+  nodes.machine = { pkgs, lib, ... }: let
     testServer = pkgs.writeScript "testserver.sh" ''
       #!${pkgs.runtimeShell}
       export PATH=${lib.escapeShellArg "${pkgs.coreutils}/bin"}
diff --git a/nixpkgs/nixos/tests/systemd-coredump.nix b/nixpkgs/nixos/tests/systemd-coredump.nix
new file mode 100644
index 000000000000..62137820878b
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-coredump.nix
@@ -0,0 +1,44 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+
+let
+
+  crasher = pkgs.writeCBin "crasher" "int main;";
+
+  commonConfig = {
+    systemd.services.crasher.serviceConfig = {
+      ExecStart = "${crasher}/bin/crasher";
+      StateDirectory = "crasher";
+      WorkingDirectory = "%S/crasher";
+      Restart = "no";
+    };
+  };
+
+in
+
+{
+  name = "systemd-coredump";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ squalus ];
+  };
+
+  nodes.machine1 = { pkgs, lib, ... }: commonConfig;
+  nodes.machine2 = { pkgs, lib, ... }: lib.recursiveUpdate commonConfig {
+    systemd.coredump.enable = false;
+    systemd.package = pkgs.systemd.override {
+      withCoredump = false;
+    };
+  };
+
+  testScript = ''
+    with subtest("systemd-coredump enabled"):
+      machine1.wait_for_unit("multi-user.target")
+      machine1.wait_for_unit("systemd-coredump.socket")
+      machine1.systemctl("start crasher");
+      machine1.wait_until_succeeds("coredumpctl list | grep crasher", timeout=10)
+      machine1.fail("stat /var/lib/crasher/core")
+
+    with subtest("systemd-coredump disabled"):
+      machine2.systemctl("start crasher");
+      machine2.wait_until_succeeds("stat /var/lib/crasher/core", timeout=10)
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-cryptenroll.nix b/nixpkgs/nixos/tests/systemd-cryptenroll.nix
index 49634ef65672..055ae7d1681f 100644
--- a/nixpkgs/nixos/tests/systemd-cryptenroll.nix
+++ b/nixpkgs/nixos/tests/systemd-cryptenroll.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ ymatsiuk ];
   };
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     environment.systemPackages = [ pkgs.cryptsetup ];
     virtualisation = {
       emptyDiskImages = [ 512 ];
diff --git a/nixpkgs/nixos/tests/systemd-escaping.nix b/nixpkgs/nixos/tests/systemd-escaping.nix
index 7f93eb5e4f70..29d2ed1aa352 100644
--- a/nixpkgs/nixos/tests/systemd-escaping.nix
+++ b/nixpkgs/nixos/tests/systemd-escaping.nix
@@ -14,7 +14,7 @@ in
 {
   name = "systemd-escaping";
 
-  machine = { pkgs, lib, utils, ... }: {
+  nodes.machine = { pkgs, lib, utils, ... }: {
     systemd.services.echo =
       assert !(builtins.tryEval (utils.escapeSystemdExecArgs [ [] ])).success;
       assert !(builtins.tryEval (utils.escapeSystemdExecArgs [ {} ])).success;
diff --git a/nixpkgs/nixos/tests/systemd-initrd-btrfs-raid.nix b/nixpkgs/nixos/tests/systemd-initrd-btrfs-raid.nix
new file mode 100644
index 000000000000..40fd2d4dc611
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-initrd-btrfs-raid.nix
@@ -0,0 +1,45 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "systemd-initrd-btrfs-raid";
+
+  nodes.machine = { pkgs, ... }: {
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 512 512 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+    boot.loader.efi.canTouchEfiVariables = true;
+
+    environment.systemPackages = with pkgs; [ btrfs-progs ];
+    boot.initrd.systemd = {
+      enable = true;
+      emergencyAccess = true;
+    };
+
+    specialisation.boot-btrfs-raid.configuration = {
+      fileSystems = lib.mkVMOverride {
+        "/".fsType = lib.mkForce "btrfs";
+      };
+      virtualisation.bootDevice = "/dev/vdc";
+    };
+  };
+
+  testScript = ''
+    # Create RAID
+    machine.succeed("mkfs.btrfs -d raid0 /dev/vdc /dev/vdd")
+    machine.succeed("mkdir -p /mnt && mount /dev/vdc /mnt && echo hello > /mnt/test && umount /mnt")
+
+    # Boot from the RAID
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-btrfs-raid.conf")
+    machine.succeed("sync")
+    machine.crash()
+    machine.wait_for_unit("multi-user.target")
+
+    # Ensure we have successfully booted from the RAID
+    assert "(initrd)" in machine.succeed("systemd-analyze")  # booted with systemd in stage 1
+    assert "/dev/vdc on / type btrfs" in machine.succeed("mount")
+    assert "hello" in machine.succeed("cat /test")
+    assert "Total devices 2" in machine.succeed("btrfs filesystem show")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix
new file mode 100644
index 000000000000..25c0c5bd866d
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-keyfile.nix
@@ -0,0 +1,53 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: let
+
+  keyfile = pkgs.writeText "luks-keyfile" ''
+    MIGHAoGBAJ4rGTSo/ldyjQypd0kuS7k2OSsmQYzMH6TNj3nQ/vIUjDn7fqa3slt2
+    gV6EK3TmTbGc4tzC1v4SWx2m+2Bjdtn4Fs4wiBwn1lbRdC6i5ZYCqasTWIntWn+6
+    FllUkMD5oqjOR/YcboxG8Z3B5sJuvTP9llsF+gnuveWih9dpbBr7AgEC
+  '';
+
+in {
+  name = "systemd-initrd-luks-keyfile";
+
+  nodes.machine = { pkgs, ... }: {
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 512 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+
+    environment.systemPackages = with pkgs; [ cryptsetup ];
+    boot.initrd.systemd = {
+      enable = true;
+      emergencyAccess = true;
+    };
+
+    specialisation.boot-luks.configuration = {
+      boot.initrd.luks.devices = lib.mkVMOverride {
+        cryptroot = {
+          device = "/dev/vdc";
+          keyFile = "/etc/cryptroot.key";
+        };
+      };
+      virtualisation.bootDevice = "/dev/mapper/cryptroot";
+      boot.initrd.secrets."/etc/cryptroot.key" = keyfile;
+    };
+  };
+
+  testScript = ''
+    # Create encrypted volume
+    machine.wait_for_unit("multi-user.target")
+    machine.succeed("cryptsetup luksFormat -q --iter-time=1 -d ${keyfile} /dev/vdc")
+
+    # Boot from the encrypted disk
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
+    machine.succeed("sync")
+    machine.crash()
+
+    # Boot and decrypt the disk
+    machine.wait_for_unit("multi-user.target")
+    assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix b/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix
new file mode 100644
index 000000000000..e8e651f7b35f
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-initrd-luks-password.nix
@@ -0,0 +1,48 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "systemd-initrd-luks-password";
+
+  nodes.machine = { pkgs, ... }: {
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 512 512 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+
+    environment.systemPackages = with pkgs; [ cryptsetup ];
+    boot.initrd.systemd = {
+      enable = true;
+      emergencyAccess = true;
+    };
+
+    specialisation.boot-luks.configuration = {
+      boot.initrd.luks.devices = lib.mkVMOverride {
+        # We have two disks and only type one password - key reuse is in place
+        cryptroot.device = "/dev/vdc";
+        cryptroot2.device = "/dev/vdd";
+      };
+      virtualisation.bootDevice = "/dev/mapper/cryptroot";
+    };
+  };
+
+  testScript = ''
+    # Create encrypted volume
+    machine.wait_for_unit("multi-user.target")
+    machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
+    machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdd -")
+
+    # Boot from the encrypted disk
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
+    machine.succeed("sync")
+    machine.crash()
+
+    # Boot and decrypt the disk
+    machine.start()
+    machine.wait_for_console_text("Please enter passphrase for disk cryptroot")
+    machine.send_console("supersecret\n")
+    machine.wait_for_unit("multi-user.target")
+
+    assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-initrd-simple.nix b/nixpkgs/nixos/tests/systemd-initrd-simple.nix
new file mode 100644
index 000000000000..5d98114304b7
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-initrd-simple.nix
@@ -0,0 +1,44 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "systemd-initrd-simple";
+
+  nodes.machine = { pkgs, ... }: {
+    boot.initrd.systemd = {
+      enable = true;
+      emergencyAccess = true;
+    };
+    fileSystems = lib.mkVMOverride {
+      "/".autoResize = true;
+    };
+  };
+
+  testScript = ''
+    import subprocess
+
+    with subtest("handover to stage-2 systemd works"):
+        machine.wait_for_unit("multi-user.target")
+        machine.succeed("systemd-analyze | grep -q '(initrd)'")  # direct handover
+        machine.succeed("touch /testfile")  # / is writable
+        machine.fail("touch /nix/store/testfile")  # /nix/store is not writable
+        # Special filesystems are mounted by systemd
+        machine.succeed("[ -e /run/booted-system ]") # /run
+        machine.succeed("[ -e /sys/class ]") # /sys
+        machine.succeed("[ -e /dev/null ]") # /dev
+        machine.succeed("[ -e /proc/1 ]") # /proc
+        # stage-2-init mounted more special filesystems
+        machine.succeed("[ -e /dev/shm ]") # /dev/shm
+        machine.succeed("[ -e /dev/pts/ptmx ]") # /dev/pts
+        machine.succeed("[ -e /run/keys ]") # /run/keys
+
+
+    with subtest("growfs works"):
+        oldAvail = machine.succeed("df --output=avail / | sed 1d")
+        machine.shutdown()
+
+        subprocess.check_call(["qemu-img", "resize", "vm-state-machine/machine.qcow2", "+1G"])
+
+        machine.start()
+        newAvail = machine.succeed("df --output=avail / | sed 1d")
+
+        assert int(oldAvail) < int(newAvail), "File system did not grow"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-initrd-swraid.nix b/nixpkgs/nixos/tests/systemd-initrd-swraid.nix
new file mode 100644
index 000000000000..28a0fb3192ae
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-initrd-swraid.nix
@@ -0,0 +1,50 @@
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "systemd-initrd-swraid";
+
+  nodes.machine = { pkgs, ... }: {
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 512 512 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+    boot.loader.efi.canTouchEfiVariables = true;
+
+    environment.systemPackages = with pkgs; [ mdadm e2fsprogs ]; # for mdadm and mkfs.ext4
+    boot.initrd = {
+      systemd = {
+        enable = true;
+        emergencyAccess = true;
+      };
+      services.swraid = {
+        enable = true;
+        mdadmConf = ''
+          ARRAY /dev/md0 devices=/dev/vdc,/dev/vdd
+        '';
+      };
+      kernelModules = [ "raid0" ];
+    };
+
+    specialisation.boot-swraid.configuration.virtualisation.bootDevice = "/dev/disk/by-label/testraid";
+  };
+
+  testScript = ''
+    # Create RAID
+    machine.succeed("mdadm --create --force /dev/md0 -n 2 --level=raid0 /dev/vdc /dev/vdd")
+    machine.succeed("mkfs.ext4 -L testraid /dev/md0")
+    machine.succeed("mkdir -p /mnt && mount /dev/md0 /mnt && echo hello > /mnt/test && umount /mnt")
+
+    # Boot from the RAID
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-swraid.conf")
+    machine.succeed("sync")
+    machine.crash()
+    machine.wait_for_unit("multi-user.target")
+
+    # Ensure we have successfully booted from the RAID
+    assert "(initrd)" in machine.succeed("systemd-analyze")  # booted with systemd in stage 1
+    assert "/dev/md0 on / type ext4" in machine.succeed("mount")
+    assert "hello" in machine.succeed("cat /test")
+    assert "md0" in machine.succeed("cat /proc/mdstat")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd-journal.nix b/nixpkgs/nixos/tests/systemd-journal.nix
index 6ab7c7246318..d2063a3b9a44 100644
--- a/nixpkgs/nixos/tests/systemd-journal.nix
+++ b/nixpkgs/nixos/tests/systemd-journal.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     maintainers = [ lewo ];
   };
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     services.journald.enableHttpGateway = true;
   };
 
diff --git a/nixpkgs/nixos/tests/systemd-machinectl.nix b/nixpkgs/nixos/tests/systemd-machinectl.nix
index 4fc5864357c0..5c7926e24abf 100644
--- a/nixpkgs/nixos/tests/systemd-machinectl.nix
+++ b/nixpkgs/nixos/tests/systemd-machinectl.nix
@@ -28,18 +28,17 @@ import ./make-test-python.nix (
   {
     name = "systemd-machinectl";
 
-    machine = { lib, ... }: {
+    nodes.machine = { lib, ... }: {
       # use networkd to obtain systemd network setup
       networking.useNetworkd = true;
       networking.useDHCP = false;
-      services.resolved.enable = false;
-
-      # open DHCP server on interface to container
-      networking.firewall.trustedInterfaces = [ "ve-+" ];
 
       # do not try to access cache.nixos.org
       nix.settings.substituters = lib.mkForce [ ];
 
+      # auto-start container
+      systemd.targets.machines.wants = [ "systemd-nspawn@${containerName}.service" ];
+
       virtualisation.additionalPaths = [ containerSystem ];
     };
 
@@ -60,11 +59,17 @@ import ./make-test-python.nix (
       machine.succeed("machinectl start ${containerName}");
       machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
 
+      # Test nss_mymachines without nscd
+      machine.succeed('LD_LIBRARY_PATH="/run/current-system/sw/lib" getent -s hosts:mymachines hosts ${containerName}');
+
+      # Test nss_mymachines via nscd
+      machine.succeed("getent hosts ${containerName}");
+
       # Test systemd-nspawn network configuration
       machine.succeed("ping -n -c 1 ${containerName}");
 
       # Test systemd-nspawn uses a user namespace
-      machine.succeed("test `stat ${containerRoot}/var/empty -c %u%g` != 00");
+      machine.succeed("test $(machinectl status ${containerName} | grep 'UID Shift: ' | wc -l) = 1")
 
       # Test systemd-nspawn reboot
       machine.succeed("machinectl shell ${containerName} /run/current-system/sw/bin/reboot");
@@ -74,8 +79,17 @@ import ./make-test-python.nix (
       machine.succeed("machinectl reboot ${containerName}");
       machine.wait_until_succeeds("systemctl -M ${containerName} is-active default.target");
 
+      # Restart machine
+      machine.shutdown()
+      machine.start()
+      machine.wait_for_unit("default.target");
+
+      # Test auto-start
+      machine.succeed("machinectl show ${containerName}")
+
       # Test machinectl stop
       machine.succeed("machinectl stop ${containerName}");
+      machine.wait_until_succeeds("test $(systemctl is-active systemd-nspawn@${containerName}) = inactive");
 
       # Show to to delete the container
       machine.succeed("chattr -i ${containerRoot}/var/empty");
diff --git a/nixpkgs/nixos/tests/systemd-misc.nix b/nixpkgs/nixos/tests/systemd-misc.nix
index e416baa8b5f5..0ddd51100463 100644
--- a/nixpkgs/nixos/tests/systemd-misc.nix
+++ b/nixpkgs/nixos/tests/systemd-misc.nix
@@ -31,7 +31,7 @@ in
 {
   name = "systemd-misc";
 
-  machine = { pkgs, lib, ... }: {
+  nodes.machine = { pkgs, lib, ... }: {
     boot.extraSystemdUnitPaths = [ "/etc/systemd-rw/system" ];
 
     users.users.limited = {
diff --git a/nixpkgs/nixos/tests/systemd-networkd-vrf.nix b/nixpkgs/nixos/tests/systemd-networkd-vrf.nix
index 8a1580fc2ada..3c18f788e927 100644
--- a/nixpkgs/nixos/tests/systemd-networkd-vrf.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd-vrf.nix
@@ -138,18 +138,18 @@ in {
   };
 
   testScript = ''
-    def compare_tables(expected, actual):
-        assert (
-            expected == actual
-        ), """
-        Routing tables don't match!
-        Expected:
-          {}
-        Actual:
-          {}
-        """.format(
-            expected, actual
-        )
+    import json
+
+    def compare(raw_json, to_compare):
+        data = json.loads(raw_json)
+        assert len(raw_json) >= len(to_compare)
+        for i, row in enumerate(to_compare):
+            actual = data[i]
+            assert len(row.keys()) > 0
+            for key, value in row.items():
+                assert value == actual[key], f"""
+                  In entry {i}, value {key}: got: {actual[key]}, expected {value}
+                """
 
 
     start_all()
@@ -159,23 +159,18 @@ in {
     node2.wait_for_unit("network.target")
     node3.wait_for_unit("network.target")
 
-    # NOTE: please keep in mind that the trailing whitespaces in the following strings
-    # are intentional as the output is compared against the raw `iproute2`-output.
-    # editorconfig-checker-disable
     client_ipv4_table = """
-    192.168.1.2 dev vrf1 proto static metric 100 
+    192.168.1.2 dev vrf1 proto static metric 100\x20
     192.168.2.3 dev vrf2 proto static metric 100
     """.strip()
     vrf1_table = """
-    broadcast 192.168.1.0 dev eth1 proto kernel scope link src 192.168.1.1 
-    192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.1 
-    local 192.168.1.1 dev eth1 proto kernel scope host src 192.168.1.1 
+    192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.1\x20
+    local 192.168.1.1 dev eth1 proto kernel scope host src 192.168.1.1\x20
     broadcast 192.168.1.255 dev eth1 proto kernel scope link src 192.168.1.1
     """.strip()
     vrf2_table = """
-    broadcast 192.168.2.0 dev eth2 proto kernel scope link src 192.168.2.1 
-    192.168.2.0/24 dev eth2 proto kernel scope link src 192.168.2.1 
-    local 192.168.2.1 dev eth2 proto kernel scope host src 192.168.2.1 
+    192.168.2.0/24 dev eth2 proto kernel scope link src 192.168.2.1\x20
+    local 192.168.2.1 dev eth2 proto kernel scope host src 192.168.2.1\x20
     broadcast 192.168.2.255 dev eth2 proto kernel scope link src 192.168.2.1
     """.strip()
     # editorconfig-checker-enable
@@ -183,14 +178,28 @@ in {
     # Check that networkd properly configures the main routing table
     # and the routing tables for the VRF.
     with subtest("check vrf routing tables"):
-        compare_tables(
-            client_ipv4_table, client.succeed("ip -4 route list | head -n2").strip()
+        compare(
+            client.succeed("ip --json -4 route list"),
+            [
+                {"dst": "192.168.1.2", "dev": "vrf1", "metric": 100},
+                {"dst": "192.168.2.3", "dev": "vrf2", "metric": 100}
+            ]
         )
-        compare_tables(
-            vrf1_table, client.succeed("ip -4 route list table 23 | head -n4").strip()
+        compare(
+            client.succeed("ip --json -4 route list table 23"),
+            [
+                {"dst": "192.168.1.0/24", "dev": "eth1", "prefsrc": "192.168.1.1"},
+                {"type": "local", "dst": "192.168.1.1", "dev": "eth1", "prefsrc": "192.168.1.1"},
+                {"type": "broadcast", "dev": "eth1", "prefsrc": "192.168.1.1", "dst": "192.168.1.255"}
+            ]
         )
-        compare_tables(
-            vrf2_table, client.succeed("ip -4 route list table 42 | head -n4").strip()
+        compare(
+            client.succeed("ip --json -4 route list table 42"),
+            [
+                {"dst": "192.168.2.0/24", "dev": "eth2", "prefsrc": "192.168.2.1"},
+                {"type": "local", "dst": "192.168.2.1", "dev": "eth2", "prefsrc": "192.168.2.1"},
+                {"type": "broadcast", "dev": "eth2", "prefsrc": "192.168.2.1", "dst": "192.168.2.255"}
+            ]
         )
 
     # Ensure that other nodes are reachable via ICMP through the VRF.
diff --git a/nixpkgs/nixos/tests/systemd-networkd.nix b/nixpkgs/nixos/tests/systemd-networkd.nix
index 7faeae3704ec..6c423f4140b1 100644
--- a/nixpkgs/nixos/tests/systemd-networkd.nix
+++ b/nixpkgs/nixos/tests/systemd-networkd.nix
@@ -8,6 +8,9 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: {
       environment.systemPackages = with pkgs; [ wireguard-tools ];
       systemd.network = {
         enable = true;
+        config = {
+          routeTables.custom = 23;
+        };
         netdevs = {
           "90-wg0" = {
             netdevConfig = { Kind = "wireguard"; Name = "wg0"; };
@@ -39,6 +42,7 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: {
             address = [ "10.0.0.${nodeId}/32" ];
             routes = [
               { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; }; }
+              { routeConfig = { Gateway = "10.0.0.${nodeId}"; Destination = "10.0.0.0/24"; Table = "custom"; }; }
             ];
           };
           "30-eth1" = {
@@ -88,6 +92,12 @@ testScript = ''
     node2.wait_for_unit("systemd-networkd-wait-online.service")
 
     # ================================
+    # Networkd Config
+    # ================================
+    node1.succeed("grep RouteTable=custom:23 /etc/systemd/networkd.conf")
+    node1.succeed("sudo ip route show table custom | grep '10.0.0.0/24 via 10.0.0.1 dev wg0 proto static'")
+
+    # ================================
     # Wireguard
     # ================================
     node1.succeed("ping -c 5 10.0.0.2")
diff --git a/nixpkgs/nixos/tests/systemd-nspawn.nix b/nixpkgs/nixos/tests/systemd-nspawn.nix
index 5bf55060d2e0..bc77ee2a4d15 100644
--- a/nixpkgs/nixos/tests/systemd-nspawn.nix
+++ b/nixpkgs/nixos/tests/systemd-nspawn.nix
@@ -10,8 +10,8 @@ let
       Key-Length: 1024
       Subkey-Type: ELG-E
       Subkey-Length: 1024
-      Name-Real: Joe Tester
-      Name-Email: joe@foo.bar
+      Name-Real: Bob Foobar
+      Name-Email: bob@foo.bar
       Expire-Date: 0
       # Do a commit here, so that we can later print "done"
       %commit
@@ -19,14 +19,21 @@ let
     EOF
     gpg --batch --generate-key foo
     rm $out/S.gpg-agent $out/S.gpg-agent.*
-    gpg --export joe@foo.bar -a > $out/pubkey.gpg
+    gpg --export bob@foo.bar -a > $out/pubkey.gpg
   '');
 
   nspawnImages = (pkgs.runCommand "localhost" { buildInputs = [ pkgs.coreutils pkgs.gnupg ]; } ''
     mkdir -p $out
     cd $out
+
+    # produce a testimage.raw
     dd if=/dev/urandom of=$out/testimage.raw bs=$((1024*1024+7)) count=5
-    sha256sum testimage.raw > SHA256SUMS
+
+    # produce a testimage2.tar.xz, containing the hello store path
+    tar cvJpf testimage2.tar.xz ${pkgs.hello}
+
+    # produce signature(s)
+    sha256sum testimage* > SHA256SUMS
     export GNUPGHOME="$(mktemp -d)"
     cp -R ${gpgKeyring}/* $GNUPGHOME
     gpg --batch --sign --detach-sign --output SHA256SUMS.gpg SHA256SUMS
@@ -56,5 +63,9 @@ in {
     client.succeed(
         "cmp /var/lib/machines/testimage.raw ${nspawnImages}/testimage.raw"
     )
+    client.succeed("machinectl pull-tar --verify=signature http://server/testimage2.tar.xz")
+    client.succeed(
+        "cmp /var/lib/machines/testimage2/${pkgs.hello}/bin/hello ${pkgs.hello}/bin/hello"
+    )
   '';
 })
diff --git a/nixpkgs/nixos/tests/systemd-shutdown.nix b/nixpkgs/nixos/tests/systemd-shutdown.nix
new file mode 100644
index 000000000000..688cd6dd2c17
--- /dev/null
+++ b/nixpkgs/nixos/tests/systemd-shutdown.nix
@@ -0,0 +1,26 @@
+import ./make-test-python.nix ({ pkgs, systemdStage1 ? false, ...} : let
+  msg = "Shutting down NixOS";
+in {
+  name = "systemd-shutdown";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ das_j ];
+  };
+
+  nodes.machine = {
+    imports = [ ../modules/profiles/minimal.nix ];
+    systemd.shutdownRamfs.contents."/etc/systemd/system-shutdown/shutdown-message".source = pkgs.writeShellScript "shutdown-message" ''
+      echo "${msg}"
+    '';
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    # .shutdown() would wait for the machine to power off
+    machine.succeed("systemctl poweroff")
+    # Message printed by systemd-shutdown
+    machine.wait_for_console_text("Unmounting '/oldroot'")
+    machine.wait_for_console_text("${msg}")
+    # Don't try to sync filesystems
+    machine.booted = False
+  '';
+})
diff --git a/nixpkgs/nixos/tests/systemd.nix b/nixpkgs/nixos/tests/systemd.nix
index f86daa5eea97..3317823e03f7 100644
--- a/nixpkgs/nixos/tests/systemd.nix
+++ b/nixpkgs/nixos/tests/systemd.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ... }: {
   name = "systemd";
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     imports = [ common/user-account.nix common/x11.nix ];
 
     virtualisation.emptyDiskImages = [ 512 512 ];
@@ -192,5 +192,9 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     with subtest("systemd per-unit accounting works"):
         assert "IP traffic received: 84B" in output_ping
         assert "IP traffic sent: 84B" in output_ping
+
+    with subtest("systemd environment is properly set"):
+        machine.systemctl("daemon-reexec")  # Rewrites /proc/1/environ
+        machine.succeed("grep -q TZDIR=/etc/zoneinfo /proc/1/environ")
   '';
 })
diff --git a/nixpkgs/nixos/tests/taskserver.nix b/nixpkgs/nixos/tests/taskserver.nix
index f34782c7059a..b2bd421e231f 100644
--- a/nixpkgs/nixos/tests/taskserver.nix
+++ b/nixpkgs/nixos/tests/taskserver.nix
@@ -63,6 +63,7 @@ in {
     server = {
       services.taskserver.enable = true;
       services.taskserver.listenHost = "::";
+      services.taskserver.openFirewall = true;
       services.taskserver.fqdn = "server";
       services.taskserver.organisations = {
         testOrganisation.users = [ "alice" "foo" ];
diff --git a/nixpkgs/nixos/tests/telegraf.nix b/nixpkgs/nixos/tests/telegraf.nix
index d99680ce2c3c..c3cdb1645213 100644
--- a/nixpkgs/nixos/tests/telegraf.nix
+++ b/nixpkgs/nixos/tests/telegraf.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ mic92 ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     services.telegraf.enable = true;
     services.telegraf.environmentFiles = [(pkgs.writeText "secrets" ''
       SECRET=example
diff --git a/nixpkgs/nixos/tests/teleport.nix b/nixpkgs/nixos/tests/teleport.nix
index 15b16e44409d..34bf1bc0c70d 100644
--- a/nixpkgs/nixos/tests/teleport.nix
+++ b/nixpkgs/nixos/tests/teleport.nix
@@ -72,9 +72,9 @@ in
     nodes = { inherit minimal; };
 
     testScript = ''
-      minimal.wait_for_open_port("3025")
-      minimal.wait_for_open_port("3080")
-      minimal.wait_for_open_port("3022")
+      minimal.wait_for_open_port(3025)
+      minimal.wait_for_open_port(3080)
+      minimal.wait_for_open_port(3022)
     '';
   };
 
@@ -86,12 +86,12 @@ in
 
     testScript = ''
       with subtest("teleport ready"):
-          server.wait_for_open_port("3025")
-          client.wait_for_open_port("3022")
+          server.wait_for_open_port(3025)
+          client.wait_for_open_port(3022)
 
       with subtest("check applied configuration"):
           server.wait_until_succeeds("tctl get nodes --format=json | ${pkgs.jq}/bin/jq -e '.[] | select(.spec.hostname==\"client\") | .metadata.labels.role==\"client\"'")
-          server.wait_for_open_port("3000")
+          server.wait_for_open_port(3000)
           client.succeed("journalctl -u teleport.service --grep='DEBU'")
           server.succeed("journalctl -u teleport.service --grep='Starting teleport in insecure mode.'")
     '';
diff --git a/nixpkgs/nixos/tests/terminal-emulators.nix b/nixpkgs/nixos/tests/terminal-emulators.nix
index 6ea0f1c18725..c724608b9155 100644
--- a/nixpkgs/nixos/tests/terminal-emulators.nix
+++ b/nixpkgs/nixos/tests/terminal-emulators.nix
@@ -197,6 +197,7 @@ in mapAttrs (name: { pkg, executable ? name, cmd ? "SHELL=$command ${executable}
 
     with subtest("have the terminal display a colour"):
         # We run this command in the background
+        assert machine.shell is not None
         machine.shell.send(b"(run-in-this-term display-colour |& systemd-cat -t terminal) &\n")
 
         with machine.nested("Waiting for the screen to have pink on it:"):
diff --git a/nixpkgs/nixos/tests/tinywl.nix b/nixpkgs/nixos/tests/tinywl.nix
index 8fb87b533306..411cdb1f6419 100644
--- a/nixpkgs/nixos/tests/tinywl.nix
+++ b/nixpkgs/nixos/tests/tinywl.nix
@@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
       maintainers = with lib.maintainers; [ primeos ];
     };
 
-    machine = { config, ... }: {
+    nodes.machine = { config, ... }: {
       # Automatically login on tty1 as a normal user:
       imports = [ ./common/user-account.nix ];
       services.getty.autologinUser = "alice";
diff --git a/nixpkgs/nixos/tests/tomcat.nix b/nixpkgs/nixos/tests/tomcat.nix
index e383f224e3d1..4cfb3cc5a7d8 100644
--- a/nixpkgs/nixos/tests/tomcat.nix
+++ b/nixpkgs/nixos/tests/tomcat.nix
@@ -3,7 +3,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
 {
   name = "tomcat";
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     services.tomcat.enable = true;
   };
 
diff --git a/nixpkgs/nixos/tests/traefik.nix b/nixpkgs/nixos/tests/traefik.nix
index 1d6c0a479ef6..989ec390c060 100644
--- a/nixpkgs/nixos/tests/traefik.nix
+++ b/nixpkgs/nixos/tests/traefik.nix
@@ -11,14 +11,20 @@ import ./make-test-python.nix ({ pkgs, ... }: {
       environment.systemPackages = [ pkgs.curl ];
     };
     traefik = { config, pkgs, ... }: {
-      virtualisation.oci-containers.containers.nginx = {
-        extraOptions = [
-          "-l" "traefik.enable=true"
-          "-l" "traefik.http.routers.nginx.entrypoints=web"
-          "-l" "traefik.http.routers.nginx.rule=Host(`nginx.traefik.test`)"
-        ];
-        image = "nginx-container";
-        imageFile = pkgs.dockerTools.examples.nginx;
+      virtualisation.oci-containers = {
+        backend = "docker";
+        containers.nginx = {
+          extraOptions = [
+            "-l"
+            "traefik.enable=true"
+            "-l"
+            "traefik.http.routers.nginx.entrypoints=web"
+            "-l"
+            "traefik.http.routers.nginx.rule=Host(`nginx.traefik.test`)"
+          ];
+          image = "nginx-container";
+          imageFile = pkgs.dockerTools.examples.nginx;
+        };
       };
 
       networking.firewall.allowedTCPPorts = [ 80 ];
diff --git a/nixpkgs/nixos/tests/transmission.nix b/nixpkgs/nixos/tests/transmission.nix
index 7e2648804de2..b69ddd84d009 100644
--- a/nixpkgs/nixos/tests/transmission.nix
+++ b/nixpkgs/nixos/tests/transmission.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ coconnor ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     networking.firewall.allowedTCPPorts = [ 9091 ];
diff --git a/nixpkgs/nixos/tests/tsm-client-gui.nix b/nixpkgs/nixos/tests/tsm-client-gui.nix
index e4bcd344a895..e11501da53d0 100644
--- a/nixpkgs/nixos/tests/tsm-client-gui.nix
+++ b/nixpkgs/nixos/tests/tsm-client-gui.nix
@@ -10,7 +10,7 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
 
   enableOCR = true;
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ./common/x11.nix ];
     programs.tsmClient = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/tuptime.nix b/nixpkgs/nixos/tests/tuptime.nix
index 6d37e3069839..93410de7bdf5 100644
--- a/nixpkgs/nixos/tests/tuptime.nix
+++ b/nixpkgs/nixos/tests/tuptime.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ evils ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
     services.tuptime.enable = true;
   };
diff --git a/nixpkgs/nixos/tests/turbovnc-headless-server.nix b/nixpkgs/nixos/tests/turbovnc-headless-server.nix
index 7d705c56ecf3..1dbf9297c813 100644
--- a/nixpkgs/nixos/tests/turbovnc-headless-server.nix
+++ b/nixpkgs/nixos/tests/turbovnc-headless-server.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
     maintainers = with lib.maintainers; [ nh2 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
 
     environment.systemPackages = with pkgs; [
       glxinfo
diff --git a/nixpkgs/nixos/tests/tuxguitar.nix b/nixpkgs/nixos/tests/tuxguitar.nix
index 63a7b6c7dec9..037f489e5448 100644
--- a/nixpkgs/nixos/tests/tuxguitar.nix
+++ b/nixpkgs/nixos/tests/tuxguitar.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ asbachb ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
diff --git a/nixpkgs/nixos/tests/udisks2.nix b/nixpkgs/nixos/tests/udisks2.nix
index 6c4b71aaa2ed..6afb200f8566 100644
--- a/nixpkgs/nixos/tests/udisks2.nix
+++ b/nixpkgs/nixos/tests/udisks2.nix
@@ -15,7 +15,7 @@ in
     maintainers = [ eelco ];
   };
 
-  machine =
+  nodes.machine =
     { ... }:
     { services.udisks2.enable = true;
       imports = [ ./common/user-account.nix ];
diff --git a/nixpkgs/nixos/tests/uptermd.nix b/nixpkgs/nixos/tests/uptermd.nix
new file mode 100644
index 000000000000..429e3c9dd5ff
--- /dev/null
+++ b/nixpkgs/nixos/tests/uptermd.nix
@@ -0,0 +1,65 @@
+import ./make-test-python.nix ({ pkgs, ...}:
+
+let
+  client = {pkgs, ...}:{
+    environment.systemPackages = [ pkgs.upterm ];
+  };
+in
+{
+  name = "uptermd";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ fleaz ];
+  };
+
+  nodes = {
+    server = {config, ...}: {
+      services.uptermd = {
+        enable = true;
+        openFirewall = true;
+        port = 1337;
+      };
+    };
+    client1 = client;
+    client2 = client;
+  };
+
+
+  testScript = ''
+    start_all()
+
+    server.wait_for_unit("uptermd.service")
+    server.wait_for_unit("network-online.target")
+
+    # wait for upterm port to be reachable
+    client1.wait_until_succeeds("nc -z -v server 1337")
+
+    # Add SSH hostkeys from the server to both clients
+    # uptermd needs an '@cert-authority entry so we need to modify the known_hosts file
+    client1.execute("mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls")
+    client1.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts")
+    client2.execute("mkdir -p ~/.ssh && ssh -o StrictHostKeyChecking=no -p 1337 server ls")
+    client2.execute("echo @cert-authority $(cat ~/.ssh/known_hosts) > ~/.ssh/known_hosts")
+
+    client1.wait_for_unit("multi-user.target")
+    client1.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
+    client1.wait_until_tty_matches("1", "login: ")
+    client1.send_chars("root\n")
+    client1.wait_until_succeeds("pgrep -u root bash")
+
+    client1.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519")
+    client1.send_chars("TERM=xterm upterm host --server ssh://server:1337 --force-command hostname -- bash > /tmp/session-details\n")
+    client1.wait_for_file("/tmp/session-details")
+    client1.send_key("q")
+
+    # uptermd can't connect if we don't have a keypair
+    client2.execute("ssh-keygen -t ed25519 -N \"\" -f /root/.ssh/id_ed25519")
+
+    # Grep the ssh connect command from the output of 'upterm host'
+    ssh_command = client1.succeed("grep 'SSH Session' /tmp/session-details | cut -d':' -f2-").strip()
+
+    # Connect with client2. Because we used '--force-command hostname' we should get "client1" as the output
+    output = client2.succeed(ssh_command)
+
+    assert output.strip() == "client1"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/usbguard.nix b/nixpkgs/nixos/tests/usbguard.nix
index bb707bdbf702..d6d3a80c5d23 100644
--- a/nixpkgs/nixos/tests/usbguard.nix
+++ b/nixpkgs/nixos/tests/usbguard.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ tnias ];
   };
 
-  machine =
+  nodes.machine =
     { ... }:
     {
       services.usbguard = {
diff --git a/nixpkgs/nixos/tests/user-activation-scripts.nix b/nixpkgs/nixos/tests/user-activation-scripts.nix
index 0de8664c5ef0..5df072ce0508 100644
--- a/nixpkgs/nixos/tests/user-activation-scripts.nix
+++ b/nixpkgs/nixos/tests/user-activation-scripts.nix
@@ -2,7 +2,7 @@ import ./make-test-python.nix ({ lib, ... }: {
   name = "user-activation-scripts";
   meta = with lib.maintainers; { maintainers = [ chkno ]; };
 
-  machine = {
+  nodes.machine = {
     system.userActivationScripts.foo = "mktemp ~/user-activation-ran.XXXXXX";
     users.users.alice = {
       initialPassword = "pass1";
@@ -19,9 +19,9 @@ import ./make-test-python.nix ({ lib, ... }: {
 
     machine.wait_for_unit("multi-user.target")
     machine.wait_for_unit("getty@tty1.service")
-    machine.wait_until_tty_matches(1, "login: ")
+    machine.wait_until_tty_matches("1", "login: ")
     machine.send_chars("alice\n")
-    machine.wait_until_tty_matches(1, "Password: ")
+    machine.wait_until_tty_matches("1", "Password: ")
     machine.send_chars("pass1\n")
     machine.send_chars("touch login-ok\n")
     machine.wait_for_file("/home/alice/login-ok")
diff --git a/nixpkgs/nixos/tests/user-home-mode.nix b/nixpkgs/nixos/tests/user-home-mode.nix
new file mode 100644
index 000000000000..070cb0b75cc9
--- /dev/null
+++ b/nixpkgs/nixos/tests/user-home-mode.nix
@@ -0,0 +1,27 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "user-home-mode";
+  meta = with lib.maintainers; { maintainers = [ fbeffa ]; };
+
+  nodes.machine = {
+    users.users.alice = {
+      initialPassword = "pass1";
+      isNormalUser = true;
+    };
+    users.users.bob = {
+      initialPassword = "pass2";
+      isNormalUser = true;
+      homeMode = "750";
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("getty@tty1.service")
+    machine.wait_until_tty_matches("1", "login: ")
+    machine.send_chars("alice\n")
+    machine.wait_until_tty_matches("1", "Password: ")
+    machine.send_chars("pass1\n")
+    machine.succeed('[ "$(stat -c %a /home/alice)" == "700" ]')
+    machine.succeed('[ "$(stat -c %a /home/bob)" == "750" ]')
+  '';
+})
diff --git a/nixpkgs/nixos/tests/uwsgi.nix b/nixpkgs/nixos/tests/uwsgi.nix
index 80dcde324aad..62da9e0a7168 100644
--- a/nixpkgs/nixos/tests/uwsgi.nix
+++ b/nixpkgs/nixos/tests/uwsgi.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
     maintainers = [ lnl7 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     users.users.hello  =
       { isSystemUser = true;
         group = "hello";
diff --git a/nixpkgs/nixos/tests/v2ray.nix b/nixpkgs/nixos/tests/v2ray.nix
index 4808e149d31e..fb36ea8557d5 100644
--- a/nixpkgs/nixos/tests/v2ray.nix
+++ b/nixpkgs/nixos/tests/v2ray.nix
@@ -57,7 +57,7 @@ in {
   meta = with lib.maintainers; {
     maintainers = [ servalcatty ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.curl ];
     services.v2ray = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/vault-dev.nix b/nixpkgs/nixos/tests/vault-dev.nix
new file mode 100644
index 000000000000..ba9a1015cc13
--- /dev/null
+++ b/nixpkgs/nixos/tests/vault-dev.nix
@@ -0,0 +1,35 @@
+import ./make-test-python.nix ({ pkgs, ... }:
+{
+  name = "vault-dev";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ lnl7 mic92 ];
+  };
+  nodes.machine = { pkgs, config, ... }: {
+    environment.systemPackages = [ pkgs.vault ];
+    environment.variables.VAULT_ADDR = "http://127.0.0.1:8200";
+    environment.variables.VAULT_TOKEN = "phony-secret";
+
+    services.vault = {
+      enable = true;
+      dev = true;
+      devRootTokenID = config.environment.variables.VAULT_TOKEN;
+    };
+  };
+
+  testScript = ''
+    import json
+    start_all()
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("vault.service")
+    machine.wait_for_open_port(8200)
+    out = machine.succeed("vault status -format=json")
+    print(out)
+    status = json.loads(out)
+    assert status.get("initialized") == True
+    machine.succeed("vault kv put secret/foo bar=baz")
+    out = machine.succeed("vault kv get -format=json secret/foo")
+    print(out)
+    status = json.loads(out)
+    assert status.get("data", {}).get("data", {}).get("bar") == "baz"
+  '';
+})
diff --git a/nixpkgs/nixos/tests/vault-postgresql.nix b/nixpkgs/nixos/tests/vault-postgresql.nix
index 2847af13cbf0..e0e5881c6da7 100644
--- a/nixpkgs/nixos/tests/vault-postgresql.nix
+++ b/nixpkgs/nixos/tests/vault-postgresql.nix
@@ -11,7 +11,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
   meta = with pkgs.lib.maintainers; {
     maintainers = [ lnl7 roberth ];
   };
-  machine = { lib, pkgs, ... }: {
+  nodes.machine = { lib, pkgs, ... }: {
     environment.systemPackages = [ pkgs.vault ];
     environment.variables.VAULT_ADDR = "http://127.0.0.1:8200";
     services.vault.enable = true;
diff --git a/nixpkgs/nixos/tests/vault.nix b/nixpkgs/nixos/tests/vault.nix
index e86acd5b593f..1b0a26a4487f 100644
--- a/nixpkgs/nixos/tests/vault.nix
+++ b/nixpkgs/nixos/tests/vault.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }:
   meta = with pkgs.lib.maintainers; {
     maintainers = [ lnl7 ];
   };
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     environment.systemPackages = [ pkgs.vault ];
     environment.variables.VAULT_ADDR = "http://127.0.0.1:8200";
     services.vault.enable = true;
diff --git a/nixpkgs/nixos/tests/vaultwarden.nix b/nixpkgs/nixos/tests/vaultwarden.nix
index 56f1d245d505..408019666da3 100644
--- a/nixpkgs/nixos/tests/vaultwarden.nix
+++ b/nixpkgs/nixos/tests/vaultwarden.nix
@@ -74,7 +74,10 @@ let
             services.vaultwarden = {
               enable = true;
               dbBackend = backend;
-              config.rocketPort = 80;
+              config = {
+                rocketAddress = "0.0.0.0";
+                rocketPort = 80;
+              };
             };
 
             networking.firewall.allowedTCPPorts = [ 80 ];
@@ -85,6 +88,8 @@ let
                   {
                     libraries = [ pkgs.python3Packages.selenium ];
                   } ''
+
+                  from selenium.webdriver.common.by import By
                   from selenium.webdriver import Firefox
                   from selenium.webdriver.firefox.options import Options
                   from selenium.webdriver.support.ui import WebDriverWait
@@ -101,41 +106,40 @@ let
 
                   wait.until(EC.title_contains("Create Account"))
 
-                  driver.find_element_by_css_selector('input#email').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#email').send_keys(
                     '${userEmail}'
                   )
-                  driver.find_element_by_css_selector('input#name').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#name').send_keys(
                     'A Cat'
                   )
-                  driver.find_element_by_css_selector('input#masterPassword').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#masterPassword').send_keys(
                     '${userPassword}'
                   )
-                  driver.find_element_by_css_selector('input#masterPasswordRetype').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#masterPasswordRetype').send_keys(
                     '${userPassword}'
                   )
-                  driver.find_element_by_css_selector('input#acceptPolicies').click()
 
-                  driver.find_element_by_xpath("//button[contains(., 'Submit')]").click()
+                  driver.find_element(By.XPATH, "//button[contains(., 'Submit')]").click()
 
                   wait.until_not(EC.title_contains("Create Account"))
 
-                  driver.find_element_by_css_selector('input#masterPassword').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#masterPassword').send_keys(
                     '${userPassword}'
                   )
-                  driver.find_element_by_xpath("//button[contains(., 'Log In')]").click()
+                  driver.find_element(By.XPATH, "//button[contains(., 'Log In')]").click()
 
-                  wait.until(EC.title_contains("My Vault"))
+                  wait.until(EC.title_contains("Bitwarden Web Vault"))
 
-                  driver.find_element_by_xpath("//button[contains(., 'Add Item')]").click()
+                  driver.find_element(By.XPATH, "//button[contains(., 'Add Item')]").click()
 
-                  driver.find_element_by_css_selector('input#name').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#name').send_keys(
                     'secrets'
                   )
-                  driver.find_element_by_css_selector('input#loginPassword').send_keys(
+                  driver.find_element(By.CSS_SELECTOR, 'input#loginPassword').send_keys(
                     '${storedPassword}'
                   )
 
-                  driver.find_element_by_xpath("//button[contains(., 'Save')]").click()
+                  driver.find_element(By.XPATH, "//button[contains(., 'Save')]").click()
                 '';
               in
               [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
diff --git a/nixpkgs/nixos/tests/vector.nix b/nixpkgs/nixos/tests/vector.nix
index 583e60ddc568..ecf94e33ff17 100644
--- a/nixpkgs/nixos/tests/vector.nix
+++ b/nixpkgs/nixos/tests/vector.nix
@@ -9,7 +9,7 @@ with pkgs.lib;
     name = "vector-test1";
     meta.maintainers = [ pkgs.lib.maintainers.happysalada ];
 
-    machine = { config, pkgs, ... }: {
+    nodes.machine = { config, pkgs, ... }: {
       services.vector = {
         enable = true;
         journaldAccess = true;
diff --git a/nixpkgs/nixos/tests/vengi-tools.nix b/nixpkgs/nixos/tests/vengi-tools.nix
index 6b90542887d5..5bc8d72c7723 100644
--- a/nixpkgs/nixos/tests/vengi-tools.nix
+++ b/nixpkgs/nixos/tests/vengi-tools.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
     maintainers = [ fgaz ];
   };
 
-  machine = { config, pkgs, ... }: {
+  nodes.machine = { config, pkgs, ... }: {
     imports = [
       ./common/x11.nix
     ];
@@ -23,7 +23,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
       # OCR on voxedit's window is very expensive, so we avoid wasting a try
       # by letting the window load fully first
       machine.sleep(15)
-      machine.wait_for_text("Palette")
+      machine.wait_for_text("Solid")
       machine.screenshot("screen")
     '';
 })
diff --git a/nixpkgs/nixos/tests/vikunja.nix b/nixpkgs/nixos/tests/vikunja.nix
index bd884b37f4f9..2f6c4c1f4661 100644
--- a/nixpkgs/nixos/tests/vikunja.nix
+++ b/nixpkgs/nixos/tests/vikunja.nix
@@ -1,9 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }: {
   name = "vikunja";
 
-  meta = with lib.maintainers; {
-    maintainers = [ em0lar ];
-  };
+  meta.maintainers = with lib.maintainers; [ leona ];
 
   nodes = {
     vikunjaSqlite = { ... }: {
diff --git a/nixpkgs/nixos/tests/virtualbox.nix b/nixpkgs/nixos/tests/virtualbox.nix
index f15412d365fa..1c1b0dac7f37 100644
--- a/nixpkgs/nixos/tests/virtualbox.nix
+++ b/nixpkgs/nixos/tests/virtualbox.nix
@@ -3,18 +3,9 @@
   pkgs ? import ../.. { inherit system config; },
   debug ? false,
   enableUnfree ? false,
-  # Nested KVM virtualization (https://www.linux-kvm.org/page/Nested_Guests)
-  # requires a modprobe flag on the build machine: (kvm-amd for AMD CPUs)
-  #   boot.extraModprobeConfig = "options kvm-intel nested=Y";
-  # Without this VirtualBox will use SW virtualization and will only be able
-  # to run 32-bit guests.
-  useKvmNestedVirt ? false,
-  # Whether to run 64-bit guests instead of 32-bit. Requires nested KVM.
-  use64bitGuest ? false
+  use64bitGuest ? true
 }:
 
-assert use64bitGuest -> useKvmNestedVirt;
-
 with import ../lib/testing-python.nix { inherit system pkgs; };
 with pkgs.lib;
 
@@ -26,7 +17,8 @@ let
       #!${pkgs.runtimeShell} -xe
       export PATH="${lib.makeBinPath [ pkgs.coreutils pkgs.util-linux ]}"
 
-      mkdir -p /run/dbus
+      mkdir -p /run/dbus /var
+      ln -s /run /var
       cat > /etc/passwd <<EOF
       root:x:0:0::/root:/bin/false
       messagebus:x:1:1::/run/dbus:/bin/false
@@ -200,6 +192,7 @@ let
       systemd.services."vboxtestlog-${name}@" = {
         description = "VirtualBox Test Machine Log For ${name}";
         serviceConfig.StandardInput = "socket";
+        serviceConfig.StandardOutput = "journal";
         serviceConfig.SyslogIdentifier = "GUEST-${name}";
         serviceConfig.ExecStart = "${pkgs.coreutils}/bin/cat";
       };
@@ -222,10 +215,11 @@ let
               machine.execute(ru("VBoxManage controlvm ${name} poweroff"))
           machine.succeed("rm -rf ${sharePath}")
           machine.succeed("mkdir -p ${sharePath}")
-          machine.succeed("chown alice.users ${sharePath}")
+          machine.succeed("chown alice:users ${sharePath}")
 
 
       def create_vm_${name}():
+          cleanup_${name}()
           vbm("createvm --name ${name} ${createFlags}")
           vbm("modifyvm ${name} ${vmFlags}")
           vbm("setextradata ${name} VBoxInternal/PDM/HaltOnReset 1")
@@ -233,7 +227,6 @@ let
           vbm("storageattach ${name} ${diskFlags}")
           vbm("sharedfolder add ${name} ${sharedFlags}")
           vbm("sharedfolder add ${name} ${nixstoreFlags}")
-          cleanup_${name}()
 
           ${mkLog "$HOME/VirtualBox VMs/${name}/Logs/VBox.log" "HOST-${name}"}
 
@@ -317,10 +310,7 @@ let
   ];
 
   dhcpScript = pkgs: ''
-    ${pkgs.dhcp}/bin/dhclient \
-      -lf /run/dhcp.leases \
-      -pf /run/dhclient.pid \
-      -v eth0 eth1
+    ${pkgs.dhcpcd}/bin/dhcpcd eth0 eth1
 
     otherIP="$(${pkgs.netcat}/bin/nc -l 1234 || :)"
     ${pkgs.iputils}/bin/ping -I eth1 -c1 "$otherIP"
@@ -353,14 +343,13 @@ let
   mkVBoxTest = useExtensionPack: vms: name: testScript: makeTest {
     name = "virtualbox-${name}";
 
-    machine = { lib, config, ... }: {
+    nodes.machine = { lib, config, ... }: {
       imports = let
         mkVMConf = name: val: val.machine // { key = "${name}-config"; };
         vmConfigs = mapAttrsToList mkVMConf vms;
       in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
       virtualisation.memorySize = 2048;
-      virtualisation.qemu.options =
-        if useKvmNestedVirt then ["-cpu" "kvm64,vmx=on"] else [];
+      virtualisation.qemu.options = ["-cpu" "kvm64,svm=on,vmx=on"];
       virtualisation.virtualbox.host.enable = true;
       test-support.displayManager.auto.user = "alice";
       users.users.alice.extraGroups = let
@@ -468,7 +457,7 @@ in mapAttrs (mkVBoxTest false vboxVMs) {
 
   headless = ''
     create_vm_headless()
-    machine.succeed(ru("VBoxHeadless --startvm headless & disown %1"))
+    machine.succeed(ru("VBoxHeadless --startvm headless >&2 & disown %1"))
     wait_for_startup_headless()
     wait_for_vm_boot_headless()
     shutdown_vm_headless()
@@ -476,6 +465,8 @@ in mapAttrs (mkVBoxTest false vboxVMs) {
   '';
 
   host-usb-permissions = ''
+    import sys
+
     user_usb = remove_uuids(vbm("list usbhost"))
     print(user_usb, file=sys.stderr)
     root_usb = remove_uuids(machine.succeed("VBoxManage list usbhost"))
diff --git a/nixpkgs/nixos/tests/vscodium.nix b/nixpkgs/nixos/tests/vscodium.nix
index 688ddfe07e3e..3bdb99947a40 100644
--- a/nixpkgs/nixos/tests/vscodium.nix
+++ b/nixpkgs/nixos/tests/vscodium.nix
@@ -32,6 +32,14 @@ let
         maintainers = [ synthetica turion ];
       };
       enableOCR = true;
+
+      # testScriptWithTypes:55: error: Item "function" of
+      # "Union[Callable[[Callable[..., Any]], ContextManager[Any]], ContextManager[Any]]"
+      # has no attribute "__enter__"
+      #     with codium_running:
+      #          ^
+      skipTypeCheck = true;
+
       testScript = ''
         @polling_condition
         def codium_running():
diff --git a/nixpkgs/nixos/tests/vsftpd.nix b/nixpkgs/nixos/tests/vsftpd.nix
index 4bea27f0eb10..6eaf32b22583 100644
--- a/nixpkgs/nixos/tests/vsftpd.nix
+++ b/nixpkgs/nixos/tests/vsftpd.nix
@@ -29,7 +29,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
   testScript = ''
     client.start()
     server.wait_for_unit("vsftpd")
-    server.wait_for_open_port("21")
+    server.wait_for_open_port(21)
 
     client.succeed("curl -u ftp-test-user:ftp-test-password ftp://server")
     client.succeed('echo "this is a test" > /tmp/test.file.up')
diff --git a/nixpkgs/nixos/tests/web-apps/healthchecks.nix b/nixpkgs/nixos/tests/web-apps/healthchecks.nix
new file mode 100644
index 000000000000..41374f5e314b
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/healthchecks.nix
@@ -0,0 +1,42 @@
+import ../make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "healthchecks";
+
+  meta = with lib.maintainers; {
+    maintainers = [ phaer ];
+  };
+
+  nodes.machine = { ... }: {
+    services.healthchecks = {
+      enable = true;
+      settings = {
+        SITE_NAME = "MyUniqueInstance";
+        COMPRESS_ENABLED = "True";
+        SECRET_KEY_FILE = pkgs.writeText "secret"
+          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+      };
+    };
+  };
+
+  testScript = ''
+    machine.start()
+    machine.wait_for_unit("healthchecks.target")
+    machine.wait_until_succeeds("journalctl --since -1m --unit healthchecks --grep Listening")
+
+    with subtest("Home screen loads"):
+        machine.succeed(
+            "curl -sSfL http://localhost:8000 | grep '<title>Sign In'"
+        )
+
+    with subtest("Setting SITE_NAME via freeform option works"):
+        machine.succeed(
+            "curl -sSfL http://localhost:8000 | grep 'MyUniqueInstance</title>'"
+        )
+
+    with subtest("Manage script works"):
+        # Should fail if not called by healthchecks user
+        machine.fail("echo 'print(\"foo\")' | healthchecks-manage help")
+
+        # "shell" sucommand should succeed, needs python in PATH.
+        assert "foo\n" == machine.succeed("echo 'print(\"foo\")' | sudo -u healthchecks healthchecks-manage shell")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/web-apps/netbox.nix b/nixpkgs/nixos/tests/web-apps/netbox.nix
new file mode 100644
index 000000000000..35decdd49e87
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/netbox.nix
@@ -0,0 +1,30 @@
+import ../make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "netbox";
+
+  meta = with lib.maintainers; {
+    maintainers = [ n0emis ];
+  };
+
+  nodes.machine = { ... }: {
+    services.netbox = {
+      enable = true;
+      secretKeyFile = pkgs.writeText "secret" ''
+        abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
+      '';
+    };
+  };
+
+  testScript = ''
+    machine.start()
+    machine.wait_for_unit("netbox.target")
+    machine.wait_until_succeeds("journalctl --since -1m --unit netbox --grep Listening")
+
+    with subtest("Home screen loads"):
+        machine.succeed(
+            "curl -sSfL http://[::1]:8001 | grep '<title>Home | NetBox</title>'"
+        )
+
+    with subtest("Staticfiles are generated"):
+        machine.succeed("test -e /var/lib/netbox/static/netbox.js")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/web-apps/nifi.nix b/nixpkgs/nixos/tests/web-apps/nifi.nix
new file mode 100644
index 000000000000..92f7fa231df3
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/nifi.nix
@@ -0,0 +1,30 @@
+import ../make-test-python.nix ({pkgs, ...}:
+{
+  name = "nifi";
+  meta.maintainers = with pkgs.lib.maintainers; [ izorkin ];
+
+  nodes = {
+    nifi = { pkgs, ... }: {
+      virtualisation = {
+        memorySize = 2048;
+        diskSize = 4096;
+      };
+      services.nifi = {
+        enable = true;
+        enableHTTPS = false;
+      };
+    };
+  };
+
+  testScript = ''
+    nifi.start()
+
+    nifi.wait_for_unit("nifi.service")
+    nifi.wait_for_open_port(8080)
+
+    # Check if NiFi is running
+    nifi.succeed("curl --fail http://127.0.0.1:8080/nifi/login 2> /dev/null | grep 'NiFi Login'")
+
+    nifi.shutdown()
+  '';
+})
diff --git a/nixpkgs/nixos/tests/web-apps/peertube.nix b/nixpkgs/nixos/tests/web-apps/peertube.nix
index 706c598338e8..ecc45bff2e2c 100644
--- a/nixpkgs/nixos/tests/web-apps/peertube.nix
+++ b/nixpkgs/nixos/tests/web-apps/peertube.nix
@@ -11,7 +11,7 @@ import ../make-test-python.nix ({pkgs, ...}:
             { address = "192.168.2.10"; prefixLength = 24; }
           ];
         };
-        firewall.allowedTCPPorts = [ 5432 6379 ];
+        firewall.allowedTCPPorts = [ 5432 31638 ];
       };
 
       services.postgresql = {
@@ -30,10 +30,11 @@ import ../make-test-python.nix ({pkgs, ...}:
         '';
       };
 
-      services.redis = {
+      services.redis.servers.peertube = {
         enable = true;
         bind = "0.0.0.0";
         requirePass = "turrQfaQwnanGbcsdhxy";
+        port = 31638;
       };
     };
 
@@ -75,6 +76,7 @@ import ../make-test-python.nix ({pkgs, ...}:
 
         redis = {
           host = "192.168.2.10";
+          port = 31638;
           passwordFile = "/etc/peertube/password-redis-db";
         };
 
@@ -109,10 +111,10 @@ import ../make-test-python.nix ({pkgs, ...}:
     start_all()
 
     database.wait_for_unit("postgresql.service")
-    database.wait_for_unit("redis.service")
+    database.wait_for_unit("redis-peertube.service")
 
     database.wait_for_open_port(5432)
-    database.wait_for_open_port(6379)
+    database.wait_for_open_port(31638)
 
     server.wait_for_unit("peertube.service")
     server.wait_for_open_port(9000)
diff --git a/nixpkgs/nixos/tests/web-apps/phylactery.nix b/nixpkgs/nixos/tests/web-apps/phylactery.nix
new file mode 100644
index 000000000000..cf2689d2300d
--- /dev/null
+++ b/nixpkgs/nixos/tests/web-apps/phylactery.nix
@@ -0,0 +1,20 @@
+import ../make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "phylactery";
+
+  nodes.machine = { ... }: {
+    services.phylactery = rec {
+      enable = true;
+      port = 8080;
+      library = "/tmp";
+    };
+  };
+
+  testScript = ''
+    start_all()
+    machine.wait_for_unit('phylactery')
+    machine.wait_for_open_port(8080)
+    machine.wait_until_succeeds('curl localhost:8080')
+  '';
+
+  meta.maintainers = with lib.maintainers; [ McSinyx ];
+})
diff --git a/nixpkgs/nixos/tests/web-servers/unit-php.nix b/nixpkgs/nixos/tests/web-servers/unit-php.nix
index 00512b506cc2..f0df371945e5 100644
--- a/nixpkgs/nixos/tests/web-servers/unit-php.nix
+++ b/nixpkgs/nixos/tests/web-servers/unit-php.nix
@@ -6,19 +6,19 @@ in {
   name = "unit-php-test";
   meta.maintainers = with pkgs.lib.maintainers; [ izorkin ];
 
-  machine = { config, lib, pkgs, ... }: {
+  nodes.machine = { config, lib, pkgs, ... }: {
     services.unit = {
       enable = true;
       config = pkgs.lib.strings.toJSON {
-        listeners."*:9080".application = "php_80";
-        applications.php_80 = {
-          type = "php 8.0";
+        listeners."*:9081".application = "php_81";
+        applications.php_81 = {
+          type = "php 8.1";
           processes = 1;
           user = "testuser";
           group = "testgroup";
           root = "${testdir}/www";
           index = "info.php";
-          options.file = "${pkgs.unit.usedPhp80}/lib/php.ini";
+          options.file = "${pkgs.unit.usedPhp81}/lib/php.ini";
         };
       };
     };
@@ -34,14 +34,19 @@ in {
     };
   };
   testScript = ''
+    machine.start()
+
     machine.wait_for_unit("unit.service")
+    machine.wait_for_open_port(9081)
 
     # Check so we get an evaluated PHP back
-    response = machine.succeed("curl -f -vvv -s http://127.0.0.1:9080/")
-    assert "PHP Version ${pkgs.unit.usedPhp80.version}" in response, "PHP version not detected"
+    response = machine.succeed("curl -f -vvv -s http://127.0.0.1:9081/")
+    assert "PHP Version ${pkgs.unit.usedPhp81.version}" in response, "PHP version not detected"
 
     # Check so we have database and some other extensions loaded
     for ext in ["json", "opcache", "pdo_mysql", "pdo_pgsql", "pdo_sqlite"]:
         assert ext in response, f"Missing {ext} extension"
+
+    machine.shutdown()
   '';
 })
diff --git a/nixpkgs/nixos/tests/wiki-js.nix b/nixpkgs/nixos/tests/wiki-js.nix
index 783887d2dcaa..c3541be5d8b5 100644
--- a/nixpkgs/nixos/tests/wiki-js.nix
+++ b/nixpkgs/nixos/tests/wiki-js.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : {
     maintainers = [ ma27 ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     virtualisation.memorySize = 2048;
     services.wiki-js = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/wine.nix b/nixpkgs/nixos/tests/wine.nix
index 8135cb90a591..8a64c3179c51 100644
--- a/nixpkgs/nixos/tests/wine.nix
+++ b/nixpkgs/nixos/tests/wine.nix
@@ -15,7 +15,7 @@ let
       inherit name;
       meta = with pkgs.lib.maintainers; { maintainers = [ chkno ]; };
 
-      machine = { pkgs, ... }: {
+      nodes.machine = { pkgs, ... }: {
         environment.systemPackages = [ pkgs."${packageSet}"."${variant}" ];
         virtualisation.diskSize = 800;
       };
diff --git a/nixpkgs/nixos/tests/wireguard/wg-quick.nix b/nixpkgs/nixos/tests/wireguard/wg-quick.nix
index 961c2e15c30f..bc2cba911888 100644
--- a/nixpkgs/nixos/tests/wireguard/wg-quick.nix
+++ b/nixpkgs/nixos/tests/wireguard/wg-quick.nix
@@ -29,6 +29,8 @@ import ../make-test-python.nix ({ pkgs, lib, ... }:
 
               inherit (wg-snakeoil-keys.peer1) publicKey;
             };
+
+            dns = [ "10.23.42.2" "fc00::2" "wg0" ];
           };
         };
       };
@@ -38,6 +40,7 @@ import ../make-test-python.nix ({ pkgs, lib, ... }:
         ip6 = "fd00::2";
         extraConfig = {
           boot = lib.mkIf (kernelPackages != null) { inherit kernelPackages; };
+          networking.useNetworkd = true;
           networking.wg-quick.interfaces.wg0 = {
             address = [ "10.23.42.2/32" "fc00::2/128" ];
             inherit (wg-snakeoil-keys.peer1) privateKey;
@@ -49,6 +52,8 @@ import ../make-test-python.nix ({ pkgs, lib, ... }:
 
               inherit (wg-snakeoil-keys.peer0) publicKey;
             };
+
+            dns = [ "10.23.42.1" "fc00::1" "wg0" ];
           };
         };
       };
diff --git a/nixpkgs/nixos/tests/wmderland.nix b/nixpkgs/nixos/tests/wmderland.nix
index 6de0cd9212ee..ebfd443763e1 100644
--- a/nixpkgs/nixos/tests/wmderland.nix
+++ b/nixpkgs/nixos/tests/wmderland.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ takagiy ];
   };
 
-  machine = { lib, ... }: {
+  nodes.machine = { lib, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     test-support.displayManager.auto.user = "alice";
     services.xserver.displayManager.defaultSession = lib.mkForce "none+wmderland";
diff --git a/nixpkgs/nixos/tests/wpa_supplicant.nix b/nixpkgs/nixos/tests/wpa_supplicant.nix
index 40d934b8e1db..a05a79e8367d 100644
--- a/nixpkgs/nixos/tests/wpa_supplicant.nix
+++ b/nixpkgs/nixos/tests/wpa_supplicant.nix
@@ -5,7 +5,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...}:
     maintainers = [ rnhmjoj ];
   };
 
-  machine = { ... }: {
+  nodes.machine = { ... }: {
     imports = [ ../modules/profiles/minimal.nix ];
 
     # add a virtual wlan interface
diff --git a/nixpkgs/nixos/tests/xfce.nix b/nixpkgs/nixos/tests/xfce.nix
index 9051deebae76..31f00f77c40d 100644
--- a/nixpkgs/nixos/tests/xfce.nix
+++ b/nixpkgs/nixos/tests/xfce.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ...} : {
   name = "xfce";
 
-  machine =
+  nodes.machine =
     { pkgs, ... }:
 
     {
diff --git a/nixpkgs/nixos/tests/xmonad-xdg-autostart.nix b/nixpkgs/nixos/tests/xmonad-xdg-autostart.nix
new file mode 100644
index 000000000000..2577a9ce2ea1
--- /dev/null
+++ b/nixpkgs/nixos/tests/xmonad-xdg-autostart.nix
@@ -0,0 +1,35 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "xmonad-xdg-autostart";
+  meta.maintainers = with lib.maintainers; [ oxalica ];
+
+  nodes.machine = { pkgs, config, ... }: {
+    imports = [ ./common/x11.nix ./common/user-account.nix ];
+    test-support.displayManager.auto.user = "alice";
+    services.xserver.displayManager.defaultSession = "none+xmonad";
+    services.xserver.windowManager.xmonad.enable = true;
+    services.xserver.desktopManager.runXdgAutostartIfNone = true;
+
+    environment.systemPackages = [
+      (pkgs.writeTextFile {
+        name = "test-xdg-autostart";
+        destination = "/etc/xdg/autostart/test-xdg-autostart.desktop";
+        text = ''
+          [Desktop Entry]
+          Name=test-xdg-autoatart
+          Type=Application
+          Terminal=false
+          Exec=${pkgs.coreutils}/bin/touch ${config.users.users.alice.home}/xdg-autostart-executed
+        '';
+      })
+    ];
+  };
+
+  testScript = { nodes, ... }:
+    let
+      user = nodes.machine.config.users.users.alice;
+    in
+    ''
+      machine.wait_for_x()
+      machine.wait_for_file("${user.home}/xdg-autostart-executed")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/xmonad.nix b/nixpkgs/nixos/tests/xmonad.nix
index a2fb38e53bd1..ec48c3e11275 100644
--- a/nixpkgs/nixos/tests/xmonad.nix
+++ b/nixpkgs/nixos/tests/xmonad.nix
@@ -13,7 +13,9 @@ let
     import System.Environment (getArgs)
     import System.FilePath ((</>))
 
-    main = launch $ def { startupHook = startup } `additionalKeysP` myKeys
+    main = do
+      dirs <- getDirectories
+      launch (def { startupHook = startup } `additionalKeysP` myKeys) dirs
 
     startup = isSessionStart >>= \sessInit ->
       spawn "touch /tmp/${name}"
@@ -23,14 +25,15 @@ let
 
     compiledConfig = printf "xmonad-%s-%s" arch os
 
-    compileRestart resume =
-      whenX (recompile True) $
+    compileRestart resume = do
+      dirs <- asks directories
+
+      whenX (recompile dirs True) $
         when resume writeStateToFile
           *> catchIO
             ( do
-                dir <- getXMonadDataDir
                 args <- getArgs
-                executeFile (dir </> compiledConfig) False args Nothing
+                executeFile (cacheDir dirs </> compiledConfig) False args Nothing
             )
   '';
 
@@ -55,7 +58,7 @@ in {
     maintainers = [ nequissimus ivanbrennan ];
   };
 
-  machine = { pkgs, ... }: {
+  nodes.machine = { pkgs, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     test-support.displayManager.auto.user = "alice";
     services.xserver.displayManager.defaultSession = "none+xmonad";
@@ -94,7 +97,7 @@ in {
 
     # set up the new config
     machine.succeed("mkdir -p ${user.home}/.xmonad")
-    machine.copy_from_host("${newConfig}", "${user.home}/.xmonad/xmonad.hs")
+    machine.copy_from_host("${newConfig}", "${user.home}/.config/xmonad/xmonad.hs")
 
     # recompile xmonad using the new config
     machine.send_key("alt-ctrl-q")
diff --git a/nixpkgs/nixos/tests/xmpp/xmpp-sendmessage.nix b/nixpkgs/nixos/tests/xmpp/xmpp-sendmessage.nix
index 47a77f524c6a..4c009464b704 100644
--- a/nixpkgs/nixos/tests/xmpp/xmpp-sendmessage.nix
+++ b/nixpkgs/nixos/tests/xmpp/xmpp-sendmessage.nix
@@ -6,7 +6,7 @@ let
     Please find this *really* important attachment.
 
     Yours truly,
-    John
+    Bob
   '';
 in writeScriptBin "send-message" ''
 #!${(python3.withPackages (ps: [ ps.slixmpp ])).interpreter}
@@ -51,11 +51,8 @@ class CthonTest(ClientXMPP):
         log.info('Message sent')
 
         # Test http upload (XEP_0363)
-        def timeout_callback(arg):
-            log.error("ERROR: Cannot upload file. XEP_0363 seems broken")
-            sys.exit(1)
         try:
-            url = await self['xep_0363'].upload_file("${dummyFile}",timeout=10, timeout_callback=timeout_callback)
+            url = await self['xep_0363'].upload_file("${dummyFile}",timeout=10)
         except:
             log.error("ERROR: Cannot run upload command. XEP_0363 seems broken")
             sys.exit(1)
diff --git a/nixpkgs/nixos/tests/xrdp.nix b/nixpkgs/nixos/tests/xrdp.nix
index 0e1d521c5ace..f277d4b79525 100644
--- a/nixpkgs/nixos/tests/xrdp.nix
+++ b/nixpkgs/nixos/tests/xrdp.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, ...} : {
   name = "xrdp";
   meta = with pkgs.lib.maintainers; {
-    maintainers = [ volth ];
+    maintainers = [ ];
   };
 
   nodes = {
diff --git a/nixpkgs/nixos/tests/xterm.nix b/nixpkgs/nixos/tests/xterm.nix
index 4ee31139ab52..745d33e8a0d5 100644
--- a/nixpkgs/nixos/tests/xterm.nix
+++ b/nixpkgs/nixos/tests/xterm.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ nequissimus ];
   };
 
-  machine = { pkgs, ... }:
+  nodes.machine = { pkgs, ... }:
     {
       imports = [ ./common/x11.nix ];
       services.xserver.desktopManager.xterm.enable = false;
diff --git a/nixpkgs/nixos/tests/yabar.nix b/nixpkgs/nixos/tests/yabar.nix
index c2431e556c37..ff7a47ae6370 100644
--- a/nixpkgs/nixos/tests/yabar.nix
+++ b/nixpkgs/nixos/tests/yabar.nix
@@ -8,7 +8,7 @@ with lib;
     maintainers = [ ];
   };
 
-  machine = {
+  nodes.machine = {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
 
     test-support.displayManager.auto.user = "bob";
diff --git a/nixpkgs/nixos/tests/yggdrasil.nix b/nixpkgs/nixos/tests/yggdrasil.nix
index b409d9ed7853..b60a0e6b06cc 100644
--- a/nixpkgs/nixos/tests/yggdrasil.nix
+++ b/nixpkgs/nixos/tests/yggdrasil.nix
@@ -42,7 +42,7 @@ in import ./make-test-python.nix ({ pkgs, ...} : {
 
         services.yggdrasil = {
           enable = true;
-          config = {
+          settings = {
             Listen = ["tcp://0.0.0.0:12345"];
             MulticastInterfaces = [ ];
           };
@@ -112,7 +112,7 @@ in import ./make-test-python.nix ({ pkgs, ...} : {
         services.yggdrasil = {
           enable = true;
           denyDhcpcdInterfaces = [ "ygg0" ];
-          config = {
+          settings = {
             IfTAPMode = true;
             IfName = "ygg0";
             MulticastInterfaces = [ "eth1" ];
diff --git a/nixpkgs/nixos/tests/zeronet-conservancy.nix b/nixpkgs/nixos/tests/zeronet-conservancy.nix
new file mode 100644
index 000000000000..8cb649cbdaab
--- /dev/null
+++ b/nixpkgs/nixos/tests/zeronet-conservancy.nix
@@ -0,0 +1,25 @@
+let
+  port = 43110;
+in
+import ./make-test-python.nix ({ pkgs, ... }: {
+  name = "zeronet-conservancy";
+  meta = with pkgs.lib.maintainers; {
+    maintainers = [ fgaz ];
+  };
+
+  nodes.machine = { config, pkgs, ... }: {
+    services.zeronet = {
+      enable = true;
+      package = pkgs.zeronet-conservancy;
+      inherit port;
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("zeronet.service")
+
+    machine.wait_for_open_port(${toString port})
+
+    machine.succeed("curl --fail -H 'Accept: text/html, application/xml, */*' localhost:${toString port}/Stats")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/zfs.nix b/nixpkgs/nixos/tests/zfs.nix
index d25090403e5f..0b44961a3deb 100644
--- a/nixpkgs/nixos/tests/zfs.nix
+++ b/nixpkgs/nixos/tests/zfs.nix
@@ -18,7 +18,7 @@ let
         maintainers = [ adisbladis ];
       };
 
-      machine = { pkgs, lib, ... }:
+      nodes.machine = { pkgs, lib, ... }:
         let
           usersharePath = "/var/lib/samba/usershares";
         in {
@@ -127,4 +127,54 @@ in {
   };
 
   installer = (import ./installer.nix { }).zfsroot;
+
+  expand-partitions = makeTest {
+    name = "multi-disk-zfs";
+    nodes = {
+      machine = { pkgs, ... }: {
+        environment.systemPackages = [ pkgs.parted ];
+        boot.supportedFilesystems = [ "zfs" ];
+        networking.hostId = "00000000";
+
+        virtualisation = {
+          emptyDiskImages = [ 20480 20480 20480 20480 20480 20480 ];
+        };
+
+        specialisation.resize.configuration = {
+          services.zfs.expandOnBoot = [ "tank" ];
+        };
+      };
+    };
+
+    testScript = { nodes, ... }:
+      ''
+        start_all()
+        machine.wait_for_unit("default.target")
+        print(machine.succeed('mount'))
+
+        print(machine.succeed('parted --script /dev/vdb -- mklabel gpt'))
+        print(machine.succeed('parted --script /dev/vdb -- mkpart primary 1M 70M'))
+
+        print(machine.succeed('parted --script /dev/vdc -- mklabel gpt'))
+        print(machine.succeed('parted --script /dev/vdc -- mkpart primary 1M 70M'))
+
+        print(machine.succeed('zpool create tank mirror /dev/vdb1 /dev/vdc1 mirror /dev/vdd /dev/vde mirror /dev/vdf /dev/vdg'))
+        print(machine.succeed('zpool list -v'))
+        print(machine.succeed('mount'))
+        start_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip())
+
+        print(machine.succeed("/run/current-system/specialisation/resize/bin/switch-to-configuration test >&2"))
+        machine.wait_for_unit("zpool-expand-pools.service")
+        machine.wait_for_unit("zpool-expand@tank.service")
+
+        print(machine.succeed('zpool list -v'))
+        new_size = int(machine.succeed('df -k --output=size /tank | tail -n1').strip())
+
+        if (new_size - start_size) > 20000000:
+          print("Disk grew appropriately.")
+        else:
+          print(f"Disk went from {start_size} to {new_size}, which doesn't seem right.")
+          exit(1)
+      '';
+  };
 }
diff --git a/nixpkgs/nixos/tests/zigbee2mqtt.nix b/nixpkgs/nixos/tests/zigbee2mqtt.nix
index 98aadbb699bd..1592202fb3a7 100644
--- a/nixpkgs/nixos/tests/zigbee2mqtt.nix
+++ b/nixpkgs/nixos/tests/zigbee2mqtt.nix
@@ -1,7 +1,7 @@
 import ./make-test-python.nix ({ pkgs, lib, ... }:
 
   {
-    machine = { pkgs, ... }:
+    nodes.machine = { pkgs, ... }:
       {
         services.zigbee2mqtt = {
           enable = true;
diff --git a/nixpkgs/nixos/tests/zoneminder.nix b/nixpkgs/nixos/tests/zoneminder.nix
index a4e1a05ec0ee..3c97bc8282d2 100644
--- a/nixpkgs/nixos/tests/zoneminder.nix
+++ b/nixpkgs/nixos/tests/zoneminder.nix
@@ -4,7 +4,7 @@ import ./make-test-python.nix ({ lib, ...}:
   name = "zoneminder";
   meta.maintainers = with lib.maintainers; [ danielfullmer ];
 
-  machine = { ... }:
+  nodes.machine = { ... }:
   {
     services.zoneminder = {
       enable = true;
diff --git a/nixpkgs/nixos/tests/zrepl.nix b/nixpkgs/nixos/tests/zrepl.nix
new file mode 100644
index 000000000000..85dd834a6aaf
--- /dev/null
+++ b/nixpkgs/nixos/tests/zrepl.nix
@@ -0,0 +1,66 @@
+import ./make-test-python.nix (
+  {
+    nodes.host = {config, pkgs, ...}: {
+      config = {
+        # Prerequisites for ZFS and tests.
+        boot.supportedFilesystems = [ "zfs" ];
+        environment.systemPackages = [ pkgs.zrepl ];
+        networking.hostId = "deadbeef";
+        services.zrepl = {
+          enable = true;
+          settings = {
+            # Enable Prometheus output for status assertions.
+            global.monitoring = [{
+              type = "prometheus";
+              listen = ":9811";
+            }];
+            # Create a periodic snapshot job for an ephemeral zpool.
+            jobs = [{
+              name = "snap_test";
+              type = "snap";
+
+              filesystems."test" = true;
+              snapshotting = {
+                type = "periodic";
+                prefix = "zrepl_";
+                interval = "1s";
+              };
+
+              pruning.keep = [{
+                type = "last_n";
+                count = 8;
+              }];
+            }];
+          };
+        };
+      };
+    };
+
+    testScript = ''
+      start_all()
+
+      with subtest("Wait for zrepl and network ready"):
+          host.wait_for_unit("network-online.target")
+          host.wait_for_unit("zrepl.service")
+
+      with subtest("Create test zpool"):
+          # ZFS requires 64MiB minimum pool size.
+          host.succeed("fallocate -l 64MiB /root/zpool.img")
+          host.succeed("zpool create test /root/zpool.img")
+
+      with subtest("Check for completed zrepl snapshot"):
+          # zrepl periodic snapshot job creates a snapshot with this prefix.
+          host.wait_until_succeeds("zfs list -t snapshot | grep -q zrepl_")
+
+      with subtest("Verify HTTP monitoring server is configured"):
+          out = host.succeed("curl -f localhost:9811/metrics")
+
+          assert (
+              "zrepl_version_daemon" in out
+          ), "zrepl version metric was not found in Prometheus output"
+
+          assert (
+              "zrepl_zfs_snapshot_duration_count{filesystem=\"test\"}" in out
+          ), "zrepl snapshot counter for test was not found in Prometheus output"
+    '';
+  })
diff --git a/nixpkgs/nixos/tests/zsh-history.nix b/nixpkgs/nixos/tests/zsh-history.nix
index 355687798406..64f32a07e215 100644
--- a/nixpkgs/nixos/tests/zsh-history.nix
+++ b/nixpkgs/nixos/tests/zsh-history.nix
@@ -21,13 +21,13 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     default.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
 
     # Login
-    default.wait_until_tty_matches(1, "login: ")
+    default.wait_until_tty_matches("1", "login: ")
     default.send_chars("root\n")
-    default.wait_until_tty_matches(1, r"\nroot@default\b")
+    default.wait_until_tty_matches("1", r"\nroot@default\b")
 
     # Generate some history
     default.send_chars("echo foobar\n")
-    default.wait_until_tty_matches(1, "foobar")
+    default.wait_until_tty_matches("1", "foobar")
 
     # Ensure that command was recorded in history
     default.succeed("/run/current-system/sw/bin/history list | grep -q foobar")