Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cirrus.star
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def compute_environment_vars():
# REPO_CI_AUTOMATIC_TRIGGER_TASKS="task_name other_task" under "Repository
# Settings" on Cirrus CI's website.

default_manual_trigger_tasks = ['mingw', 'netbsd', 'openbsd']
default_manual_trigger_tasks = []

repo_ci_automatic_trigger_tasks = env.get('REPO_CI_AUTOMATIC_TRIGGER_TASKS', '')
for task in default_manual_trigger_tasks:
Expand Down
59 changes: 43 additions & 16 deletions .cirrus.tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ env:

# target to test, for all but windows
CHECK: check-world PROVE_FLAGS=$PROVE_FLAGS
CHECKFLAGS: -Otarget
# TODO were we avoiding --keep-going on purpose?
CHECKFLAGS: -Otarget --keep-going
PROVE_FLAGS: --timer
# Build test dependencies as part of the build step, to see compiler
# errors/warnings in one place.
MBUILD_TARGET: all testprep
MTEST_ARGS: --print-errorlogs --no-rebuild -C build
MTEST_SUITES: --suite setup --suite pytest --suite ssl
PGCTLTIMEOUT: 120 # avoids spurious failures during parallel tests
TEMP_CONFIG: ${CIRRUS_WORKING_DIR}/src/tools/ci/pg_ci_base.conf
PG_TEST_EXTRA: kerberos ldap ssl libpq_encryption load_balance oauth
Expand All @@ -44,6 +46,7 @@ env:
-Dldap=enabled
-Dssl=openssl
-Dtap_tests=enabled
-Dpytest=enabled
-Dplperl=enabled
-Dplpython=enabled
-Ddocs=enabled
Expand Down Expand Up @@ -222,7 +225,10 @@ task:
chown root:postgres /tmp/cores
sysctl kern.corefile='/tmp/cores/%N.%P.core'
setup_additional_packages_script: |
#pkg install -y ...
pkg install -y \
py311-cryptography \
py311-packaging \
py311-pytest

# NB: Intentionally build without -Dllvm. The freebsd image size is already
# large enough to make VM startup slow, and even without llvm freebsd
Expand All @@ -242,7 +248,7 @@ task:
test_world_script: |
su postgres <<-EOF
ulimit -c unlimited
meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
meson test $MTEST_ARGS --num-processes ${TEST_JOBS} ${MTEST_SUITES}
EOF

# test runningcheck, freebsd chosen because it's currently fast enough
Expand Down Expand Up @@ -311,7 +317,11 @@ task:
-Dpam=enabled

setup_additional_packages_script: |
#pkgin -y install ...
pkgin -y install \
py312-cryptography \
py312-packaging \
py312-test
ln -s /usr/pkg/bin/pytest-3.12 /usr/pkg/bin/pytest
<<: *netbsd_task_template

- name: OpenBSD - Meson
Expand All @@ -322,6 +332,7 @@ task:
OS_NAME: openbsd
IMAGE_FAMILY: pg-ci-openbsd-postgres
PKGCONFIG_PATH: '/usr/lib/pkgconfig:/usr/local/lib/pkgconfig'
TERM: # TODO why does pytest print ANSI escapes on OpenBSD?

MESON_FEATURES: >-
-Dbsd_auth=enabled
Expand All @@ -330,7 +341,10 @@ task:
-Duuid=e2fs

setup_additional_packages_script: |
#pkg_add -I ...
pkg_add -I \
py3-cryptography \
py3-packaging \
py3-test
# Always core dump to ${CORE_DUMP_DIR}
set_core_dump_script: sysctl -w kern.nosuidcoredump=2
<<: *openbsd_task_template
Expand Down Expand Up @@ -378,7 +392,7 @@ task:
# Otherwise tests will fail on OpenBSD, due to inability to start enough
# processes.
ulimit -p 256
meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
meson test $MTEST_ARGS --num-processes ${TEST_JOBS} ${MTEST_SUITES}
EOF

on_failure:
Expand Down Expand Up @@ -489,8 +503,11 @@ task:
EOF

setup_additional_packages_script: |
#apt-get update
#DEBIAN_FRONTEND=noninteractive apt-get -y install ...
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get -y install \
python3-cryptography \
python3-packaging \
python3-pytest

