mirror of
https://github.com/stan220/testcontainers-php.git
synced 2026-09-12 09:29:35 +00:00
Merge remote-tracking branch 'contributor/0.2' into feat/started-generic-container
This commit is contained in:
@@ -10,7 +10,9 @@ 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 Psr\Http\Message\ResponseInterface;
|
||||||
|
use RuntimeException;
|
||||||
use Testcontainers\ContainerClient\DockerContainerClient;
|
use Testcontainers\ContainerClient\DockerContainerClient;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
class StartedGenericContainer implements StartedTestContainer
|
class StartedGenericContainer implements StartedTestContainer
|
||||||
{
|
{
|
||||||
@@ -53,7 +55,7 @@ class StartedGenericContainer implements StartedTestContainer
|
|||||||
$exec = $this->dockerClient->containerExec($this->id, $execConfig);
|
$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');
|
throw new RuntimeException('Failed to create exec command');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->lastExecId = $exec->getId();
|
$this->lastExecId = $exec->getId();
|
||||||
@@ -95,45 +97,24 @@ class StartedGenericContainer implements StartedTestContainer
|
|||||||
return preg_replace('/[\x00-\x1F\x7F]/u', '', mb_convert_encoding($output, 'UTF-8', 'UTF-8')) ?? '';
|
return preg_replace('/[\x00-\x1F\x7F]/u', '', mb_convert_encoding($output, 'UTF-8', 'UTF-8')) ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: replace with the proper implementation
|
|
||||||
public function getHost(): string
|
public function getHost(): string
|
||||||
{
|
{
|
||||||
return '127.0.0.1';
|
return $this->inspect()['NetworkSettings']['Gateway'] ?? '127.0.0.1';
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: not ready yet
|
|
||||||
public function getMappedPort(int $port): int
|
public function getMappedPort(int $port): int
|
||||||
{
|
{
|
||||||
return $this->inspect()->ports[$port];
|
$ports = $this->ports();
|
||||||
|
if (isset($ports["{$port}/tcp"][0]['HostPort'])) {
|
||||||
|
return (int) $ports["{$port}/tcp"][0]['HostPort'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException("Failed to get mapped port $port for container");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \JsonException
|
|
||||||
*/
|
|
||||||
public function getFirstMappedPort(): int
|
public function getFirstMappedPort(): int
|
||||||
{
|
{
|
||||||
//For some reason, containerInspect can crash when using FETCH_OBJECT option (e.g. with OpenSearch)
|
$ports = $this->ports();
|
||||||
//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');
|
|
||||||
}
|
|
||||||
|
|
||||||
$port = array_key_first($ports);
|
$port = array_key_first($ports);
|
||||||
|
|
||||||
return (int) $ports[$port][0]['HostPort'];
|
return (int) $ports[$port][0]['HostPort'];
|
||||||
@@ -141,32 +122,75 @@ class StartedGenericContainer implements StartedTestContainer
|
|||||||
|
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
{
|
{
|
||||||
// TODO: Implement getName() method.
|
return trim($this->inspect()['Name'], '/ ');
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
public function getLabels(): array
|
public function getLabels(): array
|
||||||
{
|
{
|
||||||
// TODO: Implement getLabels() method.
|
return $this->inspect()['Config']['Labels'] ?? [];
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
public function getNetworkNames(): array
|
public function getNetworkNames(): array
|
||||||
{
|
{
|
||||||
// TODO: Implement getNetworkNames() method.
|
$networks = $this->inspect()['NetworkSettings']['Networks'] ?? [];
|
||||||
return [];
|
return array_keys($networks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNetworkId(string $networkName): string
|
public function getNetworkId(string $networkName): string
|
||||||
{
|
{
|
||||||
// TODO: Implement getNetworkId() method.
|
$networks = $this->inspect()['NetworkSettings']['Networks'];
|
||||||
return '';
|
if (isset($networks[$networkName])) {
|
||||||
|
return $networks[$networkName]['NetworkID'];
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Network with name {$networkName} not exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getIpAddress(string $networkName): string
|
public function getIpAddress(string $networkName): string
|
||||||
{
|
{
|
||||||
// TODO: Implement getIpAddress() method.
|
$networks = $this->inspect()['NetworkSettings']['Networks'];
|
||||||
return '';
|
if (isset($networks[$networkName])) {
|
||||||
|
return $networks[$networkName]['IPAddress'];
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Network with name {$networkName} not exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
private function inspect(): array
|
||||||
|
{
|
||||||
|
//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');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return json_decode(
|
||||||
|
$containerInspectResponse->getBody()->getContents(),
|
||||||
|
true,
|
||||||
|
512,
|
||||||
|
JSON_THROW_ON_ERROR
|
||||||
|
);
|
||||||
|
} catch (Throwable $exception) {
|
||||||
|
throw new RuntimeException('Failed to inspect container', 0, $exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ports(): array
|
||||||
|
{
|
||||||
|
/** @var array<string, array<array<string, string>>> $ports */
|
||||||
|
$ports = $this->inspect()['NetworkSettings']['Ports'] ?? [];
|
||||||
|
|
||||||
|
if ($ports === []) {
|
||||||
|
throw new RuntimeException('Failed to get ports from container');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ class MySQLContainer extends GenericContainer
|
|||||||
$this->withWait(new WaitForExec([
|
$this->withWait(new WaitForExec([
|
||||||
"mysqladmin",
|
"mysqladmin",
|
||||||
"ping",
|
"ping",
|
||||||
|
"-u", "root",
|
||||||
|
"-p{$mysqlRootPassword}",
|
||||||
"-h", "127.0.0.1",
|
"-h", "127.0.0.1",
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user