Make WordPress Core


Ignore:
Timestamp:
01/29/2025 06:17:34 PM (3 months ago)
Author:
johnbillion
Message:

Build/Test Tools: Add a retry mechanism for tests that perform external HTTP requests.

While the skipTestOnTimeout() method will catch a timeout and prevent it from causing a test to fail, other errors such as a failed DNS lookup or HTTPS handshake can still cause a test to unnecessarily fail. This introduces a simple retry mechanism that will hopefully further reduce the flakiness of tests that perform HTTP API requests.

Fixes #62830

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/includes/abstract-testcase.php

    r59057 r59729  
    16951695        touch( $file );
    16961696    }
     1697
     1698    /**
     1699     * Wrapper for `wp_safe_remote_request()` that retries on error and skips the test on timeout.
     1700     *
     1701     * @param string $url  URL to retrieve.
     1702     * @param array  $args Optional. Request arguments. Default empty array.
     1703     * @return array|WP_Error The response or WP_Error on failure.
     1704     */
     1705    protected function wp_safe_remote_request( $url, $args = array() ) {
     1706        return self::retry_on_error( 'wp_safe_remote_request', $url, $args );
     1707    }
     1708
     1709    /**
     1710     * Wrapper for `wp_safe_remote_get()` that retries on error and skips the test on timeout.
     1711     *
     1712     * @param string $url  URL to retrieve.
     1713     * @param array  $args Optional. Request arguments. Default empty array.
     1714     * @return array|WP_Error The response or WP_Error on failure.
     1715     */
     1716    protected function wp_safe_remote_get( $url, $args = array() ) {
     1717        return self::retry_on_error( 'wp_safe_remote_get', $url, $args );
     1718    }
     1719
     1720    /**
     1721     * Wrapper for `wp_safe_remote_post()` that retries on error and skips the test on timeout.
     1722     *
     1723     * @param string $url  URL to retrieve.
     1724     * @param array  $args Optional. Request arguments. Default empty array.
     1725     * @return array|WP_Error The response or WP_Error on failure.
     1726     */
     1727    protected function wp_safe_remote_post( $url, $args = array() ) {
     1728        return self::retry_on_error( 'wp_safe_remote_post', $url, $args );
     1729    }
     1730
     1731    /**
     1732     * Wrapper for `wp_safe_remote_head()` that retries on error and skips the test on timeout.
     1733     *
     1734     * @param string $url  URL to retrieve.
     1735     * @param array  $args Optional. Request arguments. Default empty array.
     1736     * @return array|WP_Error The response or WP_Error on failure.
     1737     */
     1738    protected function wp_safe_remote_head( $url, $args = array() ) {
     1739        return self::retry_on_error( 'wp_safe_remote_head', $url, $args );
     1740    }
     1741
     1742    /**
     1743     * Wrapper for `wp_remote_request()` that retries on error and skips the test on timeout.
     1744     *
     1745     * @param string $url  URL to retrieve.
     1746     * @param array  $args Optional. Request arguments. Default empty array.
     1747     * @return array|WP_Error The response or WP_Error on failure.
     1748     */
     1749    protected function wp_remote_request( $url, $args = array() ) {
     1750        return self::retry_on_error( 'wp_remote_request', $url, $args );
     1751    }
     1752
     1753    /**
     1754     * Wrapper for `wp_remote_get()` that retries on error and skips the test on timeout.
     1755     *
     1756     * @param string $url  URL to retrieve.
     1757     * @param array  $args Optional. Request arguments. Default empty array.
     1758     * @return array|WP_Error The response or WP_Error on failure.
     1759     */
     1760    protected function wp_remote_get( $url, $args = array() ) {
     1761        return self::retry_on_error( 'wp_remote_get', $url, $args );
     1762    }
     1763
     1764    /**
     1765     * Wrapper for `wp_remote_post()` that retries on error and skips the test on timeout.
     1766     *
     1767     * @param string $url  URL to retrieve.
     1768     * @param array  $args Optional. Request arguments. Default empty array.
     1769     * @return array|WP_Error The response or WP_Error on failure.
     1770     */
     1771    protected function wp_remote_post( $url, $args = array() ) {
     1772        return self::retry_on_error( 'wp_remote_post', $url, $args );
     1773    }
     1774
     1775    /**
     1776     * Wrapper for `wp_remote_head()` that retries on error and skips the test on timeout.
     1777     *
     1778     * @param string $url  URL to retrieve.
     1779     * @param array  $args Optional. Request arguments. Default empty array.
     1780     * @return array|WP_Error The response or WP_Error on failure.
     1781     */
     1782    protected function wp_remote_head( $url, $args = array() ) {
     1783        return self::retry_on_error( 'wp_remote_head', $url, $args );
     1784    }
     1785
     1786    /**
     1787     * Retries an HTTP API request up to three times and skips the test on timeout.
     1788     *
     1789     * @param callable $callback The HTTP API request function to call.
     1790     * @param string   $url      URL to retrieve.
     1791     * @param array    $args     Request arguments.
     1792     * @return array|WP_Error The response or WP_Error on failure.
     1793     */
     1794    private function retry_on_error( callable $callback, $url, $args ) {
     1795        $attempts = 0;
     1796
     1797        while ( $attempts < 3 ) {
     1798            $result = call_user_func( $callback, $url, $args );
     1799
     1800            if ( ! is_wp_error( $result ) ) {
     1801                return $result;
     1802            }
     1803
     1804            ++$attempts;
     1805            sleep( 5 );
     1806        }
     1807
     1808        $this->skipTestOnTimeout( $result );
     1809
     1810        return $result;
     1811    }
    16971812}
Note: See TracChangeset for help on using the changeset viewer.