You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2026/08/24 23:23:09 UTC
(pulsar) branch master updated: [improve][ci] Run the Python function instance tests in CI (#26399)
This is an automated email from the ASF dual-hosted git repository.
merlimat pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new 98908722647c [improve][ci] Run the Python function instance tests in CI (#26399)
98908722647c is described below
commit 98908722647c7e3c867efe8e246c840e0e1a9706
Author: David Kjerrumgaard <35...@users.noreply.github.com>
AuthorDate: Mon Aug 24 16:23:02 2026 -0700
[improve][ci] Run the Python function instance tests in CI (#26399)
---
.github/workflows/ci-python-functions.yaml | 90 ++++++++++++++++++++++
.../src/scripts/run_python_instance_tests.sh | 54 +++++++++++--
2 files changed, 137 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/ci-python-functions.yaml b/.github/workflows/ci-python-functions.yaml
new file mode 100644
index 000000000000..d02ed5303ebd
--- /dev/null
+++ b/.github/workflows/ci-python-functions.yaml
@@ -0,0 +1,90 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+name: CI - Python Functions
+on:
+ pull_request:
+ branches:
+ - master
+ paths:
+ - '.github/workflows/**'
+ - 'pulsar-functions/instance/src/main/python/**'
+ - 'pulsar-functions/instance/src/test/python/**'
+ - 'pulsar-functions/instance/src/scripts/**'
+ workflow_dispatch:
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ preconditions:
+ name: Preconditions
+ runs-on: ubuntu-24.04
+ outputs:
+ docs_only: ${{ steps.check_changes.outputs.docs_only }}
+ steps:
+ - name: checkout
+ uses: actions/checkout@v6
+
+ - name: Detect changed files
+ id: changes
+ uses: apache/pulsar-test-infra/paths-filter@master
+ with:
+ filters: .github/changes-filter.yaml
+ list-files: csv
+
+ - name: Check changed files
+ id: check_changes
+ run: |
+ if [[ "${GITHUB_EVENT_NAME}" != "schedule" ]]; then
+ echo "docs_only=${{ fromJSON(steps.changes.outputs.all_count) == fromJSON(steps.changes.outputs.docs_count) && fromJSON(steps.changes.outputs.docs_count) > 0 }}" >> $GITHUB_OUTPUT
+ else
+ echo docs_only=false >> $GITHUB_OUTPUT
+ fi
+
+ - name: Check if the PR is ready for running CI
+ if: ${{ steps.check_changes.outputs.docs_only != 'true' && github.repository == 'apache/pulsar' && github.event_name == 'pull_request' }}
+ uses: ./.github/actions/check-pr-ready-to-test
+
+ instance-tests:
+ needs: preconditions
+ if: ${{ needs.preconditions.outputs.docs_only != 'true' }}
+ name: Python ${{ matrix.python-version }} Functions instance tests
+ runs-on: ubuntu-24.04
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ['3.12', '3.13']
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v6
+
+ - name: Tune Runner VM
+ uses: ./.github/actions/tune-runner-vm
+
+ - name: Set up Python
+ uses: actions/setup-python@v6
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Run Python instance tests
+ run: |
+ ./pulsar-functions/instance/src/scripts/run_python_instance_tests.sh
diff --git a/pulsar-functions/instance/src/scripts/run_python_instance_tests.sh b/pulsar-functions/instance/src/scripts/run_python_instance_tests.sh
index 11cec15e14c0..b0a0850de204 100755
--- a/pulsar-functions/instance/src/scripts/run_python_instance_tests.sh
+++ b/pulsar-functions/instance/src/scripts/run_python_instance_tests.sh
@@ -18,14 +18,54 @@
# under the License.
#
-
-# Make sure dependencies are installed
-pip3 install mock --user
-pip3 install protobuf==6.31.1 --user
-pip3 install fastavro --user
+set -o errexit
+set -o nounset
+set -o pipefail
CUR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
PULSAR_HOME="$( cd "$CUR_DIR/../../../../" >/dev/null && pwd )"
-# run instance tests
-PULSAR_HOME=${PULSAR_HOME} PYTHONPATH=${PULSAR_HOME}/pulsar-functions/instance/src/main/python python3 -m unittest discover -v -s ${PULSAR_HOME}/pulsar-functions/instance/src/test/python
+PYTHON_BIN=${PYTHON_BIN:-python3}
+
+# Keep these aligned with the Python dependencies installed in docker/pulsar/Dockerfile: the tests
+# should run against the same versions the Python instance runs with in production. pulsar-client's
+# "all" extra brings in apache-bookkeeper-client, fastavro, prometheus_client and ratelimit, which
+# the instance imports.
+PULSAR_CLIENT_PYTHON_VERSION=${PULSAR_CLIENT_PYTHON_VERSION:-3.13.0}
+PYTHON_GRPCIO_VERSION=${PYTHON_GRPCIO_VERSION:-1.78.0}
+PYTHON_PROTOBUF_VERSION=${PYTHON_PROTOBUF_VERSION:-6.33.6}
+
+# Set SKIP_PYTHON_DEPS=true to run against an environment you have prepared yourself. Otherwise the
+# dependencies are installed into whatever ${PYTHON_BIN} resolves to, so run this inside a
+# virtualenv unless you want them on your system interpreter.
+if [[ "${SKIP_PYTHON_DEPS:-false}" != "true" ]]; then
+ ${PYTHON_BIN} -m pip install \
+ mock \
+ "pulsar-client[all]==${PULSAR_CLIENT_PYTHON_VERSION}" \
+ "grpcio==${PYTHON_GRPCIO_VERSION}" \
+ "protobuf==${PYTHON_PROTOBUF_VERSION}"
+fi
+
+TEST_DIR="${PULSAR_HOME}/pulsar-functions/instance/src/test/python"
+export PULSAR_HOME
+export PYTHONPATH="${PULSAR_HOME}/pulsar-functions/instance/src/main/python"
+
+# Each test module runs in its own interpreter. They cannot share one: test_python_instance replaces
+# prometheus_client with a mock in sys.modules, which breaks test_python_instance_main when it later
+# imports the real one, and the two modules also register the same Prometheus metrics, so a shared
+# registry rejects the duplicates.
+failed_modules=()
+for test_file in "${TEST_DIR}"/test_*.py; do
+ module_name="$(basename "${test_file}" .py)"
+ echo "=== Running ${module_name} ==="
+ if ! (cd "${TEST_DIR}" && ${PYTHON_BIN} -m unittest -v "${module_name}"); then
+ failed_modules+=("${module_name}")
+ fi
+done
+
+if [[ ${#failed_modules[@]} -gt 0 ]]; then
+ echo "Failed test modules: ${failed_modules[*]}" >&2
+ exit 1
+fi
+
+echo "All Python instance test modules passed"