Skip to content

Commit 9acdbb9

Browse files
committed
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 git-svn-id: https://develop.svn.wordpress.org/trunk@59729 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 4863a92 commit 9acdbb9

File tree

4 files changed

+148
-66
lines changed

4 files changed

+148
-66
lines changed

tests/phpunit/includes/abstract-testcase.php

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,4 +1694,119 @@ public static function touch( $file ) {
16941694

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
}

0 commit comments

Comments
 (0)