From 12a97248a93fb2ffcd13ee39f7df5ac8c8d64a0d Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 13:36:19 +0300 Subject: [PATCH 01/17] commit --- .../workflows/test-package-installation.yml | 92 ++++++++++ .gitignore | 2 + test_package_installation/README.md | 30 ++++ test_package_installation/run_test.py | 160 ++++++++++++++++++ .../setup_cluster_and_test.sh | 116 +++++++++++++ test_package_installation/test_deb.sh | 49 ++++++ test_package_installation/test_rpm.sh | 47 +++++ 7 files changed, 496 insertions(+) create mode 100644 .github/workflows/test-package-installation.yml create mode 100644 test_package_installation/README.md create mode 100644 test_package_installation/run_test.py create mode 100755 test_package_installation/setup_cluster_and_test.sh create mode 100755 test_package_installation/test_deb.sh create mode 100755 test_package_installation/test_rpm.sh diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml new file mode 100644 index 000000000..008ab95f6 --- /dev/null +++ b/.github/workflows/test-package-installation.yml @@ -0,0 +1,92 @@ +name: Test Latest Citus Package Installation on Supported PostgreSQL Versions + +on: + push: + branches: + - all-citus-test-installation-workflow + workflow_dispatch: + +env: + # Branch whose build-package.yml and postgres-matrix.yml are the source of truth + SOURCE_BRANCH: "all-citus" + +jobs: + discover: + name: Discover platforms & versions + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.build_matrix.outputs.matrix }} + citus_version: ${{ steps.resolve_versions.outputs.citus_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Fetch source branch + run: git fetch origin "${SOURCE_BRANCH}" --depth=1 + + - name: Extract platform list + id: extract_platforms + run: | + git show "origin/${SOURCE_BRANCH}:.github/workflows/build-package.yml" \ + > /tmp/build-package.yml + + platforms=$( + yq -o=json '.jobs.build_package.strategy.matrix.platform' /tmp/build-package.yml \ + | jq -c '.' + ) + + echo "Discovered platforms: ${platforms}" + echo "platforms=${platforms}" >> "$GITHUB_OUTPUT" + + - name: Resolve Citus & PG versions from postgres-matrix.yml + id: resolve_versions + run: | + git show "origin/${SOURCE_BRANCH}:postgres-matrix.yml" > /tmp/postgres-matrix.yml + + # Latest entry = last element in version_matrix + citus_version=$(yq '.version_matrix[-1] | keys | .[0]' /tmp/postgres-matrix.yml) + + pg_versions=$( + yq -o=json \ + ".version_matrix[-1].\"${citus_version}\".postgres_versions" \ + /tmp/postgres-matrix.yml \ + | jq -c '[.[] | tostring]' + ) + + echo "Latest Citus version: ${citus_version}" + echo "Supported PG versions: ${pg_versions}" + echo "citus_version=${citus_version}" >> "$GITHUB_OUTPUT" + echo "pg_versions=${pg_versions}" >> "$GITHUB_OUTPUT" + + - name: Build matrix + id: build_matrix + run: | + matrix=$(jq -cn \ + --argjson platforms '${{ steps.extract_platforms.outputs.platforms }}' \ + --argjson pg_versions '${{ steps.resolve_versions.outputs.pg_versions }}' \ + '{"platform": $platforms, "pg_version": $pg_versions}') + echo "Matrix: ${matrix}" + echo "matrix=${matrix}" >> "$GITHUB_OUTPUT" + + test_package: + name: "PG${{ matrix.pg_version }}/Citus${{ needs.discover.outputs.citus_version }} - ${{ matrix.platform }}" + needs: discover + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.discover.outputs.matrix) }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ">=3.10" + + - name: Run package installation test + run: | + python3 test_package_installation/run_test.py \ + "${{ matrix.platform }}" \ + "${{ matrix.pg_version }}" \ + "${{ needs.discover.outputs.citus_version }}" diff --git a/.gitignore b/.gitignore index 44cb91719..d6d9d9ad6 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ # package output directory /packages + +.vscode diff --git a/test_package_installation/README.md b/test_package_installation/README.md new file mode 100644 index 000000000..f3dc0003a --- /dev/null +++ b/test_package_installation/README.md @@ -0,0 +1,30 @@ +# Package Installation Tests + +Verifies that Citus packages can be installed from the package repository on all supported platforms. + +Each test spins up a Docker container for the target OS, installs the PostgreSQL and Citus packages, +sets up a cluster, and runs very basic tests. + +## Running locally + +Requires **Python 3.10+** and **Docker**. No additional Python packages needed. + +```bash +python3 test_package_installation/run_test.py +``` + +Examples: + +```bash +python3 test_package_installation/run_test.py ubuntu/noble 18 14.0 +python3 test_package_installation/run_test.py el/9 17 14.0 +python3 test_package_installation/run_test.py debian/bookworm 16 14.0 +``` + +## Running via GitHub Actions + +You can manually trigger the workflow using [this GitHub Actions tab](https://github.com/citusdata/packaging/actions/workflows/test-package-installation.yml). + +It automatically discovers the supported platforms, latest Citus version that we published +packages for, and compatible PostgreSQL versions from the `all-citus` branch, using +[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml) and [postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) files. diff --git a/test_package_installation/run_test.py b/test_package_installation/run_test.py new file mode 100644 index 000000000..796eaa1d7 --- /dev/null +++ b/test_package_installation/run_test.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +""" +Docker-based package installation tester. + +Pulls a Docker image, starts a container, copies the test scripts into it, +and runs the appropriate installation + verification test for the given OS. + +Usage: + python run_test.py / + +Examples: + python run_test.py ubuntu/noble 18 14.0 + python run_test.py el/9 18 14.0 +""" + +import os +import subprocess +import sys +from typing import Optional + +def pull_docker_image(image_name: str) -> bool: + print(f"Pulling Docker image: {image_name}") + + try: + result = subprocess.run(["docker", "pull", image_name]) + + if result.returncode == 0: + print(f"Successfully pulled image: {image_name}") + return True + else: + print(f"Error pulling image: {image_name}", file=sys.stderr) + return False + except Exception as e: + print(f"Error during image pull: {e}", file=sys.stderr) + return False + +def start_container(image_name: str) -> Optional[str]: + print(f"Starting container from image: {image_name}") + + try: + result = subprocess.run( + ["docker", "run", "-d", image_name, "sleep", "infinity"], + capture_output=True, + text=True + ) + + if result.returncode == 0: + container_id = result.stdout.strip() + print(f"Container started with ID: {container_id}") + return container_id + else: + print(f"Error starting container: {result.stderr}", file=sys.stderr) + return None + except Exception as e: + print(f"Error during container start: {e}", file=sys.stderr) + return None + +def copy_into_container(container_id: str, local_path: str, container_path: str) -> bool: + print(f"Copying {local_path} to container {container_id}:{container_path}") + + try: + result = subprocess.run( + ["docker", "cp", local_path, f"{container_id}:{container_path}"] + ) + + if result.returncode == 0: + print(f"Successfully copied {local_path} to container") + return True + else: + print(f"Error copying file into container.", file=sys.stderr) + return False + except Exception as e: + print(f"Error during file copy: {e}", file=sys.stderr) + return False + + +def run_command_in_container(container_id: str, command: str) -> bool: + print(f"Executing command in container {container_id}") + + try: + result = subprocess.run( + ["docker", "exec", container_id, "bash", "-c", command] + ) + return result.returncode == 0 + except Exception as e: + print(f"Error during command execution: {e}", file=sys.stderr) + return False + + +def main(os_name: str, os_version: str, pg_major_version: str, citus_major_minor_version: str): + if os_name == "ubuntu" or os_name == "debian": + image_name = f"{os_name}:{os_version}" + test_script_name = "test_deb.sh" + test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version}" + elif os_name == "el": + image_name = f"almalinux:{os_version}" + test_script_name = "test_rpm.sh" + test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version} {os_version}" + elif os_name == "ol": + image_name = f"oraclelinux:{os_version}" + test_script_name = "test_rpm.sh" + test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version} {os_version}" + else: + print(f"Unsupported OS: {os_name}. Exiting.", file=sys.stderr) + sys.exit(1) + + # Pull the Docker image + if not pull_docker_image(image_name): + print("Failed to pull Docker image. Exiting.", file=sys.stderr) + sys.exit(1) + + container_id = start_container(image_name) + if not container_id: + print("Failed to start Docker container. Exiting.", file=sys.stderr) + sys.exit(1) + + try: + # Copy the test scripts into the container + script_dir = os.path.dirname(os.path.abspath(__file__)) + + for script_name in ["setup_cluster_and_test.sh", test_script_name]: + script_path = os.path.join(script_dir, script_name) + if not copy_into_container(container_id, script_path, f"/{script_name}"): + print(f"Failed to copy {script_name} into container. Exiting.", file=sys.stderr) + sys.exit(1) + + # Execute the test script with the provided parameters inside the container + print(f"Executing command in container: {test_command}") + success = run_command_in_container(container_id, test_command) + if not success: + print("Failed to execute command in container. Exiting.", file=sys.stderr) + sys.exit(1) + finally: + # Cleanup: force-remove the container (stops it if still running) + print(f"Removing container {container_id}") + try: + subprocess.run(["docker", "rm", "-f", container_id], capture_output=True, text=True) + print(f"Container {container_id} removed successfully.") + except Exception as e: + print(f"Error removing container: {e}", file=sys.stderr) + +if __name__ == "__main__": + if len(sys.argv) != 4: + print("Usage: python run_test.py ", file=sys.stderr) + print("Example: python run_test.py ubuntu/noble 18 14.0", file=sys.stderr) + sys.exit(1) + + os_name, os_version = sys.argv[1].split("/") + postgres_version = sys.argv[2] + citus_version = sys.argv[3] + + if not postgres_version.isdigit(): + print("PostgreSQL major version must be a number (e.g., 18). Exiting.", file=sys.stderr) + sys.exit(1) + + if not (len(citus_version.split(".")) == 2 and all(p.isdigit() for p in citus_version.split("."))): + print("Citus version must be in the format major.minor (e.g., 14.0). Exiting.", file=sys.stderr) + sys.exit(1) + + main(os_name, os_version, postgres_version, citus_version) diff --git a/test_package_installation/setup_cluster_and_test.sh b/test_package_installation/setup_cluster_and_test.sh new file mode 100755 index 000000000..85c45c17e --- /dev/null +++ b/test_package_installation/setup_cluster_and_test.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# Sets up a multi-node Citus cluster, creates a distributed table, +# rebalances shards, and verifies even distribution. +# +# Called by test_deb.sh and test_rpm.sh after package installation. +# +# Note: need to run this as superuser +# +# Usage: setup_cluster_and_test.sh +# Example: setup_cluster_and_test.sh /usr/lib/postgresql/17/bin + +set -euo pipefail + +if [ -z "$1" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_BIN="$1" + +## constants and helpers + +NODE_COUNT=3 +SHARDS_PER_NODE=5 +FIRST_NODE_PORT=9700 + +run_psql_cmd() +{ + if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: run_psql_cmd " >&2 + exit 1 + fi + + PORT_NUMBER="$1" + SQL_COMMAND="$2" + + su - postgres -c "${PG_BIN}/psql -X -qAt -p ${PORT_NUMBER} -c \"${SQL_COMMAND}\"" +} + +## initialize all nodes and create citus extension on them + +echo "Initializing nodes and creating citus extension on them ..." + +mkdir -p /test_cluster +chown postgres:postgres /test_cluster +chmod 755 /test_cluster + +for i in $(seq 0 $((NODE_COUNT - 1))); do + node_name="node${i}" + echo "Creating node: $node_name" + + su - postgres -c "mkdir -p /test_cluster/${node_name}" + + port_number=$((FIRST_NODE_PORT + i)) + + su - postgres -c "${PG_BIN}/initdb -D /test_cluster/${node_name}" + su - postgres -c "echo \"shared_preload_libraries = 'citus'\" >> /test_cluster/${node_name}/postgresql.conf" + su - postgres -c "${PG_BIN}/pg_ctl -D /test_cluster/${node_name} -o \"-p $port_number\" -l /test_cluster/${node_name}/logfile start" + run_psql_cmd "$port_number" "CREATE EXTENSION citus;" +done + +## create a distributed table + +echo "Creating a distributed table ..." + +shard_count=$((NODE_COUNT * SHARDS_PER_NODE)) +run_psql_cmd "$FIRST_NODE_PORT" "CREATE TABLE test_table (id INT); SELECT create_distributed_table('test_table', 'id', shard_count => $shard_count);" + +## add worker nodes + +echo "Adding worker nodes ..." + +for i in $(seq 1 $((NODE_COUNT - 1))); do + port_number=$((FIRST_NODE_PORT + i)) + run_psql_cmd "$FIRST_NODE_PORT" "SELECT citus_add_node('localhost', $port_number);" +done + +## run rebalancer + +echo "Running shard rebalancer ..." + +run_psql_cmd "$FIRST_NODE_PORT" "SELECT rebalance_table_shards(shard_transfer_mode =>'block_writes');" + +## verify that shards are distributed evenly across nodes + +echo "Verifying that shards are distributed evenly across nodes ..." + +result=$( + run_psql_cmd "$FIRST_NODE_PORT" " + SELECT bool_and(cnt = $SHARDS_PER_NODE) + FROM ( + SELECT nodeport, + COUNT(shardid) AS cnt + FROM pg_dist_node + LEFT JOIN pg_dist_shard_placement USING (nodeport) + GROUP BY nodeport + ) t; + " +) + +if [ "$result" = "t" ]; then + echo "Verified cluster creation, distributed table creation and shard rebalancing. Shards are distributed evenly across nodes." +else + echo "Error: Citus cluster creation failed. Shards are not distributed evenly across nodes, see below for details:" >&2 + run_psql_cmd "$FIRST_NODE_PORT" " + SELECT nodeport, + COUNT(shardid) AS cnt + FROM pg_dist_node + LEFT JOIN pg_dist_shard_placement USING (nodeport) + GROUP BY nodeport; + " + exit 1 +fi diff --git a/test_package_installation/test_deb.sh b/test_package_installation/test_deb.sh new file mode 100755 index 000000000..23002008e --- /dev/null +++ b/test_package_installation/test_deb.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Installs PostgreSQL and Citus packages on Debian/Ubuntu, then runs +# the cluster setup and verification test. +# +# Note: need to run this as superuser +# +# Usage: test_deb.sh +# Example: test_deb.sh 17 14.0 + +set -euo pipefail + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_MAJOR_VERSION="$1" +CITUS_MAJOR_MINOR_VERSION="$2" + +export DEBIAN_FRONTEND=noninteractive + +## install postgres + +echo "Installing PostgreSQL ..." + +apt-get -y update +apt-get -y install curl ca-certificates + +install -d /usr/share/postgresql-common/pgdg +curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc +. /etc/os-release +sh -c "echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $VERSION_CODENAME-pgdg main' > /etc/apt/sources.list.d/pgdg.list" + +apt -y update +apt-get -y install postgresql-${PG_MAJOR_VERSION} + +## install citus + +echo "Installing Citus ..." + +curl --fail https://install.citusdata.com/community/deb.sh > add-citus-repo.sh +bash add-citus-repo.sh +apt-get -y install postgresql-${PG_MAJOR_VERSION}-citus-${CITUS_MAJOR_MINOR_VERSION} + +## setup a citus cluster and run verification tests + +/setup_cluster_and_test.sh "/usr/lib/postgresql/${PG_MAJOR_VERSION}/bin" diff --git a/test_package_installation/test_rpm.sh b/test_package_installation/test_rpm.sh new file mode 100755 index 000000000..158cad2fe --- /dev/null +++ b/test_package_installation/test_rpm.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Installs PostgreSQL and Citus packages on EL/OL (RPM-based distros), then +# runs the cluster setup and verification test. +# +# Note: need to run this as superuser +# +# Usage: test_rpm.sh +# Example: test_rpm.sh 17 14.0 9 + +set -euo pipefail + +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_MAJOR_VERSION="$1" +CITUS_MAJOR_MINOR_VERSION="$2" +OS_VERSION="$3" + +## install postgres + +echo "Installing PostgreSQL ..." + +dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm + +# disable the built-in PostgreSQL module +dnf -qy module disable postgresql + +dnf -y update +dnf install -y postgresql${PG_MAJOR_VERSION}-server + +## install citus + +echo "Installing Citus ..." + +curl --fail https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh +bash add-citus-repo.sh + +citus_major_minor_version_without_dot="${CITUS_MAJOR_MINOR_VERSION//./}" +dnf install -y citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION} + +## setup a citus cluster and run verification tests + +/setup_cluster_and_test.sh "/usr/pgsql-${PG_MAJOR_VERSION}/bin" \ No newline at end of file From a56879d1b07ba121bebb51feafb190fbaa7cc283 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:21:13 +0300 Subject: [PATCH 02/17] remove 'on push', was added for testing before merging --- .github/workflows/test-package-installation.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index 008ab95f6..c0b4bca79 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -1,9 +1,6 @@ name: Test Latest Citus Package Installation on Supported PostgreSQL Versions on: - push: - branches: - - all-citus-test-installation-workflow workflow_dispatch: env: From ab2eb2c9c7612e01a0ff56ff8f3f6ee268c3ac7c Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:27:45 +0300 Subject: [PATCH 03/17] more --- test_package_installation/setup_cluster_and_test.sh | 2 +- test_package_installation/test_deb.sh | 2 +- test_package_installation/test_rpm.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test_package_installation/setup_cluster_and_test.sh b/test_package_installation/setup_cluster_and_test.sh index 85c45c17e..9f888b0db 100755 --- a/test_package_installation/setup_cluster_and_test.sh +++ b/test_package_installation/setup_cluster_and_test.sh @@ -5,7 +5,7 @@ # # Called by test_deb.sh and test_rpm.sh after package installation. # -# Note: need to run this as superuser +# Note: need to run this as root # # Usage: setup_cluster_and_test.sh # Example: setup_cluster_and_test.sh /usr/lib/postgresql/17/bin diff --git a/test_package_installation/test_deb.sh b/test_package_installation/test_deb.sh index 23002008e..e0b08ff21 100755 --- a/test_package_installation/test_deb.sh +++ b/test_package_installation/test_deb.sh @@ -3,7 +3,7 @@ # Installs PostgreSQL and Citus packages on Debian/Ubuntu, then runs # the cluster setup and verification test. # -# Note: need to run this as superuser +# Note: need to run this as root # # Usage: test_deb.sh # Example: test_deb.sh 17 14.0 diff --git a/test_package_installation/test_rpm.sh b/test_package_installation/test_rpm.sh index 158cad2fe..2d3521ecf 100755 --- a/test_package_installation/test_rpm.sh +++ b/test_package_installation/test_rpm.sh @@ -3,7 +3,7 @@ # Installs PostgreSQL and Citus packages on EL/OL (RPM-based distros), then # runs the cluster setup and verification test. # -# Note: need to run this as superuser +# Note: need to run this as root # # Usage: test_rpm.sh # Example: test_rpm.sh 17 14.0 9 @@ -44,4 +44,4 @@ dnf install -y citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION} ## setup a citus cluster and run verification tests -/setup_cluster_and_test.sh "/usr/pgsql-${PG_MAJOR_VERSION}/bin" \ No newline at end of file +/setup_cluster_and_test.sh "/usr/pgsql-${PG_MAJOR_VERSION}/bin" From c111ea9b356f99a1840739bbe80cdbfebcfa4311 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:42:22 +0300 Subject: [PATCH 04/17] more --- test_package_installation/run_test.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test_package_installation/run_test.py b/test_package_installation/run_test.py index 796eaa1d7..9bfb5a615 100644 --- a/test_package_installation/run_test.py +++ b/test_package_installation/run_test.py @@ -22,7 +22,8 @@ def pull_docker_image(image_name: str) -> bool: print(f"Pulling Docker image: {image_name}") try: - result = subprocess.run(["docker", "pull", image_name]) + result = subprocess.run(["docker", "pull", image_name], + stdout=sys.stdout, stderr=sys.stdout) if result.returncode == 0: print(f"Successfully pulled image: {image_name}") @@ -60,7 +61,8 @@ def copy_into_container(container_id: str, local_path: str, container_path: str) try: result = subprocess.run( - ["docker", "cp", local_path, f"{container_id}:{container_path}"] + ["docker", "cp", local_path, f"{container_id}:{container_path}"], + stdout=sys.stdout, stderr=sys.stdout ) if result.returncode == 0: @@ -79,7 +81,9 @@ def run_command_in_container(container_id: str, command: str) -> bool: try: result = subprocess.run( - ["docker", "exec", container_id, "bash", "-c", command] + ["docker", "exec", container_id, "bash", "-c", command], + stdout=sys.stdout, + stderr=sys.stdout ) return result.returncode == 0 except Exception as e: @@ -134,7 +138,8 @@ def main(os_name: str, os_version: str, pg_major_version: str, citus_major_minor # Cleanup: force-remove the container (stops it if still running) print(f"Removing container {container_id}") try: - subprocess.run(["docker", "rm", "-f", container_id], capture_output=True, text=True) + subprocess.run(["docker", "rm", "-f", container_id], + stdout=sys.stdout, stderr=sys.stdout) print(f"Container {container_id} removed successfully.") except Exception as e: print(f"Error removing container: {e}", file=sys.stderr) From 5d3b02ea656d1861f8f6b6059e18c95341e72b19 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:42:28 +0300 Subject: [PATCH 05/17] Revert "remove 'on push', was added for testing before merging" This reverts commit a56879d1b07ba121bebb51feafb190fbaa7cc283. --- .github/workflows/test-package-installation.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index c0b4bca79..008ab95f6 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -1,6 +1,9 @@ name: Test Latest Citus Package Installation on Supported PostgreSQL Versions on: + push: + branches: + - all-citus-test-installation-workflow workflow_dispatch: env: From ac6bf1d7843a95bf194066a2b489201847e9707c Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:45:23 +0300 Subject: [PATCH 06/17] consistent outputs? --- test_package_installation/run_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test_package_installation/run_test.py b/test_package_installation/run_test.py index 9bfb5a615..1a1dfaa1a 100644 --- a/test_package_installation/run_test.py +++ b/test_package_installation/run_test.py @@ -18,6 +18,11 @@ import sys from typing import Optional +# Force line-buffered stdout so print() output appears in order +# with subprocess output (Python fully buffers stdout in non-TTY +# environments like CI). +sys.stdout.reconfigure(line_buffering=True) + def pull_docker_image(image_name: str) -> bool: print(f"Pulling Docker image: {image_name}") From 165c6670a98e438c8feed66552fabb89af28b92f Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 19:21:13 +0300 Subject: [PATCH 07/17] remove 'on push', was added for testing before merging --- .github/workflows/test-package-installation.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index 008ab95f6..c0b4bca79 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -1,9 +1,6 @@ name: Test Latest Citus Package Installation on Supported PostgreSQL Versions on: - push: - branches: - - all-citus-test-installation-workflow workflow_dispatch: env: From b504db60ae8fe11ce595b3ce342a2bd662794937 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Wed, 11 Feb 2026 22:24:39 +0300 Subject: [PATCH 08/17] Update run_test.py --- test_package_installation/run_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_package_installation/run_test.py b/test_package_installation/run_test.py index 1a1dfaa1a..a2bba7a6f 100644 --- a/test_package_installation/run_test.py +++ b/test_package_installation/run_test.py @@ -6,7 +6,7 @@ and runs the appropriate installation + verification test for the given OS. Usage: - python run_test.py / + python run_test.py / Examples: python run_test.py ubuntu/noble 18 14.0 From 6f875b4cb8206c8d59c3fc29adabf83e15f74662 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:09:19 +0300 Subject: [PATCH 09/17] run regression tests too --- test_package_installation/README.md | 22 ++-- .../common/run_multi_schedule.sh | 48 +++++++ .../test_basics.sh} | 37 ++++-- .../{test_deb.sh => deb/install_package.sh} | 17 +-- .../deb/install_regression_test_deps.sh | 47 +++++++ .../rpm/install_package.sh | 49 ++++++++ .../rpm/install_regression_test_deps.sh | 56 +++++++++ test_package_installation/run_test.py | 119 ++++++++++++------ test_package_installation/test_rpm.sh | 47 ------- 9 files changed, 330 insertions(+), 112 deletions(-) create mode 100644 test_package_installation/common/run_multi_schedule.sh rename test_package_installation/{setup_cluster_and_test.sh => common/test_basics.sh} (73%) rename test_package_installation/{test_deb.sh => deb/install_package.sh} (71%) create mode 100644 test_package_installation/deb/install_regression_test_deps.sh create mode 100755 test_package_installation/rpm/install_package.sh create mode 100644 test_package_installation/rpm/install_regression_test_deps.sh delete mode 100755 test_package_installation/test_rpm.sh diff --git a/test_package_installation/README.md b/test_package_installation/README.md index f3dc0003a..195b9b60c 100644 --- a/test_package_installation/README.md +++ b/test_package_installation/README.md @@ -2,29 +2,33 @@ Verifies that Citus packages can be installed from the package repository on all supported platforms. -Each test spins up a Docker container for the target OS, installs the PostgreSQL and Citus packages, -sets up a cluster, and runs very basic tests. +Each test: +* spins up a Docker container for the target OS +* installs the PostgreSQL and Citus packages +* sets up a cluster and runs very basic tests +* runs `make check-multi` regression tests from the Citus repository against the installed Citus version ## Running locally Requires **Python 3.10+** and **Docker**. No additional Python packages needed. ```bash -python3 test_package_installation/run_test.py +python3 test_package_installation/run_test.py ``` Examples: ```bash -python3 test_package_installation/run_test.py ubuntu/noble 18 14.0 -python3 test_package_installation/run_test.py el/9 17 14.0 -python3 test_package_installation/run_test.py debian/bookworm 16 14.0 +python3 test_package_installation/run_test.py ubuntu/noble 18 14.0.0 +python3 test_package_installation/run_test.py el/9 17 14.0.0 +python3 test_package_installation/run_test.py debian/bookworm 16 14.0.0 ``` ## Running via GitHub Actions You can manually trigger the workflow using [this GitHub Actions tab](https://github.com/citusdata/packaging/actions/workflows/test-package-installation.yml). -It automatically discovers the supported platforms, latest Citus version that we published -packages for, and compatible PostgreSQL versions from the `all-citus` branch, using -[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml) and [postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) files. +It asks for the Citus version to test, and then it automatically discovers the supported platforms and +compatible PostgreSQL versions from the `all-citus` branch, using +[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml) +and [postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) files. diff --git a/test_package_installation/common/run_multi_schedule.sh b/test_package_installation/common/run_multi_schedule.sh new file mode 100644 index 000000000..3f0f89268 --- /dev/null +++ b/test_package_installation/common/run_multi_schedule.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +# Runs "make check-multi" (multi_schedule). +# +# Expects the Citus source to be cloned at /citus and pg_regress +# to be available in the PostgreSQL binary path. +# +# Usage: run_multi_schedule.sh +# Example: run_multi_schedule.sh /usr/lib/postgresql/18/bin + +set -euo pipefail + +if [ -z "$1" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_BIN="$1" + +## suppress some of the regression test failures + +# On rpm based distros, Postgres package might be linked against a newer ICU +# than the one used to generate expected test output. To avoid test failures +# due to this, patch the expected output to match the newer ICU version. +# Without this, today pg18.sql fails. +echo 's/und-u-kc-true-ks-level1/und-u-kc-ks-level1/g' >> /citus/src/test/regress/bin/normalize.sed + +## run "make check-multi" + +export PATH="${PG_BIN}:${PATH}" + +cd /citus + +# we don't need lz4 and zstd as none of the tests in multi_schedule depend on them +./configure PG_CONFIG="${PG_BIN}/pg_config" --without-libcurl --without-lz4 --without-zstd + +chown -R postgres:postgres /citus + +echo "Running make check-multi ..." + +if ! su - postgres -c "make check-multi -C /citus/src/test/regress"; then + echo "make check-multi failed. Printing regression.diffs ..." + cat /citus/src/test/regress/regression.diffs + exit 1 +fi + +echo "make check-multi completed successfully." diff --git a/test_package_installation/setup_cluster_and_test.sh b/test_package_installation/common/test_basics.sh similarity index 73% rename from test_package_installation/setup_cluster_and_test.sh rename to test_package_installation/common/test_basics.sh index 9f888b0db..04f7f9168 100755 --- a/test_package_installation/setup_cluster_and_test.sh +++ b/test_package_installation/common/test_basics.sh @@ -3,22 +3,22 @@ # Sets up a multi-node Citus cluster, creates a distributed table, # rebalances shards, and verifies even distribution. # -# Called by test_deb.sh and test_rpm.sh after package installation. -# # Note: need to run this as root # -# Usage: setup_cluster_and_test.sh -# Example: setup_cluster_and_test.sh /usr/lib/postgresql/17/bin +# Usage: test_basics.sh +# Example: test_basics.sh 18 14.0.0 /usr/lib/postgresql/17/bin set -euo pipefail -if [ -z "$1" ]; then +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then echo "Error: some arguments are missing." >&2 - echo "Usage: $0 " >&2 + echo "Usage: $0 " >&2 exit 1 fi -PG_BIN="$1" +PG_MAJOR_VERSION="$1" +CITUS_FULL_VERSION="$2" +PG_BIN="$3" ## constants and helpers @@ -26,8 +26,7 @@ NODE_COUNT=3 SHARDS_PER_NODE=5 FIRST_NODE_PORT=9700 -run_psql_cmd() -{ +run_psql_cmd() { if [ -z "$1" ] || [ -z "$2" ]; then echo "Error: some arguments are missing." >&2 echo "Usage: run_psql_cmd " >&2 @@ -62,6 +61,26 @@ for i in $(seq 0 $((NODE_COUNT - 1))); do run_psql_cmd "$port_number" "CREATE EXTENSION citus;" done +## verify PG version + +pg_version=$(run_psql_cmd "$FIRST_NODE_PORT" "SELECT version();") +if [[ "$pg_version" != "PostgreSQL ${PG_MAJOR_VERSION}."* ]]; then + echo "Error: PostgreSQL version verification failed. Expected version to start with 'PostgreSQL ${PG_MAJOR_VERSION}.', got: $pg_version" >&2 + exit 1 +else + echo "Verified PostgreSQL version: $pg_version" +fi + +## verify Citus extension version + +citus_version=$(run_psql_cmd "$FIRST_NODE_PORT" "SHOW citus.version;") +if [[ "$citus_version" != "${CITUS_FULL_VERSION}"* ]]; then + echo "Error: Citus version verification failed. Expected version to start with '${CITUS_FULL_VERSION}', got: $citus_version" >&2 + exit 1 +else + echo "Verified Citus version: $citus_version" +fi + ## create a distributed table echo "Creating a distributed table ..." diff --git a/test_package_installation/test_deb.sh b/test_package_installation/deb/install_package.sh similarity index 71% rename from test_package_installation/test_deb.sh rename to test_package_installation/deb/install_package.sh index e0b08ff21..651c9ed1d 100755 --- a/test_package_installation/test_deb.sh +++ b/test_package_installation/deb/install_package.sh @@ -5,27 +5,28 @@ # # Note: need to run this as root # -# Usage: test_deb.sh -# Example: test_deb.sh 17 14.0 +# Usage: install_package.sh +# Example: install_package.sh 18 14.0.0 set -euo pipefail if [ -z "$1" ] || [ -z "$2" ]; then echo "Error: some arguments are missing." >&2 - echo "Usage: $0 " >&2 + echo "Usage: $0 " >&2 exit 1 fi PG_MAJOR_VERSION="$1" -CITUS_MAJOR_MINOR_VERSION="$2" +CITUS_FULL_VERSION="$2" export DEBIAN_FRONTEND=noninteractive +apt-get -y update + ## install postgres echo "Installing PostgreSQL ..." -apt-get -y update apt-get -y install curl ca-certificates install -d /usr/share/postgresql-common/pgdg @@ -42,8 +43,8 @@ echo "Installing Citus ..." curl --fail https://install.citusdata.com/community/deb.sh > add-citus-repo.sh bash add-citus-repo.sh -apt-get -y install postgresql-${PG_MAJOR_VERSION}-citus-${CITUS_MAJOR_MINOR_VERSION} -## setup a citus cluster and run verification tests +citus_major_minor_version="${CITUS_FULL_VERSION%.*}" +apt-get -y install postgresql-${PG_MAJOR_VERSION}-citus-${citus_major_minor_version}=${CITUS_FULL_VERSION}.citus-1 -/setup_cluster_and_test.sh "/usr/lib/postgresql/${PG_MAJOR_VERSION}/bin" +echo "PostgreSQL and Citus packages installed successfully." diff --git a/test_package_installation/deb/install_regression_test_deps.sh b/test_package_installation/deb/install_regression_test_deps.sh new file mode 100644 index 000000000..7d1b8dde9 --- /dev/null +++ b/test_package_installation/deb/install_regression_test_deps.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Installs dependencies needed to run Citus regression tests. +# +# Note: need to run this as root +# +# Usage: install_regression_test_deps.sh +# Example: install_regression_test_deps.sh 18 14.0.0 + +set -euo pipefail + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_MAJOR_VERSION="$1" +CITUS_FULL_VERSION="$2" + +export DEBIAN_FRONTEND=noninteractive + +apt-get -y update + +## install autoreconf + +echo "Installing autoreconf and other build tools ..." + +apt-get -y install autoconf automake libtool + +## install pg_regress + +echo "Installing pg_regress via postgresql-server-dev-${PG_MAJOR_VERSION} ..." + +apt-get -y install postgresql-server-dev-${PG_MAJOR_VERSION} + +## clone citus repository + +echo "Cloning Citus repository (tag v${CITUS_FULL_VERSION}) ..." + +CITUS_TAG="v${CITUS_FULL_VERSION}" +CITUS_REPO_DIR="/citus" + +apt-get -y install git build-essential +git clone --depth 1 --branch "$CITUS_TAG" https://github.com/citusdata/citus "$CITUS_REPO_DIR" + +echo "Regression test dependencies installed successfully." diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh new file mode 100755 index 000000000..731907b48 --- /dev/null +++ b/test_package_installation/rpm/install_package.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Installs PostgreSQL and Citus packages on EL/OL (RPM-based distros), then +# runs the cluster setup and verification test. +# +# Note: need to run this as root +# +# Usage: install_package.sh +# Example: install_package.sh 18 14.0.0 8 + +set -euo pipefail + +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_MAJOR_VERSION="$1" +CITUS_FULL_VERSION="$2" +OS_VERSION="$3" + +yum -y update + +## install postgres + +echo "Installing PostgreSQL ..." + +yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm + +# disable the built-in PostgreSQL module +yum -qy module disable postgresql + +yum install -y postgresql${PG_MAJOR_VERSION}-server + +## install citus + +echo "Installing Citus ..." + +curl --fail https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh +bash add-citus-repo.sh + +citus_major_minor_version="${CITUS_FULL_VERSION%.*}" +citus_major_minor_version_without_dot="${citus_major_minor_version//./}" + +# TODO: use --nogpgcheck for now +yum install -y --nogpgcheck citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} + +echo "PostgreSQL and Citus packages installed successfully." diff --git a/test_package_installation/rpm/install_regression_test_deps.sh b/test_package_installation/rpm/install_regression_test_deps.sh new file mode 100644 index 000000000..b49dc8c06 --- /dev/null +++ b/test_package_installation/rpm/install_regression_test_deps.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Installs dependencies needed to run Citus regression tests. +# +# Note: need to run this as root +# +# Usage: install_regression_test_deps.sh +# Example: install_regression_test_deps.sh 18 14.0.0 + +set -euo pipefail + +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: some arguments are missing." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +PG_MAJOR_VERSION="$1" +CITUS_FULL_VERSION="$2" + +yum -y update + +## install pg_regress + +echo "Installing pg_regress via postgresql${PG_MAJOR_VERSION}-devel ..." + +# enable PowerTools/CRB/CodeReady repo for dependencies like perl-IPC-Run +if yum repolist --all | grep -qi 'powertools'; then + yum config-manager --set-enabled powertools +elif yum repolist --all | grep -qi 'crb'; then + yum config-manager --set-enabled crb +elif yum repolist --all | grep -qi 'codeready'; then + repo_id=$(yum repolist --all | grep -i 'codeready' | awk '{print $1}') + yum config-manager --set-enabled "$repo_id" +fi + +yum install -y postgresql${PG_MAJOR_VERSION}-devel + +## install contrib extensions needed by regression tests + +echo "Installing postgresql${PG_MAJOR_VERSION}-contrib ..." + +yum install -y postgresql${PG_MAJOR_VERSION}-contrib + +## clone citus repository + +echo "Cloning Citus repository (tag v${CITUS_FULL_VERSION}) ..." + +CITUS_TAG="v${CITUS_FULL_VERSION}" +CITUS_REPO_DIR="/citus" + +yum install -y git +yum groupinstall -y "Development Tools" +git clone --depth 1 --branch "$CITUS_TAG" https://github.com/citusdata/citus "$CITUS_REPO_DIR" + +echo "Regression test dependencies installed successfully." diff --git a/test_package_installation/run_test.py b/test_package_installation/run_test.py index a2bba7a6f..3f45f60a5 100644 --- a/test_package_installation/run_test.py +++ b/test_package_installation/run_test.py @@ -3,14 +3,14 @@ Docker-based package installation tester. Pulls a Docker image, starts a container, copies the test scripts into it, -and runs the appropriate installation + verification test for the given OS. +and runs the appropriate installation + verification tests for the given OS. Usage: - python run_test.py / + python run_test.py / Examples: - python run_test.py ubuntu/noble 18 14.0 - python run_test.py el/9 18 14.0 + python run_test.py ubuntu/noble 18 14.0.0 + python run_test.py el/9 18 14.0.0 """ import os @@ -23,12 +23,14 @@ # environments like CI). sys.stdout.reconfigure(line_buffering=True) + def pull_docker_image(image_name: str) -> bool: print(f"Pulling Docker image: {image_name}") try: - result = subprocess.run(["docker", "pull", image_name], - stdout=sys.stdout, stderr=sys.stdout) + result = subprocess.run( + ["docker", "pull", image_name], stdout=sys.stdout, stderr=sys.stdout + ) if result.returncode == 0: print(f"Successfully pulled image: {image_name}") @@ -40,6 +42,7 @@ def pull_docker_image(image_name: str) -> bool: print(f"Error during image pull: {e}", file=sys.stderr) return False + def start_container(image_name: str) -> Optional[str]: print(f"Starting container from image: {image_name}") @@ -47,7 +50,7 @@ def start_container(image_name: str) -> Optional[str]: result = subprocess.run( ["docker", "run", "-d", image_name, "sleep", "infinity"], capture_output=True, - text=True + text=True, ) if result.returncode == 0: @@ -61,13 +64,17 @@ def start_container(image_name: str) -> Optional[str]: print(f"Error during container start: {e}", file=sys.stderr) return None -def copy_into_container(container_id: str, local_path: str, container_path: str) -> bool: + +def copy_into_container( + container_id: str, local_path: str, container_path: str +) -> bool: print(f"Copying {local_path} to container {container_id}:{container_path}") try: result = subprocess.run( ["docker", "cp", local_path, f"{container_id}:{container_path}"], - stdout=sys.stdout, stderr=sys.stdout + stdout=sys.stdout, + stderr=sys.stdout, ) if result.returncode == 0: @@ -88,7 +95,7 @@ def run_command_in_container(container_id: str, command: str) -> bool: result = subprocess.run( ["docker", "exec", container_id, "bash", "-c", command], stdout=sys.stdout, - stderr=sys.stdout + stderr=sys.stdout, ) return result.returncode == 0 except Exception as e: @@ -96,23 +103,41 @@ def run_command_in_container(container_id: str, command: str) -> bool: return False -def main(os_name: str, os_version: str, pg_major_version: str, citus_major_minor_version: str): +def main(os_name: str, os_version: str, pg_major_version: str, citus_full_version: str): if os_name == "ubuntu" or os_name == "debian": + os_specific_dir = "deb" + install_package_command = ( + f"bash /install_package.sh {pg_major_version} {citus_full_version}" + ) + pg_binary_path = f"/usr/lib/postgresql/{pg_major_version}/bin" image_name = f"{os_name}:{os_version}" - test_script_name = "test_deb.sh" - test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version}" - elif os_name == "el": - image_name = f"almalinux:{os_version}" - test_script_name = "test_rpm.sh" - test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version} {os_version}" - elif os_name == "ol": - image_name = f"oraclelinux:{os_version}" - test_script_name = "test_rpm.sh" - test_command = f"bash /{test_script_name} {pg_major_version} {citus_major_minor_version} {os_version}" + elif os_name == "el" or os_name == "ol": + os_specific_dir = "rpm" + install_package_command = f"bash /install_package.sh {pg_major_version} {citus_full_version} {os_version}" + pg_binary_path = f"/usr/pgsql-{pg_major_version}/bin" + image_name = ( + f"almalinux:{os_version}" + if os_name == "el" + else f"oraclelinux:{os_version}" + ) else: print(f"Unsupported OS: {os_name}. Exiting.", file=sys.stderr) sys.exit(1) + script_relative_paths = [ + f"{os_specific_dir}/install_package.sh", + "common/test_basics.sh", + f"{os_specific_dir}/install_regression_test_deps.sh", + "common/run_multi_schedule.sh", + ] + + commands = [ + install_package_command, + f"bash /test_basics.sh {pg_major_version} {citus_full_version} {pg_binary_path}", + f"bash /install_regression_test_deps.sh {pg_major_version} {citus_full_version}", + f"bash /run_multi_schedule.sh {pg_binary_path}", + ] + # Pull the Docker image if not pull_docker_image(image_name): print("Failed to pull Docker image. Exiting.", file=sys.stderr) @@ -124,35 +149,42 @@ def main(os_name: str, os_version: str, pg_major_version: str, citus_major_minor sys.exit(1) try: - # Copy the test scripts into the container script_dir = os.path.dirname(os.path.abspath(__file__)) - for script_name in ["setup_cluster_and_test.sh", test_script_name]: - script_path = os.path.join(script_dir, script_name) - if not copy_into_container(container_id, script_path, f"/{script_name}"): - print(f"Failed to copy {script_name} into container. Exiting.", file=sys.stderr) + # Copy all necessary scripts into the container first + for p in script_relative_paths: + script_path = os.path.join(script_dir, p) + if not copy_into_container(container_id, script_path, "/"): + print(f"Failed to copy {p} into container. Exiting.", file=sys.stderr) sys.exit(1) - # Execute the test script with the provided parameters inside the container - print(f"Executing command in container: {test_command}") - success = run_command_in_container(container_id, test_command) - if not success: - print("Failed to execute command in container. Exiting.", file=sys.stderr) - sys.exit(1) + # Execute the scripts in order + for c in commands: + print(f"Running {c} in container...") + if not run_command_in_container(container_id, c): + print(f"Failed to execute {c} in container. Exiting.", file=sys.stderr) + sys.exit(1) finally: # Cleanup: force-remove the container (stops it if still running) print(f"Removing container {container_id}") try: - subprocess.run(["docker", "rm", "-f", container_id], - stdout=sys.stdout, stderr=sys.stdout) + subprocess.run( + ["docker", "rm", "-f", container_id], + stdout=sys.stdout, + stderr=sys.stdout, + ) print(f"Container {container_id} removed successfully.") except Exception as e: print(f"Error removing container: {e}", file=sys.stderr) + if __name__ == "__main__": if len(sys.argv) != 4: - print("Usage: python run_test.py ", file=sys.stderr) - print("Example: python run_test.py ubuntu/noble 18 14.0", file=sys.stderr) + print( + "Usage: python run_test.py ", + file=sys.stderr, + ) + print("Example: python run_test.py ubuntu/noble 18 14.0.0", file=sys.stderr) sys.exit(1) os_name, os_version = sys.argv[1].split("/") @@ -160,11 +192,20 @@ def main(os_name: str, os_version: str, pg_major_version: str, citus_major_minor citus_version = sys.argv[3] if not postgres_version.isdigit(): - print("PostgreSQL major version must be a number (e.g., 18). Exiting.", file=sys.stderr) + print( + "PostgreSQL major version must be a number (e.g., 18). Exiting.", + file=sys.stderr, + ) sys.exit(1) - if not (len(citus_version.split(".")) == 2 and all(p.isdigit() for p in citus_version.split("."))): - print("Citus version must be in the format major.minor (e.g., 14.0). Exiting.", file=sys.stderr) + if not ( + len(citus_version.split(".")) == 3 + and all(p.isdigit() for p in citus_version.split(".")) + ): + print( + "Citus version must be in the format major.minor.patch (e.g., 14.0.0). Exiting.", + file=sys.stderr, + ) sys.exit(1) main(os_name, os_version, postgres_version, citus_version) diff --git a/test_package_installation/test_rpm.sh b/test_package_installation/test_rpm.sh deleted file mode 100755 index 2d3521ecf..000000000 --- a/test_package_installation/test_rpm.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# Installs PostgreSQL and Citus packages on EL/OL (RPM-based distros), then -# runs the cluster setup and verification test. -# -# Note: need to run this as root -# -# Usage: test_rpm.sh -# Example: test_rpm.sh 17 14.0 9 - -set -euo pipefail - -if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then - echo "Error: some arguments are missing." >&2 - echo "Usage: $0 " >&2 - exit 1 -fi - -PG_MAJOR_VERSION="$1" -CITUS_MAJOR_MINOR_VERSION="$2" -OS_VERSION="$3" - -## install postgres - -echo "Installing PostgreSQL ..." - -dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm - -# disable the built-in PostgreSQL module -dnf -qy module disable postgresql - -dnf -y update -dnf install -y postgresql${PG_MAJOR_VERSION}-server - -## install citus - -echo "Installing Citus ..." - -curl --fail https://install.citusdata.com/community/rpm.sh > add-citus-repo.sh -bash add-citus-repo.sh - -citus_major_minor_version_without_dot="${CITUS_MAJOR_MINOR_VERSION//./}" -dnf install -y citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION} - -## setup a citus cluster and run verification tests - -/setup_cluster_and_test.sh "/usr/pgsql-${PG_MAJOR_VERSION}/bin" From f58ddb8ecca5f61a80297b50905a5b26213596bd Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:13:36 +0300 Subject: [PATCH 10/17] read citus version from pkgvars --- .github/workflows/test-package-installation.yml | 7 ++++--- test_package_installation/README.md | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index c0b4bca79..948a88520 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -35,13 +35,14 @@ jobs: echo "Discovered platforms: ${platforms}" echo "platforms=${platforms}" >> "$GITHUB_OUTPUT" - - name: Resolve Citus & PG versions from postgres-matrix.yml + - name: Resolve Citus & PG versions id: resolve_versions run: | + git show "origin/${SOURCE_BRANCH}:pkgvars" > /tmp/pkgvars git show "origin/${SOURCE_BRANCH}:postgres-matrix.yml" > /tmp/postgres-matrix.yml - # Latest entry = last element in version_matrix - citus_version=$(yq '.version_matrix[-1] | keys | .[0]' /tmp/postgres-matrix.yml) + # Extract version from pkglatest (e.g. "14.0.0.citus-1" -> "14.0.0") + citus_version=$(grep '^pkglatest=' /tmp/pkgvars | sed 's/^pkglatest=//;s/\.citus-.*//') pg_versions=$( yq -o=json \ diff --git a/test_package_installation/README.md b/test_package_installation/README.md index 195b9b60c..b2b418268 100644 --- a/test_package_installation/README.md +++ b/test_package_installation/README.md @@ -30,5 +30,6 @@ You can manually trigger the workflow using [this GitHub Actions tab](https://gi It asks for the Citus version to test, and then it automatically discovers the supported platforms and compatible PostgreSQL versions from the `all-citus` branch, using -[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml) -and [postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) files. +[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml), +[postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) and +[pkgvars](https://github.com/citusdata/packaging/blob/all-citus/pkgvars) files. From 2c207c94b0fa6d302664080049c8b4ba5b1c2b84 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:15:08 +0300 Subject: [PATCH 11/17] comment --- .github/workflows/test-package-installation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index 948a88520..98a5c34fe 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: env: - # Branch whose build-package.yml and postgres-matrix.yml are the source of truth + # Branch whose build-package.yml, postgres-matrix.yml and pkgvars files are the source of truth SOURCE_BRANCH: "all-citus" jobs: From 2a7022a488a7946499fdf37b84223d72b9ac63cd Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:29:11 +0300 Subject: [PATCH 12/17] fix --- .github/workflows/test-package-installation.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-package-installation.yml b/.github/workflows/test-package-installation.yml index 98a5c34fe..f2f1b298f 100644 --- a/.github/workflows/test-package-installation.yml +++ b/.github/workflows/test-package-installation.yml @@ -44,9 +44,12 @@ jobs: # Extract version from pkglatest (e.g. "14.0.0.citus-1" -> "14.0.0") citus_version=$(grep '^pkglatest=' /tmp/pkgvars | sed 's/^pkglatest=//;s/\.citus-.*//') + # postgres-matrix.yml keys use major.minor (e.g. "14.0"), strip patch + citus_major_minor=$(echo "${citus_version}" | cut -d. -f1,2) + pg_versions=$( yq -o=json \ - ".version_matrix[-1].\"${citus_version}\".postgres_versions" \ + ".version_matrix[-1].\"${citus_major_minor}\".postgres_versions" \ /tmp/postgres-matrix.yml \ | jq -c '[.[] | tostring]' ) From 6480bfad03bd0858346ba4132ac3c51e781d031a Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:42:19 +0300 Subject: [PATCH 13/17] more --- test_package_installation/README.md | 10 +++++----- test_package_installation/rpm/install_package.sh | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test_package_installation/README.md b/test_package_installation/README.md index b2b418268..417505c81 100644 --- a/test_package_installation/README.md +++ b/test_package_installation/README.md @@ -28,8 +28,8 @@ python3 test_package_installation/run_test.py debian/bookworm 16 14.0.0 You can manually trigger the workflow using [this GitHub Actions tab](https://github.com/citusdata/packaging/actions/workflows/test-package-installation.yml). -It asks for the Citus version to test, and then it automatically discovers the supported platforms and -compatible PostgreSQL versions from the `all-citus` branch, using -[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml), -[postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) and -[pkgvars](https://github.com/citusdata/packaging/blob/all-citus/pkgvars) files. +It automatically discovers the supported platforms, latest Citus version that we published +packages for, and compatible PostgreSQL versions from the `all-citus` branch, using +[pkgvars](https://github.com/citusdata/packaging/blob/all-citus/pkgvars), +[.github/workflows/build-package.yml](https://github.com/citusdata/packaging/blob/all-citus/.github/workflows/build-package.yml) and +[postgres-matrix.yml](https://github.com/citusdata/packaging/blob/all-citus/postgres-matrix.yml) files. diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh index 731907b48..862c8280d 100755 --- a/test_package_installation/rpm/install_package.sh +++ b/test_package_installation/rpm/install_package.sh @@ -43,7 +43,6 @@ bash add-citus-repo.sh citus_major_minor_version="${CITUS_FULL_VERSION%.*}" citus_major_minor_version_without_dot="${citus_major_minor_version//./}" -# TODO: use --nogpgcheck for now yum install -y --nogpgcheck citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} echo "PostgreSQL and Citus packages installed successfully." From bdfb04a1496714eefa2f508fe5da3f75e1afee72 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:45:45 +0300 Subject: [PATCH 14/17] more --- test_package_installation/rpm/install_package.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh index 862c8280d..3560537d7 100755 --- a/test_package_installation/rpm/install_package.sh +++ b/test_package_installation/rpm/install_package.sh @@ -43,6 +43,6 @@ bash add-citus-repo.sh citus_major_minor_version="${CITUS_FULL_VERSION%.*}" citus_major_minor_version_without_dot="${citus_major_minor_version//./}" -yum install -y --nogpgcheck citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} +yum install -y citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} echo "PostgreSQL and Citus packages installed successfully." From d35dee871ee11de32c301a54b35e6f282b5ae8ac Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 15:48:49 +0300 Subject: [PATCH 15/17] more --- test_package_installation/rpm/install_package.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh index 3560537d7..731907b48 100755 --- a/test_package_installation/rpm/install_package.sh +++ b/test_package_installation/rpm/install_package.sh @@ -43,6 +43,7 @@ bash add-citus-repo.sh citus_major_minor_version="${CITUS_FULL_VERSION%.*}" citus_major_minor_version_without_dot="${citus_major_minor_version//./}" -yum install -y citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} +# TODO: use --nogpgcheck for now +yum install -y --nogpgcheck citus${citus_major_minor_version_without_dot}_${PG_MAJOR_VERSION}-${CITUS_FULL_VERSION}.citus-1.el${OS_VERSION} echo "PostgreSQL and Citus packages installed successfully." From 4c3ab3a79c4739594d11d312f8aa3c2f4c3d9a5a Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Thu, 12 Feb 2026 21:46:05 +0300 Subject: [PATCH 16/17] more --- test_package_installation/common/test_basics.sh | 16 ++++++++-------- test_package_installation/deb/install_package.sh | 3 +-- test_package_installation/rpm/install_package.sh | 3 +-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/test_package_installation/common/test_basics.sh b/test_package_installation/common/test_basics.sh index 04f7f9168..b3c068a9f 100755 --- a/test_package_installation/common/test_basics.sh +++ b/test_package_installation/common/test_basics.sh @@ -5,19 +5,19 @@ # # Note: need to run this as root # -# Usage: test_basics.sh +# Usage: test_basics.sh # Example: test_basics.sh 18 14.0.0 /usr/lib/postgresql/17/bin set -euo pipefail if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then echo "Error: some arguments are missing." >&2 - echo "Usage: $0 " >&2 + echo "Usage: $0 " >&2 exit 1 fi -PG_MAJOR_VERSION="$1" -CITUS_FULL_VERSION="$2" +EXPECTED_PG_MAJOR_VERSION="$1" +EXPECTED_CITUS_FULL_VERSION="$2" PG_BIN="$3" ## constants and helpers @@ -64,8 +64,8 @@ done ## verify PG version pg_version=$(run_psql_cmd "$FIRST_NODE_PORT" "SELECT version();") -if [[ "$pg_version" != "PostgreSQL ${PG_MAJOR_VERSION}."* ]]; then - echo "Error: PostgreSQL version verification failed. Expected version to start with 'PostgreSQL ${PG_MAJOR_VERSION}.', got: $pg_version" >&2 +if [[ "$pg_version" != "PostgreSQL ${EXPECTED_PG_MAJOR_VERSION}."* ]]; then + echo "Error: PostgreSQL version verification failed. Expected version to start with 'PostgreSQL ${EXPECTED_PG_MAJOR_VERSION}.', got: $pg_version" >&2 exit 1 else echo "Verified PostgreSQL version: $pg_version" @@ -74,8 +74,8 @@ fi ## verify Citus extension version citus_version=$(run_psql_cmd "$FIRST_NODE_PORT" "SHOW citus.version;") -if [[ "$citus_version" != "${CITUS_FULL_VERSION}"* ]]; then - echo "Error: Citus version verification failed. Expected version to start with '${CITUS_FULL_VERSION}', got: $citus_version" >&2 +if [[ "$citus_version" != "${EXPECTED_CITUS_FULL_VERSION}"* ]]; then + echo "Error: Citus version verification failed. Expected version to start with '${EXPECTED_CITUS_FULL_VERSION}', got: $citus_version" >&2 exit 1 else echo "Verified Citus version: $citus_version" diff --git a/test_package_installation/deb/install_package.sh b/test_package_installation/deb/install_package.sh index 651c9ed1d..d3f91c29c 100755 --- a/test_package_installation/deb/install_package.sh +++ b/test_package_installation/deb/install_package.sh @@ -1,7 +1,6 @@ #!/bin/bash -# Installs PostgreSQL and Citus packages on Debian/Ubuntu, then runs -# the cluster setup and verification test. +# Installs PostgreSQL and Citus packages on a Debian/Ubuntu system. # # Note: need to run this as root # diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh index 731907b48..b2d083e26 100755 --- a/test_package_installation/rpm/install_package.sh +++ b/test_package_installation/rpm/install_package.sh @@ -1,7 +1,6 @@ #!/bin/bash -# Installs PostgreSQL and Citus packages on EL/OL (RPM-based distros), then -# runs the cluster setup and verification test. +# Installs PostgreSQL and Citus packages on an EL/OL (RPM-based) system. # # Note: need to run this as root # From d90320a595655bbc64b71d49753d26e6fd26b9a6 Mon Sep 17 00:00:00 2001 From: Onur Tirtir Date: Fri, 13 Feb 2026 15:59:30 +0300 Subject: [PATCH 17/17] more --- test_package_installation/common/run_multi_schedule.sh | 2 +- test_package_installation/common/test_basics.sh | 6 +++--- test_package_installation/deb/install_package.sh | 2 +- .../deb/install_regression_test_deps.sh | 2 +- test_package_installation/rpm/install_package.sh | 2 +- .../rpm/install_regression_test_deps.sh | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test_package_installation/common/run_multi_schedule.sh b/test_package_installation/common/run_multi_schedule.sh index 3f0f89268..8f57008a5 100644 --- a/test_package_installation/common/run_multi_schedule.sh +++ b/test_package_installation/common/run_multi_schedule.sh @@ -10,7 +10,7 @@ set -euo pipefail -if [ -z "$1" ]; then +if [ "$#" -ne 1 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1 diff --git a/test_package_installation/common/test_basics.sh b/test_package_installation/common/test_basics.sh index b3c068a9f..d111a1556 100755 --- a/test_package_installation/common/test_basics.sh +++ b/test_package_installation/common/test_basics.sh @@ -10,7 +10,7 @@ set -euo pipefail -if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then +if [ "$#" -ne 3 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1 @@ -27,7 +27,7 @@ SHARDS_PER_NODE=5 FIRST_NODE_PORT=9700 run_psql_cmd() { - if [ -z "$1" ] || [ -z "$2" ]; then + if [ "$#" -ne 2 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: run_psql_cmd " >&2 exit 1 @@ -123,7 +123,7 @@ result=$( if [ "$result" = "t" ]; then echo "Verified cluster creation, distributed table creation and shard rebalancing. Shards are distributed evenly across nodes." else - echo "Error: Citus cluster creation failed. Shards are not distributed evenly across nodes, see below for details:" >&2 + echo "Error: Failed. Shards are not distributed evenly across nodes, see below for details:" >&2 run_psql_cmd "$FIRST_NODE_PORT" " SELECT nodeport, COUNT(shardid) AS cnt diff --git a/test_package_installation/deb/install_package.sh b/test_package_installation/deb/install_package.sh index d3f91c29c..2e700dc08 100755 --- a/test_package_installation/deb/install_package.sh +++ b/test_package_installation/deb/install_package.sh @@ -9,7 +9,7 @@ set -euo pipefail -if [ -z "$1" ] || [ -z "$2" ]; then +if [ "$#" -ne 2 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1 diff --git a/test_package_installation/deb/install_regression_test_deps.sh b/test_package_installation/deb/install_regression_test_deps.sh index 7d1b8dde9..03e73b105 100644 --- a/test_package_installation/deb/install_regression_test_deps.sh +++ b/test_package_installation/deb/install_regression_test_deps.sh @@ -9,7 +9,7 @@ set -euo pipefail -if [ -z "$1" ] || [ -z "$2" ]; then +if [ "$#" -ne 2 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1 diff --git a/test_package_installation/rpm/install_package.sh b/test_package_installation/rpm/install_package.sh index b2d083e26..d257d144a 100755 --- a/test_package_installation/rpm/install_package.sh +++ b/test_package_installation/rpm/install_package.sh @@ -9,7 +9,7 @@ set -euo pipefail -if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then +if [ "$#" -ne 3 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1 diff --git a/test_package_installation/rpm/install_regression_test_deps.sh b/test_package_installation/rpm/install_regression_test_deps.sh index b49dc8c06..7c77f2bfc 100644 --- a/test_package_installation/rpm/install_regression_test_deps.sh +++ b/test_package_installation/rpm/install_regression_test_deps.sh @@ -9,7 +9,7 @@ set -euo pipefail -if [ -z "$1" ] || [ -z "$2" ]; then +if [ "$#" -ne 2 ]; then echo "Error: some arguments are missing." >&2 echo "Usage: $0 " >&2 exit 1