feature/cierres (#25)
Varios cambios Co-authored-by: Juan Pablo Vial <jpvialb@incoviba.cl> Reviewed-on: #25
This commit is contained in:
@ -5,42 +5,183 @@ require_once implode(DIRECTORY_SEPARATOR, [
|
||||
'autoload.php'
|
||||
]);
|
||||
|
||||
function setupDatabase(string $schemaFilename): void {
|
||||
printf("Loading database schema from %s", $schemaFilename);
|
||||
$start = microtime(true);
|
||||
|
||||
$dsn = "mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_DATABASE']}";
|
||||
$pdo = new PDO($dsn, $_ENV['DB_USER'], $_ENV['DB_PASSWORD']);
|
||||
|
||||
$sql = file_get_contents($schemaFilename);
|
||||
$pdo->exec($sql);
|
||||
|
||||
$end = microtime(true);
|
||||
printf(" in %.2f seconds\n", $end - $start);
|
||||
}
|
||||
function truncateTables(): void {
|
||||
printf("Truncating tables");
|
||||
$start = microtime(true);
|
||||
|
||||
$dsn = "mysql:host={$_ENV['DB_HOST']};dbname={$_ENV['DB_DATABASE']}";
|
||||
$pdo = new PDO($dsn, $_ENV['DB_USER'], $_ENV['DB_PASSWORD']);
|
||||
|
||||
$pdo->exec("SET FOREIGN_KEY_CHECKS=0");
|
||||
$statement = $pdo->query('SHOW TABLES');
|
||||
$tables = array_map(function(array $row) {
|
||||
return $row["Tables_in_{$_ENV['DB_DATABASE']}"];
|
||||
}, $statement->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
foreach ($tables as $table) {
|
||||
$pdo->exec("TRUNCATE TABLE `$table`");
|
||||
class Benchmark
|
||||
{
|
||||
protected static array $queue = [];
|
||||
public static function print(): void
|
||||
{
|
||||
if (empty(self::$queue)) {
|
||||
return;
|
||||
}
|
||||
echo implode(PHP_EOL, self::$queue), PHP_EOL;
|
||||
self::$queue = [];
|
||||
}
|
||||
$pdo->exec("SET FOREIGN_KEY_CHECKS=1");
|
||||
public static function execute(callable $callback, ?array $args = null, ?string $description = null): mixed
|
||||
{
|
||||
if (null === $description) {
|
||||
$description = self::getCallableName($callback);
|
||||
}
|
||||
$i = count(self::$queue);
|
||||
self::$queue[$i] = "Executing $description";
|
||||
$start = microtime(true);
|
||||
|
||||
$end = microtime(true);
|
||||
printf(" in %.2f seconds\n", $end - $start);
|
||||
if (null === $args) {
|
||||
$result = call_user_func($callback);
|
||||
} else {
|
||||
$result = call_user_func_array($callback, $args);
|
||||
}
|
||||
|
||||
$end = microtime(true);
|
||||
self::$queue[$i] .= sprintf(" in %.2f seconds", $end - $start);
|
||||
return $result;
|
||||
}
|
||||
public static function getCallableName(callable $callable): string
|
||||
{
|
||||
return match (true) {
|
||||
is_string($callable) && strpos($callable, '::') => '[static] ' . $callable,
|
||||
is_string($callable) => '[function] ' . $callable,
|
||||
is_array($callable) && is_object($callable[0]) => '[method] ' . get_class($callable[0]) . '->' . $callable[1],
|
||||
is_array($callable) => '[static] ' . $callable[0] . '::' . $callable[1],
|
||||
$callable instanceof Closure => '[closure]',
|
||||
is_object($callable) => '[invokable] ' . get_class($callable),
|
||||
default => '[unknown]',
|
||||
};
|
||||
}
|
||||
}
|
||||
$schemaFilename = implode(DIRECTORY_SEPARATOR, [__DIR__, 'resources', 'database', 'schema.sql']);
|
||||
setupDatabase($schemaFilename);
|
||||
register_shutdown_function(function() {
|
||||
truncateTables();
|
||||
class TestBootstrap
|
||||
{
|
||||
public function __construct(protected array $configuration) {}
|
||||
|
||||
public function run(bool $debug = false): void
|
||||
{
|
||||
if (!Benchmark::execute([$this, 'isMigrated'])) {
|
||||
Benchmark::execute([$this, 'migrate']);
|
||||
}
|
||||
$output = Benchmark::execute([$this, 'seedTables']);
|
||||
if ($debug) {
|
||||
var_dump($output);
|
||||
}
|
||||
}
|
||||
|
||||
protected string $baseCommand = "bin/phinx";
|
||||
public function isMigrated(): bool
|
||||
{
|
||||
$cmd = "{$this->baseCommand} status -e testing -f json --no-info";
|
||||
$output = shell_exec($cmd);
|
||||
$status = json_decode($output, true);
|
||||
|
||||
return $status['missing_count'] === 0 and $status['pending_count'] === 0;
|
||||
}
|
||||
public function migrate(): false|null|string
|
||||
{
|
||||
$cmd = "{$this->baseCommand} migrate -e testing";
|
||||
return shell_exec($cmd);
|
||||
}
|
||||
|
||||
public function resetDatabase(): void
|
||||
{
|
||||
$tables = $this->getTables();
|
||||
if ($this->connect()->beginTransaction()) {
|
||||
try {
|
||||
$this->connect()->query("SET FOREIGN_KEY_CHECKS=0;");
|
||||
foreach ($tables as $table) {
|
||||
$this->connect()->query("DROP TABLE IF EXISTS `{$table}`");
|
||||
}
|
||||
$this->connect()->query("SET FOREIGN_KEY_CHECKS=1;");
|
||||
if ($this->connect()->inTransaction()) {
|
||||
$this->connect()->commit();
|
||||
}
|
||||
} catch (PDOException $exception) {
|
||||
if ($this->connect()->inTransaction()) {
|
||||
$this->connect()->rollBack();
|
||||
}
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function truncateTables(): void
|
||||
{
|
||||
$tables = $this->getTables();
|
||||
if ($this->connect()->beginTransaction()) {
|
||||
try {
|
||||
$this->connect()->query("SET FOREIGN_KEY_CHECKS=0;");
|
||||
foreach ($tables as $table) {
|
||||
$this->connect()->query("TRUNCATE TABLE `{$table}`");
|
||||
}
|
||||
$this->connect()->query("SET FOREIGN_KEY_CHECKS=1;");
|
||||
if ($this->connect()->inTransaction()) {
|
||||
$this->connect()->commit();
|
||||
}
|
||||
} catch (PDOException $exception) {
|
||||
if ($this->connect()->inTransaction()) {
|
||||
$this->connect()->rollBack();
|
||||
}
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function seedTables(): false|null|string
|
||||
{
|
||||
$cmd = "{$this->baseCommand} seed:run -e testing";
|
||||
$output = shell_exec($cmd);
|
||||
|
||||
$testSeeder = new Tests\Extension\TestSeeder($this->connect());
|
||||
$testSeeder->run();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
protected PDO $connection;
|
||||
protected function connect(): PDO
|
||||
{
|
||||
if (!isset($this->connection)) {
|
||||
$dsn = "mysql:host={$this->configuration['DB_HOST']};dbname={$this->configuration['DB_DATABASE']}";
|
||||
$this->connection = new PDO(
|
||||
$dsn,
|
||||
$this->configuration['DB_USER'],
|
||||
$this->configuration['DB_PASSWORD']
|
||||
);
|
||||
}
|
||||
return $this->connection;
|
||||
}
|
||||
protected array $tables;
|
||||
protected function getTables(): array
|
||||
{
|
||||
if (!isset($this->tables)) {
|
||||
$this->tables = $this->connect()->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
|
||||
}
|
||||
return $this->tables;
|
||||
}
|
||||
}
|
||||
|
||||
spl_autoload_register(function($className) {
|
||||
$baseTestPath = __DIR__ . "/tests";
|
||||
$namespaceMap = [
|
||||
"Tests\\Extension\\" => "{$baseTestPath}/extension",
|
||||
"Tests\\Integration\\" => "{$baseTestPath}/integration",
|
||||
"Tests\\Unit\\" => "{$baseTestPath}/unit/src",
|
||||
"Tests\\Performance\\" => "{$baseTestPath}/performance",
|
||||
];
|
||||
foreach ($namespaceMap as $namespace => $path) {
|
||||
if (str_starts_with($className, $namespace)) {
|
||||
require str_replace([$namespace, '\\'], ["{$path}/", DIRECTORY_SEPARATOR], $className) . ".php";
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$bootstrap = new TestBootstrap($_ENV);
|
||||
$resetDatabase = (array_key_exists('RESET_DATABASE', $_ENV) and $_ENV['RESET_DATABASE'] === 'true') ?? false;
|
||||
$debug = (array_key_exists('DEBUG', $_ENV) and $_ENV['DEBUG'] === 'true') ?? false;
|
||||
|
||||
Benchmark::execute([$bootstrap, 'run'], ['debug' => $debug]);
|
||||
Benchmark::print();
|
||||
|
||||
register_shutdown_function(function() use ($bootstrap, $resetDatabase) {
|
||||
$method = 'truncateTables';
|
||||
if ($resetDatabase) {
|
||||
$method = 'resetDatabase';
|
||||
}
|
||||
Benchmark::execute([$bootstrap, $method]);
|
||||
Benchmark::print();
|
||||
});
|
||||
|
Reference in New Issue
Block a user