Ambiente de testeo

This commit is contained in:
Juan Pablo Vial
2025-04-29 21:41:49 -04:00
parent e6892ee085
commit 2acf0362fa
4 changed files with 151 additions and 60 deletions

View File

@ -2,7 +2,7 @@
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.4/phpunit.xsd"
bootstrap="vendor/autoload.php"
bootstrap="test.bootstrap.php"
cacheDirectory="/code/cache/tests"
executionOrder="depends,defects"
requireCoverageMetadata="false"
@ -34,10 +34,10 @@
<php outputFile="/code/public/coverage/coverage.php"/>
</report>
</coverage>
<!--<logging>
<logging>
<junit outputFile="/code/cache/tests/junit.xml"/>
<teamcity outputFile="/code/cache/tests/teamcity.txt"/>
<testdoxHtml outputFile="/code/cache/tests/testdox.html"/>
<testdoxText outputFile="/code/cache/tests/testdox.txt"/>
</logging>-->
</logging>
</phpunit>

View File

@ -5,42 +5,149 @@ 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");
$end = microtime(true);
printf(" in %.2f seconds\n", $end - $start);
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);
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(): void
{
if (Benchmark::execute([$this, 'isMigrated'])) {
Benchmark::execute([$this, 'resetDatabase']);
}
Benchmark::execute([$this, 'migrate']);
}
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;
}
public function migrate(): void
{
$cmd = "{$this->baseCommand} migrate -e testing";
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;
}
}
}
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;
}
}
$bootstrap = new TestBootstrap($_ENV);
Benchmark::execute([$bootstrap, 'run']);
Benchmark::print();
register_shutdown_function(function() use ($bootstrap) {
Benchmark::execute([$bootstrap, 'truncateTables']);
Benchmark::print();
});

View File

@ -84,20 +84,6 @@ services:
- ${CLI_PATH:-.}:/code
- ./logs/cli:/logs
testing:
profiles:
- testing
container_name: incoviba_tests
build: .
restart: unless-stopped
env_file:
- ${APP_PATH:-.}/.env
- ./.key.env
volumes:
- ${APP_PATH:-.}/:/code
- ./logs/test:/logs
command: [ '/code/bin/phpunit-watcher', 'watch' ]
volumes:
dbdata: {}
incoviba_redis: {}

View File

@ -2,34 +2,32 @@ services:
testing:
profiles:
- testing
container_name: incoviba_tests
build: .
restart: unless-stopped
container_name: incoviba_tests
env_file:
- ${APP_PATH:-.}/.test.env
- ./.key.env
volumes:
- ${APP_PATH:-.}/:/code
- ./logs/test:/logs
command: [ '/code/bin/phpunit-watcher', 'watch' ]
networks:
- testing
depends_on:
- test-db
test-db:
profiles:
- testing
image: mysql:5.7
image: mariadb:latest
container_name: incoviba_test_db
restart: unless-stopped
env_file: ${APP_PATH:-.}/.test.db.env
volumes:
- test-db:/var/lib/mysql
networks:
- default
- adminer_network
- testing
volumes:
test-db: {}
networks:
adminer_network: {}
testing: {}