Skip to content

Commit 7b6f766

Browse files
committed
test(compat): expand environment coverage
Verified wp-env Apache + MariaDB behavior against installed @wordpress/env at node_modules/@wordpress/env/lib/runtime/docker/build-docker-compose-config.js.
1 parent e84f2b7 commit 7b6f766

9 files changed

Lines changed: 291 additions & 45 deletions

File tree

.github/workflows/e2e-visual.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77

88
jobs:
99
e2e-visual:
10-
name: "E2E Visual Baselines (non-blocking)"
10+
name: "E2E Visual Baselines (Apache + MariaDB, non-blocking)"
1111
runs-on: ubuntu-24.04
1212
timeout-minutes: 30
1313

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
e2e-tests:
11-
name: "E2E Tests (Playwright)"
11+
name: "E2E Tests (Playwright, Apache + MariaDB)"
1212
runs-on: ubuntu-24.04
1313
timeout-minutes: 30
1414

.github/workflows/phpunit.yml

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
php: ['8.1', '8.2', '8.3', '8.4']
18+
php: ['8.0', '8.1', '8.2', '8.3', '8.4']
1919
steps:
2020
- name: Checkout
2121
uses: actions/checkout@v6
@@ -39,7 +39,12 @@ jobs:
3939
restore-keys: ${{ runner.os }}-composer-
4040

4141
- name: Install Composer dependencies
42-
run: composer install --no-interaction --prefer-dist
42+
run: |
43+
if [ "${{ matrix.php }}" = "8.0" ]; then
44+
composer install --no-interaction --prefer-dist --ignore-platform-req=php
45+
else
46+
composer install --no-interaction --prefer-dist
47+
fi
4348
4449
- name: Run unit tests
4550
run: composer test:unit
@@ -92,20 +97,70 @@ jobs:
9297
verbose: true
9398

9499
integration-tests:
95-
name: "Integration Tests (PHP ${{ matrix.php }}, WP ${{ matrix.wp }}, MS ${{ matrix.multisite }})"
100+
name: "Integration Tests (PHP ${{ matrix.php }}, WP ${{ matrix.wp }}, MS ${{ matrix.multisite }}, ${{ matrix.db_label }})"
96101
runs-on: ubuntu-24.04
97102
strategy:
98103
fail-fast: false
99104
matrix:
100-
php: ['8.1', '8.3']
101-
wp: ['6.7', '7.0-beta4']
102-
multisite: [false, true]
105+
include:
106+
- php: '8.0'
107+
wp: '6.2'
108+
multisite: false
109+
db_label: 'MySQL 8.0'
110+
db_image: 'mysql:8.0'
111+
- php: '8.1'
112+
wp: '6.7'
113+
multisite: false
114+
db_label: 'MySQL 8.0'
115+
db_image: 'mysql:8.0'
116+
- php: '8.1'
117+
wp: '6.7'
118+
multisite: true
119+
db_label: 'MySQL 8.0'
120+
db_image: 'mysql:8.0'
121+
- php: '8.3'
122+
wp: '6.7'
123+
multisite: false
124+
db_label: 'MySQL 8.0'
125+
db_image: 'mysql:8.0'
126+
- php: '8.3'
127+
wp: '6.7'
128+
multisite: true
129+
db_label: 'MySQL 8.0'
130+
db_image: 'mysql:8.0'
131+
- php: '8.1'
132+
wp: '7.0-beta4'
133+
multisite: false
134+
db_label: 'MySQL 8.0'
135+
db_image: 'mysql:8.0'
136+
- php: '8.1'
137+
wp: '7.0-beta4'
138+
multisite: true
139+
db_label: 'MySQL 8.0'
140+
db_image: 'mysql:8.0'
141+
- php: '8.3'
142+
wp: '7.0-beta4'
143+
multisite: false
144+
db_label: 'MySQL 8.0'
145+
db_image: 'mysql:8.0'
146+
- php: '8.3'
147+
wp: '7.0-beta4'
148+
multisite: true
149+
db_label: 'MySQL 8.0'
150+
db_image: 'mysql:8.0'
151+
- php: '8.1'
152+
wp: '6.7'
153+
multisite: false
154+
db_label: 'MariaDB LTS'
155+
db_image: 'mariadb:lts'
103156
services:
104-
mysql:
105-
image: mysql:8.0
157+
db:
158+
image: ${{ matrix.db_image }}
106159
env:
107160
MYSQL_ROOT_PASSWORD: root
108161
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
162+
MARIADB_ROOT_PASSWORD: root
163+
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 'yes'
109164
ports:
110165
- 3306:3306
111166
options: >-
@@ -143,7 +198,12 @@ jobs:
143198
restore-keys: ${{ runner.os }}-composer-
144199

