diff options
Diffstat (limited to 'nixos/tests')
-rw-r--r-- | nixos/tests/acme.nix | 64 | ||||
-rw-r--r-- | nixos/tests/all-tests.nix | 1 | ||||
-rw-r--r-- | nixos/tests/bootspec.nix | 144 | ||||
-rw-r--r-- | nixos/tests/cockroachdb.nix | 2 | ||||
-rw-r--r-- | nixos/tests/common/ec2.nix | 2 | ||||
-rw-r--r-- | nixos/tests/grafana/basic.nix | 27 | ||||
-rw-r--r-- | nixos/tests/graphite.nix | 2 | ||||
-rw-r--r-- | nixos/tests/home-assistant.nix | 2 | ||||
-rw-r--r-- | nixos/tests/networking-proxy.nix | 2 | ||||
-rw-r--r-- | nixos/tests/nginx-globalredirect.nix | 24 | ||||
-rw-r--r-- | nixos/tests/nginx.nix | 2 | ||||
-rw-r--r-- | nixos/tests/nix-ld.nix | 5 | ||||
-rw-r--r-- | nixos/tests/os-prober.nix | 2 | ||||
-rw-r--r-- | nixos/tests/pgadmin4-standalone.nix | 2 | ||||
-rw-r--r-- | nixos/tests/pgadmin4.nix | 2 | ||||
-rw-r--r-- | nixos/tests/postgresql.nix | 93 | ||||
-rw-r--r-- | nixos/tests/prometheus-exporters.nix | 19 | ||||
-rw-r--r-- | nixos/tests/sourcehut.nix | 2 | ||||
-rw-r--r-- | nixos/tests/vaultwarden.nix | 2 |
19 files changed, 360 insertions, 39 deletions
diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index d540bc6ec31bb..d62bf0c0fd92d 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -144,7 +144,11 @@ in { name = "acme"; - meta.maintainers = lib.teams.acme.members; + meta = { + maintainers = lib.teams.acme.members; + # Hard timeout in seconds. Average run time is about 7 minutes. + timeout = 1800; + }; nodes = { # The fake ACME server which will respond to client requests @@ -277,7 +281,7 @@ in { }; }; - # Test compatiblity with Caddy + # Test compatibility with Caddy # It only supports useACMEHost, hence not using mkServerConfigs } // (let baseCaddyConfig = { nodes, config, ... }: { @@ -357,6 +361,30 @@ in { import time + TOTAL_RETRIES = 20 + + + class BackoffTracker(object): + delay = 1 + increment = 1 + + def handle_fail(self, retries, message) -> int: + assert retries < TOTAL_RETRIES, message + + print(f"Retrying in {self.delay}s, {retries + 1}/{TOTAL_RETRIES}") + time.sleep(self.delay) + + # Only increment after the first try + if retries == 0: + self.delay += self.increment + self.increment *= 2 + + return retries + 1 + + + backoff = BackoffTracker() + + def switch_to(node, name): # On first switch, this will create a symlink to the current system so that we can # quickly switch between derivations @@ -404,9 +432,7 @@ in { assert False - def check_connection(node, domain, retries=3): - assert retries >= 0, f"Failed to connect to https://{domain}" - + def check_connection(node, domain, retries=0): result = node.succeed( "openssl s_client -brief -verify 2 -CAfile /tmp/ca.crt" f" -servername {domain} -connect {domain}:443 < /dev/null 2>&1" @@ -414,13 +440,11 @@ in { for line in result.lower().split("\n"): if "verification" in line and "error" in line: - time.sleep(3) - return check_connection(node, domain, retries - 1) + retries = backoff.handle_fail(retries, f"Failed to connect to https://{domain}") + return check_connection(node, domain, retries) - def check_connection_key_bits(node, domain, bits, retries=3): - assert retries >= 0, f"Did not find expected number of bits ({bits}) in key" - + def check_connection_key_bits(node, domain, bits, retries=0): result = node.succeed( "openssl s_client -CAfile /tmp/ca.crt" f" -servername {domain} -connect {domain}:443 < /dev/null" @@ -429,13 +453,11 @@ in { print("Key type:", result) if bits not in result: - time.sleep(3) - return check_connection_key_bits(node, domain, bits, retries - 1) - + retries = backoff.handle_fail(retries, f"Did not find expected number of bits ({bits}) in key") + return check_connection_key_bits(node, domain, bits, retries) - def check_stapling(node, domain, retries=3): - assert retries >= 0, "OCSP Stapling check failed" + def check_stapling(node, domain, retries=0): # Pebble doesn't provide a full OCSP responder, so just check the URL result = node.succeed( "openssl s_client -CAfile /tmp/ca.crt" @@ -445,21 +467,19 @@ in { print("OCSP Responder URL:", result) if "${caDomain}:4002" not in result.lower(): - time.sleep(3) - return check_stapling(node, domain, retries - 1) - + retries = backoff.handle_fail(retries, "OCSP Stapling check failed") + return check_stapling(node, domain, retries) - def download_ca_certs(node, retries=5): - assert retries >= 0, "Failed to connect to pebble to download root CA certs" + def download_ca_certs(node, retries=0): exit_code, _ = node.execute("curl https://${caDomain}:15000/roots/0 > /tmp/ca.crt") exit_code_2, _ = node.execute( "curl https://${caDomain}:15000/intermediate-keys/0 >> /tmp/ca.crt" ) if exit_code + exit_code_2 > 0: - time.sleep(3) - return download_ca_certs(node, retries - 1) + retries = backoff.handle_fail(retries, "Failed to connect to pebble to download root CA certs") + return download_ca_certs(node, retries) start_all() diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 7163d0c8dc608..1956d3c9e8c7c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -435,6 +435,7 @@ in { nginx = handleTest ./nginx.nix {}; nginx-auth = handleTest ./nginx-auth.nix {}; nginx-etag = handleTest ./nginx-etag.nix {}; + nginx-globalredirect = handleTest ./nginx-globalredirect.nix {}; nginx-http3 = handleTest ./nginx-http3.nix {}; nginx-modsecurity = handleTest ./nginx-modsecurity.nix {}; nginx-njs = handleTest ./nginx-njs.nix {}; diff --git a/nixos/tests/bootspec.nix b/nixos/tests/bootspec.nix new file mode 100644 index 0000000000000..13360bb1eaa2e --- /dev/null +++ b/nixos/tests/bootspec.nix @@ -0,0 +1,144 @@ +{ system ? builtins.currentSystem, + config ? {}, + pkgs ? import ../.. { inherit system config; } +}: + +with import ../lib/testing-python.nix { inherit system pkgs; }; +with pkgs.lib; + +let + baseline = { + virtualisation.useBootLoader = true; + }; + grub = { + boot.loader.grub.enable = true; + }; + systemd-boot = { + boot.loader.systemd-boot.enable = true; + }; + uefi = { + virtualisation.useEFIBoot = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.grub.efiSupport = true; + environment.systemPackages = [ pkgs.efibootmgr ]; + }; + standard = { + boot.bootspec.enable = true; + + imports = [ + baseline + systemd-boot + uefi + ]; + }; +in +{ + basic = makeTest { + name = "systemd-boot-with-bootspec"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = standard; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") + + machine.succeed("test -e /run/current-system/bootspec/boot.json") + ''; + }; + + grub = makeTest { + name = "grub-with-bootspec"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { + boot.bootspec.enable = true; + + imports = [ + baseline + grub + uefi + ]; + }; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") + + machine.succeed("test -e /run/current-system/bootspec/boot.json") + ''; + }; + + legacy-boot = makeTest { + name = "legacy-boot-with-bootspec"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { + boot.bootspec.enable = true; + + imports = [ + baseline + grub + ]; + }; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") + + machine.succeed("test -e /run/current-system/bootspec/boot.json") + ''; + }; + + # Check that specialisations create corresponding entries in bootspec. + specialisation = makeTest { + name = "bootspec-with-specialisation"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { + imports = [ standard ]; + environment.systemPackages = [ pkgs.jq ]; + specialisation.something.configuration = {}; + }; + + testScript = '' + import json + + machine.start() + machine.wait_for_unit("multi-user.target") + + machine.succeed("test -e /run/current-system/bootspec/boot.json") + machine.succeed("test -e /run/current-system/specialisation/something/bootspec/boot.json") + + sp_in_parent = json.loads(machine.succeed("jq -r '.v1.specialisation.something' /run/current-system/bootspec/boot.json")) + sp_in_fs = json.loads(machine.succeed("cat /run/current-system/specialisation/something/bootspec/boot.json")) + + assert sp_in_parent == sp_in_fs['v1'], "Bootspecs of the same specialisation are different!" + ''; + }; + + # Check that extensions are propagated. + extensions = makeTest { + name = "bootspec-with-extensions"; + meta.maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; + + nodes.machine = { config, ... }: { + imports = [ standard ]; + environment.systemPackages = [ pkgs.jq ]; + boot.bootspec.extensions = { + osRelease = config.environment.etc."os-release".source; + }; + }; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") + + current_os_release = machine.succeed("cat /etc/os-release") + bootspec_os_release = machine.succeed("cat $(jq -r '.v1.extensions.osRelease' /run/current-system/bootspec/boot.json)") + + assert current_os_release == bootspec_os_release, "Filename referenced by extension has unexpected contents" + ''; + }; + +} diff --git a/nixos/tests/cockroachdb.nix b/nixos/tests/cockroachdb.nix index d793842f0ab2d..5b1e1a7dee1f9 100644 --- a/nixos/tests/cockroachdb.nix +++ b/nixos/tests/cockroachdb.nix @@ -8,7 +8,7 @@ # Cluster joins that are outside this window will fail, and nodes that skew # outside the window after joining will promptly get kicked out. # -# To accomodate this, we use QEMU/virtio infrastructure and load the 'ptp_kvm' +# To accommodate this, we use QEMU/virtio infrastructure and load the 'ptp_kvm' # driver inside a guest. This driver allows the host machine to pass its clock # through to the guest as a hardware clock that appears as a Precision Time # Protocol (PTP) Clock device, generally /dev/ptp0. PTP devices can be measured diff --git a/nixos/tests/common/ec2.nix b/nixos/tests/common/ec2.nix index 64b0a91ac1f72..6ed420e0aae75 100644 --- a/nixos/tests/common/ec2.nix +++ b/nixos/tests/common/ec2.nix @@ -46,7 +46,7 @@ with pkgs.lib; # Note: we use net=169.0.0.0/8 rather than # net=169.254.0.0/16 to prevent dhcpcd from getting horribly # confused. (It would get a DHCP lease in the 169.254.* - # range, which it would then configure and prompty delete + # range, which it would then configure and promptly delete # again when it deletes link-local addresses.) Ideally we'd # turn off the DHCP server, but qemu does not have an option # to do that. diff --git a/nixos/tests/grafana/basic.nix b/nixos/tests/grafana/basic.nix index f6566d4497098..8bf4caad7fbfc 100644 --- a/nixos/tests/grafana/basic.nix +++ b/nixos/tests/grafana/basic.nix @@ -25,6 +25,22 @@ let extraNodeConfs = { sqlite = {}; + socket = { config, ... }: { + services.grafana.settings.server = { + protocol = "socket"; + socket = "/run/grafana/sock"; + socket_gid = config.users.groups.nginx.gid; + }; + + users.users.grafana.extraGroups = [ "nginx" ]; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts."_".locations."/".proxyPass = "http://unix:/run/grafana/sock"; + }; + }; + declarativePlugins = { services.grafana.declarativePlugins = [ pkgs.grafanaPlugins.grafana-clock-panel ]; }; @@ -92,6 +108,17 @@ in { ) sqlite.shutdown() + with subtest("Successful API query as admin user with sqlite db listening on socket"): + socket.wait_for_unit("grafana.service") + socket.wait_for_open_port(80) + print(socket.succeed( + "curl -sSfN -u testadmin:snakeoilpwd http://127.0.0.1/api/org/users -i" + )) + socket.succeed( + "curl -sSfN -u testadmin:snakeoilpwd http://127.0.0.1/api/org/users | grep admin\@localhost" + ) + socket.shutdown() + with subtest("Successful API query as admin user with postgresql db"): postgresql.wait_for_unit("grafana.service") postgresql.wait_for_unit("postgresql.service") diff --git a/nixos/tests/graphite.nix b/nixos/tests/graphite.nix index c534d45428e19..de6cd8a50e179 100644 --- a/nixos/tests/graphite.nix +++ b/nixos/tests/graphite.nix @@ -13,7 +13,7 @@ import ./make-test-python.nix ({ pkgs, ... } : ''; }; carbon.enableCache = true; - seyren.enable = false; # Implicitely requires openssl-1.0.2u which is marked insecure + seyren.enable = false; # Implicitly requires openssl-1.0.2u which is marked insecure }; }; }; diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index 0bbeffd18cf0d..8d58de75eabc3 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -120,7 +120,7 @@ in { start_all() # Parse the package path out of the systemd unit, as we cannot - # access the final package, that is overriden inside the module, + # access the final package, that is overridden inside the module, # by any other means. pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass") response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1] diff --git a/nixos/tests/networking-proxy.nix b/nixos/tests/networking-proxy.nix index fcb2558cf3b08..330bac2588a5a 100644 --- a/nixos/tests/networking-proxy.nix +++ b/nixos/tests/networking-proxy.nix @@ -37,7 +37,7 @@ in import ./make-test-python.nix ({ pkgs, ...} : { default-config // { networking.proxy = { - # useless because overriden by the next options + # useless because overridden by the next options default = "http://user:pass@host:port"; # advanced proxy setup httpProxy = "123-http://user:pass@http-host:port"; diff --git a/nixos/tests/nginx-globalredirect.nix b/nixos/tests/nginx-globalredirect.nix new file mode 100644 index 0000000000000..5f5f4f344d825 --- /dev/null +++ b/nixos/tests/nginx-globalredirect.nix @@ -0,0 +1,24 @@ +import ./make-test-python.nix ({ pkgs, ... }: { + name = "nginx-globalredirect"; + + nodes = { + webserver = { pkgs, lib, ... }: { + services.nginx = { + enable = true; + virtualHosts.localhost = { + globalRedirect = "other.example.com"; + # Add an exception + locations."/noredirect".return = "200 'foo'"; + }; + }; + }; + }; + + testScript = '' + webserver.wait_for_unit("nginx") + webserver.wait_for_open_port(80) + + webserver.succeed("curl --fail -si http://localhost/alf | grep '^Location:.*/alf'") + webserver.fail("curl --fail -si http://localhost/noredirect | grep '^Location:'") + ''; +}) diff --git a/nixos/tests/nginx.nix b/nixos/tests/nginx.nix index d9d073822a145..73f1133bd6ca9 100644 --- a/nixos/tests/nginx.nix +++ b/nixos/tests/nginx.nix @@ -61,7 +61,7 @@ import ./make-test-python.nix ({ pkgs, ... }: { specialisation.reloadWithErrorsSystem.configuration = { services.nginx.package = pkgs.nginxMainline; - services.nginx.virtualHosts."!@$$(#*%".locations."~@#*$*!)".proxyPass = ";;;"; + services.nginx.virtualHosts."hello".extraConfig = "access_log /does/not/exist.log;"; }; }; }; diff --git a/nixos/tests/nix-ld.nix b/nixos/tests/nix-ld.nix index ae5297ab87eaa..8733f5b0c3978 100644 --- a/nixos/tests/nix-ld.nix +++ b/nixos/tests/nix-ld.nix @@ -12,9 +12,6 @@ import ./make-test-python.nix ({ lib, pkgs, ...} : }; testScript = '' start_all() - path = "${pkgs.stdenv.cc}/nix-support/dynamic-linker" - with open(path) as f: - real_ld = f.read().strip() - machine.succeed(f"NIX_LD={real_ld} hello") + machine.succeed("hello") ''; }) diff --git a/nixos/tests/os-prober.nix b/nixos/tests/os-prober.nix index 1c89cf8c1c677..8f3e2494047c3 100644 --- a/nixos/tests/os-prober.nix +++ b/nixos/tests/os-prober.nix @@ -1,7 +1,7 @@ import ./make-test-python.nix ({pkgs, lib, ...}: let # A filesystem image with a (presumably) bootable debian - debianImage = pkgs.vmTools.diskImageFuns.debian9i386 { + debianImage = pkgs.vmTools.diskImageFuns.debian11i386 { # os-prober cannot detect systems installed on disks without a partition table # so we create the disk ourselves createRootFS = with pkgs; '' diff --git a/nixos/tests/pgadmin4-standalone.nix b/nixos/tests/pgadmin4-standalone.nix index 442570c5306be..5aa17fcb5bb9d 100644 --- a/nixos/tests/pgadmin4-standalone.nix +++ b/nixos/tests/pgadmin4-standalone.nix @@ -1,5 +1,5 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: - # This is seperate from pgadmin4 since we don't want both running at once + # This is separate from pgadmin4 since we don't want both running at once { name = "pgadmin4-standalone"; diff --git a/nixos/tests/pgadmin4.nix b/nixos/tests/pgadmin4.nix index bec2554a3f041..2a2b5aaa2841d 100644 --- a/nixos/tests/pgadmin4.nix +++ b/nixos/tests/pgadmin4.nix @@ -106,7 +106,7 @@ import ./make-test-python.nix ({ pkgs, lib, buildDeps ? [ ], pythonEnv ? [ ], .. && sed -i 's|driver_local.maximize_window()||' web/regression/runtests.py" ) - # Don't bother to test LDAP or kerberos authentification + # Don't bother to test LDAP or kerberos authentication with subtest("run browser test"): machine.succeed( 'cd ${pgadmin4SrcDir}/pgadmin4-${pkgs.pgadmin4.version}/web \ diff --git a/nixos/tests/postgresql.nix b/nixos/tests/postgresql.nix index 7864f5d6ff32c..7e0a82c388288 100644 --- a/nixos/tests/postgresql.nix +++ b/nixos/tests/postgresql.nix @@ -130,8 +130,97 @@ let ''; }; + + mk-ensure-clauses-test = postgresql-name: postgresql-package: makeTest { + name = postgresql-name; + meta = with pkgs.lib.maintainers; { + maintainers = [ zagy ]; + }; + + machine = {...}: + { + services.postgresql = { + enable = true; + package = postgresql-package; + ensureUsers = [ + { + name = "all-clauses"; + ensureClauses = { + superuser = true; + createdb = true; + createrole = true; + "inherit" = true; + login = true; + replication = true; + bypassrls = true; + }; + } + { + name = "default-clauses"; + } + ]; + }; + }; + + testScript = let + getClausesQuery = user: pkgs.lib.concatStringsSep " " + [ + "SELECT row_to_json(row)" + "FROM (" + "SELECT" + "rolsuper," + "rolinherit," + "rolcreaterole," + "rolcreatedb," + "rolcanlogin," + "rolreplication," + "rolbypassrls" + "FROM pg_roles" + "WHERE rolname = '${user}'" + ") row;" + ]; + in '' + import json + machine.start() + machine.wait_for_unit("postgresql") + + with subtest("All user permissions are set according to the ensureClauses attr"): + clauses = json.loads( + machine.succeed( + "sudo -u postgres psql -tc \"${getClausesQuery "all-clauses"}\"" + ) + ) + print(clauses) + assert clauses['rolsuper'], 'expected user with clauses to have superuser clause' + assert clauses['rolinherit'], 'expected user with clauses to have inherit clause' + assert clauses['rolcreaterole'], 'expected user with clauses to have create role clause' + assert clauses['rolcreatedb'], 'expected user with clauses to have create db clause' + assert clauses['rolcanlogin'], 'expected user with clauses to have login clause' + assert clauses['rolreplication'], 'expected user with clauses to have replication clause' + assert clauses['rolbypassrls'], 'expected user with clauses to have bypassrls clause' + + with subtest("All user permissions default when ensureClauses is not provided"): + clauses = json.loads( + machine.succeed( + "sudo -u postgres psql -tc \"${getClausesQuery "default-clauses"}\"" + ) + ) + assert not clauses['rolsuper'], 'expected user with no clauses set to have default superuser clause' + assert clauses['rolinherit'], 'expected user with no clauses set to have default inherit clause' + assert not clauses['rolcreaterole'], 'expected user with no clauses set to have default create role clause' + assert not clauses['rolcreatedb'], 'expected user with no clauses set to have default create db clause' + assert clauses['rolcanlogin'], 'expected user with no clauses set to have default login clause' + assert not clauses['rolreplication'], 'expected user with no clauses set to have default replication clause' + assert not clauses['rolbypassrls'], 'expected user with no clauses set to have default bypassrls clause' + + machine.shutdown() + ''; + }; in - (mapAttrs' (name: package: { inherit name; value=make-postgresql-test name package false;}) postgresql-versions) // { + concatMapAttrs (name: package: { + ${name} = make-postgresql-test name package false; + ${name + "-clauses"} = mk-ensure-clauses-test name package; + }) postgresql-versions + // { postgresql_11-backup-all = make-postgresql-test "postgresql_11-backup-all" postgresql-versions.postgresql_11 true; } - diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 7264bd5a498aa..5f50a3f87d5d2 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -1172,6 +1172,25 @@ let ''; }; + statsd = { + exporterConfig = { + enable = true; + }; + exporterTest = '' + wait_for_unit("prometheus-statsd-exporter.service") + wait_for_open_port(9102) + succeed("curl http://localhost:9102/metrics | grep 'statsd_exporter_build_info{'") + succeed( + "echo 'test.udp:1|c' > /dev/udp/localhost/9125", + "curl http://localhost:9102/metrics | grep 'test_udp 1'", + ) + succeed( + "echo 'test.tcp:1|c' > /dev/tcp/localhost/9125", + "curl http://localhost:9102/metrics | grep 'test_tcp 1'", + ) + ''; + }; + surfboard = { exporterConfig = { enable = true; diff --git a/nixos/tests/sourcehut.nix b/nixos/tests/sourcehut.nix index d52fbddd20f39..9caa1bcd98f50 100644 --- a/nixos/tests/sourcehut.nix +++ b/nixos/tests/sourcehut.nix @@ -35,7 +35,7 @@ let }; security.sudo.wheelNeedsPassword = false; - nix.trustedUsers = [ "root" "build" ]; + nix.settings.trusted-users = [ "root" "build" ]; documentation.nixos.enable = false; # builds.sr.ht-image-specific network settings diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix index 87bea66334831..c0e1d0585b931 100644 --- a/nixos/tests/vaultwarden.nix +++ b/nixos/tests/vaultwarden.nix @@ -164,7 +164,7 @@ let with subtest("configure the cli"): client.succeed("bw --nointeraction config server http://server") - with subtest("can't login to nonexistant account"): + with subtest("can't login to nonexistent account"): client.fail( "bw --nointeraction --raw login ${userEmail} ${userPassword}" ) |