diff --git a/src/ContainerClient/DockerContainerClient.php b/src/ContainerClient/DockerContainerClient.php index e308a68..a908244 100644 --- a/src/ContainerClient/DockerContainerClient.php +++ b/src/ContainerClient/DockerContainerClient.php @@ -91,12 +91,14 @@ private static function createHttpClient(): ClientInterface /** * Builds the DockerClient from the given HTTP client, using the injected factory if set. + * The server plugins are applied only to an injected HTTP client: the client from + * DockerClientFactory already adds the daemon address and the negotiated API path. */ private static function createDockerClient(ClientInterface $httpClient): DockerClient { return self::$dockerClientFactory !== null ? (self::$dockerClientFactory)($httpClient) - : DockerClient::create($httpClient); + : DockerClient::create($httpClient, [], [], self::$httpClientFactory !== null); } /** diff --git a/tests/Unit/ContainerClient/DockerContainerClientTest.php b/tests/Unit/ContainerClient/DockerContainerClientTest.php index be9a3c5..43d100c 100644 --- a/tests/Unit/ContainerClient/DockerContainerClientTest.php +++ b/tests/Unit/ContainerClient/DockerContainerClientTest.php @@ -7,8 +7,13 @@ use Docker\Docker as DockerClient; use Http\Client\Common\Plugin\HeaderDefaultsPlugin; use Http\Client\Common\PluginClient; +use Http\Client\Common\PluginClientFactory; +use Http\Client\HttpAsyncClient; +use Http\Discovery\Psr17FactoryDiscovery; use PHPUnit\Framework\TestCase; use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; use Testcontainers\ContainerClient\DockerContainerClient; /** @@ -247,6 +252,48 @@ public function testHeaderDefaultsPluginIsConfiguredWithUserAgentHeader(): void ); } + // ------------------------------------------------------------------------- + // API version path of the default client + // ------------------------------------------------------------------------- + + public function testDefaultClientUsesNegotiatedApiVersionPathOnce(): void + { + // A daemon whose maximum API version is below the installed docker-php-api line, + // as Podman reports. Requests must carry only the negotiated version path. + $paths = []; + $daemon = $this->createMock(ClientInterface::class); + $daemon->method('sendRequest')->willReturnCallback( + static function (RequestInterface $request) use (&$paths): ResponseInterface { + $path = $request->getUri()->getPath(); + $paths[] = $path; + $responses = Psr17FactoryDiscovery::findResponseFactory(); + $streams = Psr17FactoryDiscovery::findStreamFactory(); + + return match ($path) { + '/_ping' => $responses->createResponse(200)->withHeader('API-Version', '1.41')->withBody($streams->createStream('OK')), + '/v1.41/info' => $responses->createResponse(200)->withBody($streams->createStream('{}')), + default => $responses->createResponse(404)->withBody($streams->createStream('404 page not found')), + }; + } + ); + + $apiVersion = getenv('DOCKER_API_VERSION'); + putenv('DOCKER_API_VERSION'); + PluginClientFactory::setFactory( + static fn (ClientInterface|HttpAsyncClient $socketClient, array $plugins): PluginClient => new PluginClient($daemon, $plugins) + ); + try { + DockerContainerClient::getDockerClient(); + } finally { + PluginClientFactory::setFactory( + static fn (ClientInterface|HttpAsyncClient $client, array $plugins): PluginClient => new PluginClient($client, $plugins) + ); + putenv($apiVersion === false ? 'DOCKER_API_VERSION' : 'DOCKER_API_VERSION=' . $apiVersion); + } + + $this->assertSame(['/_ping', '/v1.41/info'], $paths); + } + public function testUserAgentHeaderContainsUnknownWhenVersionResolutionFails(): void { // Injects no-socket factories (same pattern as above), then calls