145200
- name: Install Composer dependencies
146-
run: composer install --no-interaction --prefer-dist
201+
run: |
202+
if [ "${{ matrix.php }}" = "8.0" ]; then
203+
composer install --no-interaction --prefer-dist --ignore-platform-req=php
204+
else
205+
composer install --no-interaction --prefer-dist
206+
fi
147207
148208
- name: Install WordPress test suite
149209
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp }}

CONTRIBUTING.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,21 @@ npm run test:e2e:local
9090

9191
Use the local site's real admin credentials. `WP_BASE_URL` can be `http://` or `https://` depending on your local environment.
9292

93+
For WordPress Studio, use the Studio site's localhost port directly. Studio is the
94+
recommended local path for SQLite-focused verification because it avoids pretending
95+
that the default `wp-env` Docker stack exercises SQLite:
96+
97+
```bash
98+
WP_BASE_URL="http://localhost:8881" \
99+
WP_USERNAME="admin" \
100+
WP_PASSWORD="password" \
101+
npm run test:e2e:local
102+
```
103+
104+
If you point Playwright at a Studio site, keep `WP_BASE_URL` and `WP_REQUEST_BASE_URL`
105+
on the same `localhost:<port>` origin unless you intentionally configured a custom
106+
domain for that Studio instance.
107+
93108
To run the multisite network-admin regression against the `multisite-subdomains` Local site:
94109

