From 6d37c07183a8d69ec20a2b5645823b65957f37da Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 12 Aug 2025 16:12:04 -0400 Subject: [PATCH 1/7] Include double quotes for environment variables Co-Authored-By: Javier Casares --- .env.default | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.env.default b/.env.default index 84de84c..8240b68 100644 --- a/.env.default +++ b/.env.default @@ -12,25 +12,25 @@ ### # Path to the directory where files can be prepared before being delivered to the environment. -export WPT_PREPARE_DIR=/tmp/wp-test-runner +export WPT_PREPARE_DIR="/tmp/wp-test-runner" # Path to the directory where the WordPress develop checkout can be placed and tests can be run. # When running tests in the same environment, set WPT_TEST_DIR to WPT_PREPARE_DIR -export WPT_TEST_DIR=wp-test-runner +export WPT_TEST_DIR="wp-test-runner" # API key to authenticate with the reporting service in 'username:password' format. -export WPT_REPORT_API_KEY= +export WPT_REPORT_API_KEY="" # (Optionally) define an alternate reporting URL -export WPT_REPORT_URL= +export WPT_REPORT_URL="" # Credentials for a database that can be written to and reset. # WARNING!!! This database will be destroyed between tests. Only use safe database credentials. # Please note that you must escape _or_ refrain from using # as special character in your credentials. -export WPT_DB_NAME= -export WPT_DB_USER= -export WPT_DB_PASSWORD= -export WPT_DB_HOST= +export WPT_DB_NAME="" +export WPT_DB_USER="" +export WPT_DB_PASSWORD="" +export WPT_DB_HOST="" # (Optionally) set a custom table prefix to permit concurrency against the same database. export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} @@ -40,26 +40,26 @@ export WPT_PHP_EXECUTABLE=${WPT_PHP_EXECUTABLE-php} # (Optionally) define the PHPUnit command execution call. # Use if `php phpunit.phar` can't be called directly for some reason. -export WPT_PHPUNIT_CMD= +export WPT_PHPUNIT_CMD="" # (Optionally) define the command execution to remove the test directory # Use if `rm -r` can't be called directly for some reason. -export WPT_RM_TEST_DIR_CMD= +export WPT_RM_TEST_DIR_CMD="" # SSH connection string (can also be an alias). # Leave empty if tests are meant to run in the same environment. -export WPT_SSH_CONNECT= +export WPT_SSH_CONNECT="" # Any options to be passed to the SSH connection # Defaults to '-o StrictHostKeyChecking=no' -export WPT_SSH_OPTIONS= +export WPT_SSH_OPTIONS="" # SSH private key, base64 encoded. -export WPT_SSH_PRIVATE_KEY_BASE64= +export WPT_SSH_PRIVATE_KEY_BASE64="" # Output logging # Use 'verbose' to increase verbosity -export WPT_DEBUG= +export WPT_DEBUG="" # Certificate validation # Use 1 to validate, and 0 to not validate From e718c0a29d210d1661bbab30805609beaacc23b3 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 12 Aug 2025 16:12:31 -0400 Subject: [PATCH 2/7] Guard against word splitting due to spaces --- .env.default | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.default b/.env.default index 8240b68..33b49c1 100644 --- a/.env.default +++ b/.env.default @@ -33,10 +33,10 @@ export WPT_DB_PASSWORD="" export WPT_DB_HOST="" # (Optionally) set a custom table prefix to permit concurrency against the same database. -export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} +export WPT_TABLE_PREFIX="${WPT_TABLE_PREFIX-wptests_}" # (Optionally) define the PHP executable to be called -export WPT_PHP_EXECUTABLE=${WPT_PHP_EXECUTABLE-php} +export WPT_PHP_EXECUTABLE="${WPT_PHP_EXECUTABLE-php}" # (Optionally) define the PHPUnit command execution call. # Use if `php phpunit.phar` can't be called directly for some reason. From b3a76f184e6d095457370b94ab94029e51297933 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 19 Aug 2025 11:27:01 -0400 Subject: [PATCH 3/7] Extract unrelated documentation changes from #212 Co-Authored-By: Javier Casares --- README.md | 363 +++++++++++++++++++++++++++++++++++++++++--------- cleanup.php | 24 ++-- functions.php | 295 ++++++++++++++++++++++++---------------- prepare.php | 51 ++++--- report.php | 27 ++-- test.php | 20 +-- 6 files changed, 542 insertions(+), 238 deletions(-) diff --git a/README.md b/README.md index 046dfad..e8c1cdc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,21 @@ +# About the PHPUnit Test Runner + +Hosting companies can have several to millions of websites hosted with WordPress, so it's important to make sure their configuration is as compatible as possible with the software. + +To verify this compatibility, the WordPress Community provides a series of PHPUnit tests with which to check the operation of WordPress in any environment. + +The Runner tests generates a report with the test results related to a bot user (a hosting company), and this captures and displays those test results at the [Host Test Result](https://make.wordpress.org/hosting/test-results/) page. + +## What's the phpunit-test-runner + +The [phpunit-test-runner](https://github.com/WordPress/phpunit-test-runner) is a tool designed to make it easier for hosting companies to run the WordPress project’s automated tests. + +There is a [whole documentation about this tool](https://make.wordpress.org/hosting/test-results-getting-started/). Also, if you want, you can make your test results appear in the [Host Test Results](https://make.wordpress.org/hosting/test-results/) page of WordPress. + +The tool can be run manually or through an automated system like Travis. To see how it works and the purpose of this document, will be shown how to run the tests manually. + +--- + # PHPUnit Test Runner Thanks for running the WordPress PHPUnit test suite on your infrastructure. We appreciate you helping to ensure WordPress’s compatibility for your users. @@ -13,7 +31,7 @@ At a high level, the test suite runner: 3. Reports the PHPUnit test results to WordPress.org 4. Cleans up the test suite environment. -## Setup +## Quick setup The test suite runner can be used in one of two ways: @@ -27,8 +45,10 @@ With a direct Git clone, you can: ```bash # Copy the default .env file. cp .env.default .env + # Edit the .env file to define your variables. vim .env + # Load your variables into scope. source .env ``` @@ -47,8 +67,10 @@ Connect to a remote environment over SSH by having the CI job provision the SSH ```bash # 1. Create a SSH key pair for the controller to use ssh-keygen -t rsa -b 4096 -C "travis@travis-ci.org" + # 2. base64 encode the private key for use with the environment variable cat ~/.ssh/id_rsa | base64 --wrap=0 + # 3. Append id_rsa.pub to authorized_keys so the CI service can SSH in cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys ``` @@ -61,21 +83,18 @@ Host wpt Hostname 123.45.67.89 User wpt Port 1234 + # 2. Use 'wpt' wherever you might normally use a SSH connection string ssh wpt ``` -## Running - -The test suite runner is run in four steps. This explanation is for the local execution. +## Requirements -### Requirements - -To use the Runner, the following is required (testing WordPress 6.5): +To use the Runner, the following is required (testing WordPress 6.7-alpha): - Server / hosting (infrastructure) with the usual configuration you use - A database where you can test (tables will be created and destroyed several times) -- PHP 7.0+ (view ) +- PHP 7.2+ - MySQL 5.5+ / MariaDB 10.0+ - NodeJS 20.x / npm 10.x / grunt - PHP Composer @@ -86,9 +105,9 @@ Test environment: - Writable filesystem for the entire test directory (see [#40910](https://core.trac.wordpress.org/ticket/40910)). - Run with a non-root user, both for security and practical purposes (see [#44233](https://core.trac.wordpress.org/ticket/44233#comment:34)/[#46577](https://core.trac.wordpress.org/ticket/46577)). -#### Database creation +### Database creation -_This is an example for MySQL / MariaDB._ +_This is a simple example for MySQL / MariaDB._ ```sql CREATE DATABASE wordpressdatabase CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci; @@ -97,9 +116,9 @@ GRANT ALL ON wordpressdatabase.* TO 'wordpressusername'@'127.0.0.1' IDENTIFIED B FLUSH PRIVILEGES; ``` -#### NodeJS installation +### NodeJS installation -_This is an example for Debian / Ubuntu._ +_This is a simple example for Debian / Ubuntu._ ```bash curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - @@ -109,9 +128,9 @@ nodejs --version npm --version ``` -#### PHP Composer +### PHP Composer -_This is an example for Debian / Ubuntu._ +_This is a simple example for Debian / Ubuntu._ ```bash curl -sS https://getcomposer.org/installer -o composer-setup.php @@ -119,35 +138,37 @@ php composer-setup.php --install-dir=/usr/local/bin --filename=composer composer --version ``` -#### Git +### Git -_This is an example for Debian / Ubuntu._ +_This is a simple example for Debian / Ubuntu._ ```bash apt -y install git git --version ``` -### Installing the Test Runner +## Installing the Runner -First, download the software. This example uses `/home/wptestrunner/` folder, but set the best for this environment. +First, download the software. This example use `/home/wptestrunner/` folder, but set the best for this environment. -```bash +``` cd /home/wptestrunner/ git clone https://github.com/WordPress/phpunit-test-runner.git cd phpunit-test-runner/ ``` +## Configuring the Runner + The next step will be to configure the environment. To do this, make a copy of the example file and then configure it. -```bash +``` cp .env.default .env vim .env ``` -The content (in summary form) can be something like this: +This is the default configuraton file: -```bash +``` ### # Configuration environment variables used by the test runner # @@ -161,28 +182,33 @@ The content (in summary form) can be something like this: # $ source .env ### -# Path to the directory where files can be prepared before being delivered to the environment. -export WPT_PREPARE_DIR=/tmp/wp-test-runner +# Path to the directory where files can be prepared before being delivered to +# the environment. +export WPT_PREPARE_DIR="/tmp/wp-test-runner" -# Path to the directory where the WordPress develop checkout can be placed and tests can be run. -# When running tests in the same environment, set WPT_TEST_DIR to WPT_PREPARE_DIR -export WPT_TEST_DIR=/tmp/wp-test-runner +# Path to the directory where the WordPress develop checkout can be placed and +# tests can be run. When running tests in the same environment, set WPT_TEST_DIR +# to WPT_PREPARE_DIR +export WPT_TEST_DIR="/tmp/wp-test-runner" -# API key to authenticate with the reporting service in 'username:password' format. -export WPT_REPORT_API_KEY= +# API key to authenticate with the reporting service in 'username:password' +# format. +export WPT_REPORT_API_KEY="" # (Optionally) define an alternate reporting URL -export WPT_REPORT_URL= +export WPT_REPORT_URL="" # Credentials for a database that can be written to and reset. -# WARNING!!! This database will be destroyed between tests. Only use safe database credentials. -# Please note that you must escape _or_ refrain from using # as special character in your credentials. -export WPT_DB_NAME= -export WPT_DB_USER= -export WPT_DB_PASSWORD= -export WPT_DB_HOST= - -# (Optionally) set a custom table prefix to permit concurrency against the same database. +# WARNING!!! This database will be destroyed between tests. Only use safe +# database credentials. Please note that you must escape _or_ refrain from +# using # as special character in your credentials. +export WPT_DB_NAME="" +export WPT_DB_USER="" +export WPT_DB_PASSWORD="" +export WPT_DB_HOST="" + +# (Optionally) set a custom table prefix to permit concurrency against the same +# database. export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} # (Optionally) define the PHP executable to be called @@ -190,26 +216,26 @@ export WPT_PHP_EXECUTABLE=${WPT_PHP_EXECUTABLE-php} # (Optionally) define the PHPUnit command execution call. # Use if `php phpunit.phar` can't be called directly for some reason. -export WPT_PHPUNIT_CMD= +export WPT_PHPUNIT_CMD="" # (Optionally) define the command execution to remove the test directory # Use if `rm -r` can't be called directly for some reason. -export WPT_RM_TEST_DIR_CMD= +export WPT_RM_TEST_DIR_CMD="" # SSH connection string (can also be an alias). # Leave empty if tests are meant to run in the same environment. -export WPT_SSH_CONNECT= +export WPT_SSH_CONNECT="" # Any options to be passed to the SSH connection # Defaults to '-o StrictHostKeyChecking=no' -export WPT_SSH_OPTIONS= +export WPT_SSH_OPTIONS="" # SSH private key, base64 encoded. -export WPT_SSH_PRIVATE_KEY_BASE64= +export WPT_SSH_PRIVATE_KEY_BASE64="" # Output logging # Use 'verbose' to increase verbosity -export WPT_DEBUG= +export WPT_DEBUG="" # Certificate validation # Use 1 to validate, and 0 to not validate @@ -218,7 +244,7 @@ export WPT_CERTIFICATE_VALIDATION=1 # WordPress flavor # 0 = WordPress (simple version) # 1 = WordPress Multisite -export WPT_FLAVOR=1 +export WPT_FLAVOR=0 # Extra tests (groups) # 0 = none @@ -226,15 +252,186 @@ export WPT_FLAVOR=1 # 2 = ms-files # 3 = external-http export WPT_EXTRATESTS=0 +```` + +### Configuration file + +And this could be an example of each part: + +**Preparation directory** + +Path to the directory where files can be prepared before being delivered to the environment. + +Usually can be a /tmp/ folder so it does everything temporary. + +``` +export WPT_PREPARE_DIR="/tmp/wp-test-runner" +``` + +**Test directory** + +Path to the directory where the WordPress develop checkout can be placed and tests can be run. When running tests in the same environment, set WPT_TEST_DIR to WPT_PREPARE_DIR equally. + + +``` +export WPT_TEST_DIR="/tmp/wp-test-runner" +``` + +**API KEY** + +API key to authenticate with the reporting service in 'username:password' format. This is only needed if you want to publish your results in the WordPress site, so data can help developers to improve WordPress. + +Read: [How to report: Creating your bot for WordPress.org](https://make.wordpress.org/hosting/handbook/tests/#how-to-report-creating-your-bot-for-wordpress-org) + +``` +export WPT_REPORT_API_KEY="userbot:12345ABCDE67890F" +``` + +**Reporting URL** + +(Optionally) Define an alternate reporting URL, if you are running your own website. + +It should look like: +`https://reporter.example.com/wp-json/wp-unit-test-api/v1/results` + +``` +export WPT_REPORT_URL="https://reporter.example.com/wp-json/wp-unit-test-api/v1/results" +``` + +**Database credentials** + +Credentials for a database that can be written to and reset. + +WARNING: This database will be destroyed between tests. Only use safe database credentials. + +Please note that you must escape _or_ refrain from using # as special character in your credentials. + + +``` +export WPT_DB_NAME="testbot" +export WPT_DB_USER="wpuser" +export WPT_DB_PASSWORD="wppassword" +export WPT_DB_HOST="localhost" +``` + +**Tables Custom prefix** + +(Optionally) Set a custom table prefix to allow concurrency against the same database. This is very useful if you activate the multi-php or multi-environment part. + +``` +export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} +``` + +**PHP versions** + +_There are two options for backward compatibility._ + +The first one is the binary file / path for the default PHP. If it's empty it will use "php" as the command. + +``` +export WPT_PHP_EXECUTABLE=${WPT_PHP_EXECUTABLE-php} +``` + +The second one is the optional part. This allow to test more than one PHP versions. The format to use is: + +_majorversion1=binary_path1;majorversion2=binary_path2_ + +or, something like: + +`8.1=/bin/php8.1;8.2=/bin/php8.2;8.3=/bin/php8.3` + +Use as much versions as you want, but it will take more time. The idea is to put all the versions offered to users. + +``` +export WPT_PHP_EXECUTABLE_MULTI="7.4=/bin/php7.4;8.3=/bin/php8.3" +``` + +**PHPUnit execution call** + +(Optionally) define the PHPUnit command execution call. Use if `php phpunit.phar` can't be called directly for some reason. + +``` +export WPT_PHPUNIT_CMD="" +``` + +**Remove directory command** + +(Optionally) define the command execution to remove the test directory. Use if `rm -r` can't be called directly for some reason. + +``` +export WPT_RM_TEST_DIR_CMD="" +``` + +**SSH connection** + +SSH connection string (can also be an alias). Leave empty if tests are meant to run in the same environment. + +``` +export WPT_SSH_CONNECT="" +``` + +**SSH connection options** + +Any options to be passed to the SSH connection. Defaults to `-o StrictHostKeyChecking=no`. + +``` +export WPT_SSH_OPTIONS="" +``` + +**SSH private key** + +SSH private key, base64 encoded. + +``` +export WPT_SSH_PRIVATE_KEY_BASE64="" +``` + +**Output logging** + +Output logging. Use 'verbose' to increase verbosity. + +``` +export WPT_DEBUG="" +``` + +**Certificate validation** + +TLS Certificate validation. Use `1` to validate, and `0` to not validate. + +This may be useful in some environments with OpenSSL limitations (usually local environments). + +``` +export WPT_CERTIFICATE_VALIDATION=0 +``` + +**WordPress flavor** + +tests can check a simple WordPress installation or a WordPress Multisite installation. Pick your favor: + +Use `0` for a simple WordPress or `1` for a WordPress Multisite. + +``` +export WPT_FLAVOR=0 +``` + +**Extra tests (groups)** + +- `0` = none +- `1` = ajax +- `2` = ms-files +- `3` = external-http + +``` +export WPT_EXTRATESTS=0 ``` Configure the folder where the WordPress software downloads and the database accesses will be made in order to prepare the tests. -### Preparing the environment +## Preparing the environment Before performing the first test, let’s update all the components. This process can be run before each test in this environment if wanted to keep it up to date, although it will depend more if it is in a production environment. -```bash +``` cd /home/wptestrunner/phpunit-test-runner/ git pull source .env @@ -255,7 +452,7 @@ Now there is the environment ready, run the test preparation. php prepare.php ``` -The system will run a long series of installations, configurations and compilations of different elements in order to prepare the test. If warnings and warnings come out you should not worry too much, as it is quite normal. At the end of the process it will warn you if it needs something it doesn’t have. If it works, you should see something like this at the end: +The system will run a long series of installations, configurations and compilations of different elements in order to prepare the test. If warnings and warnings come out you should not worry too much, as it is quite normal. At the end of the process it will warn you if it needs something it doesn't have. If it works, you should see something like this at the end: ``` Success: Prepared environment. @@ -263,7 +460,7 @@ Success: Prepared environment. Now that the environment has been prepared, the next step is to run the tests for the first time. -### Running the test +## Running the test Now that the environment is ready, let’s run the tests. To do this, execute the file that will perform it. @@ -285,7 +482,7 @@ What do the symbols mean? If you follow these steps, everything should work perfectly and not make any mistakes. In case you get any error, it may be normal due to some missing adjustment or extension of PHP, among others. We recommend that you adjust the configuration until it works correctly. After all, this tool is to help you improve the optimal configuration for WordPress in that infrastructure. -### Creating a report +## Creating a report Even if the test has failed, a report will be made. The first one shows the information about our environment. Among the most important elements are the extensions that are commonly used in WordPress and some utilities that are also generally useful. @@ -325,7 +522,7 @@ The content of this file is somewhat similar to this: } ``` -In addition to this report, a definitive file with all the information of what happened in the tests. This is the one that includes all the tests that are made (more than 10,000) giving information of the time that they take to be executed, problems that have arisen… +In addition to this report, a definitive file with all the information of what happened in the tests. This is the one that includes all the tests that are made (more than 20,000) giving information of the time that they take to be executed, problems that have arisen… ```bash cat /tmp/wp-test-runner/tests/phpunit/build/logs/junit.xml @@ -337,7 +534,7 @@ At this point we can generate the reports by sending them to WordPress.org, if n php report.php ``` -### Cleaning up the environment for other tests +## Cleaning up the environment for other tests Having the tests working, all that remains is to delete all the files that have been created so that we can start over. To do this, execute the following command: @@ -345,24 +542,64 @@ Having the tests working, all that remains is to delete all the files that have php cleanup.php ``` -### Automatic running +## Automatic running + +There are many ways to execute tests automatically. In many cases, it will depend on what you want to do and test. + +Keep in mind some aspects: + +- Tests usually take several minutes, but the system includes a mechanism to avoid repeating them. This can result in durations ranging from hours to seconds. +- When configuring the system, ensure that tests do not overlap by implementing a system that prevents a test from being re-executed if it is already running. +- Tests update their software. The configuration file is typically compatible with previous versions. + +Some suggestions: + +- Create a script (for example, in Bash) that includes all the steps to execute, including: + - Updating the Git branch + - Loading the configuration file + - Executing the 4 steps / PHP files. +- Use a task scheduling system: + - Using cron + - Using systemd.timer + +### Script en Bash + +This is a simple example of a Bash script that could be placed in the directory above the software. For example, at `/home/wptestrunner/`. + +```bash +cat > /home/wptestrunner/testrunner.sh << EOF +cd /home/wptestrunner/phpunit-test-runner/ +git pull +git checkout master +source .env +php prepare.php +php test.php +php report.php +php cleanup.php +EOF +chmod +x /home/wptestrunner/testrunner.sh +``` + +From this moment on, if you run `bash /home/wptestrunner/testrunner.sh`, the test will execute once. + +### systemd timer -The best way to run this test is to create a cron that runs everything. Having in mind that the tests can overlap, the best way can be using a systemd timer. +The best way to run this test is to create a cron that runs everything. Having in mind that the tests can overlap, the best way can be using a systemd timer and the bash script. ```bash -cat > /etc/systemd/system/wordpressphpunittestrunner.service << EOF +cat > /etc/systemd/system/testrunner.service << EOF [Unit] Description=WordPress PHPUnit Test Runner [Service] Type=oneshot -ExecStart=cd /home/wptestrunner/phpunit-test-runner/ && source .env && php prepare.php && php test.php && php report.php && php cleanup.php +ExecStart=bash /home/wptestrunner/testrunner.sh User=wptestrunner Group=wptestrunner EOF ``` ```bash -cat > /etc/systemd/system/wordpressphpunittestrunner.timer << EOF +cat > /etc/systemd/system/testrunner.timer << EOF [Unit] Description=WordPress PHPUnit Test Runner [Timer] @@ -375,16 +612,16 @@ EOF ```bash systemctl daemon-reload -systemctl enable wordpressphpunittestrunner.timer -systemctl start wordpressphpunittestrunner.timer -systemctl status wordpressphpunittestrunner.timer +systemctl enable testrunner.timer +systemctl start testrunner.timer +systemctl status testrunner.timer ``` If you want to check how is everything working... ```bash -journalctl -u wordpressphpunittestrunner.timer -journalctl -n 120 -u wordpressphpunittestrunner.service +journalctl -u testrunner.timer +journalctl -n 120 -u testrunner.service ``` ## Contributing @@ -393,4 +630,4 @@ If you have questions about the process or run into test failures along the way, ## License -See [LICENSE](LICENSE) for project license. \ No newline at end of file +See [LICENSE](LICENSE) for project license. diff --git a/cleanup.php b/cleanup.php index e584c6c..3b13c23 100644 --- a/cleanup.php +++ b/cleanup.php @@ -1,24 +1,26 @@ xpath( '//testsuites//testsuite[ ( count( testcase ) > 0 ) and ( @errors > 0 or @failures > 0 ) ]' ); foreach ( $testsuites as $testsuite ) { $result = array( @@ -178,6 +213,8 @@ function process_junit_xml( $xml_string ) 'failures' => (string) $testsuite['failures'], 'errors' => (string) $testsuite['errors'] ); + + // Only include suites with failures or errors. if ( empty( $result['failures'] ) && empty( $result['errors'] ) ) { continue; } @@ -199,35 +236,51 @@ function process_junit_xml( $xml_string ) } } - return json_encode( $results ); + return json_encode( $results ); // Return the results as a JSON encoded string. } /** - * Submits test results along with associated metadata to a specified reporting API. The function constructs - * a POST request containing the test results, SVN revision, SVN message, environment data, and uses an API key - * for authentication. The reporting API's URL is retrieved from an environment variable; if not found, a default - * URL is used. This function is typically used to automate the reporting of test outcomes to a centralized system - * for analysis, tracking, and historical record-keeping. - * - * @param string $results The test results in a processed format (e.g., JSON) ready for submission to the reporting API. - * @param string $rev The SVN revision associated with the test results. This often corresponds to a specific code - * commit or build identifier. - * @param string $message The SVN commit message associated with the revision, providing context or notes about the changes. - * @param string $env The environment data in JSON format, detailing the conditions under which the tests were run, - * such as operating system, PHP version, etc. - * @param string $api_key The API key for authenticating with the reporting API, ensuring secure and authorized access. - * - * @return array An array containing two elements: the HTTP status code of the response (int) and the body of the response - * (string) from the reporting API. This can be used to verify successful submission or to handle errors. - * - * @uses curl_init(), curl_setopt(), and curl_exec() to perform the HTTP POST request to the reporting API. - * @uses json_encode() to encode the data payload as a JSON string for submission. - * @uses base64_encode() to encode the API key for HTTP Basic Authentication in the Authorization header. + * Submits test results along with associated metadata to a specified reporting + * API. The function constructs a POST request containing the test results, SVN + * revision, SVN message, environment data, and uses an API key for + * authentication. The reporting API's URL is retrieved from an environment + * variable; if not found, a default URL is used. This function is typically + * used to automate the reporting of test outcomes to a centralized system for + * analysis, tracking, and historical record-keeping. + * + * @param string $results The test results in a processed format (e.g., JSON) + * ready for submission to the reporting API. + * + * @param string $rev The SVN revision associated with the test results. This + * often corresponds to a specific code commit or build identifier. + * + * @param string $message The SVN commit message associated with the revision, + * providing context or notes about the changes. + * + * @param string $env The environment data in JSON format, detailing the + * conditions under which the tests were run, such as operating system, PHP + * version, etc. + * + * @param string $api_key The API key for authenticating with the reporting API, + * ensuring secure and authorized access. + * + * @return array An array containing two elements: the HTTP status code of the + * response (int) and the body of the response (string) from the reporting API. + * This can be used to verify successful submission or to handle errors. + * + * @uses curl_init(), curl_setopt(), and curl_exec() to perform the HTTP POST + * request to the reporting API. + * + * @uses json_encode() to encode the data payload as a JSON string for + * submission. + * + * @uses base64_encode() to encode the API key for HTTP Basic Authentication in + * the Authorization header. */ function upload_results( $results, $rev, $message, $env, $api_key ) { $WPT_REPORT_URL = getenv( 'WPT_REPORT_URL' ); if ( ! $WPT_REPORT_URL ) { - $WPT_REPORT_URL = 'https://make.wordpress.org/hosting/wp-json/wp-unit-test-api/v1/results'; + $WPT_REPORT_URL = 'https://make.wordpress.org/hosting/wp-json/wp-unit-test-api/v1/results'; // Default URL. } $process = curl_init( $WPT_REPORT_URL ); $access_token = base64_encode( $api_key ); @@ -237,8 +290,10 @@ function upload_results( $results, $rev, $message, $env, $api_key ) { 'message' => $message, 'env' => $env, ); - $data_string = json_encode( $data ); + $data_string = json_encode( $data ); // Convert data to JSON format. + + // Set CURL options. curl_setopt( $process, CURLOPT_TIMEOUT, 30 ); curl_setopt( $process, CURLOPT_POST, 1 ); curl_setopt( $process, CURLOPT_CUSTOMREQUEST, 'POST' ); @@ -251,44 +306,48 @@ function upload_results( $results, $rev, $message, $env, $api_key ) { 'Content-Length: ' . strlen( $data_string ) )); - $return = curl_exec( $process ); - $status_code = curl_getinfo( $process, CURLINFO_HTTP_CODE ); - curl_close( $process ); + $return = curl_exec( $process ); // Execute the request. + $status_code = curl_getinfo( $process, CURLINFO_HTTP_CODE ); // Get the HTTP status code. + curl_close( $process ); // Close CURL session. - return array( $status_code, $return ); + return array( $status_code, $return ); // Return status code and response. } /** - * Collects and returns an array of key environment details relevant to the application's context. This includes - * the PHP version, installed PHP modules with their versions, system utilities like curl and OpenSSL versions, - * MySQL version, and operating system details. This function is useful for diagnostic purposes, ensuring - * compatibility, or for reporting system configurations in debugging or error logs. - * - * The function checks for the availability of specific PHP modules and system utilities and captures their versions. - * It uses shell commands to retrieve system information, which requires the PHP environment to have access to these - * commands and appropriate permissions. + * Collects and returns an array of key environment details relevant to the + * application's context. This includes the PHP version, installed PHP modules + * with their versions, system utilities like curl and OpenSSL versions, MySQL + * version, and operating system details. This function is useful for diagnostic + * purposes, ensuring compatibility, or for reporting system configurations in + * debugging or error logs. + * The function checks for the availability of specific PHP modules and system + * utilities and captures their versions. It uses shell commands to retrieve + * system information, which requires the PHP environment to have access to + * these commands and appropriate permissions. * * @return array An associative array containing detailed environment information. The array includes: - * - 'php_version': The current PHP version. - * - 'php_modules': An associative array of selected PHP modules and their versions. - * - 'system_utils': Versions of certain system utilities such as 'curl', 'imagemagick', 'graphicsmagick', and 'openssl'. - * - 'mysql_version': The version of MySQL installed. - * - 'os_name': The name of the operating system. - * - 'os_version': The version of the operating system. + * - 'php_version': The current PHP version. + * - 'php_modules': An associative array of selected PHP modules and their versions. + * - 'system_utils': Versions of certain system utilities such as 'curl', 'imagemagick', 'graphicsmagick', and 'openssl'. + * - 'mysql_version': The version of MySQL installed. + * - 'os_name': The name of the operating system. + * - 'os_version': The version of the operating system. * * @uses phpversion() to get the PHP version and module versions. + * * @uses shell_exec() to execute system commands for retrieving MySQL version, OS details, and versions of utilities like curl and OpenSSL. + * * @uses class_exists() to check for the availability of the Imagick and Gmagick classes for version detection. */ function get_env_details() { $gd_info = array(); if( extension_loaded( 'gd' ) ) { - $gd_info = gd_info(); + $gd_info = gd_info(); // Get GD info if the GD extension is loaded. } $imagick_info = array(); if( extension_loaded( 'imagick' ) ) { - $imagick_info = Imagick::queryFormats(); + $imagick_info = Imagick::queryFormats(); // Get Imagick info if the Imagick extension is loaded. } $env = array( @@ -363,16 +422,16 @@ function curl_selected_bits($k) { return in_array($k, array('version', 'ssl_vers if ( class_exists( 'Imagick' ) ) { $imagick = new Imagick(); $version = $imagick->getVersion(); - preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', $version['versionString'], $version ); - $env['system_utils']['imagemagick'] = $version[1]; + preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', $version['versionString'], $matches ); + $env['system_utils']['imagemagick'] = $matches[1]; // Get Imagick version. } elseif ( class_exists( 'Gmagick' ) ) { $gmagick = new Gmagick(); $version = $gmagick->getversion(); - preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', $version['versionString'], $version ); - $env['system_utils']['graphicsmagick'] = $version[1]; + preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', $version['versionString'], $matches ); + $env['system_utils']['graphicsmagick'] = $matches[1]; // Get GraphicsMagick version. } - $env['system_utils']['openssl'] = str_replace( 'OpenSSL ', '', trim( shell_exec( 'openssl version' ) ) ); + $env['system_utils']['openssl'] = str_replace( 'OpenSSL ', '', trim( shell_exec( 'openssl version' ) ) ); // Get OpenSSL version. - return $env; + return $env; // Return the collected environment details. } diff --git a/prepare.php b/prepare.php index 2948b70..e2c0126 100644 --- a/prepare.php +++ b/prepare.php @@ -1,26 +1,27 @@ getVersion(); - preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', \$version['versionString'], \$version ); - \$env['system_utils']['imagemagick'] = \$version[1]; -} elseif ( class_exists( 'Gmagick' ) ) { + preg_match('/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', \$version['versionString'], \$matches); + \$env['system_utils']['imagemagick'] = \$matches[1] ?? 'Unknown'; +} elseif (class_exists('Gmagick')) { \$gmagick = new Gmagick(); - \$version = \$gmagick->getversion(); - preg_match( '/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', \$version['versionString'], \$version ); - \$env['system_utils']['graphicsmagick'] = \$version[1]; + \$version = \$gmagick->getVersion(); + preg_match('/Magick (\d+\.\d+\.\d+-\d+|\d+\.\d+\.\d+|\d+\.\d+\-\d+|\d+\.\d+)/', \$version['versionString'], \$matches); + \$env['system_utils']['graphicsmagick'] = \$matches[1] ?? 'Unknown'; } \$env['system_utils']['openssl'] = str_replace( 'OpenSSL ', '', trim( shell_exec( 'openssl version' ) ) ); //\$mysqli = new mysqli( WPT_DB_HOST, WPT_DB_USER, WPT_DB_PASSWORD, WPT_DB_NAME ); @@ -314,8 +313,8 @@ function curl_selected_bits(\$k) { return in_array(\$k, array('version', 'ssl_ve } /** - * Use Composer to manage PHPUnit and its dependencies. - * This allows for better dependency management and compatibility. + * Performs a series of operations to set up the test environment. This includes creating a preparation directory, + * cloning the WordPress development repository, downloading the WordPress importer plugin, and preparing the environment with npm. */ // Check if Composer is installed and available in the PATH. diff --git a/report.php b/report.php index b690f76..b7ea593 100644 --- a/report.php +++ b/report.php @@ -1,26 +1,28 @@ Date: Tue, 19 Aug 2025 11:45:33 -0400 Subject: [PATCH 4/7] Remove double quoting of variables. This will be hanlded in #254 instead. --- .env.default | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.env.default b/.env.default index 33b49c1..84de84c 100644 --- a/.env.default +++ b/.env.default @@ -12,54 +12,54 @@ ### # Path to the directory where files can be prepared before being delivered to the environment. -export WPT_PREPARE_DIR="/tmp/wp-test-runner" +export WPT_PREPARE_DIR=/tmp/wp-test-runner # Path to the directory where the WordPress develop checkout can be placed and tests can be run. # When running tests in the same environment, set WPT_TEST_DIR to WPT_PREPARE_DIR -export WPT_TEST_DIR="wp-test-runner" +export WPT_TEST_DIR=wp-test-runner # API key to authenticate with the reporting service in 'username:password' format. -export WPT_REPORT_API_KEY="" +export WPT_REPORT_API_KEY= # (Optionally) define an alternate reporting URL -export WPT_REPORT_URL="" +export WPT_REPORT_URL= # Credentials for a database that can be written to and reset. # WARNING!!! This database will be destroyed between tests. Only use safe database credentials. # Please note that you must escape _or_ refrain from using # as special character in your credentials. -export WPT_DB_NAME="" -export WPT_DB_USER="" -export WPT_DB_PASSWORD="" -export WPT_DB_HOST="" +export WPT_DB_NAME= +export WPT_DB_USER= +export WPT_DB_PASSWORD= +export WPT_DB_HOST= # (Optionally) set a custom table prefix to permit concurrency against the same database. -export WPT_TABLE_PREFIX="${WPT_TABLE_PREFIX-wptests_}" +export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} # (Optionally) define the PHP executable to be called -export WPT_PHP_EXECUTABLE="${WPT_PHP_EXECUTABLE-php}" +export WPT_PHP_EXECUTABLE=${WPT_PHP_EXECUTABLE-php} # (Optionally) define the PHPUnit command execution call. # Use if `php phpunit.phar` can't be called directly for some reason. -export WPT_PHPUNIT_CMD="" +export WPT_PHPUNIT_CMD= # (Optionally) define the command execution to remove the test directory # Use if `rm -r` can't be called directly for some reason. -export WPT_RM_TEST_DIR_CMD="" +export WPT_RM_TEST_DIR_CMD= # SSH connection string (can also be an alias). # Leave empty if tests are meant to run in the same environment. -export WPT_SSH_CONNECT="" +export WPT_SSH_CONNECT= # Any options to be passed to the SSH connection # Defaults to '-o StrictHostKeyChecking=no' -export WPT_SSH_OPTIONS="" +export WPT_SSH_OPTIONS= # SSH private key, base64 encoded. -export WPT_SSH_PRIVATE_KEY_BASE64="" +export WPT_SSH_PRIVATE_KEY_BASE64= # Output logging # Use 'verbose' to increase verbosity -export WPT_DEBUG="" +export WPT_DEBUG= # Certificate validation # Use 1 to validate, and 0 to not validate From 17b6e6301ecf566dc5ebf5f842d455e4f399972b Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 19 Aug 2025 11:47:35 -0400 Subject: [PATCH 5/7] Copy over `.env.default` comment changes Co-Authored-By: Javier Casares --- .env.default | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.env.default b/.env.default index 84de84c..7ac902b 100644 --- a/.env.default +++ b/.env.default @@ -11,28 +11,33 @@ # $ source .env ### -# Path to the directory where files can be prepared before being delivered to the environment. +# Path to the directory where files can be prepared before being delivered to +# the environment. export WPT_PREPARE_DIR=/tmp/wp-test-runner -# Path to the directory where the WordPress develop checkout can be placed and tests can be run. -# When running tests in the same environment, set WPT_TEST_DIR to WPT_PREPARE_DIR -export WPT_TEST_DIR=wp-test-runner +# Path to the directory where the WordPress develop checkout can be placed and +# tests can be run. When running tests in the same environment, set WPT_TEST_DIR +# to WPT_PREPARE_DIR +export WPT_TEST_DIR=/tmp/wp-test-runner -# API key to authenticate with the reporting service in 'username:password' format. +# API key to authenticate with the reporting service in 'username:password' +# format. export WPT_REPORT_API_KEY= # (Optionally) define an alternate reporting URL export WPT_REPORT_URL= # Credentials for a database that can be written to and reset. -# WARNING!!! This database will be destroyed between tests. Only use safe database credentials. -# Please note that you must escape _or_ refrain from using # as special character in your credentials. +# WARNING!!! This database will be destroyed between tests. Only use safe +# database credentials. Please note that you must escape _or_ refrain from +# using # as special character in your credentials. export WPT_DB_NAME= export WPT_DB_USER= export WPT_DB_PASSWORD= export WPT_DB_HOST= -# (Optionally) set a custom table prefix to permit concurrency against the same database. +# (Optionally) set a custom table prefix to permit concurrency against the same +# database. export WPT_TABLE_PREFIX=${WPT_TABLE_PREFIX-wptests_} # (Optionally) define the PHP executable to be called From be0b307bbb44a19c14788da1d530e4074ac1a125 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 19 Aug 2025 14:36:18 -0400 Subject: [PATCH 6/7] Include handbook link for requirements Co-Authored-By: Javier Casares --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ffde4b..73917db 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ ssh wpt ## Requirements -To use the Runner, the following is required (testing WordPress 6.7-alpha): +To use the Runner, the following is required to test WordPress version 6.6 or later: - Server / hosting (infrastructure) with the usual configuration you use - A database where you can test (tables will be created and destroyed several times) @@ -100,6 +100,8 @@ To use the Runner, the following is required (testing WordPress 6.7-alpha): - PHP Composer - Git, RSync, WGet, UnZip +A full list of compatible versions of PHP for each version of WordPress [can be found in the WordPress Core Handbook](https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/). + Test environment: - Writable filesystem for the entire test directory (see [#40910](https://core.trac.wordpress.org/ticket/40910)). From 0932c1c34e19dd4e03ee32aa81c1aeb11baddaa3 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 19 Aug 2025 21:10:09 -0400 Subject: [PATCH 7/7] Few more documentation fixes. This makes the following improvements: - Ensure each function, and file have a proper short description. - Use third-person singular verbs for function summaries. - Enforces the 80 character limit (120 when indentation is present) for DocBlocks. - Code should be self-documenting. Avoid explaining every step of the code. - Multi-line inline comments should start with `/*` not `/**`. Co-Authored-By: Javier Casares --- cleanup.php | 58 +++++++++++--------- functions.php | 141 +++++++++++++++++++++++++------------------------ prepare.php | 143 +++++++++++++++++++++++++++----------------------- report.php | 116 ++++++++++++++++------------------------ test.php | 34 ++++++------ 5 files changed, 241 insertions(+), 251 deletions(-) diff --git a/cleanup.php b/cleanup.php index 3b13c23..6621751 100644 --- a/cleanup.php +++ b/cleanup.php @@ -1,8 +1,12 @@ trim( getenv( 'WPT_TABLE_PREFIX' ) ) ? : 'wptests_', @@ -263,15 +274,14 @@ function curl_selected_bits(\$k) { return in_array(\$k, array('version', 'ssl_ve // Write the modified content to the wp-tests-config.php file, which will be used by the test suite. file_put_contents( $WPT_PREPARE_DIR . '/wp-tests-config.php', $contents ); -/** - * Determines the PHP version of the test environment to ensure the correct version of PHPUnit is installed. - * It constructs a command that prints out the PHP version in a format compatible with PHPUnit's version requirements. +/* + * Construct a command that generates a PHP version string compatible with + * PHPUnit version requirements. */ $php_version_cmd = $WPT_PHP_EXECUTABLE . " -r \"print PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION;\""; /** - * If an SSH connection string is provided, the command to determine the PHP version is modified - * to execute remotely over SSH. This is required if the test environment is not the local machine. + * This command will differ when running on a remote server via SSH. */ if ( ! empty( $WPT_SSH_CONNECT ) ) { // The PHP version check command is prefixed with the SSH command, including SSH options, @@ -282,9 +292,12 @@ function curl_selected_bits(\$k) { return in_array(\$k, array('version', 'ssl_ve // Initialize return value variable for the exec function call. $retval = 0; -/** - * Executes the constructed command to obtain the PHP version of the test environment. - * The output is stored in $env_php_version, and the return value of the command execution is stored in $retval. +/* + * Execute the constructed command to obtain the PHP version of the test + * environment. + * + * The output is stored in $env_php_version and the return value of the + * command execution is stored in $retval. */ $env_php_version = exec( $php_version_cmd, $output, $retval ); @@ -297,20 +310,16 @@ function curl_selected_bits(\$k) { return in_array(\$k, array('version', 'ssl_ve // Log the obtained PHP version for confirmation and debugging purposes. log_message( 'Environment PHP Version: ' . $env_php_version ); -/** - * Checks if the detected PHP version is below 7.2. - * The test runner requires PHP version 7.2 or above, and if the environment's PHP version - * is lower, it logs an error message and could terminate the script. +/* + * Confirm that the environment meets the minimum PHP version requirement. + * + * When the requirements are not met, execution will end with an error message. */ if ( version_compare( $env_php_version, '7.2', '<' ) ) { // Logs an error message indicating the test runner's incompatibility with PHP versions below 7.2. error_message( 'The test runner is not compatible with PHP < 7.2.' ); } -/** - * Performs a series of operations to set up the test environment. This includes creating a preparation directory, - * cloning the WordPress development repository, downloading the WordPress importer plugin, and preparing the environment with npm. - */ // Check if Composer is installed and available in the PATH. $composer_cmd = 'cd ' . escapeshellarg( $WPT_PREPARE_DIR ) . ' && '; @@ -341,10 +350,14 @@ function curl_selected_bits(\$k) { return in_array(\$k, array('version', 'ssl_ve $composer_cmd . 'update', ) ); -/** - * If an SSH connection is configured, use rsync to transfer the prepared files to the remote test environment. - * The -r option for rsync enables recursive copying to handle directory structures. - * Additional rsync options may be included for more verbose output if debugging is enabled. +/* + * Transfer the built WordPress codebase to the remote test environment. + * + * When an SSH connection is configured, rsync is used to copy the files + * required tp rim the WordPress PHPUnit test suite. + * + * The -r option for rsync enables recursive copying to handle nested directory + * structures. */ if ( ! empty( $WPT_SSH_CONNECT ) ) { // Initialize rsync options with recursive copying. diff --git a/report.php b/report.php index b7ea593..ea4888b 100644 --- a/report.php +++ b/report.php @@ -1,10 +1,15 @@