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
25 changes: 21 additions & 4 deletions .github/workflows/pg-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ env:
-Dplperl=enabled
-Dplpython=enabled
-Dpltcl=enabled
-Dpytest=enabled
-Dreadline=enabled
-Dssl=openssl
-Dtap_tests=enabled
Expand Down Expand Up @@ -347,6 +348,7 @@ jobs:
--auto-features=disabled \
-Ddefault_library=shared \
-Dtap_tests=enabled \
-Dpytest=enabled \
build

- name: Build
Expand Down Expand Up @@ -382,7 +384,7 @@ jobs:

# Run a minimal set of tests. The main regression tests take too long
# for this purpose. For now this is a random quick pg_regress style
# test, and a tap test that exercises both a frontend binary and the
# test, and a pytest test that exercises both a frontend binary and the
# backend.
#
# To allow the command below to be reused by later tasks, we allow
Expand Down Expand Up @@ -502,7 +504,7 @@ jobs:
run: |
./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 \
Expand Down Expand Up @@ -668,6 +670,15 @@ jobs:

- name: Test world
shell: *su_postgres_shell
# The pytest suite loads libpq in-process via ctypes. Here libpq is
# AddressSanitizer-instrumented, and ASan must come first in the link
# order; dlopening it into an otherwise uninstrumented python aborts
# with "ASan runtime does not come first". Preload the ASan runtime
# for the test run to satisfy that (a no-op for the already-instrumented
# server/client binaries). Scoped to this step so the build is
# unaffected; detect_leaks is already disabled via ASAN_OPTIONS.
env:
ADDITIONAL_SETUP: export LD_PRELOAD="$(gcc -print-file-name=libasan.so)"
run: *meson_test_world_cmd

- *linux_collect_cores_step
Expand Down Expand Up @@ -710,6 +721,8 @@ jobs:
openssl
p5.34-io-tty
p5.34-ipc-run
py312-pexpect
py312-pytest
python312
tcl
zstd
Expand Down Expand Up @@ -869,6 +882,7 @@ jobs:
-Dldap=enabled
-Dplperl=enabled
-Dplpython=enabled
-Dpytest=enabled
-Dssl=openssl
-Dtap_tests=enabled

Expand Down Expand Up @@ -956,9 +970,11 @@ jobs:
- name: Install dependencies
shell: pwsh
run: |
# meson is not preinstalled on windows-2022. Install via pip
# meson is not preinstalled on windows-2022. Install via pip.
# pytest enables the Python test suite (pexpect is omitted: it needs
# a pty, which Windows lacks, and the interactive tests importorskip).
echo ::group::pip
python -m pip install --upgrade meson
python -m pip install --upgrade meson pytest
if (!$?) { throw 'cmdfail' }
echo ::endgroup::

Expand Down Expand Up @@ -1096,6 +1112,7 @@ jobs:
${MINGW_PACKAGE_PREFIX}-meson \
${MINGW_PACKAGE_PREFIX}-perl \
${MINGW_PACKAGE_PREFIX}-pkgconf \
${MINGW_PACKAGE_PREFIX}-python-pytest \
${MINGW_PACKAGE_PREFIX}-readline \
${MINGW_PACKAGE_PREFIX}-zlib \
${MINGW_PACKAGE_PREFIX}-zstd
Expand Down
102 changes: 102 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ vpath_build
PG_SYSROOT
PG_VERSION_NUM
LDFLAGS_EX_BE
PYTEST
PROVE
DBTOEPUB
FOP
Expand Down Expand Up @@ -773,6 +774,7 @@ CFLAGS
CC
enable_injection_points
PG_TEST_EXTRA
enable_pytest
enable_tap_tests
enable_dtrace
DTRACEFLAGS
Expand Down Expand Up @@ -851,6 +853,7 @@ enable_profiling
enable_coverage
enable_dtrace
enable_tap_tests
enable_pytest
enable_injection_points
with_blocksize
with_segsize
Expand Down Expand Up @@ -1552,6 +1555,7 @@ Optional Features:
--enable-coverage build with coverage testing instrumentation
--enable-dtrace build with DTrace support
--enable-tap-tests enable TAP tests (requires Perl and IPC::Run)
--enable-pytest enable Python (pytest) tests (requires pytest)
--enable-injection-points
enable injection points (for testing)
--enable-depend turn on automatic dependency tracking
Expand Down Expand Up @@ -3661,6 +3665,33 @@ fi



