Fix WaitForLog implementation

This commit is contained in:
Sergei Shitikov
2024-09-01 15:18:05 +02:00
parent 5ee4fdc804
commit de66ea607c
3 changed files with 55 additions and 13 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ class RedisContainer extends GenericContainer
{ {
parent::__construct('redis:' . $version); parent::__construct('redis:' . $version);
$this->withExposedPorts(6379); $this->withExposedPorts(6379);
//$this->withWait(new WaitForLog('Ready to accept connections')); $this->withWait(new WaitForLog('Ready to accept connections'));
} }
/** /**
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Testcontainers\Exception;
class ContainerWaitingTimeoutException extends \RuntimeException
{
protected string $containerId;
public function __construct(string $containerId, ?string $message = null, ?\Throwable $previous = null)
{
$this->containerId = $containerId;
$message ??= sprintf('Timeout reached while waiting for container %s', $containerId);
parent::__construct($message, 0, $previous);
}
public function getContainerId(): string
{
return $this->containerId;
}
}
+31 -11
View File
@@ -4,33 +4,53 @@ declare(strict_types=1);
namespace Testcontainers\Wait; namespace Testcontainers\Wait;
use Docker\API\Runtime\Client\Client;
use Docker\Docker; use Docker\Docker;
use Symfony\Component\Process\Process; use Testcontainers\Exception\ContainerWaitingTimeoutException;
use Testcontainers\Exception\ContainerNotReadyException;
/**
* Uses $timout and $pollInterval in milliseconds to set the parameters for waiting.
*/
class WaitForLog implements WaitInterface class WaitForLog implements WaitInterface
{ {
protected Docker $dockerClient; protected Docker $dockerClient;
public function __construct(private string $message, private bool $enableRegex = false) public function __construct(
{ protected string $message,
protected bool $enableRegex = false,
protected int $timeout = 10000,
protected int $pollInterval = 500
) {
$this->dockerClient = Docker::create(); $this->dockerClient = Docker::create();
} }
public function wait(string $id): void public function wait(string $id): void
{ {
$logs = $this->dockerClient->containerLogs($id); $startTime = microtime(true) * 1000;
$output = $logs->getBody()->getContents(); while (true) {
$elapsedTime = (microtime(true) * 1000) - $startTime;
if ($elapsedTime > $this->timeout) {
throw new ContainerWaitingTimeoutException($id);
}
$output = $this->dockerClient
->containerLogs($id, ['stdout' => true, 'stderr' => true], Client::FETCH_RESPONSE)
?->getBody()
->getContents() ?? '';
$output = preg_replace('/[\x00-\x1F\x7F]/u', '', mb_convert_encoding($output, 'UTF-8', 'UTF-8')) ?? '';
if ($this->enableRegex) { if ($this->enableRegex) {
if (!preg_match($this->message, $output)) { if (preg_match($this->message, $output)) {
throw new ContainerNotReadyException($id, new \RuntimeException('Message not found in logs')); return;
} }
} else { } elseif (str_contains($output, $this->message)) {
if (!str_contains($output, $this->message)) { return;
throw new ContainerNotReadyException($id, new \RuntimeException('Message not found in logs'));
} }
usleep($this->pollInterval * 1000);
} }
} }
} }