diff --git a/bin/install-package-tests b/bin/install-package-tests index 304744214..2646ebb1b 100755 --- a/bin/install-package-tests +++ b/bin/install-package-tests @@ -12,9 +12,13 @@ is_numeric() { case $1 in ''|*[!0-9]*) return 1;; # returns 1 if not numeric - *) return 0;; # returns 0 if numeric + *) return 0;; # returns 0 if numeric esac } +# Promt color vars. +C_RED="\033[31m" +C_BLUE="\033[34m" +NO_FORMAT="\033[0m" HOST=localhost PORT="" @@ -28,36 +32,57 @@ if [ -n "${WP_CLI_TEST_DBHOST}" ]; then if [ -n "${PORT}" ]; then # If the port is not numeric, then we assume it is a socket path. if is_numeric "${PORT}"; then + echo "Connecting to custom host: ${C_BLUE}${HOST}${NO_FORMAT} on port ${C_BLUE}${PORT}${NO_FORMAT}" HOST_STRING="${HOST_STRING} --port=${PORT} --protocol=tcp" else + echo "Connecting to custom host: ${C_BLUE}${HOST}${NO_FORMAT} on socket ${C_BLUE}${PORT}${NO_FORMAT}" HOST_STRING="${HOST_STRING} --socket=${PORT} --protocol=socket" fi + else + echo "Connecting to custom host: ${C_BLUE}${HOST}${NO_FORMAT}" fi +else + echo "Connecting to default host: ${C_BLUE}${HOST}${NO_FORMAT}" fi USER=root if [ -n "${WP_CLI_TEST_DBROOTUSER}" ]; then - USER="${WP_CLI_TEST_DBROOTUSER}" + echo "Connecting with custom root user: ${C_BLUE}${WP_CLI_TEST_DBROOTUSER}${NO_FORMAT}" + USER="${WP_CLI_TEST_DBROOTUSER}" +else + echo "Connecting with default root user: ${C_BLUE}${USER}${NO_FORMAT}" fi PASSWORD_STRING="" if [ -n "${WP_CLI_TEST_DBROOTPASS}" ]; then - PASSWORD_STRING="-p${WP_CLI_TEST_DBROOTPASS}" + echo "Connecting with custom root password: ${C_BLUE}${WP_CLI_TEST_DBROOTPASS}${NO_FORMAT}" + PASSWORD_STRING="-p${WP_CLI_TEST_DBROOTPASS}" +else + echo "Connecting with default root password: ${C_BLUE}empty${NO_FORMAT}" fi TEST_DB=wp_cli_test if [ -n "${WP_CLI_TEST_DBNAME}" ]; then - TEST_DB="${WP_CLI_TEST_DBNAME}" + echo "Using custom test database: ${C_BLUE}${WP_CLI_TEST_DBNAME}${NO_FORMAT}" + TEST_DB="${WP_CLI_TEST_DBNAME}" +else + echo "Using default test database: ${C_BLUE}${TEST_DB}${NO_FORMAT}" fi TEST_USER=wp_cli_test if [ -n "${WP_CLI_TEST_DBUSER}" ]; then - TEST_USER="${WP_CLI_TEST_DBUSER}" + echo "Using custom test user: ${C_BLUE}${WP_CLI_TEST_DBUSER}${NO_FORMAT}" + TEST_USER="${WP_CLI_TEST_DBUSER}" +else + echo "Using default test user: ${C_BLUE}${TEST_USER}${NO_FORMAT}" fi TEST_PASSWORD=password1 if [ -n "${WP_CLI_TEST_DBPASS}" ]; then - TEST_PASSWORD="${WP_CLI_TEST_DBPASS}" + echo "Using custom test password: ${C_BLUE}${WP_CLI_TEST_DBPASS}${NO_FORMAT}" + TEST_PASSWORD="${WP_CLI_TEST_DBPASS}" +else + echo "Using default test password: ${C_BLUE}${TEST_PASSWORD}${NO_FORMAT}" fi echo "Detecting database version..." @@ -71,6 +96,15 @@ case "${CLIENT_VERSION}" in ;; esac +if [ -z "$PS1" ]; then + # These vars are because github actions gave problems in the past. + MYSQL_TRIES=36 + MYSQL_WAIT=5 +else + MYSQL_TRIES=1 + MYSQL_WAIT=0 +fi + if [ "${TYPE}" = "MySQL" ]; then SERVER_VERSION=$(mysql -e "SELECT VERSION()" --skip-column-names ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}") else @@ -88,42 +122,54 @@ echo 'Checking if database is ready...' if [ "${TYPE}" = "MySQL" ]; then while ! mysql ${HOST_STRING} --user="${USER}" "${PASSWORD_STRING}" --execute="SHOW DATABASES;" | grep 'information_schema' >/dev/null; do - echo 'Waiting for database...' - sleep 5 i=$((i+1)) - if [ $i -gt 36 ]; then - echo 'Database failed to start. Aborting.' - exit 1 + if [ "${MYSQL_TRIES}" -gt 1 ]; then + echo "Waiting for MySQL(${i}/${MYSQL_TRIES})..." + sleep ${MYSQL_WAIT} + fi + + if [ $i -ge $MYSQL_TRIES ]; then + echo "${C_RED}MySQL failed to start. Aborting.${NO_FORMAT}" + echo "Cannot connect to MySQL server. For all available variables, check the documentation at:" + echo " ${C_BLUE}https://github.com/wp-cli/wp-cli-tests?tab=readme-ov-file#the-database-credentials${NO_FORMAT}" + exit 1 fi done else while ! mariadb ${HOST_STRING} --user="${USER}" "${PASSWORD_STRING}" --execute="SHOW DATABASES;" | grep 'information_schema' >/dev/null; do - echo 'Waiting for database...' - sleep 5 i=$((i+1)) - if [ $i -gt 36 ]; then - echo 'Database failed to start. Aborting.' - exit 1 + if [ "${MYSQL_TRIES}" -gt 1 ]; then + echo "Waiting for MariaDB(${i}/${MYSQL_TRIES})..." + sleep ${MYSQL_WAIT} + fi + + if [ $i -ge $MYSQL_TRIES ]; then + echo "${C_RED}MariaDB failed to start. Aborting.${NO_FORMAT}" + echo "Cannot connect to MariaDB server. For all available variables, check the documentation at:" + echo " ${C_BLUE}https://github.com/wp-cli/wp-cli-tests?tab=readme-ov-file#the-database-credentials${NO_FORMAT}" + exit 1 fi done fi # Prepare the database for running the tests with a MySQL version 8.0 or higher. install_mysql_db_8_0_plus() { - set -ex + set -ex # print all the commands. mysql -e "CREATE DATABASE IF NOT EXISTS \`${TEST_DB}\`;" ${HOST_STRING} -u"${USER}" "${PASSWORD_STRING}" mysql -e "CREATE USER IF NOT EXISTS \`${TEST_USER}\`@'%' IDENTIFIED WITH caching_sha2_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}" + { set +ex; } 2> /dev/null # stop printing the commands } # Prepare the database for running the tests with a MySQL version lower than 8.0. install_mysql_db_lower_than_8_0() { - set -ex + set -ex # print all the commands. 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}" + { set +ex; } 2> /dev/null # stop printing the commands } # Prepare the database for running the tests with MariaDB @@ -142,3 +188,6 @@ elif [ "${MAJOR}" -ge 8 ]; then else install_mysql_db_lower_than_8_0 fi + +echo "Succesfully prepared the database for running tests." +echo "This command does not have to be run again." diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index d726369fa..4f3fdb7ba 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -21,6 +21,7 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use SebastianBergmann\Environment\Runtime; use RuntimeException; +use WP_CLI; use DirectoryIterator; use WP_CLI\Process; use WP_CLI\ProcessRun; @@ -866,6 +867,7 @@ public function __construct() { $this->variables['CORE_CONFIG_SETTINGS'] = Utils\assoc_args_to_str( self::$db_settings ); + $this->test_connection(); $this->drop_db(); $this->set_cache_dir(); } @@ -1110,8 +1112,9 @@ private function set_cache_dir(): void { * @param string $sql_cmd Command to run. * @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. + * @return array{stdout: string, stderr: string, exit_code: int} */ - private static function run_sql( $sql_cmd, $assoc_args = [], $add_database = false ): void { + 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'], @@ -1120,11 +1123,19 @@ private static function run_sql( $sql_cmd, $assoc_args = [], $add_database = fal if ( $add_database ) { $sql_cmd .= ' ' . escapeshellarg( self::$db_settings['dbname'] ); } + $send_to_shell = true; + if ( isset( $assoc_args['send_to_shell'] ) ) { + $send_to_shell = (bool) $assoc_args['send_to_shell']; + unset( $assoc_args['send_to_shell'] ); + } + $start_time = microtime( true ); - Utils\run_mysql_command( $sql_cmd, array_merge( $assoc_args, $default_assoc_args ) ); + $result = Utils\run_mysql_command( $sql_cmd, array_merge( $assoc_args, $default_assoc_args ), null, $send_to_shell ); if ( self::$log_run_times ) { self::log_proc_method_run_time( 'run_sql ' . $sql_cmd, $start_time ); } + + return array_combine( [ 'stdout', 'stderr', 'exit_code' ], $result ); } public function create_db(): void { @@ -1136,6 +1147,37 @@ public function create_db(): void { self::run_sql( self::$mysql_binary . ' --no-defaults', [ 'execute' => "CREATE DATABASE IF NOT EXISTS $dbname" ] ); } + /** + * Test if the database connection is working. + */ + public function test_connection(): void { + if ( 'sqlite' === self::$db_type ) { + return; + } + + $sql_result = self::run_sql( + self::$mysql_binary . ' --no-defaults', + [ + 'execute' => 'SELECT 1', + 'send_to_shell' => false, + ] + ); + + if ( 0 !== $sql_result['exit_code'] ) { + # WP_CLI output functions are suppressed in behat context. + echo 'There was an error connecting to the database:' . \PHP_EOL; + if ( ! empty( $sql_result['stderr'] ) ) { + echo ' ' . trim( $sql_result['stderr'] ) . \PHP_EOL; + } + echo 'run `composer prepare-tests` to connect to the database.' . \PHP_EOL; + die( $sql_result['exit_code'] ); + } elseif ( ! empty( $sql_result['stderr'] ) ) { + // There is "error" output but not an exit code. + // Probably a warning, still display it. + echo trim( $sql_result['stderr'] ) . \PHP_EOL; + } + } + public function drop_db(): void { if ( 'sqlite' === self::$db_type ) { return;