packages/ztd-query-pdo-adapter/fuzz/Container/DatabaseEndpoint.php
1<?php
2
3declare(strict_types=1);
4
5namespace Fuzz\Container;
6
7use Container\MySql80Container;
8use Container\MySql84Container;
9use Container\PostgreSql16Container;
10use RuntimeException;
11use Testcontainers\Testcontainers;
12
13/**
14 * Selects a disposable service supplied by CI or starts a local test container.
15 */
16final class DatabaseEndpoint
17{
18 /**
19 * @return array{string, int}
20 * @throws RuntimeException When the service port is invalid or unmapped.
21 */
22 public static function mysql(): array
23 {
24 $host = getenv('MYSQL_HOST');
25 if ($host !== false) {
26 return [$host, self::port('MYSQL_PORT', 3306)];
27 }
28 $instance = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
29
30 return [str_replace('localhost', '127.0.0.1', $instance->getHost()), $instance->getMappedPort(3306) ?? throw new RuntimeException('MySQL port was not mapped.')];
31 }
32
33 /**
34 * @return array{string, int}
35 * @throws RuntimeException When the service port is invalid or unmapped.
36 */
37 public static function postgres(): array
38 {
39 $host = getenv('PG_HOST');
40 if ($host !== false) {
41 return [$host, self::port('PG_PORT', 5432)];
42 }
43 $instance = Testcontainers::run(PostgreSql16Container::class);
44
45 return [str_replace('localhost', '127.0.0.1', $instance->getHost()), $instance->getMappedPort(5432) ?? throw new RuntimeException('PostgreSQL port was not mapped.')];
46 }
47
48 /**
49 * @throws RuntimeException When a configured port is not a valid TCP port.
50 */
51 public static function port(string $variable, int $default): int
52 {
53 $value = getenv($variable);
54 if ($value === false) {
55 return $default;
56 }
57 $port = filter_var($value, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 65535]]);
58 if ($port === false) {
59 throw new RuntimeException($variable . ' must be a TCP port between 1 and 65535.');
60 }
61
62 return $port;
63 }
64}
65