|
| 1 | +# https://wiki.nixos.org/wiki/NixOS_VM_tests |
| 2 | +{ |
| 3 | + pkgs24_11, |
| 4 | + pkgs25_05, |
| 5 | + pkgs25_11, |
| 6 | + ... |
| 7 | +}: |
| 8 | + |
| 9 | +let |
| 10 | + inherit (pkgs25_05) lib; |
| 11 | + tryAttr25 = |
| 12 | + name: |
| 13 | + let |
| 14 | + t = builtins.tryEval (builtins.getAttr name pkgs25_05); |
| 15 | + in |
| 16 | + if t.success then t.value else null; |
| 17 | + # Safe lookup on pkgs24_11 catching insecure-package eval errors |
| 18 | + tryAttr24 = |
| 19 | + name: |
| 20 | + if pkgs24_11 != null && builtins.hasAttr name pkgs24_11 then |
| 21 | + ( |
| 22 | + let |
| 23 | + t = builtins.tryEval (builtins.getAttr name pkgs24_11); |
| 24 | + in |
| 25 | + if t.success then t.value else null |
| 26 | + ) |
| 27 | + else |
| 28 | + null; |
| 29 | + # Safe lookup on pkgs25_11 catching eval errors |
| 30 | + tryAttr2511 = |
| 31 | + name: |
| 32 | + if pkgs25_11 != null && builtins.hasAttr name pkgs25_11 then |
| 33 | + ( |
| 34 | + let |
| 35 | + t = builtins.tryEval (builtins.getAttr name pkgs25_11); |
| 36 | + in |
| 37 | + if t.success then t.value else null |
| 38 | + ) |
| 39 | + else |
| 40 | + null; |
| 41 | + |
| 42 | + # Wrapper to make legacy Nextcloud derivations ignore override args (e.g. caBundle introduced later) |
| 43 | + legacyCompat = |
| 44 | + pkg: |
| 45 | + pkg |
| 46 | + // { |
| 47 | + override = _args: legacyCompat pkg; # ignore args to avoid unexpected argument errors |
| 48 | + overrideDerivation = f: legacyCompat (pkg.overrideDerivation f); |
| 49 | + }; |
| 50 | + |
| 51 | + # Helper to fetch a legacy pkg (from 24_11 set) and wrap it if it exists |
| 52 | + legacyPkg = |
| 53 | + name: |
| 54 | + let |
| 55 | + p = tryAttr24 name; |
| 56 | + in |
| 57 | + if p != null then legacyCompat p else null; |
| 58 | + |
| 59 | + # Flexible PHP package set selection for composer |
| 60 | + phpPkgSet = |
| 61 | + pkgs25_05.php84Packages |
| 62 | + or (pkgs25_05.php83Packages or (pkgs25_05.php82Packages or (pkgs25_05.php81Packages or null))); |
| 63 | + composerPkg = |
| 64 | + if phpPkgSet != null && phpPkgSet ? composer then phpPkgSet.composer else pkgs25_05.composer; # pkgs25_05.composer as last resort |
| 65 | + phpInterp = pkgs25_05.php or (if phpPkgSet != null && phpPkgSet ? php then phpPkgSet.php else null); |
| 66 | + |
| 67 | + # Legacy (29) come from 24.11, 30/31 from 25.05, 32 from 25.11 |
| 68 | + pkg29 = legacyPkg "nextcloud29"; |
| 69 | + pkg30 = tryAttr25 "nextcloud30"; |
| 70 | + pkg31 = tryAttr25 "nextcloud31"; |
| 71 | + pkg32 = tryAttr2511 "nextcloud32"; |
| 72 | + |
| 73 | + has29 = pkg29 != null; |
| 74 | + has30 = pkg30 != null; |
| 75 | + has31 = pkg31 != null; |
| 76 | + has32 = pkg32 != null; |
| 77 | + |
| 78 | + # Build the app once (using primary pkgs set) |
| 79 | + qownnotesapiApp = |
| 80 | + pkgs25_05.runCommand "qownnotesapi-app" |
| 81 | + { |
| 82 | + src = ../../.; |
| 83 | + buildInputs = lib.filter (x: x != null) [ |
| 84 | + composerPkg |
| 85 | + phpInterp |
| 86 | + ]; |
| 87 | + preferLocalBuild = true; |
| 88 | + allowSubstitutes = false; # ensure we always build locally (still won't rebuild if output already exists) |
| 89 | + } |
| 90 | + '' |
| 91 | + mkdir -p $out |
| 92 | + cp -r $src/* $out/ |
| 93 | + chmod -R u+w $out |
| 94 | + if [ -n "$FORCE_REBUILD_NONCE" ]; then |
| 95 | + echo "$FORCE_REBUILD_NONCE" > $out/.force-rebuild-nonce |
| 96 | + echo "Force rebuild nonce embedded: $FORCE_REBUILD_NONCE" |
| 97 | + fi |
| 98 | + export COMPOSER_ALLOW_SUPERUSER=1 |
| 99 | + export HOME=$TMPDIR |
| 100 | + if [ -f "$out/composer.json" ]; then |
| 101 | + if [ -d "$out/vendor" ]; then |
| 102 | + echo "Running composer install (offline, expects vendor already vendored)" |
| 103 | + (cd $out && composer install --no-dev --optimize-autoloader --no-interaction || composer dump-autoload --optimize || true) |
| 104 | + else |
| 105 | + echo "No vendor directory found; skipping composer install to avoid network (would fail)" |
| 106 | + fi |
| 107 | + fi |
| 108 | + ''; |
| 109 | + |
| 110 | + mkNode = pkg: name: { |
| 111 | + ${name} = _: { |
| 112 | + services.nextcloud = { |
| 113 | + enable = true; |
| 114 | + package = pkg; |
| 115 | + hostName = "localhost"; |
| 116 | + config = { |
| 117 | + adminuser = "admin"; |
| 118 | + adminpassFile = "/etc/nextcloud-adminpass"; |
| 119 | + dbtype = "sqlite"; |
| 120 | + dbname = "nextcloud"; |
| 121 | + }; |
| 122 | + extraApps = { |
| 123 | + qownnotesapi = qownnotesapiApp; |
| 124 | + }; |
| 125 | + extraAppsEnable = true; |
| 126 | + }; |
| 127 | + networking.firewall.allowedTCPPorts = [ |
| 128 | + 80 |
| 129 | + 443 |
| 130 | + ]; |
| 131 | + environment.etc."nextcloud-adminpass".text = "adminpass"; |
| 132 | + }; |
| 133 | + }; |
| 134 | + |
| 135 | + node29 = if has29 then mkNode pkg29 "nextcloud29" else { }; |
| 136 | + node30 = if has30 then mkNode pkg30 "nextcloud30" else { }; |
| 137 | + node31 = if has31 then mkNode pkg31 "nextcloud31" else { }; |
| 138 | + node32 = if has32 then mkNode pkg32 "nextcloud32" else { }; |
| 139 | + |
| 140 | +in |
| 141 | +# Fail early if any required Nextcloud package is missing |
| 142 | +assert (lib.assertMsg has29 "Missing required package: nextcloud29 (expected in pkgs24_11)"); |
| 143 | +assert (lib.assertMsg has30 "Missing required package: nextcloud30 (expected in pkgs25_05)"); |
| 144 | +assert (lib.assertMsg has31 "Missing required package: nextcloud31 (expected in pkgs25_05)"); |
| 145 | +assert (lib.assertMsg has32 "Missing required package: nextcloud32 (expected in pkgs25_11)"); |
| 146 | + |
| 147 | +pkgs25_05.nixosTest { |
| 148 | + name = "nextcloud_qownnotesapi"; |
| 149 | + nodes = node29 // node30 // node31 // node32; |
| 150 | + interactive.sshBackdoor.enable = true; # provides ssh-config & vsock access (needs host vsock support) |
| 151 | + testScript = '' |
| 152 | + print("Has29=${toString has29} Has30=${toString has30} Has31=${toString has31} Has32=${toString has32}") |
| 153 | + start_all() |
| 154 | +
|
| 155 | + # Helper to test a Nextcloud node consistently |
| 156 | + def test_version(node, label, pkg_version): |
| 157 | + print(f"Testing Nextcloud {label} ({pkg_version})") |
| 158 | + node.wait_for_unit("phpfpm-nextcloud.service") |
| 159 | + node.wait_for_unit("nginx.service") |
| 160 | + node.succeed("curl -fsSL http://localhost/status.php | grep 'installed' | grep 'true'") |
| 161 | + node.succeed("sudo -u nextcloud nextcloud-occ app:list | grep -i qownnotesapi || (echo 'App missing ({label})'; sudo -u nextcloud nextcloud-occ app:list; exit 1)") |
| 162 | + assert "200" in node.succeed("curl -s -o /dev/null -w '%{http_code}' http://localhost/login"), "Login page needs to show up!" |
| 163 | + node.succeed("sudo -u nextcloud nextcloud-occ status | grep -i 'version:'") |
| 164 | + # Test qownnotesapi app endpoints |
| 165 | + assert "200" in node.succeed("curl -s -o /dev/null -w '%{http_code}' http://admin:adminpass@localhost/index.php/apps/qownnotesapi/api/v1/note/versions?format=json&file_name=/Notes/test.md"), "Version API request failed!" |
| 166 | + assert "200" in node.succeed("curl -s -o /dev/null -w '%{http_code}' http://admin:adminpass@localhost/index.php/apps/qownnotesapi/api/v1/note/trashed?format=json&dir=/Notes"), "Trash API request failed!" |
| 167 | + assert "200" in node.succeed("curl -s -o /dev/null -w '%{http_code}' http://admin:adminpass@localhost/index.php/apps/qownnotesapi/api/v1/note/app_info?notes_path=/Notes"), "App Info API request failed!" |
| 168 | +
|
| 169 | + ${ |
| 170 | + if has29 then |
| 171 | + ''test_version(nextcloud29, "29", "${pkg29.version}")'' |
| 172 | + else |
| 173 | + ''print("Skipping Nextcloud 29: package not present")'' |
| 174 | + } |
| 175 | +
|
| 176 | + ${ |
| 177 | + if has30 then |
| 178 | + ''test_version(nextcloud30, "30", "${pkg30.version}")'' |
| 179 | + else |
| 180 | + ''print("Skipping Nextcloud 30: package not present")'' |
| 181 | + } |
| 182 | +
|
| 183 | + ${ |
| 184 | + if has31 then |
| 185 | + ''test_version(nextcloud31, "31", "${pkg31.version}")'' |
| 186 | + else |
| 187 | + ''print("Skipping Nextcloud 31: package not present")'' |
| 188 | + } |
| 189 | +
|
| 190 | + ${ |
| 191 | + if has32 then |
| 192 | + ''test_version(nextcloud32, "32", "${pkg32.version}")'' |
| 193 | + else |
| 194 | + ''print("Skipping Nextcloud 32: package not present")'' |
| 195 | + } |
| 196 | + print("ALL_TESTS_DONE") |
| 197 | + ''; |
| 198 | +} |
0 commit comments