Problem con Guzzle (ConnectException) in phpunit --testsuite
NeftaliAcosta opened this issue · comments
Guzzle version(s) affected: ^7.5
PHP version: 8.1.18
cURL version:7.81.0 (hint: php -i | grep cURL
)
Description
I am making an API using slim framework, I am using Guzzle to run my unit tests, however, there has come a time when with a number of specific folders my unit tests fail (Always the last ones) it seems that Guzzle reached a limited number of requests and then the error occurs:
GuzzleHttp\Exception\ConnectException: cURL error 6: getaddrinfo() thread failed to start (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)
How to reproduce
-
Test suite configuration in composer.json:
"./vendor/bin/phpunit --testsuite Api --testdox"
-
Structure Unit Tests
-
Error:
Possible Solution
If I separate my tests into two folders and run the command from both folders they run correctly, but I don't think it's the right thing to do.:
vendor/bin/phpunit ./tests/Application/Actions/ --testdox;vendor/bin/phpunit ./tests/Application/Actions2/ --testdox;
Could you help me identify the problem and request it please?
Thank you.
*Aditional
Test suite points to the "test" folder and automatically runs all tests..
<?xml version="1.0"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
beStrictAboutTestsThatDoNotTestAnything="true"
beStrictAboutChangesToGlobalState="true"
beStrictAboutOutputDuringTests="true"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="true"
bootstrap="vendor/autoload.php"
>
<coverage processUncoveredFiles="true">
<include>
<!-- <directory suffix=".php">./src/Application/Actions</directory> -->
<directory suffix=".php">./App/Models</directory>
</include>
</coverage>
<testsuites>
<testsuite name="Test">
<directory>./tests/Models/</directory>
<directory>./tests/Application/</directory>
</testsuite>
<testsuite name="Models">
<directory>./tests/Models/</directory>
</testsuite>
<testsuite name="Api">
<directory>./tests/Application/</directory>
</testsuite>
<testsuite name="Emails">
<directory>./tests/Emails/</directory>
</testsuite>
<testsuite name="Sms">
<directory>./tests/Sms/</directory>
</testsuite>
</testsuites>
<php>
<env name="APP_ENV" value="dev"/>
<env name="DB_NAME" value="crm_test"/>
<env name="DB_HOST" value="localhost"/>
<env name="DB_PORT" value="3306"/>
<env name="DB_USER" value="root"/>
<env name="DB_PASS" value=""/>
<env name="TOOL_KEY" value="xxxxxxx"/>
</php>
</phpunit>
If I currently delete a folder that contains some tests, for example the "Enums" folder the tests run without any problem without needing to separate them into two folders.
Are you making a new Guzzle client over and over again, and leaving the connections open? Likely you are hitting OS limits on your process.
@GrahamCampbell Yes, I share the example of a unit test file.
<?php
namespace Tests\Application\Actions\User;
use App\Core\Fields;
use App\Core\Tables;
use App\Libs\Random;
use App\Libs\Tools;
use App\Models\Users\Users;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use Tests\TestCase;
class UpdateUserActionTest extends TestCase
{
/**
* @var Client
*/
private Client $client;
/**
* @var string
*/
private string $token;
/**
* @var int
*/
private int $id;
/**
* @var string
*/
private string $id_encrypt;
/**
* @var string
*/
private string $alias_table;
/**
* Setup Values
*
* @throws Exception
*/
public function setUp(): void
{
$this->client = new Client(['base_uri' => Tools::getDomain()]);
// Get JWT
$tmp_data = Tools::jwtGenToken();
$this->token = $tmp_data['token'];
// Instance of Configuration model to get alias table.
$user = new Users();
// Set alias table to local variable.
$this->alias_table = $user->getAliasTable();
// Get id parameter configuration demo
$this->id = Tools::getRandomId(Tables::get($this->alias_table));
$this->id_encrypt = Tools::myEncrypt((string)$this->id);
}
/**
* Test Action
*
* @throws Exception
* @throws GuzzleException
*/
public function testAction()
{
// Prepare headers to request
$headers = [
'Authorization' => 'Bearer ' . $this->token,
'Accept' => 'application/json',
];
// Making the API request
$uri = '/users/' . $this->id_encrypt;
$response = $this->client->request('PUT', $uri, [
'headers' => []
'json' => []
]);
// Get data response
$data = json_decode($response->getBody()->getContents(), true);
// Test response
$this->assertIsArray($data, 'data');
$this->assertEquals(200, $response->getStatusCode());
}
/**
* Test Parameter Not Found
*
* @return void
* @throws GuzzleException
*/
public function testActionNotUpdate(): void
{
$this->expectException(ClientException::class);
// Making the API request
$uri = '/users/' . $this->id_encrypt;
$response = $this->client->request('PUT', $uri, [
'headers' => []
'json' => []
]);
// Get data response
$data = json_decode($response->getBody()->getContents(), true);
// Test response
$this->assertIsArray($data, 'data');
$this->assertEquals(200, $response->getStatusCode());
}
/**
* Test Unauthorized
*
* @throws GuzzleException
* @throws Exception
*/
public function testUnauthorized(): void
{
try {
// Generate fake token
$token = Random::randomText();
// Making the API request
$this->o_client->request('GET', '/users/' ' . $this->id_encrypt, [
'headers' => $headers
]);
} catch (ClientException $e) {
// Test response
$this->assertEquals(401, $e->getCode());
}
}
}
That is the root cause of your issues. You need to re-use the client instance with each test.
Your setup method is called before every single test, consuming all your available sockets.
Thank you very much, I have solved it implement this method.
/**
* @return void
*/
protected function tearDown(): void
{
unset($this->o_client);
}