From 88f3cf9a7e180a7d56489d299f4d65b39b9cb519 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Sun, 28 Sep 2025 21:56:56 +0100 Subject: [PATCH 1/4] HTTP requests with problems should trigger alerts, not warnings. --- collectors/http.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/collectors/http.php b/collectors/http.php index 86afe35b..a8311aa9 100644 --- a/collectors/http.php +++ b/collectors/http.php @@ -346,7 +346,7 @@ public function process() { $code = intval( wp_remote_retrieve_response_code( $response['response'] ) ); $type = "HTTP {$code}"; if ( ( $code >= 400 ) && ( 'HEAD' !== $request['args']['method'] ) ) { - $this->data->errors['warning'][] = $key; + $this->data->errors['alert'][] = $key; } } @@ -464,7 +464,7 @@ public function log_guzzle_request( $request, $response, $exception, string $url $this->data->ltime += $ltime; if ( $exception || ( $response && $response->getStatusCode() >= 400 ) ) { - $this->data->errors['warning'][] = $key; + $this->data->errors['alert'][] = $key; } } From 676ea15e22ab95d615374f6adacad2c8ce287f1c Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Sun, 28 Sep 2025 21:59:37 +0100 Subject: [PATCH 2/4] Add an HTTP bin service for testing and be more specific about the panel error state. --- docker-compose.yml | 8 +++++ tests/_support/AcceptanceTester.php | 30 ++++++++++++++++-- tests/_support/MUPlugin/acceptance.php | 41 +++---------------------- tests/acceptance/CallbacksCest.php | 5 --- tests/acceptance/DoingItWrongCest.php | 12 ++++---- tests/acceptance/GuzzleRequestsCest.php | 8 ++--- tests/acceptance/PhpErrorsCest.php | 8 ++--- 7 files changed, 52 insertions(+), 60 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b93ce5bd..7e395eeb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,3 +4,11 @@ include: - vendor/johnbillion/plugin-infrastructure/tests/docker-compose.yml - tests/_support/MUPlugin/acceptance.yml project_directory: . + +services: + httpbin: + image: mccutchen/go-httpbin:latest + container_name: ${COMPOSE_PROJECT_NAME}-httpbin + restart: always + environment: + PORT: 80 diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php index 15c98d61..7fd57515 100644 --- a/tests/_support/AcceptanceTester.php +++ b/tests/_support/AcceptanceTester.php @@ -48,13 +48,15 @@ public function seeQMMenuWithNotice(): void { $this->seeElement( '#wp-admin-bar-query-monitor.qm-notice' ); } - public function seeQMMenu(): void { + protected function seeQMMenu(): void { $this->seeElement( '#wp-admin-bar-query-monitor' ); + $this->dontSeeElement( '#wp-admin-bar-query-monitor.qm-error' ); + $this->dontSeeElement( '#wp-admin-bar-query-monitor.qm-alert' ); $this->dontSeeElement( '#wp-admin-bar-query-monitor.qm-warning' ); $this->dontSeeElement( '#wp-admin-bar-query-monitor.qm-notice' ); } - public function openQMPanel( string $panel ): void { + protected function openQMPanel( string $panel ): void { $this->click( '#wp-admin-bar-query-monitor' ); $this->click( $panel, '#qm-panel-menu' ); } @@ -62,5 +64,29 @@ public function openQMPanel( string $panel ): void { public function seeInQMPanel( string $panel, string $text ): void { $this->openQMPanel( $panel ); $this->see( $text, '.qm-panel-show' ); + $this->seeQMMenu(); + } + + public function seeInQMPanelWithError( string $panel, string $text ): void { + $this->openQMPanel( $panel ); + $this->see( $text, '.qm-panel-show' ); + $this->seeElement( '#wp-admin-bar-query-monitor.qm-error' ); + } + + public function seeInQMPanelWithAlert( string $panel, string $text ): void { + $this->openQMPanel( $panel ); + $this->see( $text, '.qm-panel-show' ); + $this->seeElement( '#wp-admin-bar-query-monitor.qm-alert' ); + } + public function seeInQMPanelWithWarning( string $panel, string $text ): void { + $this->openQMPanel( $panel ); + $this->see( $text, '.qm-panel-show' ); + $this->seeElement( '#wp-admin-bar-query-monitor.qm-warning' ); + } + + public function seeInQMPanelWithNotice( string $panel, string $text ): void { + $this->openQMPanel( $panel ); + $this->see( $text, '.qm-panel-show' ); + $this->seeElement( '#wp-admin-bar-query-monitor.qm-notice' ); } } diff --git a/tests/_support/MUPlugin/acceptance.php b/tests/_support/MUPlugin/acceptance.php index b50c546b..f2542fff 100644 --- a/tests/_support/MUPlugin/acceptance.php +++ b/tests/_support/MUPlugin/acceptance.php @@ -62,50 +62,17 @@ switch ( $_GET['_qm_acceptance_test'] ) { case 'successful_request': - // Create mock handler with a successful JSON response - $mock = new \GuzzleHttp\Handler\MockHandler( - [ - new \GuzzleHttp\Psr7\Response( - 200, - [ - 'Content-Type' => 'application/json', - ], - json_encode( - [ - 'foo' => 'bar', - ] - ) - ), - ] - ); - - $stack = \GuzzleHttp\HandlerStack::create( $mock ); + $stack = \GuzzleHttp\HandlerStack::create(); $stack->push( QM_Collector_HTTP::guzzle_middleware() ); $client = new \GuzzleHttp\Client( [ 'handler' => $stack ] ); - $client->get( 'https://example.org/json' ); + $client->get( 'http://httpbin/json' ); break; case 'error_request': - // Create mock handler with a 404 response - $mock = new \GuzzleHttp\Handler\MockHandler( - [ - new \GuzzleHttp\Psr7\Response( - 404, - [ - 'Content-Type' => 'text/html', - ], - ' - 404 Not Found -

Not Found

-

The requested URL was not found on the server.

' - ), - ] - ); - - $stack = \GuzzleHttp\HandlerStack::create( $mock ); + $stack = \GuzzleHttp\HandlerStack::create(); $stack->push( QM_Collector_HTTP::guzzle_middleware() ); $client = new \GuzzleHttp\Client( [ 'handler' => $stack ] ); try { - $client->get( 'https://example.org/status/404' ); + $client->get( 'http://httpbin/status/404' ); } catch ( \GuzzleHttp\Exception\ClientException $e ) { // Expected 404 error } diff --git a/tests/acceptance/CallbacksCest.php b/tests/acceptance/CallbacksCest.php index b5c30e2d..33549ea6 100644 --- a/tests/acceptance/CallbacksCest.php +++ b/tests/acceptance/CallbacksCest.php @@ -10,28 +10,24 @@ public function _before( AcceptanceTester $I ): void { public function FunctionCallbackShouldBeDisplayed( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersCallbackType( 'function' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'Hooks & Actions', '__return_true()' ); $I->seeInQMPanel( 'Hooks & Actions', 'qm_test_hook' ); } public function MethodCallbackShouldBeDisplayed( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersCallbackType( 'method' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'Hooks & Actions', 'test_method()' ); $I->seeInQMPanel( 'Hooks & Actions', 'qm_test_hook' ); } public function StaticMethodCallbackShouldBeDisplayed( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersCallbackType( 'static_method' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'Hooks & Actions', 'QM_Test_Static_Class::test_static_method()' ); $I->seeInQMPanel( 'Hooks & Actions', 'qm_test_hook' ); } public function ClosureCallbackShouldBeDisplayed( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersCallbackType( 'closure' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'Hooks & Actions', 'Closure on line' ); $I->seeInQMPanel( 'Hooks & Actions', 'acceptance.php' ); $I->seeInQMPanel( 'Hooks & Actions', 'qm_test_hook' ); @@ -39,7 +35,6 @@ public function ClosureCallbackShouldBeDisplayed( AcceptanceTester $I ): void { public function InvokableCallbackShouldBeDisplayed( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersCallbackType( 'invokable' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'Hooks & Actions', '__invoke()' ); $I->seeInQMPanel( 'Hooks & Actions', 'qm_test_hook' ); } diff --git a/tests/acceptance/DoingItWrongCest.php b/tests/acceptance/DoingItWrongCest.php index cea5df77..03805387 100644 --- a/tests/acceptance/DoingItWrongCest.php +++ b/tests/acceptance/DoingItWrongCest.php @@ -10,31 +10,31 @@ public function _before( AcceptanceTester $I ): void { public function DeprecatedArgumentShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'argument' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'Function my_function was called with an argument that is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'Function my_function was called with an argument that is deprecated since version 2.0.0' ); } public function DeprecatedClassShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'class' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'My_Class is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'My_Class is deprecated since version 2.0.0' ); } public function DeprecatedConstructorShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'constructor' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'The called constructor method for My_Class class is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'The called constructor method for My_Class class is deprecated since version 2.0.0' ); } public function DeprecatedFileShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'file' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'my_file.php is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'my_file.php is deprecated since version 2.0.0' ); } public function DeprecatedFunctionShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'function' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'my_function is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'my_function is deprecated since version 2.0.0' ); } public function DeprecatedHookShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatIsDoingItWrong( 'hook' ); - $I->seeInQMPanel( 'Doing it Wrong (1)', 'my_hook is deprecated since version 2.0.0' ); + $I->seeInQMPanelWithNotice( 'Doing it Wrong (1)', 'my_hook is deprecated since version 2.0.0' ); } } diff --git a/tests/acceptance/GuzzleRequestsCest.php b/tests/acceptance/GuzzleRequestsCest.php index 5bc28c84..719aa82d 100644 --- a/tests/acceptance/GuzzleRequestsCest.php +++ b/tests/acceptance/GuzzleRequestsCest.php @@ -10,13 +10,13 @@ public function _before( AcceptanceTester $I ): void { public function SuccessfulGuzzleRequestShouldBeLogged( AcceptanceTester $I ): void { $I->amOnAPageThatMakesGuzzleRequest( 'successful_request' ); - $I->seeQMMenu(); - $I->seeInQMPanel( 'HTTP API Calls (1)', 'https://example.org/json' ); + $I->seeInQMPanel( 'HTTP API Calls (1)', 'http://httpbin/json' ); + $I->seeInQMPanel( 'HTTP API Calls (1)', '200 OK' ); } public function ErrorGuzzleRequestShouldBeLogged( AcceptanceTester $I ): void { $I->amOnAPageThatMakesGuzzleRequest( 'error_request' ); - $I->seeQMMenuWithWarning(); - $I->seeInQMPanel( 'HTTP API Calls (1)', 'https://example.org/status/404' ); + $I->seeInQMPanelWithAlert( 'HTTP API Calls (1)', 'http://httpbin/status/404' ); + $I->seeInQMPanelWithAlert( 'HTTP API Calls (1)', '404 Not Found' ); } } diff --git a/tests/acceptance/PhpErrorsCest.php b/tests/acceptance/PhpErrorsCest.php index a90f936b..862ebec7 100644 --- a/tests/acceptance/PhpErrorsCest.php +++ b/tests/acceptance/PhpErrorsCest.php @@ -10,26 +10,22 @@ public function _before( AcceptanceTester $I ): void { public function WarningShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersPhpError( 'warning' ); - $I->seeQMMenuWithWarning(); - $I->seeInQMPanel( 'PHP Errors (1)', 'This is a test warning' ); + $I->seeInQMPanelWithWarning( 'PHP Errors (1)', 'This is a test warning' ); } public function NoticeShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersPhpError( 'notice' ); - $I->seeQMMenuWithNotice(); - $I->seeInQMPanel( 'PHP Errors (1)', 'This is a test notice' ); + $I->seeInQMPanelWithNotice( 'PHP Errors (1)', 'This is a test notice' ); } public function SuppressedWarningShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersSuppressedPhpError( 'warning' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'PHP Errors (1)', 'Warning (Suppressed)' ); $I->seeInQMPanel( 'PHP Errors (1)', 'This is a test suppressed warning' ); } public function SuppressedNoticeShouldBeHandled( AcceptanceTester $I ): void { $I->amOnAPageThatTriggersSuppressedPhpError( 'notice' ); - $I->seeQMMenu(); $I->seeInQMPanel( 'PHP Errors (1)', 'Notice (Suppressed)' ); $I->seeInQMPanel( 'PHP Errors (1)', 'This is a test suppressed notice' ); } From 2d6e6b878a8ade0564f2672d0ed690ed87d732b4 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Sun, 28 Sep 2025 22:00:05 +0100 Subject: [PATCH 3/4] Add acceptance tests for HTTP API requests. --- tests/_support/AcceptanceTester.php | 4 ++++ tests/acceptance/HttpApiCest.php | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/acceptance/HttpApiCest.php diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php index 7fd57515..464e5767 100644 --- a/tests/_support/AcceptanceTester.php +++ b/tests/_support/AcceptanceTester.php @@ -36,6 +36,10 @@ public function amOnAPageThatMakesGuzzleRequest( string $test ): void { $this->amOnPage( "/?_qm_acceptance_group=guzzle_requests&_qm_acceptance_test={$test}" ); } + public function amOnAPageThatMakesHttpRequest( string $test ): void { + $this->amOnPage( "/?_qm_acceptance_group=http_requests&_qm_acceptance_test={$test}" ); + } + public function amOnAPageThatTriggersCallbackType( string $test ): void { $this->amOnPage( "/?_qm_acceptance_group=callback_types&_qm_acceptance_test={$test}" ); } diff --git a/tests/acceptance/HttpApiCest.php b/tests/acceptance/HttpApiCest.php new file mode 100644 index 00000000..6a0a5809 --- /dev/null +++ b/tests/acceptance/HttpApiCest.php @@ -0,0 +1,22 @@ +loginAsAdmin(); + } + + public function SuccessfulHttpRequestShouldBeLogged( AcceptanceTester $I ): void { + $I->amOnAPageThatMakesHttpRequest( 'successful_request' ); + $I->seeInQMPanel( 'HTTP API Calls (1)', 'http://httpbin/status/200' ); + $I->seeInQMPanel( 'HTTP API Calls (1)', '200 OK' ); + } + + public function ErrorHttpRequestShouldBeLogged( AcceptanceTester $I ): void { + $I->amOnAPageThatMakesHttpRequest( '404_request' ); + $I->seeInQMPanelWithAlert( 'HTTP API Calls (1)', 'http://httpbin/status/404' ); + $I->seeInQMPanelWithAlert( 'HTTP API Calls (1)', '404 Not Found' ); + } +} From b87481f6cf263f58cf50ec806f4f479bd2bd6f50 Mon Sep 17 00:00:00 2001 From: John Blackbourn Date: Sun, 28 Sep 2025 22:00:33 +0100 Subject: [PATCH 4/4] Need this too. --- tests/_support/MUPlugin/acceptance.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/_support/MUPlugin/acceptance.php b/tests/_support/MUPlugin/acceptance.php index f2542fff..2caff7a0 100644 --- a/tests/_support/MUPlugin/acceptance.php +++ b/tests/_support/MUPlugin/acceptance.php @@ -82,6 +82,19 @@ break; } break; + case 'http_requests': + switch ( $_GET['_qm_acceptance_test'] ) { + case 'successful_request': + wp_remote_get( 'http://httpbin/status/200' ); + break; + case '404_request': + wp_remote_get( 'http://httpbin/status/404' ); + break; + default: + throw new \InvalidArgumentException( 'Unknown test: ' . $_GET['_qm_acceptance_test'] ); + break; + } + break; case 'callback_types': switch ( $_GET['_qm_acceptance_test'] ) { case 'function':