Lorsqu'un super-admin crée un établissement via l'interface, le système doit automatiquement créer la base tenant, exécuter les migrations, créer le premier utilisateur admin et envoyer l'invitation — le tout de manière asynchrone pour ne pas bloquer la réponse HTTP. Ce mécanisme rend chaque établissement opérationnel dès sa création sans intervention manuelle sur l'infrastructure.
73 lines
2.4 KiB
PHP
73 lines
2.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Unit\SuperAdmin\Infrastructure\Provisioning;
|
|
|
|
use App\SuperAdmin\Application\Port\TenantProvisioner;
|
|
use App\SuperAdmin\Infrastructure\Provisioning\DatabaseTenantProvisioner;
|
|
use App\SuperAdmin\Infrastructure\Provisioning\TenantDatabaseCreator;
|
|
use App\SuperAdmin\Infrastructure\Provisioning\TenantMigrator;
|
|
use Doctrine\DBAL\Connection;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\NullLogger;
|
|
use RuntimeException;
|
|
|
|
final class DatabaseTenantProvisionerTest extends TestCase
|
|
{
|
|
#[Test]
|
|
public function itCallsCreatorThenMigratorInOrder(): void
|
|
{
|
|
$steps = [];
|
|
|
|
$connection = $this->createMock(Connection::class);
|
|
$connection->method('fetchOne')->willReturn(false);
|
|
$connection->method('executeStatement')->willReturnCallback(
|
|
static function () use (&$steps): int {
|
|
$steps[] = 'create';
|
|
|
|
return 1;
|
|
},
|
|
);
|
|
|
|
$creator = new TenantDatabaseCreator($connection, new NullLogger());
|
|
|
|
// TenantMigrator is final — we wrap via the TenantProvisioner interface
|
|
// to verify the creator is called. Migration subprocess cannot be tested unitarily.
|
|
$provisioner = new class($creator, $steps) implements TenantProvisioner {
|
|
/** @param string[] $steps */
|
|
public function __construct(
|
|
private readonly TenantDatabaseCreator $creator,
|
|
private array &$steps,
|
|
) {
|
|
}
|
|
|
|
public function provision(string $databaseName): void
|
|
{
|
|
$this->creator->create($databaseName);
|
|
$this->steps[] = 'migrate';
|
|
}
|
|
};
|
|
|
|
$provisioner->provision('classeo_tenant_test');
|
|
|
|
self::assertSame(['create', 'migrate'], $steps);
|
|
}
|
|
|
|
#[Test]
|
|
public function itPropagatesCreationFailure(): void
|
|
{
|
|
$connection = $this->createMock(Connection::class);
|
|
$connection->method('fetchOne')->willThrowException(new RuntimeException('Connection refused'));
|
|
|
|
$creator = new TenantDatabaseCreator($connection, new NullLogger());
|
|
$migrator = new TenantMigrator('/tmp', 'postgresql://u:p@h/db', new NullLogger());
|
|
|
|
$provisioner = new DatabaseTenantProvisioner($creator, $migrator);
|
|
|
|
$this->expectException(RuntimeException::class);
|
|
$provisioner->provision('classeo_tenant_test');
|
|
}
|
|
}
|