Skip to content

Commit 0e2d2c1

Browse files
committed
Run WordPress PHPUnit with native parser extension
1 parent 343920b commit 0e2d2c1

2 files changed

Lines changed: 159 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5+
WP_DIR="$ROOT_DIR/wordpress"
6+
COMPOSE_OVERRIDE="$WP_DIR/docker-compose.override.yml"
7+
RUNTIME_DIR="$ROOT_DIR/tmp-native-extension"
8+
EXTENSION_SOURCE_VOLUME=" - ../packages/mysql-on-sqlite/ext/wp-mysql-parser:/var/native-parser-extension-src"
9+
EXTENSION_RUNTIME_VOLUME=" - ../tmp-native-extension:/var/native-parser-extension:ro"
10+
EXTENSION_INI_VOLUME=" - ../tmp-native-extension/wp-mysql-parser.ini:/usr/local/etc/php/conf.d/wp-mysql-parser.ini:ro"
11+
12+
if [ ! -f "$COMPOSE_OVERRIDE" ]; then
13+
echo "Missing $COMPOSE_OVERRIDE. Run composer run wp-setup first." >&2
14+
exit 1
15+
fi
16+
17+
add_volume_to_service() {
18+
local service="$1"
19+
local volume="$2"
20+
21+
node - "$COMPOSE_OVERRIDE" "$service" "$volume" <<'NODE'
22+
const fs = require( 'fs' );
23+
24+
const file = process.argv[2];
25+
const service = process.argv[3];
26+
const volume = process.argv[4];
27+
const lines = fs.readFileSync( file, 'utf8' ).split( '\n' );
28+
29+
if ( lines.some( line => line.trim() === volume.trim() ) ) {
30+
process.exit( 0 );
31+
}
32+
33+
const serviceIndex = lines.findIndex( line => line === ` ${ service }:` );
34+
if ( serviceIndex === -1 ) {
35+
throw new Error( `Service ${ service } not found in ${ file }.` );
36+
}
37+
38+
let volumesIndex = -1;
39+
for ( let i = serviceIndex + 1; i < lines.length; i++ ) {
40+
if ( /^ [A-Za-z0-9_-]+:/.test( lines[i] ) ) {
41+
break;
42+
}
43+
44+
if ( lines[i].trim() === 'volumes:' ) {
45+
volumesIndex = i;
46+
break;
47+
}
48+
}
49+
50+
if ( volumesIndex === -1 ) {
51+
throw new Error( `Service ${ service } has no volumes list in ${ file }.` );
52+
}
53+
54+
let insertAt = volumesIndex + 1;
55+
while ( insertAt < lines.length && /^\s{6}- /.test( lines[insertAt] ) ) {
56+
insertAt++;
57+
}
58+
59+
lines.splice( insertAt, 0, volume );
60+
fs.writeFileSync( file, lines.join( '\n' ) );
61+
NODE
62+
}
63+
64+
add_volume_to_service php "$EXTENSION_SOURCE_VOLUME"
65+
add_volume_to_service cli "$EXTENSION_SOURCE_VOLUME"
66+
67+
cat > "$WP_DIR/native-build-extension.sh" <<'EOF'
68+
#!/bin/sh
69+
set -eu
70+
71+
apt-get update
72+
apt-get install -y --no-install-recommends ca-certificates curl build-essential clang libclang-dev pkg-config
73+
74+
if [ ! -x "$HOME/.cargo/bin/cargo" ]; then
75+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
76+
fi
77+
78+
. "$HOME/.cargo/env"
79+
80+
PHP_CONFIG="$(command -v php-config)"
81+
export PHP_CONFIG
82+
83+
LIBCLANG_SO="$(find /usr/lib /usr/local/lib -name 'libclang.so*' 2>/dev/null | head -n 1)"
84+
if [ -z "$LIBCLANG_SO" ]; then
85+
echo "Unable to locate libclang.so after installing libclang-dev." >&2
86+
exit 1
87+
fi
88+
89+
LIBCLANG_PATH="$(dirname "$LIBCLANG_SO")"
90+
export LIBCLANG_PATH
91+
92+
cd /var/native-parser-extension-src
93+
cargo build
94+
EOF
95+
96+
chmod +x "$WP_DIR/native-build-extension.sh"
97+
98+
cd "$WP_DIR"
99+
node tools/local-env/scripts/docker.js run --rm php sh /var/www/native-build-extension.sh
100+
101+
mkdir -p "$RUNTIME_DIR"
102+
cp "$ROOT_DIR/packages/mysql-on-sqlite/ext/wp-mysql-parser/target/debug/libwp_mysql_parser.so" "$RUNTIME_DIR/libwp_mysql_parser.so"
103+
printf '%s\n' 'extension=/var/native-parser-extension/libwp_mysql_parser.so' > "$RUNTIME_DIR/wp-mysql-parser.ini"
104+
105+
add_volume_to_service php "$EXTENSION_RUNTIME_VOLUME"
106+
add_volume_to_service cli "$EXTENSION_RUNTIME_VOLUME"
107+
add_volume_to_service php "$EXTENSION_INI_VOLUME"
108+
add_volume_to_service cli "$EXTENSION_INI_VOLUME"
109+
110+
node tools/local-env/scripts/docker.js run --rm php php -m | grep -qx 'wp_mysql_parser'
111+
node tools/local-env/scripts/docker.js run --rm php php -r '
112+
require "/var/www/src/wp-content/plugins/sqlite-database-integration/wp-includes/database/load.php";
113+
$lexer = new WP_MySQL_Lexer( "SELECT 1" );
114+
if ( ! method_exists( $lexer, "native_token_stream" ) ) {
115+
fwrite( STDERR, "Native token stream is not available in the WordPress PHP test container.\n" );
116+
exit( 1 );
117+
}
118+
$driver = new WP_PDO_MySQL_On_SQLite( "mysql-on-sqlite:path=:memory:;dbname=wp;" );
119+
$parser = $driver->create_parser( "SELECT 1" );
120+
$parser->next_query();
121+
$ast = $parser->get_query_ast();
122+
$property = ( new ReflectionClass( $ast ) )->getProperty( "native_ast" );
123+
$property->setAccessible( true );
124+
$native_ast = $property->getValue( $ast );
125+
if ( ! is_object( $native_ast ) || "WP_MySQL_Native_Ast" !== get_class( $native_ast ) ) {
126+
fwrite( STDERR, "WordPress PHP test container did not select the native-backed AST.\n" );
127+
exit( 1 );
128+
}
129+
'

