Description
Preconditions (*)
- Magento 2.3.2, just created project, no setup:install
- PHP 7.2.19
Steps to reproduce (*)
- Create Magento 2.3.2 project
- Run unit tests (at least \Magento\Downloadable\Test\Unit\Helper\DownloadTest) without internet connection
Expected result (*)
- Test should pass (image below shows test execution with internet connection):
Actual result (*)
- Test fails with message (image below shows test execution without internet connection):
PHPUnit\Framework\Exception: Warning: get_headers(): php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known in /Users/adrianmartinez/Sites/2.3/magento/vendor/magento/module-downloadable/Helper/Download.php:264.
Extended description
This behaviour cannot be reproduced in 2.2.8, test passes even if there is no internet connection. Comparing code both versions, I've seen this snippet of code has been added in new version of tested class \Magento\Downloadable\Helper\Download
:
public function setResource($resourceFile, $linkType = self::LINK_TYPE_FILE)
{
(...)
/**
* check header for urls
*/
if ($linkType === self::LINK_TYPE_URL) {
$headers = array_change_key_case(get_headers($this->_resourceFile, 1), CASE_LOWER);
if (isset($headers['location'])) {
$this->_resourceFile = is_array($headers['location']) ? current($headers['location'])
: $headers['location'];
}
}
(...)
}
This new code looks quite risky and not safe, I mean, even if problem is the test not passing, this piece of code has some assumptions that can break execution at any time.
First of all, test relies on a test url: \Magento\Downloadable\Test\Unit\Helper\DownloadTest::URL = 'http://example.com'
, that may exist or not, or could be down at any time. This means this test could even fail with internet connection if that site is down or DNS servers are not available.
In second place, it tries to extract headers using get_headers
php built-in function, and passes the result directly to array_change_key_case
, without any kind of check. get_headers
may emit a warning if it is not able to get header of supplied url, but even if silenced with @get_headers
, execution throws another warning due to get_headers
returning false instead of an array, and array_change_key_case
complaining about receiving a boolean parameter instead of an array:
1) Magento\Downloadable\Test\Unit\Helper\DownloadTest::testGetFileSizeUrl
PHPUnit\Framework\Exception: Warning: array_change_key_case() expects parameter 1 to be array, boolean given in /Users/adrianmartinez/Sites/2.3/magento/vendor/magento/module-downloadable/Helper/Download.php:264.
I think that piece of code should be refactored through a HeadersResolver (or another more appropriate name), responsible of returning always a consistent return value when requested for some headers (always return an array), and use this new class in \Magento\Downloadable\Helper\Download, so it can be mocked for testing.