# Python (pytest) tests
#


# Check whether --enable-pytest was given.
if test "${enable_pytest+set}" = set; then :
enableval=$enable_pytest;
case $enableval in
yes)
:
;;
no)
:
;;
*)
as_fn_error $? "no argument expected for --enable-pytest option" "$LINENO" 5
;;
esac

else
enable_pytest=no

fi





#
# Injection points
Expand Down Expand Up @@ -19523,6 +19554,77 @@ $as_echo "$modulestderr" >&6; }
fi
fi

if test "$enable_pytest" = yes; then
# Make sure we know how to run pytest. Prefer a "pytest" program, but fall
# back to "python -m pytest" (as the Meson build does), since some
# installations provide only the module and not a wrapper script.
if test -z "$PYTEST"; then
for ac_prog in pytest
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
$as_echo_n "checking for $ac_word... " >&6; }
if ${ac_cv_path_PYTEST+:} false; then :
$as_echo_n "(cached) " >&6
else
case $PYTEST in
[\\/]* | ?:[\\/]*)
ac_cv_path_PYTEST="$PYTEST" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
test -z "$as_dir" && as_dir=.
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
ac_cv_path_PYTEST="$as_dir/$ac_word$ac_exec_ext"
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS

;;
esac
fi
PYTEST=$ac_cv_path_PYTEST
if test -n "$PYTEST"; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTEST" >&5
$as_echo "$PYTEST" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi


test -n "$PYTEST" && break
done

else
# Report the value of PYTEST in configure's output in all cases.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTEST" >&5
$as_echo_n "checking for PYTEST... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTEST" >&5
$as_echo "$PYTEST" >&6; }
fi

if test -z "$PYTEST"; then
for pgac_python in python3 python; do
if "$pgac_python" -m pytest --version >/dev/null 2>&1; then
PYTEST="$pgac_python -m pytest"
break
fi
done
fi
if test -z "$PYTEST"; then
as_fn_error $? "pytest not found" "$LINENO" 5
fi
fi

# If compiler will take -Wl,--as-needed (or various platform-specific
# spellings thereof) then add that to LDFLAGS. This is much easier than
# trying to filter LIBS to the minimum for each executable.
Expand Down
24 changes: 24 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,12 @@ AC_SUBST(enable_dtrace)
PGAC_ARG_BOOL(enable, tap-tests, no,
[enable TAP tests (requires Perl and IPC::Run)])
AC_SUBST(enable_tap_tests)

# Python (pytest) tests
#
PGAC_ARG_BOOL(enable, pytest, no,
[enable Python (pytest) tests (requires pytest)])
AC_SUBST(enable_pytest)
AC_ARG_VAR(PG_TEST_EXTRA,
[enable selected extra tests (overridden at runtime by PG_TEST_EXTRA environment variable)])

Expand Down Expand Up @@ -2502,6 +2508,24 @@ if test "$enable_tap_tests" = yes; then
fi
fi

if test "$enable_pytest" = yes; then
# Make sure we know how to run pytest. Prefer a "pytest" program, but fall
# back to "python -m pytest" (as the Meson build does), since some
# installations provide only the module and not a wrapper script.
PGAC_PATH_PROGS(PYTEST, pytest)
if test -z "$PYTEST"; then
for pgac_python in python3 python; do
if "$pgac_python" -m pytest --version >/dev/null 2>&1; then
PYTEST="$pgac_python -m pytest"
break
fi
done
fi
if test -z "$PYTEST"; then
AC_MSG_ERROR([pytest not found])
fi
fi

