From a5ea922f5bf230f6942a970ddda5a2045c4dfbdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Roche?= Date: Thu, 6 Nov 2025 17:01:50 +0100 Subject: [PATCH 1/3] fix(exts): handle pg_upgrade generated update_extensions.sql script in the extension tests pg_upgrade may generate an update_extensions.sql script to update extensions after a major version upgrade. This commit modifies the extension tests to check for the presence of this script after upgrading PostgreSQL to version 17. If the script exists, it is executed to ensure that the extensions are updated correctly. --- nix/ext/tests/default.nix | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nix/ext/tests/default.nix b/nix/ext/tests/default.nix index facd250f6..5953b7eb0 100644 --- a/nix/ext/tests/default.nix +++ b/nix/ext/tests/default.nix @@ -179,13 +179,25 @@ let with subtest("Check pg_regress with postgresql 15 after installing the last version"): test.check_pg_regress(Path("${psql_15}/lib/pgxs/src/test/regress/pg_regress"), "15", pg_regress_test_name) + has_update_script = False with subtest("switch to postgresql 17"): server.succeed( f"{pg17_configuration}/bin/switch-to-configuration test >&2" ) + has_update_script = server.succeed( + "test -f /var/lib/postgresql/update_extensions.sql && echo 'yes' || echo 'no'" + ).strip() == "yes" + if has_update_script: + # Run the extension update script generated during the upgrade + test.run_sql_file("/var/lib/postgresql/update_extensions.sql") with subtest("Check last version of the extension after postgresql upgrade"): - test.assert_version_matches(last_version) + if has_update_script: + # If there was an update script, the last version should be installed + test.assert_version_matches(versions["17"][-1]) + else: + # Otherwise, the version should match the last version from postgresql 15 + test.assert_version_matches(last_version) with subtest("Check upgrade path with postgresql 17"): test.check_upgrade_path("17") From f27fca3adcabae830a695ac553482480e32e5dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Roche?= Date: Thu, 6 Nov 2025 17:01:50 +0100 Subject: [PATCH 2/3] Feat(ext): use the generic postgres extension test for postgis Thanks to the improvement related to the generated pg_upgrade script, we can now reuse the generic postgres extension test for postgis. --- nix/ext/tests/default.nix | 1 + nix/ext/tests/postgis.nix | 156 -------------------------------------- 2 files changed, 1 insertion(+), 156 deletions(-) delete mode 100644 nix/ext/tests/postgis.nix diff --git a/nix/ext/tests/default.nix b/nix/ext/tests/default.nix index 5953b7eb0..ec57cba0d 100644 --- a/nix/ext/tests/default.nix +++ b/nix/ext/tests/default.nix @@ -236,6 +236,7 @@ builtins.listToAttrs ( "pg_stat_monitor" "pg_tle" "pgaudit" + "postgis" "vector" "wal2json" "wrappers" diff --git a/nix/ext/tests/postgis.nix b/nix/ext/tests/postgis.nix deleted file mode 100644 index ab6a4b3f8..000000000 --- a/nix/ext/tests/postgis.nix +++ /dev/null @@ -1,156 +0,0 @@ -{ self, pkgs }: -let - pname = "postgis"; - inherit (pkgs) lib; - installedExtension = - postgresMajorVersion: self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all"; - versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions; - postgresqlWithExtension = - postgresql: - let - majorVersion = lib.versions.major postgresql.version; - pkg = pkgs.buildEnv { - name = "postgresql-${majorVersion}-${pname}"; - paths = [ - postgresql - postgresql.lib - (installedExtension majorVersion) - ]; - passthru = { - inherit (postgresql) version psqlSchema; - lib = pkg; - withPackages = _: pkg; - }; - nativeBuildInputs = [ pkgs.makeWrapper ]; - pathsToLink = [ - "/" - "/bin" - "/lib" - ]; - postBuild = '' - wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib - wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib - wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib - ''; - }; - in - pkg; -in -self.inputs.nixpkgs.lib.nixos.runTest { - name = pname; - hostPkgs = pkgs; - nodes.server = - { config, ... }: - { - virtualisation = { - forwardPorts = [ - { - from = "host"; - host.port = 13022; - guest.port = 22; - } - ]; - }; - services.openssh = { - enable = true; - }; - - services.postgresql = { - enable = true; - package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; - }; - - specialisation.postgresql17.configuration = { - services.postgresql = { - package = lib.mkForce (postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17); - }; - - systemd.services.postgresql-migrate = { - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - User = "postgres"; - Group = "postgres"; - StateDirectory = "postgresql"; - WorkingDirectory = "${builtins.dirOf config.services.postgresql.dataDir}"; - }; - script = - let - oldPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; - newPostgresql = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17; - oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}"; - newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}"; - in - '' - if [[ ! -d ${newDataDir} ]]; then - install -d -m 0700 -o postgres -g postgres "${newDataDir}" - ${newPostgresql}/bin/initdb -D "${newDataDir}" - ${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \ - --old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin" - else - echo "${newDataDir} already exists" - fi - ''; - }; - - systemd.services.postgresql = { - after = [ "postgresql-migrate.service" ]; - requires = [ "postgresql-migrate.service" ]; - }; - }; - }; - testScript = - { nodes, ... }: - let - pg17-configuration = "${nodes.server.system.build.toplevel}/specialisation/postgresql17"; - in - '' - versions = { - "15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}], - "17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}], - } - - def run_sql(query): - return server.succeed(f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """).strip() - - def check_upgrade_path(pg_version): - with subtest("Check ${pname} upgrade path"): - firstVersion = versions[pg_version][0] - server.succeed("sudo -u postgres psql -c 'DROP EXTENSION IF EXISTS ${pname};'") - run_sql(f"""CREATE EXTENSION ${pname} WITH VERSION '{firstVersion}' CASCADE;""") - installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""") - assert installed_version == firstVersion, f"Expected ${pname} version {firstVersion}, but found {installed_version}" - for version in versions[pg_version][1:]: - run_sql(f"""ALTER EXTENSION ${pname} UPDATE TO '{version}';""") - installed_version = run_sql(r"""SELECT extversion FROM pg_extension WHERE extname = '${pname}';""") - assert installed_version == version, f"Expected ${pname} version {version}, but found {installed_version}" - - start_all() - - server.wait_for_unit("multi-user.target") - server.wait_for_unit("postgresql.service") - - check_upgrade_path("15") - - with subtest("Check ${pname} latest extension version"): - server.succeed("sudo -u postgres psql -c 'DROP EXTENSION ${pname};'") - server.succeed("sudo -u postgres psql -c 'CREATE EXTENSION ${pname} CASCADE;'") - installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension where extname = '${pname}';""") - latestVersion = versions["15"][-1] - majMinVersion = ".".join(latestVersion.split('.')[:1]) - assert f"${pname},{majMinVersion}" in installed_extensions, f"Expected ${pname} version {latestVersion}, but found {installed_extensions}" - - with subtest("switch to postgresql 17"): - server.succeed( - "${pg17-configuration}/bin/switch-to-configuration test >&2" - ) - - with subtest("Check ${pname} latest extension version after upgrade"): - installed_extensions=run_sql(r"""SELECT extname, extversion FROM pg_extension;""") - latestVersion = versions["17"][-1] - majMinVersion = ".".join(latestVersion.split('.')[:1]) - assert f"${pname},{majMinVersion}" in installed_extensions - - check_upgrade_path("17") - ''; -} From 537ceef13c4a2243a12016afedc1109a582e49a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Roche?= Date: Thu, 6 Nov 2025 17:25:45 +0100 Subject: [PATCH 3/3] chore(ext): document exceptions to generic extension tests This helps us identify why certain extensions do not use the generic tests. --- nix/ext/tests/http.nix | 3 +++ nix/ext/tests/pg_repack.nix | 3 +++ nix/ext/tests/pgrouting.nix | 1 + 3 files changed, 7 insertions(+) diff --git a/nix/ext/tests/http.nix b/nix/ext/tests/http.nix index 09075c374..d36b18eba 100644 --- a/nix/ext/tests/http.nix +++ b/nix/ext/tests/http.nix @@ -154,3 +154,6 @@ self.inputs.nixpkgs.lib.nixos.runTest { check_upgrade_path("17") ''; } +# We don't use the generic test for this extension because: +# http is not using semver versioning scheme, so we need to adapt the version checks +# otherwise the test fails with ERROR: extension "http" has no installation script nor update path for version "1.5.0" diff --git a/nix/ext/tests/pg_repack.nix b/nix/ext/tests/pg_repack.nix index dae534d2e..d000ca36b 100644 --- a/nix/ext/tests/pg_repack.nix +++ b/nix/ext/tests/pg_repack.nix @@ -160,3 +160,6 @@ self.inputs.nixpkgs.lib.nixos.runTest { test.check_upgrade_path("17") ''; } +# We don't use the generic test for this extension because: +# pg_repack does not support upgrade as the extension doesn't provide the upgrade SQL scripts +# and fails with ERROR: extension "pg_repack" has no update path from version "1.4.8" to version "1.5.0" diff --git a/nix/ext/tests/pgrouting.nix b/nix/ext/tests/pgrouting.nix index f8775e4aa..2fe1113bc 100644 --- a/nix/ext/tests/pgrouting.nix +++ b/nix/ext/tests/pgrouting.nix @@ -226,3 +226,4 @@ self.inputs.nixpkgs.lib.nixos.runTest { check_upgrade_path("orioledb-17") ''; } +# We don't use the generic test for this extension because: it requires postgis to be installed as well.