mirror of
https://github.com/stan220/testcontainers-php.git
synced 2026-09-08 16:29:29 +00:00
Support for waiting on tcp port to open
This commit is contained in:
@@ -56,6 +56,11 @@ class Container
|
||||
return new Container($image);
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function withEntryPoint(string $entryPoint): self
|
||||
{
|
||||
$this->entryPoint = $entryPoint;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Testcontainer\Wait;
|
||||
|
||||
use JsonException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Testcontainer\Exception\ContainerNotReadyException;
|
||||
|
||||
/**
|
||||
* @phpstan-type ContainerInspect array<int, array{'NetworkSettings': array{'IPAddress': string}}>
|
||||
*/
|
||||
final class WaitForTcpPortOpen implements WaitInterface
|
||||
{
|
||||
public function __construct(private readonly int $port)
|
||||
{
|
||||
}
|
||||
|
||||
public static function make(int $port): self
|
||||
{
|
||||
return new self($port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
public function wait(string $id): void
|
||||
{
|
||||
if (@fsockopen($this->findContainerAddress($id), $this->port) === false) {
|
||||
throw new ContainerNotReadyException($id, new RuntimeException('Unable to connect to container TCP port'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function findContainerAddress(string $id): string
|
||||
{
|
||||
$process = new Process(['docker', 'inspect', $id]);
|
||||
$process->mustRun();
|
||||
|
||||
/** @var ContainerInspect $data */
|
||||
$data = json_decode($process->getOutput(), true, 512, JSON_THROW_ON_ERROR);
|
||||
|
||||
$containerAddress = $data[0]['NetworkSettings']['IPAddress'] ?? null;
|
||||
|
||||
if (! is_string($containerAddress)) {
|
||||
throw new ContainerNotReadyException($id, new RuntimeException('Unable to find container IP address'));
|
||||
}
|
||||
|
||||
return $containerAddress;
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,12 @@ use Predis\Client;
|
||||
use Predis\Connection\ConnectionException;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Testcontainer\Container\Container;
|
||||
use Testcontainer\Exception\ContainerNotReadyException;
|
||||
use Testcontainer\Wait\WaitForExec;
|
||||
use Testcontainer\Wait\WaitForHealthCheck;
|
||||
use Testcontainer\Wait\WaitForHttp;
|
||||
use Testcontainer\Wait\WaitForLog;
|
||||
use Testcontainer\Wait\WaitForTcpPortOpen;
|
||||
|
||||
class WaitStrategyTest extends TestCase
|
||||
{
|
||||
@@ -90,6 +92,42 @@ class WaitStrategyTest extends TestCase
|
||||
$this->assertNotEmpty($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideWaitForTcpPortOpen
|
||||
*/
|
||||
public function testWaitForTcpPortOpen(bool $canConnect): void
|
||||
{
|
||||
$container = Container::make('nginx:alpine');
|
||||
|
||||
if ($canConnect) {
|
||||
$container->withWait(WaitForTcpPortOpen::make(80));
|
||||
}
|
||||
|
||||
$container->run();
|
||||
|
||||
if ($canConnect) {
|
||||
static::assertIsResource(fsockopen($container->getAddress(), 80), 'Failed to connect to container');
|
||||
return;
|
||||
}
|
||||
|
||||
$containerId = $container->getId();
|
||||
|
||||
$this->expectExceptionObject(new ContainerNotReadyException($containerId));
|
||||
|
||||
(new WaitForTcpPortOpen(8080))->wait($containerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<bool>>
|
||||
*/
|
||||
public function provideWaitForTcpPortOpen(): array
|
||||
{
|
||||
return [
|
||||
'Can connect to container' => [true],
|
||||
'Cannot connect to container' => [false],
|
||||
];
|
||||
}
|
||||
|
||||
public function testWaitForHealthCheck(): void
|
||||
{
|
||||
$container = Container::make('nginx')
|
||||
|
||||
Reference in New Issue
Block a user