# If compiler will take -Wl,--as-needed (or various platform-specific
# spellings thereof) then add that to LDFLAGS. This is much easier than
# trying to filter LIBS to the minimum for each executable.
Expand Down
76 changes: 76 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3951,6 +3951,32 @@ install_suites = []

testwrap = files('src/tools/testwrap')

# Detect pytest for the Python-based test suite (src/test/pytest). The suite
# is optional: it is enabled when the 'pytest' feature is enabled, or (in the
# default 'auto' mode) when a usable pytest is found. We prefer a 'pytest'
# program on PATH and fall back to "python -m pytest".
pytest_enabled = false
pytest_cmd = []
pytest_pythonpath = meson.project_source_root() / 'src' / 'test' / 'pytest'
pytestopt = get_option('pytest')
if not pytestopt.disabled()
pytest_prog = find_program(get_option('PYTEST'), native: true, required: false)
if pytest_prog.found()
pytest_enabled = true
pytest_cmd = [pytest_prog.full_path()]
else
pytest_check = run_command(
python, '-m', 'pytest', '--version', check: false)
if pytest_check.returncode() == 0
pytest_enabled = true
pytest_cmd = [python.full_path(), '-m', 'pytest']
endif
endif
if not pytest_enabled and pytestopt.enabled()
error('pytest not found')
endif
endif

foreach test_dir : tests
testwrap_base = [
testwrap,
Expand Down Expand Up @@ -4118,6 +4144,56 @@ foreach test_dir : tests
)
endforeach
install_suites += test_group
elif kind == 'pytest'
testwrap_pytest = testwrap_base
if not pytest_enabled
testwrap_pytest += ['--skip', 'pytest not enabled']
endif

# Make the in-tree libpq/ and pypg/ packages importable, and put the
# temporary install (and per-directory build outputs) on PATH so client
# programs and pg_config resolve there. The 'test' subdir mirrors the
# tap branch: some dirs (e.g. libpq) build their test client programs
# into <bd>/test.
env = test_env
env.prepend('PATH', temp_install_bindir, test_dir['bd'], test_dir['bd'] / 'test')
env.prepend('PYTHONPATH', pytest_pythonpath)

foreach name, value : t.get('env', {})
env.set(name, value)
endforeach

test_group = test_dir['name']
test_kwargs = {
'protocol': 'tap',
'suite': test_group,
'timeout': 1000,
'depends': test_deps + t.get('deps', []),
'env': env,
} + t.get('test_kwargs', {})

foreach onepyt : t['tests']
# Make pytest test names prettier: drop pyt/ and .py
onepyt_p = onepyt
if onepyt_p.startswith('pyt/')
onepyt_p = onepyt.split('pyt/')[1]
endif
if onepyt_p.endswith('.py')
onepyt_p = fs.stem(onepyt_p)
endif

test(test_dir['name'] / onepyt_p,
python,
kwargs: test_kwargs,
args: testwrap_pytest + [
'--testgroup', test_dir['name'],
'--testname', onepyt_p,
'--', pytest_cmd,
test_dir['sd'] / onepyt,
],
)
endforeach
install_suites += test_group
else
error('unknown kind @0@ of test in @1@'.format(kind, test_dir['sd']))
endif
Expand Down
6 changes: 6 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ option('cassert', type: 'boolean', value: false,
option('tap_tests', type: 'feature', value: 'auto',
description: 'Enable TAP tests')

option('pytest', type: 'feature', value: 'auto',
description: 'Enable Python (pytest) test suites')

option('injection_points', type: 'boolean', value: false,
description: 'Enable injection points')

Expand Down Expand Up @@ -198,6 +201,9 @@ option('PROVE', type: 'string', value: 'prove',
option('PYTHON', type: 'array', value: ['python3', 'python'],
description: 'Path to python binary')

option('PYTEST', type: 'array', value: ['pytest', 'py.test'],
description: 'Path to pytest binary')

option('SED', type: 'string', value: 'gsed',
description: 'Path to sed binary')

Expand Down
Loading