| #!/bin/sh |
| # |
| # run-all-tests.sh -- unified runner for the two Python test suites under test/. |
| # |
| # Runs both pytest-based suites against the same built httpd: |
| # 1. pytest_suite/ -- the self-contained port of the classic Apache::Test |
| # suite (core HTTP, modules, security CVEs, SSL, PHP). Run FIRST. |
| # 2. pyhttpd tests under modules/ -- httpd's own HTTP/2, mod_md, HTTP/1, |
| # proxy and core tests (uses curl/nghttp/h2load; configured via |
| # pyhttpd/config.ini). |
| # |
| # Both run against the same httpd; pytest_suite locates it via --apxs, while |
| # the pyhttpd tests read pyhttpd/config.ini (generated by httpd's configure). |
| # |
| # Usage: |
| # ./run-all-tests.sh # run both suites (pytest_suite first) |
| # ./run-all-tests.sh --only=pysuite # run only pytest_suite |
| # ./run-all-tests.sh --only=pyhttpd # run only the pyhttpd modules/ tests |
| # ./run-all-tests.sh --apxs /path/to/apxs # override the httpd build |
| # ./run-all-tests.sh -k status -v # extra args pass through to BOTH pytests |
| # ./run-all-tests.sh --clean-modules # wipe compiled C-module artifacts before |
| # # building (emulate make clean; pytest_suite only) |
| # |
| # Environment overrides: |
| # APXS path to apxs (default: read from pyhttpd/config.ini, else $PATH) |
| # PHP_FPM path to php-fpm for pytest_suite's PHP tests (optional) |
| # PYHTTPD_TARGETS pyhttpd test paths (default: "modules") |
| # |
| set -eu |
| |
| usage() { |
| cat <<'EOF' |
| Usage: run-all-tests.sh [OPTIONS] [PATHS...] |
| |
| Run both Python test suites against a built httpd. |
| |
| Suites (run in order): |
| 1. pytest_suite/ -- classic Apache::Test port (HTTP, modules, SSL, CVEs) |
| 2. modules/ -- pyhttpd tests (HTTP/2, mod_md, proxy, core) |
| |
| Options: |
| --only=pysuite run only pytest_suite |
| --only=pyhttpd run only the pyhttpd modules/ tests |
| --apxs=PATH path to apxs for the pytest_suite build |
| --clean-modules wipe compiled C-module artifacts before building |
| (emulate make clean; pytest_suite only) |
| -k EXPR pytest keyword filter (passed to both suites) |
| -m EXPR pytest marker filter (passed to both suites) |
| -v, -x, ... other pytest flags (passed to both suites) |
| -h, --help show this help and exit |
| |
| Positional PATHS are forwarded to pytest_suite only (e.g. tests/t/modules/foo). |
| The pyhttpd suite selects tests via PYHTTPD_TARGETS or auto-detection. |
| |
| Environment: |
| APXS path to apxs (default: config.ini, then \$PATH) |
| PHP_FPM path to php-fpm for PHP tests in pytest_suite (optional) |
| PYHTTPD_TARGETS space-separated list of pyhttpd test paths (default: modules/*) |
| EOF |
| } |
| |
| here="$(cd "$(dirname "$0")" && pwd)" |
| suite_dir="$here/pytest_suite" |
| config_ini="$here/pyhttpd/config.ini" |
| |
| # Parse args once. Pull out --only and --apxs (space and = forms). Remaining |
| # arguments are split into: |
| # flags (start with '-', e.g. -v -k NAME -x): passed to BOTH pytests. |
| # paths (positional, e.g. tests/t/modules/...): these are pytest_suite |
| # paths and go ONLY to pytest_suite. The pyhttpd side selects its |
| # tests via PYHTTPD_TARGETS (or its auto-detected default), since a |
| # pytest_suite path is meaningless there. |
| # A flag that takes a separate-word value (-k NAME) keeps the value as a flag. |
| only="" |
| apxs_opt="" |
| flags="" |
| pysuite_flags="" |
| paths="" |
| expect_apxs=0 |
| expect_flagval=0 |
| for arg in "$@"; do |
| if [ "$expect_apxs" = "1" ]; then apxs_opt="$arg"; expect_apxs=0; continue; fi |
| if [ "$expect_flagval" = "1" ]; then flags="$flags $arg"; expect_flagval=0; continue; fi |
| case "$arg" in |
| -h|--help) usage; exit 0 ;; |
| --only=*) only="${arg#--only=}" ;; |
| --apxs) expect_apxs=1 ;; |
| --apxs=*) apxs_opt="${arg#--apxs=}" ;; |
| --clean-modules) pysuite_flags="$pysuite_flags $arg" ;; # pysuite-only; pyhttpd has no C modules |
| -k|-m|-p) flags="$flags $arg"; expect_flagval=1 ;; # take a value next |
| -*) flags="$flags $arg" ;; |
| *) paths="$paths $arg" ;; |
| esac |
| done |
| |
| # --- locate apxs (for pytest_suite) ----------------------------------------- |
| if [ -z "$apxs_opt" ]; then |
| if [ -n "${APXS:-}" ]; then |
| apxs_opt="$APXS" |
| elif [ -f "$config_ini" ]; then |
| # Resolve apxs = ${exec_prefix}/bin/apxs from config.ini (simple expand). |
| prefix=$(sed -n 's/^prefix = //p' "$config_ini" | head -1) |
| apxs_opt="$prefix/bin/apxs" |
| elif command -v apxs >/dev/null 2>&1; then |
| apxs_opt="$(command -v apxs)" |
| fi |
| fi |
| |
| php_args="" |
| [ -n "${PHP_FPM:-}" ] && php_args="--php-fpm=$PHP_FPM" |
| |
| rc=0 |
| |
| run_pysuite() { |
| echo "==========================================================" |
| echo "[1/2] pytest_suite (classic Apache::Test port)" |
| echo "==========================================================" |
| if [ -z "$apxs_opt" ]; then |
| echo "run-all-tests.sh: ERROR: no apxs found for pytest_suite." >&2 |
| echo " Pass --apxs=/path/to/apxs or set APXS=..." >&2 |
| return 2 |
| fi |
| # runtests.sh handles venv + cgisock cleanup + flag assembly. |
| # pytest_suite gets both the shared flags and any positional paths. |
| # pysuite_flags holds options only meaningful to this suite (e.g. --clean-modules). |
| # shellcheck disable=SC2086 |
| ( cd "$suite_dir" && ./runtests.sh --apxs="$apxs_opt" $php_args $flags $pysuite_flags $paths ) || return $? |
| } |
| |
| run_pyhttpd() { |
| echo "==========================================================" |
| echo "[2/2] pyhttpd suites (modules/: http2, md, http1, proxy, core)" |
| echo "==========================================================" |
| if [ ! -f "$config_ini" ]; then |
| echo "run-all-tests.sh: note: pyhttpd/config.ini not found;" >&2 |
| echo " build httpd with its test config (configure) to run these." >&2 |
| return 0 |
| fi |
| # runtests.sh manages the venv, prepends its bin/ to PATH (so CGI |
| # scripts forked by httpd also use the venv's Python), and runs pytest. |
| # PYHTTPD_TARGETS can override which modules/ subdirs are run. |
| # shellcheck disable=SC2086 |
| ( cd "$here/pyhttpd" && ./runtests.sh $flags ) || return $? |
| } |
| |
| case "$only" in |
| pysuite) run_pysuite || rc=$? ;; |
| pyhttpd) run_pyhttpd || rc=$? ;; |
| "") |
| # Both, pytest_suite first. Keep going if the first fails so we get |
| # results from both; report a non-zero overall rc if either failed. |
| run_pysuite || rc=$? |
| run_pyhttpd || rc=$? |
| ;; |
| *) |
| echo "run-all-tests.sh: unknown --only=$only (use pysuite|pyhttpd)" >&2 |
| exit 2 |
| ;; |
| esac |
| |
| echo "==========================================================" |
| [ "$rc" -eq 0 ] && echo "ALL SUITES PASSED" || echo "SOME TESTS FAILED (rc=$rc)" |
| echo "==========================================================" |
| exit "$rc" |