diff options
Diffstat (limited to 'nixos/tests')
-rw-r--r-- | nixos/tests/all-tests.nix | 4 | ||||
-rw-r--r-- | nixos/tests/flood.nix | 27 | ||||
-rw-r--r-- | nixos/tests/nextcloud/basic.nix | 104 | ||||
-rw-r--r-- | nixos/tests/nextcloud/default.nix | 121 | ||||
-rw-r--r-- | nixos/tests/nextcloud/with-mysql-and-memcached.nix | 58 | ||||
-rw-r--r-- | nixos/tests/nextcloud/with-objectstore.nix | 96 | ||||
-rw-r--r-- | nixos/tests/nextcloud/with-postgresql-and-redis.nix | 84 | ||||
-rw-r--r-- | nixos/tests/odoo.nix | 12 | ||||
-rw-r--r-- | nixos/tests/quickwit.nix | 72 | ||||
-rw-r--r-- | nixos/tests/searx.nix | 182 | ||||
-rw-r--r-- | nixos/tests/snapper.nix | 5 | ||||
-rw-r--r-- | nixos/tests/vaultwarden.nix | 15 |
12 files changed, 479 insertions, 301 deletions
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 746b29fd27258..8d5b865891e4a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -328,6 +328,7 @@ in { firewall-nftables = handleTest ./firewall.nix { nftables = true; }; fish = handleTest ./fish.nix {}; flannel = handleTestOn ["x86_64-linux"] ./flannel.nix {}; + flood = handleTest ./flood.nix {}; floorp = handleTest ./firefox.nix { firefoxPackage = pkgs.floorp; }; fluentd = handleTest ./fluentd.nix {}; fluidd = handleTest ./fluidd.nix {}; @@ -413,6 +414,7 @@ in { pyload = handleTest ./pyload.nix {}; oci-containers = handleTestOn ["aarch64-linux" "x86_64-linux"] ./oci-containers.nix {}; odoo = handleTest ./odoo.nix {}; + odoo16 = handleTest ./odoo.nix { package = pkgs.odoo16; }; odoo15 = handleTest ./odoo.nix { package = pkgs.odoo15; }; # 9pnet_virtio used to mount /nix partition doesn't support # hibernation. This test happens to work on x86_64-linux but @@ -833,7 +835,7 @@ in { scrutiny = handleTest ./scrutiny.nix {}; sddm = handleTest ./sddm.nix {}; seafile = handleTest ./seafile.nix {}; - searx = handleTest ./searx.nix {}; + searx = runTest ./searx.nix; seatd = handleTest ./seatd.nix {}; service-runner = handleTest ./service-runner.nix {}; sftpgo = runTest ./sftpgo.nix; diff --git a/nixos/tests/flood.nix b/nixos/tests/flood.nix new file mode 100644 index 0000000000000..075d37e62835f --- /dev/null +++ b/nixos/tests/flood.nix @@ -0,0 +1,27 @@ +import ./make-test-python.nix ({ pkgs, ... }: +let + port = 3001; +in +{ + name = "flood"; + meta = { + maintainers = with pkgs.lib.maintainers; [ thiagokokada ]; + }; + + nodes.machine = { pkgs, ... }: { + services.flood = { + inherit port; + enable = true; + openFirewall = true; + extraArgs = [ "--baseuri=/" ]; + }; + }; + + testScript = /* python */ '' + machine.start() + machine.wait_for_unit("flood.service") + machine.wait_for_open_port(${toString port}) + + machine.succeed("curl --fail http://localhost:${toString port}") + ''; +}) diff --git a/nixos/tests/nextcloud/basic.nix b/nixos/tests/nextcloud/basic.nix index 428fe0aa10db9..2a32f2b4d1992 100644 --- a/nixos/tests/nextcloud/basic.nix +++ b/nixos/tests/nextcloud/basic.nix @@ -1,27 +1,27 @@ -args@{ pkgs, nextcloudVersion ? 22, ... }: +{ name, pkgs, testBase, system,... }: -(import ../make-test-python.nix ({ pkgs, ...}: let - adminpass = "notproduction"; - adminuser = "root"; -in { - name = "nextcloud-basic"; +with import ../../lib/testing-python.nix { inherit system pkgs; }; +runTest ({ config, ... }: { + inherit name; meta = with pkgs.lib.maintainers; { - maintainers = [ globin eqyiel ]; + maintainers = [ globin eqyiel ma27 ]; }; - nodes = rec { + imports = [ testBase ]; + + nodes = { # The only thing the client needs to do is download a file. client = { ... }: { services.davfs2.enable = true; systemd.tmpfiles.settings.nextcloud = { "/tmp/davfs2-secrets"."f+" = { mode = "0600"; - argument = "http://nextcloud/remote.php/dav/files/${adminuser} ${adminuser} ${adminpass}"; + argument = "http://nextcloud/remote.php/dav/files/${config.adminuser} ${config.adminuser} ${config.adminpass}"; }; }; virtualisation.fileSystems = { "/mnt/dav" = { - device = "http://nextcloud/remote.php/dav/files/${adminuser}"; + device = "http://nextcloud/remote.php/dav/files/${config.adminuser}"; fsType = "davfs"; options = let davfs2Conf = (pkgs.writeText "davfs2.conf" "secrets /tmp/davfs2-secrets"); @@ -30,11 +30,7 @@ in { }; }; - nextcloud = { config, pkgs, ... }: let - cfg = config; - in { - networking.firewall.allowedTCPPorts = [ 80 ]; - + nextcloud = { config, pkgs, ... }: { systemd.tmpfiles.rules = [ "d /var/lib/nextcloud-data 0750 nextcloud nginx - -" ]; @@ -42,14 +38,7 @@ in { services.nextcloud = { enable = true; datadir = "/var/lib/nextcloud-data"; - hostName = "nextcloud"; - database.createLocally = true; - config = { - # Don't inherit adminuser since "root" is supposed to be the default - adminpassFile = "${pkgs.writeText "adminpass" adminpass}"; # Don't try this at home! - dbtableprefix = "nixos_"; - }; - package = pkgs.${"nextcloud" + (toString nextcloudVersion)}; + config.dbtableprefix = "nixos_"; autoUpdateApps = { enable = true; startAt = "20:00"; @@ -57,64 +46,31 @@ in { phpExtraExtensions = all: [ all.bz2 ]; }; - environment.systemPackages = [ cfg.services.nextcloud.occ ]; + specialisation.withoutMagick.configuration = { + services.nextcloud.enableImagemagick = false; + }; }; - - nextcloudWithoutMagick = args@{ config, pkgs, lib, ... }: - lib.mkMerge - [ (nextcloud args) - { services.nextcloud.enableImagemagick = false; } ]; }; - testScript = { nodes, ... }: let - withRcloneEnv = pkgs.writeScript "with-rclone-env" '' - #!${pkgs.runtimeShell} - export RCLONE_CONFIG_NEXTCLOUD_TYPE=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})" - "''${@}" - ''; - copySharedFile = pkgs.writeScript "copy-shared-file" '' - #!${pkgs.runtimeShell} - echo 'hi' | ${withRcloneEnv} ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file - ''; - - diffSharedFile = pkgs.writeScript "diff-shared-file" '' - #!${pkgs.runtimeShell} - diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) - ''; - + test-helpers.extraTests = { nodes, ... }: let findInClosure = what: drv: pkgs.runCommand "find-in-closure" { exportReferencesGraph = [ "graph" drv ]; inherit what; } '' test -e graph grep "$what" graph >$out || true ''; - nextcloudUsesImagick = findInClosure "imagick" nodes.nextcloud.system.build.vm; - nextcloudWithoutDoesntUseIt = findInClosure "imagick" nodes.nextcloudWithoutMagick.system.build.vm; + nexcloudWithImagick = findInClosure "imagick" nodes.nextcloud.system.build.vm; + nextcloudWithoutImagick = findInClosure "imagick" nodes.nextcloud.specialisation.withoutMagick.configuration.system.build.vm; in '' - assert open("${nextcloudUsesImagick}").read() != "" - assert open("${nextcloudWithoutDoesntUseIt}").read() == "" + with subtest("File is in proper nextcloud home"): + nextcloud.succeed("test -f ${nodes.nextcloud.services.nextcloud.datadir}/data/root/files/test-shared-file") + + with subtest("Closure checks"): + assert open("${nexcloudWithImagick}").read() != "" + assert open("${nextcloudWithoutImagick}").read() == "" + + with subtest("Davfs2"): + assert "hi" in client.succeed("cat /mnt/dav/test-shared-file") - nextcloud.start() - client.start() - nextcloud.wait_for_unit("multi-user.target") - # This is just to ensure the nextcloud-occ program is working - nextcloud.succeed("nextcloud-occ status") - nextcloud.succeed("curl -sSf http://nextcloud/login") - # Ensure that no OpenSSL 1.1 is used. - nextcloud.succeed( - "${nodes.nextcloud.services.phpfpm.pools.nextcloud.phpPackage}/bin/php -i | grep 'OpenSSL Library Version' | awk -F'=>' '{ print $2 }' | awk '{ print $2 }' | grep -v 1.1" - ) - nextcloud.succeed( - "${withRcloneEnv} ${copySharedFile}" - ) - client.wait_for_unit("multi-user.target") - nextcloud.succeed("test -f /var/lib/nextcloud-data/data/root/files/test-shared-file") - client.succeed( - "${withRcloneEnv} ${diffSharedFile}" - ) - assert "hi" in client.succeed("cat /mnt/dav/test-shared-file") - nextcloud.succeed("grep -vE '^HBEGIN:oc_encryption_module' /var/lib/nextcloud-data/data/root/files/test-shared-file") + with subtest("Ensure SSE is disabled by default"): + nextcloud.succeed("grep -vE '^HBEGIN:oc_encryption_module' /var/lib/nextcloud-data/data/root/files/test-shared-file") ''; -})) args +}) diff --git a/nixos/tests/nextcloud/default.nix b/nixos/tests/nextcloud/default.nix index d024adffd9f06..33aa227d2b032 100644 --- a/nixos/tests/nextcloud/default.nix +++ b/nixos/tests/nextcloud/default.nix @@ -5,21 +5,108 @@ with pkgs.lib; -foldl - (matrix: ver: matrix // { - "basic${toString ver}" = import ./basic.nix { inherit system pkgs; nextcloudVersion = ver; }; - "with-postgresql-and-redis${toString ver}" = import ./with-postgresql-and-redis.nix { - inherit system pkgs; - nextcloudVersion = ver; - }; - "with-mysql-and-memcached${toString ver}" = import ./with-mysql-and-memcached.nix { - inherit system pkgs; - nextcloudVersion = ver; - }; - "with-declarative-redis-and-secrets${toString ver}" = import ./with-declarative-redis-and-secrets.nix { - inherit system pkgs; - nextcloudVersion = ver; +let + baseModule = { config, ... }: { + imports = [ + { + options.test-helpers = { + rclone = mkOption { type = types.str; }; + upload-sample = mkOption { type = types.str; }; + check-sample = mkOption { type = types.str; }; + init = mkOption { type = types.str; default = ""; }; + extraTests = mkOption { type = types.either types.str (types.functionTo types.str); default = ""; }; + }; + options.adminuser = mkOption { type = types.str; }; + options.adminpass = mkOption { type = types.str; }; + } + ]; + + adminuser = "root"; + adminpass = "hunter2"; + + test-helpers.rclone = "${pkgs.writeShellScript "rclone" '' + set -euo pipefail + export PATH="${pkgs.rclone}/bin:$PATH" + export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav + export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/dav/files/${config.adminuser}" + export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud" + export RCLONE_CONFIG_NEXTCLOUD_USER="${config.adminuser}" + export RCLONE_CONFIG_NEXTCLOUD_PASS="$(rclone obscure ${config.adminpass})" + exec "$@" + ''}"; + test-helpers.upload-sample = "${pkgs.writeShellScript "rclone-upload" '' + <<<'hi' rclone rcat nextcloud:test-shared-file + ''}"; + test-helpers.check-sample = "${pkgs.writeShellScript "check-sample" '' + set -e + diff <(echo 'hi') <(rclone cat nextcloud:test-shared-file) + ''}"; + + nodes = { + client = { ... }: {}; + nextcloud = { + networking.firewall.allowedTCPPorts = [ 80 ]; + services.nextcloud = { + enable = true; + hostName = "nextcloud"; + https = false; + database.createLocally = true; + config = { + adminpassFile = "${pkgs.writeText "adminpass" config.adminpass}"; # Don't try this at home! + }; + }; + }; }; - }) -{ } - [ 27 28 29 ] + + testScript = args@{ nodes, ... }: let + inherit (config) test-helpers; + in mkBefore '' + nextcloud.start() + client.start() + nextcloud.wait_for_unit("multi-user.target") + + ${test-helpers.init} + + with subtest("Ensure nextcloud-occ is working"): + nextcloud.succeed("nextcloud-occ status") + nextcloud.succeed("curl -sSf http://nextcloud/login") + + with subtest("Upload/Download test"): + nextcloud.succeed( + "${test-helpers.rclone} ${test-helpers.upload-sample}" + ) + client.wait_for_unit("multi-user.target") + client.succeed( + "${test-helpers.rclone} ${test-helpers.check-sample}" + ) + + ${if builtins.isFunction test-helpers.extraTests then test-helpers.extraTests args else test-helpers.extraTests} + ''; + }; + + genTests = version: + let + testBase.imports = [ + baseModule + { + nodes.nextcloud = { pkgs, ... }: { + services.nextcloud.package = pkgs.${"nextcloud${toString version}"}; + }; + } + ]; + + callNextcloudTest = path: + let + name = "${removeSuffix ".nix" (baseNameOf path)}${toString version}"; + in nameValuePair name (import path { + inherit system pkgs testBase; + name = "nextcloud-${name}"; + }); + in map callNextcloudTest [ + ./basic.nix + ./with-mysql-and-memcached.nix + ./with-postgresql-and-redis.nix + ./with-objectstore.nix + ]; +in +listToAttrs (concatMap genTests [ 27 28 29 ]) diff --git a/nixos/tests/nextcloud/with-mysql-and-memcached.nix b/nixos/tests/nextcloud/with-mysql-and-memcached.nix index 035a7fdcb0c80..07a3e56fae4af 100644 --- a/nixos/tests/nextcloud/with-mysql-and-memcached.nix +++ b/nixos/tests/nextcloud/with-mysql-and-memcached.nix @@ -1,79 +1,37 @@ -args@{ pkgs, nextcloudVersion ? 22, ... }: +{ pkgs, testBase, system, ... }: -(import ../make-test-python.nix ({ pkgs, ...}: let - adminpass = "hunter2"; - adminuser = "root"; -in { +with import ../../lib/testing-python.nix { inherit system pkgs; }; +runTest ({ config, ... }: { name = "nextcloud-with-mysql-and-memcached"; meta = with pkgs.lib.maintainers; { maintainers = [ eqyiel ]; }; - nodes = { - # The only thing the client needs to do is download a file. - client = { ... }: {}; + imports = [ testBase ]; + nodes = { nextcloud = { config, pkgs, ... }: { - networking.firewall.allowedTCPPorts = [ 80 ]; - services.nextcloud = { - enable = true; - hostName = "nextcloud"; - https = true; - package = pkgs.${"nextcloud" + (toString nextcloudVersion)}; caching = { apcu = true; redis = false; memcached = true; }; - database.createLocally = true; - config = { - dbtype = "mysql"; - # Don't inherit adminuser since "root" is supposed to be the default - adminpassFile = "${pkgs.writeText "adminpass" adminpass}"; # Don't try this at home! - }; + config.dbtype = "mysql"; }; services.memcached.enable = true; }; }; - testScript = let + test-helpers.init = let configureMemcached = pkgs.writeScript "configure-memcached" '' - #!${pkgs.runtimeShell} nextcloud-occ config:system:set memcached_servers 0 0 --value 127.0.0.1 --type string nextcloud-occ config:system:set memcached_servers 0 1 --value 11211 --type integer nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\APCu' --type string nextcloud-occ config:system:set memcache.distributed --value '\OC\Memcache\Memcached' --type string ''; - withRcloneEnv = pkgs.writeScript "with-rclone-env" '' - #!${pkgs.runtimeShell} - export RCLONE_CONFIG_NEXTCLOUD_TYPE=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})" - ''; - copySharedFile = pkgs.writeScript "copy-shared-file" '' - #!${pkgs.runtimeShell} - echo 'hi' | ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file - ''; - - diffSharedFile = pkgs.writeScript "diff-shared-file" '' - #!${pkgs.runtimeShell} - diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) - ''; in '' - start_all() - nextcloud.wait_for_unit("multi-user.target") nextcloud.succeed("${configureMemcached}") - nextcloud.succeed("curl -sSf http://nextcloud/login") - nextcloud.succeed( - "${withRcloneEnv} ${copySharedFile}" - ) - client.wait_for_unit("multi-user.target") - client.succeed( - "${withRcloneEnv} ${diffSharedFile}" - ) ''; -})) args +}) diff --git a/nixos/tests/nextcloud/with-objectstore.nix b/nixos/tests/nextcloud/with-objectstore.nix new file mode 100644 index 0000000000000..fc26760b8babd --- /dev/null +++ b/nixos/tests/nextcloud/with-objectstore.nix @@ -0,0 +1,96 @@ +{ name, pkgs, testBase, system, ... }: + +with import ../../lib/testing-python.nix { inherit system pkgs; }; +runTest ({ config, lib, ... }: let + accessKey = "BKIKJAA5BMMU2RHO6IBB"; + secretKey = "V7f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12"; + + rootCredentialsFile = pkgs.writeText "minio-credentials-full" '' + MINIO_ROOT_USER=${accessKey} + MINIO_ROOT_PASSWORD=${secretKey} + ''; +in { + inherit name; + meta = with pkgs.lib.maintainers; { + maintainers = [ onny ma27 ]; + }; + + imports = [ testBase ]; + + nodes = { + nextcloud = { config, pkgs, ... }: { + networking.firewall.allowedTCPPorts = [ 9000 ]; + environment.systemPackages = [ pkgs.minio-client ]; + + services.nextcloud.config.objectstore.s3 = { + enable = true; + bucket = "nextcloud"; + autocreate = true; + key = accessKey; + secretFile = "${pkgs.writeText "secretKey" secretKey}"; + hostname = "nextcloud"; + useSsl = false; + port = 9000; + usePathStyle = true; + region = "us-east-1"; + }; + + services.minio = { + enable = true; + listenAddress = "0.0.0.0:9000"; + consoleAddress = "0.0.0.0:9001"; + inherit rootCredentialsFile; + }; + }; + }; + + test-helpers.init = '' + nextcloud.wait_for_open_port(9000) + ''; + + test-helpers.extraTests = { nodes, ... }: '' + with subtest("File is not on the filesystem"): + nextcloud.succeed("test ! -e ${nodes.nextcloud.services.nextcloud.home}/data/root/files/test-shared-file") + + with subtest("Check if file is in S3"): + nextcloud.succeed( + "mc config host add minio http://localhost:9000 ${accessKey} ${secretKey} --api s3v4" + ) + files = nextcloud.succeed('mc ls minio/nextcloud|sort').strip().split('\n') + + # Cannot assert an exact number here, nc27 writes more stuff initially into S3. + # For now let's assume it's always the most recently added file. + assert len(files) > 0, f""" + Expected to have at least one object in minio/nextcloud. But `mc ls` gave output: + + '{files}' + """ + + import re + ptrn = re.compile("^\[[A-Z0-9 :-]+\] +(?P<details>[A-Za-z0-9 :]+)$") + match = ptrn.match(files[-1].strip()) + assert match, "Cannot match mc client output!" + size, type_, file = tuple(match.group('details').split(' ')) + + assert size == "3B", f""" + Expected size of uploaded file to be 3 bytes, got {size} + """ + + assert type_ == 'STANDARD', f""" + Expected type of bucket entry to be a file, i.e. 'STANDARD'. Got {type_} + """ + + assert file.startswith('urn:oid'), """ + Expected filename to start with 'urn:oid', instead got '{file}. + """ + + with subtest("Test download from S3"): + client.succeed( + "env AWS_ACCESS_KEY_ID=${accessKey} AWS_SECRET_ACCESS_KEY=${secretKey} " + + f"${lib.getExe pkgs.awscli2} s3 cp s3://nextcloud/{file} test --endpoint-url http://nextcloud:9000 " + + "--region us-east-1" + ) + + client.succeed("test hi = $(cat test)") + ''; +}) diff --git a/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixos/tests/nextcloud/with-postgresql-and-redis.nix index 06afc589403dd..24c17f70932d3 100644 --- a/nixos/tests/nextcloud/with-postgresql-and-redis.nix +++ b/nixos/tests/nextcloud/with-postgresql-and-redis.nix @@ -1,45 +1,30 @@ -args@{ pkgs, nextcloudVersion ? 22, ... }: +{ name, pkgs, testBase, system, ... }: -(import ../make-test-python.nix ({ pkgs, ...}: let - adminpass = "hunter2"; - adminuser = "custom-admin-username"; -in { - name = "nextcloud-with-postgresql-and-redis"; +with import ../../lib/testing-python.nix { inherit system pkgs; }; +runTest ({ config, ... }: { + inherit name; meta = with pkgs.lib.maintainers; { - maintainers = [ eqyiel ]; + maintainers = [ eqyiel ma27 ]; }; - nodes = { - # The only thing the client needs to do is download a file. - client = { ... }: {}; + imports = [ testBase ]; + nodes = { nextcloud = { config, pkgs, lib, ... }: { - networking.firewall.allowedTCPPorts = [ 80 ]; - services.nextcloud = { - enable = true; - hostName = "nextcloud"; - package = pkgs.${"nextcloud" + (toString nextcloudVersion)}; caching = { apcu = false; redis = true; memcached = false; }; - database.createLocally = true; - config = { - dbtype = "pgsql"; - inherit adminuser; - adminpassFile = toString (pkgs.writeText "admin-pass-file" '' - ${adminpass} - ''); - }; + config.dbtype = "pgsql"; notify_push = { enable = true; logLevel = "debug"; }; extraAppsEnable = true; - extraApps = { - inherit (pkgs."nextcloud${lib.versions.major config.services.nextcloud.package.version}Packages".apps) notify_push notes; + extraApps = with config.services.nextcloud.package.packages.apps; { + inherit notify_push notes; }; settings.trusted_proxies = [ "::1" ]; }; @@ -49,50 +34,27 @@ in { }; }; - testScript = let + test-helpers.init = let configureRedis = pkgs.writeScript "configure-redis" '' - #!${pkgs.runtimeShell} nextcloud-occ config:system:set redis 'host' --value 'localhost' --type string nextcloud-occ config:system:set redis 'port' --value 6379 --type integer nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\Redis' --type string nextcloud-occ config:system:set memcache.locking --value '\OC\Memcache\Redis' --type string ''; - withRcloneEnv = pkgs.writeScript "with-rclone-env" '' - #!${pkgs.runtimeShell} - export RCLONE_CONFIG_NEXTCLOUD_TYPE=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})" - "''${@}" - ''; - copySharedFile = pkgs.writeScript "copy-shared-file" '' - #!${pkgs.runtimeShell} - echo 'hi' | ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file - ''; - - diffSharedFile = pkgs.writeScript "diff-shared-file" '' - #!${pkgs.runtimeShell} - diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) - ''; in '' - start_all() - nextcloud.wait_for_unit("multi-user.target") nextcloud.succeed("${configureRedis}") - nextcloud.succeed("curl -sSf http://nextcloud/login") - nextcloud.succeed( - "${withRcloneEnv} ${copySharedFile}" - ) - client.wait_for_unit("multi-user.target") - client.execute("${pkgs.lib.getExe pkgs.nextcloud-notify_push.passthru.test_client} http://nextcloud ${adminuser} ${adminpass} >&2 &") - client.succeed( - "${withRcloneEnv} ${diffSharedFile}" - ) - nextcloud.wait_until_succeeds("journalctl -u nextcloud-notify_push | grep -q \"Sending ping to ${adminuser}\"") + ''; + + test-helpers.extraTests = '' + with subtest("notify-push"): + client.execute("${pkgs.lib.getExe pkgs.nextcloud-notify_push.passthru.test_client} http://nextcloud ${config.adminuser} ${config.adminpass} >&2 &") + nextcloud.wait_until_succeeds("journalctl -u nextcloud-notify_push | grep -q \"Sending ping to ${config.adminuser}\"") - # redis cache should not be empty - nextcloud.fail('test "[]" = "$(redis-cli --json KEYS "*")"') + with subtest("Redis is used for caching"): + # redis cache should not be empty + nextcloud.fail('test "[]" = "$(redis-cli --json KEYS "*")"') - nextcloud.fail("curl -f http://nextcloud/nix-apps/notes/lib/AppInfo/Application.php") + with subtest("No code is returned when requesting PHP files (regression test)"): + nextcloud.fail("curl -f http://nextcloud/nix-apps/notes/lib/AppInfo/Application.php") ''; -})) args +}) diff --git a/nixos/tests/odoo.nix b/nixos/tests/odoo.nix index 00ae4a2137d10..45ec7b7d7a6b7 100644 --- a/nixos/tests/odoo.nix +++ b/nixos/tests/odoo.nix @@ -14,6 +14,18 @@ import ./make-test-python.nix ({ pkgs, lib, package ? pkgs.odoo, ...} : { package = package; domain = "localhost"; }; + + # odoo does not automatically initialize its database, + # even if passing what _should_ be the equivalent of these options: + # settings = { + # options = { + # database = "odoo"; + # init = "base"; + # }; + # }; + systemd.services.odoo.preStart = '' + HOME=$STATE_DIRECTORY ${package}/bin/odoo -d odoo -i base --stop-after-init --without-demo all + ''; }; }; diff --git a/nixos/tests/quickwit.nix b/nixos/tests/quickwit.nix index 145959f7d3f51..7e617c63d7973 100644 --- a/nixos/tests/quickwit.nix +++ b/nixos/tests/quickwit.nix @@ -1,5 +1,54 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: +let + # Define an example Quickwit index schema, + # and some `exampleDocs` below, to test if ingesting + # and querying works as expected. + index_yaml = '' + version: 0.7 + index_id: example_server_logs + doc_mapping: + mode: dynamic + field_mappings: + - name: datetime + type: datetime + fast: true + input_formats: + - iso8601 + output_format: iso8601 + fast_precision: seconds + fast: true + - name: git + type: text + tokenizer: raw + - name: hostname + type: text + tokenizer: raw + - name: level + type: text + tokenizer: raw + - name: message + type: text + - name: location + type: text + - name: source + type: text + timestamp_field: datetime + + search_settings: + default_search_fields: [message] + + indexing_settings: + commit_timeout_secs: 10 + ''; + + exampleDocs = '' + {"datetime":"2024-05-03T02:36:41.017674444Z","git":"e6e1f087ce12065e44ed3b87b50784e6f9bcc2f9","hostname":"machine-1","level":"Info","message":"Processing request done","location":"path/to/server.c:6442:32","source":""} + {"datetime":"2024-05-04T02:36:41.017674444Z","git":"e6e1f087ce12065e44ed3b87b50784e6f9bcc2f9","hostname":"machine-1","level":"Info","message":"Got exception processing request: HTTP 404","location":"path/to/server.c:6444:32","source":""} + {"datetime":"2024-05-05T02:36:41.017674444Z","git":"e6e1f087ce12065e44ed3b87b50784e6f9bcc2f9","hostname":"machine-1","level":"Info","message":"Got exception processing request: HTTP 404","location":"path/to/server.c:6444:32","source":""} + {"datetime":"2024-05-06T02:36:41.017674444Z","git":"e6e1f087ce12065e44ed3b87b50784e6f9bcc2f9","hostname":"machine-2","level":"Info","message":"Got exception processing request: HTTP 404","location":"path/to/server.c:6444:32","source":""} + ''; +in { name = "quickwit"; meta.maintainers = [ pkgs.lib.maintainers.happysalada ]; @@ -24,6 +73,29 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: "journalctl -o cat -u quickwit.service | grep 'transitioned to ready state'" ) + with subtest("verify UI installed"): + machine.succeed("curl -sSf http://127.0.0.1:7280/ui/") + + with subtest("injest and query data"): + import json + + # Test CLI ingestion + print(machine.succeed('${pkgs.quickwit}/bin/quickwit index create --index-config ${pkgs.writeText "index.yaml" index_yaml}')) + # Important to use `--wait`, otherwise the queries below race with index processing. + print(machine.succeed('${pkgs.quickwit}/bin/quickwit index ingest --index example_server_logs --input-path ${pkgs.writeText "exampleDocs.json" exampleDocs} --wait')) + + # Test CLI query + cli_query_output = machine.succeed('${pkgs.quickwit}/bin/quickwit index search --index example_server_logs --query "exception"') + print(cli_query_output) + + # Assert query result is as expected. + num_hits = len(json.loads(cli_query_output)["hits"]) + assert num_hits == 3, f"cli_query_output contains unexpected number of results: {num_hits}" + + # Test API query + api_query_output = machine.succeed('curl --fail http://127.0.0.1:7280/api/v1/example_server_logs/search?query=exception') + print(api_query_output) + quickwit.log(quickwit.succeed( "systemd-analyze security quickwit.service | grep -v '✓'" )) diff --git a/nixos/tests/searx.nix b/nixos/tests/searx.nix index 02a88f690db78..0008424f068b2 100644 --- a/nixos/tests/searx.nix +++ b/nixos/tests/searx.nix @@ -1,4 +1,4 @@ -import ./make-test-python.nix ({ pkgs, ...} : +{ pkgs, ... }: { name = "searx"; @@ -7,108 +7,108 @@ import ./make-test-python.nix ({ pkgs, ...} : }; # basic setup: searx running the built-in webserver - nodes.base = { ... }: { - imports = [ ../modules/profiles/minimal.nix ]; - - services.searx = { - enable = true; - environmentFile = pkgs.writeText "secrets" '' - WOLFRAM_API_KEY = sometoken - SEARX_SECRET_KEY = somesecret - ''; + nodes.base = + { ... }: + { + services.searx = { + enable = true; + environmentFile = pkgs.writeText "secrets" '' + WOLFRAM_API_KEY = sometoken + SEARX_SECRET_KEY = somesecret + ''; - settings.server = - { port = "8080"; + settings.server = { + port = "8080"; bind_address = "0.0.0.0"; secret_key = "@SEARX_SECRET_KEY@"; }; - settings.engines = [ - { name = "wolframalpha"; - api_key = "@WOLFRAM_API_KEY@"; - engine = "wolframalpha_api"; - } - { name = "startpage"; - shortcut = "start"; - } - ]; - }; + settings.engines = [ + { + name = "wolframalpha"; + api_key = "@WOLFRAM_API_KEY@"; + engine = "wolframalpha_api"; + } + { + name = "startpage"; + shortcut = "start"; + } + ]; + }; - }; + }; # fancy setup: run in uWSGI and use nginx as proxy - nodes.fancy = { config, ... }: { - imports = [ ../modules/profiles/minimal.nix ]; - - services.searx = { - enable = true; - # searx refuses to run if unchanged - settings.server.secret_key = "somesecret"; - - runInUwsgi = true; - uwsgiConfig = { - # serve using the uwsgi protocol - socket = "/run/searx/uwsgi.sock"; - chmod-socket = "660"; - - # use /searx as url "mountpoint" - mount = "/searx=searx.webapp:application"; - module = ""; - manage-script-name = true; + nodes.fancy = + { config, ... }: + { + services.searx = { + enable = true; + # searx refuses to run if unchanged + settings.server.secret_key = "somesecret"; + + runInUwsgi = true; + uwsgiConfig = { + # serve using the uwsgi protocol + socket = "/run/searx/uwsgi.sock"; + chmod-socket = "660"; + + # use /searx as url "mountpoint" + mount = "/searx=searx.webapp:application"; + module = ""; + manage-script-name = true; + }; }; - }; - # use nginx as reverse proxy - services.nginx.enable = true; - services.nginx.virtualHosts.localhost = { - locations."/searx".extraConfig = - '' + # use nginx as reverse proxy + services.nginx.enable = true; + services.nginx.virtualHosts.localhost = { + locations."/searx".extraConfig = '' include ${pkgs.nginx}/conf/uwsgi_params; uwsgi_pass unix:/run/searx/uwsgi.sock; ''; - locations."/searx/static/".alias = "${config.services.searx.package}/share/static/"; - }; - - # allow nginx access to the searx socket - users.users.nginx.extraGroups = [ "searx" ]; - - }; - - testScript = - '' - base.start() - - with subtest("Settings have been merged"): - base.wait_for_unit("searx-init") - base.wait_for_file("/run/searx/settings.yml") - output = base.succeed( - "${pkgs.yq-go}/bin/yq eval" - " '.engines[] | select(.name==\"startpage\") | .shortcut'" - " /run/searx/settings.yml" - ).strip() - assert output == "start", "Settings not merged" + locations."/searx/static/".alias = "${config.services.searx.package}/share/static/"; + }; - with subtest("Environment variables have been substituted"): - base.succeed("grep -q somesecret /run/searx/settings.yml") - base.succeed("grep -q sometoken /run/searx/settings.yml") - base.copy_from_vm("/run/searx/settings.yml") + # allow nginx access to the searx socket + users.users.nginx.extraGroups = [ "searx" ]; - with subtest("Basic setup is working"): - base.wait_for_open_port(8080) - base.wait_for_unit("searx") - base.succeed( - "${pkgs.curl}/bin/curl --fail http://localhost:8080" - ) - base.shutdown() + }; - with subtest("Nginx+uWSGI setup is working"): - fancy.start() - fancy.wait_for_open_port(80) - fancy.wait_for_unit("uwsgi") - fancy.succeed( - "${pkgs.curl}/bin/curl --fail http://localhost/searx >&2" - ) - fancy.succeed( - "${pkgs.curl}/bin/curl --fail http://localhost/searx/static/themes/simple/js/leaflet.js >&2" - ) - ''; -}) + testScript = '' + base.start() + + with subtest("Settings have been merged"): + base.wait_for_unit("searx-init") + base.wait_for_file("/run/searx/settings.yml") + output = base.succeed( + "${pkgs.yq-go}/bin/yq eval" + " '.engines[] | select(.name==\"startpage\") | .shortcut'" + " /run/searx/settings.yml" + ).strip() + assert output == "start", "Settings not merged" + + with subtest("Environment variables have been substituted"): + base.succeed("grep -q somesecret /run/searx/settings.yml") + base.succeed("grep -q sometoken /run/searx/settings.yml") + base.copy_from_vm("/run/searx/settings.yml") + + with subtest("Basic setup is working"): + base.wait_for_open_port(8080) + base.wait_for_unit("searx") + base.succeed( + "${pkgs.curl}/bin/curl --fail http://localhost:8080" + ) + base.shutdown() + + with subtest("Nginx+uWSGI setup is working"): + fancy.start() + fancy.wait_for_open_port(80) + fancy.wait_for_unit("uwsgi") + fancy.succeed( + "${pkgs.curl}/bin/curl --fail http://localhost/searx >&2" + ) + fancy.succeed( + "${pkgs.curl}/bin/curl --fail http://localhost/searx/static/themes/simple/js/leaflet.js >&2" + ) + ''; +} diff --git a/nixos/tests/snapper.nix b/nixos/tests/snapper.nix index 674523584fdaa..0369419930f15 100644 --- a/nixos/tests/snapper.nix +++ b/nixos/tests/snapper.nix @@ -19,7 +19,9 @@ import ./make-test-python.nix ({ ... }: services.snapper.filters = "/nix"; }; - testScript = '' + testScript = { nodes, ... }: let + inherit (nodes.machine.services.snapper) snapshotRootOnBoot; + in '' machine.succeed("btrfs subvolume create /home/.snapshots") machine.succeed("snapper -c home list") machine.succeed("snapper -c home create --description empty") @@ -31,5 +33,6 @@ import ./make-test-python.nix ({ ... }: machine.succeed("snapper -c home delete 2") machine.succeed("systemctl --wait start snapper-timeline.service") machine.succeed("systemctl --wait start snapper-cleanup.service") + machine.${if snapshotRootOnBoot then "succeed" else "fail"}("systemctl cat snapper-boot.service") ''; }) diff --git a/nixos/tests/vaultwarden.nix b/nixos/tests/vaultwarden.nix index 3aba3f6845fa7..baefa67dbf535 100644 --- a/nixos/tests/vaultwarden.nix +++ b/nixos/tests/vaultwarden.nix @@ -34,7 +34,7 @@ let driver = Firefox(options=options) driver.implicitly_wait(20) - driver.get('http://localhost/#/register') + driver.get('http://localhost:8080/#/register') wait = WebDriverWait(driver, 10) @@ -134,11 +134,11 @@ let dbBackend = backend; config = { rocketAddress = "0.0.0.0"; - rocketPort = 80; + rocketPort = 8080; }; }; - networking.firewall.allowedTCPPorts = [ 80 ]; + networking.firewall.allowedTCPPorts = [ 8080 ]; environment.systemPackages = [ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ]; } @@ -152,10 +152,10 @@ let testScript = if testScript != null then testScript else '' start_all() server.wait_for_unit("vaultwarden.service") - server.wait_for_open_port(80) + server.wait_for_open_port(8080) with subtest("configure the cli"): - client.succeed("bw --nointeraction config server http://server") + client.succeed("bw --nointeraction config server http://server:8080") with subtest("can't login to nonexistent account"): client.fail( @@ -179,6 +179,9 @@ let timeout=60 ) assert password.strip() == "${storedPassword}" + + with subtest("Check systemd unit hardening"): + server.log(server.succeed("systemd-analyze security vaultwarden.service | grep -v ✓")) ''; }); in @@ -193,7 +196,7 @@ builtins.mapAttrs (k: v: makeVaultwardenTest k v) { testScript = '' start_all() server.wait_for_unit("vaultwarden.service") - server.wait_for_open_port(80) + server.wait_for_open_port(8080) with subtest("Set up vaultwarden"): server.succeed("PYTHONUNBUFFERED=1 test-runner | systemd-cat -t test-runner") |