95110
```bash

bin/install-wp-tests.sh

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,42 @@ MYSQLADMIN_BIN=""
2121
LOCAL_SOCKET_HOST_DETECTED=false
2222

2323
download() {
24-
if [ `which curl` ]; then
25-
curl -sL "$1" > "$2";
26-
elif [ `which wget` ]; then
27-
wget -nv -O "$2" "$1"
28-
else
29-
echo "Error: Neither curl nor wget is installed."
30-
exit 1
31-
fi
24+
local url="$1"
25+
local destination="$2"
26+
local tmp_destination="${destination}.tmp"
27+
local attempt=1
28+
local max_attempts=5
29+
local sleep_seconds=2
30+
31+
while [ "$attempt" -le "$max_attempts" ]; do
32+
rm -f "$tmp_destination"
33+
34+
if command -v curl > /dev/null 2>&1; then
35+
if curl -fsSL --connect-timeout 15 --max-time 300 "$url" -o "$tmp_destination"; then
36+
mv "$tmp_destination" "$destination"
37+
return 0
38+
fi
39+
elif command -v wget > /dev/null 2>&1; then
40+
if wget -q -T 30 -O "$tmp_destination" "$url"; then
41+
mv "$tmp_destination" "$destination"
42+
return 0
43+
fi
44+
else
45+
echo "Error: Neither curl nor wget is installed."
46+
exit 1
47+
fi
48+
49+
if [ "$attempt" -lt "$max_attempts" ]; then
50+
echo "Download failed (attempt $attempt/$max_attempts): $url"
51+
sleep "$sleep_seconds"
52+
sleep_seconds=$(( sleep_seconds * 2 ))
53+
fi
54+
55+
attempt=$(( attempt + 1 ))
56+
done
57+
58+
echo "Error: failed to download $url after $max_attempts attempts."
59+
exit 1
3260
}
3361

3462
# Check if svn is installed
@@ -153,7 +181,7 @@ elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
153181
WP_TESTS_TAG="trunk"
154182
else
155183
# http serves a single offer, whereas https serves multiple. we only want one
156-
download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
184+
download https://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
157185
grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
158186
LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
159187
if [[ -z "$LATEST_VERSION" ]]; then

docs/ROADMAP.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ All 5 phases shipped. Identified by independent assessments from Codex, Gemini,
110110

111111
### ✓ CI Matrix — ~~Phase A~~ ✅ Done v2.9.2
112112

113-
- PHP 8.0–8.4, WP 6.7 + latest + trunk, single-site + multisite + PCOV coverage
113+
- PHP 8.0–8.4 for unit tests; targeted integration coverage for WordPress 6.2, 6.7, and 7.0-beta4; single-site + multisite + PCOV coverage
114114

115115
---
116116

@@ -121,17 +121,18 @@ challenges and priorities for WP Sudo.
121121

122122
Current project state (as of March 8, 2026):
123123
- Current test and size counts are centralized in [`docs/current-metrics.md`](docs/current-metrics.md).
124-
- CI pipeline: unit tests on PHP 8.1–8.4; integration tests on PHP 8.1 and 8.3; WordPress 6.7 + latest + trunk; single-site + multisite + PCOV coverage job
124+
- CI pipeline: unit tests on PHP 8.0–8.4; integration tests on PHP 8.0/8.1/8.3; WordPress 6.2, 6.7, and 7.0-beta4; single-site + multisite; MySQL 8.0 plus one MariaDB lane; PCOV coverage job
125125
- WordPress 7.0 Beta 2 tested (February 27, 2026); GA is April 9, 2026
126126

127127
---
128128

129129
## 1. Integration Tests — Scope and Value
130130

131131
> **Status: Complete.** The integration test suite shipped in v2.4.0 (55 tests) and
132-
> expanded in v2.4.1 (73 tests). CI runs against PHP 8.1–8.4, WordPress latest +
133-
> trunk, single-site + multisite. The analysis below is preserved for context on
134-
> what drove the test design.
132+
> expanded in v2.4.1 (73 tests). CI now runs targeted compatibility lanes across
133+
> PHP 8.0/8.1/8.3 and WordPress 6.2, 6.7, and 7.0-beta4 with single-site +
134+
> multisite coverage. The analysis below is preserved for context on what drove
135+
> the test design.
135136
136137
### What unit tests cover well (no integration gap)
137138
- Request matching across all 7 surfaces (98 GateTest methods)
@@ -402,10 +403,10 @@ Local by Flywheel sites. Gaps remain in CI and broader hosting diversity.
402403

403404
| Dimension | Current coverage | Gap |
404405
|-----------|-----------------|-----|
405-
| **Web server** | nginx (Studio, Local multisite-subdirectory) + Apache (Local single-site, Local multisite-subdomain) | Apache in CI (mod_php, FastCGI, FPM variants) |
406-
| **PHP version** | 8.0–8.4 (CI matrix), 8.2 (Local dev) | ✅ Covered — PHP 8.0 added to CI v2.9.2 |
407-
| **Database** | MySQL 8.0 (Local CI), SQLite (Studio) | MariaDB 10.x, MySQL 5.7 (legacy hosts) |
408-
| **WordPress version** | 6.7 + latest + trunk (CI), 6.9.1–7.0-beta2 (dev sites) | 6.2–6.6 still untested; 6.7+ now covered in CI |
406+
| **Web server** | Apache + MariaDB (`wp-env` Playwright CI), nginx + SQLite (Studio local), nginx/Apache + MySQL (Local manual) | nginx in automated CI; Apache variants beyond the default `wp-env` stack |
407+
| **PHP version** | 8.0–8.4 (unit CI), 8.0/8.1/8.3 (integration CI), 8.2 (Studio/wp-env local) | 8.2 and 8.4 are still missing from integration CI |
408+
| **Database** | MySQL 8.0 (integration CI), MariaDB LTS (`wp-env` CI + one integration lane), SQLite (Studio local) | automated SQLite CI, MariaDB matrix breadth, MySQL 5.7 legacy hosts |
409+
| **WordPress version** | 6.2 support-floor lane, 6.7 stable lane, 7.0-beta4 forward lane | 6.3–6.6 still untested in automation |
409410
| **OS** | macOS (dev), Ubuntu 24.04 (CI) | Windows (if any WP-CLI or path handling is OS-sensitive) |
410411
| **Hosting stack** | Bare local dev | Shared hosting (cPanel), managed WP (Pressable, WP Engine, Cloudways), containerized (Docker, Kubernetes) |
411412

@@ -421,21 +422,20 @@ Local by Flywheel sites. Gaps remain in CI and broader hosting diversity.
421422
`json_validate()` (8.3+), readonly properties (8.2+).
422423
- **Database engine:** MariaDB and MySQL have subtle JSON and collation differences.
423424
The upgrader migration chain and option serialization could behave differently.
424-
- **Backward compat:** The plugin declares WordPress 6.2+ minimum. CI now tests
425-
6.7, latest, and trunk. WP 6.2–6.6 remain untested — 6.7 is a reasonable floor
426-
covering most active hosts.
425+
- **Backward compat:** The plugin declares WordPress 6.2+ minimum. CI now includes
426+
a dedicated 6.2 floor lane, plus 6.7 and 7.0-beta4. WP 6.3–6.6 remain untested.
427427

428428
### Recommended approach
429429

430-
**Phase A: Expand CI matrix** ✅ Done v2.9.2
430+
**Phase A: Expand CI matrix** ✅ Done v2.9.2, extended in v2.14.x
431431

432-
CI matrix now covers PHP 8.0–8.4 (unit tests) and PHP 8.0/8.1/8.3 × WP 6.7/latest/trunk × single-site/multisite (18 integration runs). Further backward compat expansion (WP 6.2–6.6) can be added incrementally if 6.7 runs cleanly.
432+
CI matrix now covers PHP 8.0–8.4 for unit tests, a 6.2 support-floor integration lane on PHP 8.0, stable/forward integration lanes on PHP 8.1 and 8.3 for WordPress 6.7 and 7.0-beta4, and one dedicated MariaDB lane. Further backward compat expansion (WP 6.3–6.6) can be added incrementally if the 6.2 floor lane stays green.
433433

434-
**Phase B: Apache + MariaDB CI job (medium effort)**
434+
**Phase B: Apache + MariaDB CI job** ✅ Covered by Playwright `wp-env`
435435

436-
Add a separate CI job that runs on an Apache + MariaDB container instead of the
437-
default nginx + MySQL. This catches `.htaccess`-dependent behavior and MariaDB
438-
query differences.
436+
The Playwright workflow already runs against the default `wp-env` Docker stack,
437+
which is Apache + MariaDB. That lane is now named explicitly in CI so it is
438+
visible as an intentional compatibility signal rather than an accidental default.
439439

440440
**Phase C: Manual testing matrix (low effort, recurring)**
441441

docs/current-metrics.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ Verification environment: primary local repo checkout at `/Users/danknauss/Devel
2020
| Metric | Value | Verification |
2121
|---|---:|---|
2222
| Production PHP lines (`includes/`, `wp-sudo.php`, `uninstall.php`, `mu-plugin/`, `bridges/`) | 8,963 | `find ./includes ./wp-sudo.php ./uninstall.php ./mu-plugin ./bridges -type f -name "*.php" -print0 | xargs -0 wc -l | tail -1` |
23-
| Tests PHP lines (`tests/`) | 17,253 | `find ./tests -type f -name "*.php" -print0 | xargs -0 wc -l | tail -1` |
24-
| Production + tests PHP lines | 26,216 | sum of the two rows above |
25-
| Test-to-production ratio | 1.92:1 | `17253 / 8963` |
26-
| Total repo PHP lines (excluding `vendor/`, `vendor_test/`, `.tmp/`, `.git/`) | 26,273 | `find . -type f -name "*.php" ! -path "*/vendor/*" ! -path "*/vendor_test/*" ! -path "*/.tmp/*" ! -path "*/.git/*" -print0 | xargs -0 wc -l | tail -1` |
23+
| Tests PHP lines (`tests/`) | 17,290 | `find ./tests -type f -name "*.php" -print0 | xargs -0 wc -l | tail -1` |
24+
| Production + tests PHP lines | 26,253 | sum of the two rows above |
25+
| Test-to-production ratio | 1.93:1 | `17290 / 8963` |
26+
| Total repo PHP lines (excluding `vendor/`, `vendor_test/`, `.tmp/`, `.git/`) | 26,310 | `find . -type f -name "*.php" ! -path "*/vendor/*" ! -path "*/vendor_test/*" ! -path "*/.tmp/*" ! -path "*/.git/*" -print0 | xargs -0 wc -l | tail -1` |
2727

