diff --git a/classes/class-cli.php b/classes/class-cli.php index 5d7b9cde4..7258d2ed9 100644 --- a/classes/class-cli.php +++ b/classes/class-cli.php @@ -223,14 +223,19 @@ private function csv_format( $records ) { * @return void */ private function connection() { - $query = wp_stream_get_instance()->db->query( + global $wpdb; + + wp_stream_get_instance()->db->query( array( 'records_per_page' => 1, 'fields' => 'created', ) ); - if ( ! $query ) { + // An empty result set is valid (e.g. a fresh site with no logged + // activity yet); only a genuine database error means the site is + // disconnected. + if ( ! empty( $wpdb->last_error ) ) { \WP_CLI::error( esc_html__( 'SITE IS DISCONNECTED', 'stream' ) ); } } diff --git a/tests/phpunit/test-class-cli.php b/tests/phpunit/test-class-cli.php new file mode 100644 index 000000000..939621ec0 --- /dev/null +++ b/tests/phpunit/test-class-cli.php @@ -0,0 +1,74 @@ +setAccessible( true ); + $capture_exit->setValue( null, true ); + + $connection = new ReflectionMethod( CLI::class, 'connection' ); + $connection->setAccessible( true ); + + try { + $connection->invoke( new CLI() ); + } finally { + $capture_exit->setValue( null, false ); + } + } + + /** + * A query that legitimately matches zero records is not a disconnection. + */ + public function test_connection_does_not_error_on_empty_result() { + global $wpdb; + + // Force the connection check's query to match nothing, without + // touching any actual data other tests rely on. + $force_no_matches = function ( $where ) { + return $where . ' AND 1=0'; + }; + add_filter( 'wp_stream_db_query_where', $force_no_matches ); + + try { + $this->invoke_connection(); + } finally { + remove_filter( 'wp_stream_db_query_where', $force_no_matches ); + } + + // Reaching this line means WP_CLI::error() was never triggered. + $this->assertEmpty( $wpdb->last_error ); + } + + /** + * A genuine database error should still be reported as a disconnected site. + */ + public function test_connection_errors_on_database_failure() { + global $wpdb; + + $original_table = $wpdb->stream; + $wpdb->stream = $wpdb->prefix . 'stream_table_that_does_not_exist'; + $wpdb->suppress_errors( true ); + + try { + $this->expectException( ExitException::class ); + $this->invoke_connection(); + } finally { + $wpdb->stream = $original_table; + $wpdb->suppress_errors( false ); + $wpdb->last_error = ''; + } + } +}