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