From 68b6064070eba7c2823477ddc48908b008ab25c0 Mon Sep 17 00:00:00 2001 From: Sergei Shitikov Date: Sat, 24 May 2025 22:48:18 +0200 Subject: [PATCH] - Added support for dynamic port for WaitForHttp.php - Tmp fix for getBoundPorts() strange fails on the latest Docker releases. --- src/Container/StartedGenericContainer.php | 7 ++++++ src/Wait/WaitForHttp.php | 26 +++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Container/StartedGenericContainer.php b/src/Container/StartedGenericContainer.php index d3a8194..4bf7907 100644 --- a/src/Container/StartedGenericContainer.php +++ b/src/Container/StartedGenericContainer.php @@ -198,6 +198,13 @@ protected function inspect(): ContainersIdJsonGetResponse200 | null */ public function getBoundPorts(): iterable { + /** + * For some reason, in the latest Docker releases, at this moment, the container might not be fully started. + * This can lead to issues when trying to retrieve the ports. + * TODO: find a better strategy to ensure the container is fully started or run in a loop until it is ready. + * For the loop $this->inspect() shouldn't be cached. + */ + usleep(300 * 1000); $ports = $this->inspect()?->getNetworkSettings()?->getPorts(); if ($ports === null) { diff --git a/src/Wait/WaitForHttp.php b/src/Wait/WaitForHttp.php index b2dceeb..855c55f 100644 --- a/src/Wait/WaitForHttp.php +++ b/src/Wait/WaitForHttp.php @@ -31,7 +31,7 @@ class WaitForHttp extends BaseWaitStrategy protected int $readTimeout = 1000; public function __construct( - protected int $port, + protected ?int $port = null, int $timeout = 10000, int $pollInterval = 500 ) { @@ -100,13 +100,18 @@ public function wait(StartedTestContainer $container): void throw new ContainerWaitingTimeoutException($container->getId()); } - $containerAddress = $container->getHost(); + try { + $this->resolvePort($container); + $containerAddress = $container->getHost(); - $url = sprintf('%s://%s:%d%s', $this->protocol, $containerAddress, $this->port, $this->path); - $responseCode = $this->makeHttpRequest($url); + $url = sprintf('%s://%s:%d%s', $this->protocol, $containerAddress, $this->port, $this->path); + $responseCode = $this->makeHttpRequest($url); - if ($responseCode === $this->expectedStatusCode) { - return; // Container is ready + if ($responseCode === $this->expectedStatusCode) { + return; // Container is ready + } + } catch (\RuntimeException) { + // Port resolution or HTTP request failed, we'll try again until timeout } usleep($this->pollInterval * 1000); @@ -120,7 +125,7 @@ private function makeHttpRequest(string $url): int curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->method->value); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); - curl_setopt($ch, CURLOPT_NOBODY, true); // No need for response body, just headers + curl_setopt($ch, CURLOPT_NOBODY, true); // No need for a response body, just headers curl_setopt($ch, CURLOPT_TIMEOUT_MS, $this->readTimeout); // Allow insecure connections if requested @@ -139,4 +144,11 @@ private function makeHttpRequest(string $url): int return $responseCode; } + + private function resolvePort(StartedTestContainer $container): void + { + if ($this->port === null) { + $this->port = $container->getFirstMappedPort(); + } + } }