From dfad3317378393564bf17e00ced49800318e4fa7 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:12:28 +0100 Subject: [PATCH 01/10] Add http request mocking support --- features/http-mocking.feature | 317 +++++++++++++++++++++++++++ src/Context/FeatureContext.php | 2 + src/Context/GivenStepDefinitions.php | 118 ++++++++++ 3 files changed, 437 insertions(+) create mode 100644 features/http-mocking.feature diff --git a/features/http-mocking.feature b/features/http-mocking.feature new file mode 100644 index 000000000..2037f61a4 --- /dev/null +++ b/features/http-mocking.feature @@ -0,0 +1,317 @@ +Feature: HTTP request mocking + + Scenario: Mock HTTP request in WP-CLI + Given an empty directory + And an HTTP request to https://api.github.com/repos/wp-cli/wp-cli/releases?per_page=100 with this response: + """ + HTTP/1.1 200 + Content-Type: application/json + + [ + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/169243978", + "assets_url": "https://api.github.com/repos/wp-cli/wp-cli/releases/169243978/assets", + "upload_url": "https://uploads.github.com/repos/wp-cli/wp-cli/releases/169243978/assets{?name,label}", + "html_url": "https://github.com/wp-cli/wp-cli/releases/tag/v999.9.9", + "id": 169243978, + "author": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "node_id": "RE_kwDOACQFs84KFnVK", + "tag_name": "v999.9.9", + "target_commitish": "main", + "name": "Version 999.9.9", + "draft": false, + "prerelease": false, + "created_at": "2024-08-08T03:04:55Z", + "published_at": "2024-08-08T03:51:13Z", + "assets": [ + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590231", + "id": 184590231, + "node_id": "RA_kwDOACQFs84LAJ-X", + "name": "wp-cli-999.9.9.phar", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 7048108, + "download_count": 722639, + "created_at": "2024-08-08T03:51:05Z", + "updated_at": "2024-08-08T03:51:08Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar" + }, + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590236", + "id": 184590236, + "node_id": "RA_kwDOACQFs84LAJ-c", + "name": "wp-cli-999.9.9.phar.asc", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 516, + "download_count": 6279, + "created_at": "2024-08-08T03:51:08Z", + "updated_at": "2024-08-08T03:51:08Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.asc" + }, + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590237", + "id": 184590237, + "node_id": "RA_kwDOACQFs84LAJ-d", + "name": "wp-cli-999.9.9.phar.gpg", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 1654621, + "download_count": 2089, + "created_at": "2024-08-08T03:51:08Z", + "updated_at": "2024-08-08T03:51:09Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.gpg" + }, + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590241", + "id": 184590241, + "node_id": "RA_kwDOACQFs84LAJ-h", + "name": "wp-cli-999.9.9.phar.md5", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 33, + "download_count": 381247, + "created_at": "2024-08-08T03:51:09Z", + "updated_at": "2024-08-08T03:51:09Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.md5" + }, + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590242", + "id": 184590242, + "node_id": "RA_kwDOACQFs84LAJ-i", + "name": "wp-cli-999.9.9.phar.sha256", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 65, + "download_count": 1104, + "created_at": "2024-08-08T03:51:09Z", + "updated_at": "2024-08-08T03:51:10Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.sha256" + }, + { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590243", + "id": 184590243, + "node_id": "RA_kwDOACQFs84LAJ-j", + "name": "wp-cli-999.9.9.phar.sha512", + "label": null, + "uploader": { + "login": "schlessera", + "id": 83631, + "node_id": "MDQ6VXNlcjgzNjMx", + "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/schlessera", + "html_url": "https://github.com/schlessera", + "followers_url": "https://api.github.com/users/schlessera/followers", + "following_url": "https://api.github.com/users/schlessera/following{/other_user}", + "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", + "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", + "organizations_url": "https://api.github.com/users/schlessera/orgs", + "repos_url": "https://api.github.com/users/schlessera/repos", + "events_url": "https://api.github.com/users/schlessera/events{/privacy}", + "received_events_url": "https://api.github.com/users/schlessera/received_events", + "type": "User", + "user_view_type": "public", + "site_admin": false + }, + "content_type": "application/octet-stream", + "state": "uploaded", + "size": 129, + "download_count": 6587, + "created_at": "2024-08-08T03:51:10Z", + "updated_at": "2024-08-08T03:51:10Z", + "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.sha512" + } + ], + "tarball_url": "https://api.github.com/repos/wp-cli/wp-cli/tarball/v999.9.9", + "zipball_url": "https://api.github.com/repos/wp-cli/wp-cli/zipball/v999.9.9", + "body": "- Allow manually dispatching tests workflow [[#5965](https://github.com/wp-cli/wp-cli/pull/5965)]\r\n- Add fish shell completion [[#5954](https://github.com/wp-cli/wp-cli/pull/5954)]\r\n- Add defaults and accepted values for runcommand() options in doc [[#5953](https://github.com/wp-cli/wp-cli/pull/5953)]\r\n- Address warnings with filenames ending in fullstop on Windows [[#5951](https://github.com/wp-cli/wp-cli/pull/5951)]\r\n- Fix unit tests [[#5950](https://github.com/wp-cli/wp-cli/pull/5950)]\r\n- Update copyright year in license [[#5942](https://github.com/wp-cli/wp-cli/pull/5942)]\r\n- Fix breaking multi-line CSV values on reading [[#5939](https://github.com/wp-cli/wp-cli/pull/5939)]\r\n- Fix broken Gutenberg test [[#5938](https://github.com/wp-cli/wp-cli/pull/5938)]\r\n- Update docker runner to resolve docker path using `/usr/bin/env` [[#5936](https://github.com/wp-cli/wp-cli/pull/5936)]\r\n- Fix `inherit` path in nested directory [[#5930](https://github.com/wp-cli/wp-cli/pull/5930)]\r\n- Minor docblock improvements [[#5929](https://github.com/wp-cli/wp-cli/pull/5929)]\r\n- Add Signup fetcher [[#5926](https://github.com/wp-cli/wp-cli/pull/5926)]\r\n- Ensure the alias has the leading `@` symbol when added [[#5924](https://github.com/wp-cli/wp-cli/pull/5924)]\r\n- Include any non default hook information in CompositeCommand [[#5921](https://github.com/wp-cli/wp-cli/pull/5921)]\r\n- Correct completion case when ends in = [[#5913](https://github.com/wp-cli/wp-cli/pull/5913)]\r\n- Docs: Fixes for inline comments [[#5912](https://github.com/wp-cli/wp-cli/pull/5912)]\r\n- Update Inline comments [[#5910](https://github.com/wp-cli/wp-cli/pull/5910)]\r\n- Add a real-world example for `wp cli has-command` [[#5908](https://github.com/wp-cli/wp-cli/pull/5908)]\r\n- Fix typos [[#5901](https://github.com/wp-cli/wp-cli/pull/5901)]\r\n- Avoid PHP deprecation notices in PHP 8.1.x [[#5899](https://github.com/wp-cli/wp-cli/pull/5899)]", + "reactions": { + "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/169243978/reactions", + "total_count": 9, + "+1": 4, + "-1": 0, + "laugh": 0, + "hooray": 1, + "confused": 0, + "heart": 0, + "rocket": 4, + "eyes": 0 + } + } + ] + """ + + When I run `wp cli check-update` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 999.9.9 | major | https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar | + + Scenario: Mock HTTP request in WordPress + Given a WP install + And an HTTP request to https://api.wordpress.org/core/version-check/1.7/ with this response: + """ + HTTP/1.1 200 + Content-Type: application/json + + { + "offers": [ + { + "response": "latest", + "download": "https:\/\/downloads.wordpress.org\/release\/wordpress-999.9.9.zip", + "locale": "en_US", + "packages": { + "full": "https:\/\/downloads.wordpress.org\/release\/wordpress-999.9.9.zip", + "no_content": "https:\/\/downloads.wordpress.org\/release\/wordpress-999.9.9-no-content.zip", + "new_bundled": "https:\/\/downloads.wordpress.org\/release\/wordpress-999.9.9-new-bundled.zip", + "partial": false, + "rollback": false + }, + "current": "999.9.9", + "version": "999.9.9", + "php_version": "7.2.24", + "mysql_version": "5.5.5", + "new_bundled": "6.7", + "partial_version": false + } + ], + "translations": [] + } + """ + + When I run `wp core check-update` + Then STDOUT should be a table containing rows: + | version | update_type | package_url | + | 999.9.9 | major | https://downloads.wordpress.org/release/wordpress-999.9.9.zip | diff --git a/src/Context/FeatureContext.php b/src/Context/FeatureContext.php index aa53ee367..f8d694db9 100644 --- a/src/Context/FeatureContext.php +++ b/src/Context/FeatureContext.php @@ -107,6 +107,8 @@ class FeatureContext implements SnippetAcceptingContext { private static $scenario_count = 0; // Scenario count, incremented on `@AfterScenario`. 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. + private $mocked_requests = []; + /** * Get the path to the Composer vendor folder. * diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 26208bd96..92f15e670 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -81,6 +81,124 @@ public function given_string_replaced_with_string_in_a_specific_file( $search, $ file_put_contents( $full_path, $contents ); } + /** + * @Given /^an? HTTP request to (.*?) with this response:$/ + */ + public function given_a_request_to_a_url_respond_with_file( $url_or_pattern, PyStringNode $content ) { + if ( ! isset( $this->variables['RUN_DIR'] ) ) { + $this->create_run_dir(); + } + + $config_file = $this->variables['RUN_DIR'] . '/wp-cli.yml'; + $mock_file = $this->variables['RUN_DIR'] . '/mock-requests.php'; + $dir = dirname( $config_file ); + + if ( ! file_exists( $dir ) ) { + mkdir( $dir, 0777, true /*recursive*/ ); + } + + $config_file_contents = <<mocked_requests[ $pattern ] = (string) $content; + + $mocked_requests = var_export( $this->mocked_requests, true /* return */ ); + + $mock_file_contents = << \$response ) { + if ( false !== preg_match( \$pattern, \$url ) ) { + \$pos = strpos( \$response, "\n\n"); + if ( false !== \$pos ) { + \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); + } + return \$response; + } + } + + return (new Curl())->request( \$url, \$headers, \$data, \$options ); + } + + public function request_multiple( \$requests, \$options ) { + throw new Exception( 'Method not implemented: ' . __METHOD__ ); + } + + public static function test( \$capabilities = array() ) { + return true; + } +} + +WP_CLI::add_hook( + 'http_request_options', + static function( \$options ) { + \$options['transport'] = new WP_CLI_Tests_Mock_Requests_Transport(); + return \$options; + } +); + +WP_CLI::add_wp_hook( + 'pre_http_request', + static function( \$pre, \$parsed_args, \$url ) { + \$mocked_requests = $mocked_requests; + + foreach ( \$mocked_requests as \$pattern => \$response ) { + if ( false !== preg_match( \$pattern, \$url ) ) { + \$pos = strpos( \$response, "\n\n"); + if ( false !== \$pos ) { + \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); + } + Requests::parse_multiple( + \$response, + array( + 'url' => \$url, + 'headers' => array(), + 'data' => array(), + 'options' => array_merge( + Requests::OPTION_DEFAULTS, + array( + 'hooks' => new Hooks(), + ), + ), + ) + ); + + \$response = new WP_HTTP_Requests_Response( \$response ); + + return \$response->to_array(); + } + } + + return \$pre; + }, + 10, + 3 +); +FILE; + + file_put_contents( + $mock_file, + $mock_file_contents + ); + } + /** * @Given WP files */ From 869e03e5118ce5fd92dac72ac096e71869422e55 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:15:34 +0100 Subject: [PATCH 02/10] Use temp branch for demo --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7546d154b..7d7d178ae 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "wp-cli/config-command": "^1 || ^2", "wp-cli/core-command": "^1 || ^2", "wp-cli/eval-command": "^1 || ^2", - "wp-cli/wp-cli": "^2.12", + "wp-cli/wp-cli": "dev-add-http-hook", "wp-coding-standards/wpcs": "^3", "yoast/phpunit-polyfills": "^1.0.3 || ^2.0.1" }, From 4e51863d7188eb592809328af125cdeef1c8d0c5 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:21:01 +0100 Subject: [PATCH 03/10] Make test a bit shorter --- features/http-mocking.feature | 198 +--------------------------------- 1 file changed, 1 insertion(+), 197 deletions(-) diff --git a/features/http-mocking.feature b/features/http-mocking.feature index 2037f61a4..11dec7414 100644 --- a/features/http-mocking.feature +++ b/features/http-mocking.feature @@ -50,27 +50,6 @@ Feature: HTTP request mocking "node_id": "RA_kwDOACQFs84LAJ-X", "name": "wp-cli-999.9.9.phar", "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, "content_type": "application/octet-stream", "state": "uploaded", "size": 7048108, @@ -78,181 +57,6 @@ Feature: HTTP request mocking "created_at": "2024-08-08T03:51:05Z", "updated_at": "2024-08-08T03:51:08Z", "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar" - }, - { - "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590236", - "id": 184590236, - "node_id": "RA_kwDOACQFs84LAJ-c", - "name": "wp-cli-999.9.9.phar.asc", - "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, - "content_type": "application/octet-stream", - "state": "uploaded", - "size": 516, - "download_count": 6279, - "created_at": "2024-08-08T03:51:08Z", - "updated_at": "2024-08-08T03:51:08Z", - "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.asc" - }, - { - "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590237", - "id": 184590237, - "node_id": "RA_kwDOACQFs84LAJ-d", - "name": "wp-cli-999.9.9.phar.gpg", - "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, - "content_type": "application/octet-stream", - "state": "uploaded", - "size": 1654621, - "download_count": 2089, - "created_at": "2024-08-08T03:51:08Z", - "updated_at": "2024-08-08T03:51:09Z", - "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.gpg" - }, - { - "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590241", - "id": 184590241, - "node_id": "RA_kwDOACQFs84LAJ-h", - "name": "wp-cli-999.9.9.phar.md5", - "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, - "content_type": "application/octet-stream", - "state": "uploaded", - "size": 33, - "download_count": 381247, - "created_at": "2024-08-08T03:51:09Z", - "updated_at": "2024-08-08T03:51:09Z", - "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.md5" - }, - { - "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590242", - "id": 184590242, - "node_id": "RA_kwDOACQFs84LAJ-i", - "name": "wp-cli-999.9.9.phar.sha256", - "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, - "content_type": "application/octet-stream", - "state": "uploaded", - "size": 65, - "download_count": 1104, - "created_at": "2024-08-08T03:51:09Z", - "updated_at": "2024-08-08T03:51:10Z", - "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.sha256" - }, - { - "url": "https://api.github.com/repos/wp-cli/wp-cli/releases/assets/184590243", - "id": 184590243, - "node_id": "RA_kwDOACQFs84LAJ-j", - "name": "wp-cli-999.9.9.phar.sha512", - "label": null, - "uploader": { - "login": "schlessera", - "id": 83631, - "node_id": "MDQ6VXNlcjgzNjMx", - "avatar_url": "https://avatars.githubusercontent.com/u/83631?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/schlessera", - "html_url": "https://github.com/schlessera", - "followers_url": "https://api.github.com/users/schlessera/followers", - "following_url": "https://api.github.com/users/schlessera/following{/other_user}", - "gists_url": "https://api.github.com/users/schlessera/gists{/gist_id}", - "starred_url": "https://api.github.com/users/schlessera/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/schlessera/subscriptions", - "organizations_url": "https://api.github.com/users/schlessera/orgs", - "repos_url": "https://api.github.com/users/schlessera/repos", - "events_url": "https://api.github.com/users/schlessera/events{/privacy}", - "received_events_url": "https://api.github.com/users/schlessera/received_events", - "type": "User", - "user_view_type": "public", - "site_admin": false - }, - "content_type": "application/octet-stream", - "state": "uploaded", - "size": 129, - "download_count": 6587, - "created_at": "2024-08-08T03:51:10Z", - "updated_at": "2024-08-08T03:51:10Z", - "browser_download_url": "https://github.com/wp-cli/wp-cli/releases/download/v999.9.9/wp-cli-999.9.9.phar.sha512" } ], "tarball_url": "https://api.github.com/repos/wp-cli/wp-cli/tarball/v999.9.9", @@ -308,7 +112,7 @@ Feature: HTTP request mocking } ], "translations": [] - } + } """ When I run `wp core check-update` From 52acafad789c6b65cb4844d6d09b3ad97b743022 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:24:14 +0100 Subject: [PATCH 04/10] Fix alias --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 7d7d178ae..e99f99763 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "wp-cli/config-command": "^1 || ^2", "wp-cli/core-command": "^1 || ^2", "wp-cli/eval-command": "^1 || ^2", - "wp-cli/wp-cli": "dev-add-http-hook", + "wp-cli/wp-cli": "dev-add-http-hook as 2.12.x-dev", "wp-coding-standards/wpcs": "^3", "yoast/phpunit-polyfills": "^1.0.3 || ^2.0.1" }, From edf789f9175ae8819858b75d013458738cf3f8ae Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:30:13 +0100 Subject: [PATCH 05/10] No trailing comma --- src/Context/GivenStepDefinitions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 92f15e670..74a346619 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -175,7 +175,7 @@ static function( \$pre, \$parsed_args, \$url ) { Requests::OPTION_DEFAULTS, array( 'hooks' => new Hooks(), - ), + ) ), ) ); From 073acc28415259b26f82d48e1fde6585bb97390e Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Sun, 26 Jan 2025 21:46:20 +0100 Subject: [PATCH 06/10] Don't use WP_HTTP_Requests_Response (WP 3.7 compat) --- src/Context/GivenStepDefinitions.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 74a346619..b9a43901f 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -180,9 +180,16 @@ static function( \$pre, \$parsed_args, \$url ) { ) ); - \$response = new WP_HTTP_Requests_Response( \$response ); - - return \$response->to_array(); + return array( + 'headers' => \$response->headers->getAll(), + 'body' => \$response->body, + 'response' => array( + 'code' => \$response->status_code, + 'message' => get_status_header_desc( \$response->status_code ), + ), + 'cookies' => array(), + 'filename' => '', + ); } } From 152098b972a9dc944733f05458a0ca34182aa825 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Mon, 27 Jan 2025 16:25:57 +0100 Subject: [PATCH 07/10] Escape newlines & check for correct return value --- src/Context/GivenStepDefinitions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index b9a43901f..de6c534ab 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -125,10 +125,10 @@ public function request( \$url, \$headers = array(), \$data = array(), \$options \$mocked_requests = $mocked_requests; foreach ( \$mocked_requests as \$pattern => \$response ) { - if ( false !== preg_match( \$pattern, \$url ) ) { - \$pos = strpos( \$response, "\n\n"); + if ( 1 === preg_match( \$pattern, \$url ) ) { + \$pos = strpos( \$response, "\\n\\n"); if ( false !== \$pos ) { - \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); + \$response = substr( \$response, 0, \$pos ) . "\\r\\n\\r\\n" . substr( \$response, \$pos + 2 ); } return \$response; } @@ -160,7 +160,7 @@ static function( \$pre, \$parsed_args, \$url ) { \$mocked_requests = $mocked_requests; foreach ( \$mocked_requests as \$pattern => \$response ) { - if ( false !== preg_match( \$pattern, \$url ) ) { + if ( 1 === preg_match( \$pattern, \$url ) ) { \$pos = strpos( \$response, "\n\n"); if ( false !== \$pos ) { \$response = substr( \$response, 0, \$pos ) . "\r\n\r\n" . substr( \$response, \$pos + 2 ); From ec211711458e646c704c6a02d3023cdd9194dab6 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Mon, 27 Jan 2025 16:32:23 +0100 Subject: [PATCH 08/10] Fix double slash issue --- src/Context/GivenStepDefinitions.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index de6c534ab..63d66ead1 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -107,9 +107,7 @@ public function given_a_request_to_a_url_respond_with_file( $url_or_pattern, PyS $config_file_contents ); - $pattern = '/' . preg_quote( $url_or_pattern, '/' ) . '/'; - - $this->mocked_requests[ $pattern ] = (string) $content; + $this->mocked_requests[ $url_or_pattern ] = (string) $content; $mocked_requests = var_export( $this->mocked_requests, true /* return */ ); @@ -125,6 +123,7 @@ public function request( \$url, \$headers = array(), \$data = array(), \$options \$mocked_requests = $mocked_requests; foreach ( \$mocked_requests as \$pattern => \$response ) { + \$pattern = '/' . preg_quote( \$pattern, '/' ) . '/'; if ( 1 === preg_match( \$pattern, \$url ) ) { \$pos = strpos( \$response, "\\n\\n"); if ( false !== \$pos ) { @@ -160,6 +159,7 @@ static function( \$pre, \$parsed_args, \$url ) { \$mocked_requests = $mocked_requests; foreach ( \$mocked_requests as \$pattern => \$response ) { + \$pattern = '/' . preg_quote( \$pattern, '/' ) . '/'; if ( 1 === preg_match( \$pattern, \$url ) ) { \$pos = strpos( \$response, "\n\n"); if ( false !== \$pos ) { From 0a911920c873c5f4e9355be91bea76200de561a1 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Tue, 28 Jan 2025 16:53:15 +0100 Subject: [PATCH 09/10] Switch branch again --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e99f99763..7546d154b 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "wp-cli/config-command": "^1 || ^2", "wp-cli/core-command": "^1 || ^2", "wp-cli/eval-command": "^1 || ^2", - "wp-cli/wp-cli": "dev-add-http-hook as 2.12.x-dev", + "wp-cli/wp-cli": "^2.12", "wp-coding-standards/wpcs": "^3", "yoast/phpunit-polyfills": "^1.0.3 || ^2.0.1" }, From a3f9c1641a52b87c59fd8c1a33fc1913e7c934b5 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 13 Feb 2025 16:20:56 +0100 Subject: [PATCH 10/10] Rename step --- features/http-mocking.feature | 5 ++--- src/Context/GivenStepDefinitions.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/features/http-mocking.feature b/features/http-mocking.feature index 11dec7414..ac5a42c91 100644 --- a/features/http-mocking.feature +++ b/features/http-mocking.feature @@ -1,8 +1,7 @@ Feature: HTTP request mocking Scenario: Mock HTTP request in WP-CLI - Given an empty directory - And an HTTP request to https://api.github.com/repos/wp-cli/wp-cli/releases?per_page=100 with this response: + Given that HTTP requests to https://api.github.com/repos/wp-cli/wp-cli/releases?per_page=100 will respond with: """ HTTP/1.1 200 Content-Type: application/json @@ -85,7 +84,7 @@ Feature: HTTP request mocking Scenario: Mock HTTP request in WordPress Given a WP install - And an HTTP request to https://api.wordpress.org/core/version-check/1.7/ with this response: + And that HTTP requests to https://api.wordpress.org/core/version-check/1.7/ will respond with: """ HTTP/1.1 200 Content-Type: application/json diff --git a/src/Context/GivenStepDefinitions.php b/src/Context/GivenStepDefinitions.php index 63d66ead1..b8e49c068 100644 --- a/src/Context/GivenStepDefinitions.php +++ b/src/Context/GivenStepDefinitions.php @@ -82,7 +82,7 @@ public function given_string_replaced_with_string_in_a_specific_file( $search, $ } /** - * @Given /^an? HTTP request to (.*?) with this response:$/ + * @Given /^that HTTP requests to (.*?) will respond with:$/ */ public function given_a_request_to_a_url_respond_with_file( $url_or_pattern, PyStringNode $content ) { if ( ! isset( $this->variables['RUN_DIR'] ) ) {