diff --git a/README.md b/README.md index 600dcc68..bcb6efa5 100644 --- a/README.md +++ b/README.md @@ -545,6 +545,16 @@ $ nix build .#checks.${system}.modules $ nix build .#checks.${system}.vm_postgresql_peerAuth ``` +Run one VM test interactively: + +```bash +$ nix run .#checks.${system}.vm_postgresql_peerAuth.driverInteractive +``` + +When you get to the shell, run either `start_all()` or `test_script()`. The former just starts all +the VMs and service, then you can introspect. The latter also starts the VMs if they are not yet and +then will run the test script. + ### Upload test results to CI Github actions do now have hardware acceleration, so running them there is not slow anymore. If diff --git a/flake.nix b/flake.nix index d8847119..37607ed3 100644 --- a/flake.nix +++ b/flake.nix @@ -95,6 +95,7 @@ // (vm_test "ldap" ./test/vm/ldap.nix) // (vm_test "postgresql" ./test/vm/postgresql.nix) // (vm_test "monitoring" ./test/vm/monitoring.nix) + // (vm_test "nextcloud" ./test/vm/nextcloud.nix) ); } ); diff --git a/modules/services/nextcloud-server.nix b/modules/services/nextcloud-server.nix index e526f3b8..9600e7a6 100644 --- a/modules/services/nextcloud-server.nix +++ b/modules/services/nextcloud-server.nix @@ -34,6 +34,12 @@ in default = "/var/lib/nextcloud"; }; + adminUser = lib.mkOption { + type = lib.types.str; + description = "Username of the initial admin user."; + default = "root"; + }; + adminPassFile = lib.mkOption { type = lib.types.path; description = "File containing the Nextcloud admin password."; @@ -183,8 +189,8 @@ in config = { dbtype = "pgsql"; - adminuser = "root"; - adminpassFile = cfg.adminPassFile; + adminuser = cfg.adminUser; + adminpassFile = toString cfg.adminPassFile; # Not using dbpassFile as we're using socket authentication. defaultPhoneRegion = "US"; trustedProxies = [ "127.0.0.1" ]; diff --git a/modules/services/nextcloud-server/docs/default.md b/modules/services/nextcloud-server/docs/default.md index d95f8b40..8fcdda84 100644 --- a/modules/services/nextcloud-server/docs/default.md +++ b/modules/services/nextcloud-server/docs/default.md @@ -6,8 +6,13 @@ This NixOS module is a service that sets up a [Nextcloud Server](https://nextclo ## Features {#services-nextcloud-server-features} -- Integration Tests (TODO: need to add some) +- [Integration Tests](@REPO@/test/vm/nextcloud.nix) + - Tests cron job is setup correctly. + - Tests initial admin user and password are setup correctly. + - Tests admin user can create and retrieve a file through WebDAV. - [Demo](./demo-nextcloud-server.html) + - Demo deploying a Nextcloud server with [Colmena](https://colmena.cli.rs/) and with proper + secrets management with [sops-nix](https://github.com/Mic92/sops-nix). - Access through subdomain using reverse proxy. - Access through HTTPS using reverse proxy. - Automatic setup of PostgreSQL database. diff --git a/test/vm/nextcloud.nix b/test/vm/nextcloud.nix new file mode 100644 index 00000000..4df22e57 --- /dev/null +++ b/test/vm/nextcloud.nix @@ -0,0 +1,123 @@ +{ pkgs, lib, ... }: +let + adminUser = "root"; + adminPass = "rootpw"; + subdomain = "n"; + domain = "example.com"; + fqdn = "${subdomain}.${domain}"; +in +{ + basic = pkgs.nixosTest { + name = "nextcloud-basic"; + + nodes.server = { config, pkgs, ... }: { + imports = [ + { + options = { + shb.ssl.enable = lib.mkEnableOption "ssl"; + shb.backup = lib.mkOption { type = lib.types.anything; }; + }; + } + # ../../modules/blocks/authelia.nix + # ../../modules/blocks/ldap.nix + ../../modules/services/nextcloud-server.nix + ]; + + shb.nextcloud = { + enable = true; + domain = "example.com"; + subdomain = "n"; + dataDir = "/var/lib/nextcloud"; + tracing = null; + + # This option is only needed because we do not access Nextcloud at the default port in the VM. + externalFqdn = "n.example.com:8080"; + + adminUser = adminUser; + adminPassFile = pkgs.writeText "adminPassFile" adminPass; + debug = true; + }; + # Nginx port. + networking.firewall.allowedTCPPorts = [ 80 ]; + # VM needs a bit more memory than default. + virtualisation.memorySize = 4096; + }; + + nodes.client = {}; + + testScript = { nodes, ... }: '' + start_all() + server.wait_for_unit("phpfpm-nextcloud.service") + server.wait_for_unit("nginx.service") + + def find_in_logs(unit, text): + return server.systemctl("status {}".format(unit))[1].find(text) != -1 + + with subtest("cron job succeeds"): + # This calls blocks until the service is done. + server.systemctl("start nextcloud-cron.service") + + # If the service failed, then we're not happy. + server.require_unit_state("nextcloud-cron", "inactive") + + if not find_in_logs("nextcloud-cron", "nextcloud-cron.service: Deactivated successfully."): + raise Exception("Nextcloud cron job did not finish successfully.") + + with subtest("fails with incorrect authentication"): + client.fail( + "curl -f -s -X PROPFIND" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:other """ + + """ -H "Host: ${fqdn}" """ + + " http://server/remote.php/dav/files/${adminUser}/" + ) + + with subtest("fails with incorrect path"): + client.fail( + "curl -f -s -X PROPFIND" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:${adminPass} """ + + """ -H "Host: ${fqdn}" """ + + " http://server/remote.php/dav/files/other/" + ) + + with subtest("can access webdav"): + client.succeed( + "curl -f -s -X PROPFIND" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:${adminPass} """ + + """ -H "Host: ${fqdn}" """ + + " http://server/remote.php/dav/files/${adminUser}/" + ) + + with subtest("can create and retrieve file"): + client.fail( + "curl -f -s -X GET" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:${adminPass} """ + + """ -H "Host: ${fqdn}" """ + + """ -T file """ + + " http://server/remote.php/dav/files/${adminUser}/file" + ) + client.succeed("echo 'hello' > file") + client.succeed( + "curl -f -s -X PUT" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:${adminPass} """ + + """ -H "Host: ${fqdn}" """ + + """ -T file """ + + " http://server/remote.php/dav/files/${adminUser}/" + ) + content = client.succeed( + "curl -f -s -X GET" + + """ -H "Depth: 1" """ + + """ -u ${adminUser}:${adminPass} """ + + """ -H "Host: ${fqdn}" """ + + """ -T file """ + + " http://server/remote.php/dav/files/${adminUser}/file" + ) + if content != "hello\n": + raise Exception("Got incorrect content for file, expected 'hello\n' but got:\n{}".format(content)) + ''; + }; +}