Make WordPress Core


Ignore:
Timestamp:
08/31/2022 10:44:04 PM (15 months ago)
Author:
flixos90
Message:

Site Health: Introduce page cache check.

This changeset adds a new page_cache check which determines whether the site uses a full page cache, and in addition assesses the server response time. If no page cache is present and the server response time is slow, the check will suggest use of a page cache.

A few filters are included for customization of the check:

  • site_status_good_response_time_threshold filters the number of milliseconds below which the server response time is considered good. The default value is based on the server-response-time Lighthouse audit and can be altered using this filter.
  • site_status_page_cache_supported_cache_headers filters the map of supported cache headers and their callback to determine whether it was a cache hit. The default list includes commonly used cache headers, and it is filterable to support e.g. additional cache headers used by specific vendors.

Note that due to the nature of this check it is only run in production environments.

Props furi3r, westonruter, spacedmonkey, swissspidy, Clorith.
Fixes #56041.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/site-health.php

    r53955 r54043  
    110110
    111111    /**
     112     * @ticket 56041
     113     * @dataProvider data_page_cache_test
     114     * @covers ::get_test_page_cache()
     115     * @covers ::get_page_cache_detail()
     116     * @covers ::get_page_cache_headers()
     117     * @covers ::check_for_page_caching()
     118     */
     119    public function test_get_page_cache( $responses, $expected_status, $expected_label, $good_basic_auth = null, $delay_the_response = false ) {
     120        $wp_site_health = new WP_Site_Health();
     121
     122        $expected_props = array(
     123            'badge'  => array(
     124                'label' => __( 'Performance' ),
     125                'color' => 'blue',
     126            ),
     127            'test'   => 'page_cache',
     128            'status' => $expected_status,
     129            'label'  => $expected_label,
     130        );
     131
     132        if ( null !== $good_basic_auth ) {
     133            $_SERVER['PHP_AUTH_USER'] = 'admin';
     134            $_SERVER['PHP_AUTH_PW']   = 'password';
     135        }
     136
     137        $threshold = 10;
     138        if ( $delay_the_response ) {
     139            add_filter(
     140                'site_status_good_response_time_threshold',
     141                static function () use ( $threshold ) {
     142                    return $threshold;
     143                }
     144            );
     145        }
     146
     147        add_filter(
     148            'pre_http_request',
     149            function ( $r, $parsed_args ) use ( &$responses, &$is_unauthorized, $good_basic_auth, $delay_the_response, $threshold ) {
     150
     151                $expected_response = array_shift( $responses );
     152
     153                if ( $delay_the_response ) {
     154                    usleep( $threshold * 1000 + 1 );
     155                }
     156
     157                if ( 'unauthorized' === $expected_response ) {
     158                    $is_unauthorized = true;
     159
     160                    return array(
     161                        'response' => array(
     162                            'code'    => 401,
     163                            'message' => 'Unauthorized',
     164                        ),
     165                    );
     166                }
     167
     168                if ( null !== $good_basic_auth ) {
     169                    $this->assertArrayHasKey(
     170                        'Authorization',
     171                        $parsed_args['headers']
     172                    );
     173                }
     174
     175                $this->assertIsArray( $expected_response );
     176
     177                return array(
     178                    'headers'  => $expected_response,
     179                    'response' => array(
     180                        'code'    => 200,
     181                        'message' => 'OK',
     182                    ),
     183                );
     184            },
     185            20,
     186            2
     187        );
     188
     189        $actual = $wp_site_health->get_test_page_cache();
     190        $this->assertArrayHasKey( 'description', $actual );
     191        $this->assertArrayHasKey( 'actions', $actual );
     192        if ( $is_unauthorized ) {
     193            $this->assertStringContainsString( 'Unauthorized', $actual['description'] );
     194        } else {
     195            $this->assertStringNotContainsString( 'Unauthorized', $actual['description'] );
     196        }
     197
     198        $this->assertEquals(
     199            $expected_props,
     200            wp_array_slice_assoc( $actual, array_keys( $expected_props ) )
     201        );
     202    }
     203
     204    /**
    112205     * @group ms-excluded
    113206     * @ticket 56040
     
    160253        $this->assertTrue(
    161254            $wp_site_health->should_suggest_persistent_object_cache()
     255        );
     256    }
     257
     258    /**
     259     * Gets response data for get_test_page_cache().
     260     * @ticket 56041
     261     *
     262     * @return array[]
     263     */
     264    public function data_page_cache_test() {
     265        $recommended_label = 'Page cache is not detected but the server response time is OK';
     266        $good_label        = 'Page cache is detected and the server response time is good';
     267        $critical_label    = 'Page cache is not detected and the server response time is slow';
     268        $error_label       = 'Unable to detect the presence of page cache';
     269
     270        return array(
     271            'basic-auth-fail'                        => array(
     272                'responses'       => array(
     273                    'unauthorized',
     274                ),
     275                'expected_status' => 'recommended',
     276                'expected_label'  => $error_label,
     277                'good_basic_auth' => false,
     278            ),
     279            'no-cache-control'                       => array(
     280                'responses'          => array_fill( 0, 3, array() ),
     281                'expected_status'    => 'critical',
     282                'expected_label'     => $critical_label,
     283                'good_basic_auth'    => null,
     284                'delay_the_response' => true,
     285            ),
     286            'no-cache'                               => array(
     287                'responses'       => array_fill( 0, 3, array( 'cache-control' => 'no-cache' ) ),
     288                'expected_status' => 'recommended',
     289                'expected_label'  => $recommended_label,
     290            ),
     291            'no-cache-arrays'                        => array(
     292                'responses'       => array_fill(
     293                    0,
     294                    3,
     295                    array(
     296                        'cache-control' => array(
     297                            'no-cache',
     298                            'no-store',
     299                        ),
     300                    )
     301                ),
     302                'expected_status' => 'recommended',
     303                'expected_label'  => $recommended_label,
     304            ),
     305            'no-cache-with-delayed-response'         => array(
     306                'responses'          => array_fill( 0, 3, array( 'cache-control' => 'no-cache' ) ),
     307                'expected_status'    => 'critical',
     308                'expected_label'     => $critical_label,
     309                'good_basic_auth'    => null,
     310                'delay_the_response' => true,
     311            ),
     312            'age'                                    => array(
     313                'responses'       => array_fill(
     314                    0,
     315                    3,
     316                    array( 'age' => '1345' )
     317                ),
     318                'expected_status' => 'good',
     319                'expected_label'  => $good_label,
     320            ),
     321            'cache-control-max-age'                  => array(
     322                'responses'       => array_fill(
     323                    0,
     324                    3,
     325                    array( 'cache-control' => 'public; max-age=600' )
     326                ),
     327                'expected_status' => 'good',
     328                'expected_label'  => $good_label,
     329            ),
     330            'etag'                                   => array(
     331                'responses'       => array_fill(
     332                    0,
     333                    3,
     334                    array( 'etag' => '"1234567890"' )
     335                ),
     336                'expected_status' => 'good',
     337                'expected_label'  => $good_label,
     338            ),
     339            'cache-control-max-age-after-2-requests' => array(
     340                'responses'       => array(
     341                    array(),
     342                    array(),
     343                    array( 'cache-control' => 'public; max-age=600' ),
     344                ),
     345                'expected_status' => 'good',
     346                'expected_label'  => $good_label,
     347            ),
     348            'cache-control-with-future-expires'      => array(
     349                'responses'       => array_fill(
     350                    0,
     351                    3,
     352                    array( 'expires' => gmdate( 'r', time() + MINUTE_IN_SECONDS * 10 ) )
     353                ),
     354                'expected_status' => 'good',
     355                'expected_label'  => $good_label,
     356            ),
     357            'cache-control-with-past-expires'        => array(
     358                'responses'          => array_fill(
     359                    0,
     360                    3,
     361                    array( 'expires' => gmdate( 'r', time() - MINUTE_IN_SECONDS * 10 ) )
     362                ),
     363                'expected_status'    => 'critical',
     364                'expected_label'     => $critical_label,
     365                'good_basic_auth'    => null,
     366                'delay_the_response' => true,
     367            ),
     368            'cache-control-with-basic-auth'          => array(
     369                'responses'       => array_fill(
     370                    0,
     371                    3,
     372                    array( 'cache-control' => 'public; max-age=600' )
     373                ),
     374                'expected_status' => 'good',
     375                'expected_label'  => $good_label,
     376                'good_basic_auth' => true,
     377            ),
     378            'x-cache-enabled'                        => array(
     379                'responses'       => array_fill(
     380                    0,
     381                    3,
     382                    array( 'x-cache-enabled' => 'true' )
     383                ),
     384                'expected_status' => 'good',
     385                'expected_label'  => $good_label,
     386            ),
     387            'x-cache-enabled-with-delay'             => array(
     388                'responses'          => array_fill(
     389                    0,
     390                    3,
     391                    array( 'x-cache-enabled' => 'false' )
     392                ),
     393                'expected_status'    => 'critical',
     394                'expected_label'     => $critical_label,
     395                'good_basic_auth'    => null,
     396                'delay_the_response' => true,
     397            ),
     398            'x-cache-disabled'                       => array(
     399                'responses'       => array_fill(
     400                    0,
     401                    3,
     402                    array( 'x-cache-disabled' => 'off' )
     403                ),
     404                'expected_status' => 'good',
     405                'expected_label'  => $good_label,
     406            ),
    162407        );
    163408    }
Note: See TracChangeset for help on using the changeset viewer.