diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index b4b8314af..e898e6c15 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -159,6 +159,7 @@ jobs: export MYSQL_TCP_PORT=${{ job.services.mysql.ports['3306'] }} echo "WP_CLI_TEST_DBROOTUSER=root" >> $GITHUB_ENV echo "WP_CLI_TEST_DBROOTPASS=root" >> $GITHUB_ENV + echo "WP_CLI_TEST_DBNAME=wp_cli_test" >> $GITHUB_ENV echo "WP_CLI_TEST_DBUSER=wp_cli_test" >> $GITHUB_ENV echo "WP_CLI_TEST_DBPASS=password1" >> $GITHUB_ENV echo "WP_CLI_TEST_DBHOST=$MYSQL_HOST:$MYSQL_TCP_PORT" >> $GITHUB_ENV diff --git a/.readme-partials/USING.md b/.readme-partials/USING.md index a3a8d38a8..45288bbae 100644 --- a/.readme-partials/USING.md +++ b/.readme-partials/USING.md @@ -33,11 +33,14 @@ To make use of the WP-CLI testing framework, you need to complete the following The timeout is expressed in seconds. 4. Optionally add a `behat.yml` file to the package root with the following content: - ```json + ```yaml default: - paths: - features: features - bootstrap: vendor/wp-cli/wp-cli-tests/features/bootstrap + suites: + default: + contexts: + - WP_CLI\Tests\Context\FeatureContext + paths: + - features ``` This will make sure that the automated Behat system works across all platforms. This is needed on Windows. diff --git a/bin/install-package-tests b/bin/install-package-tests index 6a217ca9f..9ed4dbc3c 100755 --- a/bin/install-package-tests +++ b/bin/install-package-tests @@ -4,75 +4,81 @@ # - WP_CLI_TEST_DBHOST is the host to use and can include a port, i.e "127.0.0.1:33060" (defaults to "localhost") # - WP_CLI_TEST_DBROOTUSER is the user that has permission to administer databases and users (defaults to "root"). # - WP_CLI_TEST_DBROOTPASS is the password to use for the above user (defaults to an empty password). +# - WP_CLI_TEST_DBNAME is the database that the tests run under (defaults to "wp_cli_test"). # - 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"). HOST=localhost PORT="" HOST_STRING='' -if [ -n "$WP_CLI_TEST_DBHOST" ]; then +if [ -n "${WP_CLI_TEST_DBHOST}" ]; then case ${WP_CLI_TEST_DBHOST##*[]]} in (*:*) HOST=${WP_CLI_TEST_DBHOST%:*} PORT=${WP_CLI_TEST_DBHOST##*:};; - (*) HOST=$WP_CLI_TEST_DBHOST;; + (*) HOST=${WP_CLI_TEST_DBHOST};; esac - HOST_STRING="-h$HOST" - if [ -n "$PORT" ]; then - HOST_STRING="$HOST_STRING -P$PORT --protocol=tcp" + HOST_STRING="-h${HOST}" + if [ -n "${PORT}" ]; then + HOST_STRING="${HOST_STRING} -P${PORT} --protocol=tcp" fi fi USER=root -if [ -n "$WP_CLI_TEST_DBROOTUSER" ]; then - USER="$WP_CLI_TEST_DBROOTUSER" +if [ -n "${WP_CLI_TEST_DBROOTUSER}" ]; then + USER="${WP_CLI_TEST_DBROOTUSER}" fi PASSWORD_STRING="" -if [ -n "$WP_CLI_TEST_DBROOTPASS" ]; then - PASSWORD_STRING="-p$WP_CLI_TEST_DBROOTPASS" +if [ -n "${WP_CLI_TEST_DBROOTPASS}" ]; then + PASSWORD_STRING="-p${WP_CLI_TEST_DBROOTPASS}" +fi + +TEST_DB=wp_cli_test +if [ -n "${WP_CLI_TEST_DBNAME}" ]; then + TEST_DB="${WP_CLI_TEST_DBNAME}" fi TEST_USER=wp_cli_test -if [ -n "$WP_CLI_TEST_DBUSER" ]; then - TEST_USER="$WP_CLI_TEST_DBUSER" +if [ -n "${WP_CLI_TEST_DBUSER}" ]; then + TEST_USER="${WP_CLI_TEST_DBUSER}" fi TEST_PASSWORD=password1 -if [ -n "$WP_CLI_TEST_DBPASS" ]; then - TEST_PASSWORD="$WP_CLI_TEST_DBPASS" +if [ -n "${WP_CLI_TEST_DBPASS}" ]; then + TEST_PASSWORD="${WP_CLI_TEST_DBPASS}" fi # Prepare the database for running the tests with a MySQL version 8.0 or higher. install_mysql_db_8_0_plus() { set -ex - mysql -e "CREATE DATABASE IF NOT EXISTS \`wp_cli_test\`;" $HOST_STRING -u"$USER" "$PASSWORD_STRING" - mysql -e "CREATE USER IF NOT EXISTS \`wp_cli_test\`@'%' IDENTIFIED WITH mysql_native_password BY '$TEST_PASSWORD'" $HOST_STRING -u"$USER" "$PASSWORD_STRING" - mysql -e "GRANT ALL PRIVILEGES ON \`wp_cli_test\`.* TO '$TEST_USER'@'%'" $HOST_STRING -u"$USER" "$PASSWORD_STRING" - mysql -e "GRANT ALL PRIVILEGES ON \`wp_cli_test_scaffold\`.* TO '$TEST_USER'@'%'" $HOST_STRING -u"$USER" "$PASSWORD_STRING" + mysql -e "CREATE DATABASE IF NOT EXISTS \`${TEST_DB}\`;" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" + mysql -e "CREATE USER IF NOT EXISTS \`${TEST_DB}\`@'%' IDENTIFIED WITH mysql_native_password BY '${TEST_PASSWORD}'" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" + mysql -e "GRANT ALL PRIVILEGES ON \`${TEST_DB}\`.* TO '${TEST_USER}'@'%'" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" + mysql -e "GRANT ALL PRIVILEGES ON \`${TEST_DB}_scaffold\`.* TO '${TEST_USER}'@'%'" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" } # Prepare the database for running the tests with a MySQL version lower than 8.0. install_mysql_db_lower_than_8_0() { set -ex - mysql -e "CREATE DATABASE IF NOT EXISTS \`wp_cli_test\`;" $HOST_STRING -u"$USER" "$PASSWORD_STRING" - mysql -e "GRANT ALL ON \`wp_cli_test\`.* TO '$TEST_USER'@'%' IDENTIFIED BY '$TEST_PASSWORD'" $HOST_STRING -u"$USER" "$PASSWORD_STRING" - mysql -e "GRANT ALL ON \`wp_cli_test_scaffold\`.* TO '$TEST_USER'@'%' IDENTIFIED BY '$TEST_PASSWORD'" $HOST_STRING -u"$USER" "$PASSWORD_STRING" + mysql -e "CREATE DATABASE IF NOT EXISTS \`${TEST_DB}\`;" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" + mysql -e "GRANT ALL ON \`${TEST_DB}\`.* TO '${TEST_USER}'@'%' IDENTIFIED BY '${TEST_PASSWORD}'" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" + mysql -e "GRANT ALL ON \`${TEST_DB}_scaffold\`.* TO '${TEST_USER}'@'%' IDENTIFIED BY '${TEST_PASSWORD}'" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" } -VERSION_STRING=$(mysql -e "SELECT VERSION()" --skip-column-names $HOST_STRING -u"$USER" "$PASSWORD_STRING") -VERSION=$(echo "$VERSION_STRING" | grep -o '^[^-]*') -MAJOR=$(echo "$VERSION" | cut -d. -f1) -MINOR=$(echo "$VERSION" | cut -d. -f2) +VERSION_STRING=$(mysql -e "SELECT VERSION()" --skip-column-names ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}") +VERSION=$(echo "${VERSION_STRING}" | grep -o '^[^-]*') +MAJOR=$(echo "${VERSION}" | cut -d. -f1) +MINOR=$(echo "${VERSION}" | cut -d. -f2) TYPE="MySQL" -case "$VERSION_STRING" in +case "${VERSION_STRING}" in *"MariaDB"*) TYPE="MariaDB" ;; esac -echo "Detected $TYPE at version $MAJOR.$MINOR" +echo "Detected ${TYPE} at version ${MAJOR}.${MINOR}" -if [ "$TYPE" != "MariaDB" ] && [ "$MAJOR" -ge 8 ]; then +if [ "${TYPE}" != "MariaDB" ] && [ "${MAJOR}" -ge 8 ]; then install_mysql_db_8_0_plus else install_mysql_db_lower_than_8_0 diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index d744d598f..41515b84d 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -51,24 +51,24 @@ class FeatureContext implements SnippetAcceptingContext { /** * The test database settings. All but `dbname` can be set via environment variables. The database is dropped at the start of each scenario and created on a "Given a WP installation" step. */ - private static $db_settings = array( + private static $db_settings = [ 'dbname' => 'wp_cli_test', 'dbuser' => 'wp_cli_test', 'dbpass' => 'password1', 'dbhost' => '127.0.0.1', - ); + ]; /** * Array of background process ids started by the current scenario. Used to terminate them at the end of the scenario. */ - private $running_procs = array(); + private $running_procs = []; /** * Array of variables available as {VARIABLE_NAME}. Some are always set: CORE_CONFIG_SETTINGS, DB_USER, DB_PASSWORD, DB_HOST, SRC_DIR, CACHE_DIR, WP_VERSION-version-latest. * Some are step-dependent: RUN_DIR, SUITE_CACHE_DIR, COMPOSER_LOCAL_REPOSITORY, PHAR_PATH. One is set on use: INVOKE_WP_CLI_WITH_PHP_ARGS-args. * Scenarios can define their own variables using "Given save" steps. Variables are reset for each scenario. */ - public $variables = array(); + public $variables = []; /** * The current feature file and scenario line number as '.'. Used in RUN_DIR and SUITE_CACHE_DIR directory names. Set at the start of each scenario. @@ -84,9 +84,9 @@ class FeatureContext implements SnippetAcceptingContext { private static $num_top_processes; // Number of processes/methods to output by longest run times. Set on `@BeforeSuite`. private static $num_top_scenarios; // Number of scenarios to output by longest run times. Set on `@BeforeSuite`. - private static $scenario_run_times = array(); // Scenario run times (top `self::$num_top_scenarios` only). + private static $scenario_run_times = []; // Scenario run times (top `self::$num_top_scenarios` only). private static $scenario_count = 0; // Scenario count, incremented on `@AfterScenario`. - private static $proc_method_run_times = array(); // Array of run time info for proc methods, keyed by method name and arg, each a 2-element array containing run time and run count. + private static $proc_method_run_times = []; // Array of run time info for proc methods, keyed by method name and arg, each a 2-element array containing run time and run count. /** * Get the path to the Composer vendor folder. @@ -211,11 +211,11 @@ private static function get_process_env_variables() { } $path_separator = Utils\is_windows() ? ';' : ':'; - $env = array( + $env = [ 'PATH' => $bin_path . $path_separator . getenv( 'PATH' ), 'BEHAT_RUN' => 1, 'HOME' => sys_get_temp_dir() . '/wp-cli-home', - ); + ]; $config_path = getenv( 'WP_CLI_CONFIG_PATH' ); if ( false !== $config_path ) { @@ -490,16 +490,28 @@ public function __construct() { $this->variables['DB_ROOT_PASSWORD'] = getenv( 'WP_CLI_TEST_DBROOTPASS' ); } + if ( getenv( 'WP_CLI_TEST_DBNAME' ) ) { + $this->variables['DB_NAME'] = getenv( 'WP_CLI_TEST_DBNAME' ); + } else { + $this->variables['DB_NAME'] = 'wp_cli_test'; + } + if ( getenv( 'WP_CLI_TEST_DBUSER' ) ) { $this->variables['DB_USER'] = getenv( 'WP_CLI_TEST_DBUSER' ); + } else { + $this->variables['DB_USER'] = 'wp_cli_test'; } if ( false !== getenv( 'WP_CLI_TEST_DBPASS' ) ) { $this->variables['DB_PASSWORD'] = getenv( 'WP_CLI_TEST_DBPASS' ); + } else { + $this->variables['DB_PASSWORD'] = 'password1'; } if ( getenv( 'WP_CLI_TEST_DBHOST' ) ) { $this->variables['DB_HOST'] = getenv( 'WP_CLI_TEST_DBHOST' ); + } else { + $this->variables['DB_HOST'] = 'localhost'; } if ( getenv( 'MYSQL_TCP_PORT' ) ) { @@ -510,17 +522,10 @@ public function __construct() { $this->variables['MYSQL_HOST'] = getenv( 'MYSQL_HOST' ); } - self::$db_settings['dbuser'] = array_key_exists( 'DB_USER', $this->variables ) - ? $this->variables['DB_USER'] - : 'wp_cli_test'; - - self::$db_settings['dbpass'] = array_key_exists( 'DB_PASSWORD', $this->variables ) - ? $this->variables['DB_PASSWORD'] - : 'password1'; - - self::$db_settings['dbhost'] = array_key_exists( 'DB_HOST', $this->variables ) - ? $this->variables['DB_HOST'] - : 'localhost'; + self::$db_settings['dbname'] = $this->variables['DB_NAME']; + self::$db_settings['dbuser'] = $this->variables['DB_USER']; + self::$db_settings['dbpass'] = $this->variables['DB_PASSWORD']; + self::$db_settings['dbhost'] = $this->variables['DB_HOST']; $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); @@ -536,7 +541,7 @@ public function replace_variables( $str ) { if ( false !== strpos( $str, '{INVOKE_WP_CLI_WITH_PHP_ARGS-' ) ) { $str = $this->replace_invoke_wp_cli_with_php_args( $str ); } - $str = preg_replace_callback( '/\{([A-Z_][A-Z_0-9]*)\}/', array( $this, 'replace_var' ), $str ); + $str = preg_replace_callback( '/\{([A-Z_][A-Z_0-9]*)\}/', [ $this, 'replace_var' ], $str ); if ( false !== strpos( $str, '{WP_VERSION-' ) ) { $str = $this->replace_wp_versions( $str ); } @@ -600,9 +605,9 @@ private function replace_var( $matches ) { private function replace_wp_versions( $str ) { static $wp_versions = null; if ( null === $wp_versions ) { - $wp_versions = array(); + $wp_versions = []; - $response = Requests::get( 'https://api.wordpress.org/core/version-check/1.7/', null, array( 'timeout' => 30 ) ); + $response = Requests::get( 'https://api.wordpress.org/core/version-check/1.7/', null, [ 'timeout' => 30 ] ); if ( 200 === $response->status_code ) { $body = json_decode( $response->body ); if ( is_object( $body ) && isset( $body->offers ) && is_array( $body->offers ) ) { @@ -724,12 +729,12 @@ private function set_cache_dir() { * @param array $assoc_args Optional. Associative array of options. Default empty. * @param bool $add_database Optional. Whether to add dbname to the $sql_cmd. Default false. */ - private static function run_sql( $sql_cmd, $assoc_args = array(), $add_database = false ) { - $default_assoc_args = array( + private static function run_sql( $sql_cmd, $assoc_args = [], $add_database = false ) { + $default_assoc_args = [ 'host' => self::$db_settings['dbhost'], 'user' => self::$db_settings['dbuser'], 'pass' => self::$db_settings['dbpass'], - ); + ]; if ( $add_database ) { $sql_cmd .= ' ' . escapeshellarg( self::$db_settings['dbname'] ); } @@ -742,15 +747,15 @@ private static function run_sql( $sql_cmd, $assoc_args = array(), $add_database public function create_db() { $dbname = self::$db_settings['dbname']; - self::run_sql( 'mysql --no-defaults', array( 'execute' => "CREATE DATABASE IF NOT EXISTS $dbname" ) ); + self::run_sql( 'mysql --no-defaults', [ 'execute' => "CREATE DATABASE IF NOT EXISTS $dbname" ] ); } public function drop_db() { $dbname = self::$db_settings['dbname']; - self::run_sql( 'mysql --no-defaults', array( 'execute' => "DROP DATABASE IF EXISTS $dbname" ) ); + self::run_sql( 'mysql --no-defaults', [ 'execute' => "DROP DATABASE IF EXISTS $dbname" ] ); } - public function proc( $command, $assoc_args = array(), $path = '' ) { + public function proc( $command, $assoc_args = [], $path = '' ) { if ( ! empty( $assoc_args ) ) { $command .= Utils\assoc_args_to_str( $assoc_args ); } @@ -773,11 +778,11 @@ public function proc( $command, $assoc_args = array(), $path = '' ) { * Start a background process. Will automatically be closed when the tests finish. */ public function background_proc( $cmd ) { - $descriptors = array( + $descriptors = [ 0 => STDIN, - 1 => array( 'pipe', 'w' ), - 2 => array( 'pipe', 'w' ), - ); + 1 => [ 'pipe', 'w' ], + 2 => [ 'pipe', 'w' ], + ]; $proc = proc_open( $cmd, $descriptors, $pipes, $this->variables['RUN_DIR'], self::get_process_env_variables() ); @@ -883,14 +888,14 @@ public function install_wp( $subdir = '' ) { $this->download_wp( $subdir ); $this->create_config( $subdir, $config_extra_php ); - $install_args = array( + $install_args = [ 'url' => 'http://example.com', 'title' => 'WP CLI Site', 'admin_user' => 'admin', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1', 'skip-email' => true, - ); + ]; $install_cache_path = ''; if ( self::$install_cache_dir ) { @@ -900,7 +905,7 @@ 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::run_sql( 'mysql --no-defaults', [ 'execute' => "source {$install_cache_path}.sql" ], true /*add_database*/ ); } else { $this->proc( 'wp core install', $install_args, $subdir )->run_check(); if ( $install_cache_path ) { @@ -914,7 +919,7 @@ public function install_wp( $subdir = '' ) { $command .= ' --skip-column-statistics'; } - self::run_sql( $command, array( 'result-file' => "{$install_cache_path}.sql" ), true /*add_database*/ ); + self::run_sql( $command, [ 'result-file' => "{$install_cache_path}.sql" ], true /*add_database*/ ); } } } @@ -938,14 +943,14 @@ public function install_wp_with_composer( $vendor_directory = 'vendor' ) { $this->create_config( 'WordPress', $config_extra_php ); - $install_args = array( + $install_args = [ 'url' => 'http://localhost:8080', 'title' => 'WP CLI Site with both WordPress and wp-cli as Composer dependencies', 'admin_user' => 'admin', 'admin_email' => 'admin@example.com', 'admin_password' => 'password1', 'skip-email' => true, - ); + ]; $this->proc( 'wp core install', $install_args )->run_check(); } @@ -1065,7 +1070,7 @@ private static function dir_diff_copy( $upd_dir, $src_dir, $cop_dir ) { $error = error_get_last(); throw new RuntimeException( sprintf( "Failed to open updated directory '%s': %s. " . __FILE__ . ':' . __LINE__, $upd_dir, $error['message'] ) ); } - foreach ( array_diff( $files, array( '.', '..' ) ) as $file ) { + foreach ( array_diff( $files, [ '.', '..' ] ) as $file ) { $upd_file = $upd_dir . '/' . $file; $src_file = $src_dir . '/' . $file; $cop_file = $cop_dir . '/' . $file; @@ -1129,10 +1134,10 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { // Process and proc method run times. $run_times = array_merge( Process::$run_times, self::$proc_method_run_times ); $reduce_callback = function ( $carry, $item ) { - return array( $carry[0] + $item[0], $carry[1] + $item[1] ); + return [ $carry[0] + $item[0], $carry[1] + $item[1] ]; }; - list( $ptime, $calls ) = array_reduce( $run_times, $reduce_callback, array( 0, 0 ) ); + list( $ptime, $calls ) = array_reduce( $run_times, $reduce_callback, [ 0, 0 ] ); $overhead = $time - $ptime; $pct = round( ( $overhead / $time ) * 100 ); @@ -1208,7 +1213,7 @@ private static function log_run_times_after_suite( AfterSuiteScope $scope ) { private static function log_proc_method_run_time( $key, $start_time ) { $run_time = microtime( true ) - $start_time; if ( ! isset( self::$proc_method_run_times[ $key ] ) ) { - self::$proc_method_run_times[ $key ] = array( 0, 0 ); + self::$proc_method_run_times[ $key ] = [ 0, 0 ]; } self::$proc_method_run_times[ $key ][0] += $run_time; self::$proc_method_run_times[ $key ][1]++;