mirror of
https://github.com/stan220/testcontainers-php.git
synced 2026-09-08 16:29:29 +00:00
Merge pull request #30 from testcontainers/fix-linux-builds
fix: update tar command for macOS compatibility and clean up workflow
This commit is contained in:
@@ -5,8 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -43,6 +43,7 @@ use Testcontainers\Wait\WaitForExec;
|
||||
use Testcontainers\Wait\WaitForLog;
|
||||
use Testcontainers\Wait\WaitForHttp;
|
||||
use Testcontainers\Wait\WaitForHealthCheck;
|
||||
use Testcontainers\Wait\WaitForHostPort;
|
||||
|
||||
$container = new GenericContainer('nginx:alpine');
|
||||
|
||||
@@ -58,7 +59,10 @@ $container->withWait(new WaitForLog('Ready to accept connections'));
|
||||
|
||||
|
||||
// Wait for an http request to succeed
|
||||
$container->withWait(WaitForHttp::make($port, $method = 'GET', $path = '/'));
|
||||
$container->withWait(new WaitForHttp($port, $method = 'GET', $path = '/'));
|
||||
|
||||
// Wait for all bound ports to be open
|
||||
$container->withWait(new WaitForHostPort());
|
||||
|
||||
// Wait until the docker heartcheck is green
|
||||
$container->withWait(new WaitForHealthCheck());
|
||||
|
||||
@@ -108,7 +108,7 @@ class StartedGenericContainer implements StartedTestContainer
|
||||
|
||||
public function getMappedPort(int $port): int
|
||||
{
|
||||
$ports = (array) $this->ports();
|
||||
$ports = (array) $this->getBoundPorts();
|
||||
/** @var PortBinding | null $portBinding */
|
||||
$portBinding = $ports["{$port}/tcp"][0] ?? null;
|
||||
$mappedPort = $portBinding?->getHostPort();
|
||||
@@ -121,7 +121,7 @@ class StartedGenericContainer implements StartedTestContainer
|
||||
|
||||
public function getFirstMappedPort(): int
|
||||
{
|
||||
$ports = (array) $this->ports();
|
||||
$ports = (array) $this->getBoundPorts();
|
||||
$port = array_key_first($ports);
|
||||
/** @var PortBinding | null $firstPortBinding */
|
||||
$firstPortBinding = $ports[$port][0] ?? null;
|
||||
@@ -193,10 +193,10 @@ class StartedGenericContainer implements StartedTestContainer
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<PortBinding>>
|
||||
* @return iterable<string, array<PortBinding>>
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function ports(): iterable
|
||||
public function getBoundPorts(): iterable
|
||||
{
|
||||
$ports = $this->inspect()?->getNetworkSettings()?->getPorts();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Testcontainers\Container;
|
||||
|
||||
use Docker\API\Model\PortBinding;
|
||||
use Docker\Docker;
|
||||
|
||||
interface StartedTestContainer
|
||||
@@ -13,6 +14,11 @@ interface StartedTestContainer
|
||||
*/
|
||||
public function exec(array $command): string;
|
||||
|
||||
/**
|
||||
* @return iterable<string, array<PortBinding>>
|
||||
*/
|
||||
public function getBoundPorts(): iterable;
|
||||
|
||||
public function getClient(): Docker;
|
||||
|
||||
public function getFirstMappedPort(): int;
|
||||
|
||||
@@ -18,7 +18,7 @@ class MariaDBContainer extends GenericContainer
|
||||
"mariadb-admin",
|
||||
"ping",
|
||||
"-h", "127.0.0.1",
|
||||
]));
|
||||
], null, 15000));
|
||||
}
|
||||
|
||||
public function withMariaDBUser(string $username, string $password): self
|
||||
|
||||
@@ -18,7 +18,7 @@ class MySQLContainer extends GenericContainer
|
||||
"mysqladmin",
|
||||
"ping",
|
||||
"-h", "127.0.0.1",
|
||||
]));
|
||||
], null, 15000));
|
||||
}
|
||||
|
||||
public function withMySQLUser(string $username, string $password): self
|
||||
|
||||
@@ -136,9 +136,16 @@ class TarBuilder
|
||||
|
||||
private function runTarCommand(string $tarFilePath, string $sourceDir): void
|
||||
{
|
||||
if (PHP_OS_FAMILY === 'Darwin') {
|
||||
$additionalFlags = ' --disable-copyfile --no-xattrs';
|
||||
} else {
|
||||
$additionalFlags = '';
|
||||
}
|
||||
|
||||
// without --disable-copyfile and --no-xattrs combination, tar will fail on macOS
|
||||
$cmd = sprintf(
|
||||
'tar --no-xattrs --disable-copyfile -cf %s -C %s . 2>&1',
|
||||
'tar %s -cf %s -C %s . 2>&1',
|
||||
$additionalFlags,
|
||||
escapeshellarg($tarFilePath),
|
||||
escapeshellarg($sourceDir)
|
||||
);
|
||||
|
||||
@@ -9,18 +9,9 @@ use Testcontainers\Exception\ContainerWaitingTimeoutException;
|
||||
|
||||
class WaitForHostPort extends BaseWaitStrategy
|
||||
{
|
||||
public function __construct(
|
||||
protected int $port,
|
||||
int $timeout = 10000,
|
||||
int $pollInterval = 500
|
||||
) {
|
||||
parent::__construct($timeout, $pollInterval);
|
||||
}
|
||||
|
||||
public function wait(StartedTestContainer $container): void
|
||||
{
|
||||
$startTime = microtime(true) * 1000;
|
||||
$containerAddress = $container->getHost();
|
||||
|
||||
while (true) {
|
||||
$elapsedTime = (microtime(true) * 1000) - $startTime;
|
||||
@@ -29,7 +20,7 @@ class WaitForHostPort extends BaseWaitStrategy
|
||||
throw new ContainerWaitingTimeoutException($container->getId());
|
||||
}
|
||||
|
||||
if ($this->isPortOpen($containerAddress, $this->port)) {
|
||||
if ($this->boundPortsOpened($container)) {
|
||||
return; // Port is open, container is ready
|
||||
}
|
||||
|
||||
@@ -37,6 +28,28 @@ class WaitForHostPort extends BaseWaitStrategy
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StartedTestContainer $container
|
||||
* @return bool
|
||||
*/
|
||||
private function boundPortsOpened(StartedTestContainer $container): bool
|
||||
{
|
||||
$boundPorts = $container->getBoundPorts();
|
||||
foreach ($boundPorts as $bindings) {
|
||||
foreach ($bindings as $binding) {
|
||||
$hostIp = trim($binding->getHostIp() ?? '');
|
||||
if ($hostIp === '' || $hostIp === '0.0.0.0') {
|
||||
$hostIp = $container->getHost();
|
||||
}
|
||||
$hostPort = (int)$binding->getHostPort();
|
||||
if (!$this->isPortOpen($hostIp, $hostPort)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isPortOpen(string $ipAddress, int $port): bool
|
||||
{
|
||||
$connection = @fsockopen($ipAddress, $port, $errno, $errstr, 2);
|
||||
|
||||
@@ -38,16 +38,6 @@ class WaitForHttp extends BaseWaitStrategy
|
||||
parent::__construct($timeout, $pollInterval);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use constructor instead
|
||||
* Kept for backward compatibility
|
||||
* Should be removed in next major version
|
||||
*/
|
||||
public static function make(int $port): self
|
||||
{
|
||||
return new self($port);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HttpMethod|value-of<HttpMethod> $method
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,6 @@ namespace Testcontainers\Tests\Integration;
|
||||
use Docker\API\Model\ContainersIdJsonGetResponse200;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Testcontainers\Container\GenericContainer;
|
||||
use Testcontainers\Utils\PortGenerator\FixedPortGenerator;
|
||||
use Testcontainers\Wait\WaitForHostPort;
|
||||
|
||||
class GenericContainerTest extends TestCase
|
||||
@@ -114,14 +113,13 @@ class GenericContainerTest extends TestCase
|
||||
|
||||
public function testShouldReturnFirstMappedPort(): void
|
||||
{
|
||||
$container = (new GenericContainer('cristianrgreco/testcontainer:1.1.14'))
|
||||
->withPortGenerator(new FixedPortGenerator([8080]))
|
||||
->withExposedPorts(8080)
|
||||
->withWait(new WaitForHostPort(8080))
|
||||
$container = (new GenericContainer('nginx'))
|
||||
->withExposedPorts(80)
|
||||
->withWait(new WaitForHostPort())
|
||||
->start();
|
||||
$firstMappedPort = $container->getFirstMappedPort();
|
||||
|
||||
self::assertSame($firstMappedPort, 8080, 'First mapped port does not match 8080');
|
||||
self::assertSame($firstMappedPort, $container->getMappedPort(80));
|
||||
|
||||
$container->stop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user