mirror of
https://github.com/elyby/accounts.git
synced 2026-11-11 18:33:30 +05:30
87 lines
3.2 KiB
PHP
87 lines
3.2 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace common\tests\_support;
|
|
|
|
use Codeception\Events;
|
|
use Codeception\Extension;
|
|
use common\config\ConfigLoader;
|
|
use PDO;
|
|
use PDOException;
|
|
use RuntimeException;
|
|
|
|
/**
|
|
* The tests use a separate database on the application's MariaDB server (see common/config/config-test.php).
|
|
* It's created on demand and migrated once per tests run, so running the tests requires no manual steps.
|
|
*
|
|
* This class if fully AI generated
|
|
*/
|
|
final class TestDatabase extends Extension {
|
|
|
|
/**
|
|
* @var array<string, string>
|
|
*/
|
|
public static array $events = [
|
|
Events::SUITE_BEFORE => 'prepare',
|
|
];
|
|
|
|
/**
|
|
* The event is fired for each suite, while the preparation is needed only once per process
|
|
*/
|
|
private static bool $isPrepared = false;
|
|
|
|
public function prepare(): void {
|
|
if (self::$isPrepared) {
|
|
return;
|
|
}
|
|
|
|
/** @var array{dsn: string, username: string, password: string} $db */
|
|
$db = ConfigLoader::load('console')['components']['db'];
|
|
if (!preg_match('/^(?<server>.+);dbname=(?<name>[^;]+)$/', $db['dsn'], $matches)) {
|
|
throw new RuntimeException("Cannot extract the database name from the DSN \"{$db['dsn']}\"");
|
|
}
|
|
|
|
$name = $matches['name'];
|
|
if ($name === getenv('DB_DATABASE')) {
|
|
throw new RuntimeException("The tests database must differ from the application's one \"{$name}\", since the tests wipe all the data");
|
|
}
|
|
|
|
self::createDatabase($matches['server'], $name, $db['username'], $db['password']);
|
|
self::applyMigrations();
|
|
|
|
self::$isPrepared = true;
|
|
}
|
|
|
|
private static function createDatabase(string $serverDsn, string $name, string $username, string $password): void {
|
|
$pdo = new PDO($serverDsn, $username, $password, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
$quotedName = '`' . str_replace('`', '``', $name) . '`';
|
|
try {
|
|
// The user is able to create the "test_*" databases thanks to the default MariaDB grants
|
|
$pdo->exec("CREATE DATABASE IF NOT EXISTS {$quotedName} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
|
} catch (PDOException $e) {
|
|
throw new RuntimeException(
|
|
"Cannot create the tests database {$quotedName}. Either create it manually or grant the privileges:\n"
|
|
. "GRANT ALL PRIVILEGES ON {$quotedName}.* TO '{$username}'@'%';",
|
|
previous: $e,
|
|
);
|
|
}
|
|
}
|
|
|
|
private static function applyMigrations(): void {
|
|
$command = [PHP_BINARY, dirname(__DIR__, 3) . '/yii', 'migrate/up', '--interactive=0'];
|
|
$process = proc_open($command, [1 => ['pipe', 'w'], 2 => ['redirect', 1]], $pipes, null, array_merge(getenv(), [
|
|
'YII_ENV' => 'test',
|
|
]));
|
|
if ($process === false) {
|
|
throw new RuntimeException('Cannot run the migrations for the tests database');
|
|
}
|
|
|
|
$output = (string)stream_get_contents($pipes[1]);
|
|
fclose($pipes[1]);
|
|
if (proc_close($process) !== 0) {
|
|
throw new RuntimeException("Cannot apply the migrations to the tests database:\n{$output}");
|
|
}
|
|
}
|
|
|
|
}
|