Skip to content
Merged
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
34 changes: 34 additions & 0 deletions .github/workflows/wp-unit-tests-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Unit Tests (Dockerfile)

on:
push:
branches: [ "master", "main", "dev" ]
pull_request:
types: [synchronize, opened, reopened]

permissions: {}

jobs:
phpunit:
name: PHP Unit ${{ matrix.php-version }}
runs-on: ubuntu-latest

strategy:
matrix:
php-version: [ 8.0, 8.1, 8.2, 8.3, 8.4 ]

steps:
- name: Check out the source code
uses: actions/checkout@v4

- name: Build PHPUnit image
run: |
docker build \
--build-arg PHP_VERSION=${{ matrix.php-version }} \
-t wpconnections-phpunit:${{ matrix.php-version }} \
-f Dockerfile.phpunit .

- name: Run all tests
run: |
docker run --rm -v "$PWD:/srv/web" \
wpconnections-phpunit:${{ matrix.php-version }} test:all
4 changes: 2 additions & 2 deletions .github/workflows/wp-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

strategy:
matrix:
php-version: [ 7.4, 8.0, 8.1, 8.2, 8.3 ]
php-version: [ 8.0, 8.1, 8.2, 8.3, 8.4 ]

services:
mysql:
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:

strategy:
matrix:
php-version: [ 7.4, 8.0, 8.1, 8.2, 8.3 ]
php-version: [ 8.0, 8.1, 8.2, 8.3, 8.4 ]

services:
mysql:
Expand Down
74 changes: 74 additions & 0 deletions Dockerfile.phpunit
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# syntax=docker/dockerfile:1
# Universal image for running wpConnections PHPUnit suites with embedded services
ARG PHP_VERSION=8.2
ARG WP_VERSION=latest
FROM php:${PHP_VERSION}-cli

ARG WP_VERSION=latest

LABEL maintainer="wpConnections"

ENV COMPOSER_ALLOW_SUPERUSER=1 \
PATH="/root/.composer/vendor/bin:${PATH}" \
WP_VERSION=${WP_VERSION} \
WP_CORE_DIR=/opt/wordpress \
WP_DEVELOP_DIR=/opt/wordpress-develop \
WP_TESTS_DIR=/opt/wordpress-develop/tests/phpunit \
MYSQL_DATA_DIR=/tmp/mysql-data \
MYSQL_SOCKET=/run/mysqld/mysqld.sock \
DB_HOST=127.0.0.1 \
DB_NAME=wordpress_test \
DB_USER=wordpress \
DB_PASSWORD=wordpress

RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
gnupg \
libonig-dev \
libxml2-dev \
libzip-dev \
mariadb-client \
mariadb-server \
unzip \
zip; \
docker-php-ext-install -j"$(nproc)" mbstring mysqli pdo_mysql zip; \
rm -rf /var/lib/apt/lists/*

# Provide composer inside the image
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer

# Pre-install WordPress core and the WordPress test library so the container
# is fully self-contained when executing the WordPress PHPUnit suite.
RUN set -eux; \
rm -rf "${WP_DEVELOP_DIR}"; \
mkdir -p "${WP_DEVELOP_DIR}"; \
if [ "${WP_VERSION}" = "latest" ]; then \
WP_TARBALL_URL="https://wordpress.org/latest.tar.gz"; \
WP_TESTS_ARCHIVE="https://github.com/WordPress/wordpress-develop/archive/refs/heads/master.tar.gz"; \
WP_TESTS_REF="master"; \
else \
WP_TARBALL_URL="https://wordpress.org/wordpress-${WP_VERSION}.tar.gz"; \
WP_TESTS_ARCHIVE="https://github.com/WordPress/wordpress-develop/archive/refs/tags/${WP_VERSION}.tar.gz"; \
WP_TESTS_REF="${WP_VERSION}"; \
fi; \

curl -fsSL "$WP_TESTS_ARCHIVE" -o /tmp/wordpress-develop.tar.gz; \
tar -xzf /tmp/wordpress-develop.tar.gz -C "${WP_DEVELOP_DIR}" --strip-components=1; \
rm /tmp/wordpress-develop.tar.gz; \
if [ ! -f "${WP_DEVELOP_DIR}/wp-tests-config-sample.php" ]; then \
echo "Missing wp-tests-config-sample.php in extracted WordPress tests archive" >&2; \
exit 1; \
fi; \
cp "${WP_DEVELOP_DIR}/wp-tests-config-sample.php" "${WP_DEVELOP_DIR}/wp-tests-config.php"

WORKDIR /srv/web

COPY docker/phpunit-entrypoint.sh /usr/local/bin/phpunit-entrypoint.sh
RUN chmod +x /usr/local/bin/phpunit-entrypoint.sh

ENTRYPOINT ["phpunit-entrypoint.sh"]
CMD ["test:all"]
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# WP Connections: post-to-post connections for WordPress
[![PHP CS](https://github.com/hokoo/wpConnections/actions/workflows/php-cs.yml/badge.svg)](https://github.com/hokoo/wpConnections/actions/workflows/phpunit.yml)
[![PHP WordPress Unit Tests](https://github.com/hokoo/wpConnections/actions/workflows/wp-unit-tests.yml/badge.svg)](https://github.com/hokoo/wpConnections/actions/workflows/wp-unit-tests.yml)
[![Dockerfile Unit Tests](https://github.com/hokoo/wpConnections/actions/workflows/wp-unit-tests-docker.yml/badge.svg)](https://github.com/hokoo/wpConnections/actions/workflows/wp-unit-tests-docker.yml)

<!-- TOC -->
* [Why wpConnection?](#why-wpconnection)
Expand Down Expand Up @@ -95,4 +96,21 @@ Since you have initialized new client, its REST API endpoints are available.
5. Run folowing command in the root directory to install the project:
```bash
bash ./local-dev/init.sh && make tests.init && make docker.up && make dev.install
```
```

### Running the test suites

The project ships with a dedicated `Dockerfile.phpunit` image that bundles Composer, the WordPress test library and an embedded MariaDB server so the entire PHPUnit stack runs inside a single container locally and in CI. After the installation step you can run all tests from the project root with:

```bash
make tests.run
```

Behind the scenes this calls `docker compose` with the `phpunit` service defined in `local-dev/docker-compose.yml`. The service no longer depends on any other containers—the entrypoint spins up MariaDB and configures the WordPress test library on demand—so these commands can be executed anywhere Docker is available. You can also run the individual commands manually, for example:

```bash
docker compose -f local-dev/docker-compose.yml run --rm phpunit composer run phpunit
docker compose -f local-dev/docker-compose.yml run --rm phpunit vendor/bin/phpunit -c php-wp-unit.xml
```

The same Dockerfile is also used by the optional GitHub Actions workflow defined in `.github/workflows/wp-unit-tests-docker.yml`, allowing you to compare its output against the long-standing `wp-unit-tests.yml` pipeline before switching over entirely. You can pin WordPress to a specific release by passing `--build-arg WP_VERSION=6.5.2` (or any other version number) when building the image.
174 changes: 174 additions & 0 deletions docker/phpunit-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/env bash
set -euo pipefail

DB_HOST="${DB_HOST:-127.0.0.1}"
DB_NAME="${DB_NAME:-wordpress_test}"
DB_USER="${DB_USER:-wordpress}"
DB_PASSWORD="${DB_PASSWORD:-wordpress}"
WP_CORE_DIR="${WP_CORE_DIR:-/opt/wordpress}"
WP_DEVELOP_DIR="${WP_DEVELOP_DIR:-/opt/wordpress-develop}"
WP_TESTS_DIR="${WP_TESTS_DIR:-/opt/wordpress-develop/tests/phpunit}"
MYSQL_SOCKET="${MYSQL_SOCKET:-/run/mysqld/mysqld.sock}"
MYSQL_DATA_DIR="${MYSQL_DATA_DIR:-/tmp/mysql-data}"
CONFIG_SAMPLE="${WP_DEVELOP_DIR}/wp-tests-config-sample.php"
CONFIG_FILE="${WP_DEVELOP_DIR}/wp-tests-config.php"

MYSQL_RUNTIME_USER="${MYSQL_RUNTIME_USER:-$(id -un 2>/dev/null || echo root)}"
MYSQL_RUN_DIR="$(dirname "${MYSQL_SOCKET}")"

mkdir -p "${MYSQL_RUN_DIR}" "${MYSQL_DATA_DIR}"

if [ "$(id -u)" -eq 0 ]; then
chown -R "${MYSQL_RUNTIME_USER}" "${MYSQL_RUN_DIR}" "${MYSQL_DATA_DIR}"
fi

if [ ! -d "${MYSQL_DATA_DIR}/mysql" ]; then
mariadb-install-db \
--user="${MYSQL_RUNTIME_USER}" \
--datadir="${MYSQL_DATA_DIR}" \
--skip-test-db \
--auth-root-authentication-method=normal >/dev/null
fi

mariadbd \
--user="${MYSQL_RUNTIME_USER}" \
--datadir="${MYSQL_DATA_DIR}" \
--socket="${MYSQL_SOCKET}" \
--bind-address=127.0.0.1 \
--skip-networking=0 &
MYSQLD_PID=$!

cleanup() {
if kill -0 "${MYSQLD_PID}" >/dev/null 2>&1; then
mysqladmin --protocol=socket --socket="${MYSQL_SOCKET}" -uroot shutdown >/dev/null 2>&1 || true
wait "${MYSQLD_PID}" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT

MYSQL_READY=0
for _ in $(seq 1 30); do
if mysqladmin --protocol=socket --socket="${MYSQL_SOCKET}" -uroot ping >/dev/null 2>&1; then
MYSQL_READY=1
break
fi
sleep 1
done

if [ "${MYSQL_READY}" -ne 1 ]; then
echo "Timed out waiting for MariaDB to accept connections" >&2
exit 1
fi

mysql --protocol=socket --socket="${MYSQL_SOCKET}" -uroot <<SQL
CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${DB_USER}'@'%' IDENTIFIED BY '${DB_PASSWORD}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'%';
FLUSH PRIVILEGES;
SQL

if [ ! -f "${CONFIG_FILE}" ]; then
echo "wp-tests-config.php missing; recreating from sample" >&2
if [ -f "${CONFIG_SAMPLE}" ]; then
cp "${CONFIG_SAMPLE}" "${CONFIG_FILE}"
else
echo "Sample config not found at ${CONFIG_SAMPLE}" >&2
exit 1
fi
fi

sed -i "s/youremptytestdbnamehere/${DB_NAME}/" "${CONFIG_FILE}"
sed -i "s/yourusernamehere/${DB_USER}/" "${CONFIG_FILE}"
sed -i "s/yourpasswordhere/${DB_PASSWORD}/" "${CONFIG_FILE}"
sed -i "s|localhost|${DB_HOST}|1" "${CONFIG_FILE}"
sed -i "s|dirname( __FILE__ ) . '/../../'|'${WP_CORE_DIR}/'|" "${CONFIG_FILE}"

export WP_TESTS_DIR DB_HOST DB_NAME DB_USER DB_PASSWORD

# ==== Here and below is a universal "command dispatcher" ====

WORKDIR="/srv/web"
cd "$WORKDIR"

log_section() {
echo
echo "========================================"
echo ">>> $1"
echo "========================================"
}

run_composer_install() {
log_section "Composer install"
if [ -f composer.json ]; then
# Skip if vendor/ already exists.
if [ -d vendor ]; then
echo "vendor/ already exists, skipping composer install"
else
composer install --no-interaction --prefer-dist
fi
else
echo "composer.json not found in ${WORKDIR}, skipping composer install"
fi
}

run_phpunit() {
log_section "PHP Unit tests (phpunit.xml)"
vendor/bin/phpunit -c phpunit.xml "$@"
}

run_wpunit() {
log_section "WordPress Unit tests (php-wp-unit.xml)"
vendor/bin/phpunit -c php-wp-unit.xml "$@"
}

# Collect exit codes of both suites
run_all_tests() {
local phpunit_exit=0
local wpunit_exit=0

run_composer_install

run_phpunit "$@" || phpunit_exit=$?
run_wpunit "$@" || wpunit_exit=$?

if [ "$phpunit_exit" -ne 0 ] || [ "$wpunit_exit" -ne 0 ]; then
echo
echo "One or more test suites failed:"
echo " PHP Unit exit code: $phpunit_exit"
echo " WP Unit exit code: $wpunit_exit"
# If needed to distinguish, we could return, for example, the first non-zero
exit 1
fi
}

CMD="${1:-test:all}"

case "$CMD" in
test:all)
shift
run_all_tests "$@"
;;

test:phpunit)
shift
run_composer_install
run_phpunit "$@"
;;

test:wpunit)
shift
run_composer_install
run_wpunit "$@"
;;

composer-install)
shift
run_composer_install
;;

*)
# Fallback to default behavior: run the given command.
# docker run image vendor/bin/phpunit -c phpunit.xml
exec "$@"
;;
esac
13 changes: 13 additions & 0 deletions local-dev/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@ services:
networks:
- wpconnections-local

phpunit:
build:
context: ..
dockerfile: Dockerfile.phpunit
args:
PHP_VERSION: $PHP_VERSION
container_name: "${PROJECT_NAME}_phpunit"
working_dir: /srv/web/
volumes:
- ../:/srv/web/
networks:
- wpconnections-local

networks:
wpconnections-local:
driver: bridge
2 changes: 1 addition & 1 deletion makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ tests.init:

tests.run:
cd ./local-dev/ && \
docker-compose -p wpconnections exec php sh -c 'vendor/bin/phpunit -c phpunit.xml && vendor/bin/phpunit -c php-wp-unit.xml'
docker-compose -p wpconnections run --rm phpunit sh -c 'vendor/bin/phpunit -c phpunit.xml && vendor/bin/phpunit -c php-wp-unit.xml'

dev.install:
cd ./local-dev/ && \
Expand Down