.github/workflows/wp-tests-phpunit.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,33 @@ jobs:
3030
- name: Stop Docker containers
3131
if: always()
3232
run: composer run wp-test-clean
33+
34+
native-parser-test:
35+
name: WordPress PHPUnit Tests / Rust extension
36+
runs-on: ubuntu-latest
37+
timeout-minutes: 40
38+
39+
steps:
40+
- name: Checkout repository
41+
uses: actions/checkout@v4
42+
43+
- name: Set up Docker Buildx
44+
uses: docker/setup-buildx-action@v3
45+
46+
- name: Set UID and GID for PHP in WordPress images
47+
run: |
48+
echo "PHP_FPM_UID=$(id -u)" >> $GITHUB_ENV
49+
echo "PHP_FPM_GID=$(id -g)" >> $GITHUB_ENV
50+
51+
- name: Set up WordPress test environment
52+
run: composer run wp-setup
53+
54+
- name: Build and load parser extension in WordPress PHP containers
55+
run: bash .github/workflows/wp-tests-phpunit-native-extension-setup.sh
56+
57+
- name: Run WordPress PHPUnit tests with parser extension
58+
run: node .github/workflows/wp-tests-phpunit-run.js
59+
60+
- name: Stop Docker containers
61+
if: always()
62+
run: composer run wp-test-clean

0 commit comments

Comments
 (0)