matrix:
# SPECIAL:
Expand All @@ -513,14 +530,15 @@ task:
su postgres <<-EOF
./configure \
--enable-cassert --enable-injection-points --enable-debug \
--enable-tap-tests --enable-nls \
--enable-tap-tests --enable-pytest --enable-nls \
--with-segsize-blocks=6 \
--with-libnuma \
--with-liburing \
\
${LINUX_CONFIGURE_FEATURES} \
\
CLANG="ccache clang-16"
CLANG="ccache clang-16" \
PYTEST="env LD_PRELOAD=/lib/x86_64-linux-gnu/libasan.so.8 pytest"
EOF
build_script: su postgres -c "make -s -j${BUILD_JOBS} world-bin"
upload_caches: ccache
Expand Down Expand Up @@ -588,7 +606,7 @@ task:
test_world_script: |
su postgres <<-EOF
ulimit -c unlimited
meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
meson test $MTEST_ARGS --num-processes ${TEST_JOBS} ${MTEST_SUITES}
EOF
# so that we don't upload 64bit logs if 32bit fails
rm -rf build/
Expand All @@ -600,7 +618,7 @@ task:
test_world_32_script: |
su postgres <<-EOF
ulimit -c unlimited
PYTHONCOERCECLOCALE=0 LANG=C meson test $MTEST_ARGS -C build-32 --num-processes ${TEST_JOBS}
PYTHONCOERCECLOCALE=0 LANG=C meson test $MTEST_ARGS -C build-32 --num-processes ${TEST_JOBS} ${MTEST_SUITES}
EOF

on_failure:
Expand Down Expand Up @@ -630,6 +648,7 @@ task:
CIRRUS_WORKING_DIR: ${HOME}/pgsql/
CCACHE_DIR: ${HOME}/ccache
MACPORTS_CACHE: ${HOME}/macports-cache
PYTEST_DEBUG_TEMPROOT: /tmp # default is too long for UNIX sockets on Mac

MESON_FEATURES: >-
-Dbonjour=enabled
Expand All @@ -650,6 +669,9 @@ task:
p5.34-io-tty
p5.34-ipc-run
python312
py312-cryptography
py312-packaging
py312-pytest
tcl
zstd

Expand Down Expand Up @@ -699,6 +721,7 @@ task:
sh src/tools/ci/ci_macports_packages.sh $MACOS_PACKAGE_LIST
# system python doesn't provide headers
sudo /opt/local/bin/port select python3 python312
sudo /opt/local/bin/port select pytest pytest312
# Make macports install visible for subsequent steps
echo PATH=/opt/local/sbin/:/opt/local/bin/:$PATH >> $CIRRUS_ENV
upload_caches: macports
Expand All @@ -721,7 +744,7 @@ task:
test_world_script: |
ulimit -c unlimited # default is 0
ulimit -n 1024 # default is 256, pretty low
meson test $MTEST_ARGS --num-processes ${TEST_JOBS}
meson test $MTEST_ARGS --num-processes ${TEST_JOBS} ${MTEST_SUITES}

on_failure:
<<: *on_failure_meson
Expand Down Expand Up @@ -772,6 +795,8 @@ task:
-Dldap=enabled
-Dssl=openssl
-Dtap_tests=enabled
-Dpytest=enabled
-DPYTEST=c:\Windows\system32\config\systemprofile\AppData\Roaming\Python\Python310\Scripts\pytest.exe
-Dplperl=enabled
-Dplpython=enabled

Expand All @@ -780,8 +805,10 @@ task:
depends_on: SanityCheck
only_if: $CI_WINDOWS_ENABLED

# XXX Does Chocolatey really not have any Python package installers?
setup_additional_packages_script: |
REM choco install -y --no-progress ...
pip3 install --user cryptography packaging pytest

setup_hosts_file_script: |
echo 127.0.0.1 pg-loadbalancetest >> c:\Windows\System32\Drivers\etc\hosts
Expand All @@ -800,7 +827,7 @@ task:

check_world_script: |
vcvarsall x64
meson test %MTEST_ARGS% --num-processes %TEST_JOBS%
meson test %MTEST_ARGS% --num-processes %TEST_JOBS% %MTEST_SUITES%

on_failure:
<<: *on_failure_meson
Expand Down Expand Up @@ -844,7 +871,7 @@ task:
folder: ${CCACHE_DIR}

setup_additional_packages_script: |
REM C:\msys64\usr\bin\pacman.exe -S --noconfirm ...
C:\msys64\usr\bin\pacman.exe -S --noconfirm mingw-w64-ucrt-x86_64-python-cryptography mingw-w64-ucrt-x86_64-python-packaging mingw-w64-ucrt-x86_64-python-pytest

