about summary refs log tree commit diff
path: root/nixpkgs/nixos/tests
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/tests')
-rw-r--r--nixpkgs/nixos/tests/all-terminfo.nix6
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix3
-rw-r--r--nixpkgs/nixos/tests/auth-mysql.nix3
-rw-r--r--nixpkgs/nixos/tests/ayatana-indicators.nix71
-rw-r--r--nixpkgs/nixos/tests/cinnamon-wayland.nix71
-rw-r--r--nixpkgs/nixos/tests/guix/basic.nix38
-rw-r--r--nixpkgs/nixos/tests/guix/default.nix8
-rw-r--r--nixpkgs/nixos/tests/guix/publish.nix95
-rw-r--r--nixpkgs/nixos/tests/guix/scripts/add-existing-files-to-store.scm52
-rw-r--r--nixpkgs/nixos/tests/guix/scripts/create-file-to-store.scm8
-rw-r--r--nixpkgs/nixos/tests/input-remapper.nix5
-rw-r--r--nixpkgs/nixos/tests/installer-systemd-stage-1.nix4
-rw-r--r--nixpkgs/nixos/tests/installer.nix248
-rw-r--r--nixpkgs/nixos/tests/teleport.nix3
-rw-r--r--nixpkgs/nixos/tests/terminal-emulators.nix5
-rw-r--r--nixpkgs/nixos/tests/tsm-client-gui.nix6
16 files changed, 600 insertions, 26 deletions
diff --git a/nixpkgs/nixos/tests/all-terminfo.nix b/nixpkgs/nixos/tests/all-terminfo.nix
index dd47c66ee1c1..2f5e56f09f26 100644
--- a/nixpkgs/nixos/tests/all-terminfo.nix
+++ b/nixpkgs/nixos/tests/all-terminfo.nix
@@ -10,7 +10,11 @@ import ./make-test-python.nix ({ pkgs, ... }: rec {
         let
           o = builtins.tryEval drv;
         in
-        o.success && lib.isDerivation o.value && o.value ? outputs && builtins.elem "terminfo" o.value.outputs;
+        o.success &&
+        lib.isDerivation o.value &&
+        o.value ? outputs &&
+        builtins.elem "terminfo" o.value.outputs &&
+        !o.value.meta.broken;
       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;
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 1ed0f760c9a2..e0572e3bed9c 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -135,6 +135,7 @@ in {
   authelia = handleTest ./authelia.nix {};
   avahi = handleTest ./avahi.nix {};
   avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };
+  ayatana-indicators = handleTest ./ayatana-indicators.nix {};
   babeld = handleTest ./babeld.nix {};
   bazarr = handleTest ./bazarr.nix {};
   bcachefs = handleTestOn ["x86_64-linux" "aarch64-linux"] ./bcachefs.nix {};
@@ -187,6 +188,7 @@ in {
   chrony = handleTestOn ["aarch64-linux" "x86_64-linux"] ./chrony.nix {};
   chrony-ptp = handleTestOn ["aarch64-linux" "x86_64-linux"] ./chrony-ptp.nix {};
   cinnamon = handleTest ./cinnamon.nix {};
+  cinnamon-wayland = handleTest ./cinnamon-wayland.nix {};
   cjdns = handleTest ./cjdns.nix {};
   clickhouse = handleTest ./clickhouse.nix {};
   cloud-init = handleTest ./cloud-init.nix {};
@@ -357,6 +359,7 @@ in {
   grow-partition = runTest ./grow-partition.nix;
   grub = handleTest ./grub.nix {};
   guacamole-server = handleTest ./guacamole-server.nix {};
+  guix = handleTest ./guix {};
   gvisor = handleTest ./gvisor.nix {};
   hadoop = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop; };
   hadoop_3_2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_2; };
diff --git a/nixpkgs/nixos/tests/auth-mysql.nix b/nixpkgs/nixos/tests/auth-mysql.nix
index 0ed4b050a69a..77a69eb1cd58 100644
--- a/nixpkgs/nixos/tests/auth-mysql.nix
+++ b/nixpkgs/nixos/tests/auth-mysql.nix
@@ -84,7 +84,7 @@ in
           getpwuid = ''
             SELECT name, 'x', uid, gid, name, CONCAT('/home/', name), "/run/current-system/sw/bin/bash" \
             FROM users \
-            WHERE id=%1$u \
+            WHERE uid=%1$u \
             LIMIT 1
           '';
           getspnam = ''
@@ -140,6 +140,7 @@ in
 
     machine.wait_for_unit("multi-user.target")
     machine.wait_for_unit("mysql.service")
+    machine.wait_until_succeeds("cat /etc/security/pam_mysql.conf | grep users.db_passwd")
     machine.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
 
     with subtest("Local login"):
diff --git a/nixpkgs/nixos/tests/ayatana-indicators.nix b/nixpkgs/nixos/tests/ayatana-indicators.nix
new file mode 100644
index 000000000000..bc7ff75f390f
--- /dev/null
+++ b/nixpkgs/nixos/tests/ayatana-indicators.nix
@@ -0,0 +1,71 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: let
+  user = "alice";
+in {
+  name = "ayatana-indicators";
+
+  meta = {
+    maintainers = with lib.maintainers; [ OPNA2608 ];
+  };
+
+  nodes.machine = { config, ... }: {
+    imports = [
+      ./common/auto.nix
+      ./common/user-account.nix
+    ];
+
+    test-support.displayManager.auto = {
+      enable = true;
+      inherit user;
+    };
+
+    services.xserver = {
+      enable = true;
+      desktopManager.mate.enable = true;
+      displayManager.defaultSession = lib.mkForce "mate";
+    };
+
+    services.ayatana-indicators = {
+      enable = true;
+      packages = with pkgs; [
+        ayatana-indicator-messages
+      ];
+    };
+
+    # Services needed by some indicators
+    services.accounts-daemon.enable = true; # messages
+  };
+
+  # TODO session indicator starts up in a semi-broken state, but works fine after a restart. maybe being started before graphical session is truly up & ready?
+  testScript = { nodes, ... }: let
+    runCommandPerIndicatorService = command: lib.strings.concatMapStringsSep "\n" command nodes.machine.systemd.user.targets."ayatana-indicators".wants;
+  in ''
+    start_all()
+    machine.wait_for_x()
+
+    # Desktop environment should reach graphical-session.target
+    machine.wait_for_unit("graphical-session.target", "${user}")
+
+    # MATE relies on XDG autostart to bring up the indicators.
+    # Not sure *when* XDG autostart fires them up, and awaiting pgrep success seems to misbehave?
+    machine.sleep(10)
+
+    # Now check if all indicators were brought up successfully, and kill them for later
+  '' + (runCommandPerIndicatorService (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in ''
+    machine.succeed("pgrep -f ${serviceExec}")
+    machine.succeed("pkill -f ${serviceExec}")
+  '')) + ''
+
+    # Ayatana target is the preferred way of starting up indicators on SystemD session, the graphical session is responsible for starting this if it supports them.
+    # Mate currently doesn't do this, so start it manually for checking (https://github.com/mate-desktop/mate-indicator-applet/issues/63)
+    machine.systemctl("start ayatana-indicators.target", "${user}")
+    machine.wait_for_unit("ayatana-indicators.target", "${user}")
+
+    # Let all indicator services do their startups, potential post-launch crash & restart cycles so we can properly check for failures
+    # Not sure if there's a better way of awaiting this without false-positive potential
+    machine.sleep(10)
+
+    # Now check if all indicator services were brought up successfully
+  '' + runCommandPerIndicatorService (service: ''
+    machine.wait_for_unit("${service}", "${user}")
+  '');
+})
diff --git a/nixpkgs/nixos/tests/cinnamon-wayland.nix b/nixpkgs/nixos/tests/cinnamon-wayland.nix
new file mode 100644
index 000000000000..58dddbbb0866
--- /dev/null
+++ b/nixpkgs/nixos/tests/cinnamon-wayland.nix
@@ -0,0 +1,71 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }: {
+  name = "cinnamon-wayland";
+
+  meta.maintainers = lib.teams.cinnamon.members;
+
+  nodes.machine = { nodes, ... }: {
+    imports = [ ./common/user-account.nix ];
+    services.xserver.enable = true;
+    services.xserver.desktopManager.cinnamon.enable = true;
+    services.xserver.displayManager = {
+      autoLogin.enable = true;
+      autoLogin.user = nodes.machine.users.users.alice.name;
+      defaultSession = "cinnamon-wayland";
+    };
+  };
+
+  enableOCR = true;
+
+  testScript = { nodes, ... }:
+    let
+      user = nodes.machine.users.users.alice;
+      env = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus";
+      su = command: "su - ${user.name} -c '${env} ${command}'";
+
+      # Call javascript in cinnamon (the shell), returns a tuple (success, output),
+      # where `success` is true if the dbus call was successful and `output` is what
+      # the javascript evaluates to.
+      eval = name: su "gdbus call --session -d org.Cinnamon -o /org/Cinnamon -m org.Cinnamon.Eval ${name}";
+    in
+    ''
+      machine.wait_for_unit("display-manager.service")
+
+      with subtest("Wait for wayland server"):
+          machine.wait_for_file("/run/user/${toString user.uid}/wayland-0")
+
+      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("Wait for the Cinnamon shell"):
+          # Correct output should be (true, '2')
+          # https://github.com/linuxmint/cinnamon/blob/5.4.0/js/ui/main.js#L183-L187
+          machine.wait_until_succeeds("${eval "Main.runState"} | grep -q 'true,..2'")
+
+      with subtest("Check if Cinnamon components actually start"):
+          for i in ["csd-media-keys", "xapp-sn-watcher", "nemo-desktop"]:
+            machine.wait_until_succeeds(f"pgrep -f {i}")
+          machine.wait_until_succeeds("journalctl -b --grep 'Loaded applet menu@cinnamon.org'")
+          machine.wait_until_succeeds("journalctl -b --grep 'calendar@cinnamon.org: Calendar events supported'")
+
+      with subtest("Open Cinnamon Settings"):
+          machine.succeed("${su "cinnamon-settings themes >&2 &"}")
+          machine.wait_until_succeeds("${eval "global.display.focus_window.wm_class"} | grep -i 'cinnamon-settings'")
+          machine.wait_for_text('(Style|Appearance|Color)')
+          machine.sleep(2)
+          machine.screenshot("cinnamon_settings")
+
+      with subtest("Check if screensaver works"):
+          # This is not supported at the moment.
+          # https://trello.com/b/HHs01Pab/cinnamon-wayland
+          machine.execute("${su "cinnamon-screensaver-command -l >&2 &"}")
+          machine.wait_until_succeeds("journalctl -b --grep 'Cinnamon Screensaver is unavailable on Wayland'")
+
+      with subtest("Open GNOME Terminal"):
+          machine.succeed("${su "dbus-launch gnome-terminal"}")
+          machine.wait_until_succeeds("${eval "global.display.focus_window.wm_class"} | grep -i 'gnome-terminal'")
+          machine.sleep(2)
+
+      with subtest("Check if Cinnamon has ever coredumped"):
+          machine.fail("coredumpctl --json=short | grep -E 'cinnamon|nemo'")
+    '';
+})
diff --git a/nixpkgs/nixos/tests/guix/basic.nix b/nixpkgs/nixos/tests/guix/basic.nix
new file mode 100644
index 000000000000..7f90bdeeb1e0
--- /dev/null
+++ b/nixpkgs/nixos/tests/guix/basic.nix
@@ -0,0 +1,38 @@
+# Take note the Guix store directory is empty. Also, we're trying to prevent
+# Guix from trying to downloading substitutes because of the restricted
+# access (assuming it's in a sandboxed environment).
+#
+# So this test is what it is: a basic test while trying to use Guix as much as
+# we possibly can (including the API) without triggering its download alarm.
+
+import ../make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "guix-basic";
+  meta.maintainers = with lib.maintainers; [ foo-dogsquared ];
+
+  nodes.machine = { config, ... }: {
+    environment.etc."guix/scripts".source = ./scripts;
+    services.guix.enable = true;
+  };
+
+  testScript = ''
+    import pathlib
+
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("guix-daemon.service")
+
+    # Can't do much here since the environment has restricted network access.
+    with subtest("Guix basic package management"):
+      machine.succeed("guix build --dry-run --verbosity=0 hello")
+      machine.succeed("guix show hello")
+
+    # This is to see if the Guix API is usable and mostly working.
+    with subtest("Guix API scripting"):
+      scripts_dir = pathlib.Path("/etc/guix/scripts")
+
+      text_msg = "Hello there, NixOS!"
+      text_store_file = machine.succeed(f"guix repl -- {scripts_dir}/create-file-to-store.scm '{text_msg}'")
+      assert machine.succeed(f"cat {text_store_file}") == text_msg
+
+      machine.succeed(f"guix repl -- {scripts_dir}/add-existing-files-to-store.scm {scripts_dir}")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/guix/default.nix b/nixpkgs/nixos/tests/guix/default.nix
new file mode 100644
index 000000000000..a017668c05a7
--- /dev/null
+++ b/nixpkgs/nixos/tests/guix/default.nix
@@ -0,0 +1,8 @@
+{ system ? builtins.currentSystem
+, pkgs ? import ../../.. { inherit system; }
+}:
+
+{
+  basic = import ./basic.nix { inherit system pkgs; };
+  publish = import ./publish.nix { inherit system pkgs; };
+}
diff --git a/nixpkgs/nixos/tests/guix/publish.nix b/nixpkgs/nixos/tests/guix/publish.nix
new file mode 100644
index 000000000000..6dbe8f99ebd6
--- /dev/null
+++ b/nixpkgs/nixos/tests/guix/publish.nix
@@ -0,0 +1,95 @@
+# Testing out the substitute server with two machines in a local network. As a
+# bonus, we'll also test a feature of the substitute server being able to
+# advertise its service to the local network with Avahi.
+
+import ../make-test-python.nix ({ pkgs, lib, ... }: let
+  publishPort = 8181;
+  inherit (builtins) toString;
+in {
+  name = "guix-publish";
+
+  meta.maintainers = with lib.maintainers; [ foo-dogsquared ];
+
+  nodes = let
+    commonConfig = { config, ... }: {
+      # We'll be using '--advertise' flag with the
+      # substitute server which requires Avahi.
+      services.avahi = {
+        enable = true;
+        nssmdns = true;
+        publish = {
+          enable = true;
+          userServices = true;
+        };
+      };
+    };
+  in {
+    server = { config, lib, pkgs, ... }: {
+      imports = [ commonConfig ];
+
+      services.guix = {
+        enable = true;
+        publish = {
+          enable = true;
+          port = publishPort;
+
+          generateKeyPair = true;
+          extraArgs = [ "--advertise" ];
+        };
+      };
+
+      networking.firewall.allowedTCPPorts = [ publishPort ];
+    };
+
+    client = { config, lib, pkgs, ... }: {
+      imports = [ commonConfig ];
+
+      services.guix = {
+        enable = true;
+
+        extraArgs = [
+          # Force to only get all substitutes from the local server. We don't
+          # have anything in the Guix store directory and we cannot get
+          # anything from the official substitute servers anyways.
+          "--substitute-urls='http://server.local:${toString publishPort}'"
+
+          # Enable autodiscovery of the substitute servers in the local
+          # network. This machine shouldn't need to import the signing key from
+          # the substitute server since it is automatically done anyways.
+          "--discover=yes"
+        ];
+      };
+    };
+  };
+
+  testScript = ''
+    import pathlib
+
+    start_all()
+
+    scripts_dir = pathlib.Path("/etc/guix/scripts")
+
+    for machine in machines:
+      machine.wait_for_unit("multi-user.target")
+      machine.wait_for_unit("guix-daemon.service")
+      machine.wait_for_unit("avahi-daemon.service")
+
+    server.wait_for_unit("guix-publish.service")
+    server.wait_for_open_port(${toString publishPort})
+    server.succeed("curl http://localhost:${toString publishPort}/")
+
+    # Now it's the client turn to make use of it.
+    substitute_server = "http://server.local:${toString publishPort}"
+    client.wait_for_unit("network-online.target")
+    response = client.succeed(f"curl {substitute_server}")
+    assert "Guix Substitute Server" in response
+
+    # Authorizing the server to be used as a substitute server.
+    client.succeed(f"curl -O {substitute_server}/signing-key.pub")
+    client.succeed("guix archive --authorize < ./signing-key.pub")
+
+    # Since we're using the substitute server with the `--advertise` flag, we
+    # might as well check it.
+    client.succeed("avahi-browse --resolve --terminate _guix_publish._tcp | grep '_guix_publish._tcp'")
+  '';
+})
diff --git a/nixpkgs/nixos/tests/guix/scripts/add-existing-files-to-store.scm b/nixpkgs/nixos/tests/guix/scripts/add-existing-files-to-store.scm
new file mode 100644
index 000000000000..fa47320b6a51
--- /dev/null
+++ b/nixpkgs/nixos/tests/guix/scripts/add-existing-files-to-store.scm
@@ -0,0 +1,52 @@
+;; A simple script that adds each file given from the command-line into the
+;; store and checks them if it's the same.
+(use-modules (guix)
+             (srfi srfi-1)
+             (ice-9 ftw)
+             (rnrs io ports))
+
+;; This is based from tests/derivations.scm from Guix source code.
+(define* (directory-contents dir #:optional (slurp get-bytevector-all))
+         "Return an alist representing the contents of DIR"
+         (define prefix-len (string-length dir))
+         (sort (file-system-fold (const #t)
+                                 (lambda (path stat result)
+                                   (alist-cons (string-drop path prefix-len)
+                                               (call-with-input-file path slurp)
+                                               result))
+                                 (lambda (path stat result) result)
+                                 (lambda (path stat result) result)
+                                 (lambda (path stat result) result)
+                                 (lambda (path stat errno result) result)
+                                 '()
+                                 dir)
+               (lambda (e1 e2)
+                 (string<? (car e1) (car e2)))))
+
+(define* (check-if-same store drv path)
+         "Check if the given path and its store item are the same"
+         (let* ((filetype (stat:type (stat drv))))
+           (case filetype
+             ((regular)
+              (and (valid-path? store drv)
+                   (equal? (call-with-input-file path get-bytevector-all)
+                           (call-with-input-file drv get-bytevector-all))))
+             ((directory)
+              (and (valid-path? store drv)
+                   (equal? (directory-contents path)
+                           (directory-contents drv))))
+             (else #f))))
+
+(define* (add-and-check-item-to-store store path)
+         "Add PATH to STORE and check if the contents are the same"
+         (let* ((store-item (add-to-store store
+                                          (basename path)
+                                          #t "sha256" path))
+                (is-same (check-if-same store store-item path)))
+           (if (not is-same)
+             (exit 1))))
+
+(with-store store
+            (map (lambda (path)
+                   (add-and-check-item-to-store store (readlink* path)))
+                 (cdr (command-line))))
diff --git a/nixpkgs/nixos/tests/guix/scripts/create-file-to-store.scm b/nixpkgs/nixos/tests/guix/scripts/create-file-to-store.scm
new file mode 100644
index 000000000000..467e4c4fd53f
--- /dev/null
+++ b/nixpkgs/nixos/tests/guix/scripts/create-file-to-store.scm
@@ -0,0 +1,8 @@
+;; A script that creates a store item with the given text and prints the
+;; resulting store item path.
+(use-modules (guix))
+
+(with-store store
+            (display (add-text-to-store store "guix-basic-test-text"
+                                        (string-join
+                                          (cdr (command-line))))))
diff --git a/nixpkgs/nixos/tests/input-remapper.nix b/nixpkgs/nixos/tests/input-remapper.nix
index 1b0350063f7f..2ef55a01b290 100644
--- a/nixpkgs/nixos/tests/input-remapper.nix
+++ b/nixpkgs/nixos/tests/input-remapper.nix
@@ -46,7 +46,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
       machine.execute("su - sybil -c input-remapper-gtk >&2 &")
 
       machine.wait_for_text("Input Remapper")
-      machine.wait_for_text("Preset")
-      machine.wait_for_text("Change Key")
+      machine.wait_for_text("Device")
+      machine.wait_for_text("Presets")
+      machine.wait_for_text("Editor")
     '';
   })
diff --git a/nixpkgs/nixos/tests/installer-systemd-stage-1.nix b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
index 1b4c92b584b9..d0c01a779ef1 100644
--- a/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
+++ b/nixpkgs/nixos/tests/installer-systemd-stage-1.nix
@@ -32,6 +32,10 @@
     stratisRoot
     swraid
     zfsroot
+    clevisLuks
+    clevisLuksFallback
+    clevisZfs
+    clevisZfsFallback
     ;
 
 }
diff --git a/nixpkgs/nixos/tests/installer.nix b/nixpkgs/nixos/tests/installer.nix
index e9ec28749850..f7fc168eba8c 100644
--- a/nixpkgs/nixos/tests/installer.nix
+++ b/nixpkgs/nixos/tests/installer.nix
@@ -12,6 +12,7 @@ let
   # The configuration to install.
   makeConfig = { bootLoader, grubDevice, grubIdentifier, grubUseEfi
                , extraConfig, forceGrubReinstallCount ? 0, flake ? false
+               , clevisTest
                }:
     pkgs.writeText "configuration.nix" ''
       { config, lib, pkgs, modulesPath, ... }:
@@ -52,6 +53,15 @@ let
 
         boot.initrd.secrets."/etc/secret" = ./secret;
 
+        ${optionalString clevisTest ''
+          boot.kernelParams = [ "console=tty0" "ip=192.168.1.1:::255.255.255.0::eth1:none" ];
+          boot.initrd = {
+            availableKernelModules = [ "tpm_tis" ];
+            clevis = { enable = true; useTang = true; };
+            network.enable = true;
+          };
+          ''}
+
         users.users.alice = {
           isNormalUser = true;
           home = "/home/alice";
@@ -71,7 +81,7 @@ let
   # partitions and filesystems.
   testScriptFun = { bootLoader, createPartitions, grubDevice, grubUseEfi, grubIdentifier
                   , postInstallCommands, preBootCommands, postBootCommands, extraConfig
-                  , testSpecialisationConfig, testFlakeSwitch
+                  , testSpecialisationConfig, testFlakeSwitch, clevisTest, clevisFallbackTest
                   }:
     let iface = "virtio";
         isEfi = bootLoader == "systemd-boot" || (bootLoader == "grub" && grubUseEfi);
@@ -79,12 +89,16 @@ let
     in if !isEfi && !pkgs.stdenv.hostPlatform.isx86 then ''
       machine.succeed("true")
     '' else ''
+      import subprocess
+      tpm_folder = os.environ['NIX_BUILD_TOP']
       def assemble_qemu_flags():
           flags = "-cpu max"
           ${if (system == "x86_64-linux" || system == "i686-linux")
             then ''flags += " -m 1024"''
             else ''flags += " -m 768 -enable-kvm -machine virt,gic-version=host"''
           }
+          ${optionalString clevisTest ''flags += f" -chardev socket,id=chrtpm,path={tpm_folder}/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0"''}
+          ${optionalString clevisTest ''flags += " -device virtio-net-pci,netdev=vlan1,mac=52:54:00:12:11:02 -netdev vde,id=vlan1,sock=\"$QEMU_VDE_SOCKET_1\""''}
           return flags
 
 
@@ -110,8 +124,45 @@ let
       def create_machine_named(name):
           return create_machine({**default_flags, "name": name})
 
+      class Tpm:
+            def __init__(self):
+                self.start()
+
+            def start(self):
+                self.proc = subprocess.Popen(["${pkgs.swtpm}/bin/swtpm",
+                    "socket",
+                    "--tpmstate", f"dir={tpm_folder}/swtpm",
+                    "--ctrl", f"type=unixio,path={tpm_folder}/swtpm-sock",
+                    "--tpm2"
+                    ])
+
+                # Check whether starting swtpm failed
+                try:
+                    exit_code = self.proc.wait(timeout=0.2)
+                    if exit_code is not None and exit_code != 0:
+                        raise Exception("failed to start swtpm")
+                except subprocess.TimeoutExpired:
+                    pass
+
+            """Check whether the swtpm process exited due to an error"""
+            def check(self):
+                exit_code = self.proc.poll()
+                if exit_code is not None and exit_code != 0:
+                    raise Exception("swtpm process died")
+
+
+      os.mkdir(f"{tpm_folder}/swtpm")
+      tpm = Tpm()
+      tpm.check()
+
+      start_all()
+      ${optionalString clevisTest ''
+      tang.wait_for_unit("sockets.target")
+      tang.wait_for_unit("network-online.target")
+      machine.wait_for_unit("network-online.target")
+      ''}
+      machine.wait_for_unit("multi-user.target")
 
-      machine.start()
 
       with subtest("Assert readiness of login prompt"):
           machine.succeed("echo hello")
@@ -127,13 +178,23 @@ let
           machine.copy_from_host(
               "${ makeConfig {
                     inherit bootLoader grubDevice grubIdentifier
-                            grubUseEfi extraConfig;
+                            grubUseEfi extraConfig clevisTest;
                   }
               }",
               "/mnt/etc/nixos/configuration.nix",
           )
           machine.copy_from_host("${pkgs.writeText "secret" "secret"}", "/mnt/etc/nixos/secret")
 
+      ${optionalString clevisTest ''
+        with subtest("Create the Clevis secret with Tang"):
+             machine.wait_for_unit("network-online.target")
+             machine.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''}
+
+      ${optionalString clevisFallbackTest ''
+        with subtest("Shutdown Tang to check fallback to interactive prompt"):
+            tang.shutdown()
+      ''}
+
       with subtest("Perform the installation"):
           machine.succeed("nixos-install < /dev/null >&2")
 
@@ -200,7 +261,7 @@ let
           machine.copy_from_host_via_shell(
               "${ makeConfig {
                     inherit bootLoader grubDevice grubIdentifier
-                            grubUseEfi extraConfig;
+                            grubUseEfi extraConfig clevisTest;
                     forceGrubReinstallCount = 1;
                   }
               }",
@@ -229,7 +290,7 @@ let
       machine.copy_from_host_via_shell(
           "${ makeConfig {
                 inherit bootLoader grubDevice grubIdentifier
-                grubUseEfi extraConfig;
+                grubUseEfi extraConfig clevisTest;
                 forceGrubReinstallCount = 2;
               }
           }",
@@ -303,7 +364,7 @@ let
         """)
         machine.copy_from_host_via_shell(
           "${makeConfig {
-               inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig;
+               inherit bootLoader grubDevice grubIdentifier grubUseEfi extraConfig clevisTest;
                forceGrubReinstallCount = 1;
                flake = true;
             }}",
@@ -379,6 +440,8 @@ let
     , enableOCR ? false, meta ? {}
     , testSpecialisationConfig ? false
     , testFlakeSwitch ? false
+    , clevisTest ? false
+    , clevisFallbackTest ? false
     }:
     makeTest {
       inherit enableOCR;
@@ -416,13 +479,13 @@ let
           virtualisation.rootDevice = "/dev/vdb";
           virtualisation.bootLoaderDevice = "/dev/vda";
           virtualisation.qemu.diskInterface = "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 = [];
+          virtualisation.qemu.options = mkIf (clevisTest) [
+            "-chardev socket,id=chrtpm,path=$NIX_BUILD_TOP/swtpm-sock"
+            "-tpmdev emulator,id=tpm0,chardev=chrtpm"
+            "-device tpm-tis,tpmdev=tpm0"
+          ];
+          # We don't want to have any networking in the guest apart from the clevis tests.
+          virtualisation.vlans = mkIf (!clevisTest) [];
 
           boot.loader.systemd-boot.enable = mkIf (bootLoader == "systemd-boot") true;
 
@@ -471,7 +534,7 @@ let
           in [
             (pkgs.grub2.override { inherit zfsSupport; })
             (pkgs.grub2_efi.override { inherit zfsSupport; })
-          ]);
+          ]) ++ optionals clevisTest [ pkgs.klibc ];
 
           nix.settings = {
             substituters = mkForce [];
@@ -480,12 +543,21 @@ let
           };
         };
 
+      } // optionalAttrs clevisTest {
+        tang = {
+          services.tang = {
+            enable = true;
+            listenStream = [ "80" ];
+            ipAddressAllow = [ "192.168.1.0/24" ];
+          };
+          networking.firewall.allowedTCPPorts = [ 80 ];
+        };
       };
 
       testScript = testScriptFun {
         inherit bootLoader createPartitions postInstallCommands preBootCommands postBootCommands
                 grubDevice grubIdentifier grubUseEfi extraConfig
-                testSpecialisationConfig testFlakeSwitch;
+                testSpecialisationConfig testFlakeSwitch clevisTest clevisFallbackTest;
       };
     };
 
@@ -586,6 +658,145 @@ let
       zfs = super.zfs.overrideAttrs(_: {meta.platforms = [];});}
     )];
   };
+
+ mkClevisBcachefsTest = { fallback ? false }: makeInstallerTest "clevis-bcachefs${optionalString fallback "-fallback"}" {
+    clevisTest = true;
+    clevisFallbackTest = fallback;
+    enableOCR = fallback;
+    extraInstallerConfig = {
+      imports = [ no-zfs-module ];
+      boot.supportedFilesystems = [ "bcachefs" ];
+      environment.systemPackages = with pkgs; [ keyutils clevis ];
+    };
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"
+        + " mkpart primary linux-swap 100M 1024M"
+        + " mkpart primary 1024M -1s",
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "keyctl link @u @s",
+        "echo -n password | mkfs.bcachefs -L root --encrypted /dev/vda3",
+        "echo -n password | bcachefs unlock /dev/vda3",
+        "echo -n password | mount -t bcachefs /dev/vda3 /mnt",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount LABEL=boot /mnt/boot",
+        "udevadm settle")
+    '';
+    extraConfig = ''
+      boot.initrd.clevis.devices."/dev/vda3".secretFile = "/etc/nixos/clevis-secret.jwe";
+
+      # We override what nixos-generate-config has generated because we do
+      # not know the UUID in advance.
+      fileSystems."/" = lib.mkForce { device = "/dev/vda3"; fsType = "bcachefs"; };
+    '';
+    preBootCommands = ''
+      tpm = Tpm()
+      tpm.check()
+    '' + optionalString fallback ''
+      machine.start()
+      machine.wait_for_text("enter passphrase for")
+      machine.send_chars("password\n")
+    '';
+  };
+
+  mkClevisLuksTest = { fallback ? false }: makeInstallerTest "clevis-luks${optionalString fallback "-fallback"}" {
+    clevisTest = true;
+    clevisFallbackTest = fallback;
+    enableOCR = fallback;
+    extraInstallerConfig = {
+      environment.systemPackages = with pkgs; [ clevis ];
+    };
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"
+        + " mkpart primary linux-swap 100M 1024M"
+        + " mkpart primary 1024M -1s",
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "modprobe dm_mod dm_crypt",
+        "echo -n password | cryptsetup luksFormat -q /dev/vda3 -",
+        "echo -n password | cryptsetup luksOpen --key-file - /dev/vda3 crypt-root",
+        "mkfs.ext3 -L nixos /dev/mapper/crypt-root",
+        "mount LABEL=nixos /mnt",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount LABEL=boot /mnt/boot",
+        "udevadm settle")
+    '';
+    extraConfig = ''
+      boot.initrd.clevis.devices."crypt-root".secretFile = "/etc/nixos/clevis-secret.jwe";
+    '';
+    preBootCommands = ''
+      tpm = Tpm()
+      tpm.check()
+    '' + optionalString fallback ''
+      machine.start()
+      ${if systemdStage1 then ''
+      machine.wait_for_text("Please enter")
+      '' else ''
+      machine.wait_for_text("Passphrase for")
+      ''}
+      machine.send_chars("password\n")
+    '';
+  };
+
+  mkClevisZfsTest = { fallback ? false }: makeInstallerTest "clevis-zfs${optionalString fallback "-fallback"}" {
+    clevisTest = true;
+    clevisFallbackTest = fallback;
+    enableOCR = fallback;
+    extraInstallerConfig = {
+      boot.supportedFilesystems = [ "zfs" ];
+      environment.systemPackages = with pkgs; [ clevis ];
+    };
+    createPartitions = ''
+      machine.succeed(
+        "flock /dev/vda parted --script /dev/vda -- mklabel msdos"
+        + " mkpart primary ext2 1M 100MB"
+        + " mkpart primary linux-swap 100M 1024M"
+        + " mkpart primary 1024M -1s",
+        "udevadm settle",
+        "mkswap /dev/vda2 -L swap",
+        "swapon -L swap",
+        "zpool create -O mountpoint=legacy rpool /dev/vda3",
+        "echo -n password | zfs create"
+        + " -o encryption=aes-256-gcm -o keyformat=passphrase rpool/root",
+        "mount -t zfs rpool/root /mnt",
+        "mkfs.ext3 -L boot /dev/vda1",
+        "mkdir -p /mnt/boot",
+        "mount LABEL=boot /mnt/boot",
+        "udevadm settle")
+    '';
+    extraConfig = ''
+      boot.initrd.clevis.devices."rpool/root".secretFile = "/etc/nixos/clevis-secret.jwe";
+      boot.zfs.requestEncryptionCredentials = true;
+
+
+      # Using by-uuid overrides the default of by-id, and is unique
+      # to the qemu disks, as they don't produce by-id paths for
+      # some reason.
+      boot.zfs.devNodes = "/dev/disk/by-uuid/";
+      networking.hostId = "00000000";
+    '';
+    preBootCommands = ''
+      tpm = Tpm()
+      tpm.check()
+    '' + optionalString fallback ''
+      machine.start()
+      ${if systemdStage1 then ''
+      machine.wait_for_text("Enter key for rpool/root")
+      '' else ''
+      machine.wait_for_text("Key load error")
+      ''}
+      machine.send_chars("password\n")
+    '';
+  };
+
 in {
 
   # !!! `parted mkpart' seems to silently create overlapping partitions.
@@ -1175,6 +1386,13 @@ in {
       )
     '';
   };
+} // {
+  clevisBcachefs = mkClevisBcachefsTest { };
+  clevisBcachefsFallback = mkClevisBcachefsTest { fallback = true; };
+  clevisLuks = mkClevisLuksTest { };
+  clevisLuksFallback = mkClevisLuksTest { fallback = true; };
+  clevisZfs = mkClevisZfsTest { };
+  clevisZfsFallback = mkClevisZfsTest { fallback = true; };
 } // optionalAttrs systemdStage1 {
   stratisRoot = makeInstallerTest "stratisRoot" {
     createPartitions = ''
diff --git a/nixpkgs/nixos/tests/teleport.nix b/nixpkgs/nixos/tests/teleport.nix
index cdf762b12844..d68917c6c7ac 100644
--- a/nixpkgs/nixos/tests/teleport.nix
+++ b/nixpkgs/nixos/tests/teleport.nix
@@ -9,7 +9,8 @@ with import ../lib/testing-python.nix { inherit system pkgs; };
 let
   packages = with pkgs; {
     "default" = teleport;
-    "11" = teleport_11;
+    "12" = teleport_12;
+    "13" = teleport_13;
   };
 
   minimal = package: {
diff --git a/nixpkgs/nixos/tests/terminal-emulators.nix b/nixpkgs/nixos/tests/terminal-emulators.nix
index 2306c03c18e7..efaac03e1983 100644
--- a/nixpkgs/nixos/tests/terminal-emulators.nix
+++ b/nixpkgs/nixos/tests/terminal-emulators.nix
@@ -23,9 +23,8 @@ with pkgs.lib;
 let tests = {
       alacritty.pkg = p: p.alacritty;
 
-      # times out after spending many hours
-      #contour.pkg = p: p.contour;
-      #contour.cmd = "contour $command";
+      contour.pkg = p: p.contour;
+      contour.cmd = "contour early-exit-threshold 0 execute $command";
 
       cool-retro-term.pkg = p: p.cool-retro-term;
       cool-retro-term.colourTest = false; # broken by gloss effect
diff --git a/nixpkgs/nixos/tests/tsm-client-gui.nix b/nixpkgs/nixos/tests/tsm-client-gui.nix
index e11501da53d0..c9632546db6e 100644
--- a/nixpkgs/nixos/tests/tsm-client-gui.nix
+++ b/nixpkgs/nixos/tests/tsm-client-gui.nix
@@ -18,9 +18,9 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
       defaultServername = "testserver";
       servers.testserver = {
         # 192.0.0.8 is a "dummy address" according to RFC 7600
-        server = "192.0.0.8";
-        node = "SOME-NODE";
-        passwdDir = "/tmp";
+        tcpserveraddress = "192.0.0.8";
+        nodename = "SOME-NODE";
+        passworddir = "/tmp";
       };
     };
   };