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
1 change: 1 addition & 0 deletions .readme-partials/USING.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ The following environment variables can be set to override the default database
- `WP_CLI_TEST_DBUSER` is the user that the tests run under (defaults to "wp_cli_test").
- `WP_CLI_TEST_DBPASS` is the password to use for the above user (defaults to "password1").
- `WP_CLI_TEST_DBTYPE` is the database engine type to use, i.e. "sqlite" for running tests on SQLite instead of MySQL (defaults to "mysql").
- `WP_CLI_TEST_OBJECT_CACHE` is the persistent object cache backend to use. Only supports "sqlite".

Environment variables can be set for the whole session via the following syntax: `export WP_CLI_TEST_DBNAME=custom_db`.

Expand Down
9 changes: 9 additions & 0 deletions features/testing.feature
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ Feature: Test that WP-CLI loads.
false
"""

@require-object-cache
Scenario: Uses Object Cache
Given a WP install
When I run `wp eval 'var_export( wp_using_ext_object_cache() );'`
Then STDOUT should be:
"""
true
"""

@require-sqlite
Scenario: Custom wp-content directory
Given a WP install
Expand Down
86 changes: 82 additions & 4 deletions src/Context/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ class FeatureContext implements Context {
*/
private static $sqlite_cache_dir;

/**
* @var ?string
*/
private static $sqlite_object_cache_dir;

/**
* The directory that the WP-CLI cache (WP_CLI_CACHE_DIR, normally "$HOME/.wp-cli/cache") is set to on a "Given an empty cache" step.
* Variable SUITE_CACHE_DIR. Lives until the end of the scenario (or until another "Given an empty cache" step within the scenario).
Expand Down Expand Up @@ -599,6 +604,42 @@ private static function download_sqlite_plugin( $dir ): void {
}
}

/**
* Download the SQLite object cache plugin.
*
* @param string $dir
*/
private static function download_sqlite_object_cache_plugin( $dir ): void {
$download_url = 'https://downloads.wordpress.org/plugin/sqlite-object-cache.zip';
$download_location = $dir . '/sqlite-object-cache.zip';

if ( ! is_dir( $dir ) ) {
mkdir( $dir );
}

$response = \WP_CLI\Utils\http_request( 'GET', $download_url, null, [], [ 'filename' => $download_location ] );

if ( 200 !== $response->status_code ) {
throw new RuntimeException( "Could not download SQLite object cache plugin (HTTP code {$response->status_code})" );
}

$zip = new \ZipArchive();
$new_zip_file = $download_location;

if ( $zip->open( $new_zip_file ) === true ) {
if ( $zip->extractTo( $dir ) ) {
$zip->close();
unlink( $new_zip_file );
} else {
$error_message = $zip->getStatusString();
throw new RuntimeException( sprintf( 'Failed to extract files from the zip: %s', $error_message ) );
}
} else {
$error_message = $zip->getStatusString();
throw new RuntimeException( sprintf( 'Failed to open the zip file: %s', $error_message ) );
}
}

/**
* Given a WordPress installation with the sqlite-database-integration plugin,
* configure it to use SQLite as the database by placing the db.php dropin file
Expand Down Expand Up @@ -651,6 +692,13 @@ private static function cache_wp_files( $version = '' ): void {
}
}

if ( 'sqlite' === getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
self::$sqlite_object_cache_dir = sys_get_temp_dir() . '/wp-cli-test-sqlite-object-cache';
if ( ! is_dir( self::$sqlite_object_cache_dir . '/sqlite-object-cache' ) ) {
self::download_sqlite_object_cache_plugin( self::$sqlite_object_cache_dir );
}
}

if ( is_readable( self::$cache_dir . '/wp-config-sample.php' ) ) {
return;
}
Expand Down Expand Up @@ -1539,6 +1587,12 @@ public function download_wp( $subdir = '', $version = '' ): void {
self::copy_dir( self::$sqlite_cache_dir, $dest_dir . '/wp-content/mu-plugins' );
self::configure_sqlite( $dest_dir );
}

if ( 'sqlite' === getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
self::copy_dir( self::$sqlite_object_cache_dir, $dest_dir . '/wp-content/mu-plugins' );
copy( $dest_dir . '/wp-content/mu-plugins/sqlite-object-cache/assets/drop-in/object-cache.php', $dest_dir . '/wp-content/object-cache.php' );
file_put_contents( $dest_dir . '/wp-content/mu-plugins/sqlite-object-cache.php', "<?php\nrequire_once __DIR__ . '/sqlite-object-cache/sqlite-object-cache.php';\n" );
}
}

/**
Expand Down Expand Up @@ -1597,6 +1651,12 @@ public function install_wp( $subdir = '', $version = '' ): void {
// Disable WP Cron by default to avoid bogus HTTP requests in CLI context.
$config_extra_php = "if ( defined( 'DISABLE_WP_CRON' ) === false ) { define( 'DISABLE_WP_CRON', true ); }\n";

if ( 'sqlite' === getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
// Derive a deterministic cache key salt from the install cache directory and subdir
$salt = md5( self::$install_cache_dir . '/' . $subdir );
$config_extra_php .= "define( 'WP_CACHE_KEY_SALT', '" . $salt . "' );\n";
}

if ( 'sqlite' !== self::$db_type ) {
$this->create_db();
}
Expand All @@ -1615,7 +1675,7 @@ public function install_wp( $subdir = '', $version = '' ): void {

$run_dir = '' !== $subdir ? ( $this->variables['RUN_DIR'] . "/$subdir" ) : $this->variables['RUN_DIR'];

$install_cache_path = self::$install_cache_dir . '/install_' . md5( implode( ':', $install_args ) . ':subdir=' . $subdir );
$install_cache_path = self::$install_cache_dir . '/install_' . md5( implode( ':', $install_args ) . ':subdir=' . $subdir . ':object_cache=' . getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) );

$install_cache_is_valid = is_dir( $install_cache_path )
&& ( 'sqlite' !== self::$db_type || file_exists( "{$install_cache_path}.sqlite" ) );
Expand Down Expand Up @@ -1726,6 +1786,11 @@ public function install_wp_with_composer( $vendor_directory = 'vendor' ): void {

$config_extra_php .= "require_once dirname(__DIR__) . '/" . $vendor_directory . "/autoload.php';\n";

if ( 'sqlite' === getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
// Use a deterministic salt per install to allow create_config() to reuse cached configs.
$config_extra_php .= "define( 'WP_CACHE_KEY_SALT', '" . md5( $this->variables['RUN_DIR'] ) . "' );\n";
}

$this->create_config( 'WordPress', $config_extra_php );

$install_args = [
Expand All @@ -1747,6 +1812,12 @@ public function install_wp_with_composer( $vendor_directory = 'vendor' ): void {
self::configure_sqlite( $this->variables['RUN_DIR'] . '/WordPress' );
}

if ( 'sqlite' === getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
self::copy_dir( self::$sqlite_object_cache_dir, $this->variables['RUN_DIR'] . '/WordPress/wp-content/mu-plugins' );
copy( $this->variables['RUN_DIR'] . '/WordPress/wp-content/mu-plugins/sqlite-object-cache/assets/drop-in/object-cache.php', $this->variables['RUN_DIR'] . '/WordPress/wp-content/object-cache.php' );
file_put_contents( $this->variables['RUN_DIR'] . '/WordPress/wp-content/mu-plugins/sqlite-object-cache.php', "<?php\nrequire_once __DIR__ . '/sqlite-object-cache/sqlite-object-cache.php';\n" );
}

$this->proc( 'wp core install', $install_args )->run_check();
}

Expand Down Expand Up @@ -1894,9 +1965,16 @@ private static function dir_diff_copy( $upd_dir, $src_dir, $cop_dir ): void {
throw new RuntimeException( sprintf( "Failed to create copy directory '%s': %s. " . __FILE__ . ':' . __LINE__, $cop_file, $error['message'] ) );
}
self::copy_dir( $upd_file, $cop_file );
} elseif ( ! copy( $upd_file, $cop_file ) ) {
$error = error_get_last();
throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) );
} elseif ( ! file_exists( $upd_file ) ) {
continue; // File vanished before it could be copied.
} else {
if ( ! is_dir( dirname( $cop_file ) ) ) {
mkdir( dirname( $cop_file ), 0777, true );
}
if ( ! copy( $upd_file, $cop_file ) ) {
$error = error_get_last();
throw new RuntimeException( sprintf( "Failed to copy '%s' to '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_file, $cop_file, $error['message'] ) );
}
}
} elseif ( is_dir( $upd_file ) ) {
self::dir_diff_copy( $upd_file, $src_file, $cop_file );
Expand Down
30 changes: 26 additions & 4 deletions tests/tests/TestBehatTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public function test_behat_tags_wp_version_github_token( $env, $expected ): void
$output = $this->run_behat_tags_script( $env );

$expected .= '&&~@broken';
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$expected .= '&&~@require-object-cache';
}
if ( in_array( $env, array( 'WP_VERSION=trunk', 'WP_VERSION=nightly' ), true ) ) {
$expected .= '&&~@broken-trunk';
}
Expand Down Expand Up @@ -200,6 +203,9 @@ public function test_behat_tags_php_version(): void {
}

$expected .= '&&~@github-api&&~@broken';
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$expected .= '&&~@require-object-cache';
}

$db_type = getenv( 'WP_CLI_TEST_DBTYPE' );
switch ( $db_type ) {
Expand Down Expand Up @@ -270,7 +276,11 @@ public function test_behat_tags_extension(): void {
$expecteds[] = '~@require-extension-curl';
}

$expected = '--tags=' . implode( '&&', array_merge( array( '~@github-api', '~@broken' ), $expecteds ) );
$base_expecteds = array( '~@github-api', '~@broken' );
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$base_expecteds[] = '~@require-object-cache';
}
$expected = '--tags=' . implode( '&&', array_merge( $base_expecteds, $expecteds ) );
$output = $this->run_behat_tags_script();
$this->assertSame( $expected, $output );

Expand Down Expand Up @@ -322,7 +332,11 @@ public function test_behat_tags_db_version(): void {

file_put_contents( $this->temp_dir . DIRECTORY_SEPARATOR . 'features' . DIRECTORY_SEPARATOR . 'extension.feature', $contents );

$expected = '--tags=' . implode( '&&', array_merge( array( '~@github-api', '~@broken' ), $expecteds ) );
$base_expecteds = array( '~@github-api', '~@broken' );
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$base_expecteds[] = '~@require-object-cache';
}
$expected = '--tags=' . implode( '&&', array_merge( $base_expecteds, $expecteds ) );
$output = $this->run_behat_tags_script();
$this->assertSame( $expected, $output );
}
Expand Down Expand Up @@ -380,7 +394,11 @@ public function test_behat_tags_os(): void {
$expecteds[] = '~@skip-linux';
}

$expected = '--tags=' . implode( '&&', array_merge( array( '~@github-api', '~@broken' ), $expecteds ) );
$base_expecteds = array( '~@github-api', '~@broken' );
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$base_expecteds[] = '~@require-object-cache';
}
$expected = '--tags=' . implode( '&&', array_merge( $base_expecteds, $expecteds ) );
$output = $this->run_behat_tags_script();
$this->assertSame( $expected, $output );

Expand Down Expand Up @@ -419,7 +437,11 @@ public function test_behat_tags_skip_db_type(): void {
break;
}

$expected = '--tags=' . implode( '&&', array_merge( array( '~@github-api', '~@broken' ), $expecteds ) );
$base_expecteds = array( '~@github-api', '~@broken' );
if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$base_expecteds[] = '~@require-object-cache';
}
$expected = '--tags=' . implode( '&&', array_merge( $base_expecteds, $expecteds ) );
$output = $this->run_behat_tags_script();
$this->assertSame( $expected, $output );

Expand Down
4 changes: 4 additions & 0 deletions utils/behat-tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ function get_db_version() {
# Skip tests known to be broken.
$skip_tags[] = '@broken';

if ( 'sqlite' !== getenv( 'WP_CLI_TEST_OBJECT_CACHE' ) ) {
$skip_tags[] = '@require-object-cache';
}

if ( $wp_version && in_array( $wp_version, array( 'nightly', 'trunk' ), true ) ) {
$skip_tags[] = '@broken-trunk';
}
Expand Down