Skip to content
Open
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
2 changes: 1 addition & 1 deletion features/bootstrap.feature
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Feature: Bootstrap WP-CLI
Scenario: Override command bundled with freshly built PHAR

Given an empty directory
And a new Phar with the same version
And a new Phar with the same version and cli build
And a cli-override-command/cli.php file:
"""
<?php
Expand Down
114 changes: 105 additions & 9 deletions features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,20 @@ class FeatureContext extends BehatContext implements ClosuredContextInterface {
'dbhost' => '127.0.0.1',
);

/**
* Variables for `do_mysqli()`.
*/
private static $dbh = null; // Database handle.
private static $db_selected = false; // Whether database selected (opened).

/**
* Array of background process ids started by the current scenario. Used to terminate them at the end of the scenario.
*/
private $running_procs = array();

/**
* Array of variables available as {VARIABLE_NAME}. Some are always set: CORE_CONFIG_SETTINGS, SRC_DIR, CACHE_DIR, WP_VERSION-version-latest. Some are step-dependent:
* RUN_DIR, SUITE_CACHE_DIR, COMPOSER_LOCAL_REPOSITORY, PHAR_PATH. Scenarios can define their own variables using "Given save" steps. Variables are reset for each scenario.
* RUN_DIR, SUITE_CACHE_DIR, COMPOSER_LOCAL_REPOSITORY, COMPOSER_PATH, PHAR_PATH. Scenarios can define their own variables using "Given save" steps. Variables are reset for each scenario.
*/
public $variables = array();

Expand Down Expand Up @@ -409,7 +415,13 @@ public function create_run_dir() {
}
}

public function build_phar( $version = 'same' ) {
/**
* Build a phar based on whatever's in the directory from which behat is run.
*
* @param string $version Version to set it to. (Note: has no correspondence with the actual version of the contained source.)
* @param string $build If set to "cli" will do a fast build without any bundled commands - "cli" command only. Defaults to '' (full build).
*/
public function build_phar( $version = 'same', $build = '' ) {
$this->variables['PHAR_PATH'] = $this->variables['RUN_DIR'] . '/' . uniqid( "wp-cli-build-", TRUE ) . '.phar';

// Test running against a package installed as a WP-CLI dependency
Expand All @@ -425,13 +437,17 @@ public function build_phar( $version = 'same' ) {
}

$this->proc( Utils\esc_cmd(
'php -dphar.readonly=0 %1$s %2$s --version=%3$s && chmod +x %2$s',
'php -dphar.readonly=0 %1$s %2$s --version=%3$s --quiet --build=%4$s',
$make_phar_path,
$this->variables['PHAR_PATH'],
$version
$version,
$build
) )->run_check();
}

/**
* Download a released phar from github.com. Note: not currently used in any test.
*/
public function download_phar( $version = 'same' ) {
if ( 'same' === $version ) {
$version = WP_CLI_VERSION;
Expand Down Expand Up @@ -483,20 +499,30 @@ private static function run_sql( $sql_cmd, $assoc_args = array(), $add_database
$start_time = microtime( true );
Utils\run_mysql_command( $sql_cmd, array_merge( $assoc_args, $default_assoc_args ) );
if ( self::$log_run_times ) {
self::log_proc_method_run_time( 'run_sql ' . $sql_cmd, $start_time );
self::log_proc_method_run_time( $sql_cmd . ' ' . Utils\assoc_args_to_str( $assoc_args ), $start_time );
}
}

/**
* Create the `$db_settings['dbname']` test database. Called on a "Given a database" step and on the various "Given a WP install..." steps.
*/
public function create_db() {
$dbname = self::$db_settings['dbname'];
self::run_sql( 'mysql --no-defaults', array( 'execute' => "CREATE DATABASE IF NOT EXISTS $dbname" ) );
self::do_mysqli( "CREATE DATABASE IF NOT EXISTS `$dbname` CHARSET 'UTF8'" );
}

/**
* Drop the `$db_settings['dbname']` test database. Done at the beginning of every scenario.
*/
public function drop_db() {
$dbname = self::$db_settings['dbname'];
self::run_sql( 'mysql --no-defaults', array( 'execute' => "DROP DATABASE IF EXISTS $dbname" ) );
self::do_mysqli( "DROP DATABASE IF EXISTS `$dbname`" );
self::$db_selected = false;
}

/**
* Run a process from the RUN_DIR directory (or a sub-directory of it if given `$path`).
*/
public function proc( $command, $assoc_args = array(), $path = '' ) {
if ( !empty( $assoc_args ) )
$command .= Utils\assoc_args_to_str( $assoc_args );
Expand Down Expand Up @@ -563,6 +589,9 @@ public function add_line_to_wp_config( &$wp_config_code, $line ) {
$wp_config_code = str_replace( $token, "$line\n\n$token", $wp_config_code );
}

/**
* "Downloads" wp in the sense that it copies the version downloaded and cached by `cache_wp_files()` from CACHE_DIR to RUN_DIR (or a sub-directory of it if given `$subdir`).
*/
public function download_wp( $subdir = '' ) {
$dest_dir = $this->variables['RUN_DIR'] . "/$subdir";

Expand All @@ -584,6 +613,7 @@ public function create_config( $subdir = '', $extra_php = false ) {
$params['dbprefix'] = $subdir ? preg_replace( '#[^a-zA-Z\_0-9]#', '_', $subdir ) : 'wp_';

$params['skip-salts'] = true;
$params['skip-check'] = true;

if( false !== $extra_php ) {
$params['extra-php'] = $extra_php;
Expand Down Expand Up @@ -636,13 +666,16 @@ public function install_wp( $subdir = '' ) {

if ( $install_cache_path && file_exists( $install_cache_path ) ) {
self::copy_dir( $install_cache_path, $run_dir );
self::run_sql( 'mysql --no-defaults', array( 'execute' => "source {$install_cache_path}.sql" ), true /*add_database*/ );
self::do_mysqli_source( $install_cache_path . '.sql' );
} else {
$this->proc( 'wp core install', $install_args, $subdir )->run_check();
if ( $install_cache_path ) {
mkdir( $install_cache_path );
self::dir_diff_copy( $run_dir, self::$cache_dir, $install_cache_path );
self::run_sql( 'mysqldump --no-defaults', array( 'result-file' => "{$install_cache_path}.sql" ), true /*add_database*/ );
$install_cache_sql = $install_cache_path . '.sql';
self::run_sql( 'mysqldump --no-defaults --skip-comments', array( 'result-file' => $install_cache_sql ), true /*add_database*/ );
// Remove conditional and lock tables statements.
file_put_contents( $install_cache_sql, preg_replace( array( '/^\/\*[^*]+\*\/;\n/m', '/^(?:UN)?LOCK TABLES[^;]*;\n/m' ), '', file_get_contents( $install_cache_sql ) ) );
}
}
}
Expand Down Expand Up @@ -717,6 +750,69 @@ private function composer_command($cmd) {
$this->proc( $this->variables['COMPOSER_PATH'] . ' ' . $cmd )->run_check();
}

/**
* Do a MySQL query with `$db_settings`, using the PHP mysqli extension. Slightly faster than `run_sql()`.
*
* @param string $sql_cmd MySQL query.
* @param bool $open_database Whether to open (select) the database or not.
* @param bool $multi_query Whether the query contains multiple statements or not.
* @param bool $no_log If set won't log timing if using log run times.
*/
private static function do_mysqli( $sql_cmd, $open_database = false, $multi_query = false, $no_log = false ) {
$start_time = microtime( true );

if ( null === self::$dbh ) {
if ( ! ( self::$dbh = mysqli_connect( self::$db_settings['dbhost'], self::$db_settings['dbuser'], self::$db_settings['dbpass'] ) ) ) {
throw new \RuntimeException(
sprintf( "Failed to connect to MySQL database host '%s', user '%s', pass '%s'.", self::$db_settings['dbhost'], self::$db_settings['dbuser'], self::$db_settings['dbpass'] )
);
}
}
if ( $open_database && ! self::$db_selected ) {
if ( ! mysqli_select_db( self::$dbh, self::$db_settings['dbname'] ) ) {
throw new \RuntimeException( sprintf( "Failed to open MySQL database name '%s'.", self::$db_settings['dbname'] ) );
}
self::$db_selected = true;
}
if ( $multi_query ) {
if ( ! mysqli_multi_query( self::$dbh, $sql_cmd ) ) {
throw new \RuntimeException( sprintf( "Failed to execute MySQL query '%s': %d: %s", $sql_cmd, mysqli_errno( self::$dbh ), mysqli_error( self::$dbh ) ) );
}
// Throw away the stored results (otherwise will get "out of sync" errors).
while ( mysqli_more_results( self::$dbh ) ) {
mysqli_next_result( self::$dbh );
}
} else {
if ( ! mysqli_query( self::$dbh, $sql_cmd ) ) {
throw new \RuntimeException( sprintf( "Failed to execute MySQL query '%s': %d: %s", $sql_cmd, mysqli_errno( self::$dbh ), mysqli_error( self::$dbh ) ) );
}
}
if ( self::$log_run_times && ! $no_log ) {
self::log_proc_method_run_time( 'do_mysqli ' . $sql_cmd, $start_time );
}
}

/**
* Do a MySQL SOURCE command using the PHP mysqli extension. Slightly faster than doing a mysql SOURCE command using `run_sql()`.
*
* @param string $source_file Name of MySQL source ".sql" file.
*/
private static function do_mysqli_source( $source_file ) {
$start_time = microtime( true );

static $files = array();

if ( ! isset( $files[ $source_file ] ) ) {
$files[ $source_file ] = file_get_contents( $source_file );
}

self::do_mysqli( $files[ $source_file ], true /*open_database*/, true /*multi_query*/, true /*no_log*/ );

if ( self::$log_run_times ) {
self::log_proc_method_run_time( 'do_mysqli_source ' . $source_file, $start_time );
}
}

/**
* Initialize run time logging.
*/
Expand Down
32 changes: 9 additions & 23 deletions features/cli.feature
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Feature: `wp cli` tasks
Scenario: Ability to set a custom version when building
Given an empty directory
And save the {SRC_DIR}/VERSION file as {TRUE_VERSION}
And a new Phar with version "1.2.3"
And a new Phar with version "1.2.3" and cli build

When I run `{PHAR_PATH} cli version`
Then STDOUT should be:
Expand All @@ -45,19 +45,18 @@ Feature: `wp cli` tasks
@github-api
Scenario: Check for updates
Given an empty directory
And a new Phar with version "0.0.0"
And a new Phar with version "0.0.0" and cli build

When I run `{PHAR_PATH} cli check-update`
Then STDOUT should contain:
"""
package_url
"""
And STDERR should be empty

@github-api
Scenario: Do WP-CLI Update
Given an empty directory
And a new Phar with version "0.0.0"
And a new Phar with version "0.0.0" and cli build

When I run `{PHAR_PATH} --info`
Then STDOUT should contain:
Expand All @@ -78,8 +77,6 @@ Feature: `wp cli` tasks
"""
Success:
"""
And STDERR should be empty
And the return code should be 0

When I run `{PHAR_PATH} --info`
Then STDOUT should contain:
Expand All @@ -100,7 +97,7 @@ Feature: `wp cli` tasks
@github-api
Scenario: Patch update from 0.14.0 to 0.14.1
Given an empty directory
And a new Phar with version "0.14.0"
And a new Phar with version "0.14.0" and cli build

When I run `{PHAR_PATH} --version`
Then STDOUT should be:
Expand All @@ -117,8 +114,6 @@ Feature: `wp cli` tasks
"""
Success: Updated WP-CLI to 0.14.1
"""
And STDERR should be empty
And the return code should be 0

When I run `{PHAR_PATH} --version`
Then STDOUT should be:
Expand All @@ -129,7 +124,7 @@ Feature: `wp cli` tasks
@github-api
Scenario: Not a patch update from 0.14.0
Given an empty directory
And a new Phar with version "0.14.0"
And a new Phar with version "0.14.0" and cli build

When I run `{PHAR_PATH} cli update --no-patch --yes`
Then STDOUT should contain:
Expand All @@ -140,13 +135,11 @@ Feature: `wp cli` tasks
"""
0.14.1
"""
And STDERR should be empty
And the return code should be 0

@require-php-5.6
@github-api
Scenario: Install WP-CLI nightly
Given an empty directory
And a new Phar with version "0.14.0"
And a new Phar with version "0.14.0" and cli build

When I run `{PHAR_PATH} cli update --nightly --yes`
Then STDOUT should contain:
Expand All @@ -158,13 +151,10 @@ Feature: `wp cli` tasks
Success: Updated WP-CLI to the latest nightly release.
"""

And STDERR should be empty
And the return code should be 0

@github-api @less-than-php-7
@github-api
Scenario: Install WP-CLI stable
Given an empty directory
And a new Phar with version "0.14.0"
And a new Phar with version "0.14.0" and cli build
And a session file:
"""
y
Expand All @@ -187,8 +177,6 @@ Feature: `wp cli` tasks
"""
Success: Updated WP-CLI to the latest stable release.
"""
And STDERR should be empty
And the return code should be 0

When I run `{PHAR_PATH} cli check-update`
Then STDOUT should be:
Expand All @@ -210,5 +198,3 @@ Feature: `wp cli` tasks
"""
17"current":
"""
And STDERR should be empty
And the return code should be 0
Loading