mirror of
https://github.com/stan220/testcontainers-php.git
synced 2026-09-08 17: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);
|
return new Container($image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getId(): string
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
public function withEntryPoint(string $entryPoint): self
|
public function withEntryPoint(string $entryPoint): self
|
||||||
{
|
{
|
||||||
$this->entryPoint = $entryPoint;
|
$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 Predis\Connection\ConnectionException;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
use Testcontainer\Container\Container;
|
use Testcontainer\Container\Container;
|
||||||
|
use Testcontainer\Exception\ContainerNotReadyException;
|
||||||
use Testcontainer\Wait\WaitForExec;
|
use Testcontainer\Wait\WaitForExec;
|
||||||
use Testcontainer\Wait\WaitForHealthCheck;
|
use Testcontainer\Wait\WaitForHealthCheck;
|
||||||
use Testcontainer\Wait\WaitForHttp;
|
use Testcontainer\Wait\WaitForHttp;
|
||||||
use Testcontainer\Wait\WaitForLog;
|
use Testcontainer\Wait\WaitForLog;
|
||||||
|
use Testcontainer\Wait\WaitForTcpPortOpen;
|
||||||
|
|
||||||
class WaitStrategyTest extends TestCase
|
class WaitStrategyTest extends TestCase
|
||||||
{
|
{
|
||||||
@@ -90,6 +92,42 @@ class WaitStrategyTest extends TestCase
|
|||||||
$this->assertNotEmpty($response);
|
$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
|
public function testWaitForHealthCheck(): void
|
||||||
{
|
{
|
||||||
$container = Container::make('nginx')
|
$container = Container::make('nginx')
|
||||||
|
|||||||
Reference in New Issue
Block a user