2828
## Architectural Facts
2929

@@ -41,7 +41,7 @@ the count in prose without a verification command.
4141
| Audit hooks | 9 | `grep -c "do_action.*wp_sudo_" includes/class-*.php \| awk -F: '{sum+=$2} END{print sum}'` | v2.11.0 |
4242
| Settings fields (base) | 5 | 1 numeric (duration) + 4 policy dropdowns (REST, CLI, Cron, XML-RPC) | v2.0.0 |
4343
| Settings fields (with WPGraphQL) | 6 | +1 conditional WPGraphQL policy dropdown | v2.5.0 |
44-
| E2E tests | 45 | `npx playwright test --config tests/e2e/playwright.config.ts --list` | unreleased |
44+
| E2E tests | 47 | `npx playwright test --config tests/e2e/playwright.config.ts --list` | unreleased |
4545

4646
### Files that reference these counts
4747

@@ -61,8 +61,8 @@ value across these known consumers:
6161

6262
Source: `.github/workflows/phpunit.yml`
6363

64-
- Unit test matrix: PHP 8.1, 8.2, 8.3, 8.4
65-
- Integration matrix: PHP 8.1 and 8.3; WordPress 6.7 and 7.0-beta4; multisite true/false
64+
- Unit test matrix: PHP 8.0, 8.1, 8.2, 8.3, 8.4
65+
- Integration matrix: PHP 8.0, 8.1, 8.3; WordPress 6.2, 6.7, 7.0-beta4; MySQL 8.0 plus one MariaDB LTS lane; multisite true/false on the main MySQL lanes
6666

6767
## Verification Notes
6868

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
/**
3+
* Test-only mu-plugin for E2E coverage of wp_sudo_require().
4+
*
5+
* @package WP_Sudo
6+
*/
7+
8+
if ( ! defined( 'ABSPATH' ) ) {
9+
exit;
10+
}
11+
12+
add_action(
13+
'admin_init',
14+
static function (): void {
15+
if ( ! is_admin() || ! isset( $_GET['wp_sudo_require_test'] ) ) {
16+
return;
17+
}
18+
19+
if (
20+
! wp_sudo_require(
21+
array(
22+
'rule_id' => 'e2e.public_api.require',
23+
'return_url' => admin_url( '?wp_sudo_require_test=1' ),
24+
)
25+
)
26+
) {
27+
return;
28+
}
29+
30+
add_action(
31+
'admin_notices',
32+
static function (): void {
33+
echo '<div id="wp-sudo-e2e-public-api-ok" class="notice notice-success"><p>Public API require passed.</p></div>';
34+
}
35+
);
36+
}
37+
);

0 commit comments

Comments
 (0)