fixes and improvements

This commit is contained in:
Sergei Shitikov
2024-09-08 19:04:15 +02:00
parent aa2c1eb900
commit 357887542f
15 changed files with 140 additions and 104 deletions
+3 -1
View File
@@ -232,10 +232,12 @@ class GenericContainer implements TestContainer
$this->id = $containerCreateResponse?->getId() ?? '';
} catch (ContainerCreateNotFoundException) {
/** @var CreateImageStream $imageCreateResponse */
$this->dockerClient->imageCreate(null, [
$imageCreateResponse = $this->dockerClient->imageCreate(null, [
'fromImage' => explode(':', $this->image)[0],
'tag' => explode(':', $this->image)[1] ?? 'latest',
]);
$imageCreateResponse->wait();
return $this->start();
}
+6 -2
View File
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Testcontainers\Container;
use Testcontainers\Wait\WaitForLog;
use Testcontainers\Wait\WaitForExec;
/**
* Left for namespace backward compatibility
@@ -17,8 +17,12 @@ class MariaDBContainer extends Container
{
parent::__construct('mariadb:' . $version);
$this->withExposedPorts(3306);
$this->withWait(new WaitForLog('ready for connections'));
$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
+6 -2
View File
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Testcontainers\Container;
use Testcontainers\Wait\WaitForLog;
use Testcontainers\Wait\WaitForExec;
/**
* Left for namespace backward compatibility
@@ -18,7 +18,11 @@ class MySQLContainer extends Container
parent::__construct('mysql:' . $version);
$this->withExposedPorts(3306);
$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
+27 -8
View File
@@ -6,10 +6,10 @@ namespace Testcontainers\Container;
use Docker\API\Client;
use Docker\API\Model\ContainersIdExecPostBody;
use Docker\API\Model\ContainersIdJsonGetResponse200;
use Docker\API\Model\IdResponse;
use Docker\API\Runtime\Client\Client as DockerRuntimeClient;
use Docker\Docker;
use Psr\Http\Message\ResponseInterface;
use Testcontainers\ContainerClient\DockerContainerClient;
class StartedGenericContainer implements StartedTestContainer
@@ -53,7 +53,7 @@ class StartedGenericContainer implements StartedTestContainer
/** @var IdResponse | null $exec */
$exec = $this->dockerClient->containerExec($this->id, $execConfig);
if($exec === null || $exec->getId() === null) {
if ($exec === null || $exec->getId() === null) {
throw new \RuntimeException('Failed to create exec command');
}
@@ -108,17 +108,36 @@ class StartedGenericContainer implements StartedTestContainer
return $this->inspect()->ports[$port];
}
//TODO: not ready yet
/**
* @throws \JsonException
*/
public function getFirstMappedPort(): int
{
/** @var ContainersIdJsonGetResponse200 | null $containerInspectResponse */
$containerInspectResponse = $this->dockerClient->containerInspect($this->id);
$settings = $containerInspectResponse->getNetworkSettings();
//For some reason, containerInspect can crash when using FETCH_OBJECT option (e.g. with OpenSearch)
//should be checked within beluga-php/docker-php client library
/** @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);
return (int) $ports[$port][0]->getHostPort();
return (int) $ports[$port][0]['HostPort'];
}
public function getName(): string
@@ -1,5 +1,7 @@
<?php
declare(strict_types=1);
namespace Testcontainers\ContainerClient;
use Docker\Docker as DockerClient;
@@ -11,9 +13,6 @@ class DockerContainerClient
*/
private static ?DockerClient $dockerClient = null;
/**
* Private constructor to prevent creating instance outside the class.
*/
private function __construct()
{
}
+6 -2
View File
@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Testcontainers\Modules;
use Testcontainers\Container\GenericContainer;
use Testcontainers\Wait\WaitForLog;
use Testcontainers\Wait\WaitForExec;
class MariaDBContainer extends GenericContainer
{
@@ -13,8 +13,12 @@ class MariaDBContainer extends GenericContainer
{
parent::__construct('mariadb:' . $version);
$this->withExposedPorts(3306);
$this->withWait(new WaitForLog('ready for connections'));
$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
+6 -2
View File
@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace Testcontainers\Modules;
use Testcontainers\Container\GenericContainer;
use Testcontainers\Wait\WaitForLog;
use Testcontainers\Wait\WaitForExec;
class MySQLContainer extends GenericContainer
{
@@ -14,7 +14,11 @@ class MySQLContainer extends GenericContainer
parent::__construct('mysql:' . $version);
$this->withExposedPorts(3306);
$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
-1
View File
@@ -8,7 +8,6 @@ use Testcontainers\Container\StartedTestContainer;
abstract class BaseWaitStrategy implements WaitStrategy
{
public function __construct(protected int $timeout = 10000, protected int $pollInterval = 500)
{
}
-3
View File
@@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Testcontainers\Wait;
use Closure;
use Docker\API\Model\ContainersIdExecPostBody;
use Docker\API\Model\ExecIdJsonGetResponse200;
use Testcontainers\Container\StartedTestContainer;
use Testcontainers\Exception\ContainerWaitingTimeoutException;
@@ -15,8 +14,6 @@ use Testcontainers\Exception\ContainerWaitingTimeoutException;
*/
class WaitForExec extends BaseWaitStrategy
{
protected ContainersIdExecPostBody $execConfig;
/**
* @param array<string> $command
*/
+1
View File
@@ -9,6 +9,7 @@ use Http\Client\Socket\Exception\TimeoutException;
use Testcontainers\Container\StartedTestContainer;
use Testcontainers\Exception\ContainerNotReadyException;
//TODO: not ready yet
class WaitForHealthCheck extends BaseWaitStrategy
{
public function __construct(protected int $timeout = 5000, protected int $pollInterval = 1000)
+2 -1
View File
@@ -7,6 +7,7 @@ namespace Testcontainers\Wait;
use Docker\Docker;
use Testcontainers\Exception\ContainerNotReadyException;
//TODO: not ready yet
class WaitForHttp implements WaitStrategy
{
public const METHOD_GET = 'GET';
@@ -61,7 +62,7 @@ class WaitForHttp implements WaitStrategy
$containerNetworks = $this->dockerClient->containerInspect($id)->getNetworkSettings()->getNetworks();
$containerAddress = null;
foreach ($containerNetworks as $network) {
if($network->getNetworkID() === $id) {
if ($network->getNetworkID() === $id) {
$containerAddress = $network->getIpAddress();
break;
}
+1
View File
@@ -9,6 +9,7 @@ use JsonException;
use RuntimeException;
use Testcontainers\Exception\ContainerNotReadyException;
//TODO: not ready yet
final class WaitForTcpPortOpen implements WaitStrategy
{
private Docker $dockerClient;
@@ -18,6 +18,7 @@ use Testcontainers\Container\RedisContainer;
class ContainerTest extends TestCase
{
//TODO: remove after check
//To make it work, fixed port should be first implemented
protected function setUp(): void
{
$this->markTestIncomplete();