mirror of
https://github.com/stan220/testcontainers-php.git
synced 2026-09-12 10:29:37 +00:00
fixes and improvements
This commit is contained in:
@@ -232,10 +232,12 @@ class GenericContainer implements TestContainer
|
|||||||
$this->id = $containerCreateResponse?->getId() ?? '';
|
$this->id = $containerCreateResponse?->getId() ?? '';
|
||||||
} catch (ContainerCreateNotFoundException) {
|
} catch (ContainerCreateNotFoundException) {
|
||||||
/** @var CreateImageStream $imageCreateResponse */
|
/** @var CreateImageStream $imageCreateResponse */
|
||||||
$this->dockerClient->imageCreate(null, [
|
$imageCreateResponse = $this->dockerClient->imageCreate(null, [
|
||||||
'fromImage' => explode(':', $this->image)[0],
|
'fromImage' => explode(':', $this->image)[0],
|
||||||
'tag' => explode(':', $this->image)[1] ?? 'latest',
|
'tag' => explode(':', $this->image)[1] ?? 'latest',
|
||||||
]);
|
]);
|
||||||
|
$imageCreateResponse->wait();
|
||||||
|
|
||||||
return $this->start();
|
return $this->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Testcontainers\Container;
|
namespace Testcontainers\Container;
|
||||||
|
|
||||||
use Testcontainers\Wait\WaitForLog;
|
use Testcontainers\Wait\WaitForExec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Left for namespace backward compatibility
|
* Left for namespace backward compatibility
|
||||||
@@ -17,8 +17,12 @@ class MariaDBContainer extends Container
|
|||||||
{
|
{
|
||||||
parent::__construct('mariadb:' . $version);
|
parent::__construct('mariadb:' . $version);
|
||||||
$this->withExposedPorts(3306);
|
$this->withExposedPorts(3306);
|
||||||
$this->withWait(new WaitForLog('ready for connections'));
|
|
||||||
$this->withEnvironment('MARIADB_ROOT_PASSWORD', $mysqlRootPassword);
|
$this->withEnvironment('MARIADB_ROOT_PASSWORD', $mysqlRootPassword);
|
||||||
|
$this->withWait(new WaitForExec([
|
||||||
|
"mariadb-admin",
|
||||||
|
"ping",
|
||||||
|
"-h", "127.0.0.1",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function make(string $version = 'latest', string $mysqlRootPassword = 'root'): self
|
public static function make(string $version = 'latest', string $mysqlRootPassword = 'root'): self
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Testcontainers\Container;
|
namespace Testcontainers\Container;
|
||||||
|
|
||||||
use Testcontainers\Wait\WaitForLog;
|
use Testcontainers\Wait\WaitForExec;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Left for namespace backward compatibility
|
* Left for namespace backward compatibility
|
||||||
@@ -18,7 +18,11 @@ class MySQLContainer extends Container
|
|||||||
parent::__construct('mysql:' . $version);
|
parent::__construct('mysql:' . $version);
|
||||||
$this->withExposedPorts(3306);
|
$this->withExposedPorts(3306);
|
||||||
$this->withEnvironment('MYSQL_ROOT_PASSWORD', $mysqlRootPassword);
|
$this->withEnvironment('MYSQL_ROOT_PASSWORD', $mysqlRootPassword);
|
||||||
$this->withWait(new WaitForLog('ready for connections'));
|
$this->withWait(new WaitForExec([
|
||||||
|
"mysqladmin",
|
||||||
|
"ping",
|
||||||
|
"-h", "127.0.0.1",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function make(string $version = 'latest', string $mysqlRootPassword = 'root'): self
|
public static function make(string $version = 'latest', string $mysqlRootPassword = 'root'): self
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ namespace Testcontainers\Container;
|
|||||||
|
|
||||||
use Docker\API\Client;
|
use Docker\API\Client;
|
||||||
use Docker\API\Model\ContainersIdExecPostBody;
|
use Docker\API\Model\ContainersIdExecPostBody;
|
||||||
use Docker\API\Model\ContainersIdJsonGetResponse200;
|
|
||||||
use Docker\API\Model\IdResponse;
|
use Docker\API\Model\IdResponse;
|
||||||
use Docker\API\Runtime\Client\Client as DockerRuntimeClient;
|
use Docker\API\Runtime\Client\Client as DockerRuntimeClient;
|
||||||
use Docker\Docker;
|
use Docker\Docker;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Testcontainers\ContainerClient\DockerContainerClient;
|
use Testcontainers\ContainerClient\DockerContainerClient;
|
||||||
|
|
||||||
class StartedGenericContainer implements StartedTestContainer
|
class StartedGenericContainer implements StartedTestContainer
|
||||||
@@ -108,17 +108,36 @@ class StartedGenericContainer implements StartedTestContainer
|
|||||||
return $this->inspect()->ports[$port];
|
return $this->inspect()->ports[$port];
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: not ready yet
|
/**
|
||||||
|
* @throws \JsonException
|
||||||
|
*/
|
||||||
public function getFirstMappedPort(): int
|
public function getFirstMappedPort(): int
|
||||||
{
|
{
|
||||||
/** @var ContainersIdJsonGetResponse200 | null $containerInspectResponse */
|
//For some reason, containerInspect can crash when using FETCH_OBJECT option (e.g. with OpenSearch)
|
||||||
$containerInspectResponse = $this->dockerClient->containerInspect($this->id);
|
//should be checked within beluga-php/docker-php client library
|
||||||
$settings = $containerInspectResponse->getNetworkSettings();
|
/** @var ResponseInterface | null $containerInspectResponse */
|
||||||
|
$containerInspectResponse = $this->dockerClient->containerInspect($this->id, [], Docker::FETCH_RESPONSE);
|
||||||
|
if ($containerInspectResponse === null) {
|
||||||
|
throw new \RuntimeException('Failed to inspect container');
|
||||||
|
}
|
||||||
|
|
||||||
|
$containerInspectResponseAsArray = json_decode(
|
||||||
|
$containerInspectResponse->getBody()->getContents(),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
|
||||||
|
/** @var array<string, array<array<string, string>>> $ports */
|
||||||
|
$ports = $containerInspectResponseAsArray['NetworkSettings']['Ports'] ?? [];
|
||||||
|
|
||||||
|
if ($ports === []) {
|
||||||
|
throw new \RuntimeException('Failed to get ports from container');
|
||||||
|
}
|
||||||
|
|
||||||
$ports = (array)$settings->getPorts();
|
|
||||||
$port = array_key_first($ports);
|
$port = array_key_first($ports);
|
||||||
|
|
||||||
return (int) $ports[$port][0]->getHostPort();
|
return (int) $ports[$port][0]['HostPort'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace Testcontainers\ContainerClient;
|
namespace Testcontainers\ContainerClient;
|
||||||
|
|
||||||
use Docker\Docker as DockerClient;
|
use Docker\Docker as DockerClient;
|
||||||
@@ -11,9 +13,6 @@ class DockerContainerClient
|
|||||||
*/
|
*/
|
||||||
private static ?DockerClient $dockerClient = null;
|
private static ?DockerClient $dockerClient = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Private constructor to prevent creating instance outside the class.
|
|
||||||
*/
|
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Testcontainers\Modules;
|
namespace Testcontainers\Modules;
|
||||||
|
|
||||||
use Testcontainers\Container\GenericContainer;
|
use Testcontainers\Container\GenericContainer;
|
||||||
use Testcontainers\Wait\WaitForLog;
|
use Testcontainers\Wait\WaitForExec;
|
||||||
|
|
||||||
class MariaDBContainer extends GenericContainer
|
class MariaDBContainer extends GenericContainer
|
||||||
{
|
{
|
||||||
@@ -13,8 +13,12 @@ class MariaDBContainer extends GenericContainer
|
|||||||
{
|
{
|
||||||
parent::__construct('mariadb:' . $version);
|
parent::__construct('mariadb:' . $version);
|
||||||
$this->withExposedPorts(3306);
|
$this->withExposedPorts(3306);
|
||||||
$this->withWait(new WaitForLog('ready for connections'));
|
|
||||||
$this->withEnvironment('MARIADB_ROOT_PASSWORD', $mysqlRootPassword);
|
$this->withEnvironment('MARIADB_ROOT_PASSWORD', $mysqlRootPassword);
|
||||||
|
$this->withWait(new WaitForExec([
|
||||||
|
"mariadb-admin",
|
||||||
|
"ping",
|
||||||
|
"-h", "127.0.0.1",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withMariaDBUser(string $username, string $password): self
|
public function withMariaDBUser(string $username, string $password): self
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace Testcontainers\Modules;
|
namespace Testcontainers\Modules;
|
||||||
|
|
||||||
use Testcontainers\Container\GenericContainer;
|
use Testcontainers\Container\GenericContainer;
|
||||||
use Testcontainers\Wait\WaitForLog;
|
use Testcontainers\Wait\WaitForExec;
|
||||||
|
|
||||||
class MySQLContainer extends GenericContainer
|
class MySQLContainer extends GenericContainer
|
||||||
{
|
{
|
||||||
@@ -14,7 +14,11 @@ class MySQLContainer extends GenericContainer
|
|||||||
parent::__construct('mysql:' . $version);
|
parent::__construct('mysql:' . $version);
|
||||||
$this->withExposedPorts(3306);
|
$this->withExposedPorts(3306);
|
||||||
$this->withEnvironment('MYSQL_ROOT_PASSWORD', $mysqlRootPassword);
|
$this->withEnvironment('MYSQL_ROOT_PASSWORD', $mysqlRootPassword);
|
||||||
$this->withWait(new WaitForLog('ready for connections'));
|
$this->withWait(new WaitForExec([
|
||||||
|
"mysqladmin",
|
||||||
|
"ping",
|
||||||
|
"-h", "127.0.0.1",
|
||||||
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withMySQLUser(string $username, string $password): self
|
public function withMySQLUser(string $username, string $password): self
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use Testcontainers\Container\StartedTestContainer;
|
|||||||
|
|
||||||
abstract class BaseWaitStrategy implements WaitStrategy
|
abstract class BaseWaitStrategy implements WaitStrategy
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(protected int $timeout = 10000, protected int $pollInterval = 500)
|
public function __construct(protected int $timeout = 10000, protected int $pollInterval = 500)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ declare(strict_types=1);
|
|||||||
namespace Testcontainers\Wait;
|
namespace Testcontainers\Wait;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
use Docker\API\Model\ContainersIdExecPostBody;
|
|
||||||
use Docker\API\Model\ExecIdJsonGetResponse200;
|
use Docker\API\Model\ExecIdJsonGetResponse200;
|
||||||
use Testcontainers\Container\StartedTestContainer;
|
use Testcontainers\Container\StartedTestContainer;
|
||||||
use Testcontainers\Exception\ContainerWaitingTimeoutException;
|
use Testcontainers\Exception\ContainerWaitingTimeoutException;
|
||||||
@@ -15,8 +14,6 @@ use Testcontainers\Exception\ContainerWaitingTimeoutException;
|
|||||||
*/
|
*/
|
||||||
class WaitForExec extends BaseWaitStrategy
|
class WaitForExec extends BaseWaitStrategy
|
||||||
{
|
{
|
||||||
protected ContainersIdExecPostBody $execConfig;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string> $command
|
* @param array<string> $command
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use Http\Client\Socket\Exception\TimeoutException;
|
|||||||
use Testcontainers\Container\StartedTestContainer;
|
use Testcontainers\Container\StartedTestContainer;
|
||||||
use Testcontainers\Exception\ContainerNotReadyException;
|
use Testcontainers\Exception\ContainerNotReadyException;
|
||||||
|
|
||||||
|
//TODO: not ready yet
|
||||||
class WaitForHealthCheck extends BaseWaitStrategy
|
class WaitForHealthCheck extends BaseWaitStrategy
|
||||||
{
|
{
|
||||||
public function __construct(protected int $timeout = 5000, protected int $pollInterval = 1000)
|
public function __construct(protected int $timeout = 5000, protected int $pollInterval = 1000)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Testcontainers\Wait;
|
|||||||
use Docker\Docker;
|
use Docker\Docker;
|
||||||
use Testcontainers\Exception\ContainerNotReadyException;
|
use Testcontainers\Exception\ContainerNotReadyException;
|
||||||
|
|
||||||
|
//TODO: not ready yet
|
||||||
class WaitForHttp implements WaitStrategy
|
class WaitForHttp implements WaitStrategy
|
||||||
{
|
{
|
||||||
public const METHOD_GET = 'GET';
|
public const METHOD_GET = 'GET';
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use JsonException;
|
|||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Testcontainers\Exception\ContainerNotReadyException;
|
use Testcontainers\Exception\ContainerNotReadyException;
|
||||||
|
|
||||||
|
//TODO: not ready yet
|
||||||
final class WaitForTcpPortOpen implements WaitStrategy
|
final class WaitForTcpPortOpen implements WaitStrategy
|
||||||
{
|
{
|
||||||
private Docker $dockerClient;
|
private Docker $dockerClient;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use Testcontainers\Container\RedisContainer;
|
|||||||
class ContainerTest extends TestCase
|
class ContainerTest extends TestCase
|
||||||
{
|
{
|
||||||
//TODO: remove after check
|
//TODO: remove after check
|
||||||
|
//To make it work, fixed port should be first implemented
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete();
|
$this->markTestIncomplete();
|
||||||
|
|||||||
Reference in New Issue
Block a user