mingw_info_script: |
%BASH% -c "where gcc"
Expand All @@ -861,7 +888,7 @@ task:
upload_caches: ccache

test_world_script: |
%BASH% -c "meson test %MTEST_ARGS% --num-processes %TEST_JOBS%"
%BASH% -c "meson test %MTEST_ARGS% --num-processes %TEST_JOBS% %MTEST_SUITES%"

on_failure:
<<: *on_failure_meson
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ win32ver.rc
*.exe
lib*dll.def
lib*.pc
__pycache__/

# Local excludes in root directory
/GNUmakefile
Expand Down
138 changes: 138 additions & 0 deletions config/check_pytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Copyright (c) 2025, PostgreSQL Global Development Group
#
# Verify that pytest-requirements.txt is satisfied. This would probably be
# easier with pip, but requiring pip on build machines is a non-starter for
# many.
#
# The design philosophy of this script is to bend over backwards to help people
# figure out what is missing. The target audience for error output is the
# buildfarm operator who just wants to get the tests running, not the test
# developer who presumably already knows how to solve these problems.

import sys
from typing import List # TODO: Python 3.9 will remove the need for this


def main():
if len(sys.argv) != 2:
sys.exit("usage: python {} REQUIREMENTS_FILE".format(sys.argv[0]))

requirements_file = sys.argv[1]
with open(requirements_file, "r") as f:
requirements = f.readlines()

found = packaging_check(requirements)
if not found:
sys.exit("See src/test/pytest/README for package installation help.")


def packaging_check(requirements: List[str]) -> bool:
"""
The preferred dependency check, which unfortunately needs newer Python
facilities. Returns True if all dependencies were found.
"""
try:
# First, attempt to find importlib.metadata. This is part of the
# standard library from 3.8 onwards. Earlier Python versions have an
# official backport called importlib_metadata, which can generally be
# installed as a separate OS package (e.g. python3-importlib-metadata).
# This complication can be removed once we stop supporting Python 3.7.
try:
from importlib import metadata
except ImportError:
import importlib_metadata as metadata

# packaging contains the PyPA definitions of requirement specifiers.
# This is again contained in a separate OS package (for example,
# python3-packaging).
import packaging
from packaging.requirements import Requirement

except ImportError as err:
# We don't even have enough prerequisites to check our prerequisites.
# Try to fall back on the deprecated parser, to get a better error
# message.
found = setuptools_fallback(requirements)

if not found:
# Well, the best we can do is just print the import error as-is.
print(err, file=sys.stderr)

return False

# Strip extraneous whitespace, whole-line comments, and empty lines from our
# specifier list.
requirements = [r.strip() for r in requirements]
requirements = [r for r in requirements if r and r[0] != "#"]

found = True
for spec in requirements:
req = Requirement(spec)

# Skip any packages marked as unneeded for this particular Python env.
if req.marker and not req.marker.evaluate():
continue

# Make sure the package is installed...
try:
version = metadata.version(req.name)
except metadata.PackageNotFoundError:
print("Package '{}' is not installed".format(req.name), file=sys.stderr)
found = False
continue

# ...and that it has a compatible version.
if not req.specifier.contains(version):
print(
"Package '{}' has version {}, but '{}' is required".format(
req.name, version, req.specifier
),
file=sys.stderr,
)
found = False
continue

return found


def setuptools_fallback(requirements: List[str]) -> bool:
"""
An alternative dependency helper, based on the old deprecated pkg_resources
module in setuptools, which is pretty widely available in older Pythons. The
point of this is to bootstrap the user into an environment that can run the
packaging_check().

Returns False if pkg_resources is also unavailable, in which case we just
have to do our best.
"""
try:
import pkg_resources
except ModuleNotFoundError:
return False

# An extra newline makes the Autoconf output easier to read.
print(file=sys.stderr)

# Go one-by-one through the requirements, printing each missing dependency.
found = True
for r in requirements:
try:
pkg_resources.require(r)
except pkg_resources.DistributionNotFound as err:
# The error descriptions given here are pretty good as-is.
print(err, file=sys.stderr)
found = False
except pkg_resources.RequirementParseError as err:
assert False # TODO

# The only reason the fallback would be called is if we're missing required
# packages. So if we "found them", the requirements file is broken...
assert (
not found
), "setuptools_fallback() succeeded unexpectedly; is the requirements file incomplete?"

return True


if __name__ == "__main__":
main()
Loading