guzzle / guzzle

Guzzle, an extensible PHP HTTP client

Home Page:https://docs.guzzlephp.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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);
    }