From c7e73b0dc5991a8eac6eb310d8bf64912dcd1701 Mon Sep 17 00:00:00 2001 From: William Jacoby Date: Wed, 14 Oct 2026 12:35:41 -0500 Subject: [PATCH] Add run-unit-tests.sh: an extension's PHPUnit tests as CI runs them Sets up a phpBB checkout on first use (shallow clone, Composer dependencies, and on PHP 8 with 3.3.x the PHPUnit 9 switch phpBB's own CI makes), copies the extension in afresh every run with rsync --delete, and runs its phpunit.xml.dist with phpBB's PHPUnit and bootstrap. Options for the phpBB branch, the checkout, updating, a filter and extra PHPUnit arguments. Option-handling tests and shellcheck in CI. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/ci.yml | 2 +- phpbb-test-board/README.md | 13 ++ phpbb-test-board/run-unit-tests.sh | 187 +++++++++++++++++++++++++++++ tests/test-phpbb-test-board.sh | 24 +++- 4 files changed, 223 insertions(+), 3 deletions(-) create mode 100755 phpbb-test-board/run-unit-tests.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bf62c4..8c1ea63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: persist-credentials: false - name: ShellCheck - run: shellcheck -x git-extensions.sh git-release-api.sh git-release-style.sh git-release-langpack.sh lib/github-release.sh tests/test-release-scripts.sh tests/test-release-api.sh phpbb-test-board/setup-board.sh tests/test-phpbb-test-board.sh + run: shellcheck -x git-extensions.sh git-release-api.sh git-release-style.sh git-release-langpack.sh lib/github-release.sh tests/test-release-scripts.sh tests/test-release-api.sh phpbb-test-board/setup-board.sh phpbb-test-board/run-unit-tests.sh tests/test-phpbb-test-board.sh - name: Tests run: tests/test-release-scripts.sh diff --git a/phpbb-test-board/README.md b/phpbb-test-board/README.md index 54eb4ba..4aea136 100644 --- a/phpbb-test-board/README.md +++ b/phpbb-test-board/README.md @@ -44,6 +44,19 @@ Installs the current stable phpBB 3.3 release, or `--version`, with no extension `--force` replaces an existing board in `DIR`. +### `run-unit-tests.sh`: the extension's PHPUnit tests + +```bash +phpbb-test-board/run-unit-tests.sh path/to/extension [-b 3.3.x|master] [-f PATTERN] [-- PHPUNIT_ARGS...] +``` + +Runs the extension's `phpunit.xml.dist` the way [phpbb-extensions/test-framework](https://github.com/phpbb-extensions/test-framework) does in CI: inside a phpBB checkout, with phpBB's own PHPUnit and `tests/bootstrap.php`. It needs no board. +- **The checkout** is set up on first use in `~/.cache/phpbb-release-tools/phpbb-BRANCH` (or `--env DIR`, or `PHPBB_UNIT_ENV`): a shallow clone of phpBB, its Composer dependencies, and on PHP 8 with phpBB 3.3.x the switch to PHPUnit 9 that phpBB's own CI makes, since 3.3.x ships PHPUnit 7.5. `--update` pulls it and reinstalls. +- **The extension** is copied in afresh on every run (`rsync --delete`, without `.git`), into `phpBB/ext/` under its `composer.json` name, so a test never runs against an old copy. +- `-f PATTERN` runs only the matching tests; anything after `--` goes to PHPUnit, for example `-- --testdox` or, on `master`, `-- --display-skipped`. + +Exit status: PHPUnit's, 1 for a setup failure, 2 for bad arguments. Needs `git`, `php`, `composer`, `rsync` and `jq`. + ### `smoke_test.py`: does the extension break anything? ```bash diff --git a/phpbb-test-board/run-unit-tests.sh b/phpbb-test-board/run-unit-tests.sh new file mode 100755 index 0000000..694a79f --- /dev/null +++ b/phpbb-test-board/run-unit-tests.sh @@ -0,0 +1,187 @@ +#!/usr/bin/bash +# run-unit-tests.sh +# +# Runs a phpBB extension's PHPUnit tests the way phpbb-extensions/test-framework +# does in CI: inside a phpBB checkout, with phpBB's own PHPUnit and test +# bootstrap. +# +# The first run sets that checkout up: a shallow clone of phpBB at the chosen +# branch, its Composer dependencies, and, on PHP 8 with phpBB 3.3.x, the switch +# to PHPUnit 9 that phpBB's .github/setup-phpbb.sh makes (3.3.x ships PHPUnit +# 7.5, which does not run on PHP 8.1 and later). Every run copies the +# extension in afresh (rsync --delete, without .git), so the tests never run +# against an old copy, then runs its phpunit.xml.dist. +# +# Usage: run-unit-tests.sh [-b BRANCH] [-e DIR] [-u] [-f PATTERN] EXT_DIR [-- PHPUNIT_ARGS...] +# Outputs: PHPUnit's report on stdout +# Exit status: PHPUnit's (0 when every test passes), 1 for a setup failure, +# 2 for bad arguments. + +set -Eeuo pipefail + +readonly PHPBB_REPO="https://github.com/phpbb/phpbb.git" + +usage() { + cat <<'EOF' +Usage: run-unit-tests.sh [options] EXT_DIR [-- PHPUNIT_ARGS...] + +Run a phpBB extension's PHPUnit tests inside a phpBB checkout, as the +phpbb-extensions test framework does in CI. The checkout is set up on first +use; the extension is copied in afresh on every run. + +Arguments: + EXT_DIR the extension's checkout (with composer.json and + phpunit.xml.dist) + PHPUNIT_ARGS anything after -- is passed to PHPUnit + +Options: + -b, --branch BRANCH phpBB branch to test against: 3.3.x or master + (default: 3.3.x) + -e, --env DIR phpBB checkout to use or create (default: + $PHPBB_UNIT_ENV, else + ~/.cache/phpbb-release-tools/phpbb-BRANCH) + -u, --update pull the checkout and reinstall its dependencies first + -f, --filter PATTERN run only the tests matching PATTERN (PHPUnit --filter) + -h, --help show this help and exit + +Examples: + run-unit-tests.sh ~/repos/phpbb-ext-wiki + run-unit-tests.sh -b master ~/repos/phpbb-ext-wiki + run-unit-tests.sh -f readable_diff ~/repos/phpbb-ext-wiki -- --testdox +EOF +} + +die() { + echo "Error: $*" >&2 + exit 1 +} + +usage_error() { + echo "Error: $*" >&2 + echo "Run with --help for usage." >&2 + exit 2 +} + +need() { + command -v "$1" >/dev/null 2>&1 || die "$1 is required but not installed" +} + +branch="3.3.x" +env_dir="" +update=0 +filter="" +ext_dir="" +phpunit_args=() + +if [ "$#" -eq 0 ]; then + usage + exit 0 +fi + +while [ "$#" -gt 0 ]; do + case "$1" in + -b|--branch) + [ "$#" -ge 2 ] || usage_error "$1 needs a branch" + branch="$2" + shift 2 + ;; + -e|--env) + [ "$#" -ge 2 ] || usage_error "$1 needs a directory" + env_dir="$2" + shift 2 + ;; + -u|--update) + update=1 + shift + ;; + -f|--filter) + [ "$#" -ge 2 ] || usage_error "$1 needs a pattern" + filter="$2" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + phpunit_args=("$@") + break + ;; + -*) + usage_error "unknown option: $1" + ;; + *) + [ -z "$ext_dir" ] || usage_error "only one EXT_DIR can be given" + ext_dir="$1" + shift + ;; + esac +done + +[ -n "$ext_dir" ] || usage_error "EXT_DIR is required" +case "$branch" in + 3.3.x|master) ;; + *) usage_error "--branch must be 3.3.x or master, not $branch" ;; +esac +[ -d "$ext_dir" ] || usage_error "$ext_dir is not a directory" +ext_dir="$(cd -- "$ext_dir" && pwd)" +[ -f "$ext_dir/composer.json" ] || usage_error "$ext_dir has no composer.json" +[ -f "$ext_dir/phpunit.xml.dist" ] || usage_error "$ext_dir has no phpunit.xml.dist" + +for tool in git php composer rsync jq; do + need "$tool" +done + +# The extension's place under phpBB/ext/ comes from its Composer name. +ext_name="$(jq -r '.name // empty' "$ext_dir/composer.json")" +[[ "$ext_name" =~ ^[a-z0-9_-]+/[a-z0-9_-]+$ ]] || die "composer.json has no valid vendor/name: '$ext_name'" + +env_dir="${env_dir:-${PHPBB_UNIT_ENV:-$HOME/.cache/phpbb-release-tools/phpbb-$branch}}" +php_major="$(php -r 'echo PHP_MAJOR_VERSION;')" + +# phpBB 3.3.x needs PHPUnit 9 on PHP 8, as phpBB's own CI installs it. +use_phpunit9() { + ( + cd "$env_dir/phpBB" + composer remove phpunit/dbunit --dev --update-with-dependencies --no-interaction + composer require symfony/yaml:^4.4 misantron/dbunit:5.2.1 phpunit/phpunit:^9.3 doctrine/instantiator:^1.4 \ + --dev --update-with-all-dependencies --ignore-platform-reqs --no-interaction + ) +} + +install_dependencies() { + echo "Installing phpBB's Composer dependencies in $env_dir/phpBB ..." >&2 + (cd "$env_dir/phpBB" && composer install --no-interaction --no-progress) >&2 + if [ "$branch" = "3.3.x" ] && [ "$php_major" -ge 8 ]; then + echo "Switching to PHPUnit 9 for PHP $php_major ..." >&2 + use_phpunit9 >&2 + fi +} + +if [ ! -d "$env_dir/.git" ]; then + [ ! -e "$env_dir" ] || [ -z "$(ls -A -- "$env_dir")" ] || die "$env_dir exists and is not a phpBB checkout" + echo "Cloning phpBB $branch into $env_dir ..." >&2 + mkdir -p -- "$(dirname -- "$env_dir")" + git clone --quiet --depth 1 --branch "$branch" "$PHPBB_REPO" "$env_dir" >&2 + install_dependencies +elif [ "$update" -eq 1 ]; then + echo "Updating $env_dir ..." >&2 + git -C "$env_dir" checkout --quiet -- . >&2 + git -C "$env_dir" pull --quiet --ff-only >&2 + install_dependencies +fi + +[ -x "$env_dir/phpBB/vendor/bin/phpunit" ] || die "$env_dir has no phpBB/vendor/bin/phpunit; run again with --update" +[ -f "$env_dir/tests/bootstrap.php" ] || die "$env_dir has no tests/bootstrap.php" + +# A fresh copy every run, so no old file of the extension is left behind. +target="$env_dir/phpBB/ext/$ext_name" +mkdir -p -- "$target" +rsync -a --delete --exclude .git --exclude node_modules "$ext_dir/" "$target/" + +args=(--configuration "phpBB/ext/$ext_name/phpunit.xml.dist" --bootstrap ./tests/bootstrap.php) +[ -z "$filter" ] || args+=(--filter "$filter") + +cd -- "$env_dir" +exec phpBB/vendor/bin/phpunit "${args[@]}" "${phpunit_args[@]}" diff --git a/tests/test-phpbb-test-board.sh b/tests/test-phpbb-test-board.sh index 7239c14..7c988b4 100755 --- a/tests/test-phpbb-test-board.sh +++ b/tests/test-phpbb-test-board.sh @@ -1,8 +1,9 @@ #!/usr/bin/bash # Option-handling tests for the phpbb-test-board tools: help output, exit # status for bad arguments, and the error for a missing board. Does not build -# a board or contact phpBB; the Python scripts' first run creates their -# virtualenv (phpbb-test-board/.venv), which needs network access once. +# a board or contact phpBB, and run-unit-tests.sh is only given bad arguments; +# the Python scripts' first run creates their virtualenv +# (phpbb-test-board/.venv), which needs network access once. # Usage: tests/test-phpbb-test-board.sh # Exit status: 0 if every test passes, 1 otherwise. @@ -122,6 +123,25 @@ check "template_a11y.py reports a missing screen-reader text" \ check "template_a11y.py reports a missing tooltip" \ output_has "bad.html:2: icon-only without a title (tooltip)" "$tools/template_a11y.py" "$tmp/a11y-ext" +# run-unit-tests.sh: option handling only; no phpBB checkout is cloned or run +mkdir -p "$tmp/ext-no-phpunit" "$tmp/ext-bad-name" +echo '{"name": "vendor/ext"}' >"$tmp/ext-no-phpunit/composer.json" +echo '{"name": "Not A Name"}' >"$tmp/ext-bad-name/composer.json" +touch "$tmp/ext-bad-name/phpunit.xml.dist" +check "run-unit-tests.sh without arguments shows help and exits 0" \ + exits_with 0 "$tools/run-unit-tests.sh" +check "run-unit-tests.sh --help shows usage" output_has "Usage: run-unit-tests.sh" "$tools/run-unit-tests.sh" --help +check "run-unit-tests.sh with an unknown option exits 2" exits_with 2 "$tools/run-unit-tests.sh" --nope "$tmp" +check "run-unit-tests.sh with an unknown branch exits 2" \ + exits_with 2 "$tools/run-unit-tests.sh" -b 3.2.x "$tmp/ext-no-phpunit" +check "run-unit-tests.sh with a missing directory exits 2" exits_with 2 "$tools/run-unit-tests.sh" "$tmp/no-such-dir" +check "run-unit-tests.sh without phpunit.xml.dist exits 2" \ + exits_with 2 "$tools/run-unit-tests.sh" "$tmp/ext-no-phpunit" +check "run-unit-tests.sh with two directories exits 2" \ + exits_with 2 "$tools/run-unit-tests.sh" "$tmp/ext-no-phpunit" "$tmp/ext-bad-name" +check "run-unit-tests.sh rejects a composer name that is not vendor/name" \ + output_has "composer.json has no valid vendor/name" "$tools/run-unit-tests.sh" -e "$tmp/no-env" "$tmp/ext-bad-name" + if [ "$failures" -eq 0 ]; then echo "All tests passed." else