diff options
Diffstat (limited to 'nixos/tests')
112 files changed, 2482 insertions, 513 deletions
diff --git a/nixos/tests/3proxy.nix b/nixos/tests/3proxy.nix index 83d39de018a3..b80b4e166d48 100644 --- a/nixos/tests/3proxy.nix +++ b/nixos/tests/3proxy.nix @@ -134,6 +134,7 @@ testScript = '' start_all() + peer0.systemctl("start network-online.target") peer0.wait_for_unit("network-online.target") peer1.wait_for_unit("3proxy.service") diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index e5f2d4c7934a..272782dc2f62 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -522,6 +522,7 @@ in { 'curl --data \'{"host": "${caDomain}", "addresses": ["${nodes.acme.networking.primaryIPAddress}"]}\' http://${dnsServerIP nodes}:8055/add-a' ) + acme.systemctl("start network-online.target") acme.wait_for_unit("network-online.target") acme.wait_for_unit("pebble.service") diff --git a/nixos/tests/activation/etc-overlay-immutable.nix b/nixos/tests/activation/etc-overlay-immutable.nix new file mode 100644 index 000000000000..70c3623b929c --- /dev/null +++ b/nixos/tests/activation/etc-overlay-immutable.nix @@ -0,0 +1,30 @@ +{ lib, ... }: { + + name = "activation-etc-overlay-immutable"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { pkgs, ... }: { + system.etc.overlay.enable = true; + system.etc.overlay.mutable = false; + + # Prerequisites + systemd.sysusers.enable = true; + users.mutableUsers = false; + boot.initrd.systemd.enable = true; + boot.kernelPackages = pkgs.linuxPackages_latest; + + specialisation.new-generation.configuration = { + environment.etc."newgen".text = "newgen"; + }; + }; + + testScript = '' + machine.succeed("findmnt --kernel --type overlay /etc") + machine.fail("stat /etc/newgen") + + machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch") + + assert machine.succeed("cat /etc/newgen") == "newgen" + ''; +} diff --git a/nixos/tests/activation/etc-overlay-mutable.nix b/nixos/tests/activation/etc-overlay-mutable.nix new file mode 100644 index 000000000000..cfe7604fceb8 --- /dev/null +++ b/nixos/tests/activation/etc-overlay-mutable.nix @@ -0,0 +1,30 @@ +{ lib, ... }: { + + name = "activation-etc-overlay-mutable"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { pkgs, ... }: { + system.etc.overlay.enable = true; + system.etc.overlay.mutable = true; + + # Prerequisites + boot.initrd.systemd.enable = true; + boot.kernelPackages = pkgs.linuxPackages_latest; + + specialisation.new-generation.configuration = { + environment.etc."newgen".text = "newgen"; + }; + }; + + testScript = '' + machine.succeed("findmnt --kernel --type overlay /etc") + machine.fail("stat /etc/newgen") + machine.succeed("echo -n 'mutable' > /etc/mutable") + + machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch") + + assert machine.succeed("cat /etc/newgen") == "newgen" + assert machine.succeed("cat /etc/mutable") == "mutable" + ''; +} diff --git a/nixos/tests/activation/perlless.nix b/nixos/tests/activation/perlless.nix new file mode 100644 index 000000000000..4d784b4542f4 --- /dev/null +++ b/nixos/tests/activation/perlless.nix @@ -0,0 +1,24 @@ +{ lib, ... }: + +{ + + name = "activation-perlless"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { pkgs, modulesPath, ... }: { + imports = [ "${modulesPath}/profiles/perlless.nix" ]; + + boot.kernelPackages = pkgs.linuxPackages_latest; + + virtualisation.mountHostNixStore = false; + virtualisation.useNixStoreImage = true; + }; + + testScript = '' + perl_store_paths = machine.succeed("ls /nix/store | grep perl || true") + print(perl_store_paths) + assert len(perl_store_paths) == 0 + ''; + +} diff --git a/nixos/tests/adguardhome.nix b/nixos/tests/adguardhome.nix index a6f790b83f5f..80613ce82534 100644 --- a/nixos/tests/adguardhome.nix +++ b/nixos/tests/adguardhome.nix @@ -126,6 +126,7 @@ with subtest("Testing successful DHCP start"): dhcpConf.wait_for_unit("adguardhome.service") + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") # Test IP assignment via DHCP dhcpConf.wait_until_succeeds("ping -c 5 10.0.10.100") diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 02e3e91e2e3d..fbb4573d8135 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -242,7 +242,7 @@ in { discourse = handleTest ./discourse.nix {}; dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {}; dnscrypt-wrapper = runTestOn ["x86_64-linux"] ./dnscrypt-wrapper; - dnsdist = handleTest ./dnsdist.nix {}; + dnsdist = import ./dnsdist.nix { inherit pkgs runTest; }; doas = handleTest ./doas.nix {}; docker = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker.nix {}; docker-rootless = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker-rootless.nix {}; @@ -285,6 +285,9 @@ in { activation = pkgs.callPackage ../modules/system/activation/test.nix { }; activation-var = runTest ./activation/var.nix; activation-nix-channel = runTest ./activation/nix-channel.nix; + activation-etc-overlay-mutable = runTest ./activation/etc-overlay-mutable.nix; + activation-etc-overlay-immutable = runTest ./activation/etc-overlay-immutable.nix; + activation-perlless = runTest ./activation/perlless.nix; etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {}; etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {}; etebase-server = handleTest ./etebase-server.nix {}; @@ -387,6 +390,7 @@ in { installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {}); invidious = handleTest ./invidious.nix {}; livebook-service = handleTest ./livebook-service.nix {}; + pyload = handleTest ./pyload.nix {}; oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {}; odoo = handleTest ./odoo.nix {}; odoo15 = handleTest ./odoo.nix { package = pkgs.odoo15; }; @@ -448,6 +452,7 @@ in { kerberos = handleTest ./kerberos/default.nix {}; kernel-generic = handleTest ./kernel-generic.nix {}; kernel-latest-ath-user-regd = handleTest ./kernel-latest-ath-user-regd.nix {}; + kernel-rust = runTestOn ["x86_64-linux"] ./kernel-rust.nix; keter = handleTest ./keter.nix {}; kexec = handleTest ./kexec.nix {}; keycloak = discoverTests (import ./keycloak.nix); @@ -569,8 +574,8 @@ in { netdata = handleTest ./netdata.nix {}; networking.networkd = handleTest ./networking.nix { networkd = true; }; networking.scripted = handleTest ./networking.nix { networkd = false; }; - netbox_3_5 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_5; }; netbox_3_6 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_6; }; + netbox_3_7 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_7; }; netbox-upgrade = handleTest ./web-apps/netbox-upgrade.nix {}; # TODO: put in networking.nix after the test becomes more complete networkingProxy = handleTest ./networking-proxy.nix {}; @@ -583,9 +588,11 @@ in { nginx = handleTest ./nginx.nix {}; nginx-auth = handleTest ./nginx-auth.nix {}; nginx-etag = handleTest ./nginx-etag.nix {}; + nginx-etag-compression = handleTest ./nginx-etag-compression.nix {}; nginx-globalredirect = handleTest ./nginx-globalredirect.nix {}; nginx-http3 = handleTest ./nginx-http3.nix {}; nginx-modsecurity = handleTest ./nginx-modsecurity.nix {}; + nginx-moreheaders = handleTest ./nginx-moreheaders.nix {}; nginx-njs = handleTest ./nginx-njs.nix {}; nginx-proxyprotocol = handleTest ./nginx-proxyprotocol {}; nginx-pubhtml = handleTest ./nginx-pubhtml.nix {}; @@ -604,7 +611,9 @@ in { nixos-generate-config = handleTest ./nixos-generate-config.nix {}; nixos-rebuild-install-bootloader = handleTestOn ["x86_64-linux"] ./nixos-rebuild-install-bootloader.nix {}; nixos-rebuild-specialisations = handleTestOn ["x86_64-linux"] ./nixos-rebuild-specialisations.nix {}; + nixos-rebuild-target-host = handleTest ./nixos-rebuild-target-host.nix {}; nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; }; + nixseparatedebuginfod = handleTest ./nixseparatedebuginfod.nix {}; node-red = handleTest ./node-red.nix {}; nomad = handleTest ./nomad.nix {}; non-default-filesystems = handleTest ./non-default-filesystems.nix {}; @@ -616,6 +625,8 @@ in { nscd = handleTest ./nscd.nix {}; nsd = handleTest ./nsd.nix {}; ntfy-sh = handleTest ./ntfy-sh.nix {}; + ntfy-sh-migration = handleTest ./ntfy-sh-migration.nix {}; + ntpd-rs = handleTest ./ntpd-rs.nix {}; nzbget = handleTest ./nzbget.nix {}; nzbhydra2 = handleTest ./nzbhydra2.nix {}; oh-my-zsh = handleTest ./oh-my-zsh.nix {}; @@ -702,6 +713,7 @@ in { power-profiles-daemon = handleTest ./power-profiles-daemon.nix {}; pppd = handleTest ./pppd.nix {}; predictable-interface-names = handleTest ./predictable-interface-names.nix {}; + pretalx = runTest ./web-apps/pretalx.nix; printing-socket = handleTest ./printing.nix { socket = true; }; printing-service = handleTest ./printing.nix { socket = false; }; privoxy = handleTest ./privoxy.nix {}; @@ -752,6 +764,7 @@ in { sabnzbd = handleTest ./sabnzbd.nix {}; samba = handleTest ./samba.nix {}; samba-wsdd = handleTest ./samba-wsdd.nix {}; + sane = handleTest ./sane.nix {}; sanoid = handleTest ./sanoid.nix {}; scaphandre = handleTest ./scaphandre.nix {}; schleuder = handleTest ./schleuder.nix {}; @@ -772,6 +785,7 @@ in { sing-box = handleTest ./sing-box.nix {}; slimserver = handleTest ./slimserver.nix {}; slurm = handleTest ./slurm.nix {}; + snmpd = handleTest ./snmpd.nix {}; smokeping = handleTest ./smokeping.nix {}; snapcast = handleTest ./snapcast.nix {}; snapper = handleTest ./snapper.nix {}; @@ -802,6 +816,7 @@ in { stunnel = handleTest ./stunnel.nix {}; sudo = handleTest ./sudo.nix {}; sudo-rs = handleTest ./sudo-rs.nix {}; + suwayomi-server = handleTest ./suwayomi-server.nix {}; swap-file-btrfs = handleTest ./swap-file-btrfs.nix {}; swap-partition = handleTest ./swap-partition.nix {}; swap-random-encryption = handleTest ./swap-random-encryption.nix {}; @@ -813,6 +828,7 @@ in { syncthing-init = handleTest ./syncthing-init.nix {}; syncthing-many-devices = handleTest ./syncthing-many-devices.nix {}; syncthing-relay = handleTest ./syncthing-relay.nix {}; + sysinit-reactivation = runTest ./sysinit-reactivation.nix; systemd = handleTest ./systemd.nix {}; systemd-analyze = handleTest ./systemd-analyze.nix {}; systemd-binfmt = handleTestOn ["x86_64-linux"] ./systemd-binfmt.nix {}; @@ -841,6 +857,9 @@ in { systemd-initrd-networkd-openvpn = handleTestOn [ "x86_64-linux" "i686-linux" ] ./initrd-network-openvpn { systemdStage1 = true; }; systemd-initrd-vlan = handleTest ./systemd-initrd-vlan.nix {}; systemd-journal = handleTest ./systemd-journal.nix {}; + systemd-journal-gateway = handleTest ./systemd-journal-gateway.nix {}; + systemd-journal-upload = handleTest ./systemd-journal-upload.nix {}; + systemd-lock-handler = runTestOn ["aarch64-linux" "x86_64-linux"] ./systemd-lock-handler.nix; systemd-machinectl = handleTest ./systemd-machinectl.nix {}; systemd-networkd = handleTest ./systemd-networkd.nix {}; systemd-networkd-dhcpserver = handleTest ./systemd-networkd-dhcpserver.nix {}; @@ -855,11 +874,15 @@ in { systemd-repart = handleTest ./systemd-repart.nix {}; systemd-shutdown = handleTest ./systemd-shutdown.nix {}; systemd-sysupdate = runTest ./systemd-sysupdate.nix; + systemd-sysusers-mutable = runTest ./systemd-sysusers-mutable.nix; + systemd-sysusers-immutable = runTest ./systemd-sysusers-immutable.nix; systemd-timesyncd = handleTest ./systemd-timesyncd.nix {}; + systemd-timesyncd-nscd-dnssec = handleTest ./systemd-timesyncd-nscd-dnssec.nix {}; systemd-user-tmpfiles-rules = handleTest ./systemd-user-tmpfiles-rules.nix {}; systemd-misc = handleTest ./systemd-misc.nix {}; systemd-userdbd = handleTest ./systemd-userdbd.nix {}; systemd-homed = handleTest ./systemd-homed.nix {}; + systemtap = handleTest ./systemtap.nix {}; tandoor-recipes = handleTest ./tandoor-recipes.nix {}; tang = handleTest ./tang.nix {}; taskserver = handleTest ./taskserver.nix {}; @@ -892,6 +915,7 @@ in { trilium-server = handleTestOn ["x86_64-linux"] ./trilium-server.nix {}; tsja = handleTest ./tsja.nix {}; tsm-client-gui = handleTest ./tsm-client-gui.nix {}; + ttyd = handleTest ./web-servers/ttyd.nix {}; txredisapi = handleTest ./txredisapi.nix {}; tuptime = handleTest ./tuptime.nix {}; turbovnc-headless-server = handleTest ./turbovnc-headless-server.nix {}; @@ -904,7 +928,8 @@ in { unbound = handleTest ./unbound.nix {}; unifi = handleTest ./unifi.nix {}; unit-php = handleTest ./web-servers/unit-php.nix {}; - upnp = handleTest ./upnp.nix {}; + upnp.iptables = handleTest ./upnp.nix { useNftables = false; }; + upnp.nftables = handleTest ./upnp.nix { useNftables = true; }; uptermd = handleTest ./uptermd.nix {}; uptime-kuma = handleTest ./uptime-kuma.nix {}; usbguard = handleTest ./usbguard.nix {}; @@ -930,6 +955,7 @@ in { vsftpd = handleTest ./vsftpd.nix {}; warzone2100 = handleTest ./warzone2100.nix {}; wasabibackend = handleTest ./wasabibackend.nix {}; + watchdogd = handleTest ./watchdogd.nix {}; webhook = runTest ./webhook.nix; wiki-js = handleTest ./wiki-js.nix {}; wine = handleTest ./wine.nix {}; @@ -947,6 +973,7 @@ in { xmonad-xdg-autostart = handleTest ./xmonad-xdg-autostart.nix {}; xpadneo = handleTest ./xpadneo.nix {}; xrdp = handleTest ./xrdp.nix {}; + xrdp-with-audio-pulseaudio = handleTest ./xrdp-with-audio-pulseaudio.nix {}; xscreensaver = handleTest ./xscreensaver.nix {}; xss-lock = handleTest ./xss-lock.nix {}; xterm = handleTest ./xterm.nix {}; diff --git a/nixos/tests/appliance-repart-image.nix b/nixos/tests/appliance-repart-image.nix index 3f256db84621..861369b9f3ca 100644 --- a/nixos/tests/appliance-repart-image.nix +++ b/nixos/tests/appliance-repart-image.nix @@ -8,9 +8,8 @@ let rootPartitionLabel = "root"; - bootLoaderConfigPath = "/loader/entries/nixos.conf"; - kernelPath = "/EFI/nixos/kernel.efi"; - initrdPath = "/EFI/nixos/initrd.efi"; + imageId = "nixos-appliance"; + imageVersion = "1-rc1"; in { name = "appliance-gpt-image"; @@ -29,6 +28,9 @@ in # TODO(raitobezarius): revisit this when #244907 lands boot.loader.grub.enable = false; + system.image.id = imageId; + system.image.version = imageVersion; + virtualisation.fileSystems = lib.mkForce { "/" = { device = "/dev/disk/by-partlabel/${rootPartitionLabel}"; @@ -38,6 +40,8 @@ in image.repart = { name = "appliance-gpt-image"; + # OVMF does not work with the default repart sector size of 4096 + sectorSize = 512; partitions = { "esp" = { contents = @@ -48,19 +52,8 @@ in "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; - # TODO: create an abstraction for Boot Loader Specification (BLS) entries. - "${bootLoaderConfigPath}".source = pkgs.writeText "nixos.conf" '' - title NixOS - linux ${kernelPath} - initrd ${initrdPath} - options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} - ''; - - "${kernelPath}".source = - "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}"; - - "${initrdPath}".source = - "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}"; + "/EFI/Linux/${config.system.boot.loader.ukiFile}".source = + "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; }; repartConfig = { Type = "esp"; @@ -99,7 +92,7 @@ in "-f", "qcow2", "-b", - "${nodes.machine.system.build.image}/image.raw", + "${nodes.machine.system.build.image}/${nodes.machine.image.repart.imageFile}", "-F", "raw", tmp_disk_image.name, @@ -108,9 +101,11 @@ in # Set NIX_DISK_IMAGE so that the qemu script finds the right disk image. os.environ['NIX_DISK_IMAGE'] = tmp_disk_image.name + os_release = machine.succeed("cat /etc/os-release") + assert 'IMAGE_ID="${imageId}"' in os_release + assert 'IMAGE_VERSION="${imageVersion}"' in os_release + bootctl_status = machine.succeed("bootctl status") - assert "${bootLoaderConfigPath}" in bootctl_status - assert "${kernelPath}" in bootctl_status - assert "${initrdPath}" in bootctl_status + assert "Boot Loader Specification Type #2 (.efi)" in bootctl_status ''; } diff --git a/nixos/tests/ayatana-indicators.nix b/nixos/tests/ayatana-indicators.nix index bc7ff75f390f..c9cbbda4c601 100644 --- a/nixos/tests/ayatana-indicators.nix +++ b/nixos/tests/ayatana-indicators.nix @@ -4,7 +4,7 @@ in { name = "ayatana-indicators"; meta = { - maintainers = with lib.maintainers; [ OPNA2608 ]; + maintainers = lib.teams.lomiri.members; }; nodes.machine = { config, ... }: { @@ -27,17 +27,56 @@ in { services.ayatana-indicators = { enable = true; packages = with pkgs; [ + ayatana-indicator-datetime ayatana-indicator-messages - ]; + ] ++ (with pkgs.lomiri; [ + lomiri-indicator-network + telephony-service + ]); }; - # Services needed by some indicators + # Setup needed by some indicators + services.accounts-daemon.enable = true; # messages + + # Lomiri-ish setup for Lomiri indicators + # TODO move into a Lomiri module, once the package set is far enough for the DE to start + + networking.networkmanager.enable = true; # lomiri-network-indicator + # TODO potentially urfkill for lomiri-network-indicator? + + services.dbus.packages = with pkgs.lomiri; [ + libusermetrics + ]; + + environment.systemPackages = with pkgs.lomiri; [ + lomiri-schemas + ]; + + services.telepathy.enable = true; + + users.users.usermetrics = { + group = "usermetrics"; + home = "/var/lib/usermetrics"; + createHome = true; + isSystemUser = true; + }; + + users.groups.usermetrics = { }; }; # 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; + runCommandOverServiceList = list: command: + lib.strings.concatMapStringsSep "\n" command list; + + runCommandOverAyatanaIndicators = runCommandOverServiceList + (builtins.filter + (service: !(lib.strings.hasPrefix "lomiri" service || lib.strings.hasPrefix "telephony-service" service)) + nodes.machine.systemd.user.targets."ayatana-indicators".wants); + + runCommandOverAllIndicators = runCommandOverServiceList + nodes.machine.systemd.user.targets."ayatana-indicators".wants; in '' start_all() machine.wait_for_x() @@ -50,8 +89,8 @@ in { 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}") + '' + (runCommandOverAyatanaIndicators (service: let serviceExec = builtins.replaceStrings [ "." ] [ "-" ] service; in '' + machine.succeed("pgrep -u ${user} -f ${serviceExec}") machine.succeed("pkill -f ${serviceExec}") '')) + '' @@ -65,7 +104,7 @@ in { machine.sleep(10) # Now check if all indicator services were brought up successfully - '' + runCommandPerIndicatorService (service: '' + '' + runCommandOverAllIndicators (service: '' machine.wait_for_unit("${service}", "${user}") ''); }) diff --git a/nixos/tests/babeld.nix b/nixos/tests/babeld.nix index d4df6f86d089..e497aa5b64e1 100644 --- a/nixos/tests/babeld.nix +++ b/nixos/tests/babeld.nix @@ -120,10 +120,6 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : { '' start_all() - client.wait_for_unit("network-online.target") - local_router.wait_for_unit("network-online.target") - remote_router.wait_for_unit("network-online.target") - local_router.wait_for_unit("babeld.service") remote_router.wait_for_unit("babeld.service") diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix index 4a73fea6a09d..473b05d4c98e 100644 --- a/nixos/tests/bittorrent.nix +++ b/nixos/tests/bittorrent.nix @@ -115,6 +115,7 @@ in start_all() # Wait for network and miniupnpd. + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") router.wait_for_unit("miniupnpd") @@ -129,6 +130,7 @@ in tracker.succeed("chmod 644 /tmp/test.torrent") # Start the tracker. !!! use a less crappy tracker + tracker.systemctl("start network-online.target") tracker.wait_for_unit("network-online.target") tracker.wait_for_unit("opentracker.service") tracker.wait_for_open_port(6969) @@ -140,6 +142,7 @@ in # Now we should be able to download from the client behind the NAT. tracker.wait_for_unit("httpd") + client1.systemctl("start network-online.target") client1.wait_for_unit("network-online.target") client1.succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent >&2 &") client1.wait_for_file("${download-dir}/test.tar.bz2") @@ -152,6 +155,7 @@ in # Now download from the second client. This can only succeed if # the first client created a NAT hole in the router. + client2.systemctl("start network-online.target") client2.wait_for_unit("network-online.target") client2.succeed( "transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht >&2 &" diff --git a/nixos/tests/bootspec.nix b/nixos/tests/bootspec.nix index 9295500422a9..14928b220625 100644 --- a/nixos/tests/bootspec.nix +++ b/nixos/tests/bootspec.nix @@ -112,10 +112,39 @@ in bootspec = json.loads(machine.succeed("jq -r '.\"org.nixos.bootspec.v1\"' /run/current-system/boot.json")) - assert all(key in bootspec for key in ('initrd', 'initrdSecrets')), "Bootspec should contain initrd or initrdSecrets field when initrd is enabled" + assert 'initrd' in bootspec, "Bootspec should contain initrd field when initrd is enabled" + assert 'initrdSecrets' not in bootspec, "Bootspec should not contain initrdSecrets when there's no initrdSecrets" ''; }; + # Check that initrd secrets create corresponding entries in bootspec. + initrd-secrets = makeTest { + name = "bootspec-with-initrd-secrets"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { + imports = [ standard ]; + environment.systemPackages = [ pkgs.jq ]; + # It's probably the case, but we want to make it explicit here. + boot.initrd.enable = true; + boot.initrd.secrets."/some/example" = pkgs.writeText "example-secret" "test"; + }; + + testScript = '' + import json + + machine.start() + machine.wait_for_unit("multi-user.target") + + machine.succeed("test -e /run/current-system/boot.json") + + bootspec = json.loads(machine.succeed("jq -r '.\"org.nixos.bootspec.v1\"' /run/current-system/boot.json")) + + assert 'initrdSecrets' in bootspec, "Bootspec should contain an 'initrdSecrets' field given there's an initrd secret" + ''; + }; + + # Check that specialisations create corresponding entries in bootspec. specialisation = makeTest { name = "bootspec-with-specialisation"; diff --git a/nixos/tests/budgie.nix b/nixos/tests/budgie.nix index 19d9b2bd0bed..fe0ed2cf80ed 100644 --- a/nixos/tests/budgie.nix +++ b/nixos/tests/budgie.nix @@ -33,14 +33,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { '' with subtest("Wait for login"): # wait_for_x() checks graphical-session.target, which is expected to be - # inactive on Budgie before #228946 (i.e. systemd managed gnome-session) is - # done on upstream. - # https://github.com/BuddiesOfBudgie/budgie-desktop/blob/v10.7.2/src/session/budgie-desktop.in#L16 + # inactive on Budgie before Budgie manages user session with systemd. + # https://github.com/BuddiesOfBudgie/budgie-desktop/blob/39e9f0895c978f76/src/session/budgie-desktop.in#L16 # # Previously this was unconditionally touched by xsessionWrapper but was # changed in #233981 (we have Budgie:GNOME in XDG_CURRENT_DESKTOP). # machine.wait_for_x() - machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"') + machine.wait_until_succeeds('journalctl -t budgie-session-binary --grep "Entering running state"') machine.wait_for_file("${user.home}/.Xauthority") machine.succeed("xauth merge ${user.home}/.Xauthority") diff --git a/nixos/tests/buildbot.nix b/nixos/tests/buildbot.nix index dbf68aba9467..149d73bba09c 100644 --- a/nixos/tests/buildbot.nix +++ b/nixos/tests/buildbot.nix @@ -71,6 +71,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { gitrepo.wait_for_unit("multi-user.target") with subtest("Repo is accessible via git daemon"): + bbmaster.systemctl("start network-online.target") bbmaster.wait_for_unit("network-online.target") bbmaster.succeed("rm -rfv /tmp/fakerepo") bbmaster.succeed("git clone git://gitrepo/fakerepo /tmp/fakerepo") @@ -78,6 +79,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { with subtest("Master service and worker successfully connect"): bbmaster.wait_for_unit("buildbot-master.service") bbmaster.wait_until_succeeds("curl --fail -s --head http://bbmaster:8010") + bbworker.systemctl("start network-online.target") bbworker.wait_for_unit("network-online.target") bbworker.succeed("nc -z bbmaster 8010") bbworker.succeed("nc -z bbmaster 9989") @@ -104,5 +106,5 @@ import ./make-test-python.nix ({ pkgs, ... }: { bbworker.fail("nc -z bbmaster 8011") ''; - meta.maintainers = with pkgs.lib.maintainers; [ ]; + meta.maintainers = pkgs.lib.teams.buildbot.members; }) diff --git a/nixos/tests/c2fmzq.nix b/nixos/tests/c2fmzq.nix index d8ec816c7d29..0dd89f6881dd 100644 --- a/nixos/tests/c2fmzq.nix +++ b/nixos/tests/c2fmzq.nix @@ -9,6 +9,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { passphraseFile = builtins.toFile "pwfile" "hunter2"; # don't do this on real deployments settings = { verbose = 3; # debug + # make sure multiple freeform options evaluate + allow-new-accounts = true; + auto-approve-new-accounts = true; + licenses = false; }; }; environment = { @@ -71,5 +75,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { with subtest("Test that PWA is served"): msg = machine.succeed("curl -sSfL http://localhost:8080") assert "c2FmZQ" in msg, f"Could not find 'c2FmZQ' in the output:\n{msg}" + + with subtest("A setting with false value is properly passed"): + machine.succeed("systemctl show -p ExecStart --value c2fmzq-server.service | grep -F -- '--licenses=false'"); ''; }) diff --git a/nixos/tests/ceph-multi-node.nix b/nixos/tests/ceph-multi-node.nix index 556546beee76..b1352a4bc8f4 100644 --- a/nixos/tests/ceph-multi-node.nix +++ b/nixos/tests/ceph-multi-node.nix @@ -185,6 +185,14 @@ let monA.succeed( "ceph osd pool create multi-node-test 32 32", "ceph osd pool ls | grep 'multi-node-test'", + + # We need to enable an application on the pool, otherwise it will + # stay unhealthy in state POOL_APP_NOT_ENABLED. + # Creating a CephFS would do this automatically, but we haven't done that here. + # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application + # We use the custom application name "nixos-test" for this. + "ceph osd pool application enable multi-node-test nixos-test", + "ceph osd pool rename multi-node-test multi-node-other-test", "ceph osd pool ls | grep 'multi-node-other-test'", ) diff --git a/nixos/tests/ceph-single-node-bluestore.nix b/nixos/tests/ceph-single-node-bluestore.nix index acaae4cf300e..8bd1a78244a2 100644 --- a/nixos/tests/ceph-single-node-bluestore.nix +++ b/nixos/tests/ceph-single-node-bluestore.nix @@ -145,6 +145,14 @@ let monA.succeed( "ceph osd pool create single-node-test 32 32", "ceph osd pool ls | grep 'single-node-test'", + + # We need to enable an application on the pool, otherwise it will + # stay unhealthy in state POOL_APP_NOT_ENABLED. + # Creating a CephFS would do this automatically, but we haven't done that here. + # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application + # We use the custom application name "nixos-test" for this. + "ceph osd pool application enable single-node-test nixos-test", + "ceph osd pool rename single-node-test single-node-other-test", "ceph osd pool ls | grep 'single-node-other-test'", ) diff --git a/nixos/tests/ceph-single-node.nix b/nixos/tests/ceph-single-node.nix index a3a4072365af..c34ec511dc6d 100644 --- a/nixos/tests/ceph-single-node.nix +++ b/nixos/tests/ceph-single-node.nix @@ -145,6 +145,14 @@ let monA.succeed( "ceph osd pool create single-node-test 32 32", "ceph osd pool ls | grep 'single-node-test'", + + # We need to enable an application on the pool, otherwise it will + # stay unhealthy in state POOL_APP_NOT_ENABLED. + # Creating a CephFS would do this automatically, but we haven't done that here. + # See: https://docs.ceph.com/en/reef/rados/operations/pools/#associating-a-pool-with-an-application + # We use the custom application name "nixos-test" for this. + "ceph osd pool application enable single-node-test nixos-test", + "ceph osd pool rename single-node-test single-node-other-test", "ceph osd pool ls | grep 'single-node-other-test'", ) @@ -182,19 +190,16 @@ let monA.wait_until_succeeds("ceph -s | grep 'mgr: ${cfg.monA.name}(active,'") monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") - # This test has been commented out due to the upstream issue with pyo3 - # that has broken this dashboard - # Reference: https://www.spinics.net/lists/ceph-users/msg77812.html # Enable the dashboard and recheck health - # monA.succeed( - # "ceph mgr module enable dashboard", - # "ceph config set mgr mgr/dashboard/ssl false", - # # default is 8080 but it's better to be explicit - # "ceph config set mgr mgr/dashboard/server_port 8080", - # ) - # monA.wait_for_open_port(8080) - # monA.wait_until_succeeds("curl -q --fail http://localhost:8080") - # monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") + monA.succeed( + "ceph mgr module enable dashboard", + "ceph config set mgr mgr/dashboard/ssl false", + # default is 8080 but it's better to be explicit + "ceph config set mgr mgr/dashboard/server_port 8080", + ) + monA.wait_for_open_port(8080) + monA.wait_until_succeeds("curl -q --fail http://localhost:8080") + monA.wait_until_succeeds("ceph -s | grep 'HEALTH_OK'") ''; in { name = "basic-single-node-ceph-cluster"; diff --git a/nixos/tests/cinnamon-wayland.nix b/nixos/tests/cinnamon-wayland.nix index 824a606004cc..1629ead16f41 100644 --- a/nixos/tests/cinnamon-wayland.nix +++ b/nixos/tests/cinnamon-wayland.nix @@ -64,7 +64,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { # 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'") + machine.wait_until_succeeds("journalctl -b --grep 'cinnamon-screensaver is disabled in wayland sessions'") with subtest("Open GNOME Terminal"): machine.succeed("${su "dbus-launch gnome-terminal"}") diff --git a/nixos/tests/cloud-init.nix b/nixos/tests/cloud-init.nix index 786e01add7d4..0b4c5a55c80a 100644 --- a/nixos/tests/cloud-init.nix +++ b/nixos/tests/cloud-init.nix @@ -73,6 +73,7 @@ in makeTest { }; testScript = '' # To wait until cloud-init terminates its run + unnamed.wait_for_unit("cloud-init-local.service") unnamed.wait_for_unit("cloud-final.service") unnamed.succeed("cat /tmp/cloudinit-write-file | grep -q 'cloudinit'") diff --git a/nixos/tests/corerad.nix b/nixos/tests/corerad.nix index b6f5d7fc6f75..dd2bec794a1a 100644 --- a/nixos/tests/corerad.nix +++ b/nixos/tests/corerad.nix @@ -56,6 +56,8 @@ import ./make-test-python.nix ( with subtest("Wait for CoreRAD and network ready"): # Ensure networking is online and CoreRAD is ready. + router.systemctl("start network-online.target") + client.systemctl("start network-online.target") router.wait_for_unit("network-online.target") client.wait_for_unit("network-online.target") router.wait_for_unit("corerad.service") diff --git a/nixos/tests/curl-impersonate.nix b/nixos/tests/curl-impersonate.nix index 7954e9e5584c..33b10da1dfd0 100644 --- a/nixos/tests/curl-impersonate.nix +++ b/nixos/tests/curl-impersonate.nix @@ -144,6 +144,8 @@ in { start_all() with subtest("Wait for network"): + web.systemctl("start network-online.target") + curl.systemctl("start network-online.target") web.wait_for_unit("network-online.target") curl.wait_for_unit("network-online.target") diff --git a/nixos/tests/dnsdist.nix b/nixos/tests/dnsdist.nix index e72fa05ff282..9921be419a75 100644 --- a/nixos/tests/dnsdist.nix +++ b/nixos/tests/dnsdist.nix @@ -1,48 +1,113 @@ -import ./make-test-python.nix ( - { pkgs, ... }: { - name = "dnsdist"; - meta = with pkgs.lib; { - maintainers = with maintainers; [ jojosch ]; - }; +{ pkgs, runTest }: - nodes.machine = { pkgs, lib, ... }: { - services.bind = { - enable = true; - extraOptions = "empty-zones-enable no;"; - zones = lib.singleton { - name = "."; - master = true; - file = pkgs.writeText "root.zone" '' - $TTL 3600 - . IN SOA ns.example.org. admin.example.org. ( 1 3h 1h 1w 1d ) - . IN NS ns.example.org. - - ns.example.org. IN A 192.168.0.1 - ns.example.org. IN AAAA abcd::1 - - 1.0.168.192.in-addr.arpa IN PTR ns.example.org. - ''; - }; - }; - services.dnsdist = { - enable = true; - listenPort = 5353; - extraConfig = '' - newServer({address="127.0.0.1:53", name="local-bind"}) +let + + inherit (pkgs) lib; + + baseConfig = { + networking.nameservers = [ "::1" ]; + services.bind = { + enable = true; + extraOptions = "empty-zones-enable no;"; + zones = lib.singleton { + name = "."; + master = true; + file = pkgs.writeText "root.zone" '' + $TTL 3600 + . IN SOA ns.example.org. admin.example.org. ( 1 3h 1h 1w 1d ) + . IN NS ns.example.org. + + ns.example.org. IN A 192.168.0.1 + ns.example.org. IN AAAA abcd::1 + + 1.0.168.192.in-addr.arpa IN PTR ns.example.org. ''; }; - - environment.systemPackages = with pkgs; [ dig ]; }; + services.dnsdist = { + enable = true; + listenPort = 5353; + extraConfig = '' + newServer({address="127.0.0.1:53", name="local-bind"}) + ''; + }; + }; + +in + +{ + + base = runTest { + name = "dnsdist-base"; + meta.maintainers = with lib.maintainers; [ jojosch ]; + + nodes.machine = baseConfig; testScript = '' machine.wait_for_unit("bind.service") machine.wait_for_open_port(53) - machine.succeed("dig @127.0.0.1 +short -x 192.168.0.1 | grep -qF ns.example.org") + machine.succeed("host -p 53 192.168.0.1 | grep -qF ns.example.org") machine.wait_for_unit("dnsdist.service") machine.wait_for_open_port(5353) - machine.succeed("dig @127.0.0.1 -p 5353 +short -x 192.168.0.1 | grep -qF ns.example.org") + machine.succeed("host -p 5353 192.168.0.1 | grep -qF ns.example.org") + ''; + }; + + dnscrypt = runTest { + name = "dnsdist-dnscrypt"; + meta.maintainers = with lib.maintainers; [ rnhmjoj ]; + + nodes.server = lib.mkMerge [ + baseConfig + { + networking.firewall.allowedTCPPorts = [ 443 ]; + networking.firewall.allowedUDPPorts = [ 443 ]; + services.dnsdist.dnscrypt.enable = true; + services.dnsdist.dnscrypt.providerKey = "${./dnscrypt-wrapper/secret.key}"; + } + ]; + + nodes.client = { + services.dnscrypt-proxy2.enable = true; + services.dnscrypt-proxy2.upstreamDefaults = false; + services.dnscrypt-proxy2.settings = + { server_names = [ "server" ]; + listen_addresses = [ "[::1]:53" ]; + cache = false; + # Computed using https://dnscrypt.info/stamps/ + static.server.stamp = + "sdns://AQAAAAAAAAAADzE5Mi4xNjguMS4yOjQ0MyAUQdg6_RIIpK6pHkINhrv7nxwIG5c7b_m5NJVT3A1AXRYyLmRuc2NyeXB0LWNlcnQuc2VydmVy"; + }; + networking.nameservers = [ "::1" ]; + }; + + testScript = '' + with subtest("The DNSCrypt server is accepting connections"): + server.wait_for_unit("bind.service") + server.wait_for_unit("dnsdist.service") + server.wait_for_open_port(443) + almost_expiration = server.succeed("date --date '14min'").strip() + + with subtest("The DNSCrypt client can connect to the server"): + client.wait_until_succeeds("journalctl -u dnscrypt-proxy2 --grep '\[server\] OK'") + + with subtest("DNS queries over UDP are working"): + client.wait_for_open_port(53) + client.succeed("host -U 192.168.0.1 | grep -qF ns.example.org") + + with subtest("DNS queries over TCP are working"): + client.wait_for_open_port(53) + client.succeed("host -T 192.168.0.1 | grep -qF ns.example.org") + + with subtest("The server rotates the ephemeral keys"): + server.succeed(f"date -s '{almost_expiration}'") + client.succeed(f"date -s '{almost_expiration}'") + server.wait_until_succeeds("journalctl -u dnsdist --grep 'rotated certificate'") + + with subtest("The client can still connect to the server"): + client.wait_until_succeeds("host -T 192.168.0.1") + client.wait_until_succeeds("host -U 192.168.0.1") ''; - } -) + }; +} diff --git a/nixos/tests/dolibarr.nix b/nixos/tests/dolibarr.nix index 4fdee9e9698f..95557d317fab 100644 --- a/nixos/tests/dolibarr.nix +++ b/nixos/tests/dolibarr.nix @@ -1,6 +1,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { name = "dolibarr"; - meta.maintainers = [ lib.maintainers.raitobezarius ]; + meta.maintainers = [ ]; nodes.machine = { ... }: diff --git a/nixos/tests/elk.nix b/nixos/tests/elk.nix index 900ea6320100..b5a8cb532ae0 100644 --- a/nixos/tests/elk.nix +++ b/nixos/tests/elk.nix @@ -1,6 +1,6 @@ # To run the test on the unfree ELK use the following command: # cd path/to/nixpkgs -# NIXPKGS_ALLOW_UNFREE=1 nix-build -A nixosTests.elk.unfree.ELK-6 +# NIXPKGS_ALLOW_UNFREE=1 nix-build -A nixosTests.elk.unfree.ELK-7 { system ? builtins.currentSystem, config ? {}, @@ -120,7 +120,7 @@ let }; elasticsearch-curator = { - enable = true; + enable = elk ? elasticsearch-curator; actionYAML = '' --- actions: @@ -246,7 +246,7 @@ let one.wait_until_succeeds( expect_hits("SuperdupercalifragilisticexpialidociousIndeed") ) - '' + '' + '' + lib.optionalString (elk ? elasticsearch-curator) '' with subtest("Elasticsearch-curator works"): one.systemctl("stop logstash") one.systemctl("start elasticsearch-curator") diff --git a/nixos/tests/ferm.nix b/nixos/tests/ferm.nix index be43877445eb..87c67ac62347 100644 --- a/nixos/tests/ferm.nix +++ b/nixos/tests/ferm.nix @@ -55,6 +55,8 @@ import ./make-test-python.nix ({ pkgs, ...} : { '' start_all() + client.systemctl("start network-online.target") + server.systemctl("start network-online.target") client.wait_for_unit("network-online.target") server.wait_for_unit("network-online.target") server.wait_for_unit("ferm.service") diff --git a/nixos/tests/frp.nix b/nixos/tests/frp.nix index 2f5c0f8ec933..1f57c031a53a 100644 --- a/nixos/tests/frp.nix +++ b/nixos/tests/frp.nix @@ -18,10 +18,8 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { enable = true; role = "server"; settings = { - common = { - bind_port = 7000; - vhost_http_port = 80; - }; + bindPort = 7000; + vhostHTTPPort = 80; }; }; }; @@ -59,15 +57,16 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { enable = true; role = "client"; settings = { - common = { - server_addr = "10.0.0.1"; - server_port = 7000; - }; - web = { - type = "http"; - local_port = 80; - custom_domains = "10.0.0.1"; - }; + serverAddr = "10.0.0.1"; + serverPort = 7000; + proxies = [ + { + name = "web"; + type = "http"; + localPort = 80; + customDomains = [ "10.0.0.1" ]; + } + ]; }; }; }; diff --git a/nixos/tests/frr.nix b/nixos/tests/frr.nix index 598d7a7d2867..0d1a6a694a82 100644 --- a/nixos/tests/frr.nix +++ b/nixos/tests/frr.nix @@ -29,7 +29,7 @@ import ./make-test-python.nix ({ pkgs, ... }: name = "frr"; meta = with pkgs.lib.maintainers; { - maintainers = [ hexa ]; + maintainers = [ ]; }; nodes = { diff --git a/nixos/tests/gitdaemon.nix b/nixos/tests/gitdaemon.nix index bb07b6e97b7f..052fa902b450 100644 --- a/nixos/tests/gitdaemon.nix +++ b/nixos/tests/gitdaemon.nix @@ -59,6 +59,9 @@ in { with subtest("git daemon starts"): server.wait_for_unit("git-daemon.service") + + server.systemctl("start network-online.target") + client.systemctl("start network-online.target") server.wait_for_unit("network-online.target") client.wait_for_unit("network-online.target") diff --git a/nixos/tests/guix/publish.nix b/nixos/tests/guix/publish.nix index a15e00b0fa98..eb56fc97478c 100644 --- a/nixos/tests/guix/publish.nix +++ b/nixos/tests/guix/publish.nix @@ -80,6 +80,7 @@ in { # Now it's the client turn to make use of it. substitute_server = "http://server.local:${toString publishPort}" + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") response = client.succeed(f"curl {substitute_server}") assert "Guix Substitute Server" in response diff --git a/nixos/tests/haproxy.nix b/nixos/tests/haproxy.nix index 555474d7f299..173093873757 100644 --- a/nixos/tests/haproxy.nix +++ b/nixos/tests/haproxy.nix @@ -1,22 +1,42 @@ -import ./make-test-python.nix ({ pkgs, ...}: { +import ./make-test-python.nix ({ lib, pkgs, ...}: { name = "haproxy"; nodes = { - machine = { ... }: { - services.haproxy = { + server = { ... }: { + services.haproxy = { enable = true; config = '' + global + limited-quic + defaults + mode http timeout connect 10s + timeout client 10s + timeout server 10s + + log /dev/log local0 debug err + option logasap + option httplog + option httpslog backend http_server - mode http - server httpd [::1]:8000 + server httpd [::1]:8000 alpn http/1.1 frontend http - bind *:80 - mode http + bind :80 + bind :443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h2,http/1.1 + bind quic4@:443 ssl strict-sni crt /etc/ssl/fullchain.pem alpn h3 allow-0rtt + + http-after-response add-header alt-svc 'h3=":443"; ma=60' if { ssl_fc } + http-request use-service prometheus-exporter if { path /metrics } use_backend http_server + + frontend http-cert-auth + bind :8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt + bind quic4@:8443 ssl strict-sni crt /etc/ssl/fullchain.pem verify required ca-file /etc/ssl/cacert.crt alpn h3 + + use_backend http_server ''; }; services.httpd = { @@ -30,24 +50,75 @@ import ./make-test-python.nix ({ pkgs, ...}: { }]; }; }; + networking.firewall.allowedTCPPorts = [ 80 443 8443 ]; + networking.firewall.allowedUDPPorts = [ 443 8443 ]; + }; + client = { ... }: { + environment.systemPackages = [ pkgs.curlHTTP3 ]; }; }; testScript = '' + # Helpers + def cmd(command): + print(f"+{command}") + r = os.system(command) + if r != 0: + raise Exception(f"Command {command} failed with exit code {r}") + + def openssl(command): + cmd(f"${pkgs.openssl}/bin/openssl {command}") + + # Generate CA. + openssl("req -new -newkey rsa:4096 -nodes -x509 -days 7 -subj '/C=ZZ/ST=Cloud/L=Unspecified/O=NixOS/OU=Tests/CN=CA Certificate' -keyout cacert.key -out cacert.crt") + + # Generate and sign Server. + openssl("req -newkey rsa:4096 -nodes -subj '/CN=server/OU=Tests/O=NixOS' -keyout server.key -out server.csr") + openssl("x509 -req -in server.csr -out server.crt -CA cacert.crt -CAkey cacert.key -days 7") + cmd("cat server.crt server.key > fullchain.pem") + + # Generate and sign Client. + openssl("req -newkey rsa:4096 -nodes -subj '/CN=client/OU=Tests/O=NixOS' -keyout client.key -out client.csr") + openssl("x509 -req -in client.csr -out client.crt -CA cacert.crt -CAkey cacert.key -days 7") + cmd("cat client.crt client.key > client.pem") + + # Start the actual test. start_all() - machine.wait_for_unit("multi-user.target") - machine.wait_for_unit("haproxy.service") - machine.wait_for_unit("httpd.service") - assert "We are all good!" in machine.succeed("curl -fk http://localhost:80/index.txt") - assert "haproxy_process_pool_allocated_bytes" in machine.succeed( - "curl -fk http://localhost:80/metrics" - ) + server.copy_from_host("fullchain.pem", "/etc/ssl/fullchain.pem") + server.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt") + server.succeed("chmod 0644 /etc/ssl/fullchain.pem /etc/ssl/cacert.crt") + + client.copy_from_host("cacert.crt", "/etc/ssl/cacert.crt") + client.copy_from_host("client.pem", "/root/client.pem") + + server.wait_for_unit("multi-user.target") + server.wait_for_unit("haproxy.service") + server.wait_for_unit("httpd.service") + + assert "We are all good!" in client.succeed("curl -f http://server/index.txt") + assert "haproxy_process_pool_allocated_bytes" in client.succeed("curl -f http://server/metrics") + + with subtest("https"): + assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt https://server/index.txt") + + with subtest("https-cert-auth"): + # Client must succeed in authenticating with the right certificate. + assert "We are all good!" in client.succeed("curl -f --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt") + # Client must fail without certificate. + client.fail("curl --cacert /etc/ssl/cacert.crt https://server:8443/index.txt") + + with subtest("h3"): + assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server/index.txt") + + with subtest("h3-cert-auth"): + # Client must succeed in authenticating with the right certificate. + assert "We are all good!" in client.succeed("curl -f --http3-only --cacert /etc/ssl/cacert.crt --cert-type pem --cert /root/client.pem https://server:8443/index.txt") + # Client must fail without certificate. + client.fail("curl -f --http3-only --cacert /etc/ssl/cacert.crt https://server:8443/index.txt") with subtest("reload"): - machine.succeed("systemctl reload haproxy") + server.succeed("systemctl reload haproxy") # wait some time to ensure the following request hits the reloaded haproxy - machine.sleep(5) - assert "We are all good!" in machine.succeed( - "curl -fk http://localhost:80/index.txt" - ) + server.sleep(5) + assert "We are all good!" in client.succeed("curl -f http://server/index.txt") ''; }) diff --git a/nixos/tests/hostname.nix b/nixos/tests/hostname.nix index 6122e2ffeb83..dffec956bc0b 100644 --- a/nixos/tests/hostname.nix +++ b/nixos/tests/hostname.nix @@ -34,6 +34,7 @@ let machine = ${hostName} + machine.systemctl("start network-online.target") machine.wait_for_unit("network-online.target") # Test if NixOS computes the correct FQDN (either a FQDN or an error/null): diff --git a/nixos/tests/incus/default.nix b/nixos/tests/incus/default.nix index c88974605e30..26e8a4ac4c77 100644 --- a/nixos/tests/incus/default.nix +++ b/nixos/tests/incus/default.nix @@ -6,9 +6,8 @@ }: { container = import ./container.nix { inherit system pkgs; }; + lxd-to-incus = import ./lxd-to-incus.nix { inherit system pkgs; }; preseed = import ./preseed.nix { inherit system pkgs; }; socket-activated = import ./socket-activated.nix { inherit system pkgs; }; - virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { - inherit system pkgs; - }; + virtual-machine = handleTestOn [ "x86_64-linux" ] ./virtual-machine.nix { inherit system pkgs; }; } diff --git a/nixos/tests/incus/lxd-to-incus.nix b/nixos/tests/incus/lxd-to-incus.nix new file mode 100644 index 000000000000..67245b54e752 --- /dev/null +++ b/nixos/tests/incus/lxd-to-incus.nix @@ -0,0 +1,112 @@ +import ../make-test-python.nix ( + + { pkgs, lib, ... }: + + let + releases = import ../../release.nix { configuration.documentation.enable = lib.mkForce false; }; + + container-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system}; + container-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system}; + in + { + name = "lxd-to-incus"; + + meta = { + maintainers = lib.teams.lxc.members; + }; + + nodes.machine = + { lib, ... }: + { + environment.systemPackages = [ pkgs.lxd-to-incus ]; + + virtualisation = { + diskSize = 6144; + cores = 2; + memorySize = 2048; + + lxd.enable = true; + lxd.preseed = { + networks = [ + { + name = "nixostestbr0"; + type = "bridge"; + config = { + "ipv4.address" = "10.0.100.1/24"; + "ipv4.nat" = "true"; + }; + } + ]; + profiles = [ + { + name = "default"; + devices = { + eth0 = { + name = "eth0"; + network = "nixostestbr0"; + type = "nic"; + }; + root = { + path = "/"; + pool = "nixostest_pool"; + size = "35GiB"; + type = "disk"; + }; + }; + } + { + name = "nixos_notdefault"; + devices = { }; + } + ]; + storage_pools = [ + { + name = "nixostest_pool"; + driver = "dir"; + } + ]; + }; + + incus.enable = true; + }; + }; + + testScript = '' + def lxd_wait_for_preseed(_) -> bool: + _, output = machine.systemctl("is-active lxd-preseed.service") + return ("inactive" in output) + + def lxd_instance_is_up(_) -> bool: + status, _ = machine.execute("lxc exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true") + return status == 0 + + def incus_instance_is_up(_) -> bool: + status, _ = machine.execute("incus exec container --disable-stdin --force-interactive /run/current-system/sw/bin/true") + return status == 0 + + with machine.nested("initialize lxd and resources"): + machine.wait_for_unit("sockets.target") + machine.wait_for_unit("lxd.service") + retry(lxd_wait_for_preseed) + + machine.succeed("lxc image import ${container-image-metadata}/*/*.tar.xz ${container-image-rootfs}/*/*.tar.xz --alias nixos") + machine.succeed("lxc launch nixos container") + retry(lxd_instance_is_up) + + machine.wait_for_unit("incus.service") + + with machine.nested("run migration"): + machine.succeed("lxd-to-incus --yes") + + with machine.nested("verify resources migrated to incus"): + machine.succeed("incus config show container") + retry(incus_instance_is_up) + machine.succeed("incus exec container -- true") + machine.succeed("incus profile show default | grep nixostestbr0") + machine.succeed("incus profile show default | grep nixostest_pool") + machine.succeed("incus profile show nixos_notdefault") + machine.succeed("incus storage show nixostest_pool") + machine.succeed("incus network show nixostestbr0") + ''; + } +) diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index d83e49a3e8f7..7576fae41f83 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -158,7 +158,9 @@ let start_all() ${optionalString clevisTest '' tang.wait_for_unit("sockets.target") + tang.systemctl("start network-online.target") tang.wait_for_unit("network-online.target") + machine.systemctl("start network-online.target") machine.wait_for_unit("network-online.target") ''} machine.wait_for_unit("multi-user.target") @@ -187,6 +189,7 @@ let ${optionalString clevisTest '' with subtest("Create the Clevis secret with Tang"): + machine.systemctl("start network-online.target") machine.wait_for_unit("network-online.target") machine.succeed('echo -n password | clevis encrypt sss \'{"t": 2, "pins": {"tpm2": {}, "tang": {"url": "http://192.168.1.2"}}}\' -y > /mnt/etc/nixos/clevis-secret.jwe')''} @@ -510,14 +513,8 @@ let ntp perlPackages.ListCompare perlPackages.XMLLibXML - python3Minimal # make-options-doc/default.nix - (let - self = (pkgs.python3Minimal.override { - inherit self; - includeSiteCustomize = true; - }); - in self.withPackages (p: [ p.mistune ])) + (python3.withPackages (p: [ p.mistune ])) shared-mime-info sudo texinfo @@ -1266,68 +1263,6 @@ in { ''; }; - bcachefsLinuxTesting = makeInstallerTest "bcachefs-linux-testing" { - extraInstallerConfig = { - imports = [ no-zfs-module ]; - - boot = { - supportedFilesystems = [ "bcachefs" ]; - kernelPackages = pkgs.linuxPackages_testing; - }; - }; - - extraConfig = '' - boot.kernelPackages = pkgs.linuxPackages_testing; - ''; - - 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", - ) - ''; - }; - - bcachefsUpgradeToLinuxTesting = makeInstallerTest "bcachefs-upgrade-to-linux-testing" { - extraInstallerConfig = { - imports = [ no-zfs-module ]; - boot.supportedFilesystems = [ "bcachefs" ]; - # We don't have network access in the VM, we need this for `nixos-install` - system.extraDependencies = [ pkgs.linux_testing ]; - }; - - extraConfig = '' - boot.kernelPackages = pkgs.linuxPackages_testing; - ''; - - 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", - ) - ''; - }; - # Test using labels to identify volumes in grub simpleLabels = makeInstallerTest "simpleLabels" { createPartitions = '' diff --git a/nixos/tests/invoiceplane.nix b/nixos/tests/invoiceplane.nix index 70ed96ee39f3..0b5170717199 100644 --- a/nixos/tests/invoiceplane.nix +++ b/nixos/tests/invoiceplane.nix @@ -27,56 +27,80 @@ import ./make-test-python.nix ({ pkgs, ... }: networking.firewall.allowedTCPPorts = [ 80 ]; networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ]; }; + + invoiceplane_nginx = { ... }: { + services.invoiceplane.webserver = "nginx"; + services.invoiceplane.sites = { + "site1.local" = { + database.name = "invoiceplane1"; + database.createLocally = true; + enable = true; + }; + "site2.local" = { + database.name = "invoiceplane2"; + database.createLocally = true; + enable = true; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 ]; + networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ]; + }; }; testScript = '' start_all() invoiceplane_caddy.wait_for_unit("caddy") - invoiceplane_caddy.wait_for_open_port(80) - invoiceplane_caddy.wait_for_open_port(3306) + invoiceplane_nginx.wait_for_unit("nginx") site_names = ["site1.local", "site2.local"] - for site_name in site_names: - machine.wait_for_unit(f"phpfpm-invoiceplane-{site_name}") + machines = [invoiceplane_caddy, invoiceplane_nginx] + + for machine in machines: + machine.wait_for_open_port(80) + machine.wait_for_open_port(3306) + + for site_name in site_names: + machine.wait_for_unit(f"phpfpm-invoiceplane-{site_name}") - with subtest("Website returns welcome screen"): - assert "Please install InvoicePlane" in machine.succeed(f"curl -L {site_name}") + with subtest("Website returns welcome screen"): + assert "Please install InvoicePlane" in machine.succeed(f"curl -L {site_name}") - with subtest("Finish InvoicePlane setup"): - machine.succeed( - f"curl -sSfL --cookie-jar cjar {site_name}/setup/language" - ) - csrf_token = machine.succeed( - "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" - ) - machine.succeed( - f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&ip_lang=english&btn_continue=Continue' {site_name}/setup/language" - ) - csrf_token = machine.succeed( - "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" - ) - machine.succeed( - f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/prerequisites" - ) - csrf_token = machine.succeed( - "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" - ) - machine.succeed( - f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/configure_database" - ) - csrf_token = machine.succeed( - "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" - ) - machine.succeed( - f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/install_tables" - ) - csrf_token = machine.succeed( - "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" - ) - machine.succeed( - f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/upgrade_tables" - ) + with subtest("Finish InvoicePlane setup"): + machine.succeed( + f"curl -sSfL --cookie-jar cjar {site_name}/setup/language" + ) + csrf_token = machine.succeed( + "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" + ) + machine.succeed( + f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&ip_lang=english&btn_continue=Continue' {site_name}/setup/language" + ) + csrf_token = machine.succeed( + "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" + ) + machine.succeed( + f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/prerequisites" + ) + csrf_token = machine.succeed( + "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" + ) + machine.succeed( + f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/configure_database" + ) + csrf_token = machine.succeed( + "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" + ) + machine.succeed( + f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/install_tables" + ) + csrf_token = machine.succeed( + "grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'" + ) + machine.succeed( + f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/setup/upgrade_tables" + ) ''; }) diff --git a/nixos/tests/kanidm.nix b/nixos/tests/kanidm.nix index 3f5bca397740..fa24d4a8a5e1 100644 --- a/nixos/tests/kanidm.nix +++ b/nixos/tests/kanidm.nix @@ -67,6 +67,7 @@ import ./make-test-python.nix ({ pkgs, ... }: '' start_all() server.wait_for_unit("kanidm.service") + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") with subtest("Test HTTP interface"): diff --git a/nixos/tests/keepalived.nix b/nixos/tests/keepalived.nix index d0bf9d465200..ce291514591f 100644 --- a/nixos/tests/keepalived.nix +++ b/nixos/tests/keepalived.nix @@ -1,5 +1,6 @@ -import ./make-test-python.nix ({ pkgs, ... }: { +import ./make-test-python.nix ({ pkgs, lib, ... }: { name = "keepalived"; + maintainers = [ lib.maintainers.raitobezarius ]; nodes = { node1 = { pkgs, ... }: { diff --git a/nixos/tests/kerberos/heimdal.nix b/nixos/tests/kerberos/heimdal.nix index 47f9d0285aef..393289f7a92c 100644 --- a/nixos/tests/kerberos/heimdal.nix +++ b/nixos/tests/kerberos/heimdal.nix @@ -1,5 +1,6 @@ import ../make-test-python.nix ({pkgs, ...}: { name = "kerberos_server-heimdal"; + nodes.machine = { config, libs, pkgs, ...}: { services.kerberos_server = { enable = true; @@ -7,16 +8,18 @@ import ../make-test-python.nix ({pkgs, ...}: { "FOO.BAR".acl = [{principal = "admin"; access = ["add" "cpw"];}]; }; }; - krb5 = { + security.krb5 = { enable = true; - kerberos = pkgs.heimdal; - libdefaults = { - default_realm = "FOO.BAR"; - }; - realms = { - "FOO.BAR" = { - admin_server = "machine"; - kdc = "machine"; + package = pkgs.heimdal; + settings = { + libdefaults = { + default_realm = "FOO.BAR"; + }; + realms = { + "FOO.BAR" = { + admin_server = "machine"; + kdc = "machine"; + }; }; }; }; @@ -39,4 +42,6 @@ import ../make-test-python.nix ({pkgs, ...}: { "kinit -kt alice.keytab alice", ) ''; + + meta.maintainers = [ pkgs.lib.maintainers.dblsaiko ]; }) diff --git a/nixos/tests/kerberos/mit.nix b/nixos/tests/kerberos/mit.nix index 7e427ffef0ba..1191d047abbf 100644 --- a/nixos/tests/kerberos/mit.nix +++ b/nixos/tests/kerberos/mit.nix @@ -1,5 +1,6 @@ import ../make-test-python.nix ({pkgs, ...}: { name = "kerberos_server-mit"; + nodes.machine = { config, libs, pkgs, ...}: { services.kerberos_server = { enable = true; @@ -7,16 +8,18 @@ import ../make-test-python.nix ({pkgs, ...}: { "FOO.BAR".acl = [{principal = "admin"; access = ["add" "cpw"];}]; }; }; - krb5 = { + security.krb5 = { enable = true; - kerberos = pkgs.krb5; - libdefaults = { - default_realm = "FOO.BAR"; - }; - realms = { - "FOO.BAR" = { - admin_server = "machine"; - kdc = "machine"; + package = pkgs.krb5; + settings = { + libdefaults = { + default_realm = "FOO.BAR"; + }; + realms = { + "FOO.BAR" = { + admin_server = "machine"; + kdc = "machine"; + }; }; }; }; @@ -38,4 +41,6 @@ import ../make-test-python.nix ({pkgs, ...}: { "echo alice_pw | sudo -u alice kinit", ) ''; + + meta.maintainers = [ pkgs.lib.maintainers.dblsaiko ]; }) diff --git a/nixos/tests/kernel-generic.nix b/nixos/tests/kernel-generic.nix index 72d31246b75d..34c04e8351ce 100644 --- a/nixos/tests/kernel-generic.nix +++ b/nixos/tests/kernel-generic.nix @@ -32,6 +32,7 @@ let linux_6_1_hardened linux_6_5_hardened linux_6_6_hardened + linux_6_7_hardened linux_rt_5_4 linux_rt_5_10 linux_rt_5_15 diff --git a/nixos/tests/kernel-rust.nix b/nixos/tests/kernel-rust.nix new file mode 100644 index 000000000000..80eb38693677 --- /dev/null +++ b/nixos/tests/kernel-rust.nix @@ -0,0 +1,30 @@ +{ pkgs, ... }: { + name = "kernel-rust"; + meta = with pkgs.lib.maintainers; { + maintainers = [ blitz ]; + }; + + nodes.machine = { config, pkgs, ... }: + { + boot.kernelPackages = pkgs.linuxPackages_testing; + + boot.extraModulePackages = [ + config.boot.kernelPackages.rust-out-of-tree-module + ]; + + boot.kernelPatches = [ + { + name = "Rust Support"; + patch = null; + features = { + rust = true; + }; + } + ]; + }; + + testScript = '' + machine.wait_for_unit("default.target") + machine.succeed("modprobe rust_out_of_tree") + ''; +} diff --git a/nixos/tests/krb5/default.nix b/nixos/tests/krb5/default.nix index dd5b2f37202e..ede085632c63 100644 --- a/nixos/tests/krb5/default.nix +++ b/nixos/tests/krb5/default.nix @@ -1,5 +1,4 @@ { system ? builtins.currentSystem }: { example-config = import ./example-config.nix { inherit system; }; - deprecated-config = import ./deprecated-config.nix { inherit system; }; } diff --git a/nixos/tests/krb5/deprecated-config.nix b/nixos/tests/krb5/deprecated-config.nix deleted file mode 100644 index aca29ae6ca2b..000000000000 --- a/nixos/tests/krb5/deprecated-config.nix +++ /dev/null @@ -1,50 +0,0 @@ -# Verifies that the configuration suggested in deprecated example values -# will result in the expected output. - -import ../make-test-python.nix ({ pkgs, ...} : { - name = "krb5-with-deprecated-config"; - meta = with pkgs.lib.maintainers; { - maintainers = [ eqyiel ]; - }; - - nodes.machine = - { ... }: { - krb5 = { - enable = true; - defaultRealm = "ATHENA.MIT.EDU"; - domainRealm = "athena.mit.edu"; - kdc = "kerberos.mit.edu"; - kerberosAdminServer = "kerberos.mit.edu"; - }; - }; - - testScript = - let snapshot = pkgs.writeText "krb5-with-deprecated-config.conf" '' - [libdefaults] - default_realm = ATHENA.MIT.EDU - - [realms] - ATHENA.MIT.EDU = { - admin_server = kerberos.mit.edu - kdc = kerberos.mit.edu - } - - [domain_realm] - .athena.mit.edu = ATHENA.MIT.EDU - athena.mit.edu = ATHENA.MIT.EDU - - [capaths] - - - [appdefaults] - - - [plugins] - - ''; - in '' - machine.succeed( - "diff /etc/krb5.conf ${snapshot}" - ) - ''; -}) diff --git a/nixos/tests/krb5/example-config.nix b/nixos/tests/krb5/example-config.nix index 9a5c3b2af249..33bed481b39f 100644 --- a/nixos/tests/krb5/example-config.nix +++ b/nixos/tests/krb5/example-config.nix @@ -4,78 +4,77 @@ import ../make-test-python.nix ({ pkgs, ...} : { name = "krb5-with-example-config"; meta = with pkgs.lib.maintainers; { - maintainers = [ eqyiel ]; + maintainers = [ eqyiel dblsaiko ]; }; nodes.machine = { pkgs, ... }: { - krb5 = { + security.krb5 = { enable = true; - kerberos = pkgs.krb5; - libdefaults = { - default_realm = "ATHENA.MIT.EDU"; - }; - realms = { - "ATHENA.MIT.EDU" = { - admin_server = "athena.mit.edu"; - kdc = [ - "athena01.mit.edu" - "athena02.mit.edu" - ]; + package = pkgs.krb5; + settings = { + includedir = [ + "/etc/krb5.conf.d" + ]; + include = [ + "/etc/krb5-extra.conf" + ]; + libdefaults = { + default_realm = "ATHENA.MIT.EDU"; }; - }; - domain_realm = { - "example.com" = "EXAMPLE.COM"; - ".example.com" = "EXAMPLE.COM"; - }; - capaths = { - "ATHENA.MIT.EDU" = { - "EXAMPLE.COM" = "."; + realms = { + "ATHENA.MIT.EDU" = { + admin_server = "athena.mit.edu"; + kdc = [ + "athena01.mit.edu" + "athena02.mit.edu" + ]; + }; }; - "EXAMPLE.COM" = { - "ATHENA.MIT.EDU" = "."; + domain_realm = { + "example.com" = "EXAMPLE.COM"; + ".example.com" = "EXAMPLE.COM"; }; - }; - appdefaults = { - pam = { - debug = false; - ticket_lifetime = 36000; - renew_lifetime = 36000; - max_timeout = 30; - timeout_shift = 2; - initial_timeout = 1; + capaths = { + "ATHENA.MIT.EDU" = { + "EXAMPLE.COM" = "."; + }; + "EXAMPLE.COM" = { + "ATHENA.MIT.EDU" = "."; + }; }; - }; - plugins = { - ccselect = { - disable = "k5identity"; + appdefaults = { + pam = { + debug = false; + ticket_lifetime = 36000; + renew_lifetime = 36000; + max_timeout = 30; + timeout_shift = 2; + initial_timeout = 1; + }; + }; + plugins.ccselect.disable = "k5identity"; + logging = { + kdc = "SYSLOG:NOTICE"; + admin_server = "SYSLOG:NOTICE"; + default = "SYSLOG:NOTICE"; }; }; - extraConfig = '' - [logging] - kdc = SYSLOG:NOTICE - admin_server = SYSLOG:NOTICE - default = SYSLOG:NOTICE - ''; }; }; testScript = let snapshot = pkgs.writeText "krb5-with-example-config.conf" '' - [libdefaults] - default_realm = ATHENA.MIT.EDU - - [realms] - ATHENA.MIT.EDU = { - admin_server = athena.mit.edu - kdc = athena01.mit.edu - kdc = athena02.mit.edu + [appdefaults] + pam = { + debug = false + initial_timeout = 1 + max_timeout = 30 + renew_lifetime = 36000 + ticket_lifetime = 36000 + timeout_shift = 2 } - [domain_realm] - .example.com = EXAMPLE.COM - example.com = EXAMPLE.COM - [capaths] ATHENA.MIT.EDU = { EXAMPLE.COM = . @@ -84,25 +83,32 @@ import ../make-test-python.nix ({ pkgs, ...} : { ATHENA.MIT.EDU = . } - [appdefaults] - pam = { - debug = false - initial_timeout = 1 - max_timeout = 30 - renew_lifetime = 36000 - ticket_lifetime = 36000 - timeout_shift = 2 - } + [domain_realm] + .example.com = EXAMPLE.COM + example.com = EXAMPLE.COM + + [libdefaults] + default_realm = ATHENA.MIT.EDU + + [logging] + admin_server = SYSLOG:NOTICE + default = SYSLOG:NOTICE + kdc = SYSLOG:NOTICE [plugins] ccselect = { disable = k5identity } - [logging] - kdc = SYSLOG:NOTICE - admin_server = SYSLOG:NOTICE - default = SYSLOG:NOTICE + [realms] + ATHENA.MIT.EDU = { + admin_server = athena.mit.edu + kdc = athena01.mit.edu + kdc = athena02.mit.edu + } + + include /etc/krb5-extra.conf + includedir /etc/krb5.conf.d ''; in '' machine.succeed( diff --git a/nixos/tests/lemmy.nix b/nixos/tests/lemmy.nix index de2c4938fe23..e8d747f89a9e 100644 --- a/nixos/tests/lemmy.nix +++ b/nixos/tests/lemmy.nix @@ -59,6 +59,7 @@ in server.succeed("curl --fail localhost:${toString uiPort}") with subtest("Lemmy-UI responds through the caddy reverse proxy"): + server.systemctl("start network-online.target") server.wait_for_unit("network-online.target") server.wait_for_unit("caddy.service") server.wait_for_open_port(80) @@ -66,6 +67,7 @@ in assert "Lemmy" in body, f"String Lemmy not found in response for ${lemmyNodeName}: \n{body}" with subtest("the server is exposed externally"): + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") client.succeed("curl -v --fail ${lemmyNodeName}") diff --git a/nixos/tests/livebook-service.nix b/nixos/tests/livebook-service.nix index 56b4eb932f34..f428412e1644 100644 --- a/nixos/tests/livebook-service.nix +++ b/nixos/tests/livebook-service.nix @@ -9,13 +9,15 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: { services.livebook = { enableUserService = true; - port = 20123; + environment = { + LIVEBOOK_PORT = 20123; + LIVEBOOK_COOKIE = "chocolate chip"; + LIVEBOOK_TOKEN_ENABLED = true; + + }; environmentFile = pkgs.writeText "livebook.env" '' LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ''; - options = { - cookie = "chocolate chip"; - }; }; }; }; diff --git a/nixos/tests/miriway.nix b/nixos/tests/miriway.nix index f12c4d5ecc41..a0987d9fc41b 100644 --- a/nixos/tests/miriway.nix +++ b/nixos/tests/miriway.nix @@ -31,7 +31,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { enable-x11= ctrl-alt=t:foot --maximized - ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty --option window.startup_mode=maximized + ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY= alacritty --option window.startup_mode=\"maximized\" shell-component=dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY diff --git a/nixos/tests/netbird.nix b/nixos/tests/netbird.nix index ef793cfe9881..7342e8d04a39 100644 --- a/nixos/tests/netbird.nix +++ b/nixos/tests/netbird.nix @@ -14,7 +14,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: testScript = '' start_all() - node.wait_for_unit("netbird.service") + node.wait_for_unit("netbird-wt0.service") node.wait_for_file("/var/run/netbird/sock") node.succeed("netbird status | grep -q 'Daemon status: NeedsLogin'") ''; diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 768d0cfa2238..6bd89902eedb 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -130,6 +130,7 @@ let start_all() client.wait_for_unit("network.target") + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") with subtest("Make sure DHCP server is not started"): @@ -222,6 +223,7 @@ let start_all() client.wait_for_unit("network.target") + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") with subtest("Wait until we have an ip address on each interface"): @@ -849,6 +851,7 @@ let client.wait_for_unit("network.target") client_with_privacy.wait_for_unit("network.target") + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") with subtest("Wait until we have an ip address"): diff --git a/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix b/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix index addc898bd760..b09ee1276a13 100644 --- a/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix +++ b/nixos/tests/nextcloud/with-declarative-redis-and-secrets.nix @@ -41,7 +41,7 @@ in { }; secretFile = "/etc/nextcloud-secrets.json"; - extraOptions = { + settings = { allow_local_remote_servers = true; redis = { dbindex = 0; diff --git a/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixos/tests/nextcloud/with-postgresql-and-redis.nix index d95af8a89d07..3c090f0d3c3b 100644 --- a/nixos/tests/nextcloud/with-postgresql-and-redis.nix +++ b/nixos/tests/nextcloud/with-postgresql-and-redis.nix @@ -41,7 +41,7 @@ in { extraApps = { inherit (pkgs."nextcloud${lib.versions.major config.services.nextcloud.package.version}Packages".apps) notify_push; }; - extraOptions.trusted_proxies = [ "::1" ]; + settings.trusted_proxies = [ "::1" ]; }; services.redis.servers."nextcloud".enable = true; diff --git a/nixos/tests/nfs/kerberos.nix b/nixos/tests/nfs/kerberos.nix index a7d08bc628c6..5944b53319a0 100644 --- a/nixos/tests/nfs/kerberos.nix +++ b/nixos/tests/nfs/kerberos.nix @@ -1,15 +1,17 @@ import ../make-test-python.nix ({ pkgs, lib, ... }: let - krb5 = - { enable = true; - domain_realm."nfs.test" = "NFS.TEST"; + security.krb5 = { + enable = true; + settings = { + domain_realm."nfs.test" = "NFS.TEST"; libdefaults.default_realm = "NFS.TEST"; - realms."NFS.TEST" = - { admin_server = "server.nfs.test"; - kdc = "server.nfs.test"; - }; + realms."NFS.TEST" = { + admin_server = "server.nfs.test"; + kdc = "server.nfs.test"; + }; }; + }; hosts = '' @@ -32,7 +34,7 @@ in nodes = { client = { lib, ... }: - { inherit krb5 users; + { inherit security users; networking.extraHosts = hosts; networking.domain = "nfs.test"; @@ -48,7 +50,7 @@ in }; server = { lib, ...}: - { inherit krb5 users; + { inherit security users; networking.extraHosts = hosts; networking.domain = "nfs.test"; @@ -103,6 +105,7 @@ in server.wait_for_unit("rpc-gssd.service") server.wait_for_unit("rpc-svcgssd.service") + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") # add principals to client keytab @@ -128,4 +131,6 @@ in expected = ["alice", "users"] assert ids == expected, f"ids incorrect: got {ids} expected {expected}" ''; + + meta.maintainers = [ lib.maintainers.dblsaiko ]; }) diff --git a/nixos/tests/nginx-etag-compression.nix b/nixos/tests/nginx-etag-compression.nix new file mode 100644 index 000000000000..67493ae29984 --- /dev/null +++ b/nixos/tests/nginx-etag-compression.nix @@ -0,0 +1,45 @@ +import ./make-test-python.nix { + name = "nginx-etag-compression"; + + nodes.machine = { pkgs, lib, ... }: { + services.nginx = { + enable = true; + recommendedGzipSettings = true; + virtualHosts.default = { + root = pkgs.runCommandLocal "testdir" {} '' + mkdir "$out" + cat > "$out/index.html" <<EOF + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + Hello, world! + EOF + ${pkgs.gzip}/bin/gzip -k "$out/index.html" + ''; + }; + }; + }; + + testScript = { nodes, ... }: '' + machine.wait_for_unit("nginx") + machine.wait_for_open_port(80) + + etag_plain = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:' http://127.0.0.1/") + etag_gzip = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:gzip' http://127.0.0.1/") + + with subtest("different representations have different etags"): + assert etag_plain != etag_gzip, f"etags should differ: {etag_plain} == {etag_gzip}" + + with subtest("etag for uncompressed response is reproducible"): + etag_plain_repeat = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:' http://127.0.0.1/") + assert etag_plain == etag_plain_repeat, f"etags should be the same: {etag_plain} != {etag_plain_repeat}" + + with subtest("etag for compressed response is reproducible"): + etag_gzip_repeat = machine.succeed("curl -s -w'%header{etag}' -o/dev/null -H 'Accept-encoding:gzip' http://127.0.0.1/") + assert etag_gzip == etag_gzip_repeat, f"etags should be the same: {etag_gzip} != {etag_gzip_repeat}" + ''; +} diff --git a/nixos/tests/nginx-moreheaders.nix b/nixos/tests/nginx-moreheaders.nix new file mode 100644 index 000000000000..560dcf9ce0b8 --- /dev/null +++ b/nixos/tests/nginx-moreheaders.nix @@ -0,0 +1,37 @@ +import ./make-test-python.nix { + name = "nginx-more-headers"; + + nodes = { + webserver = { pkgs, ... }: { + services.nginx = { + enable = true; + + virtualHosts.test = { + locations = { + "/".return = "200 blub"; + "/some" = { + return = "200 blub"; + extraConfig = '' + more_set_headers "Referrer-Policy: no-referrer"; + ''; + }; + }; + extraConfig = '' + more_set_headers "X-Powered-By: nixos"; + ''; + }; + }; + }; + }; + + testScript = '' + webserver.wait_for_unit("nginx") + webserver.wait_for_open_port(80) + + webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test | grep -q \"X-Powered-By: nixos\"") + webserver.fail("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test | grep -q \"Referrer-Policy: no-referrer\"") + + webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test/some | grep -q \"X-Powered-By: nixos\"") + webserver.succeed("curl --fail --resolve test:80:127.0.0.1 --head --verbose http://test/some | grep -q \"Referrer-Policy: no-referrer\"") + ''; +} diff --git a/nixos/tests/nixops/default.nix b/nixos/tests/nixops/default.nix index f7a26f2461c4..6501d13a2ed3 100644 --- a/nixos/tests/nixops/default.nix +++ b/nixos/tests/nixops/default.nix @@ -1,6 +1,4 @@ -{ pkgs -, testers -, ... }: +{ pkgs, ... }: let inherit (pkgs) lib; @@ -21,7 +19,7 @@ let passthru.override = args': testsForPackage (args // args'); }; - testLegacyNetwork = { nixopsPkg, ... }: testers.nixosTest ({ + testLegacyNetwork = { nixopsPkg, ... }: pkgs.testers.nixosTest ({ name = "nixops-legacy-network"; nodes = { deployer = { config, lib, nodes, pkgs, ... }: { diff --git a/nixos/tests/nixos-rebuild-target-host.nix b/nixos/tests/nixos-rebuild-target-host.nix new file mode 100644 index 000000000000..bf80b2fa6606 --- /dev/null +++ b/nixos/tests/nixos-rebuild-target-host.nix @@ -0,0 +1,141 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "nixos-rebuild-target-host"; + + nodes = { + deployer = { lib, ... }: let + inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey; + in { + imports = [ ../modules/profiles/installation-device.nix ]; + + nix.settings = { + substituters = lib.mkForce [ ]; + hashed-mirrors = null; + connect-timeout = 1; + }; + + environment.systemPackages = [ pkgs.passh ]; + + system.includeBuildDependencies = true; + + virtualisation = { + cores = 2; + memorySize = 2048; + }; + + system.build.privateKey = snakeOilPrivateKey; + system.build.publicKey = snakeOilPublicKey; + }; + + target = { nodes, lib, ... }: let + targetConfig = { + documentation.enable = false; + services.openssh.enable = true; + + users.users.root.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + users.users.alice.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + users.users.bob.openssh.authorizedKeys.keys = [ nodes.deployer.system.build.publicKey ]; + + users.users.alice.extraGroups = [ "wheel" ]; + users.users.bob.extraGroups = [ "wheel" ]; + + # Disable sudo for root to ensure sudo isn't called without `--use-remote-sudo` + security.sudo.extraRules = lib.mkForce [ + { groups = [ "wheel" ]; commands = [ { command = "ALL"; } ]; } + { users = [ "alice" ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; } ]; } + ]; + + nix.settings.trusted-users = [ "@wheel" ]; + }; + in { + imports = [ ./common/user-account.nix ]; + + config = lib.mkMerge [ + targetConfig + { + system.build = { + inherit targetConfig; + }; + + networking.hostName = "target"; + } + ]; + }; + }; + + testScript = { nodes, ... }: + let + sshConfig = builtins.toFile "ssh.conf" '' + UserKnownHostsFile=/dev/null + StrictHostKeyChecking=no + ''; + + targetConfigJSON = pkgs.writeText "target-configuration.json" + (builtins.toJSON nodes.target.system.build.targetConfig); + + targetNetworkJSON = pkgs.writeText "target-network.json" + (builtins.toJSON nodes.target.system.build.networkConfig); + + configFile = hostname: pkgs.writeText "configuration.nix" '' + { lib, modulesPath, ... }: { + imports = [ + (modulesPath + "/virtualisation/qemu-vm.nix") + (modulesPath + "/testing/test-instrumentation.nix") + (modulesPath + "/../tests/common/user-account.nix") + (lib.modules.importJSON ./target-configuration.json) + (lib.modules.importJSON ./target-network.json) + ./hardware-configuration.nix + ]; + + boot.loader.grub = { + enable = true; + device = "/dev/vda"; + forceInstall = true; + }; + + # this will be asserted + networking.hostName = "${hostname}"; + } + ''; + in + '' + start_all() + target.wait_for_open_port(22) + + deployer.wait_until_succeeds("ping -c1 target") + deployer.succeed("install -Dm 600 ${nodes.deployer.system.build.privateKey} ~root/.ssh/id_ecdsa") + deployer.succeed("install ${sshConfig} ~root/.ssh/config") + + target.succeed("nixos-generate-config") + deployer.succeed("scp alice@target:/etc/nixos/hardware-configuration.nix /root/hardware-configuration.nix") + + deployer.copy_from_host("${configFile "config-1-deployed"}", "/root/configuration-1.nix") + deployer.copy_from_host("${configFile "config-2-deployed"}", "/root/configuration-2.nix") + deployer.copy_from_host("${configFile "config-3-deployed"}", "/root/configuration-3.nix") + deployer.copy_from_host("${targetNetworkJSON}", "/root/target-network.json") + deployer.copy_from_host("${targetConfigJSON}", "/root/target-configuration.json") + + # Ensure sudo is disabled for root + target.fail("sudo true") + + # This test also ensures that sudo is not called without --use-remote-sudo + with subtest("Deploy to root@target"): + deployer.succeed("nixos-rebuild switch -I nixos-config=/root/configuration-1.nix --target-host root@target &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-1-deployed", f"{target_hostname=}" + + with subtest("Deploy to alice@target with passwordless sudo"): + deployer.succeed("nixos-rebuild switch -I nixos-config=/root/configuration-2.nix --target-host alice@target --use-remote-sudo &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-2-deployed", f"{target_hostname=}" + + with subtest("Deploy to bob@target with password based sudo"): + deployer.succeed("passh -c 3 -C -p ${nodes.target.users.users.bob.password} -P \"\[sudo\] password\" nixos-rebuild switch -I nixos-config=/root/configuration-3.nix --target-host bob@target --use-remote-sudo &>/dev/console") + target_hostname = deployer.succeed("ssh alice@target cat /etc/hostname").rstrip() + assert target_hostname == "config-3-deployed", f"{target_hostname=}" + + with subtest("Deploy works with very long TMPDIR"): + tmp_dir = "/var/folder/veryveryveryveryverylongpathnamethatdoesnotworkwithcontrolpath" + deployer.succeed(f"mkdir -p {tmp_dir}") + deployer.succeed(f"TMPDIR={tmp_dir} nixos-rebuild switch -I nixos-config=/root/configuration-1.nix --target-host root@target &>/dev/console") + ''; +}) diff --git a/nixos/tests/nixseparatedebuginfod.nix b/nixos/tests/nixseparatedebuginfod.nix new file mode 100644 index 000000000000..7c192a73c706 --- /dev/null +++ b/nixos/tests/nixseparatedebuginfod.nix @@ -0,0 +1,80 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: +let + secret-key = "key-name:/COlMSRbehSh6YSruJWjL+R0JXQUKuPEn96fIb+pLokEJUjcK/2Gv8Ai96D7JGay5gDeUTx5wdpPgNvum9YtwA=="; + public-key = "key-name:BCVI3Cv9hr/AIveg+yRmsuYA3lE8ecHaT4Db7pvWLcA="; +in +{ + name = "nixseparatedebuginfod"; + /* A binary cache with debug info and source for nix */ + nodes.cache = { pkgs, ... }: { + services.nix-serve = { + enable = true; + secretKeyFile = builtins.toFile "secret-key" secret-key; + openFirewall = true; + }; + system.extraDependencies = [ + pkgs.nix.debug + pkgs.nix.src + pkgs.sl + ]; + }; + /* the machine where we need the debuginfo */ + nodes.machine = { + imports = [ + ../modules/installer/cd-dvd/channel.nix + ]; + services.nixseparatedebuginfod.enable = true; + nix.settings = { + substituters = lib.mkForce [ "http://cache:5000" ]; + trusted-public-keys = [ public-key ]; + }; + environment.systemPackages = [ + pkgs.valgrind + pkgs.gdb + (pkgs.writeShellScriptBin "wait_for_indexation" '' + set -x + while debuginfod-find debuginfo /run/current-system/sw/bin/nix |& grep 'File too large'; do + sleep 1; + done + '') + ]; + }; + testScript = '' + start_all() + cache.wait_for_unit("nix-serve.service") + cache.wait_for_open_port(5000) + machine.wait_for_unit("nixseparatedebuginfod.service") + machine.wait_for_open_port(1949) + + with subtest("show the config to debug the test"): + machine.succeed("nix --extra-experimental-features nix-command show-config |& logger") + machine.succeed("cat /etc/nix/nix.conf |& logger") + with subtest("check that the binary cache works"): + machine.succeed("nix-store -r ${pkgs.sl}") + + # nixseparatedebuginfod needs .drv to associate executable -> source + # on regular systems this would be provided by nixos-rebuild + machine.succeed("nix-instantiate '<nixpkgs>' -A nix") + + machine.succeed("timeout 600 wait_for_indexation") + + # test debuginfod-find + machine.succeed("debuginfod-find debuginfo /run/current-system/sw/bin/nix") + + # test that gdb can fetch source + out = machine.succeed("gdb /run/current-system/sw/bin/nix --batch -x ${builtins.toFile "commands" '' + start + l + ''}") + print(out) + assert 'int main(' in out + + # test that valgrind can display location information + # this relies on the fact that valgrind complains about nix + # libgc helps in this regard, and we also ask valgrind to show leak kinds + # which are usually false positives. + out = machine.succeed("valgrind --leak-check=full --show-leak-kinds=all nix-env --version 2>&1") + print(out) + assert 'main.cc' in out + ''; +}) diff --git a/nixos/tests/ntfy-sh-migration.nix b/nixos/tests/ntfy-sh-migration.nix new file mode 100644 index 000000000000..de6660052d67 --- /dev/null +++ b/nixos/tests/ntfy-sh-migration.nix @@ -0,0 +1,77 @@ +# the ntfy-sh module was switching to DynamicUser=true. this test assures that +# the migration does not break existing setups. +# +# this test works doing a migration and asserting ntfy-sh runs properly. first, +# ntfy-sh is configured to use a static user and group. then ntfy-sh is +# started and tested. after that, ntfy-sh is shut down and a systemd drop +# in configuration file is used to upate the service configuration to use +# DynamicUser=true. then the ntfy-sh is started again and tested. + +import ./make-test-python.nix { + name = "ntfy-sh"; + + nodes.machine = { + lib, + pkgs, + ... + }: { + environment.etc."ntfy-sh-dynamic-user.conf".text = '' + [Service] + Group=new-ntfy-sh + User=new-ntfy-sh + DynamicUser=true + ''; + + services.ntfy-sh.enable = true; + services.ntfy-sh.settings.base-url = "http://localhost:2586"; + + systemd.services.ntfy-sh.serviceConfig = { + DynamicUser = lib.mkForce false; + ExecStartPre = [ + "${pkgs.coreutils}/bin/id" + "${pkgs.coreutils}/bin/ls -lahd /var/lib/ntfy-sh/" + "${pkgs.coreutils}/bin/ls -lah /var/lib/ntfy-sh/" + ]; + Group = lib.mkForce "old-ntfy-sh"; + User = lib.mkForce "old-ntfy-sh"; + }; + + users.users.old-ntfy-sh = { + isSystemUser = true; + group = "old-ntfy-sh"; + }; + + users.groups.old-ntfy-sh = {}; + }; + + testScript = '' + import json + + msg = "Test notification" + + def test_ntfysh(): + machine.wait_for_unit("ntfy-sh.service") + machine.wait_for_open_port(2586) + + machine.succeed(f"curl -d '{msg}' localhost:2586/test") + + text = machine.succeed("curl -s localhost:2586/test/json?poll=1") + for line in text.splitlines(): + notif = json.loads(line) + assert msg == notif["message"], "Wrong message" + + machine.succeed("ntfy user list") + + machine.wait_for_unit("multi-user.target") + + test_ntfysh() + + machine.succeed("systemctl stop ntfy-sh.service") + machine.succeed("mkdir -p /run/systemd/system/ntfy-sh.service.d") + machine.succeed("cp /etc/ntfy-sh-dynamic-user.conf /run/systemd/system/ntfy-sh.service.d/dynamic-user.conf") + machine.succeed("systemctl daemon-reload") + machine.succeed("systemctl start ntfy-sh.service") + + test_ntfysh() + ''; +} diff --git a/nixos/tests/ntpd-rs.nix b/nixos/tests/ntpd-rs.nix new file mode 100644 index 000000000000..6f3c80e87f07 --- /dev/null +++ b/nixos/tests/ntpd-rs.nix @@ -0,0 +1,51 @@ +import ./make-test-python.nix ({ lib, ... }: +{ + name = "ntpd-rs"; + + meta = { + maintainers = with lib.maintainers; [ fpletz ]; + }; + + nodes = { + client = { + services.ntpd-rs = { + enable = true; + metrics.enable = true; + useNetworkingTimeServers = false; + settings = { + source = [ + { + mode = "server"; + address = "server"; + } + ]; + synchronization = { + minimum-agreeing-sources = 1; + }; + }; + }; + }; + server = { + networking.firewall.allowedUDPPorts = [ 123 ]; + services.ntpd-rs = { + enable = true; + metrics.enable = true; + settings = { + server = [ + { listen = "[::]:123"; } + ]; + }; + }; + }; + }; + + testScript = { nodes, ... }: '' + start_all() + + for machine in (server, client): + machine.wait_for_unit('multi-user.target') + machine.succeed('systemctl is-active ntpd-rs.service') + machine.succeed('systemctl is-active ntpd-rs-metrics.service') + machine.succeed('curl http://localhost:9975/metrics | grep ntp_uptime_seconds') + ''; +}) diff --git a/nixos/tests/opensmtpd-rspamd.nix b/nixos/tests/opensmtpd-rspamd.nix index 19969a7b47dd..e413a2050bd6 100644 --- a/nixos/tests/opensmtpd-rspamd.nix +++ b/nixos/tests/opensmtpd-rspamd.nix @@ -119,6 +119,7 @@ import ./make-test-python.nix { testScript = '' start_all() + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") smtp1.wait_for_unit("opensmtpd") smtp2.wait_for_unit("opensmtpd") diff --git a/nixos/tests/opensmtpd.nix b/nixos/tests/opensmtpd.nix index 17c1a569ba0d..d32f82ed33b8 100644 --- a/nixos/tests/opensmtpd.nix +++ b/nixos/tests/opensmtpd.nix @@ -104,6 +104,7 @@ import ./make-test-python.nix { testScript = '' start_all() + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") smtp1.wait_for_unit("opensmtpd") smtp2.wait_for_unit("opensmtpd") diff --git a/nixos/tests/openssh.nix b/nixos/tests/openssh.nix index 799497477993..8074fd2ed483 100644 --- a/nixos/tests/openssh.nix +++ b/nixos/tests/openssh.nix @@ -34,6 +34,19 @@ in { ]; }; + server-lazy-socket = { + virtualisation.vlans = [ 1 2 ]; + services.openssh = { + enable = true; + startWhenNeeded = true; + ports = [ 2222 ]; + listenAddresses = [ { addr = "0.0.0.0"; } ]; + }; + users.users.root.openssh.authorizedKeys.keys = [ + snakeOilPublicKey + ]; + }; + server-localhost-only = { ... }: @@ -96,7 +109,9 @@ in { }; client = - { ... }: { }; + { ... }: { + virtualisation.vlans = [ 1 2 ]; + }; }; @@ -109,6 +124,7 @@ in { server_lazy.wait_for_unit("sshd.socket", timeout=30) server_localhost_only_lazy.wait_for_unit("sshd.socket", timeout=30) + server_lazy_socket.wait_for_unit("sshd.socket", timeout=30) with subtest("manual-authkey"): client.succeed("mkdir -m 700 /root/.ssh") @@ -145,6 +161,16 @@ in { timeout=30 ) + with subtest("socket activation on a non-standard port"): + client.succeed( + "cat ${snakeOilPrivateKey} > privkey.snakeoil" + ) + client.succeed("chmod 600 privkey.snakeoil") + client.succeed( + "ssh -p 2222 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i privkey.snakeoil root@192.168.2.4 true", + timeout=30 + ) + with subtest("configured-authkey"): client.succeed( "cat ${snakeOilPrivateKey} > privkey.snakeoil" diff --git a/nixos/tests/os-prober.nix b/nixos/tests/os-prober.nix index dae1306bd69d..034de0620d88 100644 --- a/nixos/tests/os-prober.nix +++ b/nixos/tests/os-prober.nix @@ -95,7 +95,7 @@ in { ntp perlPackages.ListCompare perlPackages.XMLLibXML - python3Minimal + python3 shared-mime-info stdenv sudo diff --git a/nixos/tests/owncast.nix b/nixos/tests/owncast.nix index debb34f5009d..73aac4e70475 100644 --- a/nixos/tests/owncast.nix +++ b/nixos/tests/owncast.nix @@ -31,6 +31,8 @@ import ./make-test-python.nix ({ pkgs, ... }: { testScript = '' start_all() + client.systemctl("start network-online.target") + server.systemctl("start network-online.target") client.wait_for_unit("network-online.target") server.wait_for_unit("network-online.target") server.wait_for_unit("owncast.service") diff --git a/nixos/tests/pam/pam-file-contents.nix b/nixos/tests/pam/pam-file-contents.nix index 2bafd90618e9..accaa4cc70a9 100644 --- a/nixos/tests/pam/pam-file-contents.nix +++ b/nixos/tests/pam/pam-file-contents.nix @@ -7,7 +7,7 @@ import ../make-test-python.nix ({ pkgs, ... }: { nodes.machine = { ... }: { imports = [ ../../modules/profiles/minimal.nix ]; - krb5.enable = true; + security.krb5.enable = true; users = { mutableUsers = false; diff --git a/nixos/tests/pantheon.nix b/nixos/tests/pantheon.nix index be1351283d99..69a28c397bed 100644 --- a/nixos/tests/pantheon.nix +++ b/nixos/tests/pantheon.nix @@ -26,6 +26,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : with subtest("Test we can see usernames in elementary-greeter"): machine.wait_for_text("${user.description}") + machine.wait_until_succeeds("pgrep -f io.elementary.greeter-compositor") # OCR was struggling with this one. # machine.wait_for_text("${bob.description}") # Ensure the password box is focused by clicking it. @@ -39,21 +40,29 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.wait_for_x() machine.wait_for_file("${user.home}/.Xauthority") machine.succeed("xauth merge ${user.home}/.Xauthority") + machine.wait_until_succeeds('journalctl -t gnome-session-binary --grep "Entering running state"') 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("Check if pantheon session components actually start"): - machine.wait_until_succeeds("pgrep gala") - machine.wait_for_window("gala") - machine.wait_until_succeeds("pgrep -f io.elementary.wingpanel") - machine.wait_for_window("io.elementary.wingpanel") - machine.wait_until_succeeds("pgrep plank") - machine.wait_for_window("plank") - machine.wait_until_succeeds("pgrep -f gsd-media-keys") + with subtest("Check if Pantheon components actually start"): + for i in ["gala", "io.elementary.wingpanel", "plank", "gsd-media-keys", "io.elementary.desktop.agent-polkit"]: + machine.wait_until_succeeds(f"pgrep -f {i}") + for i in ["gala", "io.elementary.wingpanel", "plank"]: + machine.wait_for_window(i) machine.wait_for_unit("bamfdaemon.service", "${user.name}") machine.wait_for_unit("io.elementary.files.xdg-desktop-portal.service", "${user.name}") + with subtest("Check if various environment variables are set"): + cmd = "xargs --null --max-args=1 echo < /proc/$(pgrep -xf /run/current-system/sw/bin/gala)/environ" + machine.succeed(f"{cmd} | grep 'XDG_CURRENT_DESKTOP' | grep 'Pantheon'") + # Hopefully from the sessionPath option. + machine.succeed(f"{cmd} | grep 'XDG_DATA_DIRS' | grep 'gsettings-schemas/pantheon-agent-geoclue2'") + # Hopefully from login shell. + machine.succeed(f"{cmd} | grep '__NIXOS_SET_ENVIRONMENT_DONE' | grep '1'") + # See elementary-session-settings packaging. + machine.succeed(f"{cmd} | grep 'XDG_CONFIG_DIRS' | grep 'elementary-default-settings'") + with subtest("Open elementary videos"): machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.videos >&2 &'") machine.sleep(2) @@ -61,6 +70,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.wait_for_text("No Videos Open") with subtest("Open elementary calendar"): + machine.wait_until_succeeds("pgrep -f evolution-calendar-factory") machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.calendar >&2 &'") machine.sleep(2) machine.wait_for_window("io.elementary.calendar") @@ -75,6 +85,14 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : machine.execute("su - ${user.name} -c 'DISPLAY=:0 io.elementary.terminal >&2 &'") machine.wait_for_window("io.elementary.terminal") + with subtest("Trigger multitasking view"): + cmd = "dbus-send --session --dest=org.pantheon.gala --print-reply /org/pantheon/gala org.pantheon.gala.PerformAction int32:1" + env = "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${toString user.uid}/bus DISPLAY=:0" + machine.succeed(f"su - ${user.name} -c '{env} {cmd}'") + machine.sleep(3) + machine.screenshot("multitasking") + machine.succeed(f"su - ${user.name} -c '{env} {cmd}'") + with subtest("Check if gala has ever coredumped"): machine.fail("coredumpctl --json=short | grep gala") # So you can see the dock in the below screenshot. diff --git a/nixos/tests/paperless.nix b/nixos/tests/paperless.nix index 6a51cc522bdc..3d834b29958d 100644 --- a/nixos/tests/paperless.nix +++ b/nixos/tests/paperless.nix @@ -21,7 +21,7 @@ import ./make-test-python.nix ({ lib, ... }: { } ]; }; - services.paperless.extraConfig = { + services.paperless.settings = { PAPERLESS_DBHOST = "/run/postgresql"; }; }; diff --git a/nixos/tests/pgadmin4.nix b/nixos/tests/pgadmin4.nix index 3ee7ed19fa1c..b726a3eb3b94 100644 --- a/nixos/tests/pgadmin4.nix +++ b/nixos/tests/pgadmin4.nix @@ -4,31 +4,49 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: name = "pgadmin4"; meta.maintainers = with lib.maintainers; [ mkg20001 gador ]; - nodes.machine = { pkgs, ... }: { + nodes = { + machine = { pkgs, ... }: { - imports = [ ./common/user-account.nix ]; + imports = [ ./common/user-account.nix ]; - environment.systemPackages = with pkgs; [ - wget - curl - pgadmin4-desktopmode - ]; + environment.systemPackages = with pkgs; [ + wget + curl + pgadmin4-desktopmode + ]; - services.postgresql = { - enable = true; - authentication = '' - host all all localhost trust - ''; + services.postgresql = { + enable = true; + authentication = '' + host all all localhost trust + ''; + }; + + services.pgadmin = { + port = 5051; + enable = true; + initialEmail = "bruh@localhost.de"; + initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + }; }; + machine2 = { pkgs, ... }: { + + imports = [ ./common/user-account.nix ]; - services.pgadmin = { - port = 5051; - enable = true; - initialEmail = "bruh@localhost.de"; - initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + services.postgresql = { + enable = true; + }; + + services.pgadmin = { + enable = true; + initialEmail = "bruh@localhost.de"; + initialPasswordFile = pkgs.writeText "pw" "bruh2012!"; + minimumPasswordLength = 12; + }; }; }; + testScript = '' with subtest("Check pgadmin module"): machine.wait_for_unit("postgresql") @@ -37,6 +55,11 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: machine.wait_until_succeeds("curl -sS localhost:5051/login | grep \"<title>pgAdmin 4</title>\" > /dev/null") # check for missing support files (css, js etc). Should catch not-generated files during build. See e.g. https://github.com/NixOS/nixpkgs/pull/229184 machine.succeed("wget -nv --level=1 --spider --recursive localhost:5051/login") + # test idempotenceny + machine.systemctl("restart pgadmin.service") + machine.wait_for_unit("pgadmin") + machine.wait_until_succeeds("curl -sS localhost:5051") + machine.wait_until_succeeds("curl -sS localhost:5051/login | grep \"<title>pgAdmin 4</title>\" > /dev/null") # pgadmin4 module saves the configuration to /etc/pgadmin/config_system.py # pgadmin4-desktopmode tries to read that as well. This normally fails with a PermissionError, as the config file @@ -49,5 +72,9 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: machine.wait_until_succeeds("curl -sS localhost:5050") machine.wait_until_succeeds("curl -sS localhost:5050/browser/ | grep \"<title>pgAdmin 4</title>\" > /dev/null") machine.succeed("wget -nv --level=1 --spider --recursive localhost:5050/browser") + + with subtest("Check pgadmin minimum password length"): + machine2.wait_for_unit("postgresql") + machine2.wait_for_console_text("Password must be at least 12 characters long") ''; }) diff --git a/nixos/tests/podman/default.nix b/nixos/tests/podman/default.nix index 0e1f420f2a7d..3eea45832f0a 100644 --- a/nixos/tests/podman/default.nix +++ b/nixos/tests/podman/default.nix @@ -24,8 +24,6 @@ import ../make-test-python.nix ( virtualisation.podman.enable = true; virtualisation.podman.defaultNetwork.settings.dns_enabled = true; - - networking.firewall.allowedUDPPorts = [ 53 ]; }; docker = { pkgs, ... }: { virtualisation.podman.enable = true; diff --git a/nixos/tests/pomerium.nix b/nixos/tests/pomerium.nix index abaf56c518e0..d0204488e8ef 100644 --- a/nixos/tests/pomerium.nix +++ b/nixos/tests/pomerium.nix @@ -1,7 +1,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { name = "pomerium"; meta = with lib.maintainers; { - maintainers = [ lukegb ]; + maintainers = [ lukegb devusb ]; }; nodes = let base = myIP: { pkgs, lib, ... }: { @@ -103,7 +103,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { with subtest("ui"): pomerium.succeed( # check for a string that only appears if the UI is displayed correctly - "chromium --no-sandbox --headless --disable-gpu --dump-dom --host-resolver-rules='MAP login.required 127.0.0.1:80' http://login.required/.pomerium | grep 'contact your administrator'" + "chromium --no-sandbox --headless --disable-gpu --dump-dom --host-resolver-rules='MAP login.required 127.0.0.1:80' http://login.required/.pomerium | grep 'User Details Not Available'" ) ''; }) diff --git a/nixos/tests/postgis.nix b/nixos/tests/postgis.nix index 09c738b938ba..dacf4e576c07 100644 --- a/nixos/tests/postgis.nix +++ b/nixos/tests/postgis.nix @@ -24,6 +24,7 @@ import ./make-test-python.nix ({ pkgs, ...} : { master.wait_for_unit("postgresql") master.sleep(10) # Hopefully this is long enough!! master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis;'") + master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis_raster;'") master.succeed("sudo -u postgres psql -c 'CREATE EXTENSION postgis_topology;'") ''; }) diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index a39f3ca0739b..7e74f27174ec 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -257,21 +257,6 @@ let ''; }; - exportarr-sonarr = { - nodeName = "exportarr_sonarr"; - exporterConfig = { - enable = true; - url = "http://127.0.0.1:8989"; - # testing for real data is tricky, because the api key can not be preconfigured - apiKeyFile = pkgs.writeText "dummy-api-key" "eccff6a992bc2e4b88e46d064b26bb4e"; - }; - exporterTest = '' - wait_for_unit("prometheus-exportarr-sonarr-exporter.service") - wait_for_open_port(9707) - succeed("curl -sSf 'http://localhost:9707/metrics") - ''; - }; - fastly = { exporterConfig = { enable = true; @@ -957,31 +942,6 @@ let ''; }; - openvpn = { - exporterConfig = { - enable = true; - group = "openvpn"; - statusPaths = [ "/run/openvpn-test" ]; - }; - metricProvider = { - users.groups.openvpn = { }; - services.openvpn.servers.test = { - config = '' - dev tun - status /run/openvpn-test - status-version 3 - ''; - up = "chmod g+r /run/openvpn-test"; - }; - systemd.services."openvpn-test".serviceConfig.Group = "openvpn"; - }; - exporterTest = '' - wait_for_unit("openvpn-test.service") - wait_for_unit("prometheus-openvpn-exporter.service") - succeed("curl -sSf http://localhost:9176/metrics | grep 'openvpn_up{.*} 1'") - ''; - }; - pgbouncer = { exporterConfig = { enable = true; @@ -1425,9 +1385,11 @@ let snmp = { exporterConfig = { enable = true; - configuration.default = { - version = 2; - auth.community = "public"; + configuration = { + auths.public_v2 = { + community = "public"; + version = 2; + }; }; }; exporterTest = '' diff --git a/nixos/tests/prowlarr.nix b/nixos/tests/prowlarr.nix index af669afd5700..663743546459 100644 --- a/nixos/tests/prowlarr.nix +++ b/nixos/tests/prowlarr.nix @@ -11,6 +11,8 @@ import ./make-test-python.nix ({ lib, ... }: testScript = '' machine.wait_for_unit("prowlarr.service") machine.wait_for_open_port(9696) - machine.succeed("curl --fail http://localhost:9696/") + response = machine.succeed("curl --fail http://localhost:9696/") + assert '<title>Prowlarr</title>' in response, "Login page didn't load successfully" + machine.succeed("[ -d /var/lib/prowlarr ]") ''; }) diff --git a/nixos/tests/pyload.nix b/nixos/tests/pyload.nix new file mode 100644 index 000000000000..f913e822b2ff --- /dev/null +++ b/nixos/tests/pyload.nix @@ -0,0 +1,33 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "pyload"; + meta.maintainers = with lib.maintainers; [ ambroisie ]; + + nodes = { + machine = { ... }: { + services.pyload = { + enable = true; + + listenAddress = "0.0.0.0"; + port = 9876; + }; + + networking.firewall.allowedTCPPorts = [ 9876 ]; + }; + + client = { }; + }; + + testScript = '' + start_all() + + machine.wait_for_unit("pyload.service") + + with subtest("Web interface accessible locally"): + machine.wait_until_succeeds("curl -fs localhost:9876") + + client.wait_for_unit("network.target") + + with subtest("Web interface accessible from a different machine"): + client.wait_until_succeeds("curl -fs machine:9876") + ''; +}) diff --git a/nixos/tests/qemu-vm-restrictnetwork.nix b/nixos/tests/qemu-vm-restrictnetwork.nix index 49a105ef1076..49aefcc099bd 100644 --- a/nixos/tests/qemu-vm-restrictnetwork.nix +++ b/nixos/tests/qemu-vm-restrictnetwork.nix @@ -21,6 +21,8 @@ import ./make-test-python.nix ({ else: start_all() + unrestricted.systemctl("start network-online.target") + restricted.systemctl("start network-online.target") unrestricted.wait_for_unit("network-online.target") restricted.wait_for_unit("network-online.target") diff --git a/nixos/tests/rss2email.nix b/nixos/tests/rss2email.nix index f32326feb50f..60b27b95fabe 100644 --- a/nixos/tests/rss2email.nix +++ b/nixos/tests/rss2email.nix @@ -55,6 +55,7 @@ import ./make-test-python.nix { testScript = '' start_all() + server.systemctl("start network-online.target") server.wait_for_unit("network-online.target") server.wait_for_unit("opensmtpd") server.wait_for_unit("dovecot2") diff --git a/nixos/tests/sane.nix b/nixos/tests/sane.nix new file mode 100644 index 000000000000..cba1b4d1dc4d --- /dev/null +++ b/nixos/tests/sane.nix @@ -0,0 +1,85 @@ +import ./make-test-python.nix ({ pkgs, ... }: +/* + SANE NixOS test + =============== + SANE is intrisically tied to hardware, so testing it is not straightforward. + However: + - a fake webcam can be created with v4l2loopback + - sane has a backend (v4l) to use a webcam as a scanner + This test creates a webcam /dev/video0, streams a still image with some text + through this webcam, uses SANE to scan from the webcam, and uses OCR to check + that the expected text was scanned. +*/ +let + text = "66263666188646651519653683416"; + fontsConf = pkgs.makeFontsConf { + fontDirectories = [ + pkgs.dejavu_fonts.minimal + ]; + }; + # an image with black on white text spelling "${text}" + # for some reason, the test fails if it's jpg instead of png + # the font is quite large to make OCR easier + image = pkgs.runCommand "image.png" + { + # only imagemagickBig can render text + nativeBuildInputs = [ pkgs.imagemagickBig ]; + FONTCONFIG_FILE = fontsConf; + } '' + magick -pointsize 100 label:${text} $out + ''; +in +{ + name = "sane"; + nodes.machine = { pkgs, config, ... }: { + boot = { + # create /dev/video0 as a fake webcam whose content is filled by ffmpeg + extraModprobeConfig = '' + options v4l2loopback devices=1 max_buffers=2 exclusive_caps=1 card_label=VirtualCam + ''; + kernelModules = [ "v4l2loopback" ]; + extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; + }; + systemd.services.fake-webcam = { + wantedBy = [ "multi-user.target" ]; + description = "fill /dev/video0 with ${image}"; + /* HACK: /dev/video0 is a v4l2 only device, it misses one single v4l1 + ioctl, VIDIOCSPICT. But sane only supports v4l1, so it will log that this + ioctl failed, and assume that the pixel format is Y8 (gray). So we tell + ffmpeg to produce this pixel format. + */ + serviceConfig.ExecStart = [ "${pkgs.ffmpeg}/bin/ffmpeg -framerate 30 -re -stream_loop -1 -i ${image} -f v4l2 -pix_fmt gray /dev/video0" ]; + }; + hardware.sane.enable = true; + system.extraDependencies = [ image ]; + environment.systemPackages = [ + pkgs.fswebcam + pkgs.tesseract + pkgs.v4l-utils + ]; + environment.variables.SANE_DEBUG_V4L = "128"; + }; + testScript = '' + start_all() + machine.wait_for_unit("fake-webcam.service") + + # the device only appears when ffmpeg starts producing frames + machine.wait_until_succeeds("scanimage -L | grep /dev/video0") + + machine.succeed("scanimage -L >&2") + + with subtest("debugging: /dev/video0 works"): + machine.succeed("v4l2-ctl --all >&2") + machine.succeed("fswebcam --no-banner /tmp/webcam.jpg") + machine.copy_from_vm("/tmp/webcam.jpg", "webcam") + + # scan with the webcam + machine.succeed("scanimage -o /tmp/scan.png >&2") + machine.copy_from_vm("/tmp/scan.png", "scan") + + # the image should contain "${text}" + output = machine.succeed("tesseract /tmp/scan.png -") + print(output) + assert "${text}" in output, f"expected text ${text} was not found, OCR found {output!r}" + ''; +}) diff --git a/nixos/tests/slimserver.nix b/nixos/tests/slimserver.nix index c3f7b6fde4de..95cbdcf4a2a1 100644 --- a/nixos/tests/slimserver.nix +++ b/nixos/tests/slimserver.nix @@ -39,8 +39,8 @@ import ./make-test-python.nix ({ pkgs, ...} : { with subtest("squeezelite player successfully connects to slimserver"): machine.wait_for_unit("squeezelite.service") - machine.wait_until_succeeds("journalctl -u squeezelite.service | grep 'slimproto:937 connected'") - player_mac = machine.wait_until_succeeds("journalctl -eu squeezelite.service | grep 'sendHELO:148 mac:'").strip().split(" ")[-1] + machine.wait_until_succeeds("journalctl -u squeezelite.service | grep -E 'slimproto:[0-9]+ connected'") + player_mac = machine.wait_until_succeeds("journalctl -eu squeezelite.service | grep -E 'sendHELO:[0-9]+ mac:'").strip().split(" ")[-1] player_id = machine.succeed(f"curl http://localhost:9000/jsonrpc.js -g -X POST -d '{json.dumps(rpc_get_player)}'") assert player_mac == json.loads(player_id)["result"]["_id"], "squeezelite player not found" ''; diff --git a/nixos/tests/snmpd.nix b/nixos/tests/snmpd.nix new file mode 100644 index 000000000000..9248a6b39010 --- /dev/null +++ b/nixos/tests/snmpd.nix @@ -0,0 +1,23 @@ +import ./make-test-python.nix ({ pkgs, lib, ... }: { + name = "snmpd"; + + nodes.snmpd = { + environment.systemPackages = with pkgs; [ + net-snmp + ]; + + services.snmpd = { + enable = true; + configText = '' + rocommunity public + ''; + }; + }; + + testScript = '' + start_all(); + machine.wait_for_unit("snmpd.service") + machine.succeed("snmpwalk -v 2c -c public localhost | grep SNMPv2-MIB::sysName.0"); + ''; + +}) diff --git a/nixos/tests/spark/default.nix b/nixos/tests/spark/default.nix index eed7db35bf4f..034e9711bed5 100644 --- a/nixos/tests/spark/default.nix +++ b/nixos/tests/spark/default.nix @@ -10,7 +10,7 @@ let sparkCluster = testSparkCluster args; passthru.override = args': testsForPackage (args // args'); }; - testSparkCluster = { sparkPackage, ... }: pkgs.nixosTest ({ + testSparkCluster = { sparkPackage, ... }: pkgs.testers.nixosTest ({ name = "spark"; nodes = { diff --git a/nixos/tests/ssh-agent-auth.nix b/nixos/tests/ssh-agent-auth.nix index 2274e463ce95..fee40afd6153 100644 --- a/nixos/tests/ssh-agent-auth.nix +++ b/nixos/tests/ssh-agent-auth.nix @@ -15,7 +15,11 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: foo.isNormalUser = true; }; - security.pam.enableSSHAgentAuth = true; + security.pam.sshAgentAuth = { + # Must be specified, as nixpkgs CI expects everything to eval without warning + authorizedKeysFiles = [ "/etc/ssh/authorized_keys.d/%u" ]; + enable = true; + }; security.${lib.replaceStrings [ "_" ] [ "-" ] n} = { enable = true; wheelNeedsPassword = true; # We are checking `pam_ssh_agent_auth(8)` works for a sudoer diff --git a/nixos/tests/ssh-audit.nix b/nixos/tests/ssh-audit.nix index bd6255b8044d..25772aba3ea0 100644 --- a/nixos/tests/ssh-audit.nix +++ b/nixos/tests/ssh-audit.nix @@ -70,6 +70,7 @@ import ./make-test-python.nix ( ${serverName}.succeed("${pkgs.ssh-audit}/bin/ssh-audit 127.0.0.1") # Wait for client to be able to connect to the server + ${clientName}.systemctl("start network-online.target") ${clientName}.wait_for_unit("network-online.target") # Set up trusted private key diff --git a/nixos/tests/suwayomi-server.nix b/nixos/tests/suwayomi-server.nix new file mode 100644 index 000000000000..36072028380b --- /dev/null +++ b/nixos/tests/suwayomi-server.nix @@ -0,0 +1,46 @@ +{ system ? builtins.currentSystem +, pkgs +, lib ? pkgs.lib +}: +let + inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; + inherit (lib) recursiveUpdate; + + baseTestConfig = { + meta.maintainers = with lib.maintainers; [ ratcornu ]; + nodes.machine = { pkgs, ... }: { + services.suwayomi-server = { + enable = true; + settings.server.port = 1234; + }; + }; + testScript = '' + machine.wait_for_unit("suwayomi-server.service") + machine.wait_for_open_port(1234) + machine.succeed("curl --fail http://localhost:1234/") + ''; + }; +in + +{ + without-auth = makeTest (recursiveUpdate baseTestConfig { + name = "suwayomi-server-without-auth"; + }); + + with-auth = makeTest (recursiveUpdate baseTestConfig { + name = "suwayomi-server-with-auth"; + + nodes.machine = { pkgs, ... }: { + services.suwayomi-server = { + enable = true; + + settings.server = { + port = 1234; + basicAuthEnabled = true; + basicAuthUsername = "alice"; + basicAuthPasswordFile = pkgs.writeText "snakeoil-pass.txt" "pass"; + }; + }; + }; + }); +} diff --git a/nixos/tests/sway.nix b/nixos/tests/sway.nix index 695d4a770810..185c5b1b0aa9 100644 --- a/nixos/tests/sway.nix +++ b/nixos/tests/sway.nix @@ -134,7 +134,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { machine.wait_for_file("/tmp/sway-ipc.sock") # Test XWayland (foot does not support X): - swaymsg("exec WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty") + swaymsg("exec WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY= alacritty") wait_for_window("alice@machine") machine.send_chars("test-x11\n") machine.wait_for_file("/tmp/test-x11-exit-ok") diff --git a/nixos/tests/sysinit-reactivation.nix b/nixos/tests/sysinit-reactivation.nix new file mode 100644 index 000000000000..1a0caecb610a --- /dev/null +++ b/nixos/tests/sysinit-reactivation.nix @@ -0,0 +1,107 @@ +# This runs to two scenarios but in one tests: +# - A post-sysinit service needs to be restarted AFTER tmpfiles was restarted. +# - A service needs to be restarted BEFORE tmpfiles is restarted + +{ lib, ... }: + +let + makeGeneration = generation: { + "${generation}".configuration = { + systemd.services.pre-sysinit-before-tmpfiles.environment.USER = + lib.mkForce "${generation}-tmpfiles-user"; + + systemd.services.pre-sysinit-after-tmpfiles.environment = { + NEEDED_PATH = lib.mkForce "/run/${generation}-needed-by-pre-sysinit-after-tmpfiles"; + PATH_TO_CREATE = lib.mkForce "/run/${generation}-needed-by-post-sysinit"; + }; + + systemd.services.post-sysinit.environment = { + NEEDED_PATH = lib.mkForce "/run/${generation}-needed-by-post-sysinit"; + PATH_TO_CREATE = lib.mkForce "/run/${generation}-created-by-post-sysinit"; + }; + + systemd.tmpfiles.settings.test = lib.mkForce { + "/run/${generation}-needed-by-pre-sysinit-after-tmpfiles".f.user = + "${generation}-tmpfiles-user"; + }; + }; + }; +in + +{ + + name = "sysinit-reactivation"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { config, lib, pkgs, ... }: { + systemd.services.pre-sysinit-before-tmpfiles = { + wantedBy = [ "sysinit.target" ]; + requiredBy = [ "sysinit-reactivation.target" ]; + before = [ "systemd-tmpfiles-setup.service" "systemd-tmpfiles-resetup.service" ]; + unitConfig.DefaultDependencies = false; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + environment.USER = "tmpfiles-user"; + script = "${pkgs.shadow}/bin/useradd $USER"; + }; + + systemd.services.pre-sysinit-after-tmpfiles = { + wantedBy = [ "sysinit.target" ]; + requiredBy = [ "sysinit-reactivation.target" ]; + after = [ "systemd-tmpfiles-setup.service" "systemd-tmpfiles-resetup.service" ]; + unitConfig.DefaultDependencies = false; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + environment = { + NEEDED_PATH = "/run/needed-by-pre-sysinit-after-tmpfiles"; + PATH_TO_CREATE = "/run/needed-by-post-sysinit"; + }; + script = '' + if [[ -e $NEEDED_PATH ]]; then + touch $PATH_TO_CREATE + fi + ''; + }; + + systemd.services.post-sysinit = { + wantedBy = [ "default.target" ]; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + environment = { + NEEDED_PATH = "/run/needed-by-post-sysinit"; + PATH_TO_CREATE = "/run/created-by-post-sysinit"; + }; + script = '' + if [[ -e $NEEDED_PATH ]]; then + touch $PATH_TO_CREATE + fi + ''; + }; + + systemd.tmpfiles.settings.test = { + "/run/needed-by-pre-sysinit-after-tmpfiles".f.user = + "tmpfiles-user"; + }; + + specialisation = lib.mkMerge [ + (makeGeneration "second") + (makeGeneration "third") + ]; + }; + + testScript = { nodes, ... }: '' + def switch(generation): + toplevel = "${nodes.machine.system.build.toplevel}"; + machine.succeed(f"{toplevel}/specialisation/{generation}/bin/switch-to-configuration switch") + + machine.wait_for_unit("default.target") + machine.succeed("test -e /run/created-by-post-sysinit") + + switch("second") + machine.succeed("test -e /run/second-created-by-post-sysinit") + + switch("third") + machine.succeed("test -e /run/third-created-by-post-sysinit") + ''; +} diff --git a/nixos/tests/systemd-journal-gateway.nix b/nixos/tests/systemd-journal-gateway.nix new file mode 100644 index 000000000000..1d20943f2388 --- /dev/null +++ b/nixos/tests/systemd-journal-gateway.nix @@ -0,0 +1,90 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: +{ + name = "systemd-journal-gateway"; + meta = with pkgs.lib.maintainers; { + maintainers = [ minijackson raitobezarius ]; + }; + + # Named client for coherence with the systemd-journal-upload test, and for + # certificate validation + nodes.client = { + services.journald.gateway = { + enable = true; + cert = "/run/secrets/client/cert.pem"; + key = "/run/secrets/client/key.pem"; + trust = "/run/secrets/ca.cert.pem"; + }; + }; + + testScript = '' + import json + import subprocess + import tempfile + + tmpdir_o = tempfile.TemporaryDirectory() + tmpdir = tmpdir_o.name + + def generate_pems(domain: str): + subprocess.run( + [ + "${pkgs.minica}/bin/minica", + "--ca-key=ca.key.pem", + "--ca-cert=ca.cert.pem", + f"--domains={domain}", + ], + cwd=str(tmpdir), + ) + + with subtest("Creating keys and certificates"): + generate_pems("server") + generate_pems("client") + + client.wait_for_unit("multi-user.target") + + def copy_pem(file: str): + machine.copy_from_host(source=f"{tmpdir}/{file}", target=f"/run/secrets/{file}") + machine.succeed(f"chmod 644 /run/secrets/{file}") + + with subtest("Copying keys and certificates"): + machine.succeed("mkdir -p /run/secrets/{client,server}") + copy_pem("server/cert.pem") + copy_pem("server/key.pem") + copy_pem("client/cert.pem") + copy_pem("client/key.pem") + copy_pem("ca.cert.pem") + + client.wait_for_unit("multi-user.target") + + curl = '${pkgs.curl}/bin/curl' + accept_json = '--header "Accept: application/json"' + cacert = '--cacert /run/secrets/ca.cert.pem' + cert = '--cert /run/secrets/server/cert.pem' + key = '--key /run/secrets/server/key.pem' + base_url = 'https://client:19531' + + curl_cli = f"{curl} {accept_json} {cacert} {cert} {key} --fail" + + machine_info = client.succeed(f"{curl_cli} {base_url}/machine") + assert json.loads(machine_info)["hostname"] == "client", "wrong machine name" + + # The HTTP request should have started the gateway service, triggered by + # the .socket unit + client.wait_for_unit("systemd-journal-gatewayd.service") + + identifier = "nixos-test" + message = "Hello from NixOS test infrastructure" + + client.succeed(f"systemd-cat --identifier={identifier} <<< '{message}'") + + # max-time is a workaround against a bug in systemd-journal-gatewayd where + # if TLS is enabled, the connection is never closed. Since it will timeout, + # we ignore the return code. + entries = client.succeed( + f"{curl_cli} --max-time 5 {base_url}/entries?SYSLOG_IDENTIFIER={identifier} || true" + ) + + # Number of entries should be only 1 + added_entry = json.loads(entries) + assert added_entry["SYSLOG_IDENTIFIER"] == identifier and added_entry["MESSAGE"] == message, "journal entry does not correspond" + ''; +}) diff --git a/nixos/tests/systemd-journal-upload.nix b/nixos/tests/systemd-journal-upload.nix new file mode 100644 index 000000000000..0cbde379aee9 --- /dev/null +++ b/nixos/tests/systemd-journal-upload.nix @@ -0,0 +1,101 @@ +import ./make-test-python.nix ({ pkgs, ... }: +{ + name = "systemd-journal-upload"; + meta = with pkgs.lib.maintainers; { + maintainers = [ minijackson raitobezarius ]; + }; + + nodes.server = { nodes, ... }: { + services.journald.remote = { + enable = true; + listen = "http"; + settings.Remote = { + ServerCertificateFile = "/run/secrets/sever.cert.pem"; + ServerKeyFile = "/run/secrets/sever.key.pem"; + TrustedCertificateFile = "/run/secrets/ca.cert.pem"; + Seal = true; + }; + }; + + networking.firewall.allowedTCPPorts = [ nodes.server.services.journald.remote.port ]; + }; + + nodes.client = { lib, nodes, ... }: { + services.journald.upload = { + enable = true; + settings.Upload = { + URL = "http://server:${toString nodes.server.services.journald.remote.port}"; + ServerCertificateFile = "/run/secrets/client.cert.pem"; + ServerKeyFile = "/run/secrets/client.key.pem"; + TrustedCertificateFile = "/run/secrets/ca.cert.pem"; + }; + }; + + # Wait for the PEMs to arrive + systemd.services.systemd-journal-upload.wantedBy = lib.mkForce []; + systemd.paths.systemd-journal-upload = { + wantedBy = [ "default.target" ]; + # This file must be copied last + pathConfig.PathExists = [ "/run/secrets/ca.cert.pem" ]; + }; + }; + + testScript = '' + import subprocess + import tempfile + + tmpdir_o = tempfile.TemporaryDirectory() + tmpdir = tmpdir_o.name + + def generate_pems(domain: str): + subprocess.run( + [ + "${pkgs.minica}/bin/minica", + "--ca-key=ca.key.pem", + "--ca-cert=ca.cert.pem", + f"--domains={domain}", + ], + cwd=str(tmpdir), + ) + + with subtest("Creating keys and certificates"): + generate_pems("server") + generate_pems("client") + + server.wait_for_unit("multi-user.target") + client.wait_for_unit("multi-user.target") + + def copy_pems(machine: Machine, domain: str): + machine.succeed("mkdir /run/secrets") + machine.copy_from_host( + source=f"{tmpdir}/{domain}/cert.pem", + target=f"/run/secrets/{domain}.cert.pem", + ) + machine.copy_from_host( + source=f"{tmpdir}/{domain}/key.pem", + target=f"/run/secrets/{domain}.key.pem", + ) + # Should be last + machine.copy_from_host( + source=f"{tmpdir}/ca.cert.pem", + target="/run/secrets/ca.cert.pem", + ) + + with subtest("Copying keys and certificates"): + copy_pems(server, "server") + copy_pems(client, "client") + + client.wait_for_unit("systemd-journal-upload.service") + # The journal upload should have started the remote service, triggered by + # the .socket unit + server.wait_for_unit("systemd-journal-remote.service") + + identifier = "nixos-test" + message = "Hello from NixOS test infrastructure" + + client.succeed(f"systemd-cat --identifier={identifier} <<< '{message}'") + server.wait_until_succeeds( + f"journalctl --file /var/log/journal/remote/remote-*.journal --identifier={identifier} | grep -F '{message}'" + ) + ''; +}) diff --git a/nixos/tests/systemd-journal.nix b/nixos/tests/systemd-journal.nix index d2063a3b9a44..ad60c0f547a4 100644 --- a/nixos/tests/systemd-journal.nix +++ b/nixos/tests/systemd-journal.nix @@ -6,17 +6,11 @@ import ./make-test-python.nix ({ pkgs, ... }: maintainers = [ lewo ]; }; - nodes.machine = { pkgs, lib, ... }: { - services.journald.enableHttpGateway = true; - }; + nodes.machine = { }; testScript = '' machine.wait_for_unit("multi-user.target") machine.succeed("journalctl --grep=systemd") - - machine.succeed( - "${pkgs.curl}/bin/curl -s localhost:19531/machine | ${pkgs.jq}/bin/jq -e '.hostname == \"machine\"'" - ) ''; }) diff --git a/nixos/tests/systemd-lock-handler.nix b/nixos/tests/systemd-lock-handler.nix new file mode 100644 index 000000000000..d6fb8f545900 --- /dev/null +++ b/nixos/tests/systemd-lock-handler.nix @@ -0,0 +1,56 @@ +{ lib, ... }: { + name = "systemd-lock-handler"; + + meta.maintainers = with lib.maintainers; [ liff ]; + + enableOCR = true; + + nodes.machine = { config, pkgs, lib, ... }: + let + touch = "${lib.getBin pkgs.coreutils}/bin/touch"; + in + { + imports = [ common/wayland-cage.nix ]; + + services.systemd-lock-handler.enable = true; + + systemd.user.services = { + test-lock = { + partOf = [ "lock.target" ]; + onSuccess = [ "unlock.target" ]; + before = [ "lock.target" ]; + wantedBy = [ "lock.target" ]; + serviceConfig.ExecStart = "${touch} /tmp/lock.target.activated"; + }; + test-unlock = { + partOf = [ "unlock.target" ]; + after = [ "unlock.target" ]; + wantedBy = [ "unlock.target" ]; + serviceConfig.ExecStart = "${touch} /tmp/unlock.target.activated"; + }; + test-sleep = { + partOf = [ "sleep.target" ]; + before = [ "sleep.target" ]; + wantedBy = [ "sleep.target" ]; + serviceConfig.ExecStart = "${touch} /tmp/sleep.target.activated"; + }; + }; + }; + + testScript = '' + machine.wait_for_unit('graphical.target') + machine.wait_for_text('alice@machine') + + machine.send_chars('loginctl lock-session\n') + machine.wait_for_file('/tmp/lock.target.activated') + machine.wait_for_file('/tmp/unlock.target.activated') + + machine.send_chars('systemctl suspend\n') + # wait_for_file won’t complete before the machine is asleep, + # so we’ll watch the log instead. + machine.wait_for_console_text('Started test-sleep.service.') + + # The VM is asleep, regular shutdown won’t work. + machine.crash() + ''; +} diff --git a/nixos/tests/systemd-networkd-dhcpserver.nix b/nixos/tests/systemd-networkd-dhcpserver.nix index cf0ccb744211..665d8b5a0529 100644 --- a/nixos/tests/systemd-networkd-dhcpserver.nix +++ b/nixos/tests/systemd-networkd-dhcpserver.nix @@ -101,6 +101,9 @@ import ./make-test-python.nix ({pkgs, ...}: { }; testScript = { ... }: '' start_all() + + router.systemctl("start network-online.target") + client.systemctl("start network-online.target") router.wait_for_unit("systemd-networkd-wait-online.service") client.wait_for_unit("systemd-networkd-wait-online.service") client.wait_until_succeeds("ping -c 5 10.0.2.1") diff --git a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix index 54f371e6c070..1e55341657bd 100644 --- a/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix +++ b/nixos/tests/systemd-networkd-ipv6-prefix-delegation.nix @@ -263,9 +263,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { }; }; }; - - # make the network-online target a requirement, we wait for it in our test script - systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; }; # This is the client behind the router. We should be receiving router @@ -278,9 +275,6 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { useNetworkd = true; useDHCP = false; }; - - # make the network-online target a requirement, we wait for it in our test script - systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; }; }; @@ -294,6 +288,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { # Since we only care about IPv6 that should not involve waiting for legacy # IP leases. client.start() + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") # the static address on the router should not be reachable @@ -312,6 +307,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: { isp.wait_for_unit("multi-user.target") # wait until the uplink interface has a good status + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") router.wait_until_succeeds("ping -6 -c1 2001:DB8::1") diff --git a/nixos/tests/systemd-nspawn.nix b/nixos/tests/systemd-nspawn.nix index 1a4251ef069e..b86762233d18 100644 --- a/nixos/tests/systemd-nspawn.nix +++ b/nixos/tests/systemd-nspawn.nix @@ -38,6 +38,7 @@ in { start_all() server.wait_for_unit("nginx.service") + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") client.succeed("machinectl pull-raw --verify=signature http://server/testimage.raw") client.succeed( diff --git a/nixos/tests/systemd-sysusers-immutable.nix b/nixos/tests/systemd-sysusers-immutable.nix new file mode 100644 index 000000000000..42cbf84d175e --- /dev/null +++ b/nixos/tests/systemd-sysusers-immutable.nix @@ -0,0 +1,64 @@ +{ lib, ... }: + +let + rootPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6"; + normaloPassword = "$y$j9T$3aiOV/8CADAK22OK2QT3/0$67OKd50Z4qTaZ8c/eRWHLIM.o3ujtC1.n9ysmJfv639"; + newNormaloPassword = "mellow"; +in + +{ + + name = "activation-sysusers-immutable"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { + systemd.sysusers.enable = true; + users.mutableUsers = false; + + # Override the empty root password set by the test instrumentation + users.users.root.hashedPasswordFile = lib.mkForce null; + users.users.root.initialHashedPassword = rootPassword; + users.users.normalo = { + isNormalUser = true; + initialHashedPassword = normaloPassword; + }; + + specialisation.new-generation.configuration = { + users.users.new-normalo = { + isNormalUser = true; + initialPassword = newNormaloPassword; + }; + }; + }; + + testScript = '' + with subtest("Users are not created with systemd-sysusers"): + machine.fail("systemctl status systemd-sysusers.service") + machine.fail("ls /etc/sysusers.d") + + with subtest("Correct mode on the password files"): + assert machine.succeed("stat -c '%a' /etc/passwd") == "644\n" + assert machine.succeed("stat -c '%a' /etc/group") == "644\n" + assert machine.succeed("stat -c '%a' /etc/shadow") == "0\n" + assert machine.succeed("stat -c '%a' /etc/gshadow") == "0\n" + + with subtest("root user has correct password"): + print(machine.succeed("getent passwd root")) + assert "${rootPassword}" in machine.succeed("getent shadow root"), "root user password is not correct" + + with subtest("normalo user is created"): + print(machine.succeed("getent passwd normalo")) + assert machine.succeed("stat -c '%U' /home/normalo") == "normalo\n" + assert "${normaloPassword}" in machine.succeed("getent shadow normalo"), "normalo user password is not correct" + + + machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch") + + + with subtest("new-normalo user is created after switching to new generation"): + print(machine.succeed("getent passwd new-normalo")) + print(machine.succeed("getent shadow new-normalo")) + assert machine.succeed("stat -c '%U' /home/new-normalo") == "new-normalo\n" + ''; +} diff --git a/nixos/tests/systemd-sysusers-mutable.nix b/nixos/tests/systemd-sysusers-mutable.nix new file mode 100644 index 000000000000..e69cfe23a59a --- /dev/null +++ b/nixos/tests/systemd-sysusers-mutable.nix @@ -0,0 +1,71 @@ +{ lib, ... }: + +let + rootPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6"; + normaloPassword = "hello"; + newNormaloPassword = "$y$j9T$p6OI0WN7.rSfZBOijjRdR.$xUOA2MTcB48ac.9Oc5fz8cxwLv1mMqabnn333iOzSA6"; +in + +{ + + name = "activation-sysusers-mutable"; + + meta.maintainers = with lib.maintainers; [ nikstur ]; + + nodes.machine = { pkgs, ... }: { + systemd.sysusers.enable = true; + users.mutableUsers = true; + + # Prerequisites + system.etc.overlay.enable = true; + boot.initrd.systemd.enable = true; + boot.kernelPackages = pkgs.linuxPackages_latest; + + # Override the empty root password set by the test instrumentation + users.users.root.hashedPasswordFile = lib.mkForce null; + users.users.root.initialHashedPassword = rootPassword; + users.users.normalo = { + isNormalUser = true; + initialPassword = normaloPassword; + }; + + specialisation.new-generation.configuration = { + users.users.new-normalo = { + isNormalUser = true; + initialHashedPassword = newNormaloPassword; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("systemd-sysusers.service") + + with subtest("systemd-sysusers.service contains the credentials"): + sysusers_service = machine.succeed("systemctl cat systemd-sysusers.service") + print(sysusers_service) + assert "SetCredential=passwd.plaintext-password.normalo:${normaloPassword}" in sysusers_service + + with subtest("Correct mode on the password files"): + assert machine.succeed("stat -c '%a' /etc/passwd") == "644\n" + assert machine.succeed("stat -c '%a' /etc/group") == "644\n" + assert machine.succeed("stat -c '%a' /etc/shadow") == "0\n" + assert machine.succeed("stat -c '%a' /etc/gshadow") == "0\n" + + with subtest("root user has correct password"): + print(machine.succeed("getent passwd root")) + assert "${rootPassword}" in machine.succeed("getent shadow root"), "root user password is not correct" + + with subtest("normalo user is created"): + print(machine.succeed("getent passwd normalo")) + assert machine.succeed("stat -c '%U' /home/normalo") == "normalo\n" + + + machine.succeed("/run/current-system/specialisation/new-generation/bin/switch-to-configuration switch") + + + with subtest("new-normalo user is created after switching to new generation"): + print(machine.succeed("getent passwd new-normalo")) + assert machine.succeed("stat -c '%U' /home/new-normalo") == "new-normalo\n" + assert "${newNormaloPassword}" in machine.succeed("getent shadow new-normalo"), "new-normalo user password is not correct" + ''; +} diff --git a/nixos/tests/systemd-timesyncd-nscd-dnssec.nix b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix new file mode 100644 index 000000000000..697dd824e345 --- /dev/null +++ b/nixos/tests/systemd-timesyncd-nscd-dnssec.nix @@ -0,0 +1,61 @@ +# This test verifies that systemd-timesyncd can resolve the NTP server hostname when DNSSEC validation +# fails even though it is enforced in the systemd-resolved settings. It is required in order to solve +# the chicken-and-egg problem when DNSSEC validation needs the correct time to work, but to set the +# correct time, we need to connect to an NTP server, which usually requires resolving its hostname. +# +# This test does the following: +# - Sets up a DNS server (tinydns) listening on the eth1 ip addess, serving .ntp and fake.ntp records. +# - Configures that DNS server as a resolver and enables DNSSEC in systemd-resolved settings. +# - Configures systemd-timesyncd to use fake.ntp hostname as an NTP server. +# - Performs a regular DNS lookup, to ensure it fails due to broken DNSSEC. +# - Waits until systemd-timesyncd resolves fake.ntp by checking its debug output. +# Here, we don't expect systemd-timesyncd to connect and synchronize time because there is no NTP +# server running. For this test to succeed, we only need to ensure that systemd-timesyncd +# resolves the IP address of the fake.ntp host. + +import ./make-test-python.nix ({ pkgs, ... }: + +let + ntpHostname = "fake.ntp"; + ntpIP = "192.0.2.1"; +in +{ + name = "systemd-timesyncd"; + nodes.machine = { pkgs, lib, config, ... }: + let + eth1IP = (lib.head config.networking.interfaces.eth1.ipv4.addresses).address; + in + { + # Setup a local DNS server for the NTP domain on the eth1 IP address + services.tinydns = { + enable = true; + ip = eth1IP; + data = '' + .ntp:${eth1IP} + +.${ntpHostname}:${ntpIP} + ''; + }; + + # Enable systemd-resolved with DNSSEC and use the local DNS as a name server + services.resolved.enable = true; + services.resolved.dnssec = "true"; + networking.nameservers = [ eth1IP ]; + + # Configure systemd-timesyncd to use our NTP hostname + services.timesyncd.enable = lib.mkForce true; + services.timesyncd.servers = [ ntpHostname ]; + services.timesyncd.extraConfig = '' + FallbackNTP=${ntpHostname} + ''; + + # The debug output is necessary to determine whether systemd-timesyncd successfully resolves our NTP hostname or not + systemd.services.systemd-timesyncd.environment.SYSTEMD_LOG_LEVEL = "debug"; + }; + + testScript = '' + machine.wait_for_unit("tinydns.service") + machine.wait_for_unit("systemd-timesyncd.service") + machine.fail("resolvectl query ${ntpHostname}") + machine.wait_until_succeeds("journalctl -u systemd-timesyncd.service --grep='Resolved address ${ntpIP}:123 for ${ntpHostname}'") + ''; +}) diff --git a/nixos/tests/systemtap.nix b/nixos/tests/systemtap.nix new file mode 100644 index 000000000000..5cd79d66e872 --- /dev/null +++ b/nixos/tests/systemtap.nix @@ -0,0 +1,50 @@ +{ system ? builtins.currentSystem +, config ? { } +, pkgs ? import ../.. { inherit system config; } +}@args: + +with pkgs.lib; + +let + stapScript = pkgs.writeText "test.stp" '' + probe kernel.function("do_sys_poll") { + println("kernel function probe & println work") + exit() + } + ''; + + ## TODO shared infra with ../kernel-generic.nix + testsForLinuxPackages = linuxPackages: (import ./make-test-python.nix ({ pkgs, ... }: { + name = "kernel-${linuxPackages.kernel.version}"; + meta = with pkgs.lib.maintainers; { + maintainers = [ bendlas ]; + }; + + nodes.machine = { ... }: + { + boot.kernelPackages = linuxPackages; + programs.systemtap.enable = true; + }; + + testScript = + '' + with subtest("Capture stap ouput"): + output = machine.succeed("stap ${stapScript} 2>&1") + + with subtest("Ensure that expected output from stap script is there"): + assert "kernel function probe & println work\n" == output, "kernel function probe & println work\n != " + output + ''; + }) args); + + ## TODO shared infra with ../kernel-generic.nix + kernels = { + inherit (pkgs.linuxKernel.packageAliases) linux_default linux_latest; + }; + +in mapAttrs (_: lP: testsForLinuxPackages lP) kernels // { + passthru = { + inherit testsForLinuxPackages; + + testsForKernel = kernel: testsForLinuxPackages (pkgs.linuxPackagesFor kernel); + }; +} diff --git a/nixos/tests/tayga.nix b/nixos/tests/tayga.nix index 44974f6efea8..4aade67d74d0 100644 --- a/nixos/tests/tayga.nix +++ b/nixos/tests/tayga.nix @@ -206,6 +206,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: testScript = '' # start client and server for machine in client, server: + machine.systemctl("start network-online.target") machine.wait_for_unit("network-online.target") machine.log(machine.execute("ip addr")[1]) machine.log(machine.execute("ip route")[1]) @@ -214,6 +215,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: # test systemd-networkd and nixos-scripts based router for router in router_systemd, router_nixos: router.start() + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") router.wait_for_unit("tayga.service") router.log(machine.execute("ip addr")[1]) diff --git a/nixos/tests/terminal-emulators.nix b/nixos/tests/terminal-emulators.nix index efaac03e1983..3c1188ca88c9 100644 --- a/nixos/tests/terminal-emulators.nix +++ b/nixos/tests/terminal-emulators.nix @@ -61,6 +61,8 @@ let tests = { konsole.pkg = p: p.plasma5Packages.konsole; + lomiri-terminal-app.pkg = p: p.lomiri.lomiri-terminal-app; + lxterminal.pkg = p: p.lxterminal; mate-terminal.pkg = p: p.mate.mate-terminal; diff --git a/nixos/tests/trafficserver.nix b/nixos/tests/trafficserver.nix index e4557c6c50e5..94d0e4dd926e 100644 --- a/nixos/tests/trafficserver.nix +++ b/nixos/tests/trafficserver.nix @@ -104,6 +104,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { ats.wait_for_open_port(80) httpbin.wait_for_unit("httpbin") httpbin.wait_for_open_port(80) + client.systemctl("start network-online.target") client.wait_for_unit("network-online.target") with subtest("Traffic Server is running"): diff --git a/nixos/tests/typesense.nix b/nixos/tests/typesense.nix index 4f07a2e194be..87ed248257ea 100644 --- a/nixos/tests/typesense.nix +++ b/nixos/tests/typesense.nix @@ -18,6 +18,7 @@ in { testScript = '' machine.wait_for_unit("typesense.service") machine.wait_for_open_port(${toString testPort}) - assert machine.succeed("curl --fail http://localhost:${toString testPort}/health") == '{"ok":true}' + # After waiting for the port, typesense still hasn't initialized the database, so wait until we can connect successfully + assert machine.wait_until_succeeds("curl --fail http://localhost:${toString testPort}/health") == '{"ok":true}' ''; }) diff --git a/nixos/tests/ulogd/ulogd.py b/nixos/tests/ulogd/ulogd.py index d20daa4d733a..76a8d0c6e24a 100644 --- a/nixos/tests/ulogd/ulogd.py +++ b/nixos/tests/ulogd/ulogd.py @@ -1,5 +1,6 @@ start_all() machine.wait_for_unit("ulogd.service") +machine.systemctl("start network-online.target") machine.wait_for_unit("network-online.target") with subtest("Ulogd is running"): diff --git a/nixos/tests/upnp.nix b/nixos/tests/upnp.nix index af7cc1fe2413..93bc08f752ce 100644 --- a/nixos/tests/upnp.nix +++ b/nixos/tests/upnp.nix @@ -5,7 +5,7 @@ # this succeeds an external client will try to connect to the port # mapping. -import ./make-test-python.nix ({ pkgs, ... }: +import ./make-test-python.nix ({ pkgs, useNftables, ... }: let internalRouterAddress = "192.168.3.1"; @@ -27,6 +27,7 @@ in networking.nat.enable = true; networking.nat.internalInterfaces = [ "eth2" ]; networking.nat.externalInterface = "eth1"; + networking.nftables.enable = useNftables; networking.firewall.enable = true; networking.firewall.trustedInterfaces = [ "eth2" ]; networking.interfaces.eth1.ipv4.addresses = [ @@ -80,11 +81,13 @@ in start_all() # Wait for network and miniupnpd. + router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") # $router.wait_for_unit("nat") - router.wait_for_unit("firewall.service") + router.wait_for_unit("${if useNftables then "nftables" else "firewall"}.service") router.wait_for_unit("miniupnpd") + client1.systemctl("start network-online.target") client1.wait_for_unit("network-online.target") client1.succeed("upnpc -a ${internalClient1Address} 9000 9000 TCP") diff --git a/nixos/tests/uptermd.nix b/nixos/tests/uptermd.nix index 429e3c9dd5ff..469aa5047c27 100644 --- a/nixos/tests/uptermd.nix +++ b/nixos/tests/uptermd.nix @@ -28,6 +28,7 @@ in start_all() server.wait_for_unit("uptermd.service") + server.systemctl("start network-online.target") server.wait_for_unit("network-online.target") # wait for upterm port to be reachable diff --git a/nixos/tests/watchdogd.nix b/nixos/tests/watchdogd.nix new file mode 100644 index 000000000000..663e97cbae10 --- /dev/null +++ b/nixos/tests/watchdogd.nix @@ -0,0 +1,22 @@ +import ./make-test-python.nix ({ lib, ... }: { + name = "watchdogd"; + meta.maintainers = with lib.maintainers; [ vifino ]; + + nodes.machine = { pkgs, ... }: { + virtualisation.qemu.options = [ + "-device i6300esb" # virtual watchdog timer + ]; + boot.kernelModules = [ "i6300esb" ]; + services.watchdogd.enable = true; + services.watchdogd.settings = { + supervisor.enabled = true; + }; + }; + + testScript = '' + machine.wait_for_unit("watchdogd.service") + + assert "i6300ESB" in machine.succeed("watchdogctl status") + machine.succeed("watchdogctl test") + ''; +}) diff --git a/nixos/tests/web-apps/netbox-upgrade.nix b/nixos/tests/web-apps/netbox-upgrade.nix index b5403eb678bc..4c554e7ae613 100644 --- a/nixos/tests/web-apps/netbox-upgrade.nix +++ b/nixos/tests/web-apps/netbox-upgrade.nix @@ -1,6 +1,6 @@ import ../make-test-python.nix ({ lib, pkgs, ... }: let - oldNetbox = pkgs.netbox_3_5; - newNetbox = pkgs.netbox_3_6; + oldNetbox = pkgs.netbox_3_6; + newNetbox = pkgs.netbox_3_7; in { name = "netbox-upgrade"; diff --git a/nixos/tests/web-apps/pretalx.nix b/nixos/tests/web-apps/pretalx.nix new file mode 100644 index 000000000000..a226639b076b --- /dev/null +++ b/nixos/tests/web-apps/pretalx.nix @@ -0,0 +1,31 @@ +{ lib, ... }: + +{ + name = "pretalx"; + meta.maintainers = lib.teams.c3d2.members; + + nodes = { + pretalx = { + networking.extraHosts = '' + 127.0.0.1 talks.local + ''; + + services.pretalx = { + enable = true; + nginx.domain = "talks.local"; + settings = { + site.url = "http://talks.local"; + }; + }; + }; + }; + + testScript = '' + start_all() + + pretalx.wait_for_unit("pretalx-web.service") + pretalx.wait_for_unit("pretalx-worker.service") + + pretalx.wait_until_succeeds("curl -q --fail http://talks.local/orga/") + ''; +} diff --git a/nixos/tests/web-servers/stargazer.nix b/nixos/tests/web-servers/stargazer.nix index 6365d6a4fff1..f56d1b8c9454 100644 --- a/nixos/tests/web-servers/stargazer.nix +++ b/nixos/tests/web-servers/stargazer.nix @@ -1,4 +1,41 @@ { pkgs, lib, ... }: +let + test_script = pkgs.stdenv.mkDerivation rec { + pname = "stargazer-test-script"; + inherit (pkgs.stargazer) version src; + buildInputs = with pkgs; [ (python3.withPackages (ps: with ps; [ cryptography ])) ]; + dontBuild = true; + doCheck = false; + installPhase = '' + mkdir -p $out/bin + cp scripts/gemini-diagnostics $out/bin/test + ''; + }; + test_env = pkgs.stdenv.mkDerivation rec { + pname = "stargazer-test-env"; + inherit (pkgs.stargazer) version src; + buildPhase = '' + cc test_data/cgi-bin/loop.c -o test_data/cgi-bin/loop + ''; + doCheck = false; + installPhase = '' + mkdir -p $out + cp -r * $out/ + ''; + }; + scgi_server = pkgs.stdenv.mkDerivation rec { + pname = "stargazer-test-scgi-server"; + inherit (pkgs.stargazer) version src; + buildInputs = with pkgs; [ python3 ]; + dontConfigure = true; + dontBuild = true; + doCheck = false; + installPhase = '' + mkdir -p $out/bin + cp scripts/scgi-server $out/bin/scgi-server + ''; + }; +in { name = "stargazer"; meta = with lib.maintainers; { maintainers = [ gaykitty ]; }; @@ -7,25 +44,84 @@ geminiserver = { pkgs, ... }: { services.stargazer = { enable = true; + connectionLogging = false; + requestTimeout = 1; routes = [ { route = "localhost"; - root = toString (pkgs.writeTextDir "index.gmi" '' - # Hello NixOS! - ''); + root = "${test_env}/test_data/test_site"; + } + { + route = "localhost=/en.gmi"; + root = "${test_env}/test_data/test_site"; + lang = "en"; + charset = "ascii"; + } + { + route = "localhost~/(.*).gemini"; + root = "${test_env}/test_data/test_site"; + rewrite = "\\1.gmi"; + lang = "en"; + charset = "ascii"; + } + { + route = "localhost=/plain.txt"; + root = "${test_env}/test_data/test_site"; + lang = "en"; + charset = "ascii"; + cert-path = "/var/lib/gemini/certs/localhost.crt"; + key-path = "/var/lib/gemini/certs/localhost.key"; + } + { + route = "localhost:/cgi-bin"; + root = "${test_env}/test_data"; + cgi = true; + cgi-timeout = 5; + } + { + route = "localhost:/scgi"; + scgi = true; + scgi-address = "127.0.0.1:1099"; + } + { + route = "localhost=/root"; + redirect = ".."; + permanent = true; + } + { + route = "localhost=/priv.gmi"; + root = "${test_env}/test_data/test_site"; + client-cert = "${test_env}/test_data/client_cert/good.crt"; + } + { + route = "example.com~(.*)"; + redirect = "gemini://localhost"; + rewrite = "\\1"; + } + { + route = "localhost:/no-exist"; + root = "./does_not_exist"; } ]; }; + systemd.services.scgi_server = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${scgi_server}/bin/scgi-server"; + }; + }; }; }; testScript = { nodes, ... }: '' + geminiserver.wait_for_unit("scgi_server") + geminiserver.wait_for_open_port(1099) geminiserver.wait_for_unit("stargazer") geminiserver.wait_for_open_port(1965) - with subtest("check is serving over gemini"): - response = geminiserver.succeed("${pkgs.gemget}/bin/gemget --header -o - gemini://localhost:1965") + with subtest("stargazer test suite"): + response = geminiserver.succeed("sh -c 'cd ${test_env}; ${test_script}/bin/test'") print(response) - assert "Hello NixOS!" in response ''; } diff --git a/nixos/tests/web-servers/ttyd.nix b/nixos/tests/web-servers/ttyd.nix new file mode 100644 index 000000000000..d161673684b3 --- /dev/null +++ b/nixos/tests/web-servers/ttyd.nix @@ -0,0 +1,19 @@ +import ../make-test-python.nix ({ lib, pkgs, ... }: { + name = "ttyd"; + meta.maintainers = with lib.maintainers; [ stunkymonkey ]; + + nodes.machine = { pkgs, ... }: { + services.ttyd = { + enable = true; + username = "foo"; + passwordFile = pkgs.writeText "password" "bar"; + }; + }; + + testScript = '' + machine.wait_for_unit("ttyd.service") + machine.wait_for_open_port(7681) + response = machine.succeed("curl -vvv -u foo:bar -s -H 'Host: ttyd' http://127.0.0.1:7681/") + assert '<title>ttyd - Terminal</title>' in response, "Page didn't load successfully" + ''; +}) diff --git a/nixos/tests/xrdp-with-audio-pulseaudio.nix b/nixos/tests/xrdp-with-audio-pulseaudio.nix new file mode 100644 index 000000000000..27da7c457c49 --- /dev/null +++ b/nixos/tests/xrdp-with-audio-pulseaudio.nix @@ -0,0 +1,97 @@ +import ./make-test-python.nix ({ pkgs, ...} : { + # How to interactively test this module if the audio actually works + + # - nix run .#pulseaudio-module-xrdp.tests.xrdp-with-audio-pulseaudio.driverInteractive + # - test_script() # launches the terminal and the tests itself + # - server.send_monitor_command("hostfwd_add tcp::3389-:3389") # forward the RDP port to the host + # - Connect with the RDP client you like (ex: Remmina) + # - Don't forget to enable audio support. In remmina: Advanced -> Audio output mode to Local (default is Off) + # - Open a browser or something that plays sound. Ex: chromium + + name = "xrdp-with-audio-pulseaudio"; + meta = with pkgs.lib.maintainers; { + maintainers = [ lucasew ]; + }; + + nodes = { + server = { pkgs, ... }: { + imports = [ ./common/user-account.nix ]; + + environment.etc."xrdp/test.txt".text = "Shouldn't conflict"; + + services.xrdp.enable = true; + services.xrdp.audio.enable = true; + services.xrdp.defaultWindowManager = "${pkgs.xterm}/bin/xterm"; + + hardware.pulseaudio = { + enable = true; + }; + + systemd.user.services.pactl-list = { + script = '' + while [ ! -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]; do + sleep 1 + done + sleep 1 + ${pkgs.pulseaudio}/bin/pactl list + echo Source: + ${pkgs.pulseaudio}/bin/pactl get-default-source | tee /tmp/pulseaudio-source + echo Sink: + ${pkgs.pulseaudio}/bin/pactl get-default-sink | tee /tmp/pulseaudio-sink + + ''; + wantedBy = [ "default.target" ]; + }; + + networking.firewall.allowedTCPPorts = [ 3389 ]; + }; + + client = { pkgs, ... }: { + imports = [ ./common/x11.nix ./common/user-account.nix ]; + test-support.displayManager.auto.user = "alice"; + + environment.systemPackages = [ pkgs.freerdp ]; + + services.xrdp.enable = true; + services.xrdp.audio.enable = true; + services.xrdp.defaultWindowManager = "${pkgs.icewm}/bin/icewm"; + + hardware.pulseaudio = { + enable = true; + }; + }; + }; + + testScript = { nodes, ... }: let + user = nodes.client.config.users.users.alice; + in '' + start_all() + + client.wait_for_x() + client.wait_for_file("${user.home}/.Xauthority") + client.succeed("xauth merge ${user.home}/.Xauthority") + + client.sleep(5) + + client.execute("xterm >&2 &") + client.sleep(1) + + client.send_chars("xfreerdp /cert-tofu /w:640 /h:480 /v:127.0.0.1 /u:${user.name} /p:${user.password} /sound\n") + + client.sleep(10) + + client.succeed("[ -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]") # checks if it's a socket + client.sleep(5) + client.screenshot("localrdp") + + client.execute("xterm >&2 &") + client.sleep(1) + client.send_chars("xfreerdp /cert-tofu /w:640 /h:480 /v:server /u:${user.name} /p:${user.password} /sound\n") + client.sleep(10) + + server.succeed("[ -S /tmp/.xrdp/xrdp_chansrv_audio_in_socket_* ]") # checks if it's a socket + server.succeed('[ "$(cat /tmp/pulseaudio-source)" == "xrdp-source" ]') + server.succeed('[ "$(cat /tmp/pulseaudio-sink)" == "xrdp-sink" ]') + client.screenshot("remoterdp") + ''; +}) diff --git a/nixos/tests/zfs.nix b/nixos/tests/zfs.nix index 8fedcf095af6..0b411b0b9d8a 100644 --- a/nixos/tests/zfs.nix +++ b/nixos/tests/zfs.nix @@ -8,12 +8,9 @@ with import ../lib/testing-python.nix { inherit system pkgs; }; let makeZfsTest = name: - { kernelPackage ? if enableUnstable - then pkgs.zfsUnstable.latestCompatibleLinuxPackages - else pkgs.linuxPackages - , enableUnstable ? false + { kernelPackages , enableSystemdStage1 ? false - , zfsPackage ? if enableUnstable then pkgs.zfs else pkgs.zfsUnstable + , zfsPackage , extraTest ? "" }: makeTest { @@ -35,7 +32,7 @@ let boot.loader.timeout = 0; boot.loader.efi.canTouchEfiVariables = true; networking.hostId = "deadbeef"; - boot.kernelPackages = kernelPackage; + boot.kernelPackages = kernelPackages; boot.zfs.package = zfsPackage; boot.supportedFilesystems = [ "zfs" ]; boot.initrd.systemd.enable = enableSystemdStage1; @@ -197,16 +194,22 @@ in { # maintainer: @raitobezarius series_2_1 = makeZfsTest "2.1-series" { zfsPackage = pkgs.zfs_2_1; + kernelPackages = pkgs.linuxPackages; }; - stable = makeZfsTest "stable" { }; + stable = makeZfsTest "stable" { + zfsPackage = pkgs.zfsStable; + kernelPackages = pkgs.linuxPackages; + }; - unstable = makeZfsTest "unstable" { - enableUnstable = true; + unstable = makeZfsTest "unstable" rec { + zfsPackage = pkgs.zfsUnstable; + kernelPackages = zfsPackage.latestCompatibleLinuxPackages; }; - unstableWithSystemdStage1 = makeZfsTest "unstable" { - enableUnstable = true; + unstableWithSystemdStage1 = makeZfsTest "unstable" rec { + zfsPackage = pkgs.zfsUnstable; + kernelPackages = zfsPackage.latestCompatibleLinuxPackages; enableSystemdStage1 = true; }; diff --git a/nixos/tests/zrepl.nix b/nixos/tests/zrepl.nix index b16c7eddc7ae..bdf11122c73f 100644 --- a/nixos/tests/zrepl.nix +++ b/nixos/tests/zrepl.nix @@ -42,6 +42,7 @@ import ./make-test-python.nix ( start_all() with subtest("Wait for zrepl and network ready"): + host.systemctl("start network-online.target") host.wait_for_unit("network-online.target") host.wait_for_unit("